Merge branch 'MDL-67853-master' of https://github.com/crazyserver/moodle

This commit is contained in:
Ilya Tregubov 2022-01-27 16:41:19 +02:00
commit 57fe1a3099
62 changed files with 1175 additions and 757 deletions

View File

@ -48,69 +48,52 @@ if (($form = data_submitted()) && confirm_sesskey()) {
foreach ($providers as $provider) {
$componentproviderbase = $provider->component.'_'.$provider->name;
$disableprovidersetting = $componentproviderbase.'_disable';
$providerdisabled = false;
if (!isset($form->$disableprovidersetting)) {
$providerdisabled = true;
$newpreferences[$disableprovidersetting] = 1;
} else {
$newpreferences[$disableprovidersetting] = 0;
}
foreach (array('permitted', 'loggedin', 'loggedoff') as $setting) {
$value = null;
$componentprovidersetting = $componentproviderbase.'_'.$setting;
if ($setting == 'permitted') {
// If we deal with permitted select element, we need to create individual
// setting for each possible processor. Note that this block will
// always be processed first after entring parental foreach iteration
// so we can change form values on this stage.
foreach ($processors as $processor) {
$value = '';
if (isset($form->{$componentprovidersetting}[$processor->name])) {
$value = $form->{$componentprovidersetting}[$processor->name];
}
// Ensure that loggedin loggedoff options are set correctly for this permission.
if (($value == 'disallowed') || $providerdisabled) {
// It might be better to unset them, but I can't figure out why that cause error.
$form->{$componentproviderbase.'_loggedin'}[$processor->name] = 0;
$form->{$componentproviderbase.'_loggedoff'}[$processor->name] = 0;
} else if ($value == 'forced') {
$form->{$componentproviderbase.'_loggedin'}[$processor->name] = 1;
$form->{$componentproviderbase.'_loggedoff'}[$processor->name] = 1;
}
// Record the site preference.
$newpreferences[$processor->name.'_provider_'.$componentprovidersetting] = $value;
}
} else {
$newsettings = array();
if (property_exists($form, $componentprovidersetting)) {
// We must be processing loggedin or loggedoff checkboxes.
// Store defained comma-separated processors as setting value.
// Using array_filter eliminates elements set to 0 above.
$newsettings = array_keys(array_filter($form->{$componentprovidersetting}));
}
// Let's join existing setting values for disabled processors.
$property = 'message_provider_'.$componentprovidersetting;
if (property_exists($preferences, $property)) {
$existingsetting = $preferences->$property;
foreach ($disabledprocessors as $disable) {
if (strpos($existingsetting, $disable->name) > -1) {
$newsettings[] = $disable->name;
}
}
}
$value = join(',', $newsettings);
if (empty($value)) {
$value = null;
$componentprovidersetting = $componentproviderbase.'_locked';
foreach ($processors as $processor) {
$value = 0;
if (isset($form->{$componentprovidersetting}[$processor->name])) {
$value = $form->{$componentprovidersetting}[$processor->name];
if ($value == 'on') {
$value = 1;
}
}
if ($setting != 'permitted') {
// We have already recoded site preferences for 'permitted' type.
$newpreferences['message_provider_'.$componentprovidersetting] = $value;
// Record the site preference.
$newpreferences[$processor->name.'_provider_'.$componentprovidersetting] = $value;
}
$componentprovidersetting = $componentproviderbase.'_enabled';
$newsettings = [];
if (isset($form->$componentprovidersetting)) {
// Store defined comma-separated processors as setting value.
// Using array_filter eliminates elements set to 0 above.
$newsettings = array_keys(array_filter($form->{$componentprovidersetting}));
}
// Let's join existing setting values for disabled processors.
$property = 'message_provider_'.$componentprovidersetting;
if (property_exists($preferences, $property)) {
$existingsetting = $preferences->$property;
foreach ($disabledprocessors as $disable) {
if (strpos($existingsetting, $disable->name) > -1) {
$newsettings[] = $disable->name;
}
}
}
$value = join(',', $newsettings);
if (empty($value)) {
$value = null;
}
// Record the site preference.
$newpreferences['message_provider_'.$componentprovidersetting] = $value;
}
// Update database.
@ -142,8 +125,6 @@ if (($form = data_submitted()) && confirm_sesskey()) {
// Page settings
$PAGE->set_context(context_system::instance());
$PAGE->requires->js_init_call('M.core_message.init_defaultoutputs');
$renderer = $PAGE->get_renderer('core', 'message');
// Display the page.

View File

@ -28,8 +28,8 @@ $messageproviders = [
// Notify Data Protection Officer about incoming data requests.
'contactdataprotectionofficer' => [
'defaults' => [
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
],
'capability' => 'tool/dataprivacy:managedatarequests'
],
@ -37,15 +37,15 @@ $messageproviders = [
// Notify user about the processing results of their data request.
'datarequestprocessingresults' => [
'defaults' => [
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
]
],
// Notify Data Protection Officer about exceptions.
'notifyexceptions' => [
'defaults' => [
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
],
'capability' => 'tool/dataprivacy:managedatarequests'
],

View File

@ -107,7 +107,7 @@ class tool_mobile_api_testcase extends externallib_advanced_testcase {
set_config('allowedemaildomains', 'example.com');
$DB->set_field_select('message_processors', 'enabled', 0, "name <> 'email'");
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user2);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'email', $user2);
// Extra content for all types of messages.
$message = new \core\message\message();

View File

@ -103,7 +103,7 @@ Feature: tool_monitor_subscriptions
Given I log in as "admin"
And I follow "Preferences" in the user menu
And I click on "Notification preferences" "link" in the "#page-content" "css_element"
And I click on "//td[@data-processor-name='popup']//label[@data-state='loggedin']" "xpath_element" in the "Notifications of rule subscriptions" "table_row"
And I click on "//td[@data-processor-name='popup']//div[@class='preference-state']" "xpath_element" in the "Notifications of rule subscriptions" "table_row"
And I wait until the page is ready
And I follow "Preferences" in the user menu
And I follow "Event monitoring"
@ -124,7 +124,7 @@ Feature: tool_monitor_subscriptions
Given I log in as "teacher1"
And I follow "Preferences" in the user menu
And I click on "Notification preferences" "link" in the "#page-content" "css_element"
And I click on "//td[@data-processor-name='popup']//label[@data-state='loggedin']" "xpath_element" in the "Notifications of rule subscriptions" "table_row"
And I click on "//td[@data-processor-name='popup']//div[@class='preference-state']" "xpath_element" in the "Notifications of rule subscriptions" "table_row"
And I wait until the page is ready
And I follow "Preferences" in the user menu
And I follow "Event monitoring"

View File

@ -1301,7 +1301,41 @@ abstract class restore_dbops {
$preference = (object)$preference;
// Prepare the record and insert it
$preference->userid = $newuserid;
$status = $DB->insert_record('user_preferences', $preference);
// Translate _loggedin / _loggedoff message user preferences to _enabled. (MDL-67853)
// This code cannot be removed.
if (preg_match('/message_provider_.*/', $preference->name)) {
$nameparts = explode('_', $preference->name);
$name = array_pop($nameparts);
if ($name == 'loggedin' || $name == 'loggedoff') {
$preference->name = implode('_', $nameparts).'_enabled';
$existingpreference = $DB->get_record('user_preferences',
['name' => $preference->name , 'userid' => $newuserid]);
// Merge both values.
if ($existingpreference) {
$values = [];
if (!empty($existingpreference->value) && $existingpreference->value != 'none') {
$values = explode(',', $existingpreference->value);
}
if (!empty($preference->value) && $preference->value != 'none') {
$values = array_merge(explode(',', $preference->value), $values);
$values = array_unique($values);
}
$existingpreference->value = empty($values) ? 'none' : implode(',', $values);
$DB->update_record('user_preferences', $existingpreference);
continue;
}
}
}
// End translating loggedin / loggedoff message user preferences.
$DB->insert_record('user_preferences', $preference);
}
}
// Special handling for htmleditor which was converted to a preference.
@ -1311,7 +1345,7 @@ abstract class restore_dbops {
$preference->userid = $newuserid;
$preference->name = 'htmleditor';
$preference->value = 'textarea';
$status = $DB->insert_record('user_preferences', $preference);
$DB->insert_record('user_preferences', $preference);
}
}

View File

@ -305,7 +305,7 @@ class badgeslib_test extends advanced_testcase {
$sink = $this->redirectMessages();
$DB->set_field_select('message_processors', 'enabled', 0, "name <> 'email'");
set_user_preference('message_provider_moodle_badgerecipientnotice_loggedoff', 'email', $user1);
set_user_preference('message_provider_moodle_badgerecipientnotice_enabled', 'email', $user1);
$badge->issue($user1->id, false);
$this->assertDebuggingCalled(); // Expect debugging while baking a badge via phpunit.

View File

@ -82,3 +82,10 @@ navmethod,core_grades
dropdown,core_grades
tabs,core_grades
combo,core_grades
defaults,core_message
loggedin_help,core_message
loggedindescription,core_message
loggedoff_help,core_message
loggedoffdescription,core_message
sendingvia,core_message
sendingviawhen,core_message

View File

@ -51,7 +51,6 @@ $string['contacts'] = 'Contacts';
$string['conversationactions'] = 'Conversation actions menu';
$string['decline'] = 'Decline';
$string['defaultmessageoutputs'] = 'Notification settings';
$string['defaults'] = 'Defaults';
$string['deleteallconfirm'] = "Are you sure you would like to delete this entire conversation? This will not delete it for other conversation participants.";
$string['deleteallmessages'] = "Delete all messages";
$string['deleteallselfconfirm'] = "Are you sure you would like to delete this entire personal conversation?";
@ -93,11 +92,7 @@ $string['info'] = 'User info';
$string['isnotinyourcontacts'] = '{$a} is not in your contacts';
$string['loadmore'] = 'Load more';
$string['loggedin'] = 'Online';
$string['loggedin_help'] = 'Configure how you would like to receive notifications when you are logged into Moodle';
$string['loggedindescription'] = 'When you are logged into Moodle';
$string['loggedoff'] = 'Offline';
$string['loggedoff_help'] = 'Configure how you would like to receive notifications when you are not logged into Moodle';
$string['loggedoffdescription'] = 'When you are not logged into Moodle';
$string['managemessageoutputs'] = 'Default notification preferences';
$string['messageoutputs'] = 'Notification plugins';
$string['messagepreferences'] = 'Message preferences';
@ -213,6 +208,9 @@ $string['privacy:metadata:preference:core_message_settings'] = 'Settings related
$string['privacy:request:preference:set'] = 'The value of the setting \'{$a->name}\' was \'{$a->value}\'';
$string['privacy:export:conversationprefix'] = 'Conversation: ';
$string['processorsettings'] = 'Processor settings';
$string['providerenabled'] = 'Sending "{$a}" enabled status';
$string['providerprocesorislocked'] = '"{$a->provider}" on "{$a->processor}" is locked';
$string['providerprocesorisdisallowed'] = '"{$a->provider}" on "{$a->processor}" is disallowed';
$string['removecontact'] = 'Remove contact';
$string['removecontactconfirm'] = 'Are you sure you want to remove {$a} from your contacts?';
$string['removecoursefilter'] = 'Remove filter for course {$a}';
@ -231,9 +229,9 @@ $string['selfconversation'] = 'Personal space';
$string['selfconversationdefaultmessage'] = 'Save draft messages, links, notes etc. to access later.';
$string['send'] = 'Send';
$string['sender'] = '{$a}:';
$string['sendingvia'] = 'Sending "{$a->provider}" via "{$a->processor}"';
$string['sendingviawhen'] = 'Sending "{$a->provider}" via "{$a->processor}" when {$a->state}';
$string['sendcontactrequest'] = 'Send contact request';
$string['sendingviaenabled'] = 'Sending "{$a->provider}" via "{$a->processor}" enabled status';
$string['sendingvialocked'] = 'Sending "{$a->provider}" via "{$a->processor}" locked status';
$string['sendmessage'] = 'Send message';
$string['sendbulkmessage'] = 'Send message to {$a} people';
$string['sendbulkmessagesingle'] = 'Send message to 1 person';
@ -279,3 +277,12 @@ $string['yourcontactrequestpending'] = 'Your contact request is pending with {$a
// Deprecated since Moodle 3.9.
$string['messagecontactrequestsnotification'] = '{$a} is requesting to be added as a contact.';
$string['messagecontactrequestsnotificationsubject'] = 'Contact request from {$a}';
// Deprecated since Moodle 4.0.
$string['defaults'] = 'Defaults';
$string['loggedin_help'] = 'Configure how you would like to receive notifications when you are logged into Moodle';
$string['loggedindescription'] = 'When you are logged into Moodle';
$string['loggedoff_help'] = 'Configure how you would like to receive notifications when you are not logged into Moodle';
$string['loggedoffdescription'] = 'When you are not logged into Moodle';
$string['sendingvia'] = 'Sending "{$a->provider}" via "{$a->processor}"';
$string['sendingviawhen'] = 'Sending "{$a->provider}" via "{$a->processor}" when {$a->state}';

View File

@ -208,20 +208,6 @@ class manager {
return false;
}
// Set the online state.
if (isset($CFG->block_online_users_timetosee)) {
$timetoshowusers = $CFG->block_online_users_timetosee * 60;
} else {
$timetoshowusers = 300;
}
// Work out if the user is logged in or not.
$userstate = 'loggedoff';
if (!empty($localisedeventdata->userto->lastaccess)
&& (time() - $timetoshowusers) < $localisedeventdata->userto->lastaccess) {
$userstate = 'loggedin';
}
// Fill in the array of processors to be used based on default and user preferences.
// Do not process muted conversations.
$processorlist = [];
@ -233,23 +219,30 @@ class manager {
}
// First find out permissions.
$defaultpreference = $processor->name . '_provider_' . $preferencebase . '_permitted';
if (isset($defaultpreferences->{$defaultpreference})) {
$permitted = $defaultpreferences->{$defaultpreference};
$defaultlockedpreference = $processor->name . '_provider_' . $preferencebase . '_locked';
$locked = false;
if (isset($defaultpreferences->{$defaultlockedpreference})) {
$locked = $defaultpreferences->{$defaultlockedpreference};
} else {
// MDL-25114 They supplied an $eventdata->component $eventdata->name combination which doesn't
// exist in the message_provider table (thus there is no default settings for them).
$preferrormsg = "Could not load preference $defaultpreference. Make sure the component and name you supplied
to message_send() are valid.";
$preferrormsg = "Could not load preference $defaultlockedpreference.
Make sure the component and name you supplied to message_send() are valid.";
throw new coding_exception($preferrormsg);
}
$enabledpreference = 'message_provider_'.$preferencebase . '_enabled';
$forced = false;
if ($locked && isset($defaultpreferences->{$enabledpreference})) {
$forced = $defaultpreferences->{$enabledpreference};
}
// Find out if user has configured this output.
// Some processors cannot function without settings from the user.
$userisconfigured = $processor->object->is_user_configured($recipient);
// DEBUG: notify if we are forcing unconfigured output.
if ($permitted == 'forced' && !$userisconfigured) {
if ($forced && !$userisconfigured) {
debugging('Attempt to force message delivery to user who has "' . $processor->name .
'" output unconfigured', DEBUG_NORMAL);
}
@ -257,13 +250,13 @@ class manager {
// Populate the list of processors we will be using.
if (!$eventdata->notification && $processor->object->force_process_messages()) {
$processorlist[] = $processor->name;
} else if ($permitted == 'forced' && $userisconfigured) {
} else if ($forced && $userisconfigured) {
// An admin is forcing users to use this message processor. Use this processor unconditionally.
$processorlist[] = $processor->name;
} else if ($permitted == 'permitted' && $userisconfigured && !$recipient->emailstop) {
} else if (!$locked && $userisconfigured && !$recipient->emailstop) {
// User has not disabled notifications.
// See if user set any notification preferences, otherwise use site default ones.
$userpreferencename = 'message_provider_' . $preferencebase . '_' . $userstate;
$userpreferencename = 'message_provider_' . $preferencebase . '_enabled';
if ($userpreference = get_user_preferences($userpreferencename, null, $recipient)) {
if (in_array($processor->name, explode(',', $userpreference))) {
$processorlist[] = $processor->name;

View File

@ -37,8 +37,8 @@ $messageproviders = array (
'newlogin' => array (
'defaults' => array(
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
),
),
@ -56,15 +56,15 @@ $messageproviders = array (
'availableupdate' => array(
'capability' => 'moodle/site:config',
'defaults' => array(
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED
),
),
'instantmessage' => array (
'defaults' => array(
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDOFF,
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
),
),
@ -81,7 +81,7 @@ $messageproviders = array (
'courserequestapproved' => array (
'capability' => 'moodle/course:request',
'defaults' => array(
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
),
),
@ -89,28 +89,32 @@ $messageproviders = array (
'courserequestrejected' => array (
'capability' => 'moodle/course:request',
'defaults' => array(
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
),
),
// Course completed. Requires course completion configured at course level. It does not work with just activity progress.
'coursecompleted' => [],
'coursecompleted' => [
'defaults' => [
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
],
],
// Course content updated. New content (activities or resources) has been created or existing content updated.
'coursecontentupdated' => array (
'defaults' => array(
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDOFF,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
),
),
// Badge award notification to a badge recipient.
'badgerecipientnotice' => array (
'defaults' => array(
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDOFF,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
),
'capability' => 'moodle/badges:earnbadge'
),
@ -118,7 +122,7 @@ $messageproviders = array (
// Badge award notification to a badge creator (mostly cron-based).
'badgecreatornotice' => array (
'defaults' => array(
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDOFF,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
)
),
@ -131,9 +135,9 @@ $messageproviders = array (
// User insights.
'insights' => array (
'defaults' => [
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDOFF,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
]
),
@ -142,23 +146,23 @@ $messageproviders = array (
'defaults' => [
// We don't need to notify in the popup output here because the message drawer
// already notifies users of contact requests.
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDOFF,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
]
],
// Asyncronhous backup/restore notifications.
'asyncbackupnotification' => array(
'defaults' => array(
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDOFF,
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
)
),
'gradenotifications' => [
'defaults' => array(
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDOFF,
'popup' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
'email' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
),
],

View File

@ -3567,5 +3567,247 @@ privatefiles,moodle|/user/files.php';
upgrade_main_savepoint(true, 2022011100.01);
}
if ($oldversion < 2022012100.02) {
// Migrate default message output config.
$preferences = get_config('message');
$treatedprefs = [];
foreach ($preferences as $preference => $value) {
// Extract provider and preference name from the setting name.
// Example name: airnotifier_provider_enrol_imsenterprise_imsenterprise_enrolment_permitted
// Provider: airnotifier
// Preference: enrol_imsenterprise_imsenterprise_enrolment_permitted.
$providerparts = explode('_provider_', $preference);
if (count($providerparts) <= 1) {
continue;
}
$provider = $providerparts[0];
$preference = $providerparts[1];
// Extract and remove last part of the preference previously extracted: ie. permitted.
$parts = explode('_', $preference);
$key = array_pop($parts);
if (in_array($key, ['permitted', 'loggedin', 'loggedoff'])) {
if ($key == 'permitted') {
// We will use provider name instead of permitted.
$key = $provider;
} else {
// Logged in and logged off values are a csv of the enabled providers.
$value = explode(',', $value);
}
// Join the rest of the parts: ie enrol_imsenterprise_imsenterprise_enrolment.
$prefname = implode('_', $parts);
if (!isset($treatedprefs[$prefname])) {
$treatedprefs[$prefname] = [];
}
// Save the value with the selected key.
$treatedprefs[$prefname][$key] = $value;
}
}
// Now take every preference previous treated and its values.
foreach ($treatedprefs as $prefname => $values) {
$enabled = []; // List of providers enabled for each preference.
// Enable if one of those is enabled.
$loggedin = isset($values['loggedin']) ? $values['loggedin'] : [];
foreach ($loggedin as $provider) {
$enabled[$provider] = 1;
}
$loggedoff = isset($values['loggedoff']) ? $values['loggedoff'] : [];
foreach ($loggedoff as $provider) {
$enabled[$provider] = 1;
}
// Do not treat those values again.
unset($values['loggedin']);
unset($values['loggedoff']);
// Translate rest of values coming from permitted "key".
foreach ($values as $provider => $value) {
$locked = false;
switch ($value) {
case 'forced':
// Provider is enabled by force.
$enabled[$provider] = 1;
$locked = true;
break;
case 'disallowed':
// Provider is disabled by force.
unset($enabled[$provider]);
$locked = true;
break;
default:
// Provider is not forced (permitted) or invalid values.
}
// Save locked.
if ($locked) {
set_config($provider.'_provider_'.$prefname.'_locked', 1, 'message');
}
// Remove old value.
unset_config($provider.'_provider_'.$prefname.'_permitted', 'message');
}
// Save the new values.
$value = implode(',', array_keys($enabled));
set_config('message_provider_'.$prefname.'_enabled', $value, 'message');
// Remove old values.
unset_config('message_provider_'.$prefname.'_loggedin', 'message');
unset_config('message_provider_'.$prefname.'_loggedoff', 'message');
}
// Migrate user preferences. ie merging message_provider_moodle_instantmessage_loggedoff with
// message_provider_moodle_instantmessage_loggedin to message_provider_moodle_instantmessage_enabled.
$allrecordsloggedoff = $DB->sql_like('name', ':loggedoff');
$total = $DB->count_records_select(
'user_preferences',
$allrecordsloggedoff,
['loggedoff' => 'message_provider_%_loggedoff']
);
$i = 0;
if ($total == 0) {
$total = 1; // Avoid division by zero.
}
// Show a progress bar.
$pbar = new progress_bar('upgradeusernotificationpreferences', 500, true);
$pbar->update($i, $total, "Upgrading user notifications preferences - $i/$total.");
// We're migrating provider per provider to reduce memory usage.
$providers = $DB->get_records('message_providers', null, 'name');
foreach ($providers as $provider) {
// 60 minutes to migrate each provider.
upgrade_set_timeout(3600);
$componentproviderbase = 'message_provider_'.$provider->component.'_'.$provider->name;
$loggedinname = $componentproviderbase.'_loggedin';
$loggedoffname = $componentproviderbase.'_loggedoff';
// Change loggedin to enabled.
$enabledname = $componentproviderbase.'_enabled';
$DB->set_field('user_preferences', 'name', $enabledname, ['name' => $loggedinname]);
$selectparams = [
'enabled' => $enabledname,
'loggedoff' => $loggedoffname,
];
$sql = 'SELECT m1.id loggedoffid, m1.value as loggedoff, m2.value as enabled, m2.id as enabledid
FROM
(SELECT id, userid, value FROM {user_preferences} WHERE name = :loggedoff) m1
LEFT JOIN
(SELECT id, userid, value FROM {user_preferences} WHERE name = :enabled) m2
ON m1.userid = m2.userid';
while (($rs = $DB->get_recordset_sql($sql, $selectparams, 0, 1000)) && $rs->valid()) {
// 10 minutes for every chunk.
upgrade_set_timeout(600);
$deleterecords = [];
$changename = [];
$changevalue = []; // Multidimensional array with possible values as key to reduce SQL queries.
foreach ($rs as $record) {
if (empty($record->enabledid)) {
// Enabled does not exists, change the name.
$changename[] = $record->loggedoffid;
} else if ($record->enabledid != $record->loggedoff) {
// Exist and values differ (checked on SQL), update the enabled record.
if ($record->enabled != 'none' && !empty($record->enabled)) {
$enabledvalues = explode(',', $record->enabled);
} else {
$enabledvalues = [];
}
if ($record->loggedoff != 'none' && !empty($record->loggedoff)) {
$loggedoffvalues = explode(',', $record->loggedoff);
} else {
$loggedoffvalues = [];
}
$values = array_unique(array_merge($enabledvalues, $loggedoffvalues));
sort($values);
$newvalue = empty($values) ? 'none' : implode(',', $values);
if (!isset($changevalue[$newvalue])) {
$changevalue[$newvalue] = [];
}
$changevalue[$newvalue][] = $record->enabledid;
$deleterecords[] = $record->loggedoffid;
} else {
// They are the same, just delete loggedoff one.
$deleterecords[] = $record->loggedoffid;
}
$i++;
}
$rs->close();
// Commit the changes.
if (!empty($changename)) {
$changenameparams = [
'name' => $loggedoffname,
];
$changenameselect = 'name = :name AND id IN (' . implode(',', $changename) . ')';
$DB->set_field_select('user_preferences', 'name', $enabledname, $changenameselect, $changenameparams);
}
if (!empty($changevalue)) {
$changevalueparams = [
'name' => $enabledname,
];
foreach ($changevalue as $value => $ids) {
$changevalueselect = 'name = :name AND id IN (' . implode(',', $ids) . ')';
$DB->set_field_select('user_preferences', 'value', $value, $changevalueselect, $changevalueparams);
}
}
if (!empty($deleterecords)) {
$deleteparams = [
'name' => $loggedoffname,
];
$deleteselect = 'name = :name AND id IN (' . implode(',', $deleterecords) . ')';
$DB->delete_records_select('user_preferences', $deleteselect, $deleteparams);
}
// Update progress.
$pbar->update($i, $total, "Upgrading user notifications preferences - $i/$total.");
}
$rs->close();
// Delete the rest of loggedoff values (that are equal than enabled).
$deleteparams = [
'name' => $loggedoffname,
];
$deleteselect = 'name = :name';
$i += $DB->count_records_select('user_preferences', $deleteselect, $deleteparams);
$DB->delete_records_select('user_preferences', $deleteselect, $deleteparams);
// Update progress.
$pbar->update($i, $total, "Upgrading user notifications preferences - $i/$total.");
}
core_plugin_manager::reset_caches();
// Delete the orphan records.
$allrecordsparams = ['loggedin' => 'message_provider_%_loggedin', 'loggedoff' => 'message_provider_%_loggedoff'];
$allrecordsloggedin = $DB->sql_like('name', ':loggedin');
$allrecordsloggedinoffsql = "$allrecordsloggedin OR $allrecordsloggedoff";
$DB->delete_records_select('user_preferences', $allrecordsloggedinoffsql, $allrecordsparams);
// Update progress.
$pbar->update($total, $total, "Upgrading user notifications preferences - $total/$total.");
upgrade_main_savepoint(true, 2022012100.02);
}
return true;
}

View File

@ -241,20 +241,6 @@ function message_send(\core\message\message $eventdata) {
return false;
}
//after how long inactive should the user be considered logged off?
if (isset($CFG->block_online_users_timetosee)) {
$timetoshowusers = $CFG->block_online_users_timetosee * 60;
} else {
$timetoshowusers = 300;//5 minutes
}
// Work out if the user is logged in or not
if (!empty($eventdata->userto->lastaccess) && (time()-$timetoshowusers) < $eventdata->userto->lastaccess) {
$userstate = 'loggedin';
} else {
$userstate = 'loggedoff';
}
// Check if we are creating a notification or message.
$table = 'notifications';
@ -299,40 +285,47 @@ function message_send(\core\message\message $eventdata) {
}
// First find out permissions
$defaultpreference = $processor->name.'_provider_'.$preferencebase.'_permitted';
if (isset($defaultpreferences->{$defaultpreference})) {
$permitted = $defaultpreferences->{$defaultpreference};
$defaultlockedpreference = $processor->name . '_provider_' . $preferencebase . '_locked';
$locked = false;
if (isset($defaultpreferences->{$defaultlockedpreference})) {
$locked = $defaultpreferences->{$defaultlockedpreference};
} else {
// MDL-25114 They supplied an $eventdata->component $eventdata->name combination which doesn't
// exist in the message_provider table (thus there is no default settings for them).
$preferrormsg = "Could not load preference $defaultpreference. Make sure the component and name you supplied
$preferrormsg = "Could not load preference $defaultlockedpreference. Make sure the component and name you supplied
to message_send() are valid.";
throw new coding_exception($preferrormsg);
}
$preferencename = 'message_provider_'.$preferencebase.'_enabled';
$forced = false;
if ($locked && isset($defaultpreferences->{$preferencename})) {
$userpreference = $defaultpreferences->{$preferencename};
$forced = in_array($processor->name, explode(',', $userpreference));
}
// Find out if user has configured this output
// Some processors cannot function without settings from the user
$userisconfigured = $processor->object->is_user_configured($eventdata->userto);
// DEBUG: notify if we are forcing unconfigured output
if ($permitted == 'forced' && !$userisconfigured) {
if ($forced && !$userisconfigured) {
debugging('Attempt to force message delivery to user who has "'.$processor->name.'" output unconfigured', DEBUG_NORMAL);
}
// Populate the list of processors we will be using
if ($permitted == 'forced' && $userisconfigured) {
if ($forced && $userisconfigured) {
// An admin is forcing users to use this message processor. Use this processor unconditionally.
$processorlist[] = $processor->name;
} else if ($permitted == 'permitted' && $userisconfigured && !$eventdata->userto->emailstop) {
} else if (!$forced && !$locked && $userisconfigured && !$eventdata->userto->emailstop) {
// User has not disabled notifications
// See if user set any notification preferences, otherwise use site default ones
$userpreferencename = 'message_provider_'.$preferencebase.'_'.$userstate;
if ($userpreference = get_user_preferences($userpreferencename, null, $eventdata->userto)) {
if ($userpreference = get_user_preferences($preferencename, null, $eventdata->userto)) {
if (in_array($processor->name, explode(',', $userpreference))) {
$processorlist[] = $processor->name;
}
} else if (isset($defaultpreferences->{$userpreferencename})) {
if (in_array($processor->name, explode(',', $defaultpreferences->{$userpreferencename}))) {
} else if (isset($defaultpreferences->{$preferencename})) {
if (in_array($processor->name, explode(',', $defaultpreferences->{$preferencename}))) {
$processorlist[] = $processor->name;
}
}
@ -523,51 +516,37 @@ function message_set_default_message_preference($component, $messagename, $filep
// Setting default preference
$componentproviderbase = $component.'_'.$messagename;
$loggedinpref = array();
$loggedoffpref = array();
// set 'permitted' preference first for each messaging processor
$enabledpref = [];
// Set 'locked' preference first for each messaging processor.
foreach ($processors as $processor) {
$preferencename = $processor->name.'_provider_'.$componentproviderbase.'_permitted';
// if we do not have this setting yet, set it
$preferencename = $processor->name.'_provider_'.$componentproviderbase.'_locked';
// If we do not have this setting yet, set it.
if (!isset($defaultpreferences->{$preferencename})) {
// determine plugin default settings
// Determine plugin default settings.
$plugindefault = 0;
if (isset($fileprovider['defaults'][$processor->name])) {
$plugindefault = $fileprovider['defaults'][$processor->name];
}
// get string values of the settings
list($permitted, $loggedin, $loggedoff) = translate_message_default_setting($plugindefault, $processor->name);
// store default preferences for current processor
set_config($preferencename, $permitted, 'message');
// save loggedin/loggedoff settings
if ($loggedin) {
$loggedinpref[] = $processor->name;
}
if ($loggedoff) {
$loggedoffpref[] = $processor->name;
// Get string values of the settings.
list($locked, $enabled) = translate_message_default_setting($plugindefault, $processor->name);
// Store default preferences for current processor.
set_config($preferencename, $locked, 'message');
// Save enabled settings.
if ($enabled) {
$enabledpref[] = $processor->name;
}
}
}
// now set loggedin/loggedoff preferences
if (!empty($loggedinpref)) {
$preferencename = 'message_provider_'.$componentproviderbase.'_loggedin';
// Now set enabled preferences.
if (!empty($enabledpref)) {
$preferencename = 'message_provider_'.$componentproviderbase.'_enabled';
if (isset($defaultpreferences->{$preferencename})) {
// We have the default preferences for this message provider, which
// likely means that we have been adding a new processor. Add defaults
// to exisitng preferences.
$loggedinpref = array_merge($loggedinpref, explode(',', $defaultpreferences->{$preferencename}));
$enabledpref = array_merge($enabledpref, explode(',', $defaultpreferences->{$preferencename}));
}
set_config($preferencename, join(',', $loggedinpref), 'message');
}
if (!empty($loggedoffpref)) {
$preferencename = 'message_provider_'.$componentproviderbase.'_loggedoff';
if (isset($defaultpreferences->{$preferencename})) {
// We have the default preferences for this message provider, which
// likely means that we have been adding a new processor. Add defaults
// to exisitng preferences.
$loggedoffpref = array_merge($loggedoffpref, explode(',', $defaultpreferences->{$preferencename}));
}
set_config($preferencename, join(',', $loggedoffpref), 'message');
set_config($preferencename, join(',', $enabledpref), 'message');
}
}
@ -754,8 +733,8 @@ function message_processor_uninstall($name) {
$transaction = $DB->start_delegated_transaction();
$DB->delete_records('message_processors', array('name' => $name));
$DB->delete_records_select('config_plugins', "plugin = ?", array("message_{$name}"));
// delete permission preferences only, we do not care about loggedin/loggedoff
// defaults, they will be removed on the next attempt to update the preferences
// Delete permission preferences only, we do not care about enabled defaults,
// they will be removed on the next attempt to update the preferences.
$DB->delete_records_select('config_plugins', "plugin = 'message' AND ".$DB->sql_like('name', '?', false), array("{$name}_provider_%"));
$transaction->allow_commit();
// Purge all messaging settings from the caches. They are stored by plugin so we have to clear all message settings.

View File

@ -144,7 +144,7 @@ class core_message_testcase extends advanced_testcase {
$this->assertFileExists("$CFG->dirroot/message/output/popup/version.php");
$DB->set_field_select('message_processors', 'enabled', 0, "name <> 'email'");
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user2);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'email', $user2);
// Extra content for all types of messages.
$message = new \core\message\message();
@ -241,7 +241,7 @@ class core_message_testcase extends advanced_testcase {
$this->assertFileExists("$CFG->dirroot/message/output/popup/version.php");
$DB->set_field_select('message_processors', 'enabled', 0, "name <> 'email'");
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user2);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'email', $user2);
// Check that prefix is ammended to the subject of the email.
$message = new \core\message\message();

View File

@ -412,7 +412,7 @@ class core_messagelib_testcase extends advanced_testcase {
$eventsink = $this->redirectEvents();
// Will always use the pop-up processor.
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'none', $user2);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'none', $user2);
$message = new \core\message\message();
$message->courseid = 1;
@ -500,7 +500,7 @@ class core_messagelib_testcase extends advanced_testcase {
$eventsink->clear();
// Will always use the pop-up processor.
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user2);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'email', $user2);
$message = new \core\message\message();
$message->courseid = 1;
@ -533,7 +533,7 @@ class core_messagelib_testcase extends advanced_testcase {
$user2->emailstop = '0';
// Will always use the pop-up processor.
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user2);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'email', $user2);
$message = new \core\message\message();
$message->courseid = 1;
@ -566,7 +566,7 @@ class core_messagelib_testcase extends advanced_testcase {
$this->assertInstanceOf('\core\event\message_sent', $events[0]);
$eventsink->clear();
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email,popup', $user2);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'email,popup', $user2);
$message = new \core\message\message();
$message->courseid = 1;
@ -600,7 +600,7 @@ class core_messagelib_testcase extends advanced_testcase {
$this->assertInstanceOf('\core\event\message_sent', $events[0]);
$eventsink->clear();
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'popup', $user2);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'popup', $user2);
$message = new \core\message\message();
$message->courseid = 1;
@ -635,7 +635,7 @@ class core_messagelib_testcase extends advanced_testcase {
$transaction->allow_commit();
// Will always use the pop-up processor.
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'none', $user2);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'none', $user2);
$message = new \core\message\message();
$message->courseid = 1;
@ -668,7 +668,7 @@ class core_messagelib_testcase extends advanced_testcase {
$this->assertInstanceOf('\core\event\message_sent', $events[0]);
// Will always use the pop-up processor.
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user2);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'email', $user2);
$message = new \core\message\message();
$message->courseid = 1;
@ -783,7 +783,7 @@ class core_messagelib_testcase extends advanced_testcase {
// Ensure we're going to hit the email processor for this user.
$DB->set_field_select('message_processors', 'enabled', 0, "name <> 'email'");
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user2);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'email', $user2);
// Now, send a message and verify the message processors (in this case, email) are hit.
$sink = $this->redirectEmails();
@ -869,7 +869,7 @@ class core_messagelib_testcase extends advanced_testcase {
// Ensure we're going to hit the email processor for this user.
$DB->set_field_select('message_processors', 'enabled', 0, "name <> 'email'");
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user1);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'email', $user1);
// Now, send a message and verify the message processors are empty (self-conversations are not processed for now).
$sink = $this->redirectEmails();
@ -941,8 +941,8 @@ class core_messagelib_testcase extends advanced_testcase {
// Ensure the email processor is enabled for the recipient users.
$DB->set_field_select('message_processors', 'enabled', 0, "name <> 'email'");
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user2);
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user3);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'email', $user2);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'email', $user3);
// Now, send a message and verify the email processor are hit.
$messageid = message_send($message);
@ -1016,8 +1016,8 @@ class core_messagelib_testcase extends advanced_testcase {
$eventsink = $this->redirectEvents();
// Will always use the pop-up processor.
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user2);
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user3);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'email', $user2);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'email', $user3);
$message = new \core\message\message();
$message->courseid = 1;

View File

@ -165,6 +165,12 @@ current value for a pluginname depending on its status (enabled, disabled, other
This default applies both when there is no supplied coverage.php file, and is used to supplement any existing coverage configuration file if one is found.
* New method get_unaddable_by_theme_block_types() has been added to block_manager class. It uses the 'unaddableblocks' theme setting
value to get the list of blocks that won't be displayed for a theme.
* Loggedin / Loggedoff component settings on notification preferences have been merged to a single enabled switch:
MESSAGE_DEFAULT_LOGGEDIN and MESSAGE_DEFAULT_LOGGEDOFF are now deprecated, so plugins should be updated if db/messages.php is present and replace
MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF to MESSAGE_DEFAULT_ENABLED. Backward compatibility will take any of both settings as enabled.
MESSAGE_DEFAULT_PERMITTED also deprecated.
core_message_get_user_notification_preferences and core_message_get_user_message_preferences Webservice are now returning enabled boolean on
components > notifications > processors. loggedin and loggedoff are deprecated but present for backward compatibility.
=== 3.11.4 ===
* A new option dontforcesvgdownload has been added to the $options parameter of the send_file() function.

View File

@ -0,0 +1,2 @@
define ("core_message/default_notification_preferences",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;var b={provider:".defaultmessageoutputs .provider_enabled",lockSetting:".locked_message_setting",enabledSetting:".enabled_message_setting",allSettings:".locked_message_setting, .enabled_message_setting"},c=function(){var a=function(a){var b=a.checked||!1,c=a.id.replace("_locked[","_enabled["),d=document.getElementById(c).closest("div.custom-control");d.classList.toggle("dimmed_text",b)},c=function(a){var c=a.checked||!1,d=a.closest("tr"),e=d.querySelectorAll(b.allSettings);e.forEach(function(a){a.toggleAttribute("disabled",!c)})},d=document.querySelector(".preferences-container");d.querySelectorAll(b.provider).forEach(function(a){if(!a.checked){c(a)}a.addEventListener("change",function(a){c(a.target)})});d.querySelectorAll(b.lockSetting).forEach(function(b){if(b.checked){a(b)}b.addEventListener("change",function(b){a(b.target)})})};a.default={init:function init(){c()}};return a.default});
//# sourceMappingURL=default_notification_preferences.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
define ("core_message/message_drawer_view_settings",["jquery","core/notification","core/str","core/pubsub","core/templates","core_message/message_repository","core/custom_interaction_events","core_message/message_drawer_events"],function(a,b,c,d,e,f,g,h){var i={CHECKBOX:"input[type=\"checkbox\"]",SETTINGS:"[data-region=\"settings\"]",PRIVACY_PREFERENCE:"[data-preference=\"blocknoncontacts\"] input[type=\"radio\"]",NOTIFICATIONS_PREFERENCE:"[data-preference=\"notifications\"] input[type=\"checkbox\"]",ENTER_TO_SEND_PREFERENCE:"[data-preference=\"entertosend\"] input[type=\"checkbox\"]",NOTIFICATION_PREFERENCES_CONTAINER:"[data-region=\"notification-preference-container\"]",CONTENT_CONTAINER:"[data-region=\"content-container\"]",PLACEHOLDER_CONTAINER:"[data-region=\"placeholder-container\"]"},j={NOTIFICATION_PREFERENCES:"core_message/message_drawer_view_settings_body_content_notification_preferences"},k=function(b,c){var d=b.find(i.PRIVACY_PREFERENCE);d.each(function(b,d){d=a(d);if(d.val()==c){d.prop("checked",!0)}else{d.prop("checked",!1)}})},l=function(a,b){var c=a.find(i.ENTER_TO_SEND_PREFERENCE);if(b){c.prop("checked",!0)}else{c.prop("checked",!1)}},m=function(a,c){return f.savePreferences(a,c).then(function(){d.publish(h.PREFERENCES_UPDATED,c)}).catch(b.exception)},n=function(b,c){var d=b.find(i.SETTINGS);g.define(d,[g.events.activate]);d.on(g.events.activate,i.NOTIFICATIONS_PREFERENCE,function(b){var d=a(b.target).closest(i.NOTIFICATION_PREFERENCES_CONTAINER),e=d.find(i.CHECKBOX);if(!e.length){return}var f=e.toArray().reduce(function(b,c){c=a(c);if(c.prop("checked")){b.push(c.attr("data-name"))}return b},[]),g=f.length?f.join(","):"none";m(c,[{type:"message_provider_moodle_instantmessage_loggedoff",value:g},{type:"message_provider_moodle_instantmessage_loggedin",value:g}])});d.on("change",i.PRIVACY_PREFERENCE,function(b){var d=a(b.target).val();m(c,[{type:"message_blocknoncontacts",value:d}])});d.on(g.events.activate,i.ENTER_TO_SEND_PREFERENCE,function(b){var d=a(b.target).prop("checked");m(c,[{type:"message_entertosend",value:d}])})},o=function(a,c){f.getUserMessagePreferences(c).then(function(b){k(a,b.blocknoncontacts);l(a,b.entertosend);var c=[];if(b.preferences.components.length){b.preferences.components.forEach(function(a){if(a.notifications.length){var b=a.notifications.filter(function(a){return a.preferencekey=="message_provider_moodle_instantmessage"});if(b.length){var d=a.notifications[0];c=d.processors.map(function(a){var b=a.loggedin.checked||a.loggedoff.checked;return{displayname:a.displayname,name:a.name,checked:b,locked:a.locked,lockedmessage:a.lockedmessage||null}})}}})}var d=a.find(i.NOTIFICATION_PREFERENCES_CONTAINER);if(c.length){d.removeClass("hidden");return e.render(j.NOTIFICATION_PREFERENCES,{processors:c}).then(function(a){d.append(a);return a})}else{return!0}}).then(function(){a.find(i.CONTENT_CONTAINER).removeClass("hidden");a.find(i.PLACEHOLDER_CONTAINER).addClass("hidden");n(a,c)}).catch(b.exception)};return{show:function show(b,c,d,e,f){if(!d.attr("data-init")){o(d,f);d.attr("data-init",!0)}return a.Deferred().resolve().promise()},description:function description(){return c.get_string("messagedrawerviewsettings","core_message")}}});
define ("core_message/message_drawer_view_settings",["jquery","core/notification","core/str","core/pubsub","core/templates","core_message/message_repository","core/custom_interaction_events","core_message/message_drawer_events"],function(a,b,c,d,e,f,g,h){var i={CHECKBOX:"input[type=\"checkbox\"]",SETTINGS:"[data-region=\"settings\"]",PRIVACY_PREFERENCE:"[data-preference=\"blocknoncontacts\"] input[type=\"radio\"]",NOTIFICATIONS_PREFERENCE:"[data-preference=\"notifications\"] input[type=\"checkbox\"]",ENTER_TO_SEND_PREFERENCE:"[data-preference=\"entertosend\"] input[type=\"checkbox\"]",NOTIFICATION_PREFERENCES_CONTAINER:"[data-region=\"notification-preference-container\"]",CONTENT_CONTAINER:"[data-region=\"content-container\"]",PLACEHOLDER_CONTAINER:"[data-region=\"placeholder-container\"]"},j={NOTIFICATION_PREFERENCES:"core_message/message_drawer_view_settings_body_content_notification_preferences"},k=function(b,c){var d=b.find(i.PRIVACY_PREFERENCE);d.each(function(b,d){d=a(d);if(d.val()==c){d.prop("checked",!0)}else{d.prop("checked",!1)}})},l=function(a,b){var c=a.find(i.ENTER_TO_SEND_PREFERENCE);if(b){c.prop("checked",!0)}else{c.prop("checked",!1)}},m=function(a,c){return f.savePreferences(a,c).then(function(){d.publish(h.PREFERENCES_UPDATED,c)}).catch(b.exception)},n=function(b,c){var d=b.find(i.SETTINGS);g.define(d,[g.events.activate]);d.on(g.events.activate,i.NOTIFICATIONS_PREFERENCE,function(b){var d=a(b.target).closest(i.NOTIFICATION_PREFERENCES_CONTAINER),e=d.find(i.CHECKBOX);if(!e.length){return}var f=e.toArray().reduce(function(b,c){c=a(c);if(c.prop("checked")){b.push(c.attr("data-name"))}return b},[]),g=f.length?f.join(","):"none";m(c,[{type:"message_provider_moodle_instantmessage_enabled",value:g}])});d.on("change",i.PRIVACY_PREFERENCE,function(b){var d=a(b.target).val();m(c,[{type:"message_blocknoncontacts",value:d}])});d.on(g.events.activate,i.ENTER_TO_SEND_PREFERENCE,function(b){var d=a(b.target).prop("checked");m(c,[{type:"message_entertosend",value:d}])})},o=function(a,c){f.getUserMessagePreferences(c).then(function(b){k(a,b.blocknoncontacts);l(a,b.entertosend);var c=[];if(b.preferences.components.length){b.preferences.components.forEach(function(a){if(a.notifications.length){var b=a.notifications.filter(function(a){return a.preferencekey=="message_provider_moodle_instantmessage"});if(b.length){var d=a.notifications[0];c=d.processors.map(function(a){var b=a.enabled;return{displayname:a.displayname,name:a.name,checked:b,locked:a.locked,lockedmessage:a.lockedmessage||null}})}}})}var d=a.find(i.NOTIFICATION_PREFERENCES_CONTAINER);if(c.length){d.removeClass("hidden");return e.render(j.NOTIFICATION_PREFERENCES,{processors:c}).then(function(a){d.append(a);return a})}else{return!0}}).then(function(){a.find(i.CONTENT_CONTAINER).removeClass("hidden");a.find(i.PLACEHOLDER_CONTAINER).addClass("hidden");n(a,c)}).catch(b.exception)};return{show:function show(b,c,d,e,f){if(!d.attr("data-init")){o(d,f);d.attr("data-init",!0)}return a.Deferred().resolve().promise()},description:function description(){return c.get_string("messagedrawerviewsettings","core_message")}}});
//# sourceMappingURL=message_drawer_view_settings.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
define ("core_message/notification_preference",["jquery","core/ajax","core/notification","core_message/notification_processor"],function(a,b,c,d){var e={PROCESSOR:"[data-processor-name]",STATE_INPUTS:"[data-state] input"},f=function(b,c){this.root=a(b);this.userId=c};f.prototype.getPreferenceKey=function(){return this.root.attr("data-preference-key")};f.prototype.getLoggedInPreferenceKey=function(){return this.getPreferenceKey()+"_loggedin"};f.prototype.getLoggedOffPreferenceKey=function(){return this.getPreferenceKey()+"_loggedoff"};f.prototype.getProcessors=function(){return this.root.find(e.PROCESSOR).map(function(b,c){return new d(a(c))})};f.prototype.startLoading=function(){this.root.addClass("loading");this.root.find(e.STATE_INPUTS).prop("disabled",!0)};f.prototype.stopLoading=function(){this.root.removeClass("loading");this.root.find(e.STATE_INPUTS).prop("disabled",!1)};f.prototype.isLoading=function(){return this.root.hasClass("loading")};f.prototype.save=function(){if(this.isLoading()){return a.Deferred().resolve()}this.startLoading();var d="",e="";this.getProcessors().each(function(a,b){if(b.isLoggedInEnabled()){if(""===d){d=b.getName()}else{d+=","+b.getName()}}if(b.isLoggedOffEnabled()){if(""===e){e=b.getName()}else{e+=","+b.getName()}}});if(""===d){d="none"}if(""===e){e="none"}var f={userid:this.userId,preferences:[{type:this.getLoggedInPreferenceKey(),value:d},{type:this.getLoggedOffPreferenceKey(),value:e}]};return b.call([{methodname:"core_user_update_user_preferences",args:f}])[0].fail(c.exception).always(function(){this.stopLoading()}.bind(this))};return f});
define ("core_message/notification_preference",["jquery","core/ajax","core/notification","core_message/notification_processor"],function(a,b,c,d){var e={PROCESSOR:"[data-processor-name]",STATE_INPUTS:"[data-state] input"},f=function(b,c){this.root=a(b);this.userId=c};f.prototype.getPreferenceKey=function(){return this.root.attr("data-preference-key")};f.prototype.getEnabledPreferenceKey=function(){return this.getPreferenceKey()+"_enabled"};f.prototype.getProcessors=function(){return this.root.find(e.PROCESSOR).map(function(b,c){return new d(a(c))})};f.prototype.startLoading=function(){this.root.addClass("loading");this.root.find(e.STATE_INPUTS).prop("disabled",!0)};f.prototype.stopLoading=function(){this.root.removeClass("loading");this.root.find(e.STATE_INPUTS).prop("disabled",!1)};f.prototype.isLoading=function(){return this.root.hasClass("loading")};f.prototype.save=function(){if(this.isLoading()){return a.Deferred().resolve()}this.startLoading();var d="";this.getProcessors().each(function(a,b){if(b.isEnabled()){if(""===d){d=b.getName()}else{d+=","+b.getName()}}});if(""===d){d="none"}var e={userid:this.userId,preferences:[{type:this.getEnabledPreferenceKey(),value:d}]};return b.call([{methodname:"core_user_update_user_preferences",args:e}])[0].fail(c.exception).always(function(){this.stopLoading()}.bind(this))};return f});
//# sourceMappingURL=notification_preference.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
define ("core_message/notification_processor",["jquery"],function(a){var b={STATE_NONE:"[data-state=\"none\"]",STATE_BOTH:"[data-state=\"both\"]",STATE_LOGGED_IN:"[data-state=\"loggedin\"]",STATE_LOGGED_OFF:"[data-state=\"loggedoff\"]"},c=function(b){this.root=a(b)};c.prototype.getName=function(){return this.root.attr("data-processor-name")};c.prototype.isLoggedInEnabled=function(){var a=this.root.find(b.STATE_NONE).find("input");if(a.prop("checked")){return!1}var c=this.root.find(b.STATE_BOTH).find("input"),d=this.root.find(b.STATE_LOGGED_IN).find("input");return d.prop("checked")||c.prop("checked")};c.prototype.isLoggedOffEnabled=function(){var a=this.root.find(b.STATE_NONE).find("input");if(a.prop("checked")){return!1}var c=this.root.find(b.STATE_BOTH).find("input"),d=this.root.find(b.STATE_LOGGED_OFF).find("input");return d.prop("checked")||c.prop("checked")};return c});
define ("core_message/notification_processor",["jquery"],function(a){var b={STATE_INPUTS:".preference-state input.notification_enabled"},c=function(b){this.root=a(b)};c.prototype.getName=function(){return this.root.attr("data-processor-name")};c.prototype.isEnabled=function(){var a=this.root.find(b.STATE_INPUTS);return a.prop("checked")};return c});
//# sourceMappingURL=notification_processor.min.js.map

View File

@ -1 +1 @@
{"version":3,"sources":["../src/notification_processor.js"],"names":["define","$","SELECTORS","STATE_NONE","STATE_BOTH","STATE_LOGGED_IN","STATE_LOGGED_OFF","NotificationProcessor","element","root","prototype","getName","attr","isLoggedInEnabled","none","find","prop","both","loggedIn","isLoggedOffEnabled","loggedOff"],"mappings":"AAsBAA,OAAM,uCAAC,CAAC,QAAD,CAAD,CAAa,SAASC,CAAT,CAAY,IACvBC,CAAAA,CAAS,CAAG,CACZC,UAAU,CAAE,uBADA,CAEZC,UAAU,CAAE,uBAFA,CAGZC,eAAe,CAAE,2BAHL,CAIZC,gBAAgB,CAAE,4BAJN,CADW,CAcvBC,CAAqB,CAAG,SAASC,CAAT,CAAkB,CAC1C,KAAKC,IAAL,CAAYR,CAAC,CAACO,CAAD,CAChB,CAhB0B,CAwB3BD,CAAqB,CAACG,SAAtB,CAAgCC,OAAhC,CAA0C,UAAW,CACjD,MAAO,MAAKF,IAAL,CAAUG,IAAV,CAAe,qBAAf,CACV,CAFD,CAUAL,CAAqB,CAACG,SAAtB,CAAgCG,iBAAhC,CAAoD,UAAW,CAC3D,GAAIC,CAAAA,CAAI,CAAG,KAAKL,IAAL,CAAUM,IAAV,CAAeb,CAAS,CAACC,UAAzB,EAAqCY,IAArC,CAA0C,OAA1C,CAAX,CAEA,GAAID,CAAI,CAACE,IAAL,CAAU,SAAV,CAAJ,CAA0B,CACtB,QACH,CAL0D,GAOvDC,CAAAA,CAAI,CAAG,KAAKR,IAAL,CAAUM,IAAV,CAAeb,CAAS,CAACE,UAAzB,EAAqCW,IAArC,CAA0C,OAA1C,CAPgD,CAQvDG,CAAQ,CAAG,KAAKT,IAAL,CAAUM,IAAV,CAAeb,CAAS,CAACG,eAAzB,EAA0CU,IAA1C,CAA+C,OAA/C,CAR4C,CAU3D,MAAOG,CAAAA,CAAQ,CAACF,IAAT,CAAc,SAAd,GAA4BC,CAAI,CAACD,IAAL,CAAU,SAAV,CACtC,CAXD,CAmBAT,CAAqB,CAACG,SAAtB,CAAgCS,kBAAhC,CAAqD,UAAW,CAC5D,GAAIL,CAAAA,CAAI,CAAG,KAAKL,IAAL,CAAUM,IAAV,CAAeb,CAAS,CAACC,UAAzB,EAAqCY,IAArC,CAA0C,OAA1C,CAAX,CAEA,GAAID,CAAI,CAACE,IAAL,CAAU,SAAV,CAAJ,CAA0B,CACtB,QACH,CAL2D,GAOxDC,CAAAA,CAAI,CAAG,KAAKR,IAAL,CAAUM,IAAV,CAAeb,CAAS,CAACE,UAAzB,EAAqCW,IAArC,CAA0C,OAA1C,CAPiD,CAQxDK,CAAS,CAAG,KAAKX,IAAL,CAAUM,IAAV,CAAeb,CAAS,CAACI,gBAAzB,EAA2CS,IAA3C,CAAgD,OAAhD,CAR4C,CAU5D,MAAOK,CAAAA,CAAS,CAACJ,IAAV,CAAe,SAAf,GAA6BC,CAAI,CAACD,IAAL,CAAU,SAAV,CACvC,CAXD,CAaA,MAAOT,CAAAA,CACV,CAnEK,CAAN","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Represents the notification processor (e.g. email, popup, jabber)\n *\n * @module core_message/notification_processor\n * @copyright 2016 Ryan Wyllie <ryan@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery'], function($) {\n var SELECTORS = {\n STATE_NONE: '[data-state=\"none\"]',\n STATE_BOTH: '[data-state=\"both\"]',\n STATE_LOGGED_IN: '[data-state=\"loggedin\"]',\n STATE_LOGGED_OFF: '[data-state=\"loggedoff\"]',\n };\n\n /**\n * Constructor for the notification processor.\n *\n * @class\n * @param {object} element jQuery object root element of the processor\n */\n var NotificationProcessor = function(element) {\n this.root = $(element);\n };\n\n /**\n * Get the processor name.\n *\n * @method getName\n * @return {string}\n */\n NotificationProcessor.prototype.getName = function() {\n return this.root.attr('data-processor-name');\n };\n\n /**\n * Check if the processor is enabled when the user is logged in.\n *\n * @method isLoggedInEnabled\n * @return {bool}\n */\n NotificationProcessor.prototype.isLoggedInEnabled = function() {\n var none = this.root.find(SELECTORS.STATE_NONE).find('input');\n\n if (none.prop('checked')) {\n return false;\n }\n\n var both = this.root.find(SELECTORS.STATE_BOTH).find('input');\n var loggedIn = this.root.find(SELECTORS.STATE_LOGGED_IN).find('input');\n\n return loggedIn.prop('checked') || both.prop('checked');\n };\n\n /**\n * Check if the processor is enabled when the user is logged out.\n *\n * @method isLoggedOffEnabled\n * @return {bool}\n */\n NotificationProcessor.prototype.isLoggedOffEnabled = function() {\n var none = this.root.find(SELECTORS.STATE_NONE).find('input');\n\n if (none.prop('checked')) {\n return false;\n }\n\n var both = this.root.find(SELECTORS.STATE_BOTH).find('input');\n var loggedOff = this.root.find(SELECTORS.STATE_LOGGED_OFF).find('input');\n\n return loggedOff.prop('checked') || both.prop('checked');\n };\n\n return NotificationProcessor;\n});\n"],"file":"notification_processor.min.js"}
{"version":3,"sources":["../src/notification_processor.js"],"names":["define","$","SELECTORS","STATE_INPUTS","NotificationProcessor","element","root","prototype","getName","attr","isEnabled","enabled","find","prop"],"mappings":"AAsBAA,OAAM,uCAAC,CAAC,QAAD,CAAD,CAAa,SAASC,CAAT,CAAY,IACrBC,CAAAA,CAAS,CAAG,CACdC,YAAY,CAAE,8CADA,CADS,CAWrBC,CAAqB,CAAG,SAASC,CAAT,CAAkB,CAC5C,KAAKC,IAAL,CAAYL,CAAC,CAACI,CAAD,CAChB,CAb0B,CAqB3BD,CAAqB,CAACG,SAAtB,CAAgCC,OAAhC,CAA0C,UAAW,CACjD,MAAO,MAAKF,IAAL,CAAUG,IAAV,CAAe,qBAAf,CACV,CAFD,CAUAL,CAAqB,CAACG,SAAtB,CAAgCG,SAAhC,CAA4C,UAAW,CACnD,GAAMC,CAAAA,CAAO,CAAG,KAAKL,IAAL,CAAUM,IAAV,CAAeV,CAAS,CAACC,YAAzB,CAAhB,CAEA,MAAOQ,CAAAA,CAAO,CAACE,IAAR,CAAa,SAAb,CACV,CAJD,CAMA,MAAOT,CAAAA,CACV,CAtCK,CAAN","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Represents the notification processor (e.g. email, popup, jabber)\n *\n * @module core_message/notification_processor\n * @copyright 2016 Ryan Wyllie <ryan@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery'], function($) {\n const SELECTORS = {\n STATE_INPUTS: '.preference-state input.notification_enabled'\n };\n\n /**\n * Constructor for the notification processor.\n *\n * @class\n * @param {object} element jQuery object root element of the processor\n */\n const NotificationProcessor = function(element) {\n this.root = $(element);\n };\n\n /**\n * Get the processor name.\n *\n * @method getName\n * @return {string}\n */\n NotificationProcessor.prototype.getName = function() {\n return this.root.attr('data-processor-name');\n };\n\n /**\n * Check if the processor is enabled when the user is logged in.\n *\n * @method isLoggedInEnabled\n * @return {bool}\n */\n NotificationProcessor.prototype.isEnabled = function() {\n const enabled = this.root.find(SELECTORS.STATE_INPUTS);\n\n return enabled.prop('checked');\n };\n\n return NotificationProcessor;\n});\n"],"file":"notification_processor.min.js"}

View File

@ -1,2 +1,2 @@
define ("core_message/preferences_notifications_list_controller",["jquery","core/ajax","core/notification","core/custom_interaction_events","core_message/notification_preference","core_message/notification_processor_settings","core/modal_factory"],function(a,b,c,d,f,g,h){var i={DISABLE_NOTIFICATIONS:"[data-region=\"disable-notification-container\"] [data-disable-notifications]",DISABLE_NOTIFICATIONS_CONTAINER:"[data-region=\"disable-notification-container\"]",PREFERENCE:"[data-state]",PREFERENCE_ROW:"[data-region=\"preference-row\"]",PREFERENCE_INPUT:"[data-state] input",PROCESSOR_SETTING:"[data-processor-setting]"},j=function(b){this.root=a(b);this.userId=this.root.attr("data-user-id");this.registerEventListeners()};j.prototype.isDisabled=function(){return this.root.hasClass("disabled")};j.prototype.setDisabled=function(){this.root.addClass("disabled");this.root.find(i.PREFERENCE_INPUT).prop("disabled",!0)};j.prototype.setEnabled=function(){this.root.removeClass("disabled");this.root.find(i.PREFERENCE_INPUT).prop("disabled",!1)};j.prototype.toggleDisableAllStatus=function(){var d=a(i.DISABLE_NOTIFICATIONS),e=a(i.DISABLE_NOTIFICATIONS_CONTAINER),f=d.prop("checked");if(e.hasClass("loading")){return a.Deferred().resolve()}e.addClass("loading");var g={methodname:"core_user_update_user_preferences",args:{userid:this.userId,emailstop:f?1:0}};return b.call([g])[0].done(function(){if(f){this.setDisabled()}else{this.setEnabled()}}.bind(this)).always(function(){e.removeClass("loading")}).fail(c.exception)};j.prototype.registerEventListeners=function(){var b=a(i.DISABLE_NOTIFICATIONS);d.define(this.root,[d.events.activate]);this.root.on("change",function(b){if(!this.isDisabled()){var c=a(b.target).closest(i.PREFERENCE),d=a(b.target).closest(i.PREFERENCE_ROW),e=new f(d,this.userId);c.addClass("loading");e.save().always(function(){c.removeClass("loading")})}}.bind(this));var j=h.create({type:g.TYPE});this.root.on(d.events.activate,i.PROCESSOR_SETTING,function(b,d){var e=a(b.target).closest(i.PROCESSOR_SETTING);d.originalEvent.preventDefault();j.then(function(c){c.setUserId(a(e).attr("data-user-id"));c.setName(a(e).attr("data-name"));c.setContextId(a(e).attr("data-context-id"));c.setElement(e);c.show();b.stopImmediatePropagation()}).fail(c.exception)});d.define(b,[d.events.activate]);b.on(d.events.activate,function(){this.toggleDisableAllStatus()}.bind(this))};return j});
define ("core_message/preferences_notifications_list_controller",["jquery","core/ajax","core/notification","core/custom_interaction_events","core_message/notification_preference","core_message/notification_processor_settings","core/modal_factory"],function(a,b,c,d,f,g,h){var i={DISABLE_NOTIFICATIONS:"[data-region=\"disable-notification-container\"] [data-disable-notifications]",DISABLE_NOTIFICATIONS_CONTAINER:"[data-region=\"disable-notification-container\"]",PREFERENCE:".preference-state",PREFERENCE_ROW:"[data-region=\"preference-row\"]",PREFERENCE_INPUT:".preference-state input",PROCESSOR_SETTING:"[data-processor-setting]"},j=function(b){this.root=a(b);this.userId=this.root.attr("data-user-id");this.registerEventListeners()};j.prototype.isDisabled=function(){return this.root.hasClass("disabled")};j.prototype.setDisabled=function(){this.root.addClass("disabled");this.root.find(i.PREFERENCE_INPUT).prop("disabled",!0)};j.prototype.setEnabled=function(){this.root.removeClass("disabled");this.root.find(i.PREFERENCE_INPUT).prop("disabled",!1)};j.prototype.toggleDisableAllStatus=function(){var d=a(i.DISABLE_NOTIFICATIONS),e=a(i.DISABLE_NOTIFICATIONS_CONTAINER),f=d.prop("checked");if(e.hasClass("loading")){return a.Deferred().resolve()}e.addClass("loading");var g={methodname:"core_user_update_user_preferences",args:{userid:this.userId,emailstop:f?1:0}};return b.call([g])[0].done(function(){if(f){this.setDisabled()}else{this.setEnabled()}}.bind(this)).always(function(){e.removeClass("loading")}).fail(c.exception)};j.prototype.registerEventListeners=function(){var b=a(i.DISABLE_NOTIFICATIONS);d.define(this.root,[d.events.activate]);this.root.on("change",function(b){if(!this.isDisabled()){var c=a(b.target).closest(i.PREFERENCE),d=a(b.target).closest(i.PREFERENCE_ROW),e=new f(d,this.userId);c.addClass("loading");e.save().always(function(){c.removeClass("loading")})}}.bind(this));var j=h.create({type:g.TYPE});this.root.on(d.events.activate,i.PROCESSOR_SETTING,function(b,d){var e=a(b.target).closest(i.PROCESSOR_SETTING);d.originalEvent.preventDefault();j.then(function(c){c.setUserId(a(e).attr("data-user-id"));c.setName(a(e).attr("data-name"));c.setContextId(a(e).attr("data-context-id"));c.setElement(e);c.show();b.stopImmediatePropagation()}).fail(c.exception)});d.define(b,[d.events.activate]);b.on(d.events.activate,function(){this.toggleDisableAllStatus()}.bind(this))};return j});
//# sourceMappingURL=preferences_notifications_list_controller.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,101 @@
// 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/>.
/**
* Controls the default settings for the list of notification types on the
* notifications admin page
*
* @module core_message/default_notification_preferences
* @class default_notification_preferences
* @copyright 2021 Moodle
* @author Pau Ferrer Ocaña <pau@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
const selectors = {
provider: '.defaultmessageoutputs .provider_enabled',
lockSetting: '.locked_message_setting',
enabledSetting: '.enabled_message_setting',
allSettings: '.locked_message_setting, .enabled_message_setting'
};
/**
* Register event listeners for the default_notification_preferences page.
*/
const registerEventListeners = () => {
/**
* Update the dimmed status of the "enabled" toggle on the notification setting.
*
* @param {HTMLElement} lockedElement Element that receives the event.
*/
const toggleLockSetting = (lockedElement) => {
const isEnabled = lockedElement.checked || false;
const enabledId = lockedElement.id.replace('_locked[', '_enabled[');
const enabledElement = document.getElementById(enabledId).closest('div.custom-control');
enabledElement.classList.toggle('dimmed_text', isEnabled);
};
/**
* Enable/Disable all settings of the provider.
*
* @param {HTMLElement} providerEnabledElement Element that receives the event.
*/
const toggleEnableProviderSettings = (providerEnabledElement) => {
const isEnabled = providerEnabledElement.checked || false;
const parentRow = providerEnabledElement.closest('tr');
const elements = parentRow.querySelectorAll(selectors.allSettings);
elements.forEach((element) => {
element.toggleAttribute('disabled', !isEnabled);
});
};
const container = document.querySelector('.preferences-container');
container.querySelectorAll(selectors.provider).forEach((providerEnabledElement) => {
// Set the initial statuses.
if (!providerEnabledElement.checked) {
toggleEnableProviderSettings(providerEnabledElement);
}
providerEnabledElement.addEventListener('change', (e) => {
toggleEnableProviderSettings(e.target);
});
});
container.querySelectorAll(selectors.lockSetting).forEach((lockedElement) => {
// Set the initial statuses.
if (lockedElement.checked) {
toggleLockSetting(lockedElement);
}
lockedElement.addEventListener('change', (e) => {
toggleLockSetting(e.target);
});
});
};
/**
* Initialize the page.
*/
const init = () => {
registerEventListeners();
};
export default {
init: init,
};

View File

@ -144,11 +144,7 @@ function(
var newValue = values.length ? values.join(',') : 'none';
var preferences = [
{
type: 'message_provider_moodle_instantmessage_loggedoff',
value: newValue
},
{
type: 'message_provider_moodle_instantmessage_loggedin',
type: 'message_provider_moodle_instantmessage_enabled',
value: newValue
}
];
@ -219,7 +215,7 @@ function(
// Consider the the processor enabled if either preference is set. This is
// for backwards compatibility. Going forward they will be treated as one
// setting.
var checked = processor.loggedin.checked || processor.loggedoff.checked;
var checked = processor.enabled;
return {
displayname: processor.displayname,
name: processor.name,

View File

@ -24,7 +24,7 @@
define(['jquery', 'core/ajax', 'core/notification', 'core_message/notification_processor'],
function($, Ajax, Notification, NotificationProcessor) {
var SELECTORS = {
const SELECTORS = {
PROCESSOR: '[data-processor-name]',
STATE_INPUTS: '[data-state] input',
};
@ -36,7 +36,7 @@ define(['jquery', 'core/ajax', 'core/notification', 'core_message/notification_p
* @param {object} element jQuery object root element of the preference
* @param {int} userId The current user id
*/
var NotificationPreference = function(element, userId) {
const NotificationPreference = function(element, userId) {
this.root = $(element);
this.userId = userId;
};
@ -52,23 +52,13 @@ define(['jquery', 'core/ajax', 'core/notification', 'core_message/notification_p
};
/**
* Get the unique key for the logged in preference.
* Get the unique key for the enabled preference.
*
* @method getLoggedInPreferenceKey
* @method getEnabledPreferenceKey
* @return {string}
*/
NotificationPreference.prototype.getLoggedInPreferenceKey = function() {
return this.getPreferenceKey() + '_loggedin';
};
/**
* Get the unique key for the logged off preference.
*
* @method getLoggedOffPreferenceKey
* @return {string}
*/
NotificationPreference.prototype.getLoggedOffPreferenceKey = function() {
return this.getPreferenceKey() + '_loggedoff';
NotificationPreference.prototype.getEnabledPreferenceKey = function() {
return this.getPreferenceKey() + '_enabled';
};
/**
@ -126,50 +116,33 @@ define(['jquery', 'core/ajax', 'core/notification', 'core_message/notification_p
this.startLoading();
var loggedInValue = '';
var loggedOffValue = '';
let enabledValue = '';
this.getProcessors().each(function(index, processor) {
if (processor.isLoggedInEnabled()) {
if (loggedInValue === '') {
loggedInValue = processor.getName();
if (processor.isEnabled()) {
if (enabledValue === '') {
enabledValue = processor.getName();
} else {
loggedInValue += ',' + processor.getName();
}
}
if (processor.isLoggedOffEnabled()) {
if (loggedOffValue === '') {
loggedOffValue = processor.getName();
} else {
loggedOffValue += ',' + processor.getName();
enabledValue += ',' + processor.getName();
}
}
});
if (loggedInValue === '') {
loggedInValue = 'none';
if (enabledValue === '') {
enabledValue = 'none';
}
if (loggedOffValue === '') {
loggedOffValue = 'none';
}
var args = {
const args = {
userid: this.userId,
preferences: [
{
type: this.getLoggedInPreferenceKey(),
value: loggedInValue,
},
{
type: this.getLoggedOffPreferenceKey(),
value: loggedOffValue,
},
type: this.getEnabledPreferenceKey(),
value: enabledValue,
}
],
};
var request = {
const request = {
methodname: 'core_user_update_user_preferences',
args: args,
};

View File

@ -21,11 +21,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery'], function($) {
var SELECTORS = {
STATE_NONE: '[data-state="none"]',
STATE_BOTH: '[data-state="both"]',
STATE_LOGGED_IN: '[data-state="loggedin"]',
STATE_LOGGED_OFF: '[data-state="loggedoff"]',
const SELECTORS = {
STATE_INPUTS: '.preference-state input.notification_enabled'
};
/**
@ -34,7 +31,7 @@ define(['jquery'], function($) {
* @class
* @param {object} element jQuery object root element of the processor
*/
var NotificationProcessor = function(element) {
const NotificationProcessor = function(element) {
this.root = $(element);
};
@ -54,36 +51,10 @@ define(['jquery'], function($) {
* @method isLoggedInEnabled
* @return {bool}
*/
NotificationProcessor.prototype.isLoggedInEnabled = function() {
var none = this.root.find(SELECTORS.STATE_NONE).find('input');
NotificationProcessor.prototype.isEnabled = function() {
const enabled = this.root.find(SELECTORS.STATE_INPUTS);
if (none.prop('checked')) {
return false;
}
var both = this.root.find(SELECTORS.STATE_BOTH).find('input');
var loggedIn = this.root.find(SELECTORS.STATE_LOGGED_IN).find('input');
return loggedIn.prop('checked') || both.prop('checked');
};
/**
* Check if the processor is enabled when the user is logged out.
*
* @method isLoggedOffEnabled
* @return {bool}
*/
NotificationProcessor.prototype.isLoggedOffEnabled = function() {
var none = this.root.find(SELECTORS.STATE_NONE).find('input');
if (none.prop('checked')) {
return false;
}
var both = this.root.find(SELECTORS.STATE_BOTH).find('input');
var loggedOff = this.root.find(SELECTORS.STATE_LOGGED_OFF).find('input');
return loggedOff.prop('checked') || both.prop('checked');
return enabled.prop('checked');
};
return NotificationProcessor;

View File

@ -42,9 +42,9 @@ define(['jquery',
var SELECTORS = {
DISABLE_NOTIFICATIONS: '[data-region="disable-notification-container"] [data-disable-notifications]',
DISABLE_NOTIFICATIONS_CONTAINER: '[data-region="disable-notification-container"]',
PREFERENCE: '[data-state]',
PREFERENCE: '.preference-state',
PREFERENCE_ROW: '[data-region="preference-row"]',
PREFERENCE_INPUT: '[data-state] input',
PREFERENCE_INPUT: '.preference-state input',
PROCESSOR_SETTING: '[data-processor-setting]',
};

View File

@ -270,18 +270,17 @@ class helper {
// Get providers preferences.
foreach ($providers as $provider) {
foreach (array('loggedin', 'loggedoff') as $state) {
$linepref = get_user_preferences('message_provider_' . $provider->component . '_' . $provider->name
. '_' . $state, '', $userid);
if ($linepref == '') {
continue;
}
$lineprefarray = explode(',', $linepref);
$preferences->{$provider->component.'_'.$provider->name.'_'.$state} = array();
foreach ($lineprefarray as $pref) {
$preferences->{$provider->component.'_'.$provider->name.'_'.$state}[$pref] = 1;
}
$linepref = get_user_preferences('message_provider_' . $provider->component . '_' . $provider->name
. '_enabled', '', $userid);
if ($linepref == '') {
continue;
}
$lineprefarray = explode(',', $linepref);
$preferences->{$provider->component.'_'.$provider->name.'_enabled'} = [];
foreach ($lineprefarray as $pref) {
$preferences->{$provider->component.'_'.$provider->name.'_enabled'}[$pref] = 1;
}
}
return $preferences;

View File

@ -162,15 +162,6 @@ class notification_list implements templatable, renderable {
$context['components'][] = $notificationcomponent->export_for_template($output);
}
// This is fairly nasty but we don't currently have a way to add help icons
// in templates, so we'll need to provide it in the context.
//
// We only want the first component to render with the help icon.
if (!empty($context['components'])) {
$context['components'][0]['onlinehelphtml'] = $output->help_icon('loggedin', 'message');
$context['components'][0]['offlinehelphtml'] = $output->help_icon('loggedoff', 'message');
}
return $context;
}
}

View File

@ -127,6 +127,7 @@ class notification_list_component implements templatable, renderable {
$context = [
'displayname' => $componentname,
'colspan' => count($processors) + 1,
'notifications' => [],
];

View File

@ -81,16 +81,17 @@ class notification_list_processor implements templatable, renderable {
* Check if the given preference is enabled or not.
*
* @param string $name preference name
* @param string $locked Wether the preference is locked by admin.
* @return bool
*/
private function is_preference_enabled($name) {
private function is_preference_enabled($name, $locked) {
$processor = $this->processor;
$preferences = $this->preferences;
$defaultpreferences = get_message_output_default_preferences();
$checked = false;
// See if user has touched this preference.
if (isset($preferences->{$name})) {
if (!$locked && isset($preferences->{$name})) {
// User has some preferences for this state in the database.
$checked = isset($preferences->{$name}[$processor->name]);
} else {
@ -104,40 +105,64 @@ class notification_list_processor implements templatable, renderable {
return $checked;
}
/**
* Export this data so it can be used as the context for a mustache template.
* @todo Remove loggedin and loggedoff from context on MDL-73284.
*
* @param renderer_base $output
* @return stdClass
*/
public function export_for_template(\renderer_base $output) {
$processor = $this->processor;
$preferencebase = $this->get_preference_base();
$permitted = MESSAGE_DEFAULT_PERMITTED;
$defaultpreferences = get_message_output_default_preferences();
$defaultpreference = $processor->name.'_provider_'.$preferencebase.'_permitted';
$defaultpreference = $processor->name.'_provider_'.$preferencebase.'_locked';
$providername = get_string('messageprovider:'.$this->provider->name, $this->provider->component);
$processorname = get_string('pluginname', 'message_'.$processor->name);
$labelparams = [
'provider' => $providername,
'processor' => $processorname,
];
$context = [
'displayname' => get_string('pluginname', 'message_'.$processor->name),
'displayname' => $processorname,
'name' => $processor->name,
'locked' => false,
'userconfigured' => $processor->object->is_user_configured(),
// Backward compatibility, deprecated attribute.
'loggedin' => [
'name' => 'loggedin',
'displayname' => get_string('loggedindescription', 'message'),
'checked' => $this->is_preference_enabled($preferencebase.'_loggedin'),
'displayname' => 'loggedin',
'checked' => false,
],
// Backward compatibility, deprecated attribute.
'loggedoff' => [
'name' => 'loggedoff',
'displayname' => get_string('loggedoffdescription', 'message'),
'checked' => $this->is_preference_enabled($preferencebase.'_loggedoff'),
'displayname' => 'loggedoff',
'checked' => false,
],
'enabled' => false,
'enabledlabel' => get_string('sendingviaenabled', 'message', $labelparams),
];
// Determine the default setting.
if (isset($defaultpreferences->{$defaultpreference})) {
$permitted = $defaultpreferences->{$defaultpreference};
$context['locked'] = $defaultpreferences->{$defaultpreference};
}
$context['enabled'] = $this->is_preference_enabled($preferencebase.'_enabled', $context['locked']);
$context['loggedoff']['checked'] = $context['enabled']; // Backward compatibility, deprecated attribute.
$context['loggedin']['checked'] = $context['enabled']; // Backward compatibility, deprecated attribute.
// If settings are disallowed or forced, just display the corresponding message, if not use user settings.
if ($permitted == 'disallowed') {
$context['locked'] = true;
$context['lockedmessage'] = get_string('disallowed', 'message');
} else if ($permitted == 'forced') {
$context['locked'] = true;
$context['lockedmessage'] = get_string('forced', 'message');
if ($context['locked']) {
if ($context['enabled']) {
$context['lockedmessage'] = get_string('forced', 'message');
$context['lockedlabel'] = get_string('providerprocesorislocked', 'message', $labelparams);
} else {
$context['lockedmessage'] = get_string('disallowed', 'message');
$context['lockedlabel'] = get_string('providerprocesorisdisallowed', 'message', $labelparams);
}
}
return $context;

View File

@ -3020,6 +3020,7 @@ class core_message_external extends external_api {
*
* @return external_single_structure the structure
* @since Moodle 3.2
* @todo Remove loggedin and loggedoff from processors structure on MDL-73284.
*/
protected static function get_preferences_structure() {
return new external_single_structure(
@ -3061,15 +3062,20 @@ class core_message_external extends external_api {
'name' => new external_value(PARAM_NOTAGS, 'Name'),
'displayname' => new external_value(PARAM_TEXT, 'Display name'),
'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
)
),
'DEPRECATED ATTRIBUTE -
Kept for backward compatibility, use enabled instead.',
),
'loggedoff' => new external_single_structure(
array(
'name' => new external_value(PARAM_NOTAGS, 'Name'),
'displayname' => new external_value(PARAM_TEXT, 'Display name'),
'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
)
),
'DEPRECATED ATTRIBUTE -
Kept for backward compatibility, use enabled instead.',
),
'enabled' => new external_value(PARAM_BOOL, 'Is enabled?'),
)
),
'Processors values for this notification'

View File

@ -34,24 +34,37 @@ define('MESSAGE_TYPE_MESSAGE', 'message');
/**
* Define contants for messaging default settings population. For unambiguity of
* plugin developer intentions we use 4-bit value (LSB numbering):
* bit 0 - whether to send message when user is loggedin (MESSAGE_DEFAULT_LOGGEDIN)
* bit 1 - whether to send message when user is loggedoff (MESSAGE_DEFAULT_LOGGEDOFF)
* bit 0 - whether to send message (MESSAGE_DEFAULT_ENABLED)
* bit 1 - Deprecated: whether to send message (MESSAGE_DEFAULT_LOGGEDOFF). Used to mean only when the user is logged off.
* bit 2..3 - messaging permission (MESSAGE_DISALLOWED|MESSAGE_PERMITTED|MESSAGE_FORCED)
*
* MESSAGE_PERMITTED_MASK contains the mask we use to distinguish permission setting
* MESSAGE_PERMITTED_MASK contains the mask we use to distinguish permission setting.
*/
/**
* @deprecated since Moodle 4.0. Use MESSAGE_DEFAULT_ENABLED instead.
* @todo Remove on MDL-73284.
*/
define('MESSAGE_DEFAULT_LOGGEDIN', 0x01); // 0001
/**
* @deprecated since Moodle 4.0 MDL-73284. Use MESSAGE_DEFAULT_ENABLED instead.
* @todo Remove on MDL-73284.
*/
define('MESSAGE_DEFAULT_LOGGEDOFF', 0x02); // 0010
define('MESSAGE_DISALLOWED', 0x04); // 0100
define('MESSAGE_PERMITTED', 0x08); // 1000
define('MESSAGE_FORCED', 0x0c); // 1100
define('MESSAGE_DEFAULT_ENABLED', 0x01); // 0001.
define('MESSAGE_PERMITTED_MASK', 0x0c); // 1100
define('MESSAGE_DISALLOWED', 0x04); // 0100.
define('MESSAGE_PERMITTED', 0x08); // 1000.
define('MESSAGE_FORCED', 0x0c); // 1100.
define('MESSAGE_PERMITTED_MASK', 0x0c); // 1100.
/**
* Set default value for default outputs permitted setting
* @deprecated since Moodle 4.0 MDL-73284.
* @todo Remove on MDL-73284.
*/
define('MESSAGE_DEFAULT_PERMITTED', 'permitted');
@ -493,26 +506,15 @@ function get_message_output_default_preferences() {
* Translate message default settings from binary value to the array of string
* representing the settings to be stored. Also validate the provided value and
* use default if it is malformed.
* @todo Remove usage of MESSAGE_DEFAULT_LOGGEDOFF on MDL-73284.
*
* @param int $plugindefault Default setting suggested by plugin
* @param string $processorname The name of processor
* @return array $settings array of strings in the order: $permitted, $loggedin, $loggedoff.
* @return array $settings array of strings in the order: $locked, $enabled.
*/
function translate_message_default_setting($plugindefault, $processorname) {
// Preset translation arrays
$permittedvalues = array(
MESSAGE_DISALLOWED => 'disallowed',
MESSAGE_PERMITTED => 'permitted',
MESSAGE_FORCED => 'forced',
);
$loggedinstatusvalues = array(
0x00 => null, // use null if loggedin/loggedoff is not defined
MESSAGE_DEFAULT_LOGGEDIN => 'loggedin',
MESSAGE_DEFAULT_LOGGEDOFF => 'loggedoff',
);
// define the default setting
// Define the default setting.
$processor = get_message_processor($processorname);
$default = $processor->get_default_messaging_settings();
@ -526,15 +528,31 @@ function translate_message_default_setting($plugindefault, $processorname) {
$plugindefault = $default;
}
$permitted = $permittedvalues[$plugindefault & MESSAGE_PERMITTED_MASK];
$loggedin = $loggedoff = null;
$locked = false;
$enabled = false;
if (($plugindefault & MESSAGE_PERMITTED_MASK) == MESSAGE_PERMITTED) {
$loggedin = $loggedinstatusvalues[$plugindefault & MESSAGE_DEFAULT_LOGGEDIN];
$loggedoff = $loggedinstatusvalues[$plugindefault & MESSAGE_DEFAULT_LOGGEDOFF];
$permitted = $plugindefault & MESSAGE_PERMITTED_MASK;
switch ($permitted) {
case MESSAGE_FORCED:
$locked = true;
$enabled = true;
break;
case MESSAGE_DISALLOWED:
$locked = true;
$enabled = false;
break;
default:
$locked = false;
// It's equivalent to logged in.
$enabled = $plugindefault & MESSAGE_DEFAULT_ENABLED == MESSAGE_DEFAULT_ENABLED;
// MESSAGE_DEFAULT_LOGGEDOFF is deprecated but we're checking it just in case.
$loggedoff = $plugindefault & MESSAGE_DEFAULT_LOGGEDOFF == MESSAGE_DEFAULT_LOGGEDOFF;
$enabled = $enabled || $loggedoff;
break;
}
return array($permitted, $loggedin, $loggedoff);
return array($locked, $enabled);
}
/**
@ -791,13 +809,13 @@ function core_message_user_preferences() {
'null' => NULL_NOT_ALLOWED,
'default' => false
);
$preferences['/^message_provider_([\w\d_]*)_logged(in|off)$/'] = array('isregex' => true, 'type' => PARAM_NOTAGS,
$preferences['/^message_provider_([\w\d_]*)_enabled$/'] = array('isregex' => true, 'type' => PARAM_NOTAGS,
'null' => NULL_NOT_ALLOWED, 'default' => 'none',
'permissioncallback' => function ($user, $preferencename) {
global $CFG;
require_once($CFG->libdir.'/messagelib.php');
if (core_message_can_edit_message_profile($user) &&
preg_match('/^message_provider_([\w\d_]*)_logged(in|off)$/', $preferencename, $matches)) {
preg_match('/^message_provider_([\w\d_]*)_enabled$/', $preferencename, $matches)) {
$providers = message_get_providers_for_user($user->id);
foreach ($providers as $provider) {
if ($matches[1] === $provider->component . '_' . $provider->name) {

View File

@ -17,77 +17,6 @@ M.core_message.combinedsearchgotfocus = function(e) {
}
};
M.core_message.init_defaultoutputs = function(Y) {
var defaultoutputs = {
init : function() {
Y.all('#defaultmessageoutputs select').each(function(node) {
// attach event listener
node.on('change', defaultoutputs.changeState);
// set initial layout
node.simulate("change");
}, this);
Y.all('#defaultmessageoutputs input.messagedisable').each(function(node) {
// Attach event listener
node.on('change', defaultoutputs.changeProviderState);
node.simulate("change");
}, this);
},
changeState : function(e) {
var value = e.target._node.options[e.target.get('selectedIndex')].value;
var parentnode = e.target.ancestor('td');
switch (value) {
case 'forced':
defaultoutputs.updateCheckboxes(parentnode, 1, 1);
break;
case 'disallowed':
defaultoutputs.updateCheckboxes(parentnode, 1, 0);
break;
case 'permitted':
defaultoutputs.updateCheckboxes(parentnode, 0, 0);
break;
}
},
updateCheckboxes : function(blocknode, disabled, checked) {
blocknode.all('input[type=checkbox]').each(function(node) {
node.removeAttribute('disabled');
if (disabled) {
node.setAttribute('disabled', 1)
node.removeAttribute('checked');
}
if (checked) {
node.setAttribute('checked', 1)
}
}, this);
},
changeProviderState : function(e) {
var isenabled = e.target.get('checked') || undefined;
var parentnode = e.target.ancestor('tr');
if (!isenabled) {
parentnode.all('select').each(function(node) {
node.set('value', 'disallowed');
node.setAttribute('disabled', 1);
defaultoutputs.updateCheckboxes(node.ancestor('td'), 1, 0);
}, this);
parentnode.addClass('dimmed_text');
} else {
parentnode.all('select[disabled]').each(function(node) {
node.removeAttribute('disabled');
node.set('value', 'permitted');
defaultoutputs.updateCheckboxes(node.ancestor('td'), 0, 0);
}, this);
parentnode.removeClass('dimmed_text');
}
}
}
defaultoutputs.init();
}
M.core_message.init_editsettings = function(Y) {
var editsettings = {

View File

@ -68,7 +68,7 @@ class provider implements
'smallmessage' => 'privacy:metadata:smallmessage',
'fullmessage' => 'privacy:metadata:fullmessage'
], 'privacy:metadata:externalpurpose');
// This system is unaware of user preferences such as message_provider_moodle_instantmessage_loggedin.
// This system is unaware of user preferences such as message_provider_moodle_instantmessage_enabled.
return $collection;
}

View File

@ -115,8 +115,8 @@ class message_airnotifier_external extends external_api {
$users = $DB->get_recordset_sql($usersql, $params);
$result = array(
'users' => array(),
'warnings' => array()
'users' => [],
'warnings' => []
);
$hasuserupdatecap = has_capability('moodle/user:update', context_system::instance());
foreach ($users as $user) {
@ -126,7 +126,7 @@ class message_airnotifier_external extends external_api {
if ($currentuser or $hasuserupdatecap) {
if (!empty($user->deleted)) {
$warning = array();
$warning = [];
$warning['item'] = 'user';
$warning['itemid'] = $user->id;
$warning['warningcode'] = '1';
@ -135,7 +135,7 @@ class message_airnotifier_external extends external_api {
continue;
}
$preferences = array();
$preferences = [];
$preferences['userid'] = $user->id;
$preferences['configured'] = 0;
@ -149,33 +149,29 @@ class message_airnotifier_external extends external_api {
break;
}
foreach (array('loggedin', 'loggedoff') as $state) {
$prefstocheck = [];
$prefname = 'message_provider_'.$provider->component.'_'.$provider->name.'_enabled';
$prefstocheck = array();
$prefname = 'message_provider_'.$provider->component.'_'.$provider->name.'_'.$state;
// First get forced settings.
if ($forcedpref = get_config('message', $prefname)) {
$prefstocheck = array_merge($prefstocheck, explode(',', $forcedpref));
}
// First get forced settings.
if ($forcedpref = get_config('message', $prefname)) {
$prefstocheck = array_merge($prefstocheck, explode(',', $forcedpref));
}
// Then get user settings.
if ($userpref = get_user_preferences($prefname, '', $user->id)) {
$prefstocheck = array_merge($prefstocheck, explode(',', $userpref));
}
if (in_array('airnotifier', $prefstocheck)) {
$preferences['configured'] = 1;
$configured = true;
break;
}
// Then get user settings.
if ($userpref = get_user_preferences($prefname, '', $user->id)) {
$prefstocheck = array_merge($prefstocheck, explode(',', $userpref));
}
if (in_array('airnotifier', $prefstocheck)) {
$preferences['configured'] = 1;
$configured = true;
break;
}
}
$result['users'][] = $preferences;
} else if (!$hasuserupdatecap) {
$warning = array();
$warning = [];
$warning['item'] = 'user';
$warning['itemid'] = $user->id;
$warning['warningcode'] = '2';

View File

@ -82,10 +82,8 @@ class externallib_test extends externallib_advanced_testcase {
self::setUser($user1);
set_user_preference('message_provider_moodle_instantmessage_loggedin', 'airnotifier', $user1);
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'airnotifier', $user1);
set_user_preference('message_provider_moodle_instantmessage_loggedin', 'airnotifier', $user2);
set_user_preference('message_provider_moodle_instantmessage_loggedin', 'airnotifier', $user3);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'airnotifier', $user1);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'airnotifier', $user2);
$params = array($user1->id, $user2->id, $user3->id);
@ -112,23 +110,11 @@ class externallib_test extends externallib_advanced_testcase {
$this->assertEquals($expected, $preferences['users']);
$this->assertEquals(2, count($preferences['warnings']));
// Now, remove one user1 preference (the user still has one prefernce for airnotifier).
unset_user_preference('message_provider_moodle_instantmessage_loggedin', $user1);
// Now, remove one user1 preference (the user still has one preference for airnotifier).
unset_user_preference('message_provider_moodle_instantmessage_enabled', $user1);
$preferences = message_airnotifier_external::are_notification_preferences_configured($params);
$preferences = \external_api::clean_returnvalue($returnsdescription, $preferences);
$this->assertEquals($expected, $preferences['users']);
// Delete the last user1 preference.
unset_user_preference('message_provider_moodle_instantmessage_loggedoff', $user1);
$preferences = message_airnotifier_external::are_notification_preferences_configured($params);
$preferences = \external_api::clean_returnvalue($returnsdescription, $preferences);
$expected = array(
array(
'userid' => $user1->id,
'configured' => 1
)
);
$this->assertEquals($expected, $preferences['users']);
}
/**

View File

@ -204,7 +204,7 @@ class message_output_email extends message_output {
* @return int The default settings
*/
public function get_default_messaging_settings() {
return MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF;
return MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED;
}
/**

View File

@ -82,12 +82,11 @@ abstract class message_output {
/**
* Returns the message processors default settings
* Should the processor be enabled for logged in users by default?
* Should the processor be enabled for logged off users by default?
* Should the processor be enabled in users by default?
* Is enabling it disallowed, permitted or forced?
*
* @return int The Default message output settings expressed as a bit mask
* MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF + MESSAGE_DISALLOWED|MESSAGE_PERMITTED|MESSAGE_FORCED
* MESSAGE_DEFAULT_ENABLED + MESSAGE_PERMITTED
*/
public function get_default_messaging_settings() {
return MESSAGE_PERMITTED;

View File

@ -13,9 +13,8 @@ Feature: Notification popover unread notifications
| Course 1 | C1 | 0 | 1 |
# Make sure the popup notifications are enabled for assignments.
And the following config values are set as admin:
| popup_provider_mod_assign_assign_notification_permitted | permitted | message |
| message_provider_mod_assign_assign_notification_loggedin | popup | message |
| message_provider_mod_assign_assign_notification_loggedoff | popup | message |
| popup_provider_mod_assign_assign_notification_locked | 0 | message |
| message_provider_mod_assign_assign_notification_enabled | popup | message |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |

View File

@ -54,7 +54,6 @@ class core_message_renderer extends plugin_renderer_base {
$output .= $this->manage_messageoutputs($allprocessors);
// Add active message output processors settings.
$output .= $this->heading(get_string('managemessageoutputs', 'message'));
$output .= $this->manage_defaultmessageoutputs($processors, $providers, $preferences);
$output .= html_writer::start_tag('div', array('class' => 'form-buttons'));
@ -84,7 +83,7 @@ class core_message_renderer extends plugin_renderer_base {
get_string('settings'),
);
$table->colclasses = array(
'displayname', 'availability', 'settings',
'displayname', 'availability text-center', 'settings',
);
foreach ($processors as $processor) {
@ -124,97 +123,99 @@ class core_message_renderer extends plugin_renderer_base {
* @return string The text to render
*/
public function manage_defaultmessageoutputs($processors, $providers, $preferences) {
// Prepare list of options for dropdown menu
$options = array();
foreach (array('disallowed', 'permitted', 'forced') as $setting) {
$options[$setting] = get_string($setting, 'message');
}
$context = [];
// Display users outputs table
$table = new html_table();
$table->attributes['class'] = 'generaltable';
$table->data = array();
$table->head = array('');
// Populate the header row
foreach ($processors as $processor) {
$table->head[] = get_string('pluginname', 'message_'.$processor->name);
$processor->displayname = get_string('pluginname', 'message_'.$processor->name);
}
// Add enable/disable to head
$table->head[] = get_string('enabled', 'core_message');
// Generate the matrix of settings for each provider and processor
$activitycomponents = [];
$othercomponents = [];
foreach ($providers as $provider) {
$row = new html_table_row();
$row->attributes['class'] = 'defaultmessageoutputs';
$row->cells = array();
// Provider Name
$providername = get_string('messageprovider:'.$provider->name, $provider->component);
$row->cells[] = new html_table_cell($providername);
$provider->displayname = get_string('messageprovider:'.$provider->name, $provider->component);
$providersettingprefix = $provider->component.'_'.$provider->name.'_';
$disableprovidersetting = $providersettingprefix.'disable';
$providerdisabled = !empty($preferences->$disableprovidersetting);
$provider->enabledsetting = $providersettingprefix.'disable';
$provider->enabled = empty($preferences->{$provider->enabledsetting});
$provider->enabledlabel = get_string('providerenabled', 'message', $provider->displayname);
$provider->settings = [];
// Settings for each processor
foreach ($processors as $processor) {
$cellcontent = '';
foreach (array('permitted', 'loggedin', 'loggedoff') as $setting) {
// pepare element and preference names
$elementname = $providersettingprefix.$setting.'['.$processor->name.']';
$preferencebase = $providersettingprefix.$setting;
// prepare language bits
$processorname = get_string('pluginname', 'message_'.$processor->name);
$statename = get_string($setting, 'message');
$labelparams = array(
'provider' => $providername,
'processor' => $processorname,
'state' => $statename
);
if ($setting == 'permitted') {
$label = get_string('sendingvia', 'message', $labelparams);
// determine the current setting or use default
$select = MESSAGE_DEFAULT_PERMITTED;
$preference = $processor->name.'_provider_'.$preferencebase;
if ($providerdisabled) {
$select = MESSAGE_DISALLOWED;
} else if (property_exists($preferences, $preference)) {
$select = $preferences->{$preference};
}
// dropdown menu
$cellcontent = html_writer::label($label, $elementname, true, array('class' => 'accesshide'));
$cellcontent .= html_writer::select($options, $elementname, $select, false, array('id' => $elementname));
$cellcontent .= html_writer::tag('div', get_string('defaults', 'message'));
} else {
$label = get_string('sendingviawhen', 'message', $labelparams);
// determine the current setting based on the 'permitted' setting above
$checked = false;
if ($select == 'forced') {
$checked = true;
} else if ($select == 'permitted') {
$preference = 'message_provider_'.$preferencebase;
if (property_exists($preferences, $preference)) {
$checked = (int)in_array($processor->name, explode(',', $preferences->{$preference}));
}
}
// generate content
$cellcontent .= html_writer::start_tag('div');
$cellcontent .= html_writer::label($label, $elementname, true, array('class' => 'accesshide'));
$cellcontent .= html_writer::checkbox($elementname, 1, $checked, '', array('id' => $elementname));
$cellcontent .= $statename;
$cellcontent .= html_writer::end_tag('div');
}
$setting = new StdClass();
$setting->lockedsetting = $providersettingprefix.'locked['.$processor->name.']';
$preference = $processor->name.'_provider_'.$providersettingprefix.'locked';
$setting->locked = false;
if (property_exists($preferences, $preference)) {
$setting->locked = $preferences->{$preference} == 1;
}
$setting->enabledsetting = $providersettingprefix.'enabled['.$processor->name.']';
$preference = 'message_provider_'.$providersettingprefix.'enabled';
$setting->enabled = false;
if (property_exists($preferences, $preference)) {
$setting->enabled = (int)in_array($processor->name, explode(',', $preferences->{$preference}));
}
$labelparams = [
'provider' => $provider->displayname,
'processor' => $processor->displayname,
];
$setting->enabledlabel = get_string('sendingviaenabled', 'message', $labelparams);
$setting->lockedlabel = get_string('sendingvialocked', 'message', $labelparams);
$provider->settings[] = $setting;
}
// Order the components so that the activities appear first, followed
// by the system and then anything else.
if ($provider->component != 'moodle') {
if (substr($provider->component, 0, 4) == 'mod_') {
// Activities.
$activitycomponents[] = $provider->component;
} else {
// Other stuff.
$othercomponents[] = $provider->component;
}
$row->cells[] = new html_table_cell($cellcontent);
}
$disableprovider = html_writer::checkbox($disableprovidersetting, 1, !$providerdisabled, '',
array('id' => $disableprovidersetting, 'class' => 'messagedisable'));
$disableprovider = html_writer::tag('div', $disableprovider);
$row->cells[] = new html_table_cell($disableprovider);
$table->data[] = $row;
}
$output = html_writer::table($table);
return $output;
$activitycomponents = array_unique($activitycomponents);
asort($activitycomponents);
$othercomponents = array_unique($othercomponents);
asort($othercomponents);
$components = array_merge($activitycomponents, ['moodle'], $othercomponents);
asort($providers);
$colspan = count($processors) + 2;
$componentsexport = [];
foreach ($components as $component) {
$componentexport = new StdClass();
$componentexport->name = $component;
if ($component != 'moodle') {
$componentexport->displayname = get_string('pluginname', $component);
} else {
$componentexport->displayname = get_string('coresystem');
}
$componentexport->providers = [];
foreach ($providers as $provider) {
if ($provider->component == $component) {
$componentexport->providers[] = $provider;
}
}
$componentexport->colspan = $colspan;
$componentsexport[] = $componentexport;
}
$context['processors'] = array_values($processors);
$context['components'] = $componentsexport;
return $this->render_from_template('message/default_notification_preferences', $context);
}
/**

View File

@ -0,0 +1,150 @@
{{!
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/>.
}}
{{!
@template core_message/default_notification_preferences
This template will render the default notification preferences for admin settings.
Classes required for JS:
* none
Data attributes required for JS:
* All data attributes are required
Context variables required for this template:
* providers Message providers
* components Provider components
* processors Message processors
* preferences Saved preferences
Example context (json):
{
"processors": [
{
"displayname": "Web",
"name": "popup"
}
],
"components": [
{
"displayname": "Assignment",
"name": "mod_assign",
"colspan": 3,
"providers": [
{
"name": "assign_notification",
"component": "mod_assign",
"displayname": "Assignment notifications",
"enabledsetting": "mod_assign_assign_notification_disable",
"enabledlabel": "Sending Assignment enabled status",
"enabled": 1,
"settings": [
{
"lockedsetting": "mod_assign_assign_notification_locked[popup]",
"locked": 1,
"lockedlabel": "Sending Assignment via Web locked status",
"enabledsetting": "mod_assign_assign_notification_enabled[popup]",
"enabled": 1,
"enabledlabel": "Sending Assignment via Web enabled status"
}
]
}
]
}
]
}
}}
<div class="preferences-page-container">
<h2>{{#str}} managemessageoutputs, message {{/str}}</h2>
<div class="preferences-container">
<table class="table table-hover preference-table">
<thead>
<tr>
<th></th>
<th>{{#str}} enabled, core_message {{/str}}</th>
{{#processors}}
<th data-processor-name="{{name}}">{{{displayname}}}</th>
{{/processors}}
</tr>
</thead>
<tbody>
{{#components}}
<tr class="preference-row"><th colspan="{{{colspan}}}">{{{displayname}}}</th></tr>
{{#providers}}
<tr class="defaultmessageoutputs">
<td>{{{displayname}}}</td>
<td>
<div data-preference="{{{enabledsetting}}}">
<div class="custom-control custom-switch">
<input type="checkbox"
id="{{{enabledsetting}}}"
name="{{{enabledsetting}}}"
class="custom-control-input provider_enabled"
{{#enabled}}checked{{/enabled}}
>
<label for="{{{enabledsetting}}}" class="custom-control-label"
title="{{enabledlabel}}">
<span class="accesshide">{{enabledlabel}}</span>
</label>
</div>
</div>
</td>
{{#settings}}
<td class="text-left">
<div data-preference="{{{enabledsetting}}}">
<div class="custom-control custom-switch {{#locked}} dimmed_text{{/locked}} pb-1">
<input type="checkbox"
id="{{{enabledsetting}}}"
name="{{{enabledsetting}}}"
class="custom-control-input enabled_message_setting"
{{#enabled}}checked{{/enabled}}
>
<label for="{{{enabledsetting}}}" class="custom-control-label"
title="{{enabledlabel}}">
{{#str}} enabled, core_message {{/str}}
</label>
</div>
</div>
<div data-preference="{{{lockedsetting}}}">
<div class="custom-control custom-switch pt-1">
<input type="checkbox"
id="{{{lockedsetting}}}"
name="{{{lockedsetting}}}"
class="custom-control-input locked_message_setting"
{{#locked}}checked{{/locked}}
>
<label for="{{{lockedsetting}}}" class="custom-control-label"
title="{{lockedlabel}}">
{{#str}} forced, core_message {{/str}}
</label>
</div>
</div>
</td>
{{/settings}}
</tr>
{{/providers}}
{{/components}}
</tbody>
</table>
</div>
</div>
{{#js}}
require(['core_message/default_notification_preferences'], function(NotificationPreferences) {
NotificationPreferences.init();
});
{{/js}}

View File

@ -41,26 +41,13 @@
{
"displayname": "Notices about minor problems",
"preferencekey": "message_provider_moodle_notices",
"onlinehelphtml": "<p>some help HTML</p>",
"offlinehelphtml": "<p>some help HTML</p>",
"processors": [
{
"displayname": "Popup notification",
"name": "popup",
"locked": 0,
"userconfigured": 1,
"loggedin": {
"name": "loggedin",
"displayname": "When I'm logged in",
"checked": 0,
"disableall": 0
},
"loggedoff": {
"name": "loggedoff",
"displayname": "When I'm offline",
"checked": 0,
"disableall": 0
}
"enabled": 1
}
]
}

View File

@ -34,26 +34,13 @@
{
"displayname": "Notices about minor problems",
"preferencekey": "message_provider_moodle_notices",
"onlinehelphtml": "<p>some help HTML</p>",
"offlinehelphtml": "<p>some help HTML</p>",
"processors": [
{
"displayname": "Popup notification",
"name": "popup",
"locked": 0,
"userconfigured": 1,
"loggedin": {
"name": "loggedin",
"displayname": "When I'm logged in",
"checked": 0,
"disableall": 0
},
"loggedoff": {
"name": "loggedoff",
"displayname": "When I'm offline",
"checked": 0,
"disableall": 0
}
"enabled": 1
}
]
}
@ -64,18 +51,7 @@
<tr data-preference-key="{{preferencekey}}">
<th>{{displayname}}</th>
<td class="align-bottom">
<div class="container-fluid">
<div class="row">
<div class="span6 col-6">
{{#str}} loggedin, message {{/str}}
{{#onlinehelphtml}}{{{.}}}{{/onlinehelphtml}}
</div>
<div class="span6 col-6">
{{#str}} loggedoff, message {{/str}}
{{#offlinehelphtml}}{{{.}}}{{/offlinehelphtml}}
</div>
</div>
</div>
{{#str}} enabled, core_message {{/str}}
</td>
</tr>
{{#processors}}

View File

@ -40,16 +40,7 @@
"name": "popup",
"locked": 0,
"userconfigured": 1,
"loggedin": {
"name": "loggedin",
"displayname": "When I'm logged in",
"checked": 0
},
"loggedoff": {
"name": "loggedoff",
"displayname": "When I'm offline",
"checked": 0
}
"enabled": 1
}
]
}

View File

@ -34,15 +34,19 @@
{
"userid": 1,
"disableall": 0,
"processors": [
{
"displayname": "Popup notification",
"name": "popup",
"hassettings": 1,
"userid": 3,
"contextid": 3
}
],
"components": [
{
"displayname": "System",
"processors": [
{
"onlinehelphtml": "<p>help button HTML</p>",
"offlinehelphtml": "<p>help button HTML</p>"
}
],
"colspan": 2,
"notifications": [
{
"displayname": "Notices about minor problems",
@ -53,18 +57,8 @@
"name": "popup",
"locked": 0,
"userconfigured": 1,
"loggedin": {
"name": "loggedin",
"displayname": "When I'm logged in",
"checked": 0,
"disableall": 0
},
"loggedoff": {
"name": "loggedoff",
"displayname": "When I'm offline",
"checked": 0,
"disableall": 0
}
"enabled": 1,
"enabledlabel": "Sending Assignment enabled status"
}
]
}
@ -87,7 +81,7 @@
<table class="table preference-table">
<thead>
<tr>
<th>{{displayname}}</th>
<th>{{{displayname}}}</th>
{{#processors}}
{{> message/notification_preferences_processor }}
{{/processors}}
@ -103,8 +97,8 @@
</div>
{{#js}}
require(['jquery', 'core_message/preferences_notifications_list_controller'],
function($, controller) {
function($, Controller) {
new controller($('.preferences-container'));
new Controller($('.preferences-container'));
});
{{/js}}

View File

@ -33,12 +33,7 @@
Example context (json):
{
"displayname": "System",
"processors": [
{
"onlinehelphtml": "<p>help button HTML</p>",
"offlinehelphtml": "<p>help button HTML</p>"
}
],
"colspan": 2,
"notifications": [
{
"displayname": "Notices about minor problems",
@ -49,18 +44,8 @@
"name": "popup",
"locked": 0,
"userconfigured": 1,
"loggedin": {
"name": "loggedin",
"displayname": "When I'm logged in",
"checked": 0,
"disableall": 0
},
"loggedoff": {
"name": "loggedoff",
"displayname": "When I'm offline",
"checked": 0,
"disableall": 0
}
"enabled": 0,
"enabledlabel": "Sending Assignment enabled status"
}
]
}
@ -68,23 +53,7 @@
}
}}
<tr>
<th><h4>{{displayname}}</h4></th>
{{#processors}}
<td class="align-bottom">
<div class="container-fluid">
<div class="row">
<div class="col-6">
{{#str}} loggedin, message {{/str}}
{{#onlinehelphtml}}{{{.}}}{{/onlinehelphtml}}
</div>
<div class="col-6">
{{#str}} loggedoff, message {{/str}}
{{#offlinehelphtml}}{{{.}}}{{/offlinehelphtml}}
</div>
</div>
</div>
</td>
{{/processors}}
<th colspan="{{{colspan}}}">{{{displayname}}}</th>
</tr>
{{#notifications}}
{{> message/notification_preferences_component_notification }}

View File

@ -40,70 +40,33 @@
"name": "popup",
"locked": 0,
"userconfigured": 1,
"loggedin": {
"name": "loggedin",
"displayname": "When I'm logged in",
"checked": 0
},
"loggedoff": {
"name": "loggedoff",
"displayname": "When I'm offline",
"checked": 0
}
"enabled": 1,
"enabledlabel": "Sending Assignment enabled status"
}
]
}
}}
<tr class="preference-row" data-region="preference-row" data-preference-key="{{preferencekey}}">
<td class="preference-name">{{displayname}}</td>
<tr class="preference-row" data-region="preference-row" data-preference-key="{{{preferencekey}}}">
<td class="preference-name">{{{displayname}}}</td>
{{#processors}}
<td {{^userconfigured}}class="disabled"{{/userconfigured}} data-processor-name="{{name}}">
<td {{^userconfigured}}class="disabled"{{/userconfigured}} data-processor-name="{{name}}">
{{#locked}}
<div class="dimmed_text">{{lockedmessage}}</div>
<div class="dimmed_text" title="{{lockedlabel}}">{{{lockedmessage}}}</div>
{{/locked}}
{{^locked}}
<div class="disabled-message">{{#str}} disabled, admin {{/str}}</div>
<form>
<div class="container-fluid">
<div class="row">
<div class="col-6">
{{#loggedin}}
{{< core/hover_tooltip }}
{{$anchor}}
<label class="custom-control custom-switch"
title="{{displayname}}"
data-state="{{name}}">
<span class="accesshide">{{displayname}}</span>
<input type="checkbox"
class="custom-control-input"
{{#checked}}checked{{/checked}}
{{#disableall}}disabled{{/disableall}} />
<span class="custom-control-label d-block"></span>
</label>
{{/anchor}}
{{$tooltip}}{{displayname}}{{/tooltip}}
{{/ core/hover_tooltip }}
{{/loggedin}}
</div>
<div class="col-6">
{{#loggedoff}}
{{< core/hover_tooltip }}
{{$anchor}}
<label class="custom-control custom-switch"
title="{{displayname}}"
data-state="{{name}}">
<span class="accesshide">{{displayname}}</span>
<input type="checkbox"
class="custom-control-input"
{{#checked}}checked{{/checked}}
{{#disableall}}disabled{{/disableall}} />
<span class="custom-control-label d-block"></span>
</label>
{{/anchor}}
{{$tooltip}}{{displayname}}{{/tooltip}}
{{/ core/hover_tooltip }}
{{/loggedoff}}
</div>
<div class="preference-state" data-preference="{{{preferencekey}}}_{{{name}}}">
<div class="custom-control custom-switch">
<input type="checkbox"
id="{{{preferencekey}}}_{{{name}}}"
name="{{{preferencekey}}}_{{{name}}}"
class="custom-control-input notification_enabled"
{{#enabled}}checked{{/enabled}}
>
<label for="{{{preferencekey}}}_{{{name}}}" class="custom-control-label"
title="{{enabledlabel}}">
{{#str}} enabled, core_message {{/str}}
</label>
</div>
</div>
</form>

View File

@ -2967,15 +2967,15 @@ class core_message_api_test extends core_message_messagelib_testcase {
$this->setUser($user);
// Set a couple of preferences to test.
set_user_preference('message_provider_mod_assign_assign_notification_loggedin', 'popup', $user);
set_user_preference('message_provider_mod_assign_assign_notification_loggedoff', 'email', $user);
set_user_preference('message_provider_mod_assign_assign_notification_enabled', 'popup', $user);
set_user_preference('message_provider_mod_feedback_submission_enabled', 'email', $user);
$processors = get_message_processors();
$providers = message_get_providers_for_user($user->id);
$prefs = \core_message\api::get_all_message_preferences($processors, $providers, $user);
$this->assertEquals(1, $prefs->mod_assign_assign_notification_loggedin['popup']);
$this->assertEquals(1, $prefs->mod_assign_assign_notification_loggedoff['email']);
$this->assertEquals(1, $prefs->mod_assign_assign_notification_enabled['popup']);
$this->assertEquals(1, $prefs->mod_feedback_submission_enabled['email']);
}
/**

View File

@ -8,6 +8,7 @@ Feature: Manage notification preferences - Email
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | 1 | student1@example.com |
| student2 | Student | 2 | student2@example.com |
And the following config values are set as admin:
| messaging | 1 |
@ -27,8 +28,7 @@ Feature: Manage notification preferences - Email
# Disable email default value
Given the following "user preferences" exist:
| user | preference | value |
| student1 | message_provider_moodle_instantmessage_loggedin | none |
| student1 | message_provider_moodle_instantmessage_loggedoff | none |
| student1 | message_provider_moodle_instantmessage_enabled | none |
When I log in as "admin"
And I navigate to "Messaging > Notification settings" in site administration
And I set the field "email" to "1"
@ -61,3 +61,142 @@ Feature: Manage notification preferences - Email
And I follow "Preferences" in the user menu
And I click on "Message preferences" "link"
And the field "Email" matches value "0"
Scenario: Disable email notifications for Assignment notifications
Given I log in as "admin"
When I navigate to "Messaging > Notification settings" in site administration
And I set the field "email" to "1"
And I press "Save changes"
Then the field "email" matches value "1"
And I set the field "mod_assign_assign_notification_disable" to "0"
And I press "Save changes"
And the field "mod_assign_assign_notification_disable" matches value "0"
And I follow "Preferences" in the user menu
And I click on "Notification preferences" "link" in the "#page-content" "css_element"
And I should not see "Assignment notifications"
Scenario: Lock email notifications for Forum providers
Given I log in as "admin"
When I navigate to "Messaging > Notification settings" in site administration
And I set the field "email" to "1"
And I press "Save changes"
Then the field "email" matches value "1"
And I set the field "mod_forum_posts_enabled[email]" to "1"
And I set the field "mod_forum_posts_locked[email]" to "1"
And I set the field "mod_forum_digests_enabled[email]" to "0"
And I set the field "mod_forum_digests_locked[email]" to "1"
And I press "Save changes"
And the field "mod_forum_posts_enabled[email]" matches value "1"
And the field "mod_forum_posts_locked[email]" matches value "1"
And the field "mod_forum_digests_enabled[email]" matches value "0"
And the field "mod_forum_digests_locked[email]" matches value "1"
And I follow "Preferences" in the user menu
And I click on "Notification preferences" "link" in the "#page-content" "css_element"
And I should see "Locked" in the "[data-preference-key=message_provider_mod_forum_posts]" "css_element"
And I should see "Disallowed" in the "[data-preference-key=message_provider_mod_forum_digests]" "css_element"
Scenario: User can disable notification preferences
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student2 | C1 | student |
And the following config values are set as admin:
| popup_provider_mod_assign_assign_notification_locked | 0 | message |
| message_provider_mod_assign_assign_notification_enabled | popup | message |
And the following "user preferences" exist:
| user | preference | value |
| student1 | message_provider_mod_assign_assign_notification_enabled | none |
| student2 | message_provider_mod_assign_assign_notification_enabled | popup |
And the following "activity" exists:
| activity | assign |
| course | C1 |
| name | Test assignment name |
| assignsubmission_onlinetext_enabled | 1 |
| assignsubmission_file_enabled | 0 |
| submissiondrafts | 0 |
# This should generate a notification.
And the following "mod_assign > submissions" exist:
| assign | user | onlinetext |
| Test assignment name | student1 | I'm the student1 submission |
| Test assignment name | student2 | I'm the student2 submission |
When I log in as "student1"
# Confirm the popover is not showing any unread notifications.
Then I should not see "1" in the "#nav-notification-popover-container [data-region='count-container']" "css_element"
# Open the popover.
And I open the notification popover
# Confirm the submission notification is NOT visible.
And I should not see "You have submitted your assignment submission for Test assignment name" in the "#nav-notification-popover-container" "css_element"
And I log in as "student2"
# Confirm the popover is showing the unread notifications.
Then I should see "1" in the "#nav-notification-popover-container [data-region='count-container']" "css_element"
# Open the popover.
And I open the notification popover
# Confirm the submission notification is visible.
And I should see "You have submitted your assignment submission for Test assignment name" in the "#nav-notification-popover-container" "css_element"
Scenario: User cannot disable forced notification preferences
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
And the following config values are set as admin:
| popup_provider_mod_assign_assign_notification_locked | 1 | message |
| message_provider_mod_assign_assign_notification_enabled | popup | message |
And the following "user preferences" exist:
| user | preference | value |
| student1 | message_provider_mod_assign_assign_notification_enabled | none |
And the following "activity" exists:
| activity | assign |
| course | C1 |
| name | Test assignment name |
| assignsubmission_onlinetext_enabled | 1 |
| assignsubmission_file_enabled | 0 |
| submissiondrafts | 0 |
# This should generate a notification.
And the following "mod_assign > submissions" exist:
| assign | user | onlinetext |
| Test assignment name | student1 | I'm the student1 submission |
When I log in as "student1"
# Confirm the popover is saying 1 unread notifications.
Then I should see "1" in the "#nav-notification-popover-container [data-region='count-container']" "css_element"
# Open the popover.
And I open the notification popover
# Confirm the submission notification is visible.
And I should see "You have submitted your assignment submission for Test assignment name" in the "#nav-notification-popover-container" "css_element"
Scenario: User cannot disable disallowed notification preferences
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
And the following config values are set as admin:
| popup_provider_mod_assign_assign_notification_locked | 1 | message |
| message_provider_mod_assign_assign_notification_enabled | none | message |
And the following "user preferences" exist:
| user | preference | value |
| student1 | message_provider_mod_assign_assign_notification_enabled | popup |
And the following "activity" exists:
| activity | assign |
| course | C1 |
| name | Test assignment name |
| assignsubmission_onlinetext_enabled | 1 |
| assignsubmission_file_enabled | 0 |
| submissiondrafts | 0 |
# This should generate a notification.
And the following "mod_assign > submissions" exist:
| assign | user | onlinetext |
| Test assignment name | student1 | I'm the student1 submission |
When I log in as "student1"
# Confirm the popover is not showing any unread notifications.
Then I should not see "1" in the "#nav-notification-popover-container [data-region='count-container']" "css_element"
# Open the popover.
And I open the notification popover
# Confirm the submission notification is NOT visible.
And I should not see "You have submitted your assignment submission for Test assignment name" in the "#nav-notification-popover-container" "css_element"

View File

@ -9,8 +9,7 @@ Feature: To be able to see and save user message preferences as admin
| student1 | Student | 1 | student1@emample.com |
And the following "user preferences" exist:
| user | preference | value |
| student1 | message_provider_moodle_instantmessage_loggedin | none |
| student1 | message_provider_moodle_instantmessage_loggedoff | email |
| student1 | message_provider_moodle_instantmessage_enabled | email |
@javascript
Scenario: As an admin I can view and edit message preferences for a user
@ -22,7 +21,7 @@ Feature: To be able to see and save user message preferences as admin
And I click on "Student 1" "link" in the "Student 1" "table_row"
And I click on "Preferences" "link" in the "#region-main-box" "css_element"
And I click on "Message preferences" "link" in the "#region-main-box" "css_element"
And I click on "//label[@data-state='loggedoff']" "xpath_element"
And I click on "//div[@class='preference-state']" "xpath_element"
And I log out
And I log in as "student1"
And I follow "Preferences" in the user menu

View File

@ -1980,8 +1980,7 @@ class externallib_test extends externallib_advanced_testcase {
$this->setUser($user);
// Set a couple of preferences to test.
set_user_preference('message_provider_mod_assign_assign_notification_loggedin', 'popup', $user);
set_user_preference('message_provider_mod_assign_assign_notification_loggedoff', 'email', $user);
set_user_preference('message_provider_mod_assign_assign_notification_enabled', 'popup', $user);
$prefs = core_message_external::get_user_notification_preferences();
$prefs = \external_api::clean_returnvalue(core_message_external::get_user_notification_preferences_returns(), $prefs);
@ -2001,16 +2000,13 @@ class externallib_test extends externallib_advanced_testcase {
}
foreach ($prefdata['processors'] as $processor) {
if ($processor['name'] == 'popup') {
$this->assertTrue($processor['loggedin']['checked']);
$found++;
} else if ($processor['name'] == 'email') {
$this->assertTrue($processor['loggedoff']['checked']);
$found++;
$this->assertTrue($processor['enabled']);
$found = 1;
}
}
}
}
$this->assertEquals(2, $found);
$this->assertEquals(1, $found);
}
/**
@ -3494,8 +3490,7 @@ class externallib_test extends externallib_advanced_testcase {
set_config('messagingallusers', true);
// Set a couple of preferences to test.
set_user_preference('message_provider_moodle_instantmessage_loggedin', 'email', $user);
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'email', $user);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'email', $user);
set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_SITE, $user);
$prefs = core_message_external::get_user_message_preferences();
@ -3515,8 +3510,7 @@ class externallib_test extends externallib_advanced_testcase {
}
foreach ($prefdata['processors'] as $processor) {
if ($processor['name'] == 'email') {
$this->assertTrue($processor['loggedin']['checked']);
$this->assertTrue($processor['loggedoff']['checked']);
$this->assertTrue($processor['enabled']);
$found = true;
}
}

View File

@ -170,11 +170,12 @@ class provider_test extends \core_privacy\tests\provider_testcase {
$user = $this->getDataGenerator()->create_user();
// Set some message user preferences.
set_user_preference('message_provider_moodle_instantmessage_loggedin', 'airnotifier', $USER->id);
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'popup', $USER->id);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'airnotifier', $USER->id);
set_user_preference('message_provider_mod_feedback_submission_enabled', 'popup', $USER->id);
set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $USER->id);
set_user_preference('message_entertosend', true, $USER->id);
set_user_preference('message_provider_moodle_instantmessage_loggedoff', 'inbound', $user->id);
set_user_preference('message_provider_moodle_instantmessage_enabled', 'inbound', $user->id);
// Set an unrelated preference.
set_user_preference('some_unrelated_preference', 'courses', $USER->id);
@ -189,15 +190,15 @@ class provider_test extends \core_privacy\tests\provider_testcase {
// Check only 3 preferences exist.
$this->assertCount(4, $prefs);
$this->assertArrayHasKey('message_provider_moodle_instantmessage_loggedin', $prefs);
$this->assertArrayHasKey('message_provider_moodle_instantmessage_loggedoff', $prefs);
$this->assertArrayHasKey('message_provider_moodle_instantmessage_enabled', $prefs);
$this->assertArrayHasKey('message_provider_mod_feedback_submission_enabled', $prefs);
$this->assertArrayHasKey('message_blocknoncontacts', $prefs);
$this->assertArrayHasKey('message_entertosend', $prefs);
foreach ($prefs as $key => $pref) {
if ($key == 'message_provider_moodle_instantmessage_loggedin') {
if ($key == 'message_provider_moodle_instantmessage_enabled') {
$this->assertEquals('airnotifier', $pref->value);
} else if ($key == 'message_provider_moodle_instantmessage_loggedoff') {
} else if ($key == 'message_provider_mod_feedback_submission_enabled') {
$this->assertEquals('popup', $pref->value);
} else {
$this->assertEquals(1, $pref->value);

View File

@ -27,7 +27,7 @@ $messageproviders = array (
// Ordinary single forum posts.
'posts' => array(
'defaults' => array(
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
),
),

View File

@ -865,8 +865,7 @@ class mod_forum_mail_testcase extends advanced_testcase {
$this->helper_spoof_message_inbound_setup();
$author->emailstop = '0';
set_user_preference('message_provider_mod_forum_posts_loggedoff', 'email', $author);
set_user_preference('message_provider_mod_forum_posts_loggedin', 'email', $author);
set_user_preference('message_provider_mod_forum_posts_enabled', 'email', $author);
// Run cron and check that the expected number of users received the notification.
// Clear the mailsink, and close the messagesink.

View File

@ -28,11 +28,8 @@ $messageproviders = array (
// essay graded notification
'graded_essay' => array (
'defaults' => array(
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
),
)
);

View File

@ -34,7 +34,7 @@ $messageproviders = array(
'confirmation' => array(
'capability' => 'mod/quiz:emailconfirmsubmission',
'defaults' => array(
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
),
),
@ -43,14 +43,14 @@ $messageproviders = array(
'attempt_overdue' => array(
'capability' => 'mod/quiz:emailwarnoverdue',
'defaults' => array(
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
),
),
'attempt_grading_complete' => [
'capability' => 'mod/quiz:emailnotifyattemptgraded',
'defaults' => [
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,
'airnotifier' => MESSAGE_PERMITTED + MESSAGE_DEFAULT_ENABLED,
],
],
);

View File

@ -415,6 +415,18 @@ class core_user_external extends external_api {
if (!empty($preferences)) {
$userpref = ['id' => $userid];
foreach ($preferences as $preference) {
/*
* Rename user message provider preferences to avoid orphan settings on old app versions.
* @todo Remove this "translation" block on MDL-73284.
*/
if (preg_match('/message_provider_.*_loggedin/', $preference['type']) ||
preg_match('/message_provider_.*_loggedoff/', $preference['type'])) {
$nameparts = explode('_', $preference['type']);
array_pop($nameparts);
$preference['type'] = implode('_', $nameparts).'_enabled';
}
$userpref['preference_' . $preference['type']] = $preference['value'];
}
useredit_update_user_preference($userpref);

View File

@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
$version = 2022012100.01; // YYYYMMDD = weekly release date of this DEV branch.
$version = 2022012100.02; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
$release = '4.0dev+ (Build: 20220121)'; // Human-friendly version name