And I log out
# Create new policy document.
And I log in as "admin"
- And I navigate to "Manage policies" node in "Site administration > Privacy and policies"
+ And I navigate to "Manage policies" node in "Site administration > Users > Privacy and policies"
And I should see "Policies and agreements"
And I should see "New policy"
And I follow "New policy"
And I log out
# Create new version of the policy document.
And I log in as "admin"
- And I navigate to "Manage policies" node in "Site administration > Privacy and policies"
+ And I navigate to "Manage policies" node in "Site administration > Users > Privacy and policies"
When I follow "Actions"
Then I should see "View"
And I should see "Edit"
return;
}
}
+
+ /**
+ * Return a list of identity providers to display on the login page.
+ *
+ * @param string $wantsurl The requested URL.
+ * @return array List of arrays with keys url, iconurl and name.
+ */
+ public function loginpage_idp_list($wantsurl) {
+ $config = get_config('auth_shibboleth');
+ $result = [];
+
+ // Before displaying the button check that Shibboleth is set-up correctly.
+ if (empty($config->user_attribute)) {
+ return $result;
+ }
+
+ $url = new moodle_url('/auth/shibboleth/index.php');
+ $iconurl = moodle_url::make_pluginfile_url(context_system::instance()->id,
+ 'auth_shibboleth',
+ 'logo',
+ null,
+ '/',
+ $config->auth_logo);
+ $result[] = ['url' => $url, 'iconurl' => $iconurl, 'name' => $config->login_name];
+ return $result;
+ }
}
$string['auth_shib_auth_method'] = 'Authentication method name';
$string['auth_shib_auth_method_description'] = 'Provide a name for the Shibboleth authentication method that is familiar to your users. This could be the name of your Shibboleth federation, e.g. <tt>SWITCHaai Login</tt> or <tt>InCommon Login</tt> or similar.';
+$string['auth_shib_auth_logo'] = 'Authentication method logo';
+$string['auth_shib_auth_logo_description'] = 'Provide a logo for the Shibboleth authentication method that is familiar to your users. This could be the logo of your Shibboleth federation, e.g. <tt>SWITCHaai Login</tt> or <tt>InCommon Login</tt> or similar.';
$string['auth_shib_contact_administrator'] = 'In case you are not associated with the given organizations and you need access to a course on this server, please contact the <a href="mailto:{$a}">Moodle Administrator</a>.';
$string['auth_shibbolethdescription'] = 'Using this method users are created and authenticated using <a href="http://shibboleth.internet2.edu/">Shibboleth</a>.<br />Be sure to read the <a href="../auth/shibboleth/README.txt">README</a> for Shibboleth on how to set up your Moodle with Shibboleth';
$string['auth_shibboleth_errormsg'] = 'Please select the organization you are member of!';
--- /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/>.
+
+/**
+ * This file contains the hooks for the Shibboleth authentication module.
+ *
+ * @package auth_shibboleth
+ * @copyright 2018 Fabrice Ménard
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+/**
+ * Serves the logo file settings.
+ *
+ * @param stdClass $course course object
+ * @param stdClass $cm course module object
+ * @param stdClass $context context object
+ * @param string $filearea file area
+ * @param array $args extra arguments
+ * @param bool $forcedownload whether or not force download
+ * @param array $options additional options affecting the file serving
+ * @return bool false if file not found, does not return if found - justsend the file
+ */
+function auth_shibboleth_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
+ if ($context->contextlevel != CONTEXT_SYSTEM) {
+ return false;
+ }
+
+ if ($filearea !== 'logo' ) {
+ return false;
+ }
+
+ $itemid = 0;
+
+ $filename = array_pop($args);
+ if (!$args) {
+ $filepath = '/';
+ } else {
+ $filepath = '/'.implode('/', $args).'/';
+ }
+
+ $fs = get_file_storage();
+ $file = $fs->get_file($context->id, 'auth_shibboleth', $filearea, $itemid, $filepath, $filename);
+ if (!$file) {
+ return false;
+ }
+
+ send_stored_file($file, null, 0, $forcedownload, $options);
+}
get_string('auth_shib_auth_method', 'auth_shibboleth'),
get_string('auth_shib_auth_method_description', 'auth_shibboleth'), 'Shibboleth Login', PARAM_RAW_TRIMMED));
+ // Authentication method logo.
+ $settings->add(new admin_setting_configstoredfile('auth_shibboleth/auth_logo',
+ get_string('auth_shib_auth_logo', 'auth_shibboleth'),
+ get_string('auth_shib_auth_logo_description', 'auth_shibboleth'), 'logo', 0, ['accepted_types' => ['image']]));
+
// Login directions.
$settings->add(new admin_setting_configtextarea('auth_shibboleth/auth_instructions',
get_string('auth_shib_instructions_key', 'auth_shibboleth'),
And I set the field "Password" to "teacher1"
And I press "Log in"
# Confirm the notices are displayed.
- Then I should see "1 failed logins since your last login" in the "nav.navbar" "css_element"
+ Then I should see "1 failed logins since your last login" in the ".navbar" "css_element"
And I should see "1 failed logins since your last login" in the "page-footer" "region"
# Confirm the notices disappear when navigating to another page.
And I am on homepage
- And I should not see "1 failed logins since your last login" in the "nav.navbar" "css_element"
+ And I should not see "1 failed logins since your last login" in the ".navbar" "css_element"
And I should not see "1 failed logins since your last login" in the "page-footer" "region"
# Given the user has at least one failed login attempt, when they login, then they should see both header and footer notices.
And I set the field "Password" to "admin"
And I press "Log in"
# Confirm the notices are displayed.
- Then I should see "1 failed logins since your last login" in the "nav.navbar" "css_element"
+ Then I should see "1 failed logins since your last login" in the ".navbar" "css_element"
And I should see "1 failed logins since your last login (Logs)" in the "page-footer" "region"
# Confirm that the link works and that the notices disappear when navigating to another page.
And I click on "Logs" "link" in the "page-footer" "region"
And I should see "User login failed" in the "table.reportlog" "css_element"
- And I should not see "1 failed logins since your last login" in the "nav.navbar" "css_element"
+ And I should not see "1 failed logins since your last login" in the ".navbar" "css_element"
And I should not see "1 failed logins since your last login (Logs)" in the "page-footer" "region"
Background:
Given I log in as "admin"
- And I navigate to "Privacy settings" node in "Site administration > Privacy and policies"
+ And I navigate to "Privacy settings" node in "Site administration > Users > Privacy and policies"
Scenario: Admin provides valid value for 'Age of digital consent'.
Given I set the field "s__agedigitalconsentmap" to multiline:
And I log in as "teacher1"
Scenario: Import course's contents to another course
- Given I am on "Course 2" course homepage with editing mode on
+ Given I am on "Course 2" course homepage
And I should not see "Online users"
And I should not see "Test quiz"
- And I import "Course 1" course into "Course 2" course using this options:
+ And I import "Course 1" course into "Course 2" course using this options:
And I am on "Course 2" course homepage
And I should see "Online users"
And I should see "Test quiz"
return array('all' => true, 'my' => false, 'tag' => false);
}
- /**
- * Remove old entries from table block_recent_activity
- */
- public function cron() {
- global $DB;
- // Those entries will never be displayed as RECENT anyway.
- $DB->delete_records_select('block_recent_activity', 'timecreated < ?',
- array(time() - COURSE_MAX_RECENT_PERIOD));
- }
-
/**
* Migrates entries from table {log} into {block_recent_activity}
*
--- /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/>.
+
+/**
+ * Task for updating RSS feeds for rss client block
+ *
+ * @package block_recent_activity
+ * @author Farhan Karmali <farhan6318@gmail.com>
+ * @copyright Farhan Karmali 2018
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_recent_activity\task;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Task for updating RSS feeds for rss client block
+ *
+ * @package block_recent_activity
+ * @author Farhan Karmali <farhan6318@gmail.com>
+ * @copyright Farhan Karmali 2018
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class cleanup extends \core\task\scheduled_task {
+
+ /**
+ * Name for this task.
+ *
+ * @return string
+ */
+ public function get_name() {
+ return get_string('cleanuptask', 'block_recent_activity');
+ }
+
+ /**
+ * Remove old entries from table block_recent_activity
+ */
+ public function execute() {
+ global $DB;
+ // Those entries will never be displayed as RECENT anyway.
+ $DB->delete_records_select('block_recent_activity', 'timecreated < ?',
+ array(time() - COURSE_MAX_RECENT_PERIOD));
+ }
+}
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
- * A scheduled task.
- *
- * @package core
- * @copyright 2013 onwards Martin Dougiamas http://dougiamas.com
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * Task definition for block_recent_activity.
+ * @author Farhan Karmali <farhan6318@gmail.com>
+ * @copyright Farhan Karmali 2018
+ * @package block_recent_activity
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-namespace core\task;
-/**
- * Simple task to run the events cron.
- */
-class events_cron_task extends scheduled_task {
-
- /**
- * Get a descriptive name for this task (shown to admins).
- *
- * @return string
- */
- public function get_name() {
- return get_string('taskeventscron', 'admin');
- }
+defined('MOODLE_INTERNAL') || die();
- /**
- * Do the job.
- * Throw exceptions on errors (the job will be retried).
- */
- public function execute() {
- events_cron();
- }
+$tasks = array(
+ array(
+ 'classname' => '\block_recent_activity\task\cleanup',
+ 'blocking' => 0,
+ 'minute' => 'R',
+ 'hour' => 'R',
+ 'day' => '*',
+ 'month' => '*',
+ 'dayofweek' => '*',
+ 'disabled' => 0
+ )
+);
-}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
+$string['cleanuptask'] = 'Cleanup task for recent activity block';
$string['pluginname'] = 'Recent activity';
$string['privacy:metadata'] = 'The recent activity block contains a cache of data stored elsewhere in Moodle.';
$string['privacy:metadata:block_recent_activity'] = 'Temporary log of recent teacher activity. Removed after two days';
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2018051400; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version = 2018052900; // The current plugin version (Date: YYYYMMDDXX)
$plugin->requires = 2018050800; // Requires this Moodle version
$plugin->component = 'block_recent_activity'; // Full name of the plugin (used for diagnostics)
-$plugin->cron = 24*3600; // Cron interval 1 day.
\ No newline at end of file
}
}
- /**
- * cron - goes through all the feeds. If the feed has a skipuntil value
- * that is less than the current time cron will attempt to retrieve it
- * with the cache duration set to 0 in order to force the retrieval of
- * the item and refresh the cache.
- *
- * If a feed fails then the skipuntil time of that feed is set to be
- * later than the next expected cron time. The amount of time will
- * increase each time the fetch fails until the maximum is reached.
- *
- * If a feed that has been failing is successfully retrieved it will
- * go back to being handled as though it had never failed.
- *
- * CRON should therefor process requests for permanently broken RSS
- * feeds infrequently, and temporarily unavailable feeds will be tried
- * less often until they become available again.
- *
- * @return boolean Always returns true
- */
- function cron() {
- global $CFG, $DB;
- require_once($CFG->libdir.'/simplepie/moodle_simplepie.php');
-
- // Get the legacy cron time, strangely the cron property of block_base
- // does not seem to get set. This means we must retrive it here.
- $this->cron = $DB->get_field('block', 'cron', array('name' => 'rss_client'));
-
- // We are going to measure execution times
- $starttime = microtime();
- $starttimesec = time();
-
- // Fetch all site feeds.
- $rs = $DB->get_recordset('block_rss_client');
- $counter = 0;
- mtrace('');
- foreach ($rs as $rec) {
- mtrace(' ' . $rec->url . ' ', '');
-
- // Skip feed if it failed recently.
- if ($starttimesec < $rec->skipuntil) {
- mtrace('skipping until ' . userdate($rec->skipuntil));
- continue;
- }
-
- // Fetch the rss feed, using standard simplepie caching
- // so feeds will be renewed only if cache has expired
- core_php_time_limit::raise(60);
-
- $feed = new moodle_simplepie();
- // set timeout for longer than normal to be agressive at
- // fetching feeds if possible..
- $feed->set_timeout(40);
- $feed->set_cache_duration(0);
- $feed->set_feed_url($rec->url);
- $feed->init();
-
- if ($feed->error()) {
- // Skip this feed (for an ever-increasing time if it keeps failing).
- $rec->skiptime = $this->calculate_skiptime($rec->skiptime);
- $rec->skipuntil = time() + $rec->skiptime;
- $DB->update_record('block_rss_client', $rec);
- mtrace("Error: could not load/find the RSS feed - skipping for {$rec->skiptime} seconds.");
- } else {
- mtrace ('ok');
- // It worked this time, so reset the skiptime.
- if ($rec->skiptime > 0) {
- $rec->skiptime = 0;
- $rec->skipuntil = 0;
- $DB->update_record('block_rss_client', $rec);
- }
- // Only increase the counter when a feed is sucesfully refreshed.
- $counter ++;
- }
- }
- $rs->close();
-
- // Show times
- mtrace($counter . ' feeds refreshed (took ' . microtime_diff($starttime, microtime()) . ' seconds)');
-
- return true;
- }
-
/**
* Calculates a new skip time for a record based on the current skip time.
*
* @param int $currentskip The curreent skip time of a record.
* @return int A new skip time that should be set.
*/
- protected function calculate_skiptime($currentskip) {
+ public function calculate_skiptime($currentskip) {
// The default time to skiptime.
$newskiptime = $this->cron * 1.1;
if ($currentskip > 0) {
--- /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/>.
+
+/**
+ * Task for updating RSS feeds for rss client block
+ *
+ * @package block_rss_client
+ * @author Farhan Karmali <farhan6318@gmail.com>
+ * @copyright Farhan Karmali 2018
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_rss_client\task;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Task for updating RSS feeds for rss client block
+ *
+ * @package block_rss_client
+ * @author Farhan Karmali <farhan6318@gmail.com>
+ * @copyright Farhan Karmali 2018
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class refreshfeeds extends \core\task\scheduled_task {
+
+ /**
+ * Name for this task.
+ *
+ * @return string
+ */
+ public function get_name() {
+ return get_string('refreshfeedstask', 'block_rss_client');
+ }
+
+ /**
+ * This task goes through all the feeds. If the feed has a skipuntil value
+ * that is less than the current time cron will attempt to retrieve it
+ * with the cache duration set to 0 in order to force the retrieval of
+ * the item and refresh the cache.
+ *
+ * If a feed fails then the skipuntil time of that feed is set to be
+ * later than the next expected task time. The amount of time will
+ * increase each time the fetch fails until the maximum is reached.
+ *
+ * If a feed that has been failing is successfully retrieved it will
+ * go back to being handled as though it had never failed.
+ *
+ * Task should therefore process requests for permanently broken RSS
+ * feeds infrequently, and temporarily unavailable feeds will be tried
+ * less often until they become available again.
+ */
+ public function execute() {
+ global $CFG, $DB;
+ require_once($CFG->libdir.'/simplepie/moodle_simplepie.php');
+
+ // We are going to measure execution times.
+ $starttime = microtime();
+ $starttimesec = time();
+
+ // Fetch all site feeds.
+ $rs = $DB->get_recordset('block_rss_client');
+ $counter = 0;
+ mtrace('');
+ foreach ($rs as $rec) {
+ mtrace(' ' . $rec->url . ' ', '');
+
+ // Skip feed if it failed recently.
+ if ($starttimesec < $rec->skipuntil) {
+ mtrace('skipping until ' . userdate($rec->skipuntil));
+ continue;
+ }
+
+ // Fetch the rss feed, using standard simplepie caching
+ // so feeds will be renewed only if cache has expired.
+ \core_php_time_limit::raise(60);
+
+ $feed = new \moodle_simplepie();
+ // Set timeout for longer than normal to be agressive at
+ // fetching feeds if possible..
+ $feed->set_timeout(40);
+ $feed->set_cache_duration(0);
+ $feed->set_feed_url($rec->url);
+ $feed->init();
+
+ if ($feed->error()) {
+ // Skip this feed (for an ever-increasing time if it keeps failing).
+ $block = new \block_rss_client();
+ $rec->skiptime = $block->calculate_skiptime($rec->skiptime);
+ $rec->skipuntil = time() + $rec->skiptime;
+ $DB->update_record('block_rss_client', $rec);
+ mtrace("Error: could not load/find the RSS feed - skipping for {$rec->skiptime} seconds.");
+ } else {
+ mtrace ('ok');
+ // It worked this time, so reset the skiptime.
+ if ($rec->skiptime > 0) {
+ $rec->skiptime = 0;
+ $rec->skipuntil = 0;
+ $DB->update_record('block_rss_client', $rec);
+ }
+ // Only increase the counter when a feed is sucesfully refreshed.
+ $counter ++;
+ }
+ }
+ $rs->close();
+
+ // Show times.
+ mtrace($counter . ' feeds refreshed (took ' . microtime_diff($starttime, microtime()) . ' seconds)');
+
+ }
+}
--- /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/>.
+
+/**
+ * Task definition for block_rss_client.
+ * @author Farhan Karmali <farhan6318@gmail.com>
+ * @copyright Farhan Karmali 2018
+ * @package block_rss_client
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$tasks = array(
+ array(
+ 'classname' => '\block_rss_client\task\refreshfeeds',
+ 'blocking' => 0,
+ 'minute' => '*/5',
+ 'hour' => '*',
+ 'day' => '*',
+ 'month' => '*',
+ 'dayofweek' => '*',
+ 'disabled' => 0
+ )
+);
+
$string['privacy:metadata:block_rss_client:url'] = 'The URL of the RSS feed.';
$string['privacy:metadata:block_rss_client:userid'] = 'The ID of the user that added the RSS feed.';
$string['remotenewsfeed'] = 'Remote news feed';
+$string['refreshfeedstask'] = 'Refresh RSS feeds task';
$string['rss_client:addinstance'] = 'Add a new remote RSS feeds block';
$string['rss_client:createprivatefeeds'] = 'Create private RSS feeds';
$string['rss_client:createsharedfeeds'] = 'Create shared RSS feeds';
);
$DB->insert_record('block_rss_client', $record);
- $block = new block_rss_client();
+ $task = new \block_rss_client\task\refreshfeeds();
ob_start();
// Silence SimplePie php notices.
$errorlevel = error_reporting($CFG->debug & ~E_USER_NOTICE);
- $block->cron();
+ $task->execute();
error_reporting($errorlevel);
$cronoutput = ob_get_clean();
}
/**
- * Test that when a feed has an error the skip time is increaed correctly.
+ * Test that when a feed has an error the skip time is increased correctly.
*/
public function test_error() {
global $DB, $CFG;
);
$record3->id = $DB->insert_record('block_rss_client', $record3);
- // Run the cron.
- $block = new block_rss_client();
+ // Run the scheduled task.
+ $task = new \block_rss_client\task\refreshfeeds();
ob_start();
// Silence SimplePie php notices.
$errorlevel = error_reporting($CFG->debug & ~E_USER_NOTICE);
- $block->cron();
+ $task->execute();
error_reporting($errorlevel);
$cronoutput = ob_get_clean();
$skiptime1 = $record->skiptime * 2;
$message1 = 'http://example.com/rss Error: could not load/find the RSS feed - skipping for ' . $skiptime1 . ' seconds.';
$this->assertContains($message1, $cronoutput);
- $skiptime2 = 330; // Assumes that the cron time in the version file is 300.
+ $skiptime2 = 0;
$message2 = 'http://example.com/rss2 Error: could not load/find the RSS feed - skipping for ' . $skiptime2 . ' seconds.';
$this->assertContains($message2, $cronoutput);
$skiptime3 = block_rss_client::CLIENT_MAX_SKIPTIME;
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2018051400; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version = 2018052900; // The current plugin version (Date: YYYYMMDDXX)
$plugin->requires = 2018050800; // Requires this Moodle version
$plugin->component = 'block_rss_client'; // Full name of the plugin (used for diagnostics)
-$plugin->cron = 300; // Set min time between cron executions to 300 secs (5 mins)
*/
protected static $modulecache = array();
+ /**
+ * @var int The requesting user. All capability checks are done against this user.
+ */
+ protected static $requestinguserid;
+
/**
* Initialises the dependency graph if it hasn't yet been.
*/
[self::class, 'apply_component_provide_event_action'],
[self::class, 'apply_component_is_event_visible'],
function ($dbrow) {
+ $requestinguserid = self::get_requesting_user();
+
if (!empty($dbrow->categoryid)) {
// This is a category event. Check that the category is visible to this user.
- $category = \coursecat::get($dbrow->categoryid, IGNORE_MISSING, true);
+ $category = \coursecat::get($dbrow->categoryid, IGNORE_MISSING, true, $requestinguserid);
- if (empty($category) || !$category->is_uservisible()) {
+ if (empty($category) || !$category->is_uservisible($requestinguserid)) {
return true;
}
}
return false;
}
- $instances = get_fast_modinfo($dbrow->courseid)->instances;
+ $instances = get_fast_modinfo($dbrow->courseid, $requestinguserid)->instances;
// If modinfo doesn't know about the module, we should ignore it.
if (!isset($instances[$dbrow->modulename]) || !isset($instances[$dbrow->modulename][$dbrow->instance])) {
}
$coursecontext = \context_course::instance($dbrow->courseid);
- if (!$cm->get_course()->visible && !has_capability('moodle/course:viewhiddencourses', $coursecontext)) {
+ if (!$cm->get_course()->visible &&
+ !has_capability('moodle/course:viewhiddencourses', $coursecontext, $requestinguserid)) {
return true;
}
- if (!has_capability('moodle/course:view', $coursecontext) && !is_enrolled($coursecontext)) {
+ if (!has_capability('moodle/course:view', $coursecontext, $requestinguserid) &&
+ !is_enrolled($coursecontext, $requestinguserid)) {
return true;
}
* Reset all static caches, called between tests.
*/
public static function reset_caches() {
+ self::$requestinguserid = null;
self::$eventfactory = null;
self::$eventmapper = null;
self::$eventvault = null;
return self::$eventvault;
}
+ /**
+ * Sets the requesting user so that all capability checks are done against this user.
+ * Setting the requesting user (hence calling this function) is optional and if you do not so,
+ * $USER will be used as the requesting user. However, if you wish to set the requesting user yourself,
+ * you should call this function before any other function of the container class is called.
+ *
+ * @param int $userid The user id.
+ * @throws \coding_exception
+ */
+ public static function set_requesting_user($userid) {
+ self::$requestinguserid = $userid;
+ }
+
+ /**
+ * Returns the requesting user id.
+ * It usually is the current user unless it has been set explicitly using set_requesting_user.
+ *
+ * @return int
+ */
+ public static function get_requesting_user() {
+ global $USER;
+
+ return empty(self::$requestinguserid) ? $USER->id : self::$requestinguserid;
+ }
+
/**
* Calls callback 'core_calendar_provide_event_action' from the component responsible for the event
*
$mapper = self::$eventmapper;
$action = null;
if ($event->get_course_module()) {
+ $requestinguserid = self::get_requesting_user();
+ $legacyevent = $mapper->from_event_to_legacy_event($event);
+ // We know for a fact that the the requesting user might be different from the logged in user,
+ // but the event mapper is not aware of that.
+ if (empty($event->user) && !empty($legacyevent->userid)) {
+ $legacyevent->userid = $requestinguserid;
+ }
+
// TODO MDL-58866 Only activity modules currently support this callback.
// Any other event will not be displayed on the dashboard.
$action = component_callback(
'mod_' . $event->get_course_module()->get('modname'),
'core_calendar_provide_event_action',
[
- $mapper->from_event_to_legacy_event($event),
- self::$actionfactory
+ $legacyevent,
+ self::$actionfactory,
+ $requestinguserid
]
);
}
$mapper = self::$eventmapper;
$eventvisible = null;
if ($event->get_course_module()) {
+ $requestinguserid = self::get_requesting_user();
+ $legacyevent = $mapper->from_event_to_legacy_event($event);
+ // We know for a fact that the the requesting user might be different from the logged in user,
+ // but the event mapper is not aware of that.
+ if (empty($event->user) && !empty($legacyevent->userid)) {
+ $legacyevent->userid = $requestinguserid;
+ }
+
// TODO MDL-58866 Only activity modules currently support this callback.
$eventvisible = component_callback(
'mod_' . $event->get_course_module()->get('modname'),
'core_calendar_is_event_visible',
[
- $mapper->from_event_to_legacy_event($event)
+ $legacyevent,
+ $requestinguserid
]
);
}
return array();
}
+ if (is_numeric($users)) {
+ $users = array($users);
+ }
+ if (is_numeric($groups)) {
+ $groups = array($groups);
+ }
+ if (is_numeric($courses)) {
+ $courses = array($courses);
+ }
+ if (is_numeric($categories)) {
+ $categories = array($categories);
+ }
+
// Array of filter conditions. To be concatenated by the OR operator.
$filters = [];
// User filter.
- if ((is_array($users) && !empty($users)) or is_numeric($users)) {
+ if (is_array($users) && !empty($users)) {
// Events from a number of users.
list($insqlusers, $inparamsusers) = $DB->get_in_or_equal($users, SQL_PARAMS_NAMED);
$filters[] = "(e.userid $insqlusers AND e.courseid = 0 AND e.groupid = 0 AND e.categoryid = 0)";
// Boolean false (no users at all): We don't need to do anything.
// Group filter.
- if ((is_array($groups) && !empty($groups)) or is_numeric($groups)) {
+ if (is_array($groups) && !empty($groups)) {
// Events from a number of groups.
list($insqlgroups, $inparamsgroups) = $DB->get_in_or_equal($groups, SQL_PARAMS_NAMED);
$filters[] = "e.groupid $insqlgroups";
// Boolean false (no groups at all): We don't need to do anything.
// Course filter.
- if ((is_array($courses) && !empty($courses)) or is_numeric($courses)) {
+ if (is_array($courses) && !empty($courses)) {
list($insqlcourses, $inparamscourses) = $DB->get_in_or_equal($courses, SQL_PARAMS_NAMED);
$filters[] = "(e.groupid = 0 AND e.courseid $insqlcourses)";
$params = array_merge($params, $inparamscourses);
}
// Category filter.
- if ((is_array($categories) && !empty($categories)) or is_numeric($categories)) {
+ if (is_array($categories) && !empty($categories)) {
list($insqlcategories, $inparamscategories) = $DB->get_in_or_equal($categories, SQL_PARAMS_NAMED);
$filters[] = "(e.groupid = 0 AND e.courseid = 0 AND e.categoryid $insqlcategories)";
$params = array_merge($params, $inparamscategories);
// Build SQL subquery and conditions for filtered events based on priorities.
$subquerywhere = '';
$subqueryconditions = [];
-
- // Get the user's courses. Otherwise, get the default courses being shown by the calendar.
- $usercourses = calendar_get_default_courses(null, 'id, category, groupmode, groupmodeforce');
-
- // Set calendar filters.
- list($usercourses, $usergroups, $user) = calendar_set_filters($usercourses, true);
$subqueryparams = [];
-
- // Flag to indicate whether the query needs to exclude group overrides.
- $viewgroupsonly = false;
-
- if ($user) {
- // Set filter condition for the user's events.
- $subqueryconditions[] = "(ev.userid = :user AND ev.courseid = 0 AND ev.groupid = 0 AND ev.categoryid = 0)";
- $subqueryparams['user'] = $user;
-
- foreach ($usercourses as $courseid) {
- if (has_capability('moodle/site:accessallgroups', \context_course::instance($courseid))) {
- $usergroupmembership = groups_get_all_groups($courseid, $user, 0, 'g.id');
- if (count($usergroupmembership) == 0) {
- $viewgroupsonly = true;
- break;
+ $allusercourses = [];
+
+ if (is_array($users) && !empty($users)) {
+ $userrecords = $DB->get_records_sql("SELECT * FROM {user} WHERE id $insqlusers", $inparamsusers);
+ foreach ($userrecords as $userrecord) {
+ // Get the user's courses. Otherwise, get the default courses being shown by the calendar.
+ $usercourses = calendar_get_default_courses(null, 'id, category, groupmode, groupmodeforce',
+ false, $userrecord->id);
+
+ // Set calendar filters.
+ list($usercourses, $usergroups, $user) = calendar_set_filters($usercourses, true, $userrecord);
+
+ $allusercourses = array_merge($allusercourses, $usercourses);
+
+ // Flag to indicate whether the query needs to exclude group overrides.
+ $viewgroupsonly = false;
+
+ if ($user) {
+ // Set filter condition for the user's events.
+ // Even though $user is a single scalar, we still use get_in_or_equal() because we are inside a loop.
+ list($inusers, $inuserparams) = $DB->get_in_or_equal($user, SQL_PARAMS_NAMED);
+ $subqueryconditions[] = "(ev.userid $inusers AND ev.courseid = 0 AND ev.groupid = 0 AND ev.categoryid = 0)";
+ $subqueryparams = array_merge($subqueryparams, $inuserparams);
+
+ foreach ($usercourses as $courseid) {
+ if (has_capability('moodle/site:accessallgroups', \context_course::instance($courseid), $userrecord)) {
+ $usergroupmembership = groups_get_all_groups($courseid, $user, 0, 'g.id');
+ if (count($usergroupmembership) == 0) {
+ $viewgroupsonly = true;
+ break;
+ }
+ }
}
}
+
+ // Set filter condition for the user's group events.
+ if ($usergroups === true || $viewgroupsonly) {
+ // Fetch group events, but not group overrides.
+ $subqueryconditions[] = "(ev.groupid != 0 AND ev.eventtype = 'group')";
+ } else if (!empty($usergroups)) {
+ // Fetch group events and group overrides.
+ list($inusergroups, $inusergroupparams) = $DB->get_in_or_equal($usergroups, SQL_PARAMS_NAMED);
+ $subqueryconditions[] = "(ev.groupid $inusergroups)";
+ $subqueryparams = array_merge($subqueryparams, $inusergroupparams);
+ }
+ }
+ } else if ($users === true) {
+ // Events from ALL users.
+ $subqueryconditions[] = "(ev.userid != 0 AND ev.courseid = 0 AND ev.groupid = 0 AND ev.categoryid = 0)";
+
+ if (is_array($groups)) {
+ // Events from a number of groups.
+ list($insqlgroups, $inparamsgroups) = $DB->get_in_or_equal($groups, SQL_PARAMS_NAMED);
+ $subqueryconditions[] = "ev.groupid $insqlgroups";
+ $subqueryparams = array_merge($subqueryparams, $inparamsgroups);
+ } else if ($groups === true) {
+ // Events from ALL groups.
+ $subqueryconditions[] = "ev.groupid != 0";
}
- }
- // Set filter condition for the user's group events.
- if ($usergroups === true || $viewgroupsonly) {
- // Fetch group events, but not group overrides.
- $subqueryconditions[] = "(ev.groupid != 0 AND ev.eventtype = 'group')";
- } else if (!empty($usergroups)) {
- // Fetch group events and group overrides.
- list($inusergroups, $inusergroupparams) = $DB->get_in_or_equal($usergroups, SQL_PARAMS_NAMED);
- $subqueryconditions[] = "(ev.groupid $inusergroups)";
- $subqueryparams = array_merge($subqueryparams, $inusergroupparams);
+ if ($courses === true) {
+ // ALL course events. It's not needed to worry about users' access as $users = true.
+ $subqueryconditions[] = "(ev.groupid = 0 AND ev.courseid != 0 AND ev.categoryid = 0)";
+ }
}
// Get courses to be used for the subquery.
$subquerycourses = [];
if (is_array($courses)) {
$subquerycourses = $courses;
- } else if (is_numeric($courses)) {
- $subquerycourses[] = $courses;
}
// Merge with user courses, if necessary.
- if (!empty($usercourses)) {
- $subquerycourses = array_merge($subquerycourses, $usercourses);
+ if (!empty($allusercourses)) {
+ $subquerycourses = array_merge($subquerycourses, $allusercourses);
// Make sure we remove duplicate values.
$subquerycourses = array_unique($subquerycourses);
}
*
* @param array $courseeventsfrom An array of courses to load calendar events for
* @param bool $ignorefilters specify the use of filters, false is set as default
+ * @param stdClass $user The user object. This defaults to the global $USER object.
* @return array An array of courses, groups, and user to load calendar events for based upon filters
*/
-function calendar_set_filters(array $courseeventsfrom, $ignorefilters = false) {
- global $USER, $CFG;
+function calendar_set_filters(array $courseeventsfrom, $ignorefilters = false, stdClass $user = null) {
+ global $CFG, $USER;
- // For backwards compatability we have to check whether the courses array contains
- // just id's in which case we need to load course objects.
- $coursestoload = array();
- foreach ($courseeventsfrom as $id => $something) {
- if (!is_object($something)) {
- $coursestoload[] = $id;
- unset($courseeventsfrom[$id]);
- }
+ if (is_null($user)) {
+ $user = $USER;
}
$courses = array();
- $user = false;
+ $userid = false;
$group = false;
// Get the capabilities that allow seeing group events from all groups.
$allgroupscaps = array('moodle/site:accessallgroups', 'moodle/calendar:manageentries');
- $isloggedin = isloggedin();
+ $isvaliduser = !empty($user->id);
- if ($ignorefilters || calendar_show_event_type(CALENDAR_EVENT_COURSE)) {
+ if ($ignorefilters || calendar_show_event_type(CALENDAR_EVENT_COURSE, $user)) {
$courses = array_keys($courseeventsfrom);
}
- if ($ignorefilters || calendar_show_event_type(CALENDAR_EVENT_GLOBAL)) {
+ if ($ignorefilters || calendar_show_event_type(CALENDAR_EVENT_GLOBAL, $user)) {
$courses[] = SITEID;
}
$courses = array_unique($courses);
$courses[] = SITEID;
}
- if ($ignorefilters || ($isloggedin && calendar_show_event_type(CALENDAR_EVENT_USER))) {
- $user = $USER->id;
+ if ($ignorefilters || ($isvaliduser && calendar_show_event_type(CALENDAR_EVENT_USER, $user))) {
+ $userid = $user->id;
}
- if (!empty($courseeventsfrom) && (calendar_show_event_type(CALENDAR_EVENT_GROUP) || $ignorefilters)) {
+ if (!empty($courseeventsfrom) && (calendar_show_event_type(CALENDAR_EVENT_GROUP, $user) || $ignorefilters)) {
if (count($courseeventsfrom) == 1) {
$course = reset($courseeventsfrom);
if ($group === false) {
if (!empty($CFG->calendar_adminseesall) && has_any_capability($allgroupscaps, \context_system::instance())) {
$group = true;
- } else if ($isloggedin) {
+ } else if ($isvaliduser) {
$groupids = array();
foreach ($courseeventsfrom as $courseid => $course) {
// If the user is an editing teacher in there.
- if (!empty($USER->groupmember[$course->id])) {
+ if (!empty($user->groupmember[$course->id])) {
// We've already cached the users groups for this course so we can just use that.
- $groupids = array_merge($groupids, $USER->groupmember[$course->id]);
+ $groupids = array_merge($groupids, $user->groupmember[$course->id]);
} else if ($course->groupmode != NOGROUPS || !$course->groupmodeforce) {
// If this course has groups, show events from all of those related to the current user.
- $coursegroups = groups_get_user_groups($course->id, $USER->id);
+ $coursegroups = groups_get_user_groups($course->id, $user->id);
$groupids = array_merge($groupids, $coursegroups['0']);
}
}
$courses = false;
}
- return array($courses, $group, $user);
+ return array($courses, $group, $userid);
}
/**
*
* @param int $courseid (optional) If passed, an additional course can be returned for admins (the current course).
* @param string $fields Comma separated list of course fields to return.
- * @param bool $canmanage If true, this will return the list of courses the current user can create events in, rather
+ * @param bool $canmanage If true, this will return the list of courses the user can create events in, rather
* than the list of courses they see events from (an admin can always add events in a course
* calendar, even if they are not enrolled in the course).
+ * @param int $userid (optional) The user which this function returns the default courses for.
+ * By default the current user.
* @return array $courses Array of courses to display
*/
-function calendar_get_default_courses($courseid = null, $fields = '*', $canmanage=false) {
- global $CFG, $DB;
+function calendar_get_default_courses($courseid = null, $fields = '*', $canmanage = false, int $userid = null) {
+ global $CFG, $USER;
- if (!isloggedin()) {
- return array();
+ if (!$userid) {
+ if (!isloggedin()) {
+ return array();
+ }
+ $userid = $USER->id;
}
- if (has_capability('moodle/calendar:manageentries', context_system::instance()) &&
- (!empty($CFG->calendar_adminseesall) || $canmanage)) {
+ if ((!empty($CFG->calendar_adminseesall) || $canmanage) &&
+ has_capability('moodle/calendar:manageentries', context_system::instance(), $userid)) {
// Add a c. prefix to every field as expected by get_courses function.
$fieldlist = explode(',', $fields);
}, $fieldlist);
$courses = get_courses('all', 'c.shortname', implode(',', $prefixedfields));
} else {
- $courses = enrol_get_my_courses($fields);
+ $courses = enrol_get_users_courses($userid, true, $fields);
}
if ($courseid && $courseid != SITEID) {
- if (empty($courses[$courseid]) && has_capability('moodle/calendar:manageentries', context_system::instance())) {
+ if (empty($courses[$courseid]) && has_capability('moodle/calendar:manageentries', context_system::instance(), $userid)) {
// Allow a site admin to see calendars from courses he is not enrolled in.
// This will come from $COURSE.
$courses[$courseid] = get_course($courseid);
return $param;
}, [$users, $groups, $courses, $categories]);
+ // If a single user is provided, we can use that for capability checks.
+ // Otherwise current logged in user is used - See MDL-58768.
+ if (is_array($userparam) && count($userparam) == 1) {
+ \core_calendar\local\event\container::set_requesting_user($userparam[0]);
+ }
$mapper = \core_calendar\local\event\container::get_event_mapper();
$events = \core_calendar\local\api::get_events(
$tstart,
// Enrolled course only (ignore current).
$this->assertCount(1, $courses);
+ // Now, log out and test again.
+ $this->setUser();
+
+ $CFG->calendar_adminseesall = false;
+
+ $courses = calendar_get_default_courses(null, '*', false, $teacher->id);
+ // Only enrolled in one course.
+ $this->assertCount(1, $courses);
+ $courses = calendar_get_default_courses($course2->id, '*', false, $teacher->id);
+ // Enrolled course only (ignore current).
+ $this->assertCount(1, $courses);
+ // This setting should not affect teachers.
+ $CFG->calendar_adminseesall = true;
+ $courses = calendar_get_default_courses(null, '*', false, $teacher->id);
+ // Only enrolled in one course.
+ $this->assertCount(1, $courses);
+ $courses = calendar_get_default_courses($course2->id, '*', false, $teacher->id);
+ // Enrolled course only (ignore current).
+ $this->assertCount(1, $courses);
+
}
/**
$types = calendar_get_allowed_event_types($course->id);
$this->assertTrue($types['group']);
}
+
+ /**
+ * This is a setup helper function that create some users, courses, groups and group memberships.
+ * This is useful to prepare the environment for testing the calendar_set_filters function.
+ *
+ * @return array An array of ($users, $courses, $coursegroups)
+ */
+ protected function setup_test_calendar_set_filters() {
+ $generator = $this->getDataGenerator();
+
+ // Create some users.
+ $users = [];
+ $users[] = $generator->create_user();
+ $users[] = $generator->create_user();
+ $users[] = $generator->create_user();
+
+ // Create some courses.
+ $courses = [];
+ $courses[] = $generator->create_course();
+ $courses[] = $generator->create_course();
+ $courses[] = $generator->create_course();
+ $courses[] = $generator->create_course();
+
+ // Create some groups.
+ $coursegroups = [];
+ $coursegroups[$courses[0]->id] = [];
+ $coursegroups[$courses[0]->id][] = $generator->create_group(['courseid' => $courses[0]->id]);
+ $coursegroups[$courses[0]->id][] = $generator->create_group(['courseid' => $courses[0]->id]);
+ $coursegroups[$courses[2]->id] = [];
+ $coursegroups[$courses[2]->id][] = $generator->create_group(['courseid' => $courses[2]->id]);
+ $coursegroups[$courses[2]->id][] = $generator->create_group(['courseid' => $courses[2]->id]);
+ $coursegroups[$courses[3]->id] = [];
+ $coursegroups[$courses[3]->id][] = $generator->create_group(['courseid' => $courses[3]->id]);
+ $coursegroups[$courses[3]->id][] = $generator->create_group(['courseid' => $courses[3]->id]);
+
+ // Create some enrolments and group memberships.
+ $generator->enrol_user($users[0]->id, $courses[0]->id, 'student');
+ $generator->create_group_member(['groupid' => $coursegroups[$courses[0]->id][0]->id, 'userid' => $users[0]->id]);
+ $generator->enrol_user($users[1]->id, $courses[0]->id, 'student');
+ $generator->create_group_member(['groupid' => $coursegroups[$courses[0]->id][1]->id, 'userid' => $users[1]->id]);
+ $generator->enrol_user($users[0]->id, $courses[1]->id, 'student');
+ $generator->enrol_user($users[0]->id, $courses[2]->id, 'student');
+
+ return array($users, $courses, $coursegroups);
+ }
+
+ /**
+ * This function tests calendar_set_filters for the case when user is not logged in.
+ */
+ public function test_calendar_set_filters_not_logged_in() {
+ $this->resetAfterTest();
+
+ list($users, $courses, $coursegroups) = $this->setup_test_calendar_set_filters();
+
+ $defaultcourses = calendar_get_default_courses(null, '*', false, $users[0]->id);
+ list($courseids, $groupids, $userid) = calendar_set_filters($defaultcourses);
+
+ $this->assertEquals(
+ [$courses[0]->id, $courses[1]->id, $courses[2]->id, SITEID],
+ array_values($courseids),
+ '', 0.0, 10, true);
+ $this->assertFalse($groupids);
+ $this->assertFalse($userid);
+ }
+
+ /**
+ * This function tests calendar_set_filters for the case when no one is logged in, but a user id is provided.
+ */
+ public function test_calendar_set_filters_not_logged_in_with_user() {
+ $this->resetAfterTest();
+
+ list($users, $courses, $coursegroups) = $this->setup_test_calendar_set_filters();
+
+ $defaultcourses = calendar_get_default_courses(null, '*', false, $users[1]->id);
+ list($courseids, $groupids, $userid) = calendar_set_filters($defaultcourses, false, $users[1]);
+
+ $this->assertEquals(array($courses[0]->id, SITEID), array_values($courseids));
+ $this->assertEquals(array($coursegroups[$courses[0]->id][1]->id), $groupids);
+ $this->assertEquals($users[1]->id, $userid);
+
+ $defaultcourses = calendar_get_default_courses(null, '*', false, $users[0]->id);
+ list($courseids, $groupids, $userid) = calendar_set_filters($defaultcourses, false, $users[0]);
+
+ $this->assertEquals(
+ [$courses[0]->id, $courses[1]->id, $courses[2]->id, SITEID],
+ array_values($courseids),
+ '', 0.0, 10, true);
+ $this->assertEquals(array($coursegroups[$courses[0]->id][0]->id), $groupids);
+ $this->assertEquals($users[0]->id, $userid);
+
+ }
+
+ /**
+ * This function tests calendar_set_filters for the case when user is logged in, but no user id is provided.
+ */
+ public function test_calendar_set_filters_logged_in_no_user() {
+ $this->resetAfterTest();
+
+ list($users, $courses, $coursegroups) = $this->setup_test_calendar_set_filters();
+
+ $this->setUser($users[0]);
+ $defaultcourses = calendar_get_default_courses(null, '*', false, $users[0]->id);
+ list($courseids, $groupids, $userid) = calendar_set_filters($defaultcourses, false);
+ $this->assertEquals([$courses[0]->id, $courses[1]->id, $courses[2]->id, SITEID], array_values($courseids), '', 0.0, 10,
+ true);
+ $this->assertEquals(array($coursegroups[$courses[0]->id][0]->id), $groupids);
+ $this->assertEquals($users[0]->id, $userid);
+ }
+
+ /**
+ * This function tests calendar_set_filters for the case when a user is logged in, but another user id is provided.
+ */
+ public function test_calendar_set_filters_logged_in_another_user() {
+ $this->resetAfterTest();
+
+ list($users, $courses, $coursegroups) = $this->setup_test_calendar_set_filters();
+
+ $this->setUser($users[0]);
+ $defaultcourses = calendar_get_default_courses(null, '*', false, $users[1]->id);
+ list($courseids, $groupids, $userid) = calendar_set_filters($defaultcourses, false, $users[1]);
+
+ $this->assertEquals(array($courses[0]->id, SITEID), array_values($courseids));
+ $this->assertEquals(array($coursegroups[$courses[0]->id][1]->id), $groupids);
+ $this->assertEquals($users[1]->id, $userid);
+ }
}
$this->assertCount(2, $events);
// Disable the lesson module.
- $modulerecord = $DB->get_record('modules', ['name' => 'lesson']);
- $modulerecord->visible = 0;
- $DB->update_record('modules', $modulerecord);
+ $DB->set_field('modules', 'visible', 0, ['name' => 'lesson']);
// Check that we only return the assign event.
$events = $retrievalstrategy->get_raw_events(null, [0], null);
$this->assertCount(1, $events);
$event = reset($events);
$this->assertEquals('assign', $event->modulename);
+
+ // Now, log out and repeat the above test in the reverse order.
+ $this->setUser();
+
+ // Check that we only return the assign event (given that the lesson module is still disabled).
+ $events = $retrievalstrategy->get_raw_events([$student->id], [0], null);
+ $this->assertCount(1, $events);
+ $event = reset($events);
+ $this->assertEquals('assign', $event->modulename);
+
+ // Enable the lesson module.
+ $DB->set_field('modules', 'visible', 1, ['name' => 'lesson']);
+
+ // Get all events.
+ $events = $retrievalstrategy->get_raw_events(null, [0], null);
+ $this->assertCount(2, $events);
}
/**
calendar_event::create($event, false);
}
- $timestart = $now - 100;
- $timeend = $now + (3 * 86400);
$groups = [$group1->id, $group2->id];
- // Get user override events.
- $this->setUser($useroverridestudent);
- $events = $retrievalstrategy->get_raw_events([$useroverridestudent->id], $groups, [$course->id]);
- $this->assertCount(1, $events);
- $event = reset($events);
- $this->assertEquals('Assignment 1 due date - User override', $event->name);
-
- // Get events for user that does not belong to any group and has no user override events.
- $this->setUser($nogroupstudent);
- $events = $retrievalstrategy->get_raw_events([$nogroupstudent->id], $groups, [$course->id]);
- $this->assertCount(1, $events);
- $event = reset($events);
- $this->assertEquals('Assignment 1 due date', $event->name);
-
- // Get events for user that belongs to groups A and B and has no user override events.
- $this->setUser($group12student);
- $events = $retrievalstrategy->get_raw_events([$group12student->id], $groups, [$course->id]);
- $this->assertCount(1, $events);
- $event = reset($events);
- $this->assertEquals('Assignment 1 due date - Group A override', $event->name);
-
- // Get events for user that belongs to group A and has no user override events.
- $this->setUser($group1student);
- $events = $retrievalstrategy->get_raw_events([$group1student->id], $groups, [$course->id]);
- $this->assertCount(1, $events);
- $event = reset($events);
- $this->assertEquals('Assignment 1 due date - Group A override', $event->name);
+ // Do the following tests multiple times when logged in with different users. Also run the whole set when logged out.
+ // In any cases, the tests should not depend on the logged-in user.
+ foreach ([$useroverridestudent, $nogroupstudent, $group12student, $group1student, null] as $login) {
+ $this->setUser($login);
+
+ // Get user override events.
+ $events = $retrievalstrategy->get_raw_events([$useroverridestudent->id], $groups, [$course->id]);
+ $this->assertCount(1, $events);
+ $event = reset($events);
+ $this->assertEquals('Assignment 1 due date - User override', $event->name);
+
+ // Get events for user that does not belong to any group and has no user override events.
+ $events = $retrievalstrategy->get_raw_events([$nogroupstudent->id], $groups, [$course->id]);
+ $this->assertCount(1, $events);
+ $event = reset($events);
+ $this->assertEquals('Assignment 1 due date', $event->name);
+
+ // Get events for user that belongs to groups A and B and has no user override events.
+ $events = $retrievalstrategy->get_raw_events([$group12student->id], $groups, [$course->id]);
+ $this->assertCount(1, $events);
+ $event = reset($events);
+ $this->assertEquals('Assignment 1 due date - Group A override', $event->name);
+
+ // Get events for user that belongs to group A and has no user override events.
+ $events = $retrievalstrategy->get_raw_events([$group1student->id], $groups, [$course->id]);
+ $this->assertCount(1, $events);
+ $event = reset($events);
+ $this->assertEquals('Assignment 1 due date - Group A override', $event->name);
+ }
// Add repeating events.
$repeatingevents = [
* Test retrieval strategy with category specifications.
*/
public function test_get_raw_events_category() {
- global $DB;
-
$this->resetAfterTest();
$retrievalstrategy = new raw_event_retrieval_strategy();
$generator = $this->getDataGenerator();
$events = $retrievalstrategy->get_raw_events(null, null, null, [$category1->id, $category2->id]);
$this->assertCount(2, $events);
}
+
+ public function test_get_raw_events_for_multiple_users() {
+ $this->resetAfterTest();
+
+ $generator = $this->getDataGenerator();
+
+ // Create users.
+ $user1 = $generator->create_user();
+ $user2 = $generator->create_user();
+ $user3 = $generator->create_user();
+
+ // Create user events.
+ $events = [
+ [
+ 'name' => 'User1 Event',
+ 'eventtype' => 'user',
+ 'userid' => $user1->id,
+ 'timestart' => time(),
+ ], [
+ 'name' => 'User2 Event',
+ 'eventtype' => 'user',
+ 'userid' => $user2->id,
+ 'timestart' => time(),
+ ], [
+ 'name' => 'User3 Event',
+ 'eventtype' => 'user',
+ 'userid' => $user3->id,
+ 'timestart' => time(),
+ ]
+ ];
+ foreach ($events as $event) {
+ calendar_event::create($event, false);
+ }
+
+ $retrievalstrategy = new raw_event_retrieval_strategy();
+
+ // Get all events.
+ $events = $retrievalstrategy->get_raw_events([$user1->id, $user2->id]);
+ $this->assertCount(2, $events);
+ $this->assertEquals(
+ ['User1 Event', 'User2 Event'],
+ array_column($events, 'name'),
+ '', 0.0, 10, true);
+ }
+
+ public function test_get_raw_events_for_groups_with_no_members() {
+ $this->resetAfterTest();
+
+ $generator = $this->getDataGenerator();
+
+ $course = $generator->create_course();
+
+ // Create groups.
+ $group1 = $generator->create_group(['courseid' => $course->id, 'name' => 'Group 1']);
+ $group2 = $generator->create_group(['courseid' => $course->id, 'name' => 'Group 2']);
+
+ // Create group events.
+ $events = [
+ [
+ 'name' => 'Group 1 Event',
+ 'eventtype' => 'group',
+ 'groupid' => $group1->id,
+ 'timestart' => time(),
+ ], [
+ 'name' => 'Group 2 Event',
+ 'eventtype' => 'group',
+ 'groupid' => $group2->id,
+ 'timestart' => time(),
+ ]
+ ];
+ foreach ($events as $event) {
+ calendar_event::create($event, false);
+ }
+
+ $retrievalstrategy = new raw_event_retrieval_strategy;
+
+ // Get group eventsl.
+ $events = $retrievalstrategy->get_raw_events(null, [$group1->id, $group2->id]);
+ $this->assertCount(2, $events);
+ $this->assertEquals(
+ ['Group 1 Event', 'Group 2 Event'],
+ array_column($events, 'name'),
+ '', 0.0, 10, true);
+ }
}
This files describes API changes in /calendar/* ,
information provided here is intended especially for developers.
+=== 3.6 ===
+* calendar_get_default_courses() function now has optional $userid parameter.
+* calendar_set_filters() function now has optional $user parameter.
+* The core_calendar\local\event\container class now provides two new helper methods for getting and setting the requesting user:
+ set_requesting_user() and get_requesting_user().
+
=== 3.5 ===
* core_calendar_external::get_calendar_events now returns the categoryid for category events.
// @codingStandardsIgnoreLine This script does not require login.
require("../../config.php");
require_once("lib.php");
-require_once($CFG->libdir.'/eventslib.php');
require_once($CFG->libdir.'/enrollib.php');
require_once($CFG->libdir . '/filelib.php');
<?php
require('../config.php');
- require_once($CFG->libdir.'/eventslib.php');
// Form submitted, do not check referer (original page unknown).
if ($form = data_submitted()) {
if (!$admin and empty($data->override)) {
$records = $DB->get_records('grade_letters', array('contextid' => $context->id));
foreach ($records as $record) {
- $DB->delete_record('grade_letters', array('id' => $record->id));
+ $DB->delete_records('grade_letters', array('id' => $record->id));
// Trigger the letter grade deleted event.
$event = \core\event\grade_letter_deleted::create(array(
'objectid' => $record->id,
// delete the capabilities that were defined by this module
capabilities_cleanup($component);
- // remove event handlers and dequeue pending events
- events_uninstall($component);
-
// Delete all remaining files in the filepool owned by the component.
$fs = get_file_storage();
$fs->delete_component_files($component);
\core\event\manager::dispatch($this);
$this->dispatched = true;
-
- if ($legacyeventname = static::get_legacy_eventname()) {
- events_trigger_legacy($legacyeventname, $this->get_legacy_eventdata());
- }
}
/**
/**
* Returns coursecat object for requested category
*
- * If category is not visible to user it is treated as non existing
+ * If category is not visible to the given user, it is treated as non existing
* unless $alwaysreturnhidden is set to true
*
* If id is 0, the pseudo object for root category is returned (convenient
* returned even if this category is not visible to the current user
* (category is hidden and user does not have
* 'moodle/category:viewhiddencategories' capability). Use with care!
+ * @param int|stdClass $user The user id or object. By default (null) checks the visibility to the current user.
* @return null|coursecat
* @throws moodle_exception
*/
- public static function get($id, $strictness = MUST_EXIST, $alwaysreturnhidden = false) {
+ public static function get($id, $strictness = MUST_EXIST, $alwaysreturnhidden = false, $user = null) {
if (!$id) {
if (!isset(self::$coursecat0)) {
$record = new stdClass();
$coursecatrecordcache->set($id, $coursecat);
}
}
- if ($coursecat && ($alwaysreturnhidden || $coursecat->is_uservisible())) {
+ if ($coursecat && ($alwaysreturnhidden || $coursecat->is_uservisible($user))) {
return $coursecat;
} else {
if ($strictness == MUST_EXIST) {
}
/**
- * Checks if this course category is visible to current user
+ * Checks if this course category is visible to a user.
*
* Please note that methods coursecat::get (without 3rd argumet),
* coursecat::get_children(), etc. return only visible categories so it is
* usually not needed to call this function outside of this class
*
+ * @param int|stdClass $user The user id or object. By default (null) checks the visibility to the current user.
* @return bool
*/
- public function is_uservisible() {
+ public function is_uservisible($user = null) {
return !$this->id || $this->visible ||
- has_capability('moodle/category:viewhiddencategories', $this->get_context());
+ has_capability('moodle/category:viewhiddencategories', $this->get_context(), $user);
}
/**
'dayofweek' => '*',
'month' => '*'
),
- array(
- 'classname' => 'core\task\events_cron_task',
- 'blocking' => 0,
- 'minute' => '*',
- 'hour' => '*',
- 'day' => '*',
- 'dayofweek' => '*',
- 'month' => '*'
- ),
array(
'classname' => 'core\task\completion_regular_task',
'blocking' => 0,
}
/**
- * Function to call all event handlers when triggering an event
- *
* @deprecated since 2.6
- *
- * @param string $eventname name of the event
- * @param mixed $eventdata event data object
- * @return int number of failed events
*/
-function events_trigger($eventname, $eventdata) {
- debugging('events_trigger() is deprecated, please use new events instead', DEBUG_DEVELOPER);
- return events_trigger_legacy($eventname, $eventdata);
+function events_trigger() {
+ throw new coding_exception('events_trigger() has been deprecated along with all Events 1 API in favour of Events 2 API.');
}
/**
}
/**
- * Loads the events definitions for the component (from file). If no
- * events are defined for the component, we simply return an empty array.
- *
- * @access protected To be used from eventslib only
* @deprecated since Moodle 3.1
- * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results'
- * @return array Array of capabilities or empty array if not exists
*/
-function events_load_def($component) {
- global $CFG;
- if ($component === 'unittest') {
- $defpath = $CFG->dirroot.'/lib/tests/fixtures/events.php';
- } else {
- $defpath = core_component::get_component_directory($component).'/db/events.php';
- }
-
- $handlers = array();
-
- if (file_exists($defpath)) {
- require($defpath);
- }
+function events_load_def() {
+ throw new coding_exception('events_load_def() has been deprecated along with all Events 1 API in favour of Events 2 API.');
- // make sure the definitions are valid and complete; tell devs what is wrong
- foreach ($handlers as $eventname => $handler) {
- if ($eventname === 'reset') {
- debugging("'reset' can not be used as event name.");
- unset($handlers['reset']);
- continue;
- }
- if (!is_array($handler)) {
- debugging("Handler of '$eventname' must be specified as array'");
- unset($handlers[$eventname]);
- continue;
- }
- if (!isset($handler['handlerfile'])) {
- debugging("Handler of '$eventname' must include 'handlerfile' key'");
- unset($handlers[$eventname]);
- continue;
- }
- if (!isset($handler['handlerfunction'])) {
- debugging("Handler of '$eventname' must include 'handlerfunction' key'");
- unset($handlers[$eventname]);
- continue;
- }
- if (!isset($handler['schedule'])) {
- $handler['schedule'] = 'instant';
- }
- if ($handler['schedule'] !== 'instant' and $handler['schedule'] !== 'cron') {
- debugging("Handler of '$eventname' must include valid 'schedule' type (instant or cron)'");
- unset($handlers[$eventname]);
- continue;
- }
- if (!isset($handler['internal'])) {
- $handler['internal'] = 1;
- }
- $handlers[$eventname] = $handler;
- }
-
- return $handlers;
}
/**
- * Puts a handler on queue
- *
- * @access protected To be used from eventslib only
* @deprecated since Moodle 3.1
- * @param stdClass $handler event handler object from db
- * @param stdClass $event event data object
- * @param string $errormessage The error message indicating the problem
- * @return int id number of new queue handler
*/
-function events_queue_handler($handler, $event, $errormessage) {
- global $DB;
-
- if ($qhandler = $DB->get_record('events_queue_handlers', array('queuedeventid'=>$event->id, 'handlerid'=>$handler->id))) {
- debugging("Please check code: Event id $event->id is already queued in handler id $qhandler->id");
- return $qhandler->id;
- }
-
- // make a new queue handler
- $qhandler = new stdClass();
- $qhandler->queuedeventid = $event->id;
- $qhandler->handlerid = $handler->id;
- $qhandler->errormessage = $errormessage;
- $qhandler->timemodified = time();
- if ($handler->schedule === 'instant' and $handler->status == 1) {
- $qhandler->status = 1; //already one failed attempt to dispatch this event
- } else {
- $qhandler->status = 0;
- }
-
- return $DB->insert_record('events_queue_handlers', $qhandler);
+function events_queue_handler() {
+ throw new coding_exception('events_queue_handler() has been deprecated along with all Events 1 API in favour of Events 2 API.');
}
/**
- * trigger a single event with a specified handler
- *
- * @access protected To be used from eventslib only
* @deprecated since Moodle 3.1
- * @param stdClass $handler This shoudl be a row from the events_handlers table.
- * @param stdClass $eventdata An object containing information about the event
- * @param string $errormessage error message indicating problem
- * @return bool|null True means event processed, false means retry event later; may throw exception, NULL means internal error
*/
-function events_dispatch($handler, $eventdata, &$errormessage) {
- global $CFG;
-
- debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.', DEBUG_DEVELOPER);
-
- $function = unserialize($handler->handlerfunction);
-
- if (is_callable($function)) {
- // oki, no need for includes
-
- } else if (file_exists($CFG->dirroot.$handler->handlerfile)) {
- include_once($CFG->dirroot.$handler->handlerfile);
-
- } else {
- $errormessage = "Handler file of component $handler->component: $handler->handlerfile can not be found!";
- return null;
- }
-
- // checks for handler validity
- if (is_callable($function)) {
- $result = call_user_func($function, $eventdata);
- if ($result === false) {
- $errormessage = "Handler function of component $handler->component: $handler->handlerfunction requested resending of event!";
- return false;
- }
- return true;
-
- } else {
- $errormessage = "Handler function of component $handler->component: $handler->handlerfunction not callable function or class method!";
- return null;
- }
+function events_dispatch() {
+ throw new coding_exception('events_dispatch() has been deprecated along with all Events 1 API in favour of Events 2 API.');
}
/**
- * given a queued handler, call the respective event handler to process the event
- *
- * @access protected To be used from eventslib only
* @deprecated since Moodle 3.1
- * @param stdClass $qhandler events_queued_handler row from db
- * @return boolean true means event processed, false means retry later, NULL means fatal failure
*/
-function events_process_queued_handler($qhandler) {
- global $DB;
-
- // get handler
- if (!$handler = $DB->get_record('events_handlers', array('id'=>$qhandler->handlerid))) {
- debugging("Error processing queue handler $qhandler->id, missing handler id: $qhandler->handlerid");
- //irrecoverable error, remove broken queue handler
- events_dequeue($qhandler);
- return NULL;
- }
-
- // get event object
- if (!$event = $DB->get_record('events_queue', array('id'=>$qhandler->queuedeventid))) {
- // can't proceed with no event object - might happen when two crons running at the same time
- debugging("Error processing queue handler $qhandler->id, missing event id: $qhandler->queuedeventid");
- //irrecoverable error, remove broken queue handler
- events_dequeue($qhandler);
- return NULL;
- }
-
- // call the function specified by the handler
- try {
- $errormessage = 'Unknown error';
- if (events_dispatch($handler, unserialize(base64_decode($event->eventdata)), $errormessage)) {
- //everything ok
- events_dequeue($qhandler);
- return true;
- }
- } catch (Exception $e) {
- // the problem here is that we do not want one broken handler to stop all others,
- // cron handlers are very tricky because the needed data might have been deleted before the cron execution
- $errormessage = "Handler function of component $handler->component: $handler->handlerfunction threw exception :" .
- $e->getMessage() . "\n" . format_backtrace($e->getTrace(), true);
- if (!empty($e->debuginfo)) {
- $errormessage .= $e->debuginfo;
- }
- }
-
- //dispatching failed
- $qh = new stdClass();
- $qh->id = $qhandler->id;
- $qh->errormessage = $errormessage;
- $qh->timemodified = time();
- $qh->status = $qhandler->status + 1;
- $DB->update_record('events_queue_handlers', $qh);
-
- debugging($errormessage);
-
- return false;
+function events_process_queued_handler() {
+ throw new coding_exception(
+ 'events_process_queued_handler() has been deprecated along with all Events 1 API in favour of Events 2 API.'
+ );
}
/**
- * Updates all of the event definitions within the database.
- *
- * Unfortunately this isn't as simple as removing them all and then readding
- * the updated event definitions. Chances are queued items are referencing the
- * existing definitions.
- *
- * Note that the absence of the db/events.php event definition file
- * will cause any queued events for the component to be removed from
- * the database.
- *
- * @category event
* @deprecated since Moodle 3.1
- * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results'
- * @return boolean always returns true
*/
-function events_update_definition($component='moodle') {
- global $DB;
-
- // load event definition from events.php
- $filehandlers = events_load_def($component);
-
- if ($filehandlers) {
- debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.', DEBUG_DEVELOPER);
- }
-
- // load event definitions from db tables
- // if we detect an event being already stored, we discard from this array later
- // the remaining needs to be removed
- $cachedhandlers = events_get_cached($component);
-
- foreach ($filehandlers as $eventname => $filehandler) {
- if (!empty($cachedhandlers[$eventname])) {
- if ($cachedhandlers[$eventname]['handlerfile'] === $filehandler['handlerfile'] &&
- $cachedhandlers[$eventname]['handlerfunction'] === serialize($filehandler['handlerfunction']) &&
- $cachedhandlers[$eventname]['schedule'] === $filehandler['schedule'] &&
- $cachedhandlers[$eventname]['internal'] == $filehandler['internal']) {
- // exact same event handler already present in db, ignore this entry
-
- unset($cachedhandlers[$eventname]);
- continue;
-
- } else {
- // same event name matches, this event has been updated, update the datebase
- $handler = new stdClass();
- $handler->id = $cachedhandlers[$eventname]['id'];
- $handler->handlerfile = $filehandler['handlerfile'];
- $handler->handlerfunction = serialize($filehandler['handlerfunction']); // static class methods stored as array
- $handler->schedule = $filehandler['schedule'];
- $handler->internal = $filehandler['internal'];
-
- $DB->update_record('events_handlers', $handler);
-
- unset($cachedhandlers[$eventname]);
- continue;
- }
-
- } else {
- // if we are here, this event handler is not present in db (new)
- // add it
- $handler = new stdClass();
- $handler->eventname = $eventname;
- $handler->component = $component;
- $handler->handlerfile = $filehandler['handlerfile'];
- $handler->handlerfunction = serialize($filehandler['handlerfunction']); // static class methods stored as array
- $handler->schedule = $filehandler['schedule'];
- $handler->status = 0;
- $handler->internal = $filehandler['internal'];
-
- $DB->insert_record('events_handlers', $handler);
- }
- }
-
- // clean up the left overs, the entries in cached events array at this points are deprecated event handlers
- // and should be removed, delete from db
- events_cleanup($component, $cachedhandlers);
-
- events_get_handlers('reset');
-
- return true;
+function events_update_definition() {
+ throw new coding_exception(
+ 'events_update_definition has been deprecated along with all Events 1 API in favour of Events 2 API.'
+ );
}
/**
- * Events cron will try to empty the events queue by processing all the queued events handlers
- *
- * @access public Part of the public API
* @deprecated since Moodle 3.1
- * @category event
- * @param string $eventname empty means all
- * @return int number of dispatched events
*/
-function events_cron($eventname='') {
- global $DB;
-
- $failed = array();
- $processed = 0;
-
- if ($eventname) {
- $sql = "SELECT qh.*
- FROM {events_queue_handlers} qh, {events_handlers} h
- WHERE qh.handlerid = h.id AND h.eventname=?
- ORDER BY qh.id";
- $params = array($eventname);
- } else {
- $sql = "SELECT *
- FROM {events_queue_handlers}
- ORDER BY id";
- $params = array();
- }
-
- $rs = $DB->get_recordset_sql($sql, $params);
- if ($rs->valid()) {
- debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.', DEBUG_DEVELOPER);
- }
-
- foreach ($rs as $qhandler) {
- if (isset($failed[$qhandler->handlerid])) {
- // do not try to dispatch any later events when one already asked for retry or ended with exception
- continue;
- }
- $status = events_process_queued_handler($qhandler);
- if ($status === false) {
- // handler is asking for retry, do not send other events to this handler now
- $failed[$qhandler->handlerid] = $qhandler->handlerid;
- } else if ($status === NULL) {
- // means completely broken handler, event data was purged
- $failed[$qhandler->handlerid] = $qhandler->handlerid;
- } else {
- $processed++;
- }
- }
- $rs->close();
-
- // remove events that do not have any handlers waiting
- $sql = "SELECT eq.id
- FROM {events_queue} eq
- LEFT JOIN {events_queue_handlers} qh ON qh.queuedeventid = eq.id
- WHERE qh.id IS NULL";
- $rs = $DB->get_recordset_sql($sql);
- foreach ($rs as $event) {
- //debugging('Purging stale event '.$event->id);
- $DB->delete_records('events_queue', array('id'=>$event->id));
- }
- $rs->close();
-
- return $processed;
+function events_cron() {
+ throw new coding_exception('events_cron() has been deprecated along with all Events 1 API in favour of Events 2 API.');
}
/**
- * Do not call directly, this is intended to be used from new event base only.
- *
- * @private
* @deprecated since Moodle 3.1
- * @param string $eventname name of the event
- * @param mixed $eventdata event data object
- * @return int number of failed events
*/
-function events_trigger_legacy($eventname, $eventdata) {
- global $CFG, $USER, $DB;
-
- $failedcount = 0; // number of failed events.
-
- // pull out all registered event handlers
- if ($handlers = events_get_handlers($eventname)) {
- foreach ($handlers as $handler) {
- $errormessage = '';
-
- if ($handler->schedule === 'instant') {
- if ($handler->status) {
- //check if previous pending events processed
- if (!$DB->record_exists('events_queue_handlers', array('handlerid'=>$handler->id))) {
- // ok, queue is empty, lets reset the status back to 0 == ok
- $handler->status = 0;
- $DB->set_field('events_handlers', 'status', 0, array('id'=>$handler->id));
- // reset static handler cache
- events_get_handlers('reset');
- }
- }
-
- // dispatch the event only if instant schedule and status ok
- if ($handler->status or (!$handler->internal and $DB->is_transaction_started())) {
- // increment the error status counter
- $handler->status++;
- $DB->set_field('events_handlers', 'status', $handler->status, array('id'=>$handler->id));
- // reset static handler cache
- events_get_handlers('reset');
-
- } else {
- $errormessage = 'Unknown error';
- $result = events_dispatch($handler, $eventdata, $errormessage);
- if ($result === true) {
- // everything is fine - event dispatched
- continue;
- } else if ($result === false) {
- // retry later - set error count to 1 == send next instant into cron queue
- $DB->set_field('events_handlers', 'status', 1, array('id'=>$handler->id));
- // reset static handler cache
- events_get_handlers('reset');
- } else {
- // internal problem - ignore the event completely
- $failedcount ++;
- continue;
- }
- }
-
- // update the failed counter
- $failedcount ++;
-
- } else if ($handler->schedule === 'cron') {
- //ok - use queueing of events only
-
- } else {
- // unknown schedule - ignore event completely
- debugging("Unknown handler schedule type: $handler->schedule");
- $failedcount ++;
- continue;
- }
-
- // if even type is not instant, or dispatch asked for retry, queue it
- $event = new stdClass();
- $event->userid = $USER->id;
- $event->eventdata = base64_encode(serialize($eventdata));
- $event->timecreated = time();
- if (debugging()) {
- $dump = '';
- $callers = debug_backtrace();
- foreach ($callers as $caller) {
- if (!isset($caller['line'])) {
- $caller['line'] = '?';
- }
- if (!isset($caller['file'])) {
- $caller['file'] = '?';
- }
- $dump .= 'line ' . $caller['line'] . ' of ' . substr($caller['file'], strlen($CFG->dirroot) + 1);
- if (isset($caller['function'])) {
- $dump .= ': call to ';
- if (isset($caller['class'])) {
- $dump .= $caller['class'] . $caller['type'];
- }
- $dump .= $caller['function'] . '()';
- }
- $dump .= "\n";
- }
- $event->stackdump = $dump;
- } else {
- $event->stackdump = '';
- }
- $event->id = $DB->insert_record('events_queue', $event);
- events_queue_handler($handler, $event, $errormessage);
- }
- } else {
- // No handler found for this event name - this is ok!
- }
-
- return $failedcount;
+function events_trigger_legacy() {
+ throw new coding_exception('events_trigger_legacy() has been deprecated along with all Events 1 API in favour of Events 2 API.');
}
/**
- * checks if an event is registered for this component
- *
- * @access public Part of the public API
* @deprecated since Moodle 3.1
- * @param string $eventname name of the event
- * @param string $component component name, can be mod/data or moodle
- * @return bool
*/
-function events_is_registered($eventname, $component) {
- global $DB;
-
- debugging('events_is_registered() has been deprecated along with all Events 1 API in favour of Events 2 API,' .
- ' please use it instead.', DEBUG_DEVELOPER);
-
- return $DB->record_exists('events_handlers', array('component'=>$component, 'eventname'=>$eventname));
+function events_is_registered() {
+ throw new coding_exception('events_is_registered() has been deprecated along with all Events 1 API in favour of Events 2 API.');
}
/**
- * checks if an event is queued for processing - either cron handlers attached or failed instant handlers
- *
- * @access public Part of the public API
* @deprecated since Moodle 3.1
- * @param string $eventname name of the event
- * @return int number of queued events
*/
-function events_pending_count($eventname) {
- global $DB;
-
- debugging('events_pending_count() has been deprecated along with all Events 1 API in favour of Events 2 API,' .
- ' please use it instead.', DEBUG_DEVELOPER);
-
- $sql = "SELECT COUNT('x')
- FROM {events_queue_handlers} qh
- JOIN {events_handlers} h ON h.id = qh.handlerid
- WHERE h.eventname = ?";
-
- return $DB->count_records_sql($sql, array($eventname));
+function events_pending_count() {
+ throw new coding_exception('events_pending_count() has been deprecated along with all Events 1 API in favour of Events 2 API.');
}
/**
return $groups;
}
+
+/**
+ * Gets the capabilities that have been cached in the database for this
+ * component.
+ * @deprecated since Moodle 3.6. Please use the Events 2 API.
+ * @todo final deprecation. To be removed in Moodle 4.0
+ *
+ * @access protected To be used from eventslib only
+ *
+ * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results'
+ * @return array of events
+ */
+function events_get_cached($component) {
+ global $DB;
+
+ debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.',
+ DEBUG_DEVELOPER);
+
+ $cachedhandlers = array();
+
+ if ($storedhandlers = $DB->get_records('events_handlers', array('component'=>$component))) {
+ foreach ($storedhandlers as $handler) {
+ $cachedhandlers[$handler->eventname] = array (
+ 'id' => $handler->id,
+ 'handlerfile' => $handler->handlerfile,
+ 'handlerfunction' => $handler->handlerfunction,
+ 'schedule' => $handler->schedule,
+ 'internal' => $handler->internal);
+ }
+ }
+
+ return $cachedhandlers;
+}
+
+/**
+ * Remove all event handlers and queued events
+ * @deprecated since Moodle 3.6. Please use the Events 2 API.
+ * @todo final deprecation. To be removed in Moodle 4.0
+ *
+ * @category event
+ * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results'
+ */
+function events_uninstall($component) {
+ debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.',
+ DEBUG_DEVELOPER);
+ $cachedhandlers = events_get_cached($component);
+ events_cleanup($component, $cachedhandlers);
+
+ events_get_handlers('reset');
+}
+
+/**
+ * Deletes cached events that are no longer needed by the component.
+ * @deprecated since Moodle 3.6. Please use the Events 2 API.
+ * @todo final deprecation. To be removed in Moodle 4.0
+ *
+ * @access protected To be used from eventslib only
+ *
+ * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results'
+ * @param array $cachedhandlers array of the cached events definitions that will be
+ * @return int number of unused handlers that have been removed
+ */
+function events_cleanup($component, $cachedhandlers) {
+ global $DB;
+ debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.',
+ DEBUG_DEVELOPER);
+ $deletecount = 0;
+ foreach ($cachedhandlers as $eventname => $cachedhandler) {
+ if ($qhandlers = $DB->get_records('events_queue_handlers', array('handlerid'=>$cachedhandler['id']))) {
+ //debugging("Removing pending events from queue before deleting of event handler: $component - $eventname");
+ foreach ($qhandlers as $qhandler) {
+ events_dequeue($qhandler);
+ }
+ }
+ $DB->delete_records('events_handlers', array('eventname'=>$eventname, 'component'=>$component));
+ $deletecount++;
+ }
+
+ return $deletecount;
+}
+
+/**
+ * Removes this queued handler from the events_queued_handler table
+ *
+ * Removes events_queue record from events_queue if no more references to this event object exists
+ * @deprecated since Moodle 3.6. Please use the Events 2 API.
+ * @todo final deprecation. To be removed in Moodle 4.0
+ *
+ * @access protected To be used from eventslib only
+ *
+ * @param stdClass $qhandler A row from the events_queued_handler table
+ */
+function events_dequeue($qhandler) {
+ global $DB;
+ debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.',
+ DEBUG_DEVELOPER);
+ // first delete the queue handler
+ $DB->delete_records('events_queue_handlers', array('id'=>$qhandler->id));
+
+ // if no more queued handler is pointing to the same event - delete the event too
+ if (!$DB->record_exists('events_queue_handlers', array('queuedeventid'=>$qhandler->queuedeventid))) {
+ $DB->delete_records('events_queue', array('id'=>$qhandler->queuedeventid));
+ }
+}
+
+/**
+ * Returns handlers for given event. Uses caching for better perf.
+ * @deprecated since Moodle 3.6. Please use the Events 2 API.
+ * @todo final deprecation. To be removed in Moodle 4.0
+ *
+ * @access protected To be used from eventslib only
+ *
+ * @staticvar array $handlers
+ * @param string $eventname name of event or 'reset'
+ * @return array|false array of handlers or false otherwise
+ */
+function events_get_handlers($eventname) {
+ global $DB;
+ static $handlers = array();
+ debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.',
+ DEBUG_DEVELOPER);
+
+ if ($eventname === 'reset') {
+ $handlers = array();
+ return false;
+ }
+
+ if (!array_key_exists($eventname, $handlers)) {
+ $handlers[$eventname] = $DB->get_records('events_handlers', array('eventname'=>$eventname));
+ }
+
+ return $handlers[$eventname];
+}
+++ /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/>.
-
-/**
- * Library of functions for events manipulation.
- *
- * The public API is all at the end of this file.
- *
- * @package core
- * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-/**
- * Gets the capabilities that have been cached in the database for this
- * component.
- *
- * @access protected To be used from eventslib only
- *
- * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results'
- * @return array of events
- */
-function events_get_cached($component) {
- global $DB;
-
- $cachedhandlers = array();
-
- if ($storedhandlers = $DB->get_records('events_handlers', array('component'=>$component))) {
- foreach ($storedhandlers as $handler) {
- $cachedhandlers[$handler->eventname] = array (
- 'id' => $handler->id,
- 'handlerfile' => $handler->handlerfile,
- 'handlerfunction' => $handler->handlerfunction,
- 'schedule' => $handler->schedule,
- 'internal' => $handler->internal);
- }
- }
-
- return $cachedhandlers;
-}
-
-/**
- * Remove all event handlers and queued events
- *
- * @category event
- * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results'
- */
-function events_uninstall($component) {
- $cachedhandlers = events_get_cached($component);
- events_cleanup($component, $cachedhandlers);
-
- events_get_handlers('reset');
-}
-
-/**
- * Deletes cached events that are no longer needed by the component.
- *
- * @access protected To be used from eventslib only
- *
- * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results'
- * @param array $cachedhandlers array of the cached events definitions that will be
- * @return int number of unused handlers that have been removed
- */
-function events_cleanup($component, $cachedhandlers) {
- global $DB;
-
- $deletecount = 0;
- foreach ($cachedhandlers as $eventname => $cachedhandler) {
- if ($qhandlers = $DB->get_records('events_queue_handlers', array('handlerid'=>$cachedhandler['id']))) {
- //debugging("Removing pending events from queue before deleting of event handler: $component - $eventname");
- foreach ($qhandlers as $qhandler) {
- events_dequeue($qhandler);
- }
- }
- $DB->delete_records('events_handlers', array('eventname'=>$eventname, 'component'=>$component));
- $deletecount++;
- }
-
- return $deletecount;
-}
-
-/**
- * Removes this queued handler from the events_queued_handler table
- *
- * Removes events_queue record from events_queue if no more references to this event object exists
- *
- * @access protected To be used from eventslib only
- *
- * @param stdClass $qhandler A row from the events_queued_handler table
- */
-function events_dequeue($qhandler) {
- global $DB;
-
- // first delete the queue handler
- $DB->delete_records('events_queue_handlers', array('id'=>$qhandler->id));
-
- // if no more queued handler is pointing to the same event - delete the event too
- if (!$DB->record_exists('events_queue_handlers', array('queuedeventid'=>$qhandler->queuedeventid))) {
- $DB->delete_records('events_queue', array('id'=>$qhandler->queuedeventid));
- }
-}
-
-/**
- * Returns handlers for given event. Uses caching for better perf.
- *
- * @access protected To be used from eventslib only
- *
- * @staticvar array $handlers
- * @param string $eventname name of event or 'reset'
- * @return array|false array of handlers or false otherwise
- */
-function events_get_handlers($eventname) {
- global $DB;
- static $handlers = array();
-
- if ($eventname === 'reset') {
- $handlers = array();
- return false;
- }
-
- if (!array_key_exists($eventname, $handlers)) {
- $handlers[$eventname] = $DB->get_records('events_handlers', array('eventname'=>$eventname));
- }
-
- return $handlers[$eventname];
-}
+++ /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/>.
-
-
-/**
- * submit link type form element
- *
- * Contains HTML class for a submitting to link
- *
- * @deprecated since 3.2
- * @package core_form
- * @copyright 2006 Jamie Pratt <me@jamiep.org>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-global $CFG;
-require_once("$CFG->libdir/form/submit.php");
-/**
- * submit link type form element
- *
- * HTML class for a submitting to link
- *
- * @package core_form
- * @category form
- * @copyright 2006 Jamie Pratt <me@jamiep.org>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class MoodleQuickForm_submitlink extends MoodleQuickForm_submit {
- /** @var string javascript for submitting element's data */
- var $_js;
-
- /** @var string callback function which will be called onclick event */
- var $_onclick;
-
- /**
- * constructor
- *
- * @param string $elementName (optional) name of the field
- * @param string $value (optional) field label
- * @param string $attributes (optional) Either a typical HTML attribute string or an associative array
- */
- public function __construct($elementName=null, $value=null, $attributes=null) {
- debugging('Element type submitlink is deprecated.', DEBUG_DEVELOPER);
- parent::__construct($elementName, $value, $attributes);
- }
-
- /**
- * Old syntax of class constructor. Deprecated in PHP7.
- *
- * @deprecated since Moodle 3.1
- */
- public function MoodleQuickForm_submitlink($elementName=null, $value=null, $attributes=null) {
- debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
- self::__construct($elementName, $value, $attributes);
- }
-
- /**
- * Returns HTML for submitlink form element.
- *
- * @return string
- */
- function toHtml() {
- $text = $this->_attributes['value'];
-
- return "<noscript><div>" . parent::toHtml() . '</div></noscript><script type="text/javascript">' . $this->_js . "\n"
- . 'document.write(\'<a href="#" onclick="' . $this->_onclick . '">'
- . $text . "</a>');\n</script>";
- }
-}
MoodleQuickForm::registerElementType('selectyesno', "$CFG->libdir/form/selectyesno.php", 'MoodleQuickForm_selectyesno');
MoodleQuickForm::registerElementType('static', "$CFG->libdir/form/static.php", 'MoodleQuickForm_static');
MoodleQuickForm::registerElementType('submit', "$CFG->libdir/form/submit.php", 'MoodleQuickForm_submit');
-MoodleQuickForm::registerElementType('submitlink', "$CFG->libdir/form/submitlink.php", 'MoodleQuickForm_submitlink');
MoodleQuickForm::registerElementType('tags', "$CFG->libdir/form/tags.php", 'MoodleQuickForm_tags');
MoodleQuickForm::registerElementType('text', "$CFG->libdir/form/text.php", 'MoodleQuickForm_text');
MoodleQuickForm::registerElementType('textarea', "$CFG->libdir/form/textarea.php", 'MoodleQuickForm_textarea');
$records = $DB->get_records('grade_letters', array('contextid' => $context->id));
foreach ($records as $record) {
- $DB->delete_record('grade_letters', array('id' => $record->id));
+ $DB->delete_records('grade_letters', array('id' => $record->id));
// Trigger the letter grade deleted event.
$event = \core\event\grade_letter_deleted::create(array(
'objectid' => $record->id,
$context = context_coursecat::instance($categoryid);
$records = $DB->get_records('grade_letters', array('contextid' => $context->id));
foreach ($records as $record) {
- $DB->delete_record('grade_letters', array('id' => $record->id));
+ $DB->delete_records('grade_letters', array('id' => $record->id));
// Trigger the letter grade deleted event.
$event = \core\event\grade_letter_deleted::create(array(
'objectid' => $record->id,
+++ /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/>.
-
-/**
- * Deprecated classes and constants.
- *
- * DO NOT INCLUDE THIS FILE
- *
- * use $CFG->media_default_width instead of CORE_MEDIA_VIDEO_WIDTH,
- * $CFG->media_default_height instead of CORE_MEDIA_VIDEO_HEIGHT,
- * core_media_manager::instance() instead of static methods in core_media,
- * core_media_manager::OPTION_zzz instead of core_media::OPTION_zzz
- *
- * New syntax to include media files:
- *
- * $mediamanager = core_media_manager::instance();
- * echo $mediamanager->embed_url(new moodle_url('http://example.org/a.mp3'));
- *
- * @package core_media
- * @copyright 2012 The Open University
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-if (!defined('CORE_MEDIA_VIDEO_WIDTH')) {
- // Default video width if no width is specified; some players may do something
- // more intelligent such as use real video width.
- // May be defined in config.php if required.
- define('CORE_MEDIA_VIDEO_WIDTH', 400);
-}
-if (!defined('CORE_MEDIA_VIDEO_HEIGHT')) {
- // Default video height. May be defined in config.php if required.
- define('CORE_MEDIA_VIDEO_HEIGHT', 300);
-}
-if (!defined('CORE_MEDIA_AUDIO_WIDTH')) {
- // Default audio width if no width is specified.
- // May be defined in config.php if required.
- define('CORE_MEDIA_AUDIO_WIDTH', 300);
-}
-
-debugging('Do not include lib/medialib.php, use $CFG->media_default_width instead of CORE_MEDIA_VIDEO_WIDTH, ' .
- '$CFG->media_default_height instead of CORE_MEDIA_VIDEO_HEIGHT, ' .
- 'core_media_manager::instance() instead of static methods in core_media, ' .
- 'core_media_manager::OPTION_zzz instead of core_media::OPTION_zzz',
- DEBUG_DEVELOPER);
-
-/**
- * Constants and static utility functions for use with core_media_renderer.
- *
- * @deprecated since Moodle 3.2
- *
- * @copyright 2011 The Open University
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-abstract class core_media {
- /**
- * Option: Disable text link fallback.
- *
- * Use this option if you are going to print a visible link anyway so it is
- * pointless to have one as fallback.
- *
- * To enable, set value to true.
- */
- const OPTION_NO_LINK = 'nolink';
-
- /**
- * Option: When embedding, if there is no matching embed, do not use the
- * default link fallback player; instead return blank.
- *
- * This is different from OPTION_NO_LINK because this option still uses the
- * fallback link if there is some kind of embedding. Use this option if you
- * are going to check if the return value is blank and handle it specially.
- *
- * To enable, set value to true.
- */
- const OPTION_FALLBACK_TO_BLANK = 'embedorblank';
-
- /**
- * Option: Enable players which are only suitable for use when we trust the
- * user who embedded the content.
- *
- * At present, this option enables the SWF player.
- *
- * To enable, set value to true.
- */
- const OPTION_TRUSTED = 'trusted';
-
- /**
- * Option: Put a div around the output (if not blank) so that it displays
- * as a block using the 'resourcecontent' CSS class.
- *
- * To enable, set value to true.
- */
- const OPTION_BLOCK = 'block';
-
- /**
- * Given a string containing multiple URLs separated by #, this will split
- * it into an array of moodle_url objects suitable for using when calling
- * embed_alternatives.
- *
- * Note that the input string should NOT be html-escaped (i.e. if it comes
- * from html, call html_entity_decode first).
- *
- * @param string $combinedurl String of 1 or more alternatives separated by #
- * @param int $width Output variable: width (will be set to 0 if not specified)
- * @param int $height Output variable: height (0 if not specified)
- * @return array Array of 1 or more moodle_url objects
- */
- public static function split_alternatives($combinedurl, &$width, &$height) {
- return core_media_manager::instance()->split_alternatives($combinedurl, $width, $height);
- }
-
- /**
- * Returns the file extension for a URL.
- * @param moodle_url $url URL
- */
- public static function get_extension(moodle_url $url) {
- return core_media_manager::instance()->get_extension($url);
- }
-
- /**
- * Obtains the filename from the moodle_url.
- * @param moodle_url $url URL
- * @return string Filename only (not escaped)
- */
- public static function get_filename(moodle_url $url) {
- return core_media_manager::instance()->get_filename($url);
- }
-
- /**
- * Guesses MIME type for a moodle_url based on file extension.
- * @param moodle_url $url URL
- * @return string MIME type
- */
- public static function get_mimetype(moodle_url $url) {
- return core_media_manager::instance()->get_mimetype($url);
- }
-}
$a->sitename = format_string($site->fullname);
$a->username = $user->username;
$a->newpassword = $newpassword;
- $a->link = $CFG->wwwroot .'/login/';
+ $a->link = $CFG->wwwroot .'/login/?lang='.$lang;
$a->signoff = generate_email_signoff();
$message = (string)new lang_string('newusernewpasswordtext', '', $a, $lang);
}
/**
- * Returns HTML to display the 'Update this Modulename' button that appears on module pages.
- *
* @deprecated since Moodle 3.2
- *
- * @param string $cmid the course_module id.
- * @param string $modulename the module name, eg. "forum", "quiz" or "workshop"
- * @return string the HTML for the button, if this user has permission to edit it, else an empty string.
*/
- public function update_module_button($cmid, $modulename) {
- global $CFG;
-
- debugging('core_renderer::update_module_button() has been deprecated and should not be used anymore. Activity modules ' .
- 'should not add the edit module button, the link is already available in the Administration block. Themes can choose ' .
- 'to display the link in the buttons row consistently for all module types.', DEBUG_DEVELOPER);
-
- if (has_capability('moodle/course:manageactivities', context_module::instance($cmid))) {
- $modulename = get_string('modulename', $modulename);
- $string = get_string('updatethis', '', $modulename);
- $url = new moodle_url("$CFG->wwwroot/course/mod.php", array('update' => $cmid, 'return' => true, 'sesskey' => sesskey()));
- return $this->single_button($url, $string);
- } else {
- return '';
- }
+ public function update_module_button() {
+ throw new coding_exception('core_renderer::update_module_button() can not be used anymore. Activity ' .
+ 'modules should not add the edit module button, the link is already available in the Administration block. ' .
+ 'Themes can choose to display the link in the buttons row consistently for all module types.');
}
/**
}
-/**
- * Renderer for media files.
- *
- * Used in file resources, media filter, and any other places that need to
- * output embedded media.
- *
- * @deprecated since Moodle 3.2
- * @copyright 2011 The Open University
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class core_media_renderer extends plugin_renderer_base {
- /** @var array Array of available 'player' objects */
- private $players;
- /** @var string Regex pattern for links which may contain embeddable content */
- private $embeddablemarkers;
-
- /**
- * Constructor
- *
- * This is needed in the constructor (not later) so that you can use the
- * constants and static functions that are defined in core_media class
- * before you call renderer functions.
- */
- public function __construct() {
- debugging('Class core_media_renderer is deprecated, please use core_media_manager::instance()', DEBUG_DEVELOPER);
- }
-
- /**
- * Renders a media file (audio or video) using suitable embedded player.
- *
- * See embed_alternatives function for full description of parameters.
- * This function calls through to that one.
- *
- * When using this function you can also specify width and height in the
- * URL by including ?d=100x100 at the end. If specified in the URL, this
- * will override the $width and $height parameters.
- *
- * @param moodle_url $url Full URL of media file
- * @param string $name Optional user-readable name to display in download link
- * @param int $width Width in pixels (optional)
- * @param int $height Height in pixels (optional)
- * @param array $options Array of key/value pairs
- * @return string HTML content of embed
- */
- public function embed_url(moodle_url $url, $name = '', $width = 0, $height = 0,
- $options = array()) {
- return core_media_manager::instance()->embed_url($url, $name, $width, $height, $options);
- }
-
- /**
- * Renders media files (audio or video) using suitable embedded player.
- * The list of URLs should be alternative versions of the same content in
- * multiple formats. If there is only one format it should have a single
- * entry.
- *
- * If the media files are not in a supported format, this will give students
- * a download link to each format. The download link uses the filename
- * unless you supply the optional name parameter.
- *
- * Width and height are optional. If specified, these are suggested sizes
- * and should be the exact values supplied by the user, if they come from
- * user input. These will be treated as relating to the size of the video
- * content, not including any player control bar.
- *
- * For audio files, height will be ignored. For video files, a few formats
- * work if you specify only width, but in general if you specify width
- * you must specify height as well.
- *
- * The $options array is passed through to the core_media_player classes
- * that render the object tag. The keys can contain values from
- * core_media::OPTION_xx.
- *
- * @param array $alternatives Array of moodle_url to media files
- * @param string $name Optional user-readable name to display in download link
- * @param int $width Width in pixels (optional)
- * @param int $height Height in pixels (optional)
- * @param array $options Array of key/value pairs
- * @return string HTML content of embed
- */
- public function embed_alternatives($alternatives, $name = '', $width = 0, $height = 0,
- $options = array()) {
- return core_media_manager::instance()->embed_alternatives($alternatives, $name, $width, $height, $options);
- }
-
- /**
- * Checks whether a file can be embedded. If this returns true you will get
- * an embedded player; if this returns false, you will just get a download
- * link.
- *
- * This is a wrapper for can_embed_urls.
- *
- * @param moodle_url $url URL of media file
- * @param array $options Options (same as when embedding)
- * @return bool True if file can be embedded
- */
- public function can_embed_url(moodle_url $url, $options = array()) {
- return core_media_manager::instance()->can_embed_url($url, $options);
- }
-
- /**
- * Checks whether a file can be embedded. If this returns true you will get
- * an embedded player; if this returns false, you will just get a download
- * link.
- *
- * @param array $urls URL of media file and any alternatives (moodle_url)
- * @param array $options Options (same as when embedding)
- * @return bool True if file can be embedded
- */
- public function can_embed_urls(array $urls, $options = array()) {
- return core_media_manager::instance()->can_embed_urls($urls, $options);
- }
-
- /**
- * Obtains a list of markers that can be used in a regular expression when
- * searching for URLs that can be embedded by any player type.
- *
- * This string is used to improve peformance of regex matching by ensuring
- * that the (presumably C) regex code can do a quick keyword check on the
- * URL part of a link to see if it matches one of these, rather than having
- * to go into PHP code for every single link to see if it can be embedded.
- *
- * @return string String suitable for use in regex such as '(\.mp4|\.flv)'
- */
- public function get_embeddable_markers() {
- return core_media_manager::instance()->get_embeddable_markers();
- }
-}
/**
* The maintenance renderer.
accesslib_clear_all_caches(true);
get_string_manager()->reset_caches(true);
reset_text_filters_cache(true);
- events_get_handlers('reset');
core_text::reset_caches();
get_message_processors(false, true, true);
filter_manager::reset_caches();
require_once($CFG->libdir .'/enrollib.php'); // Enrolment related functions
require_once($CFG->libdir .'/pagelib.php'); // Library that defines the moodle_page class, used for $PAGE
require_once($CFG->libdir .'/blocklib.php'); // Library for controlling blocks
-require_once($CFG->libdir .'/eventslib.php'); // Events functions
require_once($CFG->libdir .'/grouplib.php'); // Groups functions
require_once($CFG->libdir .'/sessionlib.php'); // All session and cookie related stuff
require_once($CFG->libdir .'/editorlib.php'); // All text editor related functions and classes
$this->assertEquals("{$cat1name} / {$cat2name} / {$cat4name}", $category4->get_nested_name(false));
}
+ public function test_coursecat_is_uservisible() {
+ global $USER;
+
+ // Create category 1 as visible.
+ $category1 = coursecat::create(array('name' => 'Cat1', 'visible' => 1));
+ // Create category 2 as hidden.
+ $category2 = coursecat::create(array('name' => 'Cat2', 'visible' => 0));
+
+ $this->assertTrue($category1->is_uservisible());
+ $this->assertFalse($category2->is_uservisible());
+
+ $this->assign_capability('moodle/category:viewhiddencategories');
+
+ $this->assertTrue($category1->is_uservisible());
+ $this->assertTrue($category2->is_uservisible());
+
+ // First, store current user's id, then login as another user.
+ $userid = $USER->id;
+ $this->setUser($this->getDataGenerator()->create_user());
+
+ // User $user should still have the moodle/category:viewhiddencategories capability.
+ $this->assertTrue($category1->is_uservisible($userid));
+ $this->assertTrue($category2->is_uservisible($userid));
+
+ $this->assign_capability('moodle/category:viewhiddencategories', CAP_INHERIT);
+
+ $this->assertTrue($category1->is_uservisible());
+ $this->assertFalse($category2->is_uservisible());
+ }
+
+ public function test_current_user_coursecat_get() {
+ $this->assign_capability('moodle/category:viewhiddencategories');
+
+ // Create category 1 as visible.
+ $category1 = coursecat::create(array('name' => 'Cat1', 'visible' => 1));
+ // Create category 2 as hidden.
+ $category2 = coursecat::create(array('name' => 'Cat2', 'visible' => 0));
+
+ $this->assertEquals($category1->id, coursecat::get($category1->id)->id);
+ $this->assertEquals($category2->id, coursecat::get($category2->id)->id);
+
+ // Login as another user to test coursecat::get.
+ $this->setUser($this->getDataGenerator()->create_user());
+ $this->assertEquals($category1->id, coursecat::get($category1->id)->id);
+
+ // Expecting to get an exception as this new user does not have the moodle/category:viewhiddencategories capability.
+ $this->expectException('moodle_exception');
+ $this->expectExceptionMessage('unknowncategory');
+ coursecat::get($category2->id);
+ }
+
+ public function test_another_user_coursecat_get() {
+ global $USER;
+
+ $this->assign_capability('moodle/category:viewhiddencategories');
+
+ // Create category 1 as visible.
+ $category1 = coursecat::create(array('name' => 'Cat1', 'visible' => 1));
+ // Create category 2 as hidden.
+ $category2 = coursecat::create(array('name' => 'Cat2', 'visible' => 0));
+
+ // First, store current user's object, then login as another user.
+ $user1 = $USER;
+ $user2 = $this->getDataGenerator()->create_user();
+ $this->setUser($user2);
+
+ $this->assertEquals($category1->id, coursecat::get($category1->id, MUST_EXIST, false, $user1)->id);
+ $this->assertEquals($category2->id, coursecat::get($category2->id, MUST_EXIST, false, $user1)->id);
+
+ $this->setUser($user1);
+
+ $this->assertEquals($category1->id, coursecat::get($category1->id, MUST_EXIST, false, $user2)->id);
+ $this->expectException('moodle_exception');
+ $this->expectExceptionMessage('unknowncategory');
+ coursecat::get($category2->id, MUST_EXIST, false, $user2);
+ }
+
/**
* Creates a draft area for current user and fills it with fake files
*
);
$DB->delete_records('log', array());
+ $this->expectException('coding_exception');
events_update_definition('unittest');
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
+
$DB->delete_records_select('events_handlers', "component <> 'unittest'");
events_get_handlers('reset');
+ $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
$this->assertEquals(3, $DB->count_records('events_handlers'));
set_config('loglifetime', 60*60*24*5);
$event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>5, 'xx'=>10)));
$event1->trigger();
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
$event2 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>6, 'xx'=>11)));
$event2->nest = true;
$event2->trigger();
- $this->assertDebuggingCalledCount(2, array(self::DEBUGGING_MSG, self::DEBUGGING_MSG), array(DEBUG_DEVELOPER, DEBUG_DEVELOPER));
$this->assertSame(
- array('observe_all-5', 'observe_one-5', 'legacy_handler-0', 'observe_all-nesting-6', 'legacy_handler-0', 'observe_one-6', 'observe_all-666', 'observe_one-666', 'legacy_handler-0'),
+ array('observe_all-5', 'observe_one-5', 'observe_all-nesting-6', 'observe_one-6', 'observe_all-666', 'observe_one-666'),
\core_tests\event\unittest_observer::$info);
$this->assertSame($event1, \core_tests\event\unittest_observer::$event[0]);
$this->assertSame($event1, \core_tests\event\unittest_observer::$event[1]);
- $this->assertSame(array(0, 5), \core_tests\event\unittest_observer::$event[2]);
$logs = $DB->get_records('log', array(), 'id ASC');
$this->assertCount(0, $logs);
+++ /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/>.
-
-/**
- * Tests events subsystem.
- *
- * @package core_event
- * @subpackage phpunit
- * @copyright 2007 onwards Martin Dougiamas (http://dougiamas.com)
- * @author Petr Skoda {@link http://skodak.org}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-
-class core_eventslib_testcase extends advanced_testcase {
-
- const DEBUGGING_MSG = 'Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.';
-
- /**
- * Create temporary entries in the database for these tests.
- * These tests have to work no matter the data currently in the database
- * (meaning they should run on a brand new site). This means several items of
- * data have to be artificially inseminated (:-) in the DB.
- */
- protected function setUp() {
- parent::setUp();
- // Set global category settings to -1 (not force).
- eventslib_sample_function_handler('reset');
- eventslib_sample_handler_class::static_method('reset');
-
- $this->resetAfterTest();
- }
-
- /**
- * Tests the installation of event handlers from file
- */
- public function test_events_update_definition__install() {
- global $DB;
-
- events_update_definition('unittest');
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
-
- $dbcount = $DB->count_records('events_handlers', array('component'=>'unittest'));
- $handlers = array();
- require(__DIR__.'/fixtures/events.php');
- $this->assertCount($dbcount, $handlers, 'Equal number of handlers in file and db: %s');
- }
-
- /**
- * Tests the uninstallation of event handlers from file.
- */
- public function test_events_update_definition__uninstall() {
- global $DB;
-
- events_update_definition('unittest');
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
-
- events_uninstall('unittest');
- $this->assertEquals(0, $DB->count_records('events_handlers', array('component'=>'unittest')), 'All handlers should be uninstalled: %s');
- }
-
- /**
- * Tests the update of event handlers from file.
- */
- public function test_events_update_definition__update() {
- global $DB;
-
- events_update_definition('unittest');
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
-
- // First modify directly existing handler.
- $handler = $DB->get_record('events_handlers', array('component'=>'unittest', 'eventname'=>'test_instant'));
-
- $original = $handler->handlerfunction;
-
- // Change handler in db.
- $DB->set_field('events_handlers', 'handlerfunction', serialize('some_other_function_handler'), array('id'=>$handler->id));
-
- // Update the definition, it should revert the handler back.
- events_update_definition('unittest');
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
- $handler = $DB->get_record('events_handlers', array('component'=>'unittest', 'eventname'=>'test_instant'));
- $this->assertSame($handler->handlerfunction, $original, 'update should sync db with file definition: %s');
- }
-
- /**
- * Tests events_trigger_is_registered() function.
- */
- public function test_events_is_registered() {
-
- events_update_definition('unittest');
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
-
- $this->assertTrue(events_is_registered('test_instant', 'unittest'));
- $this->assertDebuggingCalled('events_is_registered() has been deprecated along with all Events 1 API in favour of Events 2' .
- ' API, please use it instead.', DEBUG_DEVELOPER);
- }
-
- /**
- * Tests events_trigger_legacy() function.
- */
- public function test_events_trigger_legacy_instant() {
-
- events_update_definition('unittest');
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
-
- $this->assertEquals(0, events_trigger_legacy('test_instant', 'ok'));
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
- $this->assertEquals(0, events_trigger_legacy('test_instant', 'ok'));
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
- $this->assertEquals(2, eventslib_sample_function_handler('status'));
- }
-
- /**
- * Tests events_trigger_legacy() function.
- */
- public function test_events_trigger__cron() {
-
- events_update_definition('unittest');
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
-
- $this->assertEquals(0, events_trigger_legacy('test_cron', 'ok'));
- $this->assertEquals(0, eventslib_sample_handler_class::static_method('status'));
- events_cron('test_cron');
- // The events_cron one + one for each triggered event above (triggered in events_dispatch).
- $this->assertDebuggingCalledCount(2, array(self::DEBUGGING_MSG, self::DEBUGGING_MSG),
- array(DEBUG_DEVELOPER, DEBUG_DEVELOPER));
- $this->assertEquals(1, eventslib_sample_handler_class::static_method('status'));
- }
-
- /**
- * Tests events_pending_count() function.
- */
- public function test_events_pending_count() {
-
- events_update_definition('unittest');
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
-
- events_trigger_legacy('test_cron', 'ok');
- $this->assertDebuggingNotCalled();
- events_trigger_legacy('test_cron', 'ok');
- $this->assertDebuggingNotCalled();
- events_cron('test_cron');
- // The events_cron one + one for each triggered event above (triggered in events_dispatch).
- $this->assertDebuggingCalledCount(3);
- $this->assertEquals(0, events_pending_count('test_cron'), 'all messages should be already dequeued: %s');
- $this->assertDebuggingCalled('events_pending_count() has been deprecated along with all Events 1 API in favour of Events 2' .
- ' API, please use it instead.', DEBUG_DEVELOPER);
- }
-
- /**
- * Tests events_trigger_legacy() function when instant handler fails.
- */
- public function test_events_trigger__failed_instant() {
- global $CFG;
-
- events_update_definition('unittest');
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
-
- $olddebug = $CFG->debug;
-
- $this->assertEquals(1, events_trigger_legacy('test_instant', 'fail'), 'fail first event: %s');
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
- $this->assertEquals(1, events_trigger_legacy('test_instant', 'ok'), 'this one should fail too: %s');
- $this->assertDebuggingNotCalled();
-
- $this->assertEquals(0, events_cron('test_instant'), 'all events should stay in queue: %s');
- // events_cron + one for each dispatched event.
- $this->assertDebuggingCalledCount(3);
-
- $this->assertEquals(2, events_pending_count('test_instant'), 'two events should in queue: %s');
- $this->assertDebuggingCalled('events_pending_count() has been deprecated along with all Events 1 API in favour of Events 2' .
- ' API, please use it instead.', DEBUG_DEVELOPER);
-
- $this->assertEquals(0, eventslib_sample_function_handler('status'), 'verify no event dispatched yet: %s');
- eventslib_sample_function_handler('ignorefail'); // Ignore "fail" eventdata from now on.
- $this->assertEquals(1, events_trigger_legacy('test_instant', 'ok'), 'this one should go to queue directly: %s');
- $this->assertDebuggingNotCalled();
-
- $this->assertEquals(3, events_pending_count('test_instant'), 'three events should in queue: %s');
- $this->assertDebuggingCalled('events_pending_count() has been deprecated along with all Events 1 API in favour of Events 2' .
- ' API, please use it instead.', DEBUG_DEVELOPER);
-
- $this->assertEquals(0, eventslib_sample_function_handler('status'), 'verify previous event was not dispatched: %s');
- $this->assertEquals(3, events_cron('test_instant'), 'all events should be dispatched: %s');
- // events_cron + one for each dispatched event.
- $this->assertDebuggingCalledCount(4);
-
- $this->assertEquals(3, eventslib_sample_function_handler('status'), 'verify three events were dispatched: %s');
- $this->assertEquals(0, events_pending_count('test_instant'), 'no events should in queue: %s');
- $this->assertDebuggingCalled('events_pending_count() has been deprecated along with all Events 1 API in favour of Events 2' .
- ' API, please use it instead.', DEBUG_DEVELOPER);
-
- $this->assertEquals(0, events_trigger_legacy('test_instant', 'ok'), 'this event should be dispatched immediately: %s');
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
-
- $this->assertEquals(4, eventslib_sample_function_handler('status'), 'verify event was dispatched: %s');
- $this->assertEquals(0, events_pending_count('test_instant'), 'no events should in queue: %s');
- $this->assertDebuggingCalled('events_pending_count() has been deprecated along with all Events 1 API in favour of Events 2' .
- ' API, please use it instead.', DEBUG_DEVELOPER);
- }
-
- /**
- * Tests events_trigger() function.
- */
- public function test_events_trigger_debugging() {
-
- events_update_definition('unittest');
- $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
-
- $this->assertEquals(0, events_trigger('test_instant', 'ok'));
- $debugmessages = array('events_trigger() is deprecated, please use new events instead', self::DEBUGGING_MSG);
- $this->assertDebuggingCalledCount(2, $debugmessages, array(DEBUG_DEVELOPER, DEBUG_DEVELOPER));
- }
-}
-
-/**
- * Test handler function.
- */
-function eventslib_sample_function_handler($eventdata) {
- static $called = 0;
- static $ignorefail = false;
-
- if ($eventdata == 'status') {
- return $called;
-
- } else if ($eventdata == 'reset') {
- $called = 0;
- $ignorefail = false;
- return;
-
- } else if ($eventdata == 'fail') {
- if ($ignorefail) {
- $called++;
- return true;
- } else {
- return false;
- }
-
- } else if ($eventdata == 'ignorefail') {
- $ignorefail = true;
- return;
-
- } else if ($eventdata == 'ok') {
- $called++;
- return true;
- }
-
- print_error('invalideventdata', '', '', $eventdata);
-}
-
-
-/**
- * Test handler class with static method.
- */
-class eventslib_sample_handler_class {
- public static function static_method($eventdata) {
- static $called = 0;
- static $ignorefail = false;
-
- if ($eventdata == 'status') {
- return $called;
-
- } else if ($eventdata == 'reset') {
- $called = 0;
- $ignorefail = false;
- return;
-
- } else if ($eventdata == 'fail') {
- if ($ignorefail) {
- $called++;
- return true;
- } else {
- return false;
- }
-
- } else if ($eventdata == 'ignorefail') {
- $ignorefail = true;
- return;
-
- } else if ($eventdata == 'ok') {
- $called++;
- return true;
- }
-
- print_error('invalideventdata', '', '', $eventdata);
- }
-}
$this->assertTrue(grade_update_mod_grades($modinstance));
}
+
+ /**
+ * Tests the function remove_grade_letters().
+ */
+ public function test_remove_grade_letters() {
+ global $DB;
+
+ $this->resetAfterTest();
+
+ $course = $this->getDataGenerator()->create_course();
+
+ $context = context_course::instance($course->id);
+
+ // Add a grade letter to the course.
+ $letter = new stdClass();
+ $letter->letter = 'M';
+ $letter->lowerboundary = '100';
+ $letter->contextid = $context->id;
+ $DB->insert_record('grade_letters', $letter);
+
+ remove_grade_letters($context, false);
+
+ // Confirm grade letter was deleted.
+ $this->assertEquals(0, $DB->count_records('grade_letters'));
+ }
+
+ /**
+ * Tests the function grade_course_category_delete().
+ */
+ public function test_grade_course_category_delete() {
+ global $DB;
+
+ $this->resetAfterTest();
+
+ $category = coursecat::create(array('name' => 'Cat1'));
+
+ // Add a grade letter to the category.
+ $letter = new stdClass();
+ $letter->letter = 'M';
+ $letter->lowerboundary = '100';
+ $letter->contextid = context_coursecat::instance($category->id)->id;
+ $DB->insert_record('grade_letters', $letter);
+
+ grade_course_category_delete($category->id, '', false);
+
+ // Confirm grade letter was deleted.
+ $this->assertEquals(0, $DB->count_records('grade_letters'));
+ }
}
}
/**
- * Test for core_media_renderer get_players
+ * Test for get_players
*/
public function test_get_players() {
// All players are initially disabled (except link, which you can't).
}
/**
- * Test for core_media_renderer can_embed_url
+ * Test for can_embed_url
*/
public function test_can_embed_url() {
// All players are initially disabled, so mp4 cannot be rendered.
}
/**
- * Test for core_media_renderer embed_url.
+ * Test for embed_url.
* Checks multiple format/fallback support.
*/
public function test_embed_url_fallbacks() {
}
/**
- * Test for core_media_renderer embed_url.
+ * Test for embed_url.
* Check SWF works including the special option required to enable it
*/
public function test_embed_url_swf() {
}
/**
- * Test for core_media_renderer embed_url.
+ * Test for embed_url.
* Checks the EMBED_OR_BLANK option.
*/
public function test_embed_or_blank() {
}
/**
- * Test for core_media_renderer embed_url.
+ * Test for embed_url.
* Checks that size is passed through correctly to player objects and tests
* size support in html5video output.
*/
}
/**
- * Test for core_media_renderer embed_url.
+ * Test for embed_url.
* Checks that name is passed through correctly to player objects and tests
* name support in html5video output.
*/
}
/**
- * Test for core_media_renderer split_alternatives.
+ * Test for split_alternatives.
*/
public function test_split_alternatives() {
$mediamanager = core_media_manager::instance();
}
/**
- * Test for core_media_renderer embed_alternatives (with multiple urls)
+ * Test for embed_alternatives (with multiple urls)
*/
public function test_embed_alternatives() {
// Most aspects of this are same as single player so let's just try
=== 3.6 ===
* Custom AJAX handlers for the form autocomplete fields can now optionally return string in their processResults()
- callback. If a string is returned, it is displayed instead of the list if suggested items. This can be used, for
+ callback. If a string is returned, it is displayed instead of the list of suggested items. This can be used, for
example, to inform the user that there are too many items matching the current search criteria.
* The following functions have been finally deprecated and can not be used any more:
- - external_function_info()
+ - external_function_info()
+ - core_renderer::update_module_button()
+ - events_trigger()
+ - events_cron()
+ - events_dispatch()
+ - events_is_registered()
+ - events_load_def()
+ - events_pending_count()
+ - events_process_queued_handler()
+ - events_queue_handler()
+ - events_trigger_legacy()
+ - events_update_definition()
+* The following classes have been finally deprecated and can not be used any more:
+ - core_media_renderer
+ - core_media
* Following api's have been removed in behat_config_manager, please use behat_config_util instead.
- get_features_with_tags()
- get_components_steps_definitions()
- I set the field "<field_string>" to multiline
- I follow "<link_string>"" in the open menu
* Removed the lib/password_compat/lib/password.php file.
+* The eventslib.php file has been deleted and its functions have been moved to deprecatedlib.php. The affected functions are:
+ - events_get_cached()
+ - events_uninstall()
+ - events_cleanup()
+ - events_dequeue()
+ - events_get_handlers()
+* coursecat::get() now has optional $user parameter.
+* coursecat::is_uservisible() now has optional $user parameter.
+* Removed the lib/form/submitlink.php element which was deprecated in 3.2.
=== 3.5 ===
$someexamplesofremovedfiles = array(
// Removed in 3.6.
+ '/lib/medialib.php',
'/lib/password_compat/lib/password.php',
// Removed in 3.5.
'/lib/dml/mssql_native_moodle_database.php',
update_capabilities($component);
log_update_descriptions($component);
external_update_descriptions($component);
- events_update_definition($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
update_capabilities($component);
log_update_descriptions($component);
external_update_descriptions($component);
- events_update_definition($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
update_capabilities($component);
log_update_descriptions($component);
external_update_descriptions($component);
- events_update_definition($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
update_capabilities($component);
log_update_descriptions($component);
external_update_descriptions($component);
- events_update_definition($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
update_capabilities($component);
log_update_descriptions($component);
external_update_descriptions($component);
- events_update_definition($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
update_capabilities($component);
log_update_descriptions($component);
external_update_descriptions($component);
- events_update_definition($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
update_capabilities($component);
log_update_descriptions($component);
external_update_descriptions($component);
- events_update_definition($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
update_capabilities($component);
log_update_descriptions($component);
external_update_descriptions($component);
- events_update_definition($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
update_capabilities($component);
log_update_descriptions($component);
external_update_descriptions($component);
- events_update_definition($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
// Continue with the installation
log_update_descriptions('moodle');
external_update_descriptions('moodle');
- events_update_definition('moodle');
\core\task\manager::reset_scheduled_tasks_for_component('moodle');
message_update_providers('moodle');
\core\message\inbound\manager::update_handlers_for_component('moodle');
update_capabilities('moodle');
log_update_descriptions('moodle');
external_update_descriptions('moodle');
- events_update_definition('moodle');
\core\task\manager::reset_scheduled_tasks_for_component('moodle');
message_update_providers('moodle');
\core\message\inbound\manager::update_handlers_for_component('moodle');
public abstract function get_rank();
/**
- * Returns if the current player is enabled.
- *
* @deprecated since Moodle 3.2
- * @return bool True if player is enabled
*/
public function is_enabled() {
- debugging('Function core_media_player::is_enabled() is deprecated without replacement', DEBUG_DEVELOPER);
-
- $enabled = \core\plugininfo\media::get_enabled_plugins();
-
- if ($enabled && preg_match('/^media_(.*)_plugin$/', get_class($this), $matches)) {
- return array_key_exists($matches[1], $enabled);
- }
-
- return false;
+ throw new coding_exception('core_media_player::is_enabled() can not be used anymore.');
}
/**
}
/**
- * Compares by rank order, highest first. Used for sort functions.
* @deprecated since Moodle 3.2
- * @param core_media_player $a Player A
- * @param core_media_player $b Player B
- * @return int Negative if A should go before B, positive for vice versa
*/
- public static function compare_by_rank(core_media_player $a, core_media_player $b) {
- debugging('Function core_media_player::compare_by_rank() is deprecated without replacement', DEBUG_DEVELOPER);
- return $b->get_rank() - $a->get_rank();
+ public static function compare_by_rank() {
+ throw new coding_exception('core_media_player::compare_by_rank() can not be used anymore.');
}
/**
This files describes API changes in /media/ plugins,
information provided here is intended especially for developers.
+=== 3.6 ===
+
+* The following functions have been finally deprecated and can not be used anymore:
+ * core_media_player::is_enabled()
+ * core_media_player::compare_by_rank()
+
=== 3.3 ===
* core_media_manager setup() is now deprecated as it is now called when initialising core_media_manager::instance().
* core_media_manager is now final. Do not extend core_media_manager, instead create a media plugin.
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-require_once($CFG->libdir.'/eventslib.php');
-
define('MESSAGE_SHORTLENGTH', 300);
define('MESSAGE_HISTORY_ALL', 1);
* the ASSIGN_EVENT_TYPE_GRADINGDUE event will not be shown to students on their calendar.
*
* @param calendar_event $event
+ * @param int $userid User id to use for all capability checks, etc. Set to 0 for current user (default).
* @return bool Returns true if the event is visible to the current user, false otherwise.
*/
-function mod_assign_core_calendar_is_event_visible(calendar_event $event) {
+function mod_assign_core_calendar_is_event_visible(calendar_event $event, $userid = 0) {
global $CFG, $USER;
require_once($CFG->dirroot . '/mod/assign/locallib.php');
- $cm = get_fast_modinfo($event->courseid)->instances['assign'][$event->instance];
+ if (empty($userid)) {
+ $userid = $USER->id;
+ }
+
+ $cm = get_fast_modinfo($event->courseid, $userid)->instances['assign'][$event->instance];
$context = context_module::instance($cm->id);
$assign = new assign($context, $cm, null);
if ($event->eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {
- return $assign->can_grade();
+ return $assign->can_grade($userid);
} else {
return true;
}
*
* @param calendar_event $event
* @param \core_calendar\action_factory $factory
+ * @param int $userid User id to use for all capability checks, etc. Set to 0 for current user (default).
* @return \core_calendar\local\event\entities\action_interface|null
*/
function mod_assign_core_calendar_provide_event_action(calendar_event $event,
- \core_calendar\action_factory $factory) {
+ \core_calendar\action_factory $factory,
+ $userid = 0) {
global $CFG, $USER;
require_once($CFG->dirroot . '/mod/assign/locallib.php');
- $cm = get_fast_modinfo($event->courseid)->instances['assign'][$event->instance];
+ if (empty($userid)) {
+ $userid = $USER->id;
+ }
+
+ $cm = get_fast_modinfo($event->courseid, $userid)->instances['assign'][$event->instance];
$context = context_module::instance($cm->id);
$assign = new assign($context, $cm, null);
// Apply overrides.
- $assign->update_effective_access($USER->id);
+ $assign->update_effective_access($userid);
if ($event->eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {
$name = get_string('grade');
'action' => 'grader'
]);
$itemcount = $assign->count_submissions_need_grading();
- $actionable = $assign->can_grade() && (time() >= $assign->get_instance()->allowsubmissionsfromdate);
+ $actionable = $assign->can_grade($userid) && (time() >= $assign->get_instance()->allowsubmissionsfromdate);
} else {
- $usersubmission = $assign->get_user_submission($USER->id, false);
+ $usersubmission = $assign->get_user_submission($userid, false);
if ($usersubmission && $usersubmission->status === ASSIGN_SUBMISSION_STATUS_SUBMITTED) {
// The user has already submitted.
// We do not want to change the text to edit the submission, we want to remove the event from the Dashboard entirely.
return null;
}
- $participant = $assign->get_participant($USER->id);
+ $participant = $assign->get_participant($userid);
if (!$participant) {
// If the user is not a participant in the assignment then they have
'action' => 'editsubmission'
]);
$itemcount = 1;
- $actionable = $assign->is_any_submission_plugin_enabled() && $assign->can_edit_submission($USER->id);
+ $actionable = $assign->is_any_submission_plugin_enabled() && $assign->can_edit_submission($userid, $userid);
}
return $factory->create_instance(
require_once($CFG->dirroot . '/mod/assign/submissionplugin.php');
require_once($CFG->dirroot . '/mod/assign/renderable.php');
require_once($CFG->dirroot . '/mod/assign/gradingtable.php');
-require_once($CFG->libdir . '/eventslib.php');
require_once($CFG->libdir . '/portfolio/caller.php');
use \mod_assign\output\grading_app;
} else if ($plugin->is_visible() && $plugin->is_configurable()) {
$name = $plugin->get_subtype() . '_' . $plugin->get_type() . '_enabled';
$label = $plugin->get_name();
- $label .= ' ' . $this->get_renderer()->help_icon('enabled', $plugin->get_subtype() . '_' . $plugin->get_type());
$pluginsenabled[] = $mform->createElement('checkbox', $name, '', $label);
+ $helpicon = $this->get_renderer()->help_icon('enabled', $plugin->get_subtype() . '_' . $plugin->get_type());
+ $pluginsenabled[] = $mform->createElement('static', '', '', $helpicon);
$default = get_config($plugin->get_subtype() . '_' . $plugin->get_type(), 'default');
if ($plugin->get_config('enabled') !== false) {
/**
* Does this user have grade permission for this assignment?
*
+ * @param int|stdClass $user The object or id of the user who will do the editing (default to current user).
* @return bool
*/
- public function can_grade() {
+ public function can_grade($user = null) {
// Permissions check.
- if (!has_capability('mod/assign:grade', $this->context)) {
+ if (!has_capability('mod/assign:grade', $this->context, $user)) {
return false;
}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-require_once($CFG->libdir.'/eventslib.php');
-
defined('MOODLE_INTERNAL') || die();
// File areas for file submission assignment.
$this->assertTrue(mod_assign_core_calendar_is_event_visible($event));
}
+ public function test_assign_core_calendar_is_event_visible_duedate_event_for_teacher() {
+ $this->resetAfterTest();
+ $course = $this->getDataGenerator()->create_course();
+ $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+ $assign = $this->create_instance($course);
+
+ $this->setAdminUser();
+
+ // Create a calendar event.
+ $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_DUE);
+
+ // Now, log out.
+ $this->setUser();
+
+ // The teacher should see the due date event.
+ $this->assertTrue(mod_assign_core_calendar_is_event_visible($event, $teacher->id));
+ }
+
public function test_assign_core_calendar_is_event_visible_duedate_event_as_student() {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$this->assertTrue(mod_assign_core_calendar_is_event_visible($event));
}
+ public function test_assign_core_calendar_is_event_visible_duedate_event_for_student() {
+ $this->resetAfterTest();
+ $course = $this->getDataGenerator()->create_course();
+ $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+ $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+ $assign = $this->create_instance($course, ['assignsubmission_onlinetext_enabled' => 1]);
+
+ $this->setAdminUser();
+
+ // Create a calendar event.
+ $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_DUE);
+
+ // Now, log out.
+ $this->setUser();
+
+ // The student should care about the due date event.
+ $this->assertTrue(mod_assign_core_calendar_is_event_visible($event, $student->id));
+ }
+
public function test_assign_core_calendar_is_event_visible_gradingduedate_event_as_teacher() {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$this->assertTrue(mod_assign_core_calendar_is_event_visible($event));
}
+
+ public function test_assign_core_calendar_is_event_visible_gradingduedate_event_for_teacher() {
+ $this->resetAfterTest();
+ $course = $this->getDataGenerator()->create_course();
+ $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+ $assign = $this->create_instance($course);
+
+ // Create a calendar event.
+ $this->setAdminUser();
+ $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_GRADINGDUE);
+
+ // Now, log out.
+ $this->setUser();
+
+ // The teacher should see the due date event.
+ $this->assertTrue(mod_assign_core_calendar_is_event_visible($event, $teacher->id));
+ }
+
public function test_assign_core_calendar_is_event_visible_gradingduedate_event_as_student() {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$this->assertFalse(mod_assign_core_calendar_is_event_visible($event));
}
+
+ public function test_assign_core_calendar_is_event_visible_gradingduedate_event_for_student() {
+ $this->resetAfterTest();
+ $course = $this->getDataGenerator()->create_course();
+ $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+ $assign = $this->create_instance($course);
+
+ // Create a calendar event.
+ $this->setAdminUser();
+ $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_GRADINGDUE);
+
+ // Now, log out.
+ $this->setUser();
+
+ // The student should not see the due date event.
+ $this->assertFalse(mod_assign_core_calendar_is_event_visible($event, $student->id));
+ }
+
public function test_assign_core_calendar_provide_event_action_duedate_as_teacher() {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$this->assertNull($actionevent);
}
+ public function test_assign_core_calendar_provide_event_action_duedate_for_teacher() {
+ $this->resetAfterTest();
+ $course = $this->getDataGenerator()->create_course();
+ $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+ $assign = $this->create_instance($course);
+
+ // Create a calendar event.
+ $this->setAdminUser();
+ $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_DUE);
+
+ // Now, log out.
+ $this->setUser();
+
+ // Decorate action event for a teacher.
+ $factory = new \core_calendar\action_factory();
+ $actionevent = mod_assign_core_calendar_provide_event_action($event, $factory, $teacher->id);
+
+ // The teacher should not have an action for a due date event.
+ $this->assertNull($actionevent);
+ }
+
public function test_assign_core_calendar_provide_event_action_duedate_as_student() {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$this->assertTrue($actionevent->is_actionable());
}
+ public function test_assign_core_calendar_provide_event_action_duedate_for_student() {
+ $this->resetAfterTest();
+ $course = $this->getDataGenerator()->create_course();
+ $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+ $assign = $this->create_instance($course, ['assignsubmission_onlinetext_enabled' => 1]);
+
+ // Create a calendar event.
+ $this->setAdminUser();
+ $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_DUE);
+
+ // Now, log out.
+ $this->setUser();
+
+ // Decorate action event for a student.
+ $factory = new \core_calendar\action_factory();
+ $actionevent = mod_assign_core_calendar_provide_event_action($event, $factory, $student->id);
+
+ // Confirm the event was decorated.
+ $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
+ $this->assertEquals(get_string('addsubmission', 'assign'), $actionevent->get_name());
+ $this->assertInstanceOf('moodle_url', $actionevent->get_url());
+ $this->assertEquals(1, $actionevent->get_item_count());
+ $this->assertTrue($actionevent->is_actionable());
+ }
+
public function test_assign_core_calendar_provide_event_action_gradingduedate_as_teacher() {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$this->assertTrue($actionevent->is_actionable());
}
+ public function test_assign_core_calendar_provide_event_action_gradingduedate_for_teacher() {
+ $this->resetAfterTest();
+ $course = $this->getDataGenerator()->create_course();
+ $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+ $assign = $this->create_instance($course);
+
+ // Create a calendar event.
+ $this->setAdminUser();
+ $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_GRADINGDUE);
+
+ // Now, log out.
+ $this->setUser();
+
+ // Decorate action event for a teacher.
+ $factory = new \core_calendar\action_factory();
+ $actionevent = mod_assign_core_calendar_provide_event_action($event, $factory, $teacher->id);
+
+ // Confirm the event was decorated.
+ $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
+ $this->assertEquals(get_string('grade'), $actionevent->get_name());
+ $this->assertInstanceOf('moodle_url', $actionevent->get_url());
+ $this->assertEquals(0, $actionevent->get_item_count());
+ $this->assertTrue($actionevent->is_actionable());
+ }
+
public function test_assign_core_calendar_provide_event_action_gradingduedate_as_student() {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$this->assertFalse($actionevent->is_actionable());
}
+ public function test_assign_core_calendar_provide_event_action_gradingduedate_for_student() {
+ $this->resetAfterTest();
+ $course = $this->getDataGenerator()->create_course();
+ $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+ $assign = $this->create_instance($course);
+
+ // Create a calendar event.
+ $this->setAdminUser();
+ $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_GRADINGDUE);
+
+ // Now, log out.
+ $this->setUser();
+
+ // Decorate action event for a student.
+ $factory = new \core_calendar\action_factory();
+ $actionevent = mod_assign_core_calendar_provide_event_action($event, $factory, $student->id);
+
+ // Confirm the event was decorated.
+ $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
+ $this->assertEquals(get_string('grade'), $actionevent->get_name());
+ $this->assertInstanceOf('moodle_url', $actionevent->get_url());
+ $this->assertEquals(0, $actionevent->get_item_count());
+ $this->assertFalse($actionevent->is_actionable());
+ }
+
public function test_assign_core_calendar_provide_event_action_duedate_as_student_submitted() {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$this->assertNull($actionevent);
}
+ public function test_assign_core_calendar_provide_event_action_duedate_for_student_submitted() {
+ $this->resetAfterTest();
+ $course = $this->getDataGenerator()->create_course();
+ $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
+ $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
+ $assign = $this->create_instance($course, ['assignsubmission_onlinetext_enabled' => 1]);
+
+ $this->setAdminUser();
+
+ // Create a calendar event.
+ $event = $this->create_action_event($course, $assign, ASSIGN_EVENT_TYPE_DUE);
+
+ // Create an action factory.
+ $factory = new \core_calendar\action_factory();
+
+ // Submit as the student.
+ $this->add_submission($student, $assign);
+ $this->submit_for_grading($student, $assign);
+
+ // Now, log out.
+ $this->setUser();
+
+ // Confirm there was no event to action.
+ $factory = new \core_calendar\action_factory();
+ $actionevent = mod_assign_core_calendar_provide_event_action($event, $factory, $student->id);
+ $this->assertNull($actionevent);
+ }
+
/**
* Creates an action event.
*
$this->setUser($teacher);
$this->assertEquals(true, $assign->can_grade());
+ // Test the viewgrades capability for other users.
+ $this->setUser();
+ $this->assertTrue($assign->can_grade($teacher->id));
+ $this->assertFalse($assign->can_grade($student->id));
+
// Test the viewgrades capability - without mod/assign:grade.
$this->setUser($student);
* The mod_assign_base_testcase unit test base class has been deprecated.
It encouraged poor unit test design and led to significant performance issues with unit tests. See MDL-55609 for
further information.
+* The function can_grade() now has optional $user parameter.
=== 3.5 ===
* Functions assign:get_assign_grading_summary_renderable, assign:can_view_submission, assign:count_submissions_with_status,
*/
protected function init($group = 0) {
- $tablecolumns = array('userpic', 'fullname');
- $tableheaders = array(get_string('userpic'), get_string('fullnameuser'));
+ $tablecolumns = array('userpic', 'fullname', 'groups');
+ $tableheaders = array(
+ get_string('userpic'),
+ get_string('fullnameuser'),
+ get_string('groups')
+ );
$extrafields = get_extra_user_fields($this->get_context());
$ufields = user_picture::fields('u', $extrafields, $this->useridfield);
return $name;
}
+ /**
+ * Prepares column groups for display
+ * @param array $row
+ * @return string
+ */
+ public function col_groups($row) {
+ $groups = '';
+ if ($usergrps = groups_get_all_groups($this->feedbackstructure->get_cm()->course, $row->userid, 0, 'name')) {
+ foreach ($usergrps as $group) {
+ $groups .= format_string($group->name). ' ';
+ }
+ }
+ return trim($groups);
+ }
+
/**
* Adds common values to the table that do not change the number or order of entries and
* are only needed when outputting or downloading data.
defined('MOODLE_INTERNAL') || die();
-/** Include eventslib.php */
-require_once($CFG->libdir.'/eventslib.php');
// Include forms lib.
require_once($CFG->libdir.'/formslib.php');
/** Include required files */
require_once(__DIR__ . '/deprecatedlib.php');
require_once($CFG->libdir.'/filelib.php');
-require_once($CFG->libdir.'/eventslib.php');
/// CONSTANTS ///////////////////////////////////////////////////////////
require_once($CFG->dirroot.'/mod/lesson/locallib.php');
require_once($CFG->dirroot.'/mod/lesson/pagetypes/essay.php');
require_once($CFG->dirroot.'/mod/lesson/essay_form.php');
-require_once($CFG->libdir.'/eventslib.php');
$id = required_param('id', PARAM_INT); // Course Module ID
$mode = optional_param('mode', 'display', PARAM_ALPHA);
if (count($answers) > 1) {
$answer = array_shift($answers);
foreach ($answers as $a) {
- $DB->delete_record('lesson_answers', array('id' => $a->id));
+ $DB->delete_records('lesson_answers', array('id' => $a->id));
}
} else if (count($answers) == 1) {
$answer = array_shift($answers);
defined('MOODLE_INTERNAL') || die();
-require_once($CFG->libdir . '/eventslib.php');
require_once($CFG->dirroot . '/calendar/lib.php');
require_once($CFG->dirroot . '/mod/quiz/renderer.php');
require_once($CFG->dirroot . '/mod/quiz/attemptlib.php');
require_once($CFG->libdir . '/completionlib.php');
-require_once($CFG->libdir . '/eventslib.php');
require_once($CFG->libdir . '/filelib.php');
require_once($CFG->libdir . '/questionlib.php');
$launch = false; // Does this automatically trigger a launch based on skipview.
if (!empty($scorm->popup)) {
- $orgidentifier = '';
-
$scoid = 0;
$orgidentifier = '';
$result = scorm_get_toc($USER, $scorm, $cm->id, TOCFULLURL);
// Set last incomplete sco to launch first.
if (!empty($result->sco->id)) {
- $scoid = $result->sco->id;
+ $sco = $result->sco;
} else {
- if ($sco = scorm_get_sco($scorm->launch, SCO_ONLY)) {
- if (($sco->organization == '') && ($sco->launch == '')) {
- $orgidentifier = $sco->identifier;
- } else {
- $orgidentifier = $sco->organization;
- }
- $scoid = $sco->id;
+ $sco = scorm_get_sco($scorm->launch, SCO_ONLY);
+ }
+ if (!empty($sco)) {
+ $scoid = $sco->id;
+ if (($sco->organization == '') && ($sco->launch == '')) {
+ $orgidentifier = $sco->identifier;
+ } else {
+ $orgidentifier = $sco->organization;
}
}
* The final deprecation of xxx_get_types() callback means that this function will no longer be called.
Please use get_shortcuts() instead.
* lti_get_shortcuts has been deprecated. Please use get_shortcuts() instead to add items to the activity chooser.
+* Now, when mod_<modname>_core_calendar_is_event_visible or mod_<modname>_core_calendar_provide_event_action callback functions
+ are called, the userid of the requesting user is also passed to them.
=== 3.5 ===
MDL-55611 can be found at https://docs.moodle.org/dev/Calendar_API. The 3 new callbacks are:
- mod_<modname>_core_calendar_is_event_visible
- mod_<modname>_core_calendar_provide_event_action
- - mod_<modname>_core_calendar_event_action_show_items_acount
+ - mod_<modname>_core_calendar_event_action_shows_item_count
* Changes to the moodleform_mod class and its usage (MDL-58138):
- the get_data() method has been overriden. The implementation calls parent::get_data() and a new data_postprocessing() method
- new data_postprocessing() method added. Mods can override this in their mod_form subclass to modify the submit data. Previously
var root = $('[data-region="tag-condition-container-{{uniqid}}"]');
var selectElement = root.find('[data-region="tag-select"]');
var loadingContainer = root.find('[data-region="overlay-icon-container"]');
- var placeholderText = '{{#str}} filterbytags, core_question {{/str}}';
- var noSelectionText = '{{#str}} notagfiltersapplied, core_question {{/str}}';
+ var placeholderText = {{#quote}}{{#str}} filterbytags, core_question {{/str}}{{/quote}};
+ var noSelectionText = {{#quote}}{{#str}} notagfiltersapplied, core_question {{/str}}{{/quote}};
AutoComplete.enhance(
selectElement, // Element to enhance.
*/
abstract public function get_document($record, $options = array());
+ /**
+ * Returns the document title to display.
+ *
+ * Allow to customize the document title string to display.
+ *
+ * @param \core_search\document $doc
+ * @return string Document title to display in the search results page
+ */
+ public function get_document_display_title(\core_search\document $doc) {
+
+ return $doc->get('title');
+ }
+
/**
* Return the context info required to index files for
* this search area.
public function export_for_template(\renderer_base $output) {
list($componentname, $areaname) = \core_search\manager::extract_areaid_parts($this->get('areaid'));
- $title = $this->is_set('title') ? $this->format_text($this->get('title')) : '';
+ $searcharea = \core_search\manager::get_search_area($this->data['areaid']);
+ $title = $this->is_set('title') ? $this->format_text($searcharea->get_document_display_title($this)) : '';
$data = [
'componentname' => $componentname,
'areaname' => $areaname,
color: @dropdownLinkColorHover;
background-color: @dropdownLinkBackgroundHover;
}
- &:first-child {
- .border-top-radius(4px);
- }
- &:last-child {
- .border-bottom-radius(4px);
- }
}
a.hidden {
display: none;
}
> li {
display: block;
+ &:first-child a {
+ .border-top-radius(4px);
+ }
+ &:last-child a {
+ .border-bottom-radius(4px);
+ }
}
/** bottom left of button **/
color: #fff;
background-color: #0070a8;
}
-.moodle-actionmenu[data-enhanced].show .menu a:first-child {
- -webkit-border-top-right-radius: 4px;
- -moz-border-radius-topright: 4px;
- border-top-right-radius: 4px;
- -webkit-border-top-left-radius: 4px;
- -moz-border-radius-topleft: 4px;
- border-top-left-radius: 4px;
-}
-.moodle-actionmenu[data-enhanced].show .menu a:last-child {
- -webkit-border-bottom-right-radius: 4px;
- -moz-border-radius-bottomright: 4px;
- border-bottom-right-radius: 4px;
- -webkit-border-bottom-left-radius: 4px;
- -moz-border-radius-bottomleft: 4px;
- border-bottom-left-radius: 4px;
-}
.moodle-actionmenu[data-enhanced].show .menu a.hidden {
display: none;
}
.moodle-actionmenu[data-enhanced].show .menu > li {
display: block;
}
+.moodle-actionmenu[data-enhanced].show .menu > li:first-child a {
+ -webkit-border-top-right-radius: 4px;
+ -moz-border-radius-topright: 4px;
+ border-top-right-radius: 4px;
+ -webkit-border-top-left-radius: 4px;
+ -moz-border-radius-topleft: 4px;
+ border-top-left-radius: 4px;
+}
+.moodle-actionmenu[data-enhanced].show .menu > li:last-child a {
+ -webkit-border-bottom-right-radius: 4px;
+ -moz-border-radius-bottomright: 4px;
+ border-bottom-right-radius: 4px;
+ -webkit-border-bottom-left-radius: 4px;
+ -moz-border-radius-bottomleft: 4px;
+ border-bottom-left-radius: 4px;
+}
.moodle-actionmenu[data-enhanced].show .menu.align-tl-bl {
top: 100%;
left: 0;
// Prepare associative array with data from DB.
$doc = \core_search\document_factory::instance($record->id, $this->componentname, $this->areaname);
+ // Include all alternate names in title.
+ $array = [];
+ foreach (get_all_user_name_fields(false, null, null, null, true) as $field) {
+ $array[$field] = $record->$field;
+ }
+ $fullusername = join(' ', $array);
// Assigning properties to our document.
- $doc->set('title', content_to_text(fullname($record), false));
+ $doc->set('title', content_to_text($fullusername, false));
$doc->set('contextid', $context->id);
$doc->set('courseid', SITEID);
$doc->set('itemid', $record->id);
return $doc;
}
+ /**
+ * Returns the user fullname to display as document title
+ *
+ * @param \core_search\document $doc
+ * @return string User fullname
+ */
+ public function get_document_display_title(\core_search\document $doc) {
+
+ $user = \core_user::get_user($doc->get('itemid'));
+ return fullname($user);
+ }
+
/**
* Checking whether I can access a document
*
}
/**
- * Updates the provided users profile picture based upon the expected fields returned from the edit or edit_advanced forms.
- *
- * @deprecated since Moodle 3.2 MDL-51789 - please use core_user::update_picture() instead.
- * @todo MDL-54858 This will be deleted in Moodle 3.6.
+ * @deprecated since Moodle 3.2
* @see core_user::update_picture()
- *
- * @global moodle_database $DB
- * @param stdClass $usernew An object that contains some information about the user being updated
- * @param moodleform $userform The form that was submitted to edit the form (unused)
- * @param array $filemanageroptions
- * @return bool True if the user was updated, false if it stayed the same.
*/
-function useredit_update_picture(stdClass $usernew, moodleform $userform, $filemanageroptions = array()) {
- debugging('useredit_update_picture() is deprecated. Please use core_user::update_picture() instead.', DEBUG_DEVELOPER);
- return core_user::update_picture($usernew, $filemanageroptions);
+function useredit_update_picture() {
+ throw new coding_exception('useredit_update_picture() can not be used anymore. Please use ' .
+ 'core_user::update_picture() instead.');
}
/**
$mform->addElement('select', 'timezone', get_string('timezone'), $choices);
}
+ if ($user->id < 0) {
+ $mform->addElement('select', 'lang', get_string('preferredlanguage'), get_string_manager()->get_list_of_translations());
+ $lang = empty($user->lang) ? $CFG->lang : $user->lang;
+ $mform->setDefault('lang', $lang);
+ }
+
if (!empty($CFG->allowuserthemes)) {
$choices = array();
$choices[''] = get_string('default');
--- /dev/null
+@core @core_user
+Feature: Create manually an user.
+ In order create a user properly
+ As an admin
+ I need to be able to add new users and edit their fields.
+
+ @javascript
+ Scenario: Change default language for a new user
+ Given I log in as "admin"
+ When I navigate to "Add a new user" node in "Site administration > Users > Accounts"
+ Then I should see "Preferred language"
+
+ @javascript
+ Scenario: Language not displayed when editing an existing user
+ Given the following "users" exist:
+ | username | firstname | lastname | email |
+ | student1 | Student | 1 | student1@example.com |
+ When I log in as "admin"
+ And I navigate to "Browse list of users" node in "Site administration > Users > Accounts"
+ And I follow "Student 1"
+ And I follow "Edit profile"
+ Then I should not see "Preferred language"
Given I log in as "admin"
And I am on "Course 1" course homepage
And I navigate to course participants
- When I navigate to "Enrolment methods" in current page administration
+ When I navigate to "Users > Enrolment methods" in current page administration
And I click on "Disable" "link" in the "Manual enrolments" "table_row"
Then I navigate to course participants
And I should see "Not current" in the "student0x" "table_row"
$this->assertEquals(SITEID, $doc->get('courseid'));
$this->assertFalse($doc->is_set('userid'));
$this->assertEquals(\core_search\manager::NO_OWNER_ID, $doc->get('owneruserid'));
- $this->assertEquals(content_to_text(fullname($user), false), $doc->get('title'));
+ $this->assertEquals(content_to_text(fullname($user), false), $searcharea->get_document_display_title($doc));
$this->assertEquals(content_to_text($user->description, $user->descriptionformat), $doc->get('content'));
}
--- /dev/null
+This files describes API changes for code that uses the user API.
+
+=== 3.6 ===
+
+* The following functions have been finally deprecated and can not be used anymore:
+ * useredit_update_picture()