Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 567ab3d5d1 | |||
| ebbad9ca59 | |||
| b2d737b90d | |||
| db46fe6c59 | |||
| b31ba08ffa | |||
| 365ecbead3 | |||
| 51bde4b0dc | |||
| 72f8b25b24 | |||
| ce75268a2f | |||
| 2d6e97b5c2 | |||
| f14fa82b5b | |||
| 4fd4f002ee | |||
| 139f1a0ad8 | |||
| fa8fb6fbe1 | |||
| 27d127b9c5 | |||
| 1174a463f3 | |||
| 33d0756aac | |||
| 41d01a8f98 | |||
| 67889ed5be | |||
| 65c1213e00 | |||
| df4907d146 | |||
| 85d91d18b4 | |||
| b0dd37fa73 | |||
| 4f5fba677a | |||
| 95ac714f8f | |||
| 1ea01c9c50 | |||
| 94587407ec | |||
| f3076b17b4 | |||
| b54ac35cb3 | |||
| 8b3a8b9438 | |||
| e3e619e845 | |||
| c345c3a460 | |||
| 81b1e515f4 | |||
| 218d2c0eb3 | |||
| 81fcfc2065 | |||
| 5c18bd041a | |||
| ad1b3e2a11 | |||
| e647d73811 | |||
| 554826ec78 | |||
| d23c5c8c8d |
@@ -1698,4 +1698,149 @@
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="3.2" requires="2.7">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="5.5.31" />
|
||||
<VENDOR name="mysql" version="5.5.31" />
|
||||
<VENDOR name="postgres" version="9.1" />
|
||||
<VENDOR name="mssql" version="10.0" />
|
||||
<VENDOR name="oracle" version="10.2" />
|
||||
</DATABASE>
|
||||
<PHP version="5.6.5" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="mbstringrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opensslrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlrpc" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="xmlrpcrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="intlrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
@@ -140,6 +140,10 @@ class eventobservers {
|
||||
$subscriptions = subscription_manager::get_subscriptions_by_event($eventobj);
|
||||
$idstosend = array();
|
||||
foreach ($subscriptions as $subscription) {
|
||||
// Only proceed to fire events and notifications if the subscription is active.
|
||||
if (!subscription_manager::subscription_is_active($subscription)) {
|
||||
continue;
|
||||
}
|
||||
$starttime = $now - $subscription->timewindow;
|
||||
$starttime = ($starttime > $subscription->lastnotificationsent) ? $starttime : $subscription->lastnotificationsent;
|
||||
if ($subscription->courseid == 0) {
|
||||
|
||||
@@ -55,17 +55,26 @@ class subscription {
|
||||
* Magic get method.
|
||||
*
|
||||
* @param string $prop property to get.
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function __get($prop) {
|
||||
if (property_exists($this->subscription, $prop)) {
|
||||
if (isset($this->subscription->$prop)) {
|
||||
return $this->subscription->$prop;
|
||||
}
|
||||
throw new \coding_exception('Property "' . $prop . '" doesn\'t exist');
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic isset method.
|
||||
*
|
||||
* @param string $prop the property to get.
|
||||
* @return bool true if the property is set, false otherwise.
|
||||
*/
|
||||
public function __isset($prop) {
|
||||
return property_exists($this->subscription, $prop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a human readable name for instances associated with this subscription.
|
||||
*
|
||||
|
||||
@@ -35,6 +35,10 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class subscription_manager {
|
||||
|
||||
/** @const Period of time, in days, after which an inactive subscription will be removed completely.*/
|
||||
const INACTIVE_SUBSCRIPTION_LIFESPAN_IN_DAYS = 30;
|
||||
|
||||
/**
|
||||
* Subscribe a user to a given rule.
|
||||
*
|
||||
@@ -456,4 +460,78 @@ class subscription_manager {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates a group of subscriptions based on an input array of ids.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param array $ids of subscription ids.
|
||||
* @return bool true if the operation was successful, false otherwise.
|
||||
*/
|
||||
public static function activate_subscriptions(array $ids) {
|
||||
global $DB;
|
||||
if (!empty($ids)) {
|
||||
list($sql, $params) = $DB->get_in_or_equal($ids);
|
||||
$success = $DB->set_field_select('tool_monitor_subscriptions', 'inactivedate', '0', 'id ' . $sql, $params);
|
||||
return $success;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates a group of subscriptions based on an input array of ids.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param array $ids of subscription ids.
|
||||
* @return bool true if the operation was successful, false otherwise.
|
||||
*/
|
||||
public static function deactivate_subscriptions(array $ids) {
|
||||
global $DB;
|
||||
if (!empty($ids)) {
|
||||
$inactivedate = time();
|
||||
list($sql, $params) = $DB->get_in_or_equal($ids);
|
||||
$success = $DB->set_field_select('tool_monitor_subscriptions', 'inactivedate', $inactivedate, 'id ' . $sql,
|
||||
$params);
|
||||
return $success;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes subscriptions which have been inactive for a period of time.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param int $userid if provided, only this user's stale subscriptions will be deleted.
|
||||
* @return bool true if the operation was successful, false otherwise.
|
||||
*/
|
||||
public static function delete_stale_subscriptions($userid = 0) {
|
||||
global $DB;
|
||||
// Get the expiry duration, in days.
|
||||
$cutofftime = strtotime("-" . self::INACTIVE_SUBSCRIPTION_LIFESPAN_IN_DAYS . " days", time());
|
||||
|
||||
if (!empty($userid)) {
|
||||
// Remove any stale subscriptions for the desired user only.
|
||||
$success = $DB->delete_records_select('tool_monitor_subscriptions',
|
||||
'userid = ? AND inactivedate < ? AND inactivedate <> 0',
|
||||
array($userid, $cutofftime));
|
||||
|
||||
} else {
|
||||
// Remove all stale subscriptions.
|
||||
$success = $DB->delete_records_select('tool_monitor_subscriptions',
|
||||
'inactivedate < ? AND inactivedate <> 0',
|
||||
array($cutofftime));
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a subscription is active.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param \tool_monitor\subscription $subscription instance.
|
||||
* @return bool true if the subscription is active, false otherwise.
|
||||
*/
|
||||
public static function subscription_is_active(subscription $subscription) {
|
||||
return empty($subscription->inactivedate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
namespace tool_monitor\task;
|
||||
use tool_monitor\subscription;
|
||||
use tool_monitor\subscription_manager;
|
||||
|
||||
/**
|
||||
* Simple task class responsible for activating, deactivating and removing subscriptions.
|
||||
*
|
||||
* Activation/deactivation is managed by looking at the same access rules used to determine whether a user can
|
||||
* subscribe to the rule in the first place.
|
||||
*
|
||||
* Removal occurs when a subscription has been inactive for a period of time exceeding the lifespan, as set by
|
||||
* subscription_manager::get_inactive_subscription_lifespan().
|
||||
*
|
||||
* I.e.
|
||||
* - Activation: If a user can subscribe currently, then an existing subscription should be made active.
|
||||
* - Deactivation: If a user cannot subscribe currently, then an existing subscription should be made inactive.
|
||||
* - Removal: If a user has a subscription that has been inactive for longer than the prescribed period, then
|
||||
* delete the subscription entirely.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @package tool_monitor
|
||||
* @copyright 2016 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class check_subscriptions extends \core\task\scheduled_task {
|
||||
|
||||
/** @var array 1d static cache, indexed by userid, storing whether or not the user has been fully set up.*/
|
||||
protected $userssetupcache = array();
|
||||
|
||||
/** @var array 2d static cache, indexed by courseid and userid, storing whether a user can access the course with
|
||||
* the 'tool/monitor:subscribe' capability.
|
||||
*/
|
||||
protected $courseaccesscache = array();
|
||||
|
||||
/**
|
||||
* Get a descriptive name for this task.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @return string name of the task.
|
||||
*/
|
||||
public function get_name() {
|
||||
return get_string('taskchecksubscriptions', 'tool_monitor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks all course-level rule subscriptions and activates/deactivates based on current course access.
|
||||
*
|
||||
* The ordering of checks within the task is important for optimisation purposes. The aim is to be able to make a decision
|
||||
* about whether to activate/deactivate each subscription without making unnecessary checks. The ordering roughly follows the
|
||||
* context model, starting with system and user checks and moving down to course and course-module only when necessary.
|
||||
*
|
||||
* For example, if the user is suspended, then any active subscription is made inactive right away. I.e. there is no need to
|
||||
* check site-level, course-level or course-module-level permissions. Likewise, if a subscriptions is site-level, there is no
|
||||
* need to check course-level and course-module-level permissions.
|
||||
*
|
||||
* The task performs the following checks, in this order:
|
||||
* 1. Check for a suspended user, breaking if suspended.
|
||||
* 2. Check for an incomplete (not set up) user, breaking if not fully set up.
|
||||
* 3. Check for the required capability in the relevant context, breaking if the capability is not found.
|
||||
* 4. Check whether the subscription is site-context, breaking if true.
|
||||
* 5. Check whether the user has course access, breaking only if the subscription is not also course-module-level.
|
||||
* 6. Check whether the user has course-module access.
|
||||
*
|
||||
* @since 2.9.7
|
||||
*/
|
||||
public function execute() {
|
||||
global $DB;
|
||||
|
||||
if (!get_config('tool_monitor', 'enablemonitor')) {
|
||||
return; // The tool is disabled. Nothing to do.
|
||||
}
|
||||
|
||||
$toactivate = array(); // Store the ids of subscriptions to be activated upon completion.
|
||||
$todeactivate = array(); // Store the ids of subscriptions to be deactivated upon completion.
|
||||
|
||||
// Resultset rows are ordered by userid and courseid to work nicely with get_fast_modinfo() caching.
|
||||
$sql = "SELECT u.id AS userid, u.firstname AS userfirstname, u.lastname AS userlastname, u.suspended AS usersuspended,
|
||||
u.email AS useremail, c.visible as coursevisible, c.cacherev as coursecacherev, s.courseid AS subcourseid,
|
||||
s.userid AS subuserid, s.cmid AS subcmid, s.inactivedate AS subinactivedate, s.id AS subid
|
||||
FROM {user} u
|
||||
JOIN {tool_monitor_subscriptions} s ON (s.userid = u.id)
|
||||
LEFT JOIN {course} c ON (c.id = s.courseid)
|
||||
WHERE u.id = s.userid
|
||||
ORDER BY s.userid, s.courseid";
|
||||
$rs = $DB->get_recordset_sql($sql);
|
||||
|
||||
foreach ($rs as $row) {
|
||||
// Create skeleton records from the result. This should be enough to use in subsequent access calls and avoids DB hits.
|
||||
$sub = $this->get_subscription_from_rowdata($row);
|
||||
$sub = new subscription($sub);
|
||||
if (!isset($user) || $user->id != $sub->userid) {
|
||||
$user= $this->get_user_from_rowdata($row);
|
||||
}
|
||||
if ((!isset($course) || $course->id != $sub->courseid) && !empty($sub->courseid)) {
|
||||
$course = $this->get_course_from_rowdata($row);
|
||||
}
|
||||
|
||||
// The user is suspended at site level, so deactivate any active subscriptions.
|
||||
if ($user->suspended) {
|
||||
if (subscription_manager::subscription_is_active($sub)) {
|
||||
$todeactivate[] = $sub->id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Is the user fully set up? As per require_login on the subscriptions page.
|
||||
if (!$this->is_user_setup($user)) {
|
||||
if (subscription_manager::subscription_is_active($sub)) {
|
||||
$todeactivate[] = $sub->id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine the context, based on the subscription course id.
|
||||
$sitelevelsubscription = false;
|
||||
if (empty($sub->courseid)) {
|
||||
$context = \context_system::instance();
|
||||
$sitelevelsubscription = true;
|
||||
} else {
|
||||
$context = \context_course::instance($sub->courseid);
|
||||
}
|
||||
|
||||
// Check capability in the context.
|
||||
if (!has_capability('tool/monitor:subscribe', $context, $user)) {
|
||||
if (subscription_manager::subscription_is_active($sub)) {
|
||||
$todeactivate[] = $sub->id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the subscription is site-level, then we've run all the checks required to make an access decision.
|
||||
if ($sitelevelsubscription) {
|
||||
if (!subscription_manager::subscription_is_active($sub)) {
|
||||
$toactivate[] = $sub->id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check course access.
|
||||
if (!$this->user_can_access_course($user, $course, 'tool/monitor:subscribe')) {
|
||||
if (subscription_manager::subscription_is_active($sub)) {
|
||||
$todeactivate[] = $sub->id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the subscription has no course module relationship.
|
||||
if (empty($sub->cmid)) {
|
||||
if (!subscription_manager::subscription_is_active($sub)) {
|
||||
$toactivate[] = $sub->id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, check the course module info. We use the same checks as on the subscription page.
|
||||
$modinfo = get_fast_modinfo($course, $sub->userid);
|
||||
$cm = $modinfo->get_cm($sub->cmid);
|
||||
if (!$cm || !$cm->uservisible || !$cm->available) {
|
||||
if (subscription_manager::subscription_is_active($sub)) {
|
||||
$todeactivate[] = $sub->id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// The course module is available and visible, so make a decision.
|
||||
if (!subscription_manager::subscription_is_active($sub)) {
|
||||
$toactivate[] = $sub->id;
|
||||
}
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
// Activate/deactivate/delete relevant subscriptions.
|
||||
subscription_manager::activate_subscriptions($toactivate);
|
||||
subscription_manager::deactivate_subscriptions($todeactivate);
|
||||
subscription_manager::delete_stale_subscriptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a user is fully set up, using cached results where possible.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param \stdClass $user the user record.
|
||||
* @return bool true if the user is fully set up, false otherwise.
|
||||
*/
|
||||
protected function is_user_setup($user) {
|
||||
if (!isset($this->userssetupcache[$user->id])) {
|
||||
$this->userssetupcache[$user->id] = !user_not_fully_set_up($user);
|
||||
}
|
||||
return $this->userssetupcache[$user->id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines a user's access to a course with a given capability, using cached results where possible.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param \stdClass $user the user record.
|
||||
* @param \stdClass $course the course record.
|
||||
* @param string $capability the capability to check.
|
||||
* @return bool true if the user can access the course with the specified capability, false otherwise.
|
||||
*/
|
||||
protected function user_can_access_course($user, $course, $capability) {
|
||||
if (!isset($this->courseaccesscache[$course->id][$user->id][$capability])) {
|
||||
$this->courseaccesscache[$course->id][$user->id][$capability] = can_access_course($course, $user, $capability, true);
|
||||
}
|
||||
return $this->courseaccesscache[$course->id][$user->id][$capability];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a partial subscription record, created from properties of the supplied recordset row object.
|
||||
* Intended to return a minimal record for specific use within this class and in subsequent access control calls only.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param \stdClass $rowdata the row object.
|
||||
* @return \stdClass a partial subscription record.
|
||||
*/
|
||||
protected function get_subscription_from_rowdata($rowdata) {
|
||||
$sub = new \stdClass();
|
||||
$sub->id = $rowdata->subid;
|
||||
$sub->userid = $rowdata->subuserid;
|
||||
$sub->courseid = $rowdata->subcourseid;
|
||||
$sub->cmid = $rowdata->subcmid;
|
||||
$sub->inactivedate = $rowdata->subinactivedate;
|
||||
return $sub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a partial course record, created from properties of the supplied recordset row object.
|
||||
* Intended to return a minimal record for specific use within this class and in subsequent access control calls only.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param \stdClass $rowdata the row object.
|
||||
* @return \stdClass a partial course record.
|
||||
*/
|
||||
protected function get_course_from_rowdata($rowdata) {
|
||||
$course = new \stdClass();
|
||||
$course->id = $rowdata->subcourseid;
|
||||
$course->visible = $rowdata->coursevisible;
|
||||
$course->cacherev = $rowdata->coursecacherev;
|
||||
return $course;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a partial user record, created from properties of the supplied recordset row object.
|
||||
* Intended to return a minimal record for specific use within this class and in subsequent access control calls only.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param \stdClass $rowdata the row object.
|
||||
* @return \stdClass a partial user record.
|
||||
*/
|
||||
protected function get_user_from_rowdata($rowdata) {
|
||||
$user = new \stdClass();
|
||||
$user->id = $rowdata->userid;
|
||||
$user->firstname = $rowdata->userfirstname;
|
||||
$user->lastname = $rowdata->userlastname;
|
||||
$user->email = $rowdata->useremail;
|
||||
$user->suspended = $rowdata->usersuspended;
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="User id of the subscriber"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Timestamp of when this subscription was created"/>
|
||||
<FIELD NAME="lastnotificationsent" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Timestamp of the time when a notification was last sent for this subscription."/>
|
||||
<FIELD NAME="inactivedate" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
|
||||
@@ -32,5 +32,14 @@ $tasks = array(
|
||||
'day' => '*',
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
),
|
||||
array(
|
||||
'classname' => 'tool_monitor\task\check_subscriptions',
|
||||
'blocking' => 0,
|
||||
'minute' => 'R',
|
||||
'hour' => 'R',
|
||||
'day' => '*',
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
)
|
||||
);
|
||||
|
||||
@@ -56,5 +56,20 @@ function xmldb_tool_monitor_upgrade($oldversion) {
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
if ($oldversion < 2015051101) {
|
||||
|
||||
// Define field inactivedate to be added to tool_monitor_subscriptions.
|
||||
$table = new xmldb_table('tool_monitor_subscriptions');
|
||||
$field = new xmldb_field('inactivedate', XMLDB_TYPE_INTEGER, '10', null, true, null, 0, 'lastnotificationsent');
|
||||
|
||||
// Conditionally launch add field inactivedate.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Monitor savepoint reached.
|
||||
upgrade_plugin_savepoint(true, 2015051101, 'tool', 'monitor');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -99,4 +99,5 @@ $string['subhelp'] = 'Subscription details';
|
||||
$string['subhelp_help'] = 'This subscription listens for when the event \'{$a->eventname}\' has been triggered in \'{$a->moduleinstance}\' {$a->frequency} time(s) in {$a->minutes} minute(s).';
|
||||
$string['subscribeto'] = 'Subscribe to rule "{$a}"';
|
||||
$string['taskcleanevents'] = 'Removes any unnecessary event monitor events';
|
||||
$string['taskchecksubscriptions'] = 'Activate/deactivate invalid rule subscriptions';
|
||||
$string['unsubscribe'] = 'Unsubscribe';
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<?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/>.
|
||||
defined('MOODLE_INTERNAL') || exit();
|
||||
|
||||
/**
|
||||
* Unit tests for the subscription class.
|
||||
* @since 2.9.7
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @category test
|
||||
* @copyright 2016 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_monitor_subscription_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* @var \tool_monitor\subscription $subscription object.
|
||||
*/
|
||||
private $subscription;
|
||||
|
||||
/**
|
||||
* Test set up.
|
||||
*/
|
||||
public function setUp() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Create the mock subscription.
|
||||
$sub = new stdClass();
|
||||
$sub->id = 100;
|
||||
$sub->name = 'My test rule';
|
||||
$sub->courseid = 20;
|
||||
$this->subscription = $this->getMock('\tool_monitor\subscription',null, array($sub));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for the magic __isset method.
|
||||
*/
|
||||
public function test_magic_isset() {
|
||||
$this->assertEquals(true, isset($this->subscription->name));
|
||||
$this->assertEquals(true, isset($this->subscription->courseid));
|
||||
$this->assertEquals(false, isset($this->subscription->ruleid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for the magic __get method.
|
||||
*/
|
||||
public function test_magic_get() {
|
||||
$this->assertEquals(20, $this->subscription->courseid);
|
||||
$this->setExpectedException('coding_exception');
|
||||
$this->subscription->ruleid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
<?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/>.
|
||||
defined('MOODLE_INTERNAL') || exit();
|
||||
|
||||
/**
|
||||
* Unit tests for the tool_monitor clean events task.
|
||||
* @since 2.9.7
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @category test
|
||||
* @copyright 2016 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_monitor_task_check_subscriptions_testcase extends advanced_testcase {
|
||||
|
||||
private $course;
|
||||
private $user;
|
||||
private $rule;
|
||||
private $subscription;
|
||||
private $teacherrole;
|
||||
private $studentrole;
|
||||
|
||||
/**
|
||||
* Test set up.
|
||||
*/
|
||||
public function setUp() {
|
||||
global $DB;
|
||||
set_config('enablemonitor', 1, 'tool_monitor');
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// All tests defined herein need a user, course, rule and subscription, so set these up.
|
||||
$this->user = $this->getDataGenerator()->create_user();
|
||||
$this->course = $this->getDataGenerator()->create_course();
|
||||
|
||||
$rule = new stdClass();
|
||||
$rule->userid = 2; // Rule created by admin.
|
||||
$rule->courseid = $this->course->id;
|
||||
$rule->plugin = 'mod_book';
|
||||
$rule->eventname = '\mod_book\event\course_module_viewed';
|
||||
$rule->timewindow = 500;
|
||||
$monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
|
||||
$this->rule = $monitorgenerator->create_rule($rule);
|
||||
|
||||
$sub = new stdClass();
|
||||
$sub->courseid = $this->course->id;
|
||||
$sub->userid = $this->user->id;
|
||||
$sub->ruleid = $this->rule->id;
|
||||
$this->subscription = $monitorgenerator->create_subscription($sub);
|
||||
|
||||
// Also set up a student and a teacher role for use in some tests.
|
||||
$this->teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
|
||||
$this->studentrole = $DB->get_record('role', array('shortname' => 'student'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the subscription object from the DB.
|
||||
*
|
||||
* @return void.
|
||||
*/
|
||||
private function reload_subscription() {
|
||||
global $DB;
|
||||
$sub = $DB->get_record('tool_monitor_subscriptions', array('id' => $this->subscription->id));
|
||||
$this->subscription = new \tool_monitor\subscription($sub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm the task is named correctly.
|
||||
*/
|
||||
public function test_task_name() {
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$this->assertEquals(get_string('taskchecksubscriptions', 'tool_monitor'), $task->get_name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that site level subscriptions are activated and deactivated according to system capabilities.
|
||||
*/
|
||||
public function test_site_level_subscription() {
|
||||
// Create a site level subscription.
|
||||
$monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
|
||||
$sub = new stdClass();
|
||||
$sub->userid = $this->user->id;
|
||||
$sub->ruleid = $this->rule->id;
|
||||
$this->subscription = $monitorgenerator->create_subscription($sub);
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should be inactive as the user doesn't have the capability. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Now, assign the user as a teacher role at system context.
|
||||
$this->getDataGenerator()->role_assign($this->teacherrole->id, $this->user->id, context_system::instance());
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should be active now. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that if the module is disabled, no changes are made to active subscriptions.
|
||||
*/
|
||||
public function test_module_disabled() {
|
||||
set_config('enablemonitor', 0, 'tool_monitor');
|
||||
|
||||
// Subscription should be active to start with.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Run the task. Note, we never enrolled the user.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should still be active. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm an active, valid subscription stays active once the scheduled task is run.
|
||||
*/
|
||||
public function test_active_unaffected() {
|
||||
// Enrol the user as a teacher. This role should have the required capability.
|
||||
$this->getDataGenerator()->enrol_user($this->user->id, $this->course->id, $this->teacherrole->id);
|
||||
|
||||
// Subscription should be active to start with.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should still be active. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that a subscription for a user without an enrolment to the course is made inactive.
|
||||
*/
|
||||
public function test_course_enrolment() {
|
||||
// Subscription should be active until deactivated by the scheduled task. Remember, by default the test setup
|
||||
// doesn't enrol the user, so the first run of the task should deactivate it.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should NOT be active. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Enrol the user.
|
||||
$this->getDataGenerator()->enrol_user($this->user->id, $this->course->id, $this->teacherrole->id);
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// Subscription should now be active again.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that subscriptions for enrolled users without the required capability are made inactive.
|
||||
*/
|
||||
public function test_enrolled_user_with_no_capability() {
|
||||
// Enrol the user. By default, students won't have the required capability.
|
||||
$this->getDataGenerator()->enrol_user($this->user->id, $this->course->id, $this->studentrole->id);
|
||||
|
||||
// The subscription should be active to start with. Pass in the id only to refetch the data.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should NOT be active. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that subscriptions for users who fail can_access_course(), are deactivated.
|
||||
*/
|
||||
public function test_can_access_course() {
|
||||
// Enrol the user as a teacher. This role should have the required capability.
|
||||
$this->getDataGenerator()->enrol_user($this->user->id, $this->course->id, $this->teacherrole->id);
|
||||
|
||||
// Strip the ability to see hidden courses, so we'll fail the check_subscriptions->user_can_access_course call.
|
||||
$context = \context_course::instance($this->course->id);
|
||||
assign_capability('moodle/course:viewhiddencourses', CAP_PROHIBIT, $this->teacherrole->id, $context);
|
||||
|
||||
// Subscription should be active to start with.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Hide the course.
|
||||
course_change_visibility($this->course->id, false);
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should be inactive. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that subscriptions for enrolled users who don't have CM access, are deactivated.
|
||||
*/
|
||||
public function test_cm_access() {
|
||||
// Enrol the user as a student but grant to ability to subscribe. Students cannot view hidden activities.
|
||||
$context = \context_course::instance($this->course->id);
|
||||
assign_capability('tool/monitor:subscribe', CAP_ALLOW, $this->studentrole->id, $context);
|
||||
$this->getDataGenerator()->enrol_user($this->user->id, $this->course->id, $this->studentrole->id);
|
||||
|
||||
// Generate a course module.
|
||||
$book = $this->getDataGenerator()->create_module('book', array('course' => $this->course->id));
|
||||
|
||||
// And add a subscription to it.
|
||||
$sub = new stdClass();
|
||||
$sub->courseid = $this->course->id;
|
||||
$sub->userid = $this->user->id;
|
||||
$sub->ruleid = $this->rule->id;
|
||||
$sub->cmid = $book->cmid;
|
||||
$monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
|
||||
$this->subscription = $monitorgenerator->create_subscription($sub);
|
||||
|
||||
// The subscription should be active to start with. Pass in the id only to refetch the data.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should still be active. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Make the course module invisible, which should in turn make the subscription inactive.
|
||||
set_coursemodule_visible($book->cmid, false);
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should NOT be active. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Make the course module visible again.
|
||||
set_coursemodule_visible($book->cmid, true);
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should be active. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that long term inactive subscriptions are removed entirely.
|
||||
*/
|
||||
public function test_stale_subscription_removal() {
|
||||
global $DB;
|
||||
// Manually set the inactivedate to 1 day older than the limit allowed.
|
||||
$daysold = 1 + \tool_monitor\subscription_manager::INACTIVE_SUBSCRIPTION_LIFESPAN_IN_DAYS;
|
||||
|
||||
$inactivedate = strtotime("-$daysold days", time());
|
||||
$DB->set_field('tool_monitor_subscriptions', 'inactivedate', $inactivedate, array('id' => $this->subscription->id));
|
||||
|
||||
// Subscription should be inactive to start with.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// Subscription should now not exist at all.
|
||||
$this->assertEquals(false, $DB->record_exists('tool_monitor_subscriptions', array('id' => $this->subscription->id)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that subscriptions for a partially set up user are deactivated.
|
||||
*/
|
||||
public function test_user_not_fully_set_up() {
|
||||
global $DB;
|
||||
|
||||
// Enrol the user as a teacher.
|
||||
$this->getDataGenerator()->enrol_user($this->user->id, $this->course->id, $this->teacherrole->id);
|
||||
|
||||
// The subscription should be active to start.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Unset the user's email address, so we fail the check_subscriptions->is_user_setup() call.
|
||||
$DB->set_field('user', 'email', '', array('id' => $this->user->id));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should now be inactive.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that a suspended user's subscriptions are deactivated properly.
|
||||
*/
|
||||
public function test_suspended_user() {
|
||||
global $DB;
|
||||
|
||||
// Enrol the user as a teacher. This role should have the required capability.
|
||||
$this->getDataGenerator()->enrol_user($this->user->id, $this->course->id, $this->teacherrole->id);
|
||||
|
||||
// Subscription should be active to start with.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Suspend the user.
|
||||
$DB->set_field('user', 'suspended', '1', array('id' => $this->user->id));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should now be inactive.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Unsuspend the user.
|
||||
$DB->set_field('user', 'suspended', '0', array('id' => $this->user->id));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should now be active again.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
$plugin->version = 2015051100; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2015051101; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2015050500; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_monitor'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -96,6 +96,7 @@ class behat_calendar extends behat_base {
|
||||
$dayofmonth = "a[{$daycontains}]";
|
||||
return array(
|
||||
new Given('I hover "//' . $currentmonth . '/descendant::' . $daycell . '/' . $dayofmonth . '" "xpath_element"'),
|
||||
new Given('I wait until the page is ready'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,20 +32,21 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['cannotcreatedboninstall'] = '<p>No és pot crear la base de dades.</p> <p>La base de dades especificada no existeix i l\'usuari que heu proporcionat no té permís per a crear-la.</p>
|
||||
<p>L\'administrador del lloc hauria de verificar la configuració de la base de dades.</p>';
|
||||
$string['cannotcreatelangdir'] = 'No s\'ha pogut crear el directori d\'idiomes.';
|
||||
$string['cannotcreatelangdir'] = 'No s\'ha pogut crear el directori d\'idiomes';
|
||||
$string['cannotcreatetempdir'] = 'No s\'ha pogut crear el directori temporal';
|
||||
$string['cannotdownloadcomponents'] = 'No s\'han pogut baixar components';
|
||||
$string['cannotdownloadzipfile'] = 'No s\'ha pogut baixar el fitxer zip';
|
||||
$string['cannotdownloadzipfile'] = 'No s\'ha pogut baixar el fitxer ZIP';
|
||||
$string['cannotfindcomponent'] = 'No s\'ha pogut trobar el component';
|
||||
$string['cannotsavemd5file'] = 'No s\'ha pogut desar el fitxer md5';
|
||||
$string['cannotsavezipfile'] = 'No s\'ha pogut desar el fitxer zip';
|
||||
$string['cannotsavezipfile'] = 'No s\'ha pogut desar el fitxer ZIP';
|
||||
$string['cannotunzipfile'] = 'No s\'ha pogut descomprimir el fitxer';
|
||||
$string['componentisuptodate'] = 'El component està al dia';
|
||||
$string['componentisuptodate'] = 'El component està actualitzat';
|
||||
$string['dmlexceptiononinstall'] = '<p>S\'ha produït un error de la base de dades [{$a->errorcode}].<br />{$a->debuginfo}</p>';
|
||||
$string['downloadedfilecheckfailed'] = 'Ha fallat la comprovació del fitxer baixat';
|
||||
$string['invalidmd5'] = 'L\'md5 no és vàlid. Torneu-ho a provar';
|
||||
$string['missingrequiredfield'] = 'Falta algun camp necessari';
|
||||
$string['remotedownloaderror'] = 'No s\'ha pogut baixar el component al vostre servidor. Verifiqueu els paràmetres de servidor intermediari. Es recomana l\'extensió cURL.<br /><br />Haureu de baixar manualment el fitxer <a href="{$a->url}">{$a->url}</a>, copiar-lo a la ubicació "{$a->dest}" del vostre servidor i descomprimir-lo allí.';
|
||||
$string['remotedownloaderror'] = '<p>No s\'ha pogut baixar el component al vostre servidor. Verifiqueu els paràmetres del servidor intermediari. Es recomana vivament l\'extensió cURL de PHP.</p>
|
||||
<p>Haureu de baixar manualment el fitxer <a href="{$a->url}">{$a->url}</a>, copiar-lo a la ubicació «{$a->dest}» del vostre servidor i descomprimir-lo allí.</p>';
|
||||
$string['wrongdestpath'] = 'El camí de destinació és erroni';
|
||||
$string['wrongsourcebase'] = 'L\'adreça (URL) base de la font és errònia';
|
||||
$string['wrongzipfilename'] = 'El nom del fitxer ZIP és erroni';
|
||||
|
||||
@@ -34,7 +34,7 @@ $string['admindirname'] = 'Directori d\'administració';
|
||||
$string['availablelangs'] = 'Llista d\'idiomes disponibles';
|
||||
$string['chooselanguagehead'] = 'Trieu un idioma';
|
||||
$string['chooselanguagesub'] = 'Trieu un idioma per a la instal·lació. S\'utilitzarà també com a idioma per defecte del lloc, tot i que després podeu canviar-lo.';
|
||||
$string['clialreadyconfigured'] = 'El fitxer config.php ja existeix, feu servir dmin/cli/install_database.php si voleu instal·lar aquest lloc web.';
|
||||
$string['clialreadyconfigured'] = 'El fitxer config.php ja existeix, feu servir admin/cli/install_database.php si voleu instal·lar el Moodle en aquest lloc web.';
|
||||
$string['clialreadyinstalled'] = 'El fitxer de configuració config.php ja existeix. Feu servir admin/cli/upgrade.php si voleu actualitzar Moodle per a aquest lloc web.';
|
||||
$string['cliinstallheader'] = 'Programa d\'instal·lació de línia d\'ordres de Moodle {$a}';
|
||||
$string['databasehost'] = 'Servidor de base de dades:';
|
||||
@@ -67,14 +67,14 @@ $string['pathserrcreatedataroot'] = 'L\'instal·lador no pot crear el directori
|
||||
$string['pathshead'] = 'Confirmeu els camins';
|
||||
$string['pathsrodataroot'] = 'No es pot escriure en el directori dataroot.';
|
||||
$string['pathsroparentdataroot'] = 'No es pot escriure en el directori pare ({$a->parent}). L\'instal·lador no pot crear el directori ({$a->dataroot}).';
|
||||
$string['pathssubadmindir'] = 'Alguns serveis d\'allotjament web (pocs) utilitzen un URL especial /admin p. ex. per a accedir a un tauler de control o quelcom semblant. Malauradament això entra en conflicte amb la ubicació estàndard de les pàgines d\'administració de Moodle. Podeu arreglar aquest problema canviant el nom del directori d\'administració de Moodle en la vostra instal·lació i posant el nou nom aquí. Per exemple <em>moodleadmin</em>. Això modificarà els enllaços d\'administració de Moodle.';
|
||||
$string['pathssubdataroot'] = 'Necessiteu un espai on Moodle pugui desar els fitxers penjats. Aquest directori hauria de tenir permisos de lectura I ESCRIPTURA per a l\'usuari del servidor web (normalment \'nobody\' o \'apache\'), però no cal que sigui accessible directament via web. L\'instal·lador provarà de crear-lo si no existeix.';
|
||||
$string['pathssubadmindir'] = 'Alguns serveis d\'allotjament web (pocs) utilitzen /admin com a URL especial perquè accediu a un tauler de control o quelcom semblant. Malauradament, això entra en conflicte amb la ubicació estàndard de les pàgines d\'administració de Moodle. Podeu arreglar aquest problema canviant el nom del directori d\'administració de Moodle en la vostra instal·lació i posant el nou nom aquí. Per exemple: <em>moodleadmin</em>. Això arreglarà els enllaços d\'administració de Moodle.';
|
||||
$string['pathssubdataroot'] = '<p>Directori on el Moodle emmagatzemarà els materials pujats pels usuaris.</p>
|
||||
<p>Aquest directori hauria de tenir permisos de lectura i escriptura per a l\'usuari del servidor web (normalment \'www-data\', \'nobody\', or \'apache\').</p>
|
||||
<p>No ha de ser accessible directament via web.</p>
|
||||
<p>L\'instal·lador provarà de crear-lo si no existeix.</p>';
|
||||
$string['pathssubdirroot'] = 'Camí complet del directori d\'instal·lació de Moodle.';
|
||||
$string['pathssubwwwroot'] = 'L\'adreça web completa on s\'accedirà a Moodle.
|
||||
No és possible accedir a Moodle en diferents adreces.
|
||||
Si el vostre lloc té múltiples adreces públiques haureu de configurar redireccions permanents per a totes excepte aquesta.
|
||||
Si el vostre lloc és accessible tant des d\'Internet com des d\'una intranet, utilitzeu aquí l\'adreça pública i configureu el DNS de manera que els usuaris de la intranet puguin utilitzar també l\'adreça pública.
|
||||
Si l\'adreça no és correcta, canvieu l\'URL en el vostre navegador per reiniciar la instal·lació amb un altre valor.';
|
||||
$string['pathssubwwwroot'] = '<p>L\'adreça web completa on s\'accedirà a Moodle; per exemple, l\'adreça que els usuaris introduiran a la barra d\'adreces del navegador per accedir a Moodle.</p> <p> No és possible accedir a Moodle utilitzant diferents adreces. Si el vostre lloc és accessible a través de diferents adreces, trieu-ne la més fàcil i configureu una redirecció permanent per a cadascuna de les altres adreces.</p> <p>
|
||||
Si el vostre lloc és accessible tant des d\'Internet com des d\'una xarxa interna (anomenada de vegades intranet), utilitzeu l\'adreça pública aquí.</p> <p>Si l\'adreça actual no és correcta, canvieu l\'URL a la barra d\'adreces del navegador i reinicieu la instal·lació.';
|
||||
$string['pathsunsecuredataroot'] = 'La ubicació del dataroot no és segura.';
|
||||
$string['pathswrongadmindir'] = 'No existeix el directori d\'administració';
|
||||
$string['phpextension'] = 'Extensió PHP {$a}';
|
||||
@@ -84,7 +84,7 @@ $string['phpversionhelp'] = '<p>Moodle necessita una versió de PHP 4.3.0 o 5.1.
|
||||
<p>Us cal actualitzar el PHP o traslladar Moodle a un ordinador amb una versió de PHP més recent.<br />(Si esteu utilitzant la versió 5.0.x, alternativament també podríeu tornar enrere a la 4.4.x)</p>';
|
||||
$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
|
||||
$string['welcomep20'] = 'Esteu veient aquesta pàgina perquè heu instal·lat amb èxit i heu executat el paquet <strong>{$a->packname} {$a->packversion}</strong>. Felicitacions.';
|
||||
$string['welcomep30'] = 'Aquesta versió de <strong>{$a->installername}</strong> inclou les aplicacions necessàries per crear un entorn en el qual funcioni <strong>Moodle</strong>:';
|
||||
$string['welcomep30'] = 'Aquesta versió de <strong>{$a->installername}</strong> inclou les aplicacions necessàries per crear un entorn en el qual funcioni <strong>Moodle</strong>, concretament:';
|
||||
$string['welcomep40'] = 'El paquet inclou també <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
|
||||
$string['welcomep50'] = 'L\'ús de totes les aplicacions d\'aquest paquet és governat per les seves llicències respectives. El paquet <strong>{$a->installername}</strong> complet és
|
||||
<a href="http://www.opensource.org/docs/definition_plain.html">codi font obert</a> i es distribueix
|
||||
|
||||
@@ -30,5 +30,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = '';
|
||||
$string['thisdirection'] = 'ltr';
|
||||
$string['thislanguage'] = 'Català';
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['language'] = 'زمان';
|
||||
$string['moodlelogo'] = 'لۆگۆی موودڵ';
|
||||
$string['next'] = 'دواتر';
|
||||
$string['previous'] = 'پێشوو';
|
||||
$string['reload'] = 'بارکردنەوە';
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['cannotcreatedboninstall'] = '<p>Kan ikke oprette databasen.</p> <p>Den specificerede database eksisterer ikke og brugeren har ikke tilladelse til at oprette den.</p> <p>Administrator bør verificere databasekonfigurationen.</p>';
|
||||
$string['cannotcreatelangdir'] = 'Kan ikke oprette sprogmappe';
|
||||
$string['cannotcreatetempdir'] = 'Kan ikke oprette temp-mappe';
|
||||
$string['cannotdownloadcomponents'] = 'Kan ikke downloade komponenter';
|
||||
@@ -39,9 +40,12 @@ $string['cannotsavemd5file'] = 'Kan ikke gemme md5-fil';
|
||||
$string['cannotsavezipfile'] = 'Kan ikke gemme zip-fil';
|
||||
$string['cannotunzipfile'] = 'Kan ikke pakke filen ud';
|
||||
$string['componentisuptodate'] = 'Komponenten er ajour';
|
||||
$string['dmlexceptiononinstall'] = '<p>En database fejl er opstået [{$a->errorcode}].<br />{$a->debuginfo}</p>';
|
||||
$string['downloadedfilecheckfailed'] = 'Downloadet fil-tjek fejlede';
|
||||
$string['invalidmd5'] = 'Tjekvariablen var forkert - prøv igen';
|
||||
$string['missingrequiredfield'] = 'Der mangler nogle obligatoriske felter';
|
||||
$string['remotedownloaderror'] = '<p> Download af komponent til din server fejlede. Venligst verificer proxy indstillilnger; PHP cURL filtypen anbefales kraftigt. </p>
|
||||
<p>Du må downloade <a href="{$a->url}">{$a->url}</a> filen manuelt, kopier den til "{$a->dest}" på din server og udpak den her </p>';
|
||||
$string['wrongdestpath'] = 'Forkert destinationssti';
|
||||
$string['wrongsourcebase'] = 'Forkert kilde-URL';
|
||||
$string['wrongzipfilename'] = 'Forkert zip-filnavn';
|
||||
|
||||
@@ -41,6 +41,7 @@ $string['databasehost'] = 'Databasevært';
|
||||
$string['databasename'] = 'Databasenavn';
|
||||
$string['databasetypehead'] = 'Vælg databasedriver';
|
||||
$string['dataroot'] = 'Datamappe';
|
||||
$string['datarootpermission'] = 'Rettighed til data mapper';
|
||||
$string['dbprefix'] = 'Præfix for tabeller';
|
||||
$string['dirroot'] = 'Moodle-mappe';
|
||||
$string['environmenthead'] = 'Kontrollerer din serveropsætning...';
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['language'] = 'Sprog';
|
||||
$string['moodlelogo'] = 'Moodlelogo';
|
||||
$string['next'] = 'Næste';
|
||||
$string['previous'] = 'Forrige';
|
||||
$string['reload'] = 'Genindlæs';
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Automatically generated strings for Moodle installer
|
||||
*
|
||||
* Do not edit this file manually! It contains just a subset of strings
|
||||
* needed during the very first steps of installation. This file was
|
||||
* generated automatically by export-installer.php (which is part of AMOS
|
||||
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
|
||||
* list of strings defined in /install/stringnames.txt.
|
||||
*
|
||||
* @package installer
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'da';
|
||||
$string['thisdirection'] = 'ltr';
|
||||
$string['thislanguage'] = 'Dansk Rum';
|
||||
@@ -31,6 +31,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['language'] = 'སྐད་ཡིག།';
|
||||
$string['moodlelogo'] = 'Moodle ལས་རྟགས།';
|
||||
$string['next'] = 'ཤུལ་མམ';
|
||||
$string['previous'] = 'ཧེ་མམ';
|
||||
$string['reload'] = 'ཡང་བསྐྱར་མངོན་གསལ་འབད';
|
||||
|
||||
@@ -30,4 +30,5 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['cannotfindcomponent'] = 'کامپوننت پیدا نشد';
|
||||
$string['missingrequiredfield'] = 'بعضی از فیلدهای ضروری خالی است';
|
||||
|
||||
@@ -34,6 +34,8 @@ $string['admindirname'] = 'دایرکتوری مدیر';
|
||||
$string['availablelangs'] = 'بستههای زبانی موجود';
|
||||
$string['chooselanguagehead'] = 'انتخاب زبان';
|
||||
$string['chooselanguagesub'] = 'لطفاً زبانی را به جهت استفاده در حین نصب انتخاب نمائید. زبان سایت و کاربر را در صفحهای دیگر میتوانید انتخاب کنید.';
|
||||
$string['databasehost'] = 'میزبان پایگاه داده';
|
||||
$string['databasename'] = 'نام پایگاه داده';
|
||||
$string['dataroot'] = 'دایرکتوری داده';
|
||||
$string['dbprefix'] = 'پیشوند جدولها';
|
||||
$string['dirroot'] = 'دایرکتوری مودل';
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['language'] = 'زبان';
|
||||
$string['moodlelogo'] = 'لوگوی مودل';
|
||||
$string['next'] = 'ادامه';
|
||||
$string['previous'] = 'قبلی';
|
||||
$string['reload'] = 'بررسی مجدد';
|
||||
|
||||
@@ -41,5 +41,5 @@ $string['cliunknowoption'] = 'אפשרויות לא מוכרות :
|
||||
{$a}
|
||||
אנא השתמש באפשרות העזרה.';
|
||||
$string['cliyesnoprompt'] = 'רשום y (שפרושו כן) או n (שפרושו לא)';
|
||||
$string['environmentrequireinstall'] = 'נדרש להתקין/לאפשר זאת';
|
||||
$string['environmentrequireversion'] = 'גירסת {$a->needed} נדרשת ואתה מריץ {$a->current}';
|
||||
$string['environmentrequireinstall'] = 'נדרש להתקין ולאפשר הרחבה זו';
|
||||
$string['environmentrequireversion'] = 'גירסה {$a->needed} נדרשת אך הגירסה הנוכחית היא {$a->current}';
|
||||
|
||||
@@ -86,10 +86,10 @@ $string['pathsunsecuredataroot'] = 'ספריית המידע (Data Directory) ל
|
||||
$string['pathswrongadmindir'] = 'ספריית ה-admin לא קיימת';
|
||||
$string['phpextension'] = 'הרחבת PHP {$a}';
|
||||
$string['phpversion'] = 'גירסת PHP';
|
||||
$string['phpversionhelp'] = '<p>גרסת PHP חייבת להיות לפחות 4.3.0 או 5.1.0 (בגרסאות 5.0.x קיימות מספר בעיות ידועות) </p>
|
||||
$string['phpversionhelp'] = '<p>גרסת PHP חייבת להיות לפחות 4.3.0 או 5.1.0 (בגרסאות 5.0 קיימות מספר בעיות ידועות) </p>
|
||||
<p> במערכת שלך פועלת כרגע גרסת {$a} </p>
|
||||
<p> אתה חייב לשדרג את גרסת ה-PHP שלך או לעבור למחשב מארח עם עם גירסת PHP חדשה! <br/>
|
||||
(במקרים של גרסת 5.0.x תוכל גם לרדת בגרסה ל- 4.4.x)
|
||||
(במקרים של גרסת 5.0 תוכל גם לרדת בגרסה ל- 4.4)
|
||||
</p>';
|
||||
$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
|
||||
$string['welcomep20'] = 'הינך רואה את עמוד זה מפני שהתקנת והפעלת בהלכה את <strong>{$a->packname} {$a->packversion}</strong>
|
||||
|
||||
@@ -33,4 +33,4 @@ defined('MOODLE_INTERNAL') || die();
|
||||
$string['language'] = 'שפת ממשק';
|
||||
$string['next'] = 'הבא';
|
||||
$string['previous'] = 'קודם';
|
||||
$string['reload'] = 'טען מחדש';
|
||||
$string['reload'] = 'טעינה מחדש';
|
||||
|
||||
@@ -66,7 +66,9 @@ $string['pathshead'] = 'Bekreft stier';
|
||||
$string['pathsrodataroot'] = 'Dataroot katalog er ikke skrivbar.';
|
||||
$string['pathsroparentdataroot'] = 'Overordnet katalog ({$a->parent}) er ikke skrivbar. Datakatalogen ({$a->dataroot}) kan ikke opprettes av installasjonsprogrammet.';
|
||||
$string['pathssubadmindir'] = 'Noen ganske få webhoteller bruker /admin som en egen url for å få tilgang til et kontrollpanel. Dessverre kommer det i konflikt med standard lokalisering av Moodle sine admin-sider. Du kan fikse dette ved å endre navn på admin-mappen og deretter oppgi dette navnet her. F.eks. <em>moodleadmin</em>. Dette vil fikse adminlenkene i Moodle.';
|
||||
$string['pathssubdataroot'] = 'Du trenger et sted hvor Moodle kan lagre opplastede filer. Denne mappen må være med lese og skriverettigheter for webserver-brukeren (veldig ofte \'nobody\' eller \'apache\'), men denne mappen må IKKE være direkte tilgjengelig via web. Installasjonsprogrammet vil forsøke å opprette den om den ikke finnes fra før.';
|
||||
$string['pathssubdataroot'] = '<p>En mappe der Moodle vil lagre alle filer lastet opp av brukerne.</p>
|
||||
<p>Denne mappen må være med lese og skriverettigheter for webserver-brukeren (vanligvis \'www-data\', \'nobody\' eller \'apache\').</p>
|
||||
<p>Denne mappen må IKKE være direkte tilgjengelig via web.</p> <p>Installasjonsprogrammet vil forsøke å opprette den om den ikke finnes fra før.</p>';
|
||||
$string['pathssubdirroot'] = '<p>Full mappesti til moodleinstallasjonen.</p>';
|
||||
$string['pathssubwwwroot'] = '<p>Full webadresse til der hvor Moodle skal vises, altså den addressen som brukere skriver inn i adresselinjen i nettlseren sin.</p>
|
||||
<p>Det er ikke mulig å bruke Moodle med mer enn en adresse. Dersom portalen din har flere webadresser bør du oppgi den enkleste av de her, og bruke videresending for hver av de andre adressene.</p>
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['cannotcreatedboninstall'] = '<p>Impossible de crear la banca de donadas.</p>
|
||||
<p>La banca de donadas indicada existís pas e l\'utilizaire especificat a pas las autorizacions que permeton de crear una banca de donadas.</p>.
|
||||
<p>L\'administrator del site deu repassar la configuracion de la banca de donadas.</p>';
|
||||
$string['cannotcreatedboninstall'] = '<p>Impossible de crear la basa de donadas.</p>
|
||||
<p>La banca de donadas indicada existís pas e l\'utilizaire especificat a pas las autorizacions que permeton de crear una basa de donadas.</p>.
|
||||
<p>L\'administrator del site deu repassar la configuracion de la basa de donadas.</p>';
|
||||
$string['cannotcreatelangdir'] = 'Creacion del dorsièr lang impossible';
|
||||
$string['cannotcreatetempdir'] = 'Creacion del dorsièr temp impossibla';
|
||||
$string['cannotdownloadcomponents'] = 'Telecargament dels components impossible';
|
||||
@@ -42,12 +42,12 @@ $string['cannotsavemd5file'] = 'Enregistrament del fichièr md5 impossible';
|
||||
$string['cannotsavezipfile'] = 'Enregistrament del fichièr ZIP impossible';
|
||||
$string['cannotunzipfile'] = 'Descompression del fichièr ZIP impossibla';
|
||||
$string['componentisuptodate'] = 'Lo component es a jorn';
|
||||
$string['dmlexceptiononinstall'] = '<p>Una error de banca de donadas s\'es producha [{$a->errorcode}].<br />{$a->debuginfo}</p>';
|
||||
$string['dmlexceptiononinstall'] = '<p>Una error de basa de donadas s\'es produita [{$a->errorcode}].<br />{$a->debuginfo}</p>';
|
||||
$string['downloadedfilecheckfailed'] = 'La verificacion del fichièr telecargat a fracassat';
|
||||
$string['invalidmd5'] = 'Lo còde de contraròtle md5 es pas valid';
|
||||
$string['invalidmd5'] = 'Lo còdi de contraròtle md5 es pas valid';
|
||||
$string['missingrequiredfield'] = 'Un camp obligatòri es pas completat';
|
||||
$string['remotedownloaderror'] = '<p>Lo telecargament del component sus vòstre servidor a fracassat. Verificatz los reglatges de proxy. L\'extension cURL de PHP es bravament recomandada.</p>
|
||||
<p>Vos cal telecargar manualament lo fichièr <a href="{$a->url}">{$a->url}</a>, lo copiar sus vòstre servidor a l\'emplaçament « {$a->dest} » e lo descompressar a aqueste endrech.</p>';
|
||||
<p>Vos cal telecargar manualament lo fichièr <a href="{$a->url}">{$a->url}</a>, lo copiar sus vòstre servidor a l\'emplaçament « {$a->dest} » e lo descompressar a aqueste endreit.</p>';
|
||||
$string['wrongdestpath'] = 'Camin de destinacion incorrècte';
|
||||
$string['wrongsourcebase'] = 'Adreça URL de basa de la font incorrècta';
|
||||
$string['wrongzipfilename'] = 'Nom de fichièr ZIP incorrècte';
|
||||
|
||||
@@ -54,7 +54,7 @@ $string['paths'] = 'Caminhos';
|
||||
$string['pathserrcreatedataroot'] = 'O programa de instalação não conseguiu criar a pasta de dados <b>{$a->dataroot}</b>.';
|
||||
$string['pathshead'] = 'Confirmar caminhos';
|
||||
$string['pathsrodataroot'] = 'A pasta de dados não tem permissões de escrita.';
|
||||
$string['pathsroparentdataroot'] = 'A pasta pai <b>{$a->parent}</b> não tem permissões de escrita. O programa de instalação não conseguiu criar a pasta <b>{$a->dataroot}</b>.';
|
||||
$string['pathsroparentdataroot'] = 'A pasta ascendente <b>{$a->parent}</b> não tem permissões de escrita. O programa de instalação não conseguiu criar a pasta <b>{$a->dataroot}</b>.';
|
||||
$string['pathssubadmindir'] = 'Alguns servidores Web utilizam a pasta <strong>admin</strong> em URLs especiais de acesso a funcionalidades especiais, como é o caso de painéis de controlo. Algumas situações podem criar conflitos com a localização normal das páginas de administração do Moodle. Estes problemas podem ser resolvidos renomeando a pasta <strong>admin</strong> na instalação do Moodle e indicando aqui o novo nome a utilizar. Por exemplo:<br /><br /><b>moodleadmin</b><br /><br />Esta ação resolverá os problemas de acesso das hiperligações para as funcionalidades de administração do Moodle.';
|
||||
$string['pathssubdataroot'] = '<p>Uma diretoria em que o Moodle irá armazenar todo o conteúdo de ficheiros enviados pelos utilizadores.</p>
|
||||
<p>Esta diretoria deve ser legível e gravável pelo utilizador do servidor web (geralmente \'www-data\', \'nobody\', ou \'apache\').</p>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['language'] = 'Idioma';
|
||||
$string['moodlelogo'] = 'Logotipo Moodle';
|
||||
$string['moodlelogo'] = 'Logótipo Moodle';
|
||||
$string['next'] = 'Seguinte';
|
||||
$string['previous'] = 'Anterior';
|
||||
$string['reload'] = 'Recarregar';
|
||||
|
||||
@@ -34,7 +34,7 @@ $string['clianswerno'] = 'n';
|
||||
$string['cliansweryes'] = 's';
|
||||
$string['cliincorrectvalueerror'] = 'Erro, valor incorreto "{$a->value}" para "{$a->option}"';
|
||||
$string['cliincorrectvalueretry'] = 'Valor incorreto, por favor tente novamente';
|
||||
$string['clitypevalue'] = 'Digite o valor';
|
||||
$string['clitypevalue'] = 'digite o valor';
|
||||
$string['clitypevaluedefault'] = 'digite o valor, pressione Enter para utilizar o valor padrão ({$a})';
|
||||
$string['cliunknowoption'] = 'Opções não reconhecidas:
|
||||
{$a}
|
||||
|
||||
@@ -64,5 +64,6 @@ $string['phpversionhelp'] = '<p>Moodle necesită o versiune PHP de cel puțin 4
|
||||
<p>Trebuie să upgradați PHP sau să îl mutați pe o gazdă cu o nouă versiune de PHP!<br />
|
||||
(În cazul 5.0.x puteți, de asemenea, să downgradați la versiunea 4.4.x)</p>';
|
||||
$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
|
||||
$string['welcomep20'] = 'Vedeți această pagină deoarece ați instalat și lansat cu succes pachetul <strong>{$a->packname} {$a->packversion}</strong> în computerul dumneavoastră. Felicitări!';
|
||||
$string['welcomep40'] = 'Pachetul include și <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
|
||||
$string['wwwroot'] = 'Adresă Web';
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['language'] = 'Язык';
|
||||
$string['moodlelogo'] = 'Логотип Moodle';
|
||||
$string['next'] = 'Далее';
|
||||
$string['previous'] = 'Назад';
|
||||
$string['reload'] = 'Обновить';
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['language'] = 'Språk';
|
||||
$string['moodlelogo'] = 'Moodie-logotyp';
|
||||
$string['next'] = 'Nästa';
|
||||
$string['previous'] = 'Tidigare';
|
||||
$string['reload'] = 'Uppdatera';
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['language'] = 'Мова інтерфейсу';
|
||||
$string['moodlelogo'] = 'Логотип Moodle';
|
||||
$string['next'] = 'Далі';
|
||||
$string['previous'] = 'Назад';
|
||||
$string['reload'] = 'Оновити';
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['cannotcreatedboninstall'] = '<p>无法建立数据库</p>
|
||||
<p>指定数据库不存在。使用者没有权限建立数据库</p>
|
||||
<p>网站管理员需查明数据库状态.</p>';
|
||||
$string['cannotcreatelangdir'] = '无法创建 lang 目录。';
|
||||
$string['cannotcreatetempdir'] = '无法创建 temp 目录。';
|
||||
$string['cannotdownloadcomponents'] = '无法下载组件';
|
||||
|
||||
@@ -4450,6 +4450,7 @@ function hash_internal_user_password($password, $fasthash = false) {
|
||||
*
|
||||
* Updating the password will modify the $user object and the database
|
||||
* record to use the current hashing algorithm.
|
||||
* It will remove Web Services user tokens too.
|
||||
*
|
||||
* @param stdClass $user User object (password property may be updated).
|
||||
* @param string $password Plain text password.
|
||||
@@ -4499,6 +4500,10 @@ function update_internal_user_password($user, $password, $fasthash = false) {
|
||||
// Trigger event.
|
||||
$user = $DB->get_record('user', array('id' => $user->id));
|
||||
\core\event\user_password_updated::create_from_user($user)->trigger();
|
||||
|
||||
// Remove WS user tokens.
|
||||
require_once($CFG->dirroot.'/webservice/lib.php');
|
||||
webservice::delete_user_ws_tokens($user->id);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -85,11 +85,15 @@ class moodle_phpmailer extends PHPMailer {
|
||||
public function encodeHeader($str, $position = 'text') {
|
||||
$encoded = core_text::encode_mimeheader($str, $this->CharSet);
|
||||
if ($encoded !== false) {
|
||||
$encoded = str_replace("\n", $this->LE, $encoded);
|
||||
if ($position === 'phrase') {
|
||||
return ("\"$encoded\"");
|
||||
// Escape special symbols in each line in the encoded string, join back together and enclose in quotes.
|
||||
$chunks = preg_split("/\\n/", $encoded);
|
||||
$chunks = array_map(function($chunk) {
|
||||
return addcslashes($chunk, "\0..\37\177\\\"");
|
||||
}, $chunks);
|
||||
return '"' . join($this->LE, $chunks) . '"';
|
||||
}
|
||||
return $encoded;
|
||||
return str_replace("\n", $this->LE, $encoded);
|
||||
}
|
||||
|
||||
return parent::encodeHeader($str, $position);
|
||||
|
||||
+32
-1
@@ -295,10 +295,41 @@ class core_text_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Tests the static encode_mimeheader method.
|
||||
* This also tests method moodle_phpmailer::encodeHeader that calls core_text::encode_mimeheader
|
||||
*/
|
||||
public function test_encode_mimeheader() {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir.'/phpmailer/moodle_phpmailer.php');
|
||||
$mailer = new moodle_phpmailer();
|
||||
|
||||
// Encode short string with non-latin characters.
|
||||
$str = "Žluťoučký koníček";
|
||||
$this->assertSame('=?utf-8?B?xb1sdcWlb3XEjWvDvSBrb27DrcSNZWs=?=', core_text::encode_mimeheader($str));
|
||||
$encodedstr = '=?utf-8?B?xb1sdcWlb3XEjWvDvSBrb27DrcSNZWs=?=';
|
||||
$this->assertSame($encodedstr, core_text::encode_mimeheader($str));
|
||||
$this->assertSame($encodedstr, $mailer->encodeHeader($str));
|
||||
$this->assertSame('"' . $encodedstr . '"', $mailer->encodeHeader($str, 'phrase'));
|
||||
|
||||
// Encode short string without non-latin characters. Make sure the quotes are escaped in quoted email headers.
|
||||
$latinstr = 'text"with quotes';
|
||||
$this->assertSame($latinstr, core_text::encode_mimeheader($latinstr));
|
||||
$this->assertSame($latinstr, $mailer->encodeHeader($latinstr));
|
||||
$this->assertSame('"text\\"with quotes"', $mailer->encodeHeader($latinstr, 'phrase'));
|
||||
|
||||
// Encode long string without non-latin characters.
|
||||
$longlatinstr = 'This is a very long text that still should not be split into several lines in the email headers because '.
|
||||
'it does not have any non-latin characters. The "quotes" and \\backslashes should be escaped only if it\'s a part of email address';
|
||||
$this->assertSame($longlatinstr, core_text::encode_mimeheader($longlatinstr));
|
||||
$this->assertSame($longlatinstr, $mailer->encodeHeader($longlatinstr));
|
||||
$longlatinstrwithslash = preg_replace(['/\\\\/', "/\"/"], ['\\\\\\', '\\"'], $longlatinstr);
|
||||
$this->assertSame('"' . $longlatinstrwithslash . '"', $mailer->encodeHeader($longlatinstr, 'phrase'));
|
||||
|
||||
// Encode long string with non-latin characters.
|
||||
$longstr = "Неопознанная ошибка в файле C:\\tmp\\: \"Не пользуйтесь виндоуз\"";
|
||||
$encodedlongstr = "=?utf-8?B?0J3QtdC+0L/QvtC30L3QsNC90L3QsNGPINC+0YjQuNCx0LrQsCDQsiDRhNCw?=
|
||||
=?utf-8?B?0LnQu9C1IEM6XHRtcFw6ICLQndC1INC/0L7Qu9GM0LfRg9C50YLQtdGB?=
|
||||
=?utf-8?B?0Ywg0LLQuNC90LTQvtGD0Lci?=";
|
||||
$this->assertSame($encodedlongstr, $mailer->encodeHeader($longstr));
|
||||
$this->assertSame('"' . $encodedlongstr . '"', $mailer->encodeHeader($longstr, 'phrase'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,14 @@
|
||||
*
|
||||
* Finds the user and calls the appropriate routine for their authentication type.
|
||||
*
|
||||
* There are several pathways to/through this page, summarised below:
|
||||
* 1. User clicks the 'forgotten your username or password?' link on the login page.
|
||||
* - No token is received, render the username/email search form.
|
||||
* 2. User clicks the link in the forgot password email
|
||||
* - Token received as GET param, store the token in session, redirect to self
|
||||
* 3. Redirected from (2)
|
||||
* - Fetch token from session, and continue to run the reset routine defined in 'core_login_process_password_set()'.
|
||||
*
|
||||
* @package core
|
||||
* @subpackage auth
|
||||
* @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
|
||||
@@ -59,12 +67,27 @@ if (isloggedin() and !isguestuser()) {
|
||||
redirect($CFG->wwwroot.'/index.php', get_string('loginalready'), 5);
|
||||
}
|
||||
|
||||
// Fetch the token from the session, if present, and unset the session var immediately.
|
||||
$tokeninsession = false;
|
||||
if (!empty($SESSION->password_reset_token)) {
|
||||
$token = $SESSION->password_reset_token;
|
||||
unset($SESSION->password_reset_token);
|
||||
$tokeninsession = true;
|
||||
}
|
||||
|
||||
if (empty($token)) {
|
||||
// This is a new password reset request.
|
||||
// Process the request; identify the user & send confirmation email.
|
||||
core_login_process_password_reset_request();
|
||||
} else {
|
||||
// User clicked on confirmation link in email message
|
||||
// validate the token & set new password
|
||||
core_login_process_password_set($token);
|
||||
// A token has been found, but not in the session, and not from a form post.
|
||||
// This must be the user following the original rest link, so store the reset token in the session and redirect to self.
|
||||
// The session var is intentionally used only during the lifespan of one request (the redirect) and is unset above.
|
||||
if (!$tokeninsession && $_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
$SESSION->password_reset_token = $token;
|
||||
redirect($CFG->wwwroot . '/login/forgot_password.php');
|
||||
} else {
|
||||
// Continue with the password reset process.
|
||||
core_login_process_password_set($token);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -224,7 +224,7 @@ class rating implements renderable {
|
||||
|
||||
// Only display aggregate if aggregation method isn't COUNT.
|
||||
$aggregatestr = '';
|
||||
if ($aggregate && $method != RATING_AGGREGATE_COUNT) {
|
||||
if (is_numeric($aggregate) && $method != RATING_AGGREGATE_COUNT) {
|
||||
if ($method != RATING_AGGREGATE_SUM && !$this->settings->scale->isnumeric) {
|
||||
|
||||
// Round aggregate as we're using it as an index.
|
||||
|
||||
@@ -272,6 +272,97 @@ class core_rating_testcase extends advanced_testcase {
|
||||
$this->assertNull($result[0]->rating->rating);
|
||||
$this->assertEquals($result[0]->rating->aggregate, 3); // Should still get the aggregate.
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for get_aggregate_string tests.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_aggregate_string_provider() {
|
||||
return [
|
||||
'Non-numeric aggregate produces empty string' => [
|
||||
RATING_AGGREGATE_NONE,
|
||||
'string',
|
||||
null,
|
||||
['Foo', 'Bar'],
|
||||
'',
|
||||
],
|
||||
'Aggregate count produces empty string' => [
|
||||
RATING_AGGREGATE_COUNT,
|
||||
0,
|
||||
null,
|
||||
['Foo', 'Bar'],
|
||||
'',
|
||||
],
|
||||
'Numeric SUM with non-numeric scale produces returns original value' => [
|
||||
RATING_AGGREGATE_SUM,
|
||||
10,
|
||||
false,
|
||||
['Foo', 'Bar'],
|
||||
'10',
|
||||
],
|
||||
'Numeric SUM with non-numeric scale produces returns rounded value' => [
|
||||
RATING_AGGREGATE_SUM,
|
||||
10.45,
|
||||
false,
|
||||
['Foo', 'Bar'],
|
||||
'10.5',
|
||||
],
|
||||
'Numeric SUM with numeric scale produces returns rounded value' => [
|
||||
RATING_AGGREGATE_SUM,
|
||||
10.45,
|
||||
true,
|
||||
['Foo', 'Bar'],
|
||||
'10.5',
|
||||
],
|
||||
'Numeric AVERAGE with numeric scale produces returns rounded value' => [
|
||||
RATING_AGGREGATE_AVERAGE,
|
||||
10.45,
|
||||
true,
|
||||
['Foo', 'Bar'],
|
||||
'10.5',
|
||||
],
|
||||
'Numeric AVERAGE with non-numeric scale produces returns indexed value (0)' => [
|
||||
RATING_AGGREGATE_AVERAGE,
|
||||
0,
|
||||
false,
|
||||
['Foo', 'Bar'],
|
||||
'Foo',
|
||||
],
|
||||
'Numeric AVERAGE with non-numeric scale produces returns indexed value (1)' => [
|
||||
RATING_AGGREGATE_AVERAGE,
|
||||
1,
|
||||
false,
|
||||
['Foo', 'Bar'],
|
||||
'Bar',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the value returned by get_aggregate_string().
|
||||
*
|
||||
* @dataProvider get_aggregate_string_provider
|
||||
*/
|
||||
public function test_get_aggregate_string($method, $aggregate, $isnumeric, $scaleitems, $expectation) {
|
||||
$options = new stdClass();
|
||||
$options->aggregate = $aggregate;
|
||||
$options->context = null;
|
||||
$options->component = null;
|
||||
$options->ratingarea = null;
|
||||
$options->itemid = null;
|
||||
$options->scaleid = null;
|
||||
$options->userid = null;
|
||||
|
||||
$options->settings = new stdClass();
|
||||
$options->settings->aggregationmethod = $method;
|
||||
$options->settings->scale = new stdClass();
|
||||
$options->settings->scale->isnumeric = $isnumeric;
|
||||
$options->settings->scale->scaleitems = $scaleitems;
|
||||
|
||||
$rating = new rating($options);
|
||||
$this->assertEquals($expectation, $rating->get_aggregate_string());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -29,11 +29,11 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2015051106.00; // 20150511 = branching date YYYYMMDD - do not modify!
|
||||
$version = 2015051108.00; // 20150511 = branching date YYYYMMDD - do not modify!
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
|
||||
$release = '2.9.6 (Build: 20160509)'; // Human-friendly version name
|
||||
$release = '2.9.8 (Build: 20160912)'; // Human-friendly version name
|
||||
|
||||
$branch = '29'; // This version's branch.
|
||||
$maturity = MATURITY_STABLE; // This version's maturity level.
|
||||
|
||||
@@ -421,6 +421,16 @@ class webservice {
|
||||
$DB->delete_records('external_tokens', array('id'=>$tokenid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all the tokens belonging to a user.
|
||||
*
|
||||
* @param int $userid the user id whose tokens must be deleted
|
||||
*/
|
||||
public static function delete_user_ws_tokens($userid) {
|
||||
global $DB;
|
||||
$DB->delete_records('external_tokens', array('userid' => $userid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a service
|
||||
* Also delete function references and authorised user references.
|
||||
|
||||
Reference in New Issue
Block a user