require_once($CFG->libdir.'/classes/component.php');
require_once($CFG->libdir.'/classes/text.php');
+require_once($CFG->libdir.'/classes/string_manager.php');
+require_once($CFG->libdir.'/classes/string_manager_install.php');
+require_once($CFG->libdir.'/classes/string_manager_standard.php');
require_once($CFG->libdir.'/installlib.php');
require_once($CFG->libdir.'/clilib.php');
require_once($CFG->libdir.'/setuplib.php');
require_once($CFG->libdir.'/adminlib.php');
$confirm = optional_param('confirm', 0, PARAM_BOOL);
+$returnurl = optional_param('returnurl', null, PARAM_LOCALURL);
-admin_externalpage_setup('purgecaches');
-
-require_login();
-require_capability('moodle/site:config', context_system::instance());
-
-if ($confirm) {
- require_sesskey();
+// If we have got here as a confirmed aciton, do it.
+if ($confirm && isloggedin() && confirm_sesskey()) {
+ require_capability('moodle/site:config', context_system::instance());
- // Valid request. Purge, and redisplay the form so it is easy to purge again
- // in the near future.
+ // Valid request. Purge, and redirect the user back to where they came from.
purge_all_caches();
- redirect(new moodle_url('/admin/purgecaches.php'), get_string('purgecachesfinished', 'admin'));
-
-} else {
- // Show a confirm form.
- echo $OUTPUT->header();
- echo $OUTPUT->heading(get_string('purgecaches', 'admin'));
-
- $url = new moodle_url('/admin/purgecaches.php', array('sesskey'=>sesskey(), 'confirm'=>1));
- $button = new single_button($url, get_string('purgecaches','admin'), 'post');
-
- // Cancel button takes them back to the page the were on, if possible,
- // otherwise to the site home page.
- $return = new moodle_url('/');
- if (isset($_SERVER['HTTP_REFERER']) and !empty($_SERVER['HTTP_REFERER'])) {
- if ($_SERVER['HTTP_REFERER'] !== "$CFG->wwwroot/$CFG->admin/purgecaches.php") {
- $return = $_SERVER['HTTP_REFERER'];
- }
+
+ if ($returnurl) {
+ $returnurl = $CFG->wwwroot . $returnurl;
+ } else {
+ $returnurl = new moodle_url('/admin/purgecaches.php');
}
+ redirect($returnurl, get_string('purgecachesfinished', 'admin'));
+}
- echo $OUTPUT->confirm(get_string('purgecachesconfirm', 'admin'), $button, $return);
- echo $OUTPUT->footer();
+// Otherwise, show a button to actually purge the caches.
+admin_externalpage_setup('purgecaches');
+
+$actionurl = new moodle_url('/admin/purgecaches.php', array('sesskey'=>sesskey(), 'confirm'=>1));
+if ($returnurl) {
+ $actionurl->param('returnurl', $returnurl);
}
+
+echo $OUTPUT->header();
+echo $OUTPUT->heading(get_string('purgecaches', 'admin'));
+
+echo $OUTPUT->box_start('generalbox', 'notice');
+echo html_writer::tag('p', get_string('purgecachesconfirm', 'admin'));
+echo $OUTPUT->single_button($actionurl, get_string('purgecaches', 'admin'), 'post');
+echo $OUTPUT->box_end();
+
+echo $OUTPUT->footer();
if (optional_param('submit', false, PARAM_BOOL) && data_submitted() && confirm_sesskey()) {
$controller->process_submission();
$syscontext->mark_dirty();
- add_to_log(SITEID, 'role', 'edit allow ' . $mode, str_replace($CFG->wwwroot . '/', '', $baseurl), '', '', $USER->id);
+ $event = null;
+ // Create event depending on mode.
+ switch ($mode) {
+ case 'assign':
+ $event = \core\event\role_allow_assign_updated::create(array('context' => $syscontext));
+ break;
+ case 'override':
+ $event = \core\event\role_allow_override_updated::create(array('context' => $syscontext));
+ break;
+ case 'switch':
+ $event = \core\event\role_allow_switch_updated::create(array('context' => $syscontext));
+ break;
+ }
+ if ($event) {
+ $event->trigger();
+ }
redirect($baseurl);
}
$potentialuserselector->invalidate_selected_users();
$currentuserselector->invalidate_selected_users();
- $rolename = $assignableroles[$roleid];
- add_to_log($course->id, 'role', 'assign', 'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$roleid, $rolename, '', $USER->id);
// Counts have changed, so reload.
list($assignableroles, $assigncounts, $nameswithcounts) = get_assignable_roles($context, ROLENAME_BOTH, true);
}
$potentialuserselector->invalidate_selected_users();
$currentuserselector->invalidate_selected_users();
- $rolename = $assignableroles[$roleid];
- add_to_log($course->id, 'role', 'unassign', 'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$roleid, $rolename, '', $USER->id);
// Counts have changed, so reload.
list($assignableroles, $assigncounts, $nameswithcounts) = get_assignable_roles($context, ROLENAME_BOTH, true);
}
// Process submission in necessary.
if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey() && $definitiontable->is_submission_valid()) {
$definitiontable->save_changes();
- add_to_log(SITEID, 'role', $action, 'admin/roles/define.php?action=view&roleid=' .
- $definitiontable->get_role_id(), $definitiontable->get_role_name(), '', $USER->id);
+ $tableroleid = $definitiontable->get_role_id();
+ // Trigger event.
+ $event = \core\event\role_capabilities_updated::create(
+ array(
+ 'context' => $systemcontext,
+ 'objectid' => $roleid,
+ 'other' => array('name' => $definitiontable->get_role_name())
+ )
+ );
+ $event->set_legacy_logdata(array(SITEID, 'role', $action, 'admin/roles/define.php?action=view&roleid=' . $tableroleid,
+ $definitiontable->get_role_name(), '', $USER->id));
+ if (!empty($role)) {
+ $event->add_record_snapshot('role', $role);
+ }
+ $event->trigger();
+
if ($action === 'add') {
redirect(new moodle_url('/admin/roles/define.php', array('action'=>'view', 'roleid'=>$definitiontable->get_role_id())));
} else {
}
// Deleted a role sitewide...
$systemcontext->mark_dirty();
- add_to_log(SITEID, 'role', 'delete', 'admin/roles/manage.php', $roles[$roleid]->localname, '', $USER->id);
redirect($baseurl);
break;
if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
$overridestable->save_changes();
$rolename = $overridableroles[$roleid];
- add_to_log($course->id, 'role', 'override', 'admin/roles/override.php?contextid='.$context->id.'&roleid='.$roleid, $rolename, '', $USER->id);
+ // Trigger event.
+ $event = \core\event\role_capabilities_updated::create(
+ array(
+ 'context' => $context,
+ 'objectid' => $roleid,
+ 'courseid' => $courseid,
+ 'other' => array('name' => $rolename)
+ )
+ );
+
+ $event->set_legacy_logdata(
+ array(
+ $course->id, 'role', 'override', 'admin/roles/override.php?contextid=' . $context->id . '&roleid=' . $roleid,
+ $rolename, '', $USER->id
+ )
+ );
+ $event->add_record_snapshot('role', $role);
+ $event->trigger();
+
redirect($returnurl);
}
// "performance" settingpage
$temp = new admin_settingpage('performance', new lang_string('performance', 'admin'));
+// Memory limit options for large administration tasks.
+$memoryoptions = array(
+ '64M' => '64M',
+ '128M' => '128M',
+ '256M' => '256M',
+ '512M' => '512M',
+ '1024M' => '1024M',
+ '2048M' => '2048M');
+
+// Allow larger memory usage for 64-bit sites only.
+if (PHP_INT_SIZE === 8) {
+ $memoryoptions['3072M'] = '3072M';
+ $memoryoptions['4096M'] = '4096M';
+}
+
$temp->add(new admin_setting_configselect('extramemorylimit', new lang_string('extramemorylimit', 'admin'),
new lang_string('configextramemorylimit', 'admin'), '512M',
- // if this option is set to 0, default 128M will be used
- array( '64M' => '64M',
- '128M' => '128M',
- '256M' => '256M',
- '512M' => '512M',
- '1024M' => '1024M',
- '2048M' => '2048M',
- )));
+ $memoryoptions));
+
$temp->add(new admin_setting_configtext('curlcache', new lang_string('curlcache', 'admin'),
new lang_string('configcurlcache', 'admin'), 120, PARAM_INT));
And I should see "Grouping 1"
And I should see "Grouping 2"
+ @javascript
+ Scenario: Role overrides
+ Given the following "users" exists:
+ | username | firstname | lastname | email |
+ | teacher1 | Teacher | 1 | teacher1@asd.com |
+ | student1 | Student | 1 | student1@asd.com |
+ And the following "categories" exists:
+ | name | category | idnumber |
+ | Cat 1 | 0 | CAT1 |
+ And the following "courses" exists:
+ | fullname | shortname |
+ | Course 1 | C1 |
+ And the following "course enrolments" exists:
+ | user | course | role |
+ | student1 | C1 | student |
+ | teacher1 | C1 | editingteacher |
+ And the following "permission overrides" exists:
+ | capability | permission | role | contextlevel | reference |
+ | mod/forum:editanypost | Allow | student | Course | C1 |
+ | mod/forum:replynews | Prevent | editingteacher | Course | C1 |
+ When I log in as "admin"
+ And I follow "Course 1"
+ And I expand "Users" node
+ And I follow "Permissions"
+ And I select "Student (1)" from "Advanced role override"
+ Then the "mod/forum:editanypost" field should match "1" value
+ And I press "Cancel"
+ And I select "Teacher (1)" from "Advanced role override"
+ And the "mod/forum:replynews" field should match "-1" value
+ And I press "Cancel"
+
Scenario: Add course enrolments
Given the following "users" exists:
| username | firstname | lastname | email |
$mform->addHelpButton('restrictedusers', 'restrictedusers', 'webservice');
$mform->setType('restrictedusers', PARAM_BOOL);
- //can users download files
+ // Can users download files?
$mform->addElement('advcheckbox', 'downloadfiles', get_string('downloadfiles', 'webservice'));
$mform->setAdvanced('downloadfiles');
$mform->addHelpButton('downloadfiles', 'downloadfiles', 'webservice');
$mform->setType('downloadfiles', PARAM_BOOL);
+ // Can users upload files?
+ $mform->addElement('advcheckbox', 'uploadfiles', get_string('uploadfiles', 'webservice'));
+ $mform->setAdvanced('uploadfiles');
+ $mform->addHelpButton('uploadfiles', 'uploadfiles', 'webservice');
+
/// needed to select automatically the 'No required capability" option
$currentcapabilityexist = false;
if (empty($service->requiredcapability)) {
return $errors;
}
-}
\ No newline at end of file
+}
print_error('unknownbackuptype');
}
+// Backup of large courses requires extra memory. Use the amount configured
+// in admin settings.
+raise_memory_limit(MEMORY_EXTRA);
+
if (!($bc = backup_ui::load_controller($backupid))) {
$bc = new backup_controller($type, $id, backup::FORMAT_MOODLE,
backup::INTERACTIVE_YES, backup::MODE_GENERAL, $USER->id);
require_login($course, null, $cm);
require_capability('moodle/restore:restorecourse', $context);
+// Restore of large courses requires extra memory. Use the amount configured
+// in admin settings.
+raise_memory_limit(MEMORY_EXTRA);
+
if ($stage & restore_ui::STAGE_CONFIRM + restore_ui::STAGE_DESTINATION) {
$restore = restore_ui::engage_independent_stage($stage, $contextid);
} else {
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Local stuff for category enrolment plugin.
+ *
+ * @package core_badges
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Event observer for badges.
+ */
+class core_badges_observer {
+ /**
+ * Triggered when 'course_module_completion_updated' event is triggered.
+ *
+ * @param \core\event\course_module_completion_updated $event
+ */
+ public static function course_module_criteria_review(\core\event\course_module_completion_updated $event) {
+ global $DB, $CFG;
+
+ if (!empty($CFG->enablebadges)) {
+ require_once($CFG->dirroot.'/lib/badgeslib.php');
+
+ $eventdata = $event->get_record_snapshot('course_modules_completion', $event->objectid);
+ $userid = $event->other['relateduserid'];
+ $mod = $eventdata->coursemoduleid;
+
+ if ($eventdata->completionstate == COMPLETION_COMPLETE
+ || $eventdata->completionstate == COMPLETION_COMPLETE_PASS
+ || $eventdata->completionstate == COMPLETION_COMPLETE_FAIL) {
+ // Need to take into account that there can be more than one badge with the same activity in its criteria.
+ if ($rs = $DB->get_records('badge_criteria_param', array('name' => 'module_' . $mod, 'value' => $mod))) {
+ foreach ($rs as $r) {
+ $bid = $DB->get_field('badge_criteria', 'badgeid', array('id' => $r->critid), MUST_EXIST);
+ $badge = new badge($bid);
+ if (!$badge->is_active() || $badge->is_issued($userid)) {
+ continue;
+ }
+
+ if ($badge->criteria[BADGE_CRITERIA_TYPE_ACTIVITY]->review($userid)) {
+ $badge->criteria[BADGE_CRITERIA_TYPE_ACTIVITY]->mark_complete($userid);
+
+ if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
+ $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
+ $badge->issue($userid);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Triggered when 'course_completed' event is triggered.
+ *
+ * @param \core\event\course_completed $event
+ */
+ public static function course_criteria_review(\core\event\course_completed $event) {
+ global $DB, $CFG;
+
+ if (!empty($CFG->enablebadges)) {
+ require_once($CFG->dirroot.'/lib/badgeslib.php');
+
+ $eventdata = $event->get_record_snapshot('course_completions', $event->objectid);
+ $userid = $event->other['relateduserid'];
+ $courseid = $event->courseid;
+
+ // Need to take into account that course can be a part of course_completion and courseset_completion criteria.
+ if ($rs = $DB->get_records('badge_criteria_param', array('name' => 'course_' . $courseid, 'value' => $courseid))) {
+ foreach ($rs as $r) {
+ $crit = $DB->get_record('badge_criteria', array('id' => $r->critid), 'badgeid, criteriatype', MUST_EXIST);
+ $badge = new badge($crit->badgeid);
+ if (!$badge->is_active() || $badge->is_issued($userid)) {
+ continue;
+ }
+
+ if ($badge->criteria[$crit->criteriatype]->review($userid)) {
+ $badge->criteria[$crit->criteriatype]->mark_complete($userid);
+
+ if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
+ $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
+ $badge->issue($userid);
+ }
+ }
+ }
+ }
+ }
+ }
+}
class core_badgeslib_testcase extends advanced_testcase {
protected $badgeid;
+ protected $course;
+ protected $user;
+ protected $module;
+ protected $coursebadge;
protected function setUp() {
- global $DB;
+ global $DB, $CFG;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$fordb->status = BADGE_STATUS_INACTIVE;
$this->badgeid = $DB->insert_record('badge', $fordb, true);
+
+ // Create a course with activity and auto completion tracking.
+ $this->course = $this->getDataGenerator()->create_course();
+ $this->user = $this->getDataGenerator()->create_user();
+ $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+ $this->assertNotEmpty($studentrole);
+
+ // Get manual enrolment plugin and enrol user.
+ require_once($CFG->dirroot.'/enrol/manual/locallib.php');
+ $manplugin = enrol_get_plugin('manual');
+ $maninstance = $DB->get_record('enrol', array('courseid' => $this->course->id, 'enrol' => 'manual'), '*', MUST_EXIST);
+ $manplugin->enrol_user($maninstance, $this->user->id, $studentrole->id);
+ $this->assertEquals(1, $DB->count_records('user_enrolments'));
+
+ $completionauto = array('completion' => COMPLETION_TRACKING_AUTOMATIC);
+ $this->module = $this->getDataGenerator()->create_module('forum', array('course' => $this->course->id), $completionauto);
+
+ // Build badge and criteria.
+ $fordb->type = BADGE_TYPE_COURSE;
+ $fordb->courseid = $this->course->id;
+ $fordb->status = BADGE_STATUS_ACTIVE;
+
+ $this->coursebadge = $DB->insert_record('badge', $fordb, true);
}
public function test_create_badge() {
$this->assertEquals(badge_message_from_template($message, $params), $result);
}
+ /**
+ * Test badges observer when course module completion event id fired.
+ */
+ public function test_badges_observer_course_module_criteria_review() {
+ $badge = new badge($this->coursebadge);
+ $this->assertFalse($badge->is_issued($this->user->id));
+
+ $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id));
+ $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY));
+ $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_ACTIVITY, 'badgeid' => $badge->id));
+ $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY, 'module_'.$this->module->id => $this->module->id));
+
+ // Set completion for forum activity.
+ $c = new completion_info($this->course);
+ $activities = $c->get_activities();
+ $this->assertEquals(1, count($activities));
+ $this->assertTrue(isset($activities[$this->module->cmid]));
+ $this->assertEquals($activities[$this->module->cmid]->name, $this->module->name);
+
+ $current = $c->get_data($activities[$this->module->cmid], false, $this->user->id);
+ $current->completionstate = COMPLETION_COMPLETE;
+ $current->timemodified = time();
+ $c->internal_set_data($activities[$this->module->cmid], $current);
+
+ // Check if badge is awarded.
+ $this->assertDebuggingCalled('Error baking badge image!');
+ $this->assertTrue($badge->is_issued($this->user->id));
+ }
+
+ /**
+ * Test badges observer when course_completed event is fired.
+ */
+ public function test_badges_observer_course_criteria_review() {
+ $badge = new badge($this->coursebadge);
+ $this->assertFalse($badge->is_issued($this->user->id));
+
+ $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id));
+ $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY));
+ $criteria_overall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_COURSE, 'badgeid' => $badge->id));
+ $criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY, 'course_'.$this->course->id => $this->course->id));
+
+ $ccompletion = new completion_completion(array('course' => $this->course->id, 'userid' => $this->user->id));
+
+ // Mark course as complete.
+ $ccompletion->mark_complete();
+
+ // Check if badge is awarded.
+ $this->assertDebuggingCalled('Error baking badge image!');
+ $this->assertTrue($badge->is_issued($this->user->id));
+ }
}
$events = calendar_get_upcoming($courses, $group, $user, $lookahead, $maxevents);
if (!empty($this->instance)) {
- $this->content->text = calendar_get_block_upcoming($events, 'view.php?view=day&course='.$courseshown.'&');
+ $link = 'view.php?view=day&course='.$courseshown.'&';
+ $showcourselink = ($this->page->course->id == SITEID);
+ $this->content->text = calendar_get_block_upcoming($events, $link, $showcourselink);
}
if (empty($this->content->text)) {
$this->delete_attachments();
$this->remove_associations();
+ // Get record to pass onto the event.
+ $record = $DB->get_record('post', array('id' => $this->id));
$DB->delete_records('post', array('id' => $this->id));
tag_set('post', $this->id, array());
- add_to_log(SITEID, 'blog', 'delete', 'index.php?userid='. $this->userid, 'deleted blog entry with entry id# '. $this->id);
- events_trigger('blog_entry_deleted', $this);
+ $event = \core\event\blog_entry_deleted::create(array('objectid' => $this->id,
+ 'userid' => $this->userid,
+ 'other' => array("record" => (array)$record)
+ ));
+ $event->add_record_snapshot("post", $record);
+ $event->set_custom_data($this);
+ $event->trigger();
}
/**
* Test various blog related events.
*/
public function test_blog_entry_events() {
- global $USER;
+ global $USER, $DB;
$this->setAdminUser();
$this->resetAfterTest();
$this->assertEquals($blog->id, $event->objectid);
$this->assertEquals($USER->id, $event->userid);
$this->assertEquals("post", $event->objecttable);
+
+ // Delete a blog entry.
+ $record = $DB->get_record('post', array('id' => $blog->id));
+ $blog->delete();
+ $events = $sink->get_events();
+ $event = array_pop($events);
+
+ // Validate event data.
+ $this->assertInstanceOf('\core\event\blog_entry_deleted', $event);
+ $this->assertEquals(context_system::instance()->id, $event->contextid);
+ $this->assertEquals($blog->id, $event->objectid);
+ $this->assertEquals($USER->id, $event->userid);
+ $this->assertEquals("post", $event->objecttable);
+ $this->assertEquals($record, $event->get_record_snapshot("post", $blog->id));
+ $this->assertSame('blog_entry_deleted', $event->get_legacy_eventname());
+
}
}
}
$class = 'cachestore_'.$plugin;
if (!class_exists($class)) {
- $plugins = get_plugin_list_with_file('cachestore', 'lib.php');
+ $plugins = core_component::get_plugin_list_with_file('cachestore', 'lib.php');
if (!array_key_exists($plugin, $plugins)) {
throw new cache_exception('Invalid plugin name specified. The plugin does not exist or is not valid.');
}
}
$class = 'cachelock_'.$plugin;
if (!class_exists($class)) {
- $plugins = get_plugin_list_with_file('cachelock', 'lib.php');
+ $plugins = core_component::get_plugin_list_with_file('cachelock', 'lib.php');
if (!array_key_exists($plugin, $plugins)) {
throw new cache_exception('Invalid lock name specified. The plugin does not exist or is not valid.');
}
if (!array_key_exists($name, $this->configstores)) {
throw new cache_exception('The requested instance does not exist.');
}
- $plugins = get_plugin_list_with_file('cachestore', 'lib.php');
+ $plugins = core_component::get_plugin_list_with_file('cachestore', 'lib.php');
if (!array_key_exists($plugin, $plugins)) {
throw new cache_exception('Invalid plugin name specified. The plugin either does not exist or is not valid.');
}
if (!$coreonly) {
$plugintypes = core_component::get_plugin_types();
foreach ($plugintypes as $type => $location) {
- $plugins = get_plugin_list_with_file($type, 'db/caches.php');
+ $plugins = core_component::get_plugin_list_with_file($type, 'db/caches.php');
foreach ($plugins as $plugin => $filepath) {
$component = clean_param($type.'_'.$plugin, PARAM_COMPONENT); // Standardised plugin name.
$files[$component] = $filepath;
*/
public static function get_store_plugin_summaries() {
$return = array();
- $plugins = get_plugin_list_with_file('cachestore', 'lib.php', true);
+ $plugins = core_component::get_plugin_list_with_file('cachestore', 'lib.php', true);
foreach ($plugins as $plugin => $path) {
$class = 'cachestore_'.$plugin;
$return[$plugin] = array(
$strtested = new lang_string('tested', 'cache');
$strnotready = new lang_string('storenotready', 'cache');
-foreach (get_plugin_list_with_file('cachestore', 'lib.php', true) as $plugin => $path) {
+foreach (core_component::get_plugin_list_with_file('cachestore', 'lib.php', true) as $plugin => $path) {
$class = 'cachestore_'.$plugin;
$plugin = get_string('pluginname', 'cachestore_'.$plugin);
return $output;
}
+
+/**
+ * Get a HTML link to a course.
+ *
+ * @param int $courseid the course id
+ * @return string a link to the course (as HTML); empty if the course id is invalid
+ */
+function calendar_get_courselink($courseid) {
+
+ if (!$courseid) {
+ return '';
+ }
+
+ calendar_get_course_cached($coursecache, $courseid);
+ $context = context_course::instance($courseid);
+ $fullname = format_string($coursecache[$courseid]->fullname, true, array('context' => $context));
+ $url = new moodle_url('/course/view.php', array('id' => $courseid));
+ $link = html_writer::link($url, $fullname);
+
+ return $link;
+}
+
+
/**
* Add calendar event metadata
*
}
$icon = $OUTPUT->pix_url('icon', $event->modulename) . '';
- $context = context_course::instance($module->course);
- $fullname = format_string($coursecache[$module->course]->fullname, true, array('context' => $context));
-
$event->icon = '<img src="'.$icon.'" alt="'.$eventtype.'" title="'.$modulename.'" class="icon" />';
$event->referer = '<a href="'.$CFG->wwwroot.'/mod/'.$event->modulename.'/view.php?id='.$module->id.'">'.$event->name.'</a>';
- $event->courselink = '<a href="'.$CFG->wwwroot.'/course/view.php?id='.$module->course.'">'.$fullname.'</a>';
+ $event->courselink = calendar_get_courselink($module->course);
$event->cmid = $module->id;
-
} else if($event->courseid == SITEID) { // Site event
$event->icon = '<img src="'.$OUTPUT->pix_url('i/siteevent') . '" alt="'.get_string('globalevent', 'calendar').'" class="icon" />';
$event->cssclass = 'calendar_event_global';
} else if($event->courseid != 0 && $event->courseid != SITEID && $event->groupid == 0) { // Course event
- calendar_get_course_cached($coursecache, $event->courseid);
-
- $context = context_course::instance($event->courseid);
- $fullname = format_string($coursecache[$event->courseid]->fullname, true, array('context' => $context));
-
$event->icon = '<img src="'.$OUTPUT->pix_url('i/courseevent') . '" alt="'.get_string('courseevent', 'calendar').'" class="icon" />';
- $event->courselink = '<a href="'.$CFG->wwwroot.'/course/view.php?id='.$event->courseid.'">'.$fullname.'</a>';
+ $event->courselink = calendar_get_courselink($event->courseid);
$event->cssclass = 'calendar_event_course';
} else if ($event->groupid) { // Group event
$event->icon = '<img src="'.$OUTPUT->pix_url('i/groupevent') . '" alt="'.get_string('groupevent', 'calendar').'" class="icon" />';
+ $event->courselink = calendar_get_courselink($event->courseid);
$event->cssclass = 'calendar_event_group';
} else if($event->userid) { // User event
$event->icon = '<img src="'.$OUTPUT->pix_url('i/userevent') . '" alt="'.get_string('userevent', 'calendar').'" class="icon" />';
*
* @param array $events list of events
* @param moodle_url|string $linkhref link to event referer
+ * @param boolean $showcourselink whether links to courses should be shown
* @return string|null $content html block content
*/
-function calendar_get_block_upcoming($events, $linkhref = NULL) {
+function calendar_get_block_upcoming($events, $linkhref = NULL, $showcourselink = false) {
$content = '';
$lines = count($events);
if (!$lines) {
}
}
$events[$i]->time = str_replace('»', '<br />»', $events[$i]->time);
+ if ($showcourselink && !empty($events[$i]->courselink)) {
+ $content .= html_writer::div($events[$i]->courselink, 'course');
+ }
$content .= '<div class="date">'.$events[$i]->time.'</div></div>';
if ($i < $lines - 1) $content .= '<hr />';
}
* @return void
*/
public function mark_complete($timecomplete = null) {
+ global $USER;
- // Never change a completion time
+ // Never change a completion time.
if ($this->timecompleted) {
return;
}
- // Use current time if nothing supplied
+ // Use current time if nothing supplied.
if (!$timecomplete) {
$timecomplete = time();
}
- // Set time complete
+ // Set time complete.
$this->timecompleted = $timecomplete;
- // Save record
+ // Save record.
if ($result = $this->_save()) {
- events_trigger('course_completed', $this->get_record_data());
+ $data = $this->get_record_data();
+ $event = \core\event\course_completed::create(
+ array(
+ 'objectid' => $data->id,
+ 'userid' => $USER->id,
+ 'context' => context_course::instance($data->course),
+ 'courseid' => $data->course,
+ 'other' => array('relateduserid' => $data->userid)
+ )
+ );
+ $event->add_record_snapshot('course_completions', $data);
+ $event->trigger();
}
return $result;
// Locking resolves race conditions and is strongly recommended for production servers.
// $CFG->preventfilelocking = false;
//
-// If $CFG->langstringcache is enabled (which should always be in production
-// environment), Moodle keeps aggregated strings in its own internal format
-// optimised for performance. By default, this on-disk cache is created in
-// $CFG->cachedir/lang. In cluster environment, you may wish to specify
-// an alternative location of this cache so that each web server in the cluster
-// uses its own local cache and does not need to access the shared dataroot.
-// Make sure that the web server process has write permission to this location
-// and that it has permission to remove the folder, too (so that the cache can
-// be pruned).
-//
-// $CFG->langcacheroot = '/var/www/moodle/htdocs/altcache/lang';
-//
-// If $CFG->langcache is enabled (which should always be in production
-// environment), Moodle stores the list of available languages in a cache file.
-// By default, the file $CFG->dataroot/languages is used. You may wish to
-// specify an alternative location of this cache file.
-//
-// $CFG->langmenucachefile = '/var/www/moodle/htdocs/altcache/languages';
-//
// Site default language can be set via standard administration interface. If you
// want to have initial error messages for eventual database connection problems
// localized too, you have to set your language code here.
// Prevent JS caching
// $CFG->jsrev = -1; // NOT FOR PRODUCTION SERVERS!
//
-// Prevent core_string_manager on-disk cache
+// Prevent core_string_manager application caching
// $CFG->langstringcache = false; // NOT FOR PRODUCTION SERVERS!
//
// When working with production data on test servers, no emails or other messages
function make_categories_options() {
global $CFG;
require_once($CFG->libdir. '/coursecatlib.php');
- $cats = coursecat::make_categories_list();
+ $cats = coursecat::make_categories_list('', 0, ' / ');
foreach ($cats as $key => $value) {
- $cats[$key] = str_repeat(' ', coursecat::get($key)->depth - 1). $value;
+ // Prefix the value with the number of spaces equal to category depth (number of separators in the value).
+ $cats[$key] = str_repeat(' ', substr_count($value, ' / ')). $value;
}
return $cats;
}
*
* Updates both tables {course_sections} and {course_modules}
*
+ * Note: This function does not use modinfo PROVIDED that the section you are
+ * adding the module to already exists. If the section does not exist, it will
+ * build modinfo if necessary and create the section.
+ *
* @param int|stdClass $courseorid course id or course object
* @param int $cmid id of the module already existing in course_modules table
* @param int $sectionnum relative number of the section (field course_sections.section)
} else {
$courseid = $courseorid;
}
- course_create_sections_if_missing($courseorid, $sectionnum);
// Do not try to use modinfo here, there is no guarantee it is valid!
- $section = $DB->get_record('course_sections', array('course'=>$courseid, 'section'=>$sectionnum), '*', MUST_EXIST);
+ $section = $DB->get_record('course_sections',
+ array('course' => $courseid, 'section' => $sectionnum), '*', IGNORE_MISSING);
+ if (!$section) {
+ // This function call requires modinfo.
+ course_create_sections_if_missing($courseorid, $sectionnum);
+ $section = $DB->get_record('course_sections',
+ array('course' => $courseid, 'section' => $sectionnum), '*', MUST_EXIST);
+ }
+
$modarray = explode(",", trim($section->sequence));
if (empty($section->sequence)) {
$newsequence = "$cmid";
$label = is_null($customlabel) ? get_string('moduleintro') : $customlabel;
$mform->addElement('editor', 'introeditor', $label, array('rows' => 10), array('maxfiles' => EDITOR_UNLIMITED_FILES,
- 'noclean' => true, 'context' => $this->context, 'collapsed' => true));
+ 'noclean' => true, 'context' => $this->context));
$mform->setType('introeditor', PARAM_RAW); // no XSS prevention here, users must be trusted
if ($required) {
$mform->addRule('introeditor', get_string('required'), 'required', null, 'client');
$this->assertEquals(range(0, $course->numsections + 1), $sectionscreated);
}
+ public function test_course_add_cm_to_section() {
+ global $DB;
+ $this->resetAfterTest(true);
+
+ // Create course with 1 section.
+ $course = $this->getDataGenerator()->create_course(
+ array('shortname' => 'GrowingCourse',
+ 'fullname' => 'Growing Course',
+ 'numsections' => 1),
+ array('createsections' => true));
+
+ // Trash modinfo.
+ rebuild_course_cache($course->id, true);
+
+ // Create some cms for testing.
+ $cmids = array();
+ for ($i=0; $i<4; $i++) {
+ $cmids[$i] = $DB->insert_record('course_modules', array('course' => $course->id));
+ }
+
+ // Add it to section that exists.
+ course_add_cm_to_section($course, $cmids[0], 1);
+
+ // Check it got added to sequence.
+ $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 1));
+ $this->assertEquals($cmids[0], $sequence);
+
+ // Add a second, this time using courseid variant of parameters.
+ course_add_cm_to_section($course->id, $cmids[1], 1);
+ $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 1));
+ $this->assertEquals($cmids[0] . ',' . $cmids[1], $sequence);
+
+ // Check modinfo was not rebuilt (important for performance if calling
+ // repeatedly).
+ $this->assertNull($DB->get_field('course', 'modinfo', array('id' => $course->id)));
+
+ // Add one to section that doesn't exist (this might rebuild modinfo).
+ course_add_cm_to_section($course, $cmids[2], 2);
+ $this->assertEquals(3, $DB->count_records('course_sections', array('course' => $course->id)));
+ $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 2));
+ $this->assertEquals($cmids[2], $sequence);
+
+ // Add using the 'before' option.
+ course_add_cm_to_section($course, $cmids[3], 2, $cmids[2]);
+ $this->assertEquals(3, $DB->count_records('course_sections', array('course' => $course->id)));
+ $sequence = $DB->get_field('course_sections', 'sequence', array('course' => $course->id, 'section' => 2));
+ $this->assertEquals($cmids[3] . ',' . $cmids[2], $sequence);
+ }
+
public function test_reorder_sections() {
global $DB;
$this->resetAfterTest(true);
$filepath = '/';
}
+ // Only allow uploads to draft or private areas (private is deprecated but still supported)
+ if (!($fileinfo['component'] == 'user' and in_array($fileinfo['filearea'], array('private', 'draft')))) {
+ throw new coding_exception('File can be uploaded to user private or draft areas only');
+ } else {
+ $component = 'user';
+ $filearea = $fileinfo['filearea'];
+ }
+
+ $itemid = 0;
if (isset($fileinfo['itemid'])) {
+ $itemid = $fileinfo['itemid'];
+ }
+ if ($filearea == 'draft' && $itemid <= 0) {
+ // Generate a draft area for the files.
+ $itemid = file_get_unused_draft_itemid();
+ } else if ($filearea == 'private') {
// TODO MDL-31116 in user private area, itemid is always 0.
$itemid = 0;
- } else {
- throw new coding_exception('itemid cannot be empty');
}
// We need to preserve backword compatibility. Context id is no more a required.
// Get and validate context.
$context = self::get_context_from_params($fileinfo);
self::validate_context($context);
-
- if (!($fileinfo['component'] == 'user' and $fileinfo['filearea'] == 'private')) {
- throw new coding_exception('File can be uploaded to user private area only');
- } else {
- // TODO MDL-31116 hard-coded to use user_private area.
- $component = 'user';
- $filearea = 'private';
+ if (($fileinfo['component'] == 'user' and $fileinfo['filearea'] == 'private')) {
+ debugging('Uploading directly to user private files area is deprecated. Upload to a draft area and then move the files with core_user::add_user_private_files');
}
$browser = get_file_browser();
$module = array(
'name'=>'form_filemanager',
'fullpath'=>'/lib/form/filemanager.js',
- 'requires' => array('core_filepicker', 'base', 'io-base', 'node', 'json', 'core_dndupload', 'panel', 'resize-plugin', 'dd-plugin'),
+ 'requires' => array('moodle-core-notification-dialogue', 'core_filepicker', 'base', 'io-base', 'node', 'json', 'core_dndupload', 'panel', 'resize-plugin', 'dd-plugin'),
'strings' => array(
array('error', 'moodle'), array('info', 'moodle'), array('confirmdeletefile', 'repository'),
array('draftareanofiles', 'repository'), array('entername', 'repository'), array('enternewname', 'repository'),
array('invalidjson', 'repository'), array('popupblockeddownload', 'repository'),
array('unknownoriginal', 'repository'), array('confirmdeletefolder', 'repository'),
array('confirmdeletefilewithhref', 'repository'), array('confirmrenamefolder', 'repository'),
- array('confirmrenamefile', 'repository'), array('newfolder', 'repository')
+ array('confirmrenamefile', 'repository'), array('newfolder', 'repository'), array('edit', 'moodle')
)
);
if (empty($filemanagertemplateloaded)) {
<li class="{!}fp-repo"><a href="#"><img class="{!}fp-repo-icon" alt="'. get_string('repositoryicon', 'repository') .'" width="16" height="16" /> <span class="{!}fp-repo-name"></span></a></li>
</ul>
</div>
- <div class="fp-repo-items">
+ <div class="fp-repo-items" tabindex="0">
<div class="fp-navbar">
<div>
<div class="{!}fp-toolbar">
$context = context_user::instance($USER->id);
$contextid = $context->id;
$component = "user";
- $filearea = "private";
+ $filearea = "draft";
$itemid = 0;
$filepath = "/";
$filename = "Simple.txt";
$this->assertEmpty($file);
// Call the api to create a file.
- core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath,
+ $fileinfo = core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath,
$filename, $filecontent, $contextlevel, $instanceid);
+ // Get the created draft item id.
+ $itemid = $fileinfo['itemid'];
// Make sure the file was created.
$file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
$this->assertNotEmpty($file);
// Make sure no file exists.
- $itemid = 2;
$filename = "Simple2.txt";
$file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
$this->assertEmpty($file);
// Call the api to create a file.
$fileinfo = core_files_external::upload($contextid, $component, $filearea, $itemid,
$filepath, $filename, $filecontent, $contextlevel, $instanceid);
-
- // Make sure itemid is always set to 0.
- $this->assertEquals(0, $fileinfo['itemid']);
+ $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
+ $this->assertNotEmpty($file);
// Let us try creating a file using contextlevel and instance id.
- $itemid = 0;
$filename = "Simple5.txt";
$contextid = 0;
$contextlevel = "user";
$this->assertEmpty($file);
$fileinfo = core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath,
$filename, $filecontent, $contextlevel, $instanceid);
- $this->assertEmpty($file);
+ $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
+ $this->assertNotEmpty($file);
// Make sure the same file cannot be created again.
$this->setExpectedException("moodle_exception");
}
/*
- * Make sure only private area is allowed in core_files_external::upload().
+ * Make sure only private or draft areas are allowed in core_files_external::upload().
*/
public function test_upload_param_area() {
global $USER;
$contextid = $context->id;
$component = "user";
$filearea = "draft";
- $itemid = 0;
+ $itemid = file_get_unused_draft_itemid();
$filepath = "/";
$filename = "Simple4.txt";
$filecontent = base64_encode("Let us create a nice simple file");
$contextlevel = null;
$instanceid = null;
- // Make sure exception is thrown.
- $this->setExpectedException("coding_exception");
- core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath,
- $filename, $filecontent, $contextlevel, $instanceid);
+ // Make sure the file is created.
+ @core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath, $filename, $filecontent);
+ $browser = get_file_browser();
+ $file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
+ $this->assertNotEmpty($file);
}
/*
$filename = "Simple4.txt";
$filecontent = base64_encode("Let us create a nice simple file");
- // Make sure the file is created.
@core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath, $filename, $filecontent);
+
+ // Assert debugging called (deprecation warning).
+ $this->assertDebuggingCalled();
+
+ // Make sure the file is created.
$browser = get_file_browser();
$file = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename);
$this->assertNotEmpty($file);
}
-}
\ No newline at end of file
+}
if ($type == 'grade' and empty($object->id)) {
$object->insert();
}
+ if (!$object->can_control_visibility()) {
+ print_error('componentcontrolsvisibility', 'grades', $returnurl);
+ }
$object->set_hidden(1, true);
}
break;
if ($type == 'grade' and empty($object->id)) {
$object->insert();
}
+ if (!$object->can_control_visibility()) {
+ print_error('componentcontrolsvisibility', 'grades', $returnurl);
+ }
$object->set_hidden(0, true);
}
break;
public $columns = array();
/**
- * @var object $gtree @see grade/lib.php
+ * @var grade_tree $gtree @see grade/lib.php
*/
public $gtree;
public function get_hiding_icon($element, $gpr) {
global $CFG, $OUTPUT;
+ if (!$element['object']->can_control_visibility()) {
+ return '';
+ }
+
if (!has_capability('moodle/grade:manage', $this->context) and
!has_capability('moodle/grade:hide', $this->context)) {
return '';
// Continue with lib loading
require_once($CFG->libdir.'/classes/text.php');
+require_once($CFG->libdir.'/classes/string_manager.php');
+require_once($CFG->libdir.'/classes/string_manager_install.php');
+require_once($CFG->libdir.'/classes/string_manager_standard.php');
require_once($CFG->libdir.'/weblib.php');
require_once($CFG->libdir.'/outputlib.php');
require_once($CFG->libdir.'/dmllib.php');
$string['entrytitle'] = 'Entry title';
$string['entryupdated'] = 'Blog entry updated';
$string['evententryadded'] = 'Blog entry added';
+$string['evententrydeleted'] = 'Blog entry deleted';
$string['externalblogcrontime'] = 'External blog cron schedule';
$string['externalblogdeleteconfirm'] = 'Unregister this external blog?';
$string['externalblogdeleted'] = 'External blog unregistered';
$string['cachedef_eventinvalidation'] = 'Event invalidation';
$string['cachedef_groupdata'] = 'Course group information';
$string['cachedef_htmlpurifier'] = 'HTML Purifier - cleaned content';
+$string['cachedef_langmenu'] = 'List of available languages';
$string['cachedef_locking'] = 'Locking';
$string['cachedef_observers'] = 'Event observers';
$string['cachedef_plugininfo_base'] = 'Plugin info - base';
$string['err_nousers'] = 'There are no students on this course or group for whom completion information is displayed. (By default, completion information is displayed only for students, so if there are no students, you will see this error. Administrators can alter this option via the admin screens.)';
$string['err_settingslocked'] = 'One or more students have already completed a criteria so the settings have been locked. Unlocking the completion criteria settings will delete any existing user data and may cause confusion.';
$string['err_system'] = 'An internal error occurred in the completion system. (System administrators can enable debugging information to see more detail.)';
+$string['eventcoursecompleted'] = 'Course completed';
+$string['eventcoursemodulecompletionupdated'] = 'Course module completion updated';
$string['excelcsvdownload'] = 'Download in Excel-compatible format (.csv)';
$string['fraction'] = 'Fraction';
$string['graderequired'] = 'Required course grade';
$string['err_required'] = 'You must supply a value here.';
$string['general'] = 'General';
$string['hideadvanced'] = 'Hide advanced';
-$string['hideeditortoolbar'] = 'Hide editing tools';
$string['hour'] = 'Hour';
$string['minute'] = 'Minute';
$string['miscellaneoussettings'] = 'Miscellaneous settings';
$string['showadvanced'] = 'Show advanced';
$string['showless'] = 'Show less...';
$string['showmore'] = 'Show more...';
-$string['showeditortoolbar'] = 'Show editing tools';
$string['somefieldsrequired'] = 'There are required fields in this form marked {$a}.';
$string['time'] = 'Time';
$string['timeunit'] = 'Time unit';
<p>It contains easy instructions to complete your registration.</p>
<p>If you continue to have difficulty, contact the site administrator.</p>';
$string['emaildigest'] = 'Email digest type';
+$string['emaildigest_help'] = 'This is the daily digest setting that forums will use by default.
+
+* No digest - you will receive one e-mail per forum post;
+* Digest - complete posts - you will receive one digest e-mail per day containing the complete contents of each forum post;
+* Digest - subjects only - you will receive one digest e-mail per day containing just the subject of each forum post.
+
+You can also choose a different setting for each forum if you wish.';
$string['emaildigestcomplete'] = 'Complete (daily email with full posts)';
$string['emaildigestoff'] = 'No digest (single email per forum post)';
$string['emaildigestsubjects'] = 'Subjects (daily email with subjects only)';
$string['errorbadroleshortname'] = 'Incorrect role short name';
$string['errorexistsrolename'] = 'Role name already exists';
$string['errorexistsroleshortname'] = 'Role name already exists';
+$string['eventroleallowassignupdated'] = 'Allow role assignment';
+$string['eventroleallowoverrideupdated'] = 'Allow role override';
+$string['eventroleallowswitchupdated'] = 'Allow role switch';
$string['eventroleassigned'] = 'Role assigned';
+$string['eventrolecapabilitiesupdated'] = 'Role capabilities updated';
+$string['eventroledeleted'] = 'Role deleted';
$string['eventroleunassigned'] = 'Role unassigned';
$string['existingadmins'] = 'Current site administrators';
$string['existingusers'] = '{$a} existing users';
$string['unknownoptionkey'] = 'Unknown option key ({$a})';
$string['unnamedstringparam'] = 'A string parameter is unnamed.';
$string['updateusersettings'] = 'Update';
+$string['uploadfiles'] = 'Can upload files';
+$string['uploadfiles_help'] = 'If enabled, any user can upload files with their security keys to their own private files area or a draft file area. Any user file quotas apply.';
$string['userasclients'] = 'Users as clients with token';
$string['userasclientsdescription'] = 'The following steps help you to set up the Moodle web service for users as clients. These steps also help to set up the recommended token (security keys) authentication method. In this use case, the user will generate his token from the security keys page via My profile settings.';
$string['usermissingcaps'] = 'Missing capabilities: {$a}';
$DB->delete_records('role_names', array('roleid'=>$roleid));
$DB->delete_records('role_context_levels', array('roleid'=>$roleid));
- // finally delete the role itself
- // get this before the name is gone for logging
- $rolename = $DB->get_field('role', 'name', array('id'=>$roleid));
+ // Get role record before it's deleted.
+ $role = $DB->get_record('role', array('id'=>$roleid));
+ // Finally delete the role itself.
$DB->delete_records('role', array('id'=>$roleid));
- add_to_log(SITEID, 'role', 'delete', 'admin/roles/action=delete&roleid='.$roleid, $rolename, '');
+ // Trigger event.
+ $event = \core\event\role_deleted::create(
+ array(
+ 'context' => context_system::instance(),
+ 'objectid' => $roleid,
+ 'other' =>
+ array(
+ 'name' => $role->name,
+ 'shortname' => $role->shortname,
+ 'description' => $role->description,
+ 'archetype' => $role->archetype
+ )
+ )
+ );
+ $event->add_record_snapshot('role', $role);
+ $event->trigger();
return true;
}
}
}
-/**
- * Triggered when 'course_completed' event happens.
- *
- * @param object $eventdata
- * @return boolean
- */
-function badges_award_handle_course_criteria_review(stdClass $eventdata) {
- global $DB, $CFG;
-
- if (!empty($CFG->enablebadges)) {
- $userid = $eventdata->userid;
- $courseid = $eventdata->course;
-
- // Need to take into account that course can be a part of course_completion and courseset_completion criteria.
- if ($rs = $DB->get_records('badge_criteria_param', array('name' => 'course_' . $courseid, 'value' => $courseid))) {
- foreach ($rs as $r) {
- $crit = $DB->get_record('badge_criteria', array('id' => $r->critid), 'badgeid, criteriatype', MUST_EXIST);
- $badge = new badge($crit->badgeid);
- if (!$badge->is_active() || $badge->is_issued($userid)) {
- continue;
- }
-
- if ($badge->criteria[$crit->criteriatype]->review($userid)) {
- $badge->criteria[$crit->criteriatype]->mark_complete($userid);
-
- if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
- $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
- $badge->issue($userid);
- }
- }
- }
- }
- }
-
- return true;
-}
-
-/**
- * Triggered when 'activity_completed' event happens.
- *
- * @param object $eventdata
- * @return boolean
- */
-function badges_award_handle_activity_criteria_review(stdClass $eventdata) {
- global $DB, $CFG;
-
- if (!empty($CFG->enablebadges)) {
- $userid = $eventdata->userid;
- $mod = $eventdata->coursemoduleid;
-
- if ($eventdata->completionstate == COMPLETION_COMPLETE
- || $eventdata->completionstate == COMPLETION_COMPLETE_PASS
- || $eventdata->completionstate == COMPLETION_COMPLETE_FAIL) {
- // Need to take into account that there can be more than one badge with the same activity in its criteria.
- if ($rs = $DB->get_records('badge_criteria_param', array('name' => 'module_' . $mod, 'value' => $mod))) {
- foreach ($rs as $r) {
- $bid = $DB->get_field('badge_criteria', 'badgeid', array('id' => $r->critid), MUST_EXIST);
- $badge = new badge($bid);
- if (!$badge->is_active() || $badge->is_issued($userid)) {
- continue;
- }
-
- if ($badge->criteria[BADGE_CRITERIA_TYPE_ACTIVITY]->review($userid)) {
- $badge->criteria[BADGE_CRITERIA_TYPE_ACTIVITY]->mark_complete($userid);
-
- if ($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($userid)) {
- $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($userid);
- $badge->issue($userid);
- }
- }
- }
- }
- }
- }
-
- return true;
-}
-
/**
* Triggered when 'user_updated' event happens.
*
// Finds the button inside the DOM, is a modal window, so should be unique.
$classname = 'fp-file-' . $action;
- $button = $this->find('css', '.yui3-panel-focused button.' . $classname, $exception);
+ $button = $this->find('css', '.moodle-dialogue-focused button.' . $classname, $exception);
$button->click();
}
$exception = new ExpectationException('The file manager is taking too much time to finish the current action', $this->getSession());
- $this->find(
- 'xpath',
- "//div[@id='filesskin']" .
- "/descendant::div[contains(concat(' ', @class, ' '), ' yui3-widget-mask ')]" .
- "[contains(concat(' ', @style, ' '), ' display: none; ')]",
- $exception
- );
+ $this->find(
+ 'xpath',
+ "//div[contains(concat(' ', @class, ' '), ' moodle-dialogue-lightbox ')][contains(@style, 'display: none;')]",
+ $exception
+ );
}
/**
protected static $subsystems = null;
/** @var null list of all known classes that can be autoloaded */
protected static $classmap = null;
+ /** @var null list of some known files that can be included. */
+ protected static $filemap = null;
+ /** @var array list of the files to map. */
+ protected static $filestomap = array('lib.php', 'settings.php');
/**
* Class loader for Frankenstyle named classes in standard locations.
self::$plugins = $cache['plugins'];
self::$subsystems = $cache['subsystems'];
self::$classmap = $cache['classmap'];
+ self::$filemap = $cache['filemap'];
return;
}
self::$plugins = $cache['plugins'];
self::$subsystems = $cache['subsystems'];
self::$classmap = $cache['classmap'];
+ self::$filemap = $cache['filemap'];
return;
}
// Note: we do not verify $CFG->admin here intentionally,
'plugintypes' => self::$plugintypes,
'plugins' => self::$plugins,
'classmap' => self::$classmap,
+ 'filemap' => self::$filemap,
);
return '<?php
}
self::fill_classmap_cache();
+ self::fill_filemap_cache();
}
/**
self::$classmap['collatorlib'] = "$CFG->dirroot/lib/classes/collator.php";
}
+
+ /**
+ * Fills up the cache defining what plugins have certain files.
+ *
+ * @see self::get_plugin_list_with_file
+ * @return void
+ */
+ protected static function fill_filemap_cache() {
+ global $CFG;
+
+ self::$filemap = array();
+
+ foreach (self::$filestomap as $file) {
+ if (!isset(self::$filemap[$file])) {
+ self::$filemap[$file] = array();
+ }
+ foreach (self::$plugins as $plugintype => $plugins) {
+ if (!isset(self::$filemap[$file][$plugintype])) {
+ self::$filemap[$file][$plugintype] = array();
+ }
+ foreach ($plugins as $pluginname => $fulldir) {
+ if (file_exists("$fulldir/$file")) {
+ self::$filemap[$file][$plugintype][$pluginname] = "$fulldir/$file";
+ }
+ }
+ }
+ }
+ }
+
/**
* Find classes in directory and recurse to subdirs.
* @param string $component
return $pluginclasses;
}
+ /**
+ * Get a list of all the plugins of a given type that contain a particular file.
+ *
+ * @param string $plugintype the type of plugin, e.g. 'mod' or 'report'.
+ * @param string $file the name of file that must be present in the plugin.
+ * (e.g. 'view.php', 'db/install.xml').
+ * @param bool $include if true (default false), the file will be include_once-ed if found.
+ * @return array with plugin name as keys (e.g. 'forum', 'courselist') and the path
+ * to the file relative to dirroot as value (e.g. "$CFG->dirroot/mod/forum/view.php").
+ */
+ public static function get_plugin_list_with_file($plugintype, $file, $include = false) {
+ global $CFG; // Necessary in case it is referenced by included PHP scripts.
+ $pluginfiles = array();
+
+ if (isset(self::$filemap[$file])) {
+ // If the file was supposed to be mapped, then it should have been set in the array.
+ if (isset(self::$filemap[$file][$plugintype])) {
+ $pluginfiles = self::$filemap[$file][$plugintype];
+ }
+ } else {
+ // Old-style search for non-cached files.
+ $plugins = self::get_plugin_list($plugintype);
+ foreach ($plugins as $plugin => $fulldir) {
+ $path = $fulldir . '/' . $file;
+ if (file_exists($path)) {
+ $pluginfiles[$plugin] = $path;
+ }
+ }
+ }
+
+ if ($include) {
+ foreach ($pluginfiles as $path) {
+ include_once($path);
+ }
+ }
+
+ return $pluginfiles;
+ }
+
/**
* Returns the exact absolute path to plugin directory.
*
return $return;
}
+ /**
+ * Returns hash of all versions including core and all plugins.
+ *
+ * This is relatively slow and not fully cached, use with care!
+ *
+ * @return string sha1 hash
+ */
+ public static function get_all_versions_hash() {
+ global $CFG;
+
+ self::init();
+
+ $versions = array();
+
+ // Main version first.
+ $version = null;
+ include($CFG->dirroot.'/version.php');
+ $versions['core'] = $version;
+
+ // The problem here is tha the component cache might be stable,
+ // we want this to work also on frontpage without resetting the component cache.
+ $usecache = false;
+ if (CACHE_DISABLE_ALL or (defined('IGNORE_COMPONENT_CACHE') and IGNORE_COMPONENT_CACHE)) {
+ $usecache = true;
+ }
+
+ // Now all plugins.
+ $plugintypes = core_component::get_plugin_types();
+ foreach ($plugintypes as $type => $typedir) {
+ if ($usecache) {
+ $plugs = core_component::get_plugin_list($type);
+ } else {
+ $plugs = self::fetch_plugins($type, $typedir);
+ }
+ foreach ($plugs as $plug => $fullplug) {
+ if ($type === 'mod') {
+ $module = new stdClass();
+ $module->version = null;
+ include($fullplug.'/version.php');
+ $versions[$plug] = $module->version;
+ } else {
+ $plugin = new stdClass();
+ $plugin->version = null;
+ @include($fullplug.'/version.php');
+ $versions[$plug] = $plugin->version;
+ }
+ }
+ }
+
+ return sha1(serialize($versions));
+ }
+
/**
* Invalidate opcode cache for given file, this is intended for
* php files that are stored in dataroot.
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Abstract assessable submitted event.
+ *
+ * @package core
+ * @copyright 2013 Frédéric Massart
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Abstract assessable submitted event class.
+ *
+ * This class has to be extended by any event which represent that some content,
+ * on which someone will be assessed, has been submitted and so made available
+ * for grading. See {@link \core\event\assessable_uploaded} for when the content
+ * has just been uploaded.
+ *
+ * Both events could be triggered in a row, first the uploaded, then the submitted.
+ *
+ * @package core
+ * @copyright 2013 Frédéric Massart
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+abstract class assessable_submitted extends \core\event\base {
+
+ /**
+ * Init method.
+ *
+ * @return void
+ */
+ protected function init() {
+ $this->data['crud'] = 'u';
+ $this->data['level'] = 50; // TODO MDL-37658.
+ }
+
+ /**
+ * Custom validation.
+ *
+ * @throws \coding_exception on error.
+ * @return void
+ */
+ protected function validate_data() {
+ if (!$this->context->contextlevel === CONTEXT_MODULE) {
+ throw new \coding_exception('Content level must be CONTEXT_MODULE.');
+ }
+ }
+
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Abstract assessable uploaded event.
+ *
+ * @package core
+ * @copyright 2013 Frédéric Massart
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Abstract assessable uploaded event class.
+ *
+ * This class has to be extended by any event which represent that some content,
+ * on which someone will be assessed, has been uploaded. This is different
+ * than other events such as assessable_submitted, which means that the content
+ * has been submitted and made available for grading.
+ *
+ * Both events could be triggered in a row, first the uploaded, then the submitted.
+ *
+ * @package core
+ * @copyright 2013 Frédéric Massart
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+abstract class assessable_uploaded extends \core\event\base {
+
+ /**
+ * Init method.
+ *
+ * @return void
+ */
+ protected function init() {
+ $this->data['crud'] = 'c';
+ $this->data['level'] = 50; // TODO MDL-37658.
+ }
+
+ /**
+ * Validation that should be shared among child classes.
+ *
+ * @throws \coding_exception when validation fails.
+ * @return void
+ */
+ protected function validate_data() {
+ if (!$this->context->contextlevel === CONTEXT_MODULE) {
+ throw new \coding_exception('Content level must be CONTEXT_MODULE.');
+ } else if (!isset($this->other['pathnamehashes']) || !is_array($this->other['pathnamehashes'])) {
+ throw new \coding_exception('pathnamehashes must be set in $other and must be an array.');
+ } else if (!isset($this->other['content']) || !is_string($this->other['content'])) {
+ throw new \coding_exception('content must be set in $other and must be a string.');
+ }
+ }
+
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+/**
+ * Event for when a new blog entry is deleted.
+ *
+ * @package core_blog
+ * @copyright 2013 Ankit Agarwal
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace core\event;
+
+/**
+ * class blog_entry_deleted
+ *
+ * Event for when a new blog entry is deleted.
+ *
+ * @package core_blog
+ * @copyright 2013 Ankit Agarwal
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class blog_entry_deleted extends \core\event\base {
+
+ /** @var \blog_entry A reference to the active blog_entry object. */
+ protected $customobject;
+
+ /**
+ * Set basic event properties.
+ */
+ protected function init() {
+ $this->context = \context_system::instance();
+ $this->data['objecttable'] = 'post';
+ $this->data['crud'] = 'd';
+ // TODO: MDL-37658 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised general event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return get_string("evententrydeleted", "core_blog");
+ }
+
+ /**
+ * Set custom data of the event.
+ *
+ * @param \blog_entry $data A reference to the active blog_entry object.
+ */
+ public function set_custom_data($data) {
+ $this->customobject = $data;
+ }
+
+ /**
+ * Returns non-localised description of what happened.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return "Blog entry ".$this->other['record']['subject']." was deleted by user with id ".$this->userid;
+ }
+
+ /**
+ * Does this event replace legacy event?
+ *
+ * @return string legacy event name
+ */
+ public static function get_legacy_eventname() {
+ return 'blog_entry_deleted';
+ }
+
+ /**
+ * Legacy event data if get_legacy_eventname() is not empty.
+ *
+ * @return \blog_entry
+ */
+ protected function get_legacy_eventdata() {
+ return $this->customobject;
+ }
+
+ /**
+ * replace add_to_log() statement.
+ *
+ * @return array of parameters to be passed to legacy add_to_log() function.
+ */
+ protected function get_legacy_logdata() {
+ return array (SITEID, 'blog', 'delete', 'index.php?userid='.$this->userid, 'deleted blog entry with entry id# '. $this->objectid);
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+namespace core\event;
+
+/**
+ * Event when course completed.
+ *
+ * @package core_event
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class course_completed extends base {
+
+ /**
+ * Initialise required event data properties.
+ */
+ protected function init() {
+ $this->data['objecttable'] = 'course_completions';
+ $this->data['crud'] = 'u';
+ // TODO: MDL-37658 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return new get_string('eventcoursecompleted', 'core_completion');
+ }
+
+ /**
+ * Returns non-localised event description with id's for admin use only.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'Course completed by user '.$this->userid;
+ }
+
+ /**
+ * Returns relevant URL.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new moodle_url('/report/completion/index.php', array('course' => $this->courseid));
+ }
+
+ /**
+ * Return name of the legacy event, which is replaced by this event.
+ *
+ * @return string legacy event name
+ */
+ public static function get_legacy_eventname() {
+ return 'course_completed';
+ }
+
+ /**
+ * Return course_completed legacy event data.
+ *
+ * @return \stdClass completion data.
+ */
+ protected function get_legacy_eventdata() {
+ return $this->get_record_snapshot('course_completions', $this->objectid);
+ }
+
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+namespace core\event;
+
+/**
+ * Event when course module completion is updated.
+ *
+ * @package core
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class course_module_completion_updated extends base {
+
+ /**
+ * Initialise required event data properties.
+ */
+ protected function init() {
+ $this->data['objecttable'] = 'course_modules_completion';
+ $this->data['crud'] = 'u';
+ // TODO: MDL-37658 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return new get_string('eventcoursemodulecompletionupdated', 'core_completion');
+ }
+
+ /**
+ * Returns non-localised event description with id's for admin use only.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'Course module completion updated for user ' . $this->userid;
+ }
+
+ /**
+ * Returns relevant URL.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new moodle_url('/report/completion/index.php', array('course' => $this->courseid));
+ }
+
+ /**
+ * Return name of the legacy event, which is replaced by this event.
+ *
+ * @return string legacy event name
+ */
+ public static function get_legacy_eventname() {
+ return 'activity_completion_changed';
+ }
+
+ /**
+ * Return course module completion legacy event data.
+ *
+ * @return \stdClass completion data.
+ */
+ protected function get_legacy_eventdata() {
+ return $this->get_record_snapshot('course_modules_completion', $this->objectid);
+ }
+
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+namespace core\event;
+
+/**
+ * Event when role allow assignments is updated.
+ *
+ * @package core_event
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class role_allow_assign_updated extends base {
+ /**
+ * Initialise event parameters.
+ */
+ protected function init() {
+ $this->data['crud'] = 'u';
+ // TODO: MDL-41040 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return get_string('eventroleallowassignupdated', 'role');
+ }
+
+ /**
+ * Returns non-localised event description with id's for admin use only.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'Allow role assignments updated by user ' . $this->userid;
+ }
+
+ /**
+ * Returns relevant URL.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new \moodle_url('/admin/roles/allow.php', array('mode' => 'assign'));
+ }
+
+ /**
+ * Returns array of parameters to be passed to legacy add_to_log() function.
+ *
+ * @return array
+ */
+ protected function get_legacy_logdata() {
+ return array(SITEID, 'role', 'edit allow assign', 'admin/roles/allow.php?mode=assign');
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+namespace core\event;
+
+/**
+ * Event when role allow override is updated.
+ *
+ * @package core_event
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class role_allow_override_updated extends base {
+ /**
+ * Initialise event parameters.
+ */
+ protected function init() {
+ $this->data['crud'] = 'u';
+ // TODO: MDL-41040 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return get_string('eventroleallowoverrideupdated', 'role');
+ }
+
+ /**
+ * Returns non-localised event description with id's for admin use only.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'Allow role override updated by user ' . $this->userid;
+ }
+
+ /**
+ * Returns relevant URL.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new \moodle_url('/admin/roles/allow.php', array('mode' => 'override'));
+ }
+
+ /**
+ * Returns array of parameters to be passed to legacy add_to_log() function.
+ *
+ * @return array
+ */
+ protected function get_legacy_logdata() {
+ return array(SITEID, 'role', 'edit allow override', 'admin/roles/allow.php?mode=override');
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+namespace core\event;
+
+/**
+ * Event when role allow switch is updated.
+ *
+ * @package core_event
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class role_allow_switch_updated extends base {
+ /**
+ * Initialise event parameters.
+ */
+ protected function init() {
+ $this->data['crud'] = 'u';
+ // TODO: MDL-41040 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return get_string('eventroleallowswitchupdated', 'role');
+ }
+
+ /**
+ * Returns non-localised event description with id's for admin use only.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'Allow role switch updated by user ' . $this->userid;
+ }
+
+ /**
+ * Returns relevant URL.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new \moodle_url('/admin/roles/allow.php', array('mode' => 'switch'));
+ }
+
+ /**
+ * Returns array of parameters to be passed to legacy add_to_log() function.
+ *
+ * @return array
+ */
+ protected function get_legacy_logdata() {
+ return array(SITEID, 'role', 'edit allow switch', 'admin/roles/allow.php?mode=switch');
+ }
+}
protected function get_legacy_eventdata() {
return $this->get_record_snapshot('role_assignments', $this->data['other']['id']);
}
+
+ /**
+ * Returns array of parameters to be passed to legacy add_to_log() function.
+ *
+ * @return array
+ */
+ protected function get_legacy_logdata() {
+ $roles = get_all_roles();
+ $rolenames = role_fix_names($roles, $this->get_context(), ROLENAME_ORIGINAL, true);
+ return array($this->courseid, 'role', 'assign', 'admin/roles/assign.php?contextid='.$this->contextid.'&roleid='.$this->objectid,
+ $rolenames[$this->objectid], '', $this->userid);
+ }
}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+namespace core\event;
+
+/**
+ * Role updated event.
+ *
+ * @package core_event
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class role_capabilities_updated extends base {
+ /** @var array Legacy log data */
+ protected $legacylogdata = null;
+
+ /**
+ * Initialise event parameters.
+ */
+ protected function init() {
+ $this->data['objecttable'] = 'role';
+ $this->data['crud'] = 'u';
+ // TODO: MDL-41040 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return get_string('eventrolecapabilitiesupdated', 'role');
+ }
+
+ /**
+ * Returns non-localised event description with id's for admin use only.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'Capabilities for role ' . $this->objectid . ' are updated by user ' . $this->userid;
+ }
+
+ /**
+ * Returns relevant URL.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ if ($this->contextlevel === CONTEXT_SYSTEM) {
+ return new \moodle_url('admin/roles/define.php', array('action' => 'view', 'roleid' => $this->objectid));
+ } else {
+ return new \moodle_url('/admin/roles/override.php', array('contextid' => $this->contextid, 'roleid' => $this->objectid));
+ }
+ }
+
+ /**
+ * Sets legacy log data.
+ *
+ * @param array $legacylogdata
+ * @return void
+ */
+ public function set_legacy_logdata($legacylogdata) {
+ $this->legacylogdata = $legacylogdata;
+ }
+
+ /**
+ * Returns array of parameters to be passed to legacy add_to_log() function.
+ *
+ * @return null|array
+ */
+ protected function get_legacy_logdata() {
+ return $this->legacylogdata;
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+namespace core\event;
+
+/**
+ * Role assigned event.
+ *
+ * @package core_event
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class role_deleted extends base {
+ /**
+ * Initialise event parameters.
+ */
+ protected function init() {
+ $this->data['objecttable'] = 'role';
+ $this->data['crud'] = 'd';
+ // TODO: MDL-41040 set level.
+ $this->data['level'] = 50;
+ }
+
+ /**
+ * Returns localised event name.
+ *
+ * @return string
+ */
+ public static function get_name() {
+ return get_string('eventroledeleted', 'role');
+ }
+
+ /**
+ * Returns non-localised event description with id's for admin use only.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'Role ' . $this->objectid . ' is deleted by user ' . $this->userid;
+ }
+
+ /**
+ * Returns relevant URL.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new \moodle_url('/admin/roles/manage.php');
+ }
+
+ /**
+ * Returns array of parameters to be passed to legacy add_to_log() function.
+ *
+ * @return array
+ */
+ protected function get_legacy_logdata() {
+ return array(SITEID, 'role', 'delete', 'admin/roles/manage.php?action=delete&roleid='.$this->objectid, $this->other['shortname'], '');
+ }
+}
protected function get_legacy_eventdata() {
return $this->get_record_snapshot('role_assignments', $this->data['other']['id']);
}
+
+ /**
+ * Returns array of parameters to be passed to legacy add_to_log() function.
+ *
+ * @return array
+ */
+ protected function get_legacy_logdata() {
+ $roles = get_all_roles();
+ $rolenames = role_fix_names($roles, $this->get_context(), ROLENAME_ORIGINAL, true);
+ return array($this->courseid, 'role', 'unassign', 'admin/roles/assign.php?contextid='.$this->contextid.'&roleid='.$this->objectid,
+ $rolenames[$this->objectid], '', $this->userid);
+ }
}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * String manager interface.
+ *
+ * @package core
+ * @copyright 2010 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Interface for string manager
+ *
+ * Interface describing class which is responsible for getting
+ * of localised strings from language packs.
+ *
+ * @package core
+ * @copyright 2010 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+interface core_string_manager {
+ /**
+ * Get String returns a requested string
+ *
+ * @param string $identifier The identifier of the string to search for
+ * @param string $component The module the string is associated with
+ * @param string|object|array $a An object, string or number that can be used
+ * within translation strings
+ * @param string $lang moodle translation language, null means use current
+ * @return string The String !
+ */
+ public function get_string($identifier, $component = '', $a = null, $lang = null);
+
+ /**
+ * Does the string actually exist?
+ *
+ * get_string() is throwing debug warnings, sometimes we do not want them
+ * or we want to display better explanation of the problem.
+ *
+ * Use with care!
+ *
+ * @param string $identifier The identifier of the string to search for
+ * @param string $component The module the string is associated with
+ * @return bool true if exists
+ */
+ public function string_exists($identifier, $component);
+
+ /**
+ * Returns a localised list of all country names, sorted by country keys.
+ * @param bool $returnall return all or just enabled
+ * @param string $lang moodle translation language, null means use current
+ * @return array two-letter country code => translated name.
+ */
+ public function get_list_of_countries($returnall = false, $lang = null);
+
+ /**
+ * Returns a localised list of languages, sorted by code keys.
+ *
+ * @param string $lang moodle translation language, null means use current
+ * @param string $standard language list standard
+ * iso6392: three-letter language code (ISO 639-2/T) => translated name.
+ * @return array language code => translated name
+ */
+ public function get_list_of_languages($lang = null, $standard = 'iso6392');
+
+ /**
+ * Checks if the translation exists for the language
+ *
+ * @param string $lang moodle translation language code
+ * @param bool $includeall include also disabled translations
+ * @return bool true if exists
+ */
+ public function translation_exists($lang, $includeall = true);
+
+ /**
+ * Returns localised list of installed translations
+ * @param bool $returnall return all or just enabled
+ * @return array moodle translation code => localised translation name
+ */
+ public function get_list_of_translations($returnall = false);
+
+ /**
+ * Returns localised list of currencies.
+ *
+ * @param string $lang moodle translation language, null means use current
+ * @return array currency code => localised currency name
+ */
+ public function get_list_of_currencies($lang = null);
+
+ /**
+ * Load all strings for one component
+ * @param string $component The module the string is associated with
+ * @param string $lang
+ * @param bool $disablecache Do not use caches, force fetching the strings from sources
+ * @param bool $disablelocal Do not use customized strings in xx_local language packs
+ * @return array of all string for given component and lang
+ */
+ public function load_component_strings($component, $lang, $disablecache=false, $disablelocal=false);
+
+ /**
+ * Invalidates all caches, should the implementation use any
+ * @param bool $phpunitreset true means called from our PHPUnit integration test reset
+ */
+ public function reset_caches($phpunitreset = false);
+
+ /**
+ * Returns string revision counter, this is incremented after any
+ * string cache reset.
+ * @return int lang string revision counter, -1 if unknown
+ */
+ public function get_revision();
+}
+
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Installation time string manager.
+ *
+ * @package core
+ * @copyright 2010 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+
+/**
+ * Fetches minimum strings for installation
+ *
+ * Minimalistic string fetching implementation
+ * that is used in installer before we fetch the wanted
+ * language pack from moodle.org lang download site.
+ *
+ * @package core
+ * @copyright 2010 Petr Skoda (http://skodak.org)
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class core_string_manager_install implements core_string_manager {
+ /** @var string location of pre-install packs for all langs */
+ protected $installroot;
+
+ /**
+ * Crate new instance of install string manager
+ */
+ public function __construct() {
+ global $CFG;
+ $this->installroot = "$CFG->dirroot/install/lang";
+ }
+
+ /**
+ * Load all strings for one component
+ * @param string $component The module the string is associated with
+ * @param string $lang
+ * @param bool $disablecache Do not use caches, force fetching the strings from sources
+ * @param bool $disablelocal Do not use customized strings in xx_local language packs
+ * @return array of all string for given component and lang
+ */
+ public function load_component_strings($component, $lang, $disablecache = false, $disablelocal = false) {
+ // Not needed in installer.
+ return array();
+ }
+
+ /**
+ * Does the string actually exist?
+ *
+ * get_string() is throwing debug warnings, sometimes we do not want them
+ * or we want to display better explanation of the problem.
+ *
+ * Use with care!
+ *
+ * @param string $identifier The identifier of the string to search for
+ * @param string $component The module the string is associated with
+ * @return boot true if exists
+ */
+ public function string_exists($identifier, $component) {
+ // Simple old style hack ;).
+ $str = get_string($identifier, $component);
+ return (strpos($str, '[[') === false);
+ }
+
+ /**
+ * Get String returns a requested string
+ *
+ * @param string $identifier The identifier of the string to search for
+ * @param string $component The module the string is associated with
+ * @param string|object|array $a An object, string or number that can be used
+ * within translation strings
+ * @param string $lang moodle translation language, null means use current
+ * @return string The String !
+ */
+ public function get_string($identifier, $component = '', $a = null, $lang = null) {
+ if (!$component) {
+ $component = 'moodle';
+ }
+
+ if ($lang === null) {
+ $lang = current_language();
+ }
+
+ // Get parent lang.
+ $parent = '';
+ if ($lang !== 'en' and $identifier !== 'parentlanguage' and $component !== 'langconfig') {
+ if (file_exists("$this->installroot/$lang/langconfig.php")) {
+ $string = array();
+ include("$this->installroot/$lang/langconfig.php");
+ if (isset($string['parentlanguage'])) {
+ $parent = $string['parentlanguage'];
+ }
+ }
+ }
+
+ // Include en string first.
+ if (!file_exists("$this->installroot/en/$component.php")) {
+ return "[[$identifier]]";
+ }
+ $string = array();
+ include("$this->installroot/en/$component.php");
+
+ // Now override en with parent if defined.
+ if ($parent and $parent !== 'en' and file_exists("$this->installroot/$parent/$component.php")) {
+ include("$this->installroot/$parent/$component.php");
+ }
+
+ // Finally override with requested language.
+ if ($lang !== 'en' and file_exists("$this->installroot/$lang/$component.php")) {
+ include("$this->installroot/$lang/$component.php");
+ }
+
+ if (!isset($string[$identifier])) {
+ return "[[$identifier]]";
+ }
+
+ $string = $string[$identifier];
+
+ if ($a !== null) {
+ if (is_object($a) or is_array($a)) {
+ $a = (array)$a;
+ $search = array();
+ $replace = array();
+ foreach ($a as $key => $value) {
+ if (is_int($key)) {
+ // We do not support numeric keys - sorry!
+ continue;
+ }
+ $search[] = '{$a->' . $key . '}';
+ $replace[] = (string)$value;
+ }
+ if ($search) {
+ $string = str_replace($search, $replace, $string);
+ }
+ } else {
+ $string = str_replace('{$a}', (string)$a, $string);
+ }
+ }
+
+ return $string;
+ }
+
+ /**
+ * Returns a localised list of all country names, sorted by country keys.
+ *
+ * @param bool $returnall return all or just enabled
+ * @param string $lang moodle translation language, null means use current
+ * @return array two-letter country code => translated name.
+ */
+ public function get_list_of_countries($returnall = false, $lang = null) {
+ // Not used in installer.
+ return array();
+ }
+
+ /**
+ * Returns a localised list of languages, sorted by code keys.
+ *
+ * @param string $lang moodle translation language, null means use current
+ * @param string $standard language list standard
+ * iso6392: three-letter language code (ISO 639-2/T) => translated name.
+ * @return array language code => translated name
+ */
+ public function get_list_of_languages($lang = null, $standard = 'iso6392') {
+ // Not used in installer.
+ return array();
+ }
+
+ /**
+ * Checks if the translation exists for the language
+ *
+ * @param string $lang moodle translation language code
+ * @param bool $includeall include also disabled translations
+ * @return bool true if exists
+ */
+ public function translation_exists($lang, $includeall = true) {
+ return file_exists($this->installroot . '/' . $lang . '/langconfig.php');
+ }
+
+ /**
+ * Returns localised list of installed translations
+ * @param bool $returnall return all or just enabled
+ * @return array moodle translation code => localised translation name
+ */
+ public function get_list_of_translations($returnall = false) {
+ // Return all is ignored here - we need to know all langs in installer.
+ $languages = array();
+ // Get raw list of lang directories.
+ $langdirs = get_list_of_plugins('install/lang');
+ asort($langdirs);
+ // Get some info from each lang.
+ foreach ($langdirs as $lang) {
+ if (file_exists($this->installroot . '/' . $lang . '/langconfig.php')) {
+ $string = array();
+ include($this->installroot . '/' . $lang . '/langconfig.php');
+ if (!empty($string['thislanguage'])) {
+ $languages[$lang] = $string['thislanguage'] . ' (' . $lang . ')';
+ }
+ }
+ }
+ // Return array.
+ return $languages;
+ }
+
+ /**
+ * Returns localised list of currencies.
+ *
+ * @param string $lang moodle translation language, null means use current
+ * @return array currency code => localised currency name
+ */
+ public function get_list_of_currencies($lang = null) {
+ // Not used in installer.
+ return array();
+ }
+
+ /**
+ * This implementation does not use any caches.
+ *
+ * @param bool $phpunitreset true means called from our PHPUnit integration test reset
+ */
+ public function reset_caches($phpunitreset = false) {
+ // Nothing to do.
+ }
+
+ /**
+ * Returns string revision counter, this is incremented after any string cache reset.
+ * @return int lang string revision counter, -1 if unknown
+ */
+ public function get_revision() {
+ return -1;
+ }
+}
--- /dev/null
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Standard string manager.
+ *
+ * @package core
+ * @copyright 2010 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+
+/**
+ * Standard string_manager implementation
+ *
+ * Implements string_manager with getting and printing localised strings
+ *
+ * @package core
+ * @copyright 2010 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class core_string_manager_standard implements core_string_manager {
+ /** @var string location of all packs except 'en' */
+ protected $otherroot;
+ /** @var string location of all lang pack local modifications */
+ protected $localroot;
+ /** @var cache lang string cache - it will be optimised more later */
+ protected $cache;
+ /** @var int get_string() counter */
+ protected $countgetstring = 0;
+ /** @var bool use disk cache */
+ protected $translist;
+ /** @var cache stores list of available translations */
+ protected $menucache;
+
+ /**
+ * Create new instance of string manager
+ *
+ * @param string $otherroot location of downloaded lang packs - usually $CFG->dataroot/lang
+ * @param string $localroot usually the same as $otherroot
+ * @param array $translist limit list of visible translations
+ */
+ public function __construct($otherroot, $localroot, $translist) {
+ $this->otherroot = $otherroot;
+ $this->localroot = $localroot;
+ if ($translist) {
+ $this->translist = array_combine($translist, $translist);
+ } else {
+ $this->translist = array();
+ }
+
+ if ($this->get_revision() > 0) {
+ // We can use a proper cache, establish the cache using the 'String cache' definition.
+ $this->cache = cache::make('core', 'string');
+ $this->menucache = cache::make('core', 'langmenu');
+ } else {
+ // We only want a cache for the length of the request, create a static cache.
+ $options = array(
+ 'simplekeys' => true,
+ 'simpledata' => true
+ );
+ $this->cache = cache::make_from_params(cache_store::MODE_REQUEST, 'core', 'string', array(), $options);
+ $this->menucache = cache::make_from_params(cache_store::MODE_REQUEST, 'core', 'langmenu', array(), $options);
+ }
+ }
+
+ /**
+ * Returns list of all explicit parent languages for the given language.
+ *
+ * English (en) is considered as the top implicit parent of all language packs
+ * and is not included in the returned list. The language itself is appended to the
+ * end of the list. The method is aware of circular dependency risk.
+ *
+ * @see self::populate_parent_languages()
+ * @param string $lang the code of the language
+ * @return array all explicit parent languages with the lang itself appended
+ */
+ public function get_language_dependencies($lang) {
+ return $this->populate_parent_languages($lang);
+ }
+
+ /**
+ * Load all strings for one component
+ *
+ * @param string $component The module the string is associated with
+ * @param string $lang
+ * @param bool $disablecache Do not use caches, force fetching the strings from sources
+ * @param bool $disablelocal Do not use customized strings in xx_local language packs
+ * @return array of all string for given component and lang
+ */
+ public function load_component_strings($component, $lang, $disablecache = false, $disablelocal = false) {
+ global $CFG;
+
+ list($plugintype, $pluginname) = core_component::normalize_component($component);
+ if ($plugintype === 'core' and is_null($pluginname)) {
+ $component = 'core';
+ } else {
+ $component = $plugintype . '_' . $pluginname;
+ }
+
+ $cachekey = $lang.'_'.$component.'_'.$this->get_key_suffix();
+
+ $cachedstring = $this->cache->get($cachekey);
+ if (!$disablecache and !$disablelocal) {
+ if ($cachedstring !== false) {
+ return $cachedstring;
+ }
+ }
+
+ // No cache found - let us merge all possible sources of the strings.
+ if ($plugintype === 'core') {
+ $file = $pluginname;
+ if ($file === null) {
+ $file = 'moodle';
+ }
+ $string = array();
+ // First load english pack.
+ if (!file_exists("$CFG->dirroot/lang/en/$file.php")) {
+ return array();
+ }
+ include("$CFG->dirroot/lang/en/$file.php");
+ $enstring = $string;
+
+ // And then corresponding local if present and allowed.
+ if (!$disablelocal and file_exists("$this->localroot/en_local/$file.php")) {
+ include("$this->localroot/en_local/$file.php");
+ }
+ // Now loop through all langs in correct order.
+ $deps = $this->get_language_dependencies($lang);
+ foreach ($deps as $dep) {
+ // The main lang string location.
+ if (file_exists("$this->otherroot/$dep/$file.php")) {
+ include("$this->otherroot/$dep/$file.php");
+ }
+ if (!$disablelocal and file_exists("$this->localroot/{$dep}_local/$file.php")) {
+ include("$this->localroot/{$dep}_local/$file.php");
+ }
+ }
+
+ } else {
+ if (!$location = core_component::get_plugin_directory($plugintype, $pluginname) or !is_dir($location)) {
+ return array();
+ }
+ if ($plugintype === 'mod') {
+ // Bloody mod hack.
+ $file = $pluginname;
+ } else {
+ $file = $plugintype . '_' . $pluginname;
+ }
+ $string = array();
+ // First load English pack.
+ if (!file_exists("$location/lang/en/$file.php")) {
+ // English pack does not exist, so do not try to load anything else.
+ return array();
+ }
+ include("$location/lang/en/$file.php");
+ $enstring = $string;
+ // And then corresponding local english if present.
+ if (!$disablelocal and file_exists("$this->localroot/en_local/$file.php")) {
+ include("$this->localroot/en_local/$file.php");
+ }
+
+ // Now loop through all langs in correct order.
+ $deps = $this->get_language_dependencies($lang);
+ foreach ($deps as $dep) {
+ // Legacy location - used by contrib only.
+ if (file_exists("$location/lang/$dep/$file.php")) {
+ include("$location/lang/$dep/$file.php");
+ }
+ // The main lang string location.
+ if (file_exists("$this->otherroot/$dep/$file.php")) {
+ include("$this->otherroot/$dep/$file.php");
+ }
+ // Local customisations.
+ if (!$disablelocal and file_exists("$this->localroot/{$dep}_local/$file.php")) {
+ include("$this->localroot/{$dep}_local/$file.php");
+ }
+ }
+ }
+
+ // We do not want any extra strings from other languages - everything must be in en lang pack.
+ $string = array_intersect_key($string, $enstring);
+
+ if (!$disablelocal) {
+ // Now we have a list of strings from all possible sources,
+ // cache it in MUC cache if not already there.
+ if ($cachedstring === false) {
+ $this->cache->set($cachekey, $string);
+ }
+ }
+ return $string;
+ }
+
+ /**
+ * Does the string actually exist?
+ *
+ * get_string() is throwing debug warnings, sometimes we do not want them
+ * or we want to display better explanation of the problem.
+ * Note: Use with care!
+ *
+ * @param string $identifier The identifier of the string to search for
+ * @param string $component The module the string is associated with
+ * @return boot true if exists
+ */
+ public function string_exists($identifier, $component) {
+ $lang = current_language();
+ $string = $this->load_component_strings($component, $lang);
+ return isset($string[$identifier]);
+ }
+
+ /**
+ * Get String returns a requested string
+ *
+ * @param string $identifier The identifier of the string to search for
+ * @param string $component The module the string is associated with
+ * @param string|object|array $a An object, string or number that can be used
+ * within translation strings
+ * @param string $lang moodle translation language, null means use current
+ * @return string The String !
+ */
+ public function get_string($identifier, $component = '', $a = null, $lang = null) {
+ $this->countgetstring++;
+ // There are very many uses of these time formatting strings without the 'langconfig' component,
+ // it would not be reasonable to expect that all of them would be converted during 2.0 migration.
+ static $langconfigstrs = array(
+ 'strftimedate' => 1,
+ 'strftimedatefullshort' => 1,
+ 'strftimedateshort' => 1,
+ 'strftimedatetime' => 1,
+ 'strftimedatetimeshort' => 1,
+ 'strftimedaydate' => 1,
+ 'strftimedaydatetime' => 1,
+ 'strftimedayshort' => 1,
+ 'strftimedaytime' => 1,
+ 'strftimemonthyear' => 1,
+ 'strftimerecent' => 1,
+ 'strftimerecentfull' => 1,
+ 'strftimetime' => 1);
+
+ if (empty($component)) {
+ if (isset($langconfigstrs[$identifier])) {
+ $component = 'langconfig';
+ } else {
+ $component = 'moodle';
+ }
+ }
+
+ if ($lang === null) {
+ $lang = current_language();
+ }
+
+ $string = $this->load_component_strings($component, $lang);
+
+ if (!isset($string[$identifier])) {
+ if ($component === 'pix' or $component === 'core_pix') {
+ // This component contains only alt tags for emoticons, not all of them are supposed to be defined.
+ return '';
+ }
+ if ($identifier === 'parentlanguage' and ($component === 'langconfig' or $component === 'core_langconfig')) {
+ // Identifier parentlanguage is a special string, undefined means use English if not defined.
+ return 'en';
+ }
+ // Do not rebuild caches here!
+ // Devs need to learn to purge all caches after any change or disable $CFG->langstringcache.
+ if (!isset($string[$identifier])) {
+ // The string is still missing - should be fixed by developer.
+ if (debugging('', DEBUG_DEVELOPER)) {
+ list($plugintype, $pluginname) = core_component::normalize_component($component);
+ if ($plugintype === 'core') {
+ $file = "lang/en/{$component}.php";
+ } else if ($plugintype == 'mod') {
+ $file = "mod/{$pluginname}/lang/en/{$pluginname}.php";
+ } else {
+ $path = core_component::get_plugin_directory($plugintype, $pluginname);
+ $file = "{$path}/lang/en/{$plugintype}_{$pluginname}.php";
+ }
+ debugging("Invalid get_string() identifier: '{$identifier}' or component '{$component}'. " .
+ "Perhaps you are missing \$string['{$identifier}'] = ''; in {$file}?", DEBUG_DEVELOPER);
+ }
+ return "[[$identifier]]";
+ }
+ }
+
+ $string = $string[$identifier];
+
+ if ($a !== null) {
+ // Process array's and objects (except lang_strings).
+ if (is_array($a) or (is_object($a) && !($a instanceof lang_string))) {
+ $a = (array)$a;
+ $search = array();
+ $replace = array();
+ foreach ($a as $key => $value) {
+ if (is_int($key)) {
+ // We do not support numeric keys - sorry!
+ continue;
+ }
+ if (is_array($value) or (is_object($value) && !($value instanceof lang_string))) {
+ // We support just string or lang_string as value.
+ continue;
+ }
+ $search[] = '{$a->'.$key.'}';
+ $replace[] = (string)$value;
+ }
+ if ($search) {
+ $string = str_replace($search, $replace, $string);
+ }
+ } else {
+ $string = str_replace('{$a}', (string)$a, $string);
+ }
+ }
+
+ return $string;
+ }
+
+ /**
+ * Returns information about the core_string_manager performance.
+ *
+ * @return array
+ */
+ public function get_performance_summary() {
+ return array(array(
+ 'langcountgetstring' => $this->countgetstring,
+ ), array(
+ 'langcountgetstring' => 'get_string calls',
+ ));
+ }
+
+ /**
+ * Returns a localised list of all country names, sorted by localised name.
+ *
+ * @param bool $returnall return all or just enabled
+ * @param string $lang moodle translation language, null means use current
+ * @return array two-letter country code => translated name.
+ */
+ public function get_list_of_countries($returnall = false, $lang = null) {
+ global $CFG;
+
+ if ($lang === null) {
+ $lang = current_language();
+ }
+
+ $countries = $this->load_component_strings('core_countries', $lang);
+ core_collator::asort($countries);
+ if (!$returnall and !empty($CFG->allcountrycodes)) {
+ $enabled = explode(',', $CFG->allcountrycodes);
+ $return = array();
+ foreach ($enabled as $c) {
+ if (isset($countries[$c])) {
+ $return[$c] = $countries[$c];
+ }
+ }
+ return $return;
+ }
+
+ return $countries;
+ }
+
+ /**
+ * Returns a localised list of languages, sorted by code keys.
+ *
+ * @param string $lang moodle translation language, null means use current
+ * @param string $standard language list standard
+ * - iso6392: three-letter language code (ISO 639-2/T) => translated name
+ * - iso6391: two-letter language code (ISO 639-1) => translated name
+ * @return array language code => translated name
+ */
+ public function get_list_of_languages($lang = null, $standard = 'iso6391') {
+ if ($lang === null) {
+ $lang = current_language();
+ }
+
+ if ($standard === 'iso6392') {
+ $langs = $this->load_component_strings('core_iso6392', $lang);
+ ksort($langs);
+ return $langs;
+
+ } else if ($standard === 'iso6391') {
+ $langs2 = $this->load_component_strings('core_iso6392', $lang);
+ static $mapping = array('aar' => 'aa', 'abk' => 'ab', 'afr' => 'af', 'aka' => 'ak', 'sqi' => 'sq', 'amh' => 'am', 'ara' => 'ar', 'arg' => 'an', 'hye' => 'hy',
+ 'asm' => 'as', 'ava' => 'av', 'ave' => 'ae', 'aym' => 'ay', 'aze' => 'az', 'bak' => 'ba', 'bam' => 'bm', 'eus' => 'eu', 'bel' => 'be', 'ben' => 'bn', 'bih' => 'bh',
+ 'bis' => 'bi', 'bos' => 'bs', 'bre' => 'br', 'bul' => 'bg', 'mya' => 'my', 'cat' => 'ca', 'cha' => 'ch', 'che' => 'ce', 'zho' => 'zh', 'chu' => 'cu', 'chv' => 'cv',
+ 'cor' => 'kw', 'cos' => 'co', 'cre' => 'cr', 'ces' => 'cs', 'dan' => 'da', 'div' => 'dv', 'nld' => 'nl', 'dzo' => 'dz', 'eng' => 'en', 'epo' => 'eo', 'est' => 'et',
+ 'ewe' => 'ee', 'fao' => 'fo', 'fij' => 'fj', 'fin' => 'fi', 'fra' => 'fr', 'fry' => 'fy', 'ful' => 'ff', 'kat' => 'ka', 'deu' => 'de', 'gla' => 'gd', 'gle' => 'ga',
+ 'glg' => 'gl', 'glv' => 'gv', 'ell' => 'el', 'grn' => 'gn', 'guj' => 'gu', 'hat' => 'ht', 'hau' => 'ha', 'heb' => 'he', 'her' => 'hz', 'hin' => 'hi', 'hmo' => 'ho',
+ 'hrv' => 'hr', 'hun' => 'hu', 'ibo' => 'ig', 'isl' => 'is', 'ido' => 'io', 'iii' => 'ii', 'iku' => 'iu', 'ile' => 'ie', 'ina' => 'ia', 'ind' => 'id', 'ipk' => 'ik',
+ 'ita' => 'it', 'jav' => 'jv', 'jpn' => 'ja', 'kal' => 'kl', 'kan' => 'kn', 'kas' => 'ks', 'kau' => 'kr', 'kaz' => 'kk', 'khm' => 'km', 'kik' => 'ki', 'kin' => 'rw',
+ 'kir' => 'ky', 'kom' => 'kv', 'kon' => 'kg', 'kor' => 'ko', 'kua' => 'kj', 'kur' => 'ku', 'lao' => 'lo', 'lat' => 'la', 'lav' => 'lv', 'lim' => 'li', 'lin' => 'ln',
+ 'lit' => 'lt', 'ltz' => 'lb', 'lub' => 'lu', 'lug' => 'lg', 'mkd' => 'mk', 'mah' => 'mh', 'mal' => 'ml', 'mri' => 'mi', 'mar' => 'mr', 'msa' => 'ms', 'mlg' => 'mg',
+ 'mlt' => 'mt', 'mon' => 'mn', 'nau' => 'na', 'nav' => 'nv', 'nbl' => 'nr', 'nde' => 'nd', 'ndo' => 'ng', 'nep' => 'ne', 'nno' => 'nn', 'nob' => 'nb', 'nor' => 'no',
+ 'nya' => 'ny', 'oci' => 'oc', 'oji' => 'oj', 'ori' => 'or', 'orm' => 'om', 'oss' => 'os', 'pan' => 'pa', 'fas' => 'fa', 'pli' => 'pi', 'pol' => 'pl', 'por' => 'pt',
+ 'pus' => 'ps', 'que' => 'qu', 'roh' => 'rm', 'ron' => 'ro', 'run' => 'rn', 'rus' => 'ru', 'sag' => 'sg', 'san' => 'sa', 'sin' => 'si', 'slk' => 'sk', 'slv' => 'sl',
+ 'sme' => 'se', 'smo' => 'sm', 'sna' => 'sn', 'snd' => 'sd', 'som' => 'so', 'sot' => 'st', 'spa' => 'es', 'srd' => 'sc', 'srp' => 'sr', 'ssw' => 'ss', 'sun' => 'su',
+ 'swa' => 'sw', 'swe' => 'sv', 'tah' => 'ty', 'tam' => 'ta', 'tat' => 'tt', 'tel' => 'te', 'tgk' => 'tg', 'tgl' => 'tl', 'tha' => 'th', 'bod' => 'bo', 'tir' => 'ti',
+ 'ton' => 'to', 'tsn' => 'tn', 'tso' => 'ts', 'tuk' => 'tk', 'tur' => 'tr', 'twi' => 'tw', 'uig' => 'ug', 'ukr' => 'uk', 'urd' => 'ur', 'uzb' => 'uz', 'ven' => 've',
+ 'vie' => 'vi', 'vol' => 'vo', 'cym' => 'cy', 'wln' => 'wa', 'wol' => 'wo', 'xho' => 'xh', 'yid' => 'yi', 'yor' => 'yo', 'zha' => 'za', 'zul' => 'zu');
+ $langs1 = array();
+ foreach ($mapping as $c2 => $c1) {
+ $langs1[$c1] = $langs2[$c2];
+ }
+ ksort($langs1);
+ return $langs1;
+
+ } else {
+ debugging('Unsupported $standard parameter in get_list_of_languages() method: '.$standard);
+ }
+
+ return array();
+ }
+
+ /**
+ * Checks if the translation exists for the language
+ *
+ * @param string $lang moodle translation language code
+ * @param bool $includeall include also disabled translations
+ * @return bool true if exists
+ */
+ public function translation_exists($lang, $includeall = true) {
+ $translations = $this->get_list_of_translations($includeall);
+ return isset($translations[$lang]);
+ }
+
+ /**
+ * Returns localised list of installed translations
+ *
+ * @param bool $returnall return all or just enabled
+ * @return array moodle translation code => localised translation name
+ */
+ public function get_list_of_translations($returnall = false) {
+ global $CFG;
+
+ $languages = array();
+
+ $cachekey = 'list_'.$this->get_key_suffix();
+ $cachedlist = $this->menucache->get($cachekey);
+ if ($cachedlist !== false) {
+ // The cache content is invalid.
+ if ($returnall or empty($this->translist)) {
+ return $cachedlist;
+ }
+ // Return only enabled translations.
+ foreach ($cachedlist as $langcode => $langname) {
+ if (isset($this->translist[$langcode])) {
+ $languages[$langcode] = $langname;
+ }
+ }
+ return $languages;
+ }
+
+ // Get all languages available in system.
+ $langdirs = get_list_of_plugins('', 'en', $this->otherroot);
+ $langdirs["$CFG->dirroot/lang/en"] = 'en';
+
+ // Loop through all langs and get info.
+ foreach ($langdirs as $lang) {
+ if (strrpos($lang, '_local') !== false) {
+ // Just a local tweak of some other lang pack.
+ continue;
+ }
+ if (strrpos($lang, '_utf8') !== false) {
+ // Legacy 1.x lang pack.
+ continue;
+ }
+ if ($lang !== clean_param($lang, PARAM_SAFEDIR)) {
+ // Invalid lang pack name!
+ continue;
+ }
+ $string = $this->load_component_strings('langconfig', $lang);
+ if (!empty($string['thislanguage'])) {
+ $languages[$lang] = $string['thislanguage'].' ('. $lang .')';
+ }
+ }
+
+ core_collator::asort($languages);
+
+ // Cache the list so that it can be used next time.
+ $this->menucache->set($cachekey, $languages);
+
+ if ($returnall or empty($this->translist)) {
+ return $languages;
+ }
+
+ $cachedlist = $languages;
+
+ // Return only enabled translations.
+ $languages = array();
+ foreach ($cachedlist as $langcode => $langname) {
+ if (isset($this->translist[$langcode])) {
+ $languages[$langcode] = $langname;
+ }
+ }
+
+ return $languages;
+ }
+
+ /**
+ * Returns localised list of currencies.
+ *
+ * @param string $lang moodle translation language, null means use current
+ * @return array currency code => localised currency name
+ */
+ public function get_list_of_currencies($lang = null) {
+ if ($lang === null) {
+ $lang = current_language();
+ }
+
+ $currencies = $this->load_component_strings('core_currencies', $lang);
+ asort($currencies);
+
+ return $currencies;
+ }
+
+ /**
+ * Clears both in-memory and on-disk caches
+ * @param bool $phpunitreset true means called from our PHPUnit integration test reset
+ */
+ public function reset_caches($phpunitreset = false) {
+ // Clear the on-disk disk with aggregated string files.
+ $this->cache->purge();
+ $this->menucache->purge();
+
+ if (!$phpunitreset) {
+ // Increment the revision counter.
+ $langrev = get_config('core', 'langrev');
+ $next = time();
+ if ($langrev !== false and $next <= $langrev and $langrev - $next < 60*60) {
+ // This resolves problems when reset is requested repeatedly within 1s,
+ // the < 1h condition prevents accidental switching to future dates
+ // because we might not recover from it.
+ $next = $langrev+1;
+ }
+ set_config('langrev', $next);
+ }
+
+ // Lang packs use PHP files in dataroot, it is better to invalidate opcode caches.
+ if (function_exists('opcache_reset')) {
+ opcache_reset();
+ }
+ }
+
+ /**
+ * Returns cache key suffix, this enables us to store string + lang menu
+ * caches in local caches on cluster nodes. We can not use prefix because
+ * it would cause problems when creating subdirs in cache file store.
+ * @return string
+ */
+ protected function get_key_suffix() {
+ $rev = $this->get_revision();
+ if ($rev < 0) {
+ // Simple keys do not like minus char.
+ $rev = 0;
+ }
+
+ return $rev;
+ }
+
+ /**
+ * Returns string revision counter, this is incremented after any string cache reset.
+ * @return int lang string revision counter, -1 if unknown
+ */
+ public function get_revision() {
+ global $CFG;
+ if (empty($CFG->langstringcache)) {
+ return -1;
+ }
+ if (isset($CFG->langrev)) {
+ return (int)$CFG->langrev;
+ } else {
+ return -1;
+ }
+ }
+
+ /**
+ * Helper method that recursively loads all parents of the given language.
+ *
+ * @see self::get_language_dependencies()
+ * @param string $lang language code
+ * @param array $stack list of parent languages already populated in previous recursive calls
+ * @return array list of all parents of the given language with the $lang itself added as the last element
+ */
+ protected function populate_parent_languages($lang, array $stack = array()) {
+
+ // English does not have a parent language.
+ if ($lang === 'en') {
+ return $stack;
+ }
+
+ // Prevent circular dependency (and thence the infinitive recursion loop).
+ if (in_array($lang, $stack)) {
+ return $stack;
+ }
+
+ // Load language configuration and look for the explicit parent language.
+ if (!file_exists("$this->otherroot/$lang/langconfig.php")) {
+ return $stack;
+ }
+ $string = array();
+ include("$this->otherroot/$lang/langconfig.php");
+
+ if (empty($string['parentlanguage']) or $string['parentlanguage'] === 'en') {
+ return array_merge(array($lang), $stack);
+
+ }
+
+ $parentlang = $string['parentlanguage'];
+ return $this->populate_parent_languages($parentlang, array_merge(array($lang), $stack));
+ }
+}
}
$transaction->allow_commit();
- events_trigger('activity_completion_changed', $data);
+ $cmcontext = context_module::instance($data->coursemoduleid, MUST_EXIST);
+ $coursecontext = $cmcontext->get_parent_context();
+
+ // Trigger an event for course module completion changed.
+ $event = \core\event\course_module_completion_updated::create(
+ array('objectid' => $data->id,
+ 'userid' => $USER->id,
+ 'context' => $cmcontext,
+ 'courseid' => $coursecontext->instanceid,
+ 'other' => array('relateduserid' => $data->userid)
+ )
+ );
+ $event->add_record_snapshot('course_modules_completion', $data);
+ $event->trigger();
if ($data->userid == $USER->id) {
$SESSION->completioncache[$cm->course][$cm->id] = $data;
'descriptionformat' => null, // not cached
'parent' => array('pa', 0),
'sortorder' => array('so', 0),
- 'coursecount' => null, // not cached
+ 'coursecount' => array('cc', 0),
'visible' => array('vi', 1),
'visibleold' => null, // not cached
'timemodified' => null, // not cached
foreach ($rs as $record) {
// If the category's parent is not visible to the user, it is not visible as well.
if (!$record->parent || isset($baselist[$record->parent])) {
+ context_helper::preload_from_record($record);
$context = context_coursecat::instance($record->id);
if (!$record->visible && !has_capability('moodle/category:viewhiddencategories', $context)) {
// No cap to view category, added to neither $baselist nor $thislist
$definitions = array(
// Used to store processed lang files.
- // The keys used are the component of the string file.
+ // The keys used are the revision, lang and component of the string file.
// The persistent max size has been based upon student access of the site.
+ // NOTE: this data may be safely stored in local caches on cluster nodes.
'string' => array(
'mode' => cache_store::MODE_APPLICATION,
'simplekeys' => true,
'persistentmaxsize' => 30
),
+ // Used to store cache of all available translations.
+ // NOTE: this data may be safely stored in local caches on cluster nodes.
+ 'langmenu' => array(
+ 'mode' => cache_store::MODE_APPLICATION,
+ 'simplekeys' => true,
+ 'simpledata' => true,
+ 'persistent' => true,
+ ),
+
// Used to store database meta information.
// The database meta information includes information about tables and there columns.
// Its keys are the table names.
$handlers = array(
- 'course_completed' => array (
- 'handlerfile' => '/lib/badgeslib.php',
- 'handlerfunction' => 'badges_award_handle_course_criteria_review',
- 'schedule' => 'instant',
- 'internal' => 1,
- ),
- 'activity_completion_changed' => array (
- 'handlerfile' => '/lib/badgeslib.php',
- 'handlerfunction' => 'badges_award_handle_activity_criteria_review',
- 'schedule' => 'instant',
- 'internal' => 1,
- ),
'user_updated' => array (
'handlerfile' => '/lib/badgeslib.php',
'handlerfunction' => 'badges_award_handle_profile_criteria_review',
/* no more here please, core should not consume any events!!!!!!! */
);
+$observers = array(
+ array(
+ 'eventname' => '\core\event\course_module_completion_updated',
+ 'callback' => 'core_badges_observer::course_module_criteria_review',
+ ),
+ array(
+ 'eventname' => '\core\event\course_completed',
+ 'callback' => 'core_badges_observer::course_criteria_review',
+ )
+
+);
/* List of events thrown from Moodle core
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="shortname" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="a unique shortname"/>
<FIELD NAME="downloadfiles" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="1 if the service allow people to download file from webservice/plugins.php - 0 if not"/>
+ <FIELD NAME="uploadfiles" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="1 if the service allow people to upload files to webservice/upload.php - 0 if not"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
'enabled' => 0,
'restrictedusers' => 0,
'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE,
- 'downloadfiles' => 1
+ 'downloadfiles' => 1,
+ 'uploadfiles' => 1
),
);
upgrade_main_savepoint(true, 2013072600.01);
}
+ if ($oldversion < 2013081200.00) {
+ // Define field uploadfiles to be added to external_services.
+ $table = new xmldb_table('external_services');
+ $field = new xmldb_field('uploadfiles', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'downloadfiles');
+
+ // Conditionally launch add field uploadfiles.
+ if (!$dbman->field_exists($table, $field)) {
+ $dbman->add_field($table, $field);
+ }
+
+ // Main savepoint reached.
+ upgrade_main_savepoint(true, 2013081200.00);
+ }
+
return true;
}
function isediting() {
throw new coding_exception('isediting() can not be used any more, please use $PAGE->user_is_editing() instead.');
}
+
+/**
+ * Get a list of all the plugins of a given type that contain a particular file.
+ *
+ * @param string $plugintype the type of plugin, e.g. 'mod' or 'report'.
+ * @param string $file the name of file that must be present in the plugin.
+ * (e.g. 'view.php', 'db/install.xml').
+ * @param bool $include if true (default false), the file will be include_once-ed if found.
+ * @return array with plugin name as keys (e.g. 'forum', 'courselist') and the path
+ * to the file relative to dirroot as value (e.g. "$CFG->dirroot/mod/forum/view.php").
+ * @deprecated since 2.6
+ * @see core_component::get_plugin_list_with_file()
+ */
+function get_plugin_list_with_file($plugintype, $file, $include = false) {
+ debugging('get_plugin_list_with_file() is deprecated, please use core_component::get_plugin_list_with_file() instead.',
+ DEBUG_DEVELOPER);
+ return core_component::get_plugin_list_with_file($plugintype, $file, $include);
+}
if ($fpoptions) {
$PAGE->requires->js_init_call('M.editor_tinymce.init_filepicker', array($elementid, $fpoptions), true);
}
- $this->initialise_collapse_js();
}
protected function get_init_params($elementid, array $options=null) {
return new moodle_url("$CFG->httpswwwroot/lib/editor/tinymce/tiny_mce/$this->version/");
}
- /**
- * Initialise javascript form elements
- * @return void
- */
- public function initialise_collapse_js() {
- global $PAGE;
- // This method is called for every editor instance. Ensure it's only run once.
- // Static is a clunky solution but the best we could find to keep everything simple and encapsulated.
- static $isinitialised;
- if ($isinitialised) {
- return;
- }
-
- // Initialise language strings.
- $PAGE->requires->strings_for_js(array('hideeditortoolbar', 'showeditortoolbar'), 'form');
- $PAGE->requires->yui_module('moodle-editor_tinymce-collapse', 'M.editor_collapse.init');
- $isinitialised = true;
- }
}
};
ed.windowManager.onClose.add(onClose);
var vp = ed.dom.getViewPort(),
- width = 865 + parseInt(ed.getLang('advimage.delta_width', 0)),
+ width = 900 + parseInt(ed.getLang('advimage.delta_width', 0)),
height = 600 + parseInt(ed.getLang('advimage.delta_height', 0)),
maximizedmode = (width >= vp.w - 2 || height >= vp.h - 2);
if (maximizedmode) {
2/ bump up version.php
3/ update lib/thirdpartylibs.xml
4/ reimplement patch in MDL-23646
-5/ add in "DOM.setStyle(ifr, 'width',DOM.getSize(ifrcon).w); // Resize iframe" (without quotes)
+5/ reimplement patch in MDL-40668
+6/ add in "DOM.setStyle(ifr, 'width',DOM.getSize(ifrcon).w); // Resize iframe" (without quotes)
after "DOM.setStyle(ifr, 'height',DOM.getSize(ifr).h + dy); // Resize iframe"
-5/ reminify the js manually (I used uglifyjs)
_resizeIframe : function(ed, tb_id, dy) {\r
var ifr = ed.getContentAreaContainer().firstChild;\r
var ifrcon = ed.getContentAreaContainer();\r
- \r
- DOM.setStyle(ifr, 'height',DOM.getSize(ifr).h + dy); // Resize iframe\r
- DOM.setStyle(ifr, 'width',DOM.getSize(ifrcon).w); // Resize iframe\r
- ed.theme.deltaHeight += dy; // For resize cookie\r
+ var textarea = DOM.get(ed.id);\r
+ var rows = textarea ? textarea.getAttribute('rows') : 3;\r
+\r
+ // For very small text areas - allow the editable region to be smaller than the size of the toolbars.\r
+ if (rows >= 3) {\r
+ DOM.setStyle(ifr, 'height',DOM.getSize(ifr).h + dy); // Resize iframe\r
+ DOM.setStyle(ifr, 'width',DOM.getSize(ifrcon).w); // Resize iframe\r
+ ed.theme.deltaHeight += dy; // For resize cookie\r
+ }\r
},\r
\r
/**\r
-.mform .felement.feditor .toggle_editor_toolbar {
- background: #EEEEEE;
- border-color: #BBBBBB;
- border-radius: 4px 4px 0 0;
- border-style: solid solid none;
- border-width: 1px 1px 0;
- display: inline-block;
- font-size: 0.7em;
- padding: 3px 6px;
-}
-.mform .felement.feditor .toggle_editor_toolbar:hover {
- text-decoration: underline;
- color: red;
- cursor: pointer;
-}
-
@media (max-width: 480px) {
.mceToolbar td {
float: left;
+++ /dev/null
-{
- "name": "moodle-editor_tinymce-collapse",
- "builds": {
- "moodle-editor_tinymce-collapse": {
- "jsfiles": [
- "collapse.js"
- ]
- }
- }
-}
+++ /dev/null
-var COLLAPSE = function() {
- COLLAPSE.superclass.constructor.apply(this, arguments);
-};
-
-Y.extend(COLLAPSE, Y.Base, {
- // A location to store the node toggling template so that we do not have to create it each time.
- toggleNodeTemplate : null,
-
- /**
- * Set up basic values for static access.
- */
- init : function() {
- this.initialise_toggles(10);
- },
-
- /**
- * Has TinyMCE been loaded and the editors been initialised?
- * Designed mainly for IE
- * @return bool
- */
- editors_initialised : function() {
- return typeof tinyMCE !== 'undefined';
- },
-
- initialise_toggles : function(refreshes) {
- var editors_initialised = this.editors_initialised(), self = this, editor;
- if (!editors_initialised && refreshes) {
- setTimeout(function() {
- self.initialise_toggles(refreshes - 1);
- }, 100);
- return;
- }
-
- // Create the toggle template for use later
- this.toggleNodeTemplate = Y.Node.create('<a class="toggle_editor_toolbar" />');
- this.toggleNodeTemplate.setContent(M.util.get_string('showeditortoolbar', 'form'));
-
- // Delegate clicks of the toggle_editor_toolbar
- Y.one('body').delegate('click', this.toggle_collapse_from_event, 'a.toggle_editor_toolbar', this);
-
- // Set up editors which have already been created
- for (editor in tinyMCE.editors) {
- this.setup_collapse(tinyMCE.editors[editor]);
- }
-
- // Set up for future editors.
- // I haven't yet found a way of directly delegating the editor.onInit event. Instead we have to listen for the
- // tinyMCE.onAddEditor event, and then add a further event listener to the editor's onInit event.
- // onAddEditor is triggered before the editor has been created.
- // We use Y.Bind to ensure that context is maintained.
- tinyMCE.onAddEditor.add(Y.bind(this.add_setup_collapse_listener, this));
-
- },
-
- /**
- * Setup a listener for a new editor which will actually set the editor up
- * @param {Manager} mgr
- * @param {Editor} ed
- */
- add_setup_collapse_listener : function (mgr, ed) {
- // Bind the editor.onInit function to set this editor up. This ensures we maintain our context (this)
- ed.onInit.add(Y.bind(this.setup_collapse, this));
- },
-
- /**
- * Setup the toggle system for the provided editor
- *
- * @param {Editor} ed The TinyMCE editor instance
- */
- setup_collapse : function(ed) {
- var textarea = Y.Node(ed.getElement()),
- editortable = Y.Node(ed.getContainer()).one('> table'),
- thisToggleNode;
-
- // Does this text area support collapsing at all?
- if (!textarea.hasClass('collapsible')) {
- return;
- }
-
- // Did we find an appropriate table to work with
- if (!editortable) {
- return;
- }
-
- // Add toggle button.
- thisToggleNode = this.toggleNodeTemplate.cloneNode(true);
- editortable.get('parentNode').insert(thisToggleNode, editortable);
-
- // Toggle the toolbars initially.
- if (Y.Node(ed.getElement()).hasClass('collapsed')) {
- this.toggle_collapse(thisToggleNode, editortable, 0);
- } else {
- this.toggle_collapse(thisToggleNode, editortable, 1);
- }
-
- // When TinyMCE initialises itself, it adds a height to the table.
- // Unfortuately, the height it sets is too big for when the editor is collpsed.
- // Fortunately, the hight is not necessary, so we can just remove it.
- // (If you re-size the editor then it will remove this style attribute itself.)
- editortable.setStyle('height', '');
- editortable.setStyle('width', '');
- },
-
- /**
- * Toggle the specified editor toolbars.
- *
- * @param {Node} button The toggle button which we have to change the text for
- * @param {Node} editortable The table which the tinyMCE editor is in
- * @param {Boolean} newstate The intended toggle state
- */
- toggle_collapse : function(button, editortable, newstate) {
- var toolbar = editortable.one('td.mceToolbar').ancestor('tr'),
- statusbar = editortable.one('.mceStatusbar').ancestor('tr');
-
- // Check whether we have a state already.
- if (typeof newstate === 'undefined') {
- if (toolbar.getStyle('display') === 'none') {
- newstate = 1;
- } else {
- newstate = 0;
- }
- }
-
- // Toggle the various states and update the button text to suit
- if (newstate === 0) {
- toolbar.hide();
- statusbar.hide();
- button.setContent(M.util.get_string('showeditortoolbar', 'form'));
- } else {
- toolbar.show();
- statusbar.show();
- button.setContent(M.util.get_string('hideeditortoolbar', 'form'));
- }
- },
-
- toggle_collapse_from_event : function(thisevent) {
- var button = thisevent.target.ancestor('a', true),
- editortable = thisevent.target.ancestor('span', true).one('table.mceLayout');
- this.toggle_collapse(button, editortable);
- }
-});
-
-M.editor_collapse = M.editor_collapse || {};
-M.editor_collapse.init = function(params) {
- return new COLLAPSE(params);
-};
+++ /dev/null
-{
- "moodle-editor_tinymce-collapse": {
- "requires": [
- "base",
- "node",
- "dom"
- ]
- }
-}
/** @var array options provided to initalize filepicker */
protected $_options = array('subdirs' => 0, 'maxbytes' => 0, 'maxfiles' => 0, 'changeformat' => 0,
'areamaxbytes' => FILE_AREA_MAX_BYTES_UNLIMITED, 'context' => null, 'noclean' => 0, 'trusttext' => 0,
- 'return_types' => 7, 'collapsible' => 0, 'collapsed' => 0);
+ 'return_types' => 7);
// $_options['return_types'] = FILE_INTERNAL | FILE_EXTERNAL | FILE_REFERENCE
/** @var array values for editor */
if (!is_null($this->getAttribute('onblur')) && !is_null($this->getAttribute('onchange'))) {
$editorrules = ' onblur="'.htmlspecialchars($this->getAttribute('onblur')).'" onchange="'.htmlspecialchars($this->getAttribute('onchange')).'"';
}
- $str .= '<div><textarea id="'.$id.'" name="'.$elname.'[text]" rows="'.$rows.'" cols="'.$cols.'" spellcheck="true"';
- $classes = array();
- if (isset($this->_options['collapsed']) && $this->_options['collapsed']) {
- $this->_options['collapsible'] = 1;
- $classes[] = 'collapsed';
- }
- if (isset($this->_options['collapsible']) && $this->_options['collapsible']) {
- $classes[] = 'collapsible';
- }
- $str .= ' class="' . implode(' ', $classes) . '"';
- $str .= $editorrules.'>';
+ $str .= '<div><textarea id="'.$id.'" name="'.$elname.'[text]" rows="'.$rows.'" cols="'.$cols.'" spellcheck="true"'.$editorrules.'>';
$str .= s($text);
$str .= '</textarea></div>';
* this.areamaxbytes, the maximum size of the area
* this.filemanager, contains reference to filemanager Node
* this.selectnode, contains referenct to select-file Node
- * this.selectui, YUI Panel to select the file
+ * this.selectui, M.core.dialogue to select the file
*
* FileManager options:
* =====
}
// initialize 'select file' panel
this.selectnode = Y.Node.createWithFilesSkin(M.form_filemanager.templates.fileselectlayout);
+ this.selectnode.setAttribute('aria-live', 'assertive');
+ this.selectnode.setAttribute('role', 'dialog');
this.selectnode.generateID();
- this.selectui = new Y.Panel({
- srcNode : this.selectnode,
- zIndex : 7600,
+
+ var labelid = 'fm-dialog-label_'+ this.selectnode.get('id');
+ this.selectui = new M.core.dialogue({
+ draggable : true,
+ headerContent: '<span id="' + labelid +'">' + M.str.moodle.edit + '</span>',
+ bodyContent : this.selectnode,
centered : true,
+ width : '480px',
modal : true,
- close : true,
- render : true
+ visible : false
});
- this.selectui.plug(Y.Plugin.Drag,{handles:['#'+this.selectnode.get('id')+' .yui3-widget-hd']});
+ Y.one('#'+this.selectnode.get('id')).setAttribute('aria-labelledby', labelid);
this.selectui.hide();
this.setup_select_file();
// setup buttons onclick events
this.msg_dlg_node = Y.Node.createWithFilesSkin(M.form_filemanager.templates.message);
var nodeid = this.msg_dlg_node.generateID();
- this.msg_dlg = new Y.Panel({
- srcNode : this.msg_dlg_node,
- zIndex : 8000,
+ this.msg_dlg = new M.core.dialogue({
+ draggable : true,
+ bodyContent : this.msg_dlg_node,
centered : true,
modal : true,
visible : false,
- render : true
});
- this.msg_dlg.plug(Y.Plugin.Drag,{handles:['#'+nodeid+' .yui3-widget-hd']});
this.msg_dlg_node.one('.fp-msg-butok').on('click', function(e) {
e.preventDefault();
this.msg_dlg.hide();
};
if (!this.mkdir_dialog) {
var node = Y.Node.createWithFilesSkin(M.form_filemanager.templates.mkdir);
- this.mkdir_dialog = new Y.Panel({
- srcNode : node,
- zIndex : 8000,
+ this.mkdir_dialog = new M.core.dialogue({
+ draggable : true,
+ bodyContent : node,
centered : true,
modal : true,
visible : false,
- render : true
});
- this.mkdir_dialog.plug(Y.Plugin.Drag,{handles:['.yui3-widget-hd']});
node.one('.fp-dlg-butcreate').set('id', 'fm-mkdir-butcreate-'+this.client_id).on('click',
perform_action, this);
node.one('input').set('id', 'fm-newname-'+this.client_id).on('keydown', function(e) {
this.confirm_dlg_node = Y.Node.createWithFilesSkin(M.form_filemanager.templates.confirmdialog);
var node = this.confirm_dlg_node;
node.generateID();
- this.confirm_dlg = new Y.Panel({
- srcNode : node,
- zIndex : 8000,
+ this.confirm_dlg = new M.core.dialogue({
+ draggable : true,
+ bodyContent : node,
centered : true,
modal : true,
visible : false,
- render : true,
buttons : {}
});
- this.confirm_dlg.plug(Y.Plugin.Drag,{handles:['#'+node.get('id')+' .yui3-widget-hd']});
var handle_confirm = function(ev) {
var dlgopt = this.confirm_dlg.dlgopt;
ev.preventDefault();
}
}, false);
}
+ // update dialog header
+ var nodename = node.fullname;
+ // Limit the string length so it fits nicely on mobile devices
+ var namelength = 50;
+ if (nodename.length > namelength) {
+ nodename = nodename.substring(0, namelength) + '...';
+ }
+ Y.one('#fm-dialog-label_'+selectnode.get('id')).setContent(Y.Escape.html(M.str.moodle.edit+' '+nodename));
// show panel
this.selectui.show();
+ Y.one('#'+selectnode.get('id')).focus();
},
render: function() {
this.print_path();
// switch next two lines for ol li containers for form items.
// $this->_elementTemplates=array('default'=>"\n\t\t".'<li class="fitem"><label>{label}{help}<!-- BEGIN required -->{req}<!-- END required --></label><div class="qfelement<!-- BEGIN error --> error<!-- END error --> {type}"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></li>');
$this->_elementTemplates = array(
- 'default'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}" {aria-live}><div class="fitemtitle"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg}{help} </label></div><div class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></div>',
+ 'default'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}" {aria-live}><div class="fitemtitle"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} </label>{help}</div><div class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</div></div>',
'actionbuttons'=>"\n\t\t".'<div id="{id}" class="fitem fitem_actionbuttons fitem_{type}"><div class="felement {type}">{element}</div></div>',
- 'fieldset'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><div class="fgrouplabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg}{help} </label></div></div><fieldset class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</fieldset></div>',
+ 'fieldset'=>"\n\t\t".'<div id="{id}" class="fitem {advanced}<!-- BEGIN required --> required<!-- END required --> fitem_{type}"><div class="fitemtitle"><div class="fgrouplabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} </label>{help}</div></div><fieldset class="felement {type}<!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element}</fieldset></div>',
- 'static'=>"\n\t\t".'<div class="fitem {advanced}"><div class="fitemtitle"><div class="fstaticlabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg}{help} </label></div></div><div class="felement fstatic <!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element} </div></div>',
+ 'static'=>"\n\t\t".'<div class="fitem {advanced}"><div class="fitemtitle"><div class="fstaticlabel"><label>{label}<!-- BEGIN required -->{req}<!-- END required -->{advancedimg} </label>{help}</div></div><div class="felement fstatic <!-- BEGIN error --> error<!-- END error -->"><!-- BEGIN error --><span class="error">{error}</span><br /><!-- END error -->{element} </div></div>',
'warning'=>"\n\t\t".'<div class="fitem {advanced}">{element}</div>',
if ($children = grade_item::fetch_all(array('categoryid'=>$this->id))) {
foreach ($children as $child) {
- $child->set_hidden($hidden, $cascade);
+ if ($child->can_control_visibility()) {
+ $child->set_hidden($hidden, $cascade);
+ }
}
}
if (core_component::get_plugin_directory($this->itemtype, $this->itemmodule)) {
return !plugin_supports($this->itemtype, $this->itemmodule, FEATURE_CONTROLS_GRADE_VISIBILITY, false);
}
- return true;
+ return parent::can_control_visibility();
}
}
$this->hidden = $hidden;
$this->update();
}
+
+ /**
+ * Returns whether the grade object can control the visibility of the grades.
+ *
+ * @return bool
+ */
+ public function can_control_visibility() {
+ return true;
+ }
}
$this->activities[6] = $this->getDataGenerator()->create_module('forum', array('course'=>$this->course->id));
$this->course_module[6] = get_coursemodule_from_instance('forum', $this->activities[6]->id);
+
+ $this->activities[7] = $this->getDataGenerator()->create_module('quiz', array('course'=>$this->course->id));
+ $this->course_module[7] = get_coursemodule_from_instance('quiz', $this->activities[7]->id);
}
private function load_scales() {
$grade_item->id = $DB->insert_record('grade_items', $grade_item);
$this->grade_items[10] = $grade_item;
+
+ // Quiz grade_item (course_module = 7).
+ // id = 11
+ $grade_item = new stdClass();
+
+ $grade_item->courseid = $this->course->id;
+ $grade_item->categoryid = $course_category->id;
+ $grade_item->itemname = 'Quiz grade item';
+ $grade_item->itemtype = 'mod';
+ $grade_item->itemmodule = $this->course_module[7]->modname;
+ $grade_item->iteminstance = $this->course_module[7]->instance;
+ $grade_item->itemnumber = 0;
+ $grade_item->gradetype = GRADE_TYPE_VALUE;
+ $grade_item->grademin = 0;
+ $grade_item->grademax = 100;
+ $grade_item->locked = 0;
+ $grade_item->iteminfo = 'Quiz grade item used for unit testing';
+ $grade_item->timecreated = time();
+ $grade_item->timemodified = time();
+ $grade_item->sortorder = 11;
+
+ $grade_item->id = $DB->insert_record('grade_items', $grade_item);
+ $this->grade_items[11] = $grade_item;
}
/**
$this->grade_outcomes[] = $grade_outcome;
}
}
-
-
$this->sub_test_grade_category_set_locked();
$this->sub_test_grade_category_is_hidden();
$this->sub_test_grade_category_set_hidden();
+ $this->sub_test_grade_category_can_control_visibility();
//this won't work until MDL-11837 is complete
//$this->sub_test_grade_category_generate_grades();
$this->assertEquals(true, $category->grade_item->is_hidden());
}
+ protected function sub_test_grade_category_can_control_visibility() {
+ $category = new grade_category($this->grade_categories[0]);
+ $this->assertTrue($category->can_control_visibility());
+ }
+
//beware: adding a duplicate course category messes up the data in a way that's hard to recover from
protected function sub_test_grade_category_insert_course_category() {
$grade_category = new grade_category();
$this->sub_test_grade_item_get_calculation();
$this->sub_test_grade_item_compute();
$this->sub_test_update_final_grade();
+ $this->sub_test_grade_item_can_control_visibility();
}
protected function sub_test_grade_item_construct() {
$last_grade_item = end($this->grade_items);
$this->assertEquals($grade_item->id, $last_grade_item->id + 1);
- $this->assertEquals(11, $grade_item->sortorder);
+ $this->assertEquals(12, $grade_item->sortorder);
//keep our reference collection the same as what is in the database
$this->grade_items[] = $grade_item;
$this->assertEquals($min, $grade_grade->rawgrademin);
$this->assertEquals($max, $grade_grade->rawgrademax);
}
+
+ protected function sub_test_grade_item_can_control_visibility() {
+ // Grade item 0 == Course module 0 == Assignment.
+ $grade_item = new grade_item($this->grade_items[0], false);
+ $this->assertTrue($grade_item->can_control_visibility());
+
+ // Grade item == Course module 7 == Quiz.
+ $grade_item = new grade_item($this->grade_items[11], false);
+ $this->assertFalse($grade_item->can_control_visibility());
+ }
}
*
* @category string
* @param bool $forcereload shall the singleton be released and new instance created instead?
- * @return string_manager
+ * @return core_string_manager
*/
function get_string_manager($forcereload=false) {
global $CFG;
$translist = explode(',', $CFG->langlist);
}
- if (empty($CFG->langmenucachefile)) {
- $langmenucache = $CFG->cachedir . '/languages';
- } else {
- $langmenucache = $CFG->langmenucachefile;
- }
-
- $singleton = new core_string_manager($CFG->langotherroot, $CFG->langlocalroot,
- !empty($CFG->langstringcache), $translist, $langmenucache);
+ $singleton = new core_string_manager_standard($CFG->langotherroot, $CFG->langlocalroot, $translist);
} else {
- $singleton = new install_string_manager();
+ $singleton = new core_string_manager_install();
}
}
return $singleton;
}
-
-/**
- * Interface for string manager
- *
- * Interface describing class which is responsible for getting
- * of localised strings from language packs.
- *
- * @package core
- * @copyright 2010 Petr Skoda (http://skodak.org)
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-interface string_manager {
- /**
- * Get String returns a requested string
- *
- * @param string $identifier The identifier of the string to search for
- * @param string $component The module the string is associated with
- * @param string|object|array $a An object, string or number that can be used
- * within translation strings
- * @param string $lang moodle translation language, null means use current
- * @return string The String !
- */
- public function get_string($identifier, $component = '', $a = null, $lang = null);
-
- /**
- * Does the string actually exist?
- *
- * get_string() is throwing debug warnings, sometimes we do not want them
- * or we want to display better explanation of the problem.
- *
- * Use with care!
- *
- * @param string $identifier The identifier of the string to search for
- * @param string $component The module the string is associated with
- * @return boot true if exists
- */
- public function string_exists($identifier, $component);
-
- /**
- * Returns a localised list of all country names, sorted by country keys.
- * @param bool $returnall return all or just enabled
- * @param string $lang moodle translation language, null means use current
- * @return array two-letter country code => translated name.
- */
- public function get_list_of_countries($returnall = false, $lang = null);
-
- /**
- * Returns a localised list of languages, sorted by code keys.
- *
- * @param string $lang moodle translation language, null means use current
- * @param string $standard language list standard
- * iso6392: three-letter language code (ISO 639-2/T) => translated name.
- * @return array language code => translated name
- */
- public function get_list_of_languages($lang = null, $standard = 'iso6392');
-
- /**
- * Checks if the translation exists for the language
- *
- * @param string $lang moodle translation language code
- * @param bool $includeall include also disabled translations
- * @return bool true if exists
- */
- public function translation_exists($lang, $includeall = true);
-
- /**
- * Returns localised list of installed translations
- * @param bool $returnall return all or just enabled
- * @return array moodle translation code => localised translation name
- */
- public function get_list_of_translations($returnall = false);
-
- /**
- * Returns localised list of currencies.
- *
- * @param string $lang moodle translation language, null means use current
- * @return array currency code => localised currency name
- */
- public function get_list_of_currencies($lang = null);
-
- /**
- * Load all strings for one component
- * @param string $component The module the string is associated with
- * @param string $lang
- * @param bool $disablecache Do not use caches, force fetching the strings from sources
- * @param bool $disablelocal Do not use customized strings in xx_local language packs
- * @return array of all string for given component and lang
- */
- public function load_component_strings($component, $lang, $disablecache=false, $disablelocal=false);
-
- /**
- * Invalidates all caches, should the implementation use any
- * @param bool $phpunitreset true means called from our PHPUnit integration test reset
- */
- public function reset_caches($phpunitreset = false);
-
- /**
- * Returns string revision counter, this is incremented after any
- * string cache reset.
- * @return int lang string revision counter, -1 if unknown
- */
- public function get_revision();
-}
-
-
-/**
- * Standard string_manager implementation
- *
- * Implements string_manager with getting and printing localised strings
- *
- * @package core
- * @category string
- * @copyright 2010 Petr Skoda (http://skodak.org)
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class core_string_manager implements string_manager {
- /** @var string location of all packs except 'en' */
- protected $otherroot;
- /** @var string location of all lang pack local modifications */
- protected $localroot;
- /** @var cache lang string cache - it will be optimised more later */
- protected $cache;
- /** @var int get_string() counter */
- protected $countgetstring = 0;
- /** @var bool use disk cache */
- protected $usecache;
- /** @var array limit list of translations */
- protected $translist;
- /** @var string location of a file that caches the list of available translations */
- protected $menucache;
-
- /**
- * Create new instance of string manager
- *
- * @param string $otherroot location of downlaoded lang packs - usually $CFG->dataroot/lang
- * @param string $localroot usually the same as $otherroot
- * @param bool $usecache use disk cache
- * @param array $translist limit list of visible translations
- * @param string $menucache the location of a file that caches the list of available translations
- */
- public function __construct($otherroot, $localroot, $usecache, $translist, $menucache) {
- $this->otherroot = $otherroot;
- $this->localroot = $localroot;
- $this->usecache = $usecache;
- $this->translist = $translist;
- $this->menucache = $menucache;
-
- if ($this->usecache) {
- // We can use a proper cache, establish the cache using the 'String cache' definition.
- $this->cache = cache::make('core', 'string');
- } else {
- // We only want a cache for the length of the request, create a static cache.
- $options = array(
- 'simplekeys' => true,
- 'simpledata' => true
- );
- $this->cache = cache::make_from_params(cache_store::MODE_REQUEST, 'core', 'string', array(), $options);
- }
- }
-
- /**
- * Returns list of all explicit parent languages for the given language.
- *
- * English (en) is considered as the top implicit parent of all language packs
- * and is not included in the returned list. The language itself is appended to the
- * end of the list. The method is aware of circular dependency risk.
- *
- * @see self::populate_parent_languages()
- * @param string $lang the code of the language
- * @return array all explicit parent languages with the lang itself appended
- */
- public function get_language_dependencies($lang) {
- return $this->populate_parent_languages($lang);
- }
-
- /**
- * Load all strings for one component
- *
- * @param string $component The module the string is associated with
- * @param string $lang
- * @param bool $disablecache Do not use caches, force fetching the strings from sources
- * @param bool $disablelocal Do not use customized strings in xx_local language packs
- * @return array of all string for given component and lang
- */
- public function load_component_strings($component, $lang, $disablecache=false, $disablelocal=false) {
- global $CFG;
-
- list($plugintype, $pluginname) = core_component::normalize_component($component);
- if ($plugintype == 'core' and is_null($pluginname)) {
- $component = 'core';
- } else {
- $component = $plugintype . '_' . $pluginname;
- }
-
- $cachekey = $lang.'_'.$component;
-
- if (!$disablecache and !$disablelocal) {
- $string = $this->cache->get($cachekey);
- if ($string) {
- return $string;
- }
- }
-
- // No cache found - let us merge all possible sources of the strings.
- if ($plugintype === 'core') {
- $file = $pluginname;
- if ($file === null) {
- $file = 'moodle';
- }
- $string = array();
- // First load english pack.
- if (!file_exists("$CFG->dirroot/lang/en/$file.php")) {
- return array();
- }
- include("$CFG->dirroot/lang/en/$file.php");
- $originalkeys = array_keys($string);
- $originalkeys = array_flip($originalkeys);
-
- // And then corresponding local if present and allowed.
- if (!$disablelocal and file_exists("$this->localroot/en_local/$file.php")) {
- include("$this->localroot/en_local/$file.php");
- }
- // Now loop through all langs in correct order.
- $deps = $this->get_language_dependencies($lang);
- foreach ($deps as $dep) {
- // The main lang string location.
- if (file_exists("$this->otherroot/$dep/$file.php")) {
- include("$this->otherroot/$dep/$file.php");
- }
- if (!$disablelocal and file_exists("$this->localroot/{$dep}_local/$file.php")) {
- include("$this->localroot/{$dep}_local/$file.php");
- }
- }
-
- } else {
- if (!$location = core_component::get_plugin_directory($plugintype, $pluginname) or !is_dir($location)) {
- return array();
- }
- if ($plugintype === 'mod') {
- // Bloody mod hack.
- $file = $pluginname;
- } else {
- $file = $plugintype . '_' . $pluginname;
- }
- $string = array();
- // First load English pack.
- if (!file_exists("$location/lang/en/$file.php")) {
- // English pack does not exist, so do not try to load anything else.
- return array();
- }
- include("$location/lang/en/$file.php");
- $originalkeys = array_keys($string);
- $originalkeys = array_flip($originalkeys);
- // And then corresponding local english if present.
- if (!$disablelocal and file_exists("$this->localroot/en_local/$file.php")) {
- include("$this->localroot/en_local/$file.php");
- }
-
- // Now loop through all langs in correct order.
- $deps = $this->get_language_dependencies($lang);
- foreach ($deps as $dep) {
- // Legacy location - used by contrib only.
- if (file_exists("$location/lang/$dep/$file.php")) {
- include("$location/lang/$dep/$file.php");
- }
- // The main lang string location.
- if (file_exists("$this->otherroot/$dep/$file.php")) {
- include("$this->otherroot/$dep/$file.php");
- }
- // Local customisations.
- if (!$disablelocal and file_exists("$this->localroot/{$dep}_local/$file.php")) {
- include("$this->localroot/{$dep}_local/$file.php");
- }
- }
- }
-
- // We do not want any extra strings from other languages - everything must be in en lang pack.
- $string = array_intersect_key($string, $originalkeys);
-
- if (!$disablelocal) {
- // Now we have a list of strings from all possible sources. put it into both in-memory and on-disk
- // caches so we do not need to do all this merging and dependencies resolving again.
- $this->cache->set($cachekey, $string);
- }
- return $string;
- }
-
- /**
- * Does the string actually exist?
- *
- * get_string() is throwing debug warnings, sometimes we do not want them
- * or we want to display better explanation of the problem.
- * Note: Use with care!
- *
- * @param string $identifier The identifier of the string to search for
- * @param string $component The module the string is associated with
- * @return boot true if exists
- */
- public function string_exists($identifier, $component) {
- $lang = current_language();
- $string = $this->load_component_strings($component, $lang);
- return isset($string[$identifier]);
- }
-
- /**
- * Get String returns a requested string
- *
- * @param string $identifier The identifier of the string to search for
- * @param string $component The module the string is associated with
- * @param string|object|array $a An object, string or number that can be used
- * within translation strings
- * @param string $lang moodle translation language, null means use current
- * @return string The String !
- */
- public function get_string($identifier, $component = '', $a = null, $lang = null) {
- $this->countgetstring++;
- // There are very many uses of these time formating strings without the 'langconfig' component,
- // it would not be reasonable to expect that all of them would be converted during 2.0 migration.
- static $langconfigstrs = array(
- 'strftimedate' => 1,
- 'strftimedatefullshort' => 1,
- 'strftimedateshort' => 1,
- 'strftimedatetime' => 1,
- 'strftimedatetimeshort' => 1,
- 'strftimedaydate' => 1,
- 'strftimedaydatetime' => 1,
- 'strftimedayshort' => 1,
- 'strftimedaytime' => 1,
- 'strftimemonthyear' => 1,
- 'strftimerecent' => 1,
- 'strftimerecentfull' => 1,
- 'strftimetime' => 1);
-
- if (empty($component)) {
- if (isset($langconfigstrs[$identifier])) {
- $component = 'langconfig';
- } else {
- $component = 'moodle';
- }
- }
-
- if ($lang === null) {
- $lang = current_language();
- }
-
- $string = $this->load_component_strings($component, $lang);
-
- if (!isset($string[$identifier])) {
- if ($component === 'pix' or $component === 'core_pix') {
- // This component contains only alt tags for emoticons, not all of them are supposed to be defined.
- return '';
- }
- if ($identifier === 'parentlanguage' and ($component === 'langconfig' or $component === 'core_langconfig')) {
- // Identifier parentlanguage is a special string, undefined means use English if not defined.
- return 'en';
- }
- if ($this->usecache) {
- // Maybe the on-disk cache is dirty - let the last attempt be to find the string in original sources,
- // do NOT write the results to disk cache because it may end up in race conditions see MDL-31904.
- $this->usecache = false;
- $string = $this->load_component_strings($component, $lang, true);
- $this->usecache = true;
- }
- if (!isset($string[$identifier])) {
- // The string is still missing - should be fixed by developer.
- list($plugintype, $pluginname) = core_component::normalize_component($component);
- if ($plugintype == 'core') {
- $file = "lang/en/{$component}.php";
- } else if ($plugintype == 'mod') {
- $file = "mod/{$pluginname}/lang/en/{$pluginname}.php";
- } else {
- $path = core_component::get_plugin_directory($plugintype, $pluginname);
- $file = "{$path}/lang/en/{$plugintype}_{$pluginname}.php";
- }
- debugging("Invalid get_string() identifier: '{$identifier}' or component '{$component}'. " .
- "Perhaps you are missing \$string['{$identifier}'] = ''; in {$file}?", DEBUG_DEVELOPER);
- return "[[$identifier]]";
- }
- }
-
- $string = $string[$identifier];
-
- if ($a !== null) {
- // Process array's and objects (except lang_strings).
- if (is_array($a) or (is_object($a) && !($a instanceof lang_string))) {
- $a = (array)$a;
- $search = array();
- $replace = array();
- foreach ($a as $key => $value) {
- if (is_int($key)) {
- // We do not support numeric keys - sorry!
- continue;
- }
- if (is_array($value) or (is_object($value) && !($value instanceof lang_string))) {
- // We support just string or lang_string as value.
- continue;
- }
- $search[] = '{$a->'.$key.'}';
- $replace[] = (string)$value;
- }
- if ($search) {
- $string = str_replace($search, $replace, $string);
- }
- } else {
- $string = str_replace('{$a}', (string)$a, $string);
- }
- }
-
- return $string;
- }
-
- /**
- * Returns information about the string_manager performance.
- *
- * @return array
- */
- public function get_performance_summary() {
- return array(array(
- 'langcountgetstring' => $this->countgetstring,
- ), array(
- 'langcountgetstring' => 'get_string calls',
- ));
- }
-
- /**
- * Returns a localised list of all country names, sorted by localised name.
- *
- * @param bool $returnall return all or just enabled
- * @param string $lang moodle translation language, null means use current
- * @return array two-letter country code => translated name.
- */
- public function get_list_of_countries($returnall = false, $lang = null) {
- global $CFG;
-
- if ($lang === null) {
- $lang = current_language();
- }
-
- $countries = $this->load_component_strings('core_countries', $lang);
- core_collator::asort($countries);
- if (!$returnall and !empty($CFG->allcountrycodes)) {
- $enabled = explode(',', $CFG->allcountrycodes);
- $return = array();
- foreach ($enabled as $c) {
- if (isset($countries[$c])) {
- $return[$c] = $countries[$c];
- }
- }
- return $return;
- }
-
- return $countries;
- }
-
- /**
- * Returns a localised list of languages, sorted by code keys.
- *
- * @param string $lang moodle translation language, null means use current
- * @param string $standard language list standard
- * - iso6392: three-letter language code (ISO 639-2/T) => translated name
- * - iso6391: two-letter langauge code (ISO 639-1) => translated name
- * @return array language code => translated name
- */
- public function get_list_of_languages($lang = null, $standard = 'iso6391') {
- if ($lang === null) {
- $lang = current_language();
- }
-
- if ($standard === 'iso6392') {
- $langs = $this->load_component_strings('core_iso6392', $lang);
- ksort($langs);
- return $langs;
-
- } else if ($standard === 'iso6391') {
- $langs2 = $this->load_component_strings('core_iso6392', $lang);
- static $mapping = array('aar' => 'aa', 'abk' => 'ab', 'afr' => 'af', 'aka' => 'ak', 'sqi' => 'sq', 'amh' => 'am', 'ara' => 'ar', 'arg' => 'an', 'hye' => 'hy',
- 'asm' => 'as', 'ava' => 'av', 'ave' => 'ae', 'aym' => 'ay', 'aze' => 'az', 'bak' => 'ba', 'bam' => 'bm', 'eus' => 'eu', 'bel' => 'be', 'ben' => 'bn', 'bih' => 'bh',
- 'bis' => 'bi', 'bos' => 'bs', 'bre' => 'br', 'bul' => 'bg', 'mya' => 'my', 'cat' => 'ca', 'cha' => 'ch', 'che' => 'ce', 'zho' => 'zh', 'chu' => 'cu', 'chv' => 'cv',
- 'cor' => 'kw', 'cos' => 'co', 'cre' => 'cr', 'ces' => 'cs', 'dan' => 'da', 'div' => 'dv', 'nld' => 'nl', 'dzo' => 'dz', 'eng' => 'en', 'epo' => 'eo', 'est' => 'et',
- 'ewe' => 'ee', 'fao' => 'fo', 'fij' => 'fj', 'fin' => 'fi', 'fra' => 'fr', 'fry' => 'fy', 'ful' => 'ff', 'kat' => 'ka', 'deu' => 'de', 'gla' => 'gd', 'gle' => 'ga',
- 'glg' => 'gl', 'glv' => 'gv', 'ell' => 'el', 'grn' => 'gn', 'guj' => 'gu', 'hat' => 'ht', 'hau' => 'ha', 'heb' => 'he', 'her' => 'hz', 'hin' => 'hi', 'hmo' => 'ho',
- 'hrv' => 'hr', 'hun' => 'hu', 'ibo' => 'ig', 'isl' => 'is', 'ido' => 'io', 'iii' => 'ii', 'iku' => 'iu', 'ile' => 'ie', 'ina' => 'ia', 'ind' => 'id', 'ipk' => 'ik',
- 'ita' => 'it', 'jav' => 'jv', 'jpn' => 'ja', 'kal' => 'kl', 'kan' => 'kn', 'kas' => 'ks', 'kau' => 'kr', 'kaz' => 'kk', 'khm' => 'km', 'kik' => 'ki', 'kin' => 'rw',
- 'kir' => 'ky', 'kom' => 'kv', 'kon' => 'kg', 'kor' => 'ko', 'kua' => 'kj', 'kur' => 'ku', 'lao' => 'lo', 'lat' => 'la', 'lav' => 'lv', 'lim' => 'li', 'lin' => 'ln',
- 'lit' => 'lt', 'ltz' => 'lb', 'lub' => 'lu', 'lug' => 'lg', 'mkd' => 'mk', 'mah' => 'mh', 'mal' => 'ml', 'mri' => 'mi', 'mar' => 'mr', 'msa' => 'ms', 'mlg' => 'mg',
- 'mlt' => 'mt', 'mon' => 'mn', 'nau' => 'na', 'nav' => 'nv', 'nbl' => 'nr', 'nde' => 'nd', 'ndo' => 'ng', 'nep' => 'ne', 'nno' => 'nn', 'nob' => 'nb', 'nor' => 'no',
- 'nya' => 'ny', 'oci' => 'oc', 'oji' => 'oj', 'ori' => 'or', 'orm' => 'om', 'oss' => 'os', 'pan' => 'pa', 'fas' => 'fa', 'pli' => 'pi', 'pol' => 'pl', 'por' => 'pt',
- 'pus' => 'ps', 'que' => 'qu', 'roh' => 'rm', 'ron' => 'ro', 'run' => 'rn', 'rus' => 'ru', 'sag' => 'sg', 'san' => 'sa', 'sin' => 'si', 'slk' => 'sk', 'slv' => 'sl',
- 'sme' => 'se', 'smo' => 'sm', 'sna' => 'sn', 'snd' => 'sd', 'som' => 'so', 'sot' => 'st', 'spa' => 'es', 'srd' => 'sc', 'srp' => 'sr', 'ssw' => 'ss', 'sun' => 'su',
- 'swa' => 'sw', 'swe' => 'sv', 'tah' => 'ty', 'tam' => 'ta', 'tat' => 'tt', 'tel' => 'te', 'tgk' => 'tg', 'tgl' => 'tl', 'tha' => 'th', 'bod' => 'bo', 'tir' => 'ti',
- 'ton' => 'to', 'tsn' => 'tn', 'tso' => 'ts', 'tuk' => 'tk', 'tur' => 'tr', 'twi' => 'tw', 'uig' => 'ug', 'ukr' => 'uk', 'urd' => 'ur', 'uzb' => 'uz', 'ven' => 've',
- 'vie' => 'vi', 'vol' => 'vo', 'cym' => 'cy', 'wln' => 'wa', 'wol' => 'wo', 'xho' => 'xh', 'yid' => 'yi', 'yor' => 'yo', 'zha' => 'za', 'zul' => 'zu');
- $langs1 = array();
- foreach ($mapping as $c2 => $c1) {
- $langs1[$c1] = $langs2[$c2];
- }
- ksort($langs1);
- return $langs1;
-
- } else {
- debugging('Unsupported $standard parameter in get_list_of_languages() method: '.$standard);
- }
-
- return array();
- }
-
- /**
- * Checks if the translation exists for the language
- *
- * @param string $lang moodle translation language code
- * @param bool $includeall include also disabled translations
- * @return bool true if exists
- */
- public function translation_exists($lang, $includeall = true) {
-
- if (strpos($lang, '_local') !== false) {
- // Local packs are not real translations.
- return false;
- }
- if (!$includeall and !empty($this->translist)) {
- if (!in_array($lang, $this->translist)) {
- return false;
- }
- }
- if ($lang === 'en') {
- // Part of distribution.
- return true;
- }
- return file_exists("$this->otherroot/$lang/langconfig.php");
- }
-
- /**
- * Returns localised list of installed translations
- *
- * @param bool $returnall return all or just enabled
- * @return array moodle translation code => localised translation name
- */
- public function get_list_of_translations($returnall = false) {
- global $CFG;
-
- $languages = array();
-
- if (!empty($CFG->langcache) and is_readable($this->menucache)) {
- // Try to re-use the cached list of all available languages.
- $cachedlist = json_decode(file_get_contents($this->menucache), true);
-
- if (is_array($cachedlist) and !empty($cachedlist)) {
- // The cache file is restored correctly.
-
- if (!$returnall and !empty($this->translist)) {
- // Return just enabled translations.
- foreach ($cachedlist as $langcode => $langname) {
- if (in_array($langcode, $this->translist)) {
- $languages[$langcode] = $langname;
- }
- }
- return $languages;
-
- } else {
- // Return all translations.
- return $cachedlist;
- }
- }
- }
-
- // The cached list of languages is not available, let us populate the list.
- if (!$returnall and !empty($this->translist)) {
- // Return only some translations.
- foreach ($this->translist as $lang) {
- $lang = trim($lang); // Just trim spaces to be a bit more permissive.
- if (strstr($lang, '_local') !== false) {
- continue;
- }
- if (strstr($lang, '_utf8') !== false) {
- continue;
- }
- if ($lang !== 'en' and !file_exists("$this->otherroot/$lang/langconfig.php")) {
- // Some broken or missing lang - can not switch to it anyway.
- continue;
- }
- $string = $this->load_component_strings('langconfig', $lang);
- if (!empty($string['thislanguage'])) {
- $languages[$lang] = $string['thislanguage'].' ('. $lang .')';
- }
- unset($string);
- }
-
- } else {
- // Return all languages available in system.
- $langdirs = get_list_of_plugins('', '', $this->otherroot);
-
- $langdirs = array_merge($langdirs, array("$CFG->dirroot/lang/en" => 'en'));
- // Sort all.
-
- // Loop through all langs and get info.
- foreach ($langdirs as $lang) {
- if (strstr($lang, '_local') !== false) {
- continue;
- }
- if (strstr($lang, '_utf8') !== false) {
- continue;
- }
- $string = $this->load_component_strings('langconfig', $lang);
- if (!empty($string['thislanguage'])) {
- $languages[$lang] = $string['thislanguage'].' ('. $lang .')';
- }
- unset($string);
- }
-
- if (!empty($CFG->langcache) and !empty($this->menucache)) {
- // Cache the list so that it can be used next time.
- core_collator::asort($languages);
- check_dir_exists(dirname($this->menucache), true, true);
- file_put_contents($this->menucache, json_encode($languages));
- @chmod($this->menucache, $CFG->filepermissions);
- }
- }
-
- core_collator::asort($languages);
-
- return $languages;
- }
-
- /**
- * Returns localised list of currencies.
- *
- * @param string $lang moodle translation language, null means use current
- * @return array currency code => localised currency name
- */
- public function get_list_of_currencies($lang = null) {
- if ($lang === null) {
- $lang = current_language();
- }
-
- $currencies = $this->load_component_strings('core_currencies', $lang);
- asort($currencies);
-
- return $currencies;
- }
-
- /**
- * Clears both in-memory and on-disk caches
- * @param bool $phpunitreset true means called from our PHPUnit integration test reset
- */
- public function reset_caches($phpunitreset = false) {
- global $CFG;
- require_once("$CFG->libdir/filelib.php");
-
- // Clear the on-disk disk with aggregated string files.
- $this->cache->purge();
-
- if (!$phpunitreset) {
- // Increment the revision counter.
- $langrev = get_config('core', 'langrev');
- $next = time();
- if ($langrev !== false and $next <= $langrev and $langrev - $next < 60*60) {
- // This resolves problems when reset is requested repeatedly within 1s,
- // the < 1h condition prevents accidental switching to future dates
- // because we might not recover from it.
- $next = $langrev+1;
- }
- set_config('langrev', $next);
- }
-
- // Clear the cache containing the list of available translations
- // and re-populate it again.
- fulldelete($this->menucache);
- $this->get_list_of_translations(true);
-
- // Lang packs use PHP files in dataroot, it is better to invalidate opcode caches.
- if (function_exists('opcache_reset')) {
- opcache_reset();
- }
- }
-
- /**
- * Returns string revision counter, this is incremented after any string cache reset.
- * @return int lang string revision counter, -1 if unknown
- */
- public function get_revision() {
- global $CFG;
- if (isset($CFG->langrev)) {
- return (int)$CFG->langrev;
- } else {
- return -1;
- }
- }
-
- // End of external API.
-
- /**
- * Helper method that recursively loads all parents of the given language.
- *
- * @see self::get_language_dependencies()
- * @param string $lang language code
- * @param array $stack list of parent languages already populated in previous recursive calls
- * @return array list of all parents of the given language with the $lang itself added as the last element
- */
- protected function populate_parent_languages($lang, array $stack = array()) {
-
- // English does not have a parent language.
- if ($lang === 'en') {
- return $stack;
- }
-
- // Prevent circular dependency (and thence the infinitive recursion loop).
- if (in_array($lang, $stack)) {
- return $stack;
- }
-
- // Load language configuration and look for the explicit parent language.
- if (!file_exists("$this->otherroot/$lang/langconfig.php")) {
- return $stack;
- }
- $string = array();
- include("$this->otherroot/$lang/langconfig.php");
-
- if (empty($string['parentlanguage']) or $string['parentlanguage'] === 'en') {
- unset($string);
- return array_merge(array($lang), $stack);
-
- } else {
- $parentlang = $string['parentlanguage'];
- unset($string);
- return $this->populate_parent_languages($parentlang, array_merge(array($lang), $stack));
- }
- }
-}
-
-
-/**
- * Fetches minimum strings for installation
- *
- * Minimalistic string fetching implementation
- * that is used in installer before we fetch the wanted
- * language pack from moodle.org lang download site.
- *
- * @package core
- * @copyright 2010 Petr Skoda (http://skodak.org)
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class install_string_manager implements string_manager {
- /** @var string location of pre-install packs for all langs */
- protected $installroot;
-
- /**
- * Crate new instance of install string manager
- */
- public function __construct() {
- global $CFG;
- $this->installroot = "$CFG->dirroot/install/lang";
- }
-
- /**
- * Load all strings for one component
- * @param string $component The module the string is associated with
- * @param string $lang
- * @param bool $disablecache Do not use caches, force fetching the strings from sources
- * @param bool $disablelocal Do not use customized strings in xx_local language packs
- * @return array of all string for given component and lang
- */
- public function load_component_strings($component, $lang, $disablecache=false, $disablelocal=false) {
- // Not needed in installer.
- return array();
- }
-
- /**
- * Does the string actually exist?
- *
- * get_string() is throwing debug warnings, sometimes we do not want them
- * or we want to display better explanation of the problem.
- *
- * Use with care!
- *
- * @param string $identifier The identifier of the string to search for
- * @param string $component The module the string is associated with
- * @return boot true if exists
- */
- public function string_exists($identifier, $component) {
- // Simple old style hack ;).
- $str = get_string($identifier, $component);
- return (strpos($str, '[[') === false);
- }
-
- /**
- * Get String returns a requested string
- *
- * @param string $identifier The identifier of the string to search for
- * @param string $component The module the string is associated with
- * @param string|object|array $a An object, string or number that can be used
- * within translation strings
- * @param string $lang moodle translation language, null means use current
- * @return string The String !
- */
- public function get_string($identifier, $component = '', $a = null, $lang = null) {
- if (!$component) {
- $component = 'moodle';
- }
-
- if ($lang === null) {
- $lang = current_language();
- }
-
- // Get parent lang.
- $parent = '';
- if ($lang !== 'en' and $identifier !== 'parentlanguage' and $component !== 'langconfig') {
- if (file_exists("$this->installroot/$lang/langconfig.php")) {
- $string = array();
- include("$this->installroot/$lang/langconfig.php");
- if (isset($string['parentlanguage'])) {
- $parent = $string['parentlanguage'];
- }
- unset($string);
- }
- }
-
- // Include en string first.
- if (!file_exists("$this->installroot/en/$component.php")) {
- return "[[$identifier]]";
- }
- $string = array();
- include("$this->installroot/en/$component.php");
-
- // Now override en with parent if defined.
- if ($parent and $parent !== 'en' and file_exists("$this->installroot/$parent/$component.php")) {
- include("$this->installroot/$parent/$component.php");
- }
-
- // Finally override with requested language.
- if ($lang !== 'en' and file_exists("$this->installroot/$lang/$component.php")) {
- include("$this->installroot/$lang/$component.php");
- }
-
- if (!isset($string[$identifier])) {
- return "[[$identifier]]";
- }
-
- $string = $string[$identifier];
-
- if ($a !== null) {
- if (is_object($a) or is_array($a)) {
- $a = (array)$a;
- $search = array();
- $replace = array();
- foreach ($a as $key => $value) {
- if (is_int($key)) {
- // We do not support numeric keys - sorry!
- continue;
- }
- $search[] = '{$a->'.$key.'}';
- $replace[] = (string)$value;
- }
- if ($search) {
- $string = str_replace($search, $replace, $string);
- }
- } else {
- $string = str_replace('{$a}', (string)$a, $string);
- }
- }
-
- return $string;
- }
-
- /**
- * Returns a localised list of all country names, sorted by country keys.
- *
- * @param bool $returnall return all or just enabled
- * @param string $lang moodle translation language, null means use current
- * @return array two-letter country code => translated name.
- */
- public function get_list_of_countries($returnall = false, $lang = null) {
- // Not used in installer.
- return array();
- }
-
- /**
- * Returns a localised list of languages, sorted by code keys.
- *
- * @param string $lang moodle translation language, null means use current
- * @param string $standard language list standard
- * iso6392: three-letter language code (ISO 639-2/T) => translated name.
- * @return array language code => translated name
- */
- public function get_list_of_languages($lang = null, $standard = 'iso6392') {
- // Not used in installer.
- return array();
- }
-
- /**
- * Checks if the translation exists for the language
- *
- * @param string $lang moodle translation language code
- * @param bool $includeall include also disabled translations
- * @return bool true if exists
- */
- public function translation_exists($lang, $includeall = true) {
- return file_exists($this->installroot.'/'.$lang.'/langconfig.php');
- }
-
- /**
- * Returns localised list of installed translations
- * @param bool $returnall return all or just enabled
- * @return array moodle translation code => localised translation name
- */
- public function get_list_of_translations($returnall = false) {
- // Return all is ignored here - we need to know all langs in installer.
- $languages = array();
- // Get raw list of lang directories.
- $langdirs = get_list_of_plugins('install/lang');
- asort($langdirs);
- // Get some info from each lang.
- foreach ($langdirs as $lang) {
- if (file_exists($this->installroot.'/'.$lang.'/langconfig.php')) {
- $string = array();
- include($this->installroot.'/'.$lang.'/langconfig.php');
- if (!empty($string['thislanguage'])) {
- $languages[$lang] = $string['thislanguage'].' ('.$lang.')';
- }
- }
- }
- // Return array.
- return $languages;
- }
-
- /**
- * Returns localised list of currencies.
- *
- * @param string $lang moodle translation language, null means use current
- * @return array currency code => localised currency name
- */
- public function get_list_of_currencies($lang = null) {
- // Not used in installer.
- return array();
- }
-
- /**
- * This implementation does not use any caches.
- *
- * @param bool $phpunitreset true means called from our PHPUnit integration test reset
- */
- public function reset_caches($phpunitreset = false) {
- // Nothing to do.
- }
-
- /**
- * Returns string revision counter, this is incremented after any string cache reset.
- * @return int lang string revision counter, -1 if unknown
- */
- public function get_revision() {
- return -1;
- }
-}
-
-
/**
* Returns a localized string.
*
/**
* rc4encrypt
*
- * Please note that in this version of moodle that the default for rc4encryption is
- * using the slightly more secure password key. There may be an issue when upgrading
- * from an older version of moodle.
- *
- * @todo MDL-31836 Remove the old password key in version 2.4
- * Code also needs to be changed in sessionlib.php
- * @see get_moodle_cookie()
- * @see set_moodle_cookie()
- *
* @param string $data Data to encrypt.
- * @param bool $usesecurekey Lets us know if we are using the old or new secure password key.
* @return string The now encrypted data.
*/
-function rc4encrypt($data, $usesecurekey = true) {
- if (!$usesecurekey) {
- $passwordkey = 'nfgjeingjk';
- } else {
- $passwordkey = get_site_identifier();
- }
- return endecrypt($passwordkey, $data, '');
+function rc4encrypt($data) {
+ return endecrypt(get_site_identifier(), $data, '');
}
/**
* rc4decrypt
*
- * Please note that in this version of moodle that the default for rc4encryption is
- * using the slightly more secure password key. There may be an issue when upgrading
- * from an older version of moodle.
- *
- * @todo MDL-31836 Remove the old password key in version 2.4
- * Code also needs to be changed in sessionlib.php
- * @see get_moodle_cookie()
- * @see set_moodle_cookie()
- *
* @param string $data Data to decrypt.
- * @param bool $usesecurekey Lets us know if we are using the old or new secure password key.
* @return string The now decrypted data.
*/
-function rc4decrypt($data, $usesecurekey = true) {
- if (!$usesecurekey) {
- $passwordkey = 'nfgjeingjk';
- } else {
- $passwordkey = get_site_identifier();
- }
- return endecrypt($passwordkey, $data, 'de');
+function rc4decrypt($data) {
+ return endecrypt(get_site_identifier(), $data, 'de');
}
/**
return core_component::is_valid_plugin_name('tool', $name);
}
-/**
- * Get a list of all the plugins of a given type that contain a particular file.
- *
- * @param string $plugintype the type of plugin, e.g. 'mod' or 'report'.
- * @param string $file the name of file that must be present in the plugin.
- * (e.g. 'view.php', 'db/install.xml').
- * @param bool $include if true (default false), the file will be include_once-ed if found.
- * @return array with plugin name as keys (e.g. 'forum', 'courselist') and the path
- * to the file relative to dirroot as value (e.g. "$CFG->dirroot/mod/forum/view.php").
- */
-function get_plugin_list_with_file($plugintype, $file, $include = false) {
- global $CFG; // Necessary in case it is referenced by include()d PHP scripts.
-
- $plugins = array();
-
- foreach (core_component::get_plugin_list($plugintype) as $plugin => $dir) {
- $path = $dir . '/' . $file;
- if (file_exists($path)) {
- if ($include) {
- include_once($path);
- }
- $plugins[$plugin] = $path;
- }
- }
-
- return $plugins;
-}
-
/**
* Get a list of all the plugins of a given type that define a certain API function
* in a certain file. The plugin component names and function names are returned.
*/
function get_plugin_list_with_function($plugintype, $function, $file = 'lib.php') {
$pluginfunctions = array();
- foreach (get_plugin_list_with_file($plugintype, $file, true) as $plugin => $notused) {
+ $pluginswithfile = core_component::get_plugin_list_with_file($plugintype, $file, true);
+ foreach ($pluginswithfile as $plugin => $notused) {
$fullfunction = $plugintype . '_' . $plugin . '_' . $function;
if (function_exists($fullfunction)) {
}
/**
- * Determine if moodle installation requires update
+ * Determine if moodle installation requires update.
*
- * Checks version numbers of main code and all modules to see
- * if there are any mismatches
+ * Checks version numbers of main code and all plugins to see
+ * if there are any mismatches.
*
* @return bool
*/
function moodle_needs_upgrading() {
- global $CFG, $DB;
+ global $CFG;
if (empty($CFG->version)) {
return true;
}
- // We have to purge plugin related caches now to be sure we have fresh data
- // and new plugins can be detected.
- cache::make('core', 'plugininfo_base')->purge();
- cache::make('core', 'plugininfo_mod')->purge();
- cache::make('core', 'plugininfo_block')->purge();
- cache::make('core', 'plugininfo_filter')->purge();
- cache::make('core', 'plugininfo_repository')->purge();
- cache::make('core', 'plugininfo_portfolio')->purge();
+ // There is no need to purge plugininfo caches here because
+ // these caches are not used during upgrade and they are purged after
+ // every upgrade.
- // Check the main version first.
- $version = null;
- include($CFG->dirroot.'/version.php'); // Defines $version and upgrades.
- if ($version > $CFG->version) {
+ if (empty($CFG->allversionshash)) {
return true;
}
- // Modules.
- $mods = core_component::get_plugin_list('mod');
- $installed = $DB->get_records('modules', array(), '', 'name, version');
- foreach ($mods as $mod => $fullmod) {
- if ($mod === 'NEWMODULE') { // Someone has unzipped the template, ignore it.
- continue;
- }
- $module = new stdClass();
- $plugin = new stdClass();
- if (!is_readable($fullmod.'/version.php')) {
- continue;
- }
- include($fullmod.'/version.php'); // Defines $module with version etc.
- if (!isset($module->version) and isset($plugin->version)) {
- $module = $plugin;
- }
- if (empty($installed[$mod])) {
- return true;
- } else if ($module->version > $installed[$mod]->version) {
- return true;
- }
- }
- unset($installed);
-
- // Blocks.
- $blocks = core_component::get_plugin_list('block');
- $installed = $DB->get_records('block', array(), '', 'name, version');
- require_once($CFG->dirroot.'/blocks/moodleblock.class.php');
- foreach ($blocks as $blockname => $fullblock) {
- if ($blockname === 'NEWBLOCK') { // Someone has unzipped the template, ignore it.
- continue;
- }
- if (!is_readable($fullblock.'/version.php')) {
- continue;
- }
- $plugin = new stdClass();
- $plugin->version = null;
- include($fullblock.'/version.php');
- if (empty($installed[$blockname])) {
- return true;
- } else if ($plugin->version > $installed[$blockname]->version) {
- return true;
- }
- }
- unset($installed);
-
- // Now the rest of plugins.
- $plugintypes = core_component::get_plugin_types();
- unset($plugintypes['mod']);
- unset($plugintypes['block']);
+ $hash = core_component::get_all_versions_hash();
- $versions = $DB->get_records_menu('config_plugins', array('name' => 'version'), 'plugin', 'plugin, value');
- foreach ($plugintypes as $type => $unused) {
- $plugs = core_component::get_plugin_list($type);
- foreach ($plugs as $plug => $fullplug) {
- $component = $type.'_'.$plug;
- if (!is_readable($fullplug.'/version.php')) {
- continue;
- }
- $plugin = new stdClass();
- include($fullplug.'/version.php'); // Defines $plugin with version etc.
- if (array_key_exists($component, $versions)) {
- $installedversion = $versions[$component];
- } else {
- $installedversion = get_config($component, 'version');
- }
- if (empty($installedversion)) { // New installation.
- return true;
- } else if ($installedversion < $plugin->version) { // Upgrade.
- return true;
- }
- }
- }
-
- return false;
+ return ($hash !== $CFG->allversionshash);
}
/**
}
// Give the local plugins a chance to include some navigation if they want.
- foreach (get_plugin_list_with_file('local', 'lib.php', true) as $plugin => $file) {
+ foreach (core_component::get_plugin_list_with_file('local', 'lib.php', true) as $plugin => $file) {
$function = "local_{$plugin}_extends_navigation";
$oldfunction = "{$plugin}_extends_navigation";
if (function_exists($function)) {
// Portfolio
if ($currentuser && !empty($CFG->enableportfolios) && has_capability('moodle/portfolio:export', $systemcontext)) {
require_once($CFG->libdir . '/portfoliolib.php');
- if (portfolio_instances(true, false)) {
+ if (portfolio_has_visible_instances()) {
$portfolio = $usersetting->add(get_string('portfolios', 'portfolio'), null, self::TYPE_SETTING);
$url = new moodle_url('/user/portfolio.php', array('courseid'=>$course->id));
$link= '<a title="' . $title . '" href="' . $url . '">' . $txt . '</a>';
$output .= '<div class="profilingfooter">' . $link . '</div>';
}
- $output .= '<div class="purgecaches"><a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/purgecaches.php?confirm=1&sesskey='.sesskey().'">'.get_string('purgecaches', 'admin').'</a></div>';
+ $purgeurl = new moodle_url('/admin/purgecaches.php', array('confirm' => 1,
+ 'sesskey' => sesskey(), 'returnurl' => $this->page->url->out_as_local_url(false)));
+ $output .= '<div class="purgecaches">' .
+ html_writer::link($purgeurl, get_string('purgecaches', 'admin')) . '</div>';
}
if (!empty($CFG->debugvalidators)) {
// NOTE: this is not a nice hack, $PAGE->url is not always accurate and $FULLME neither, it is not a bug if it fails. --skodak
array('nofilesavailable', 'repository'), array('norepositoriesavailable', 'repository'),
array('fileexistsdialogheader', 'repository'), array('fileexistsdialog_editor', 'repository'),
array('fileexistsdialog_filemanager', 'repository'), array('renameto', 'repository'),
- array('referencesexist', 'repository')
+ array('referencesexist', 'repository'), array('select', 'repository')
));
break;
case 'core_comment':
initialise_cfg();
return;
}
- if ($dbhash !== self::get_version_hash()) {
+ if ($dbhash !== core_component::get_all_versions_hash()) {
// do not set CFG - the only way forward is to drop and reinstall
return;
}
return $instances;
}
+/**
+ * Return whether there are visible instances in portfolio.
+ *
+ * @return bool true when there are some visible instances.
+ */
+function portfolio_has_visible_instances() {
+ global $DB;
+ return $DB->record_exists('portfolio_instance', array('visible' => 1));
+}
+
/**
* Supported formats currently in use.
* Canonical place for a list of all formats
// Remove some absolute paths from message and debugging info.
$searches = array();
$replaces = array();
- $cfgnames = array('tempdir', 'cachedir', 'localcachedir', 'themedir',
- 'langmenucachefile', 'langcacheroot', 'dataroot', 'dirroot');
+ $cfgnames = array('tempdir', 'cachedir', 'localcachedir', 'themedir', 'dataroot', 'dirroot');
foreach ($cfgnames as $cfgname) {
if (property_exists($CFG, $cfgname)) {
$searches[] = $CFG->$cfgname;
}
} else if ($newlimit == MEMORY_HUGE) {
+ // MEMORY_HUGE uses 2G or MEMORY_EXTRA, whichever is bigger.
$newlimit = get_real_size('2G');
+ if (!empty($CFG->extramemorylimit)) {
+ $extra = get_real_size($CFG->extramemorylimit);
+ if ($extra > $newlimit) {
+ $newlimit = $extra;
+ }
+ }
} else {
$newlimit = get_real_size($newlimit);
*/
function redirect_if_major_upgrade_required() {
global $CFG;
- $lastmajordbchanges = 2013080700.00;
+ $lastmajordbchanges = 2013081400.00;
if (empty($CFG->version) or (float)$CFG->version < $lastmajordbchanges or
during_initial_install() or !empty($CFG->adminsetuppending)) {
try {
return false;
}
- $hash = self::get_version_hash();
+ $hash = core_component::get_all_versions_hash();
$oldhash = file_get_contents($datarootpath . '/versionshash.txt');
if ($hash !== $oldhash) {
global $CFG;
$framework = self::get_framework();
- $hash = self::get_version_hash();
+ $hash = core_component::get_all_versions_hash();
// add test db flag
set_config($framework . 'test', $hash);
}
}
}
-
- /**
- * Calculate unique version hash for all plugins and core.
- * @static
- * @return string sha1 hash
- */
- public static function get_version_hash() {
- global $CFG;
-
- if (self::$versionhash) {
- return self::$versionhash;
- }
-
- $versions = array();
-
- // main version first
- $version = null;
- include($CFG->dirroot.'/version.php');
- $versions['core'] = $version;
-
- // modules
- $mods = core_component::get_plugin_list('mod');
- ksort($mods);
- foreach ($mods as $mod => $fullmod) {
- $module = new stdClass();
- $module->version = null;
- include($fullmod.'/version.php');
- $versions[$mod] = $module->version;
- }
-
- // now the rest of plugins
- $plugintypes = core_component::get_plugin_types();
- unset($plugintypes['mod']);
- ksort($plugintypes);
- foreach ($plugintypes as $type => $unused) {
- $plugs = core_component::get_plugin_list($type);
- ksort($plugs);
- foreach ($plugs as $plug => $fullplug) {
- $plugin = new stdClass();
- $plugin->version = null;
- @include($fullplug.'/version.php');
- $versions[$plug] = $plugin->version;
- }
- }
-
- self::$versionhash = sha1(serialize($versions));
-
- return self::$versionhash;
- }
-
}
$this->assertTrue($result);
$permission = $DB->get_record('role_capabilities', array('contextid'=>$frontcontext->id, 'roleid'=>$student->id, 'capability'=>'moodle/backup:backupcourse'));
$this->assertEmpty($permission);
+
+ // Test event trigger.
+ $rolecapabilityevent = \core\event\role_capabilities_updated::create(array('context' => $syscontext,
+