MDL-85777 message: Disable message input when sending isn’t allowed
This commit is contained in:
@@ -86,3 +86,4 @@ maxsectionslimit,core
|
||||
maxsectionaddmessage,core_courseformat
|
||||
activities_help,core
|
||||
resources_help,core
|
||||
unabletomessage,core_message
|
||||
|
||||
@@ -39,6 +39,7 @@ $string['blockuserconfirm'] = 'Are you sure you want to block {$a}?';
|
||||
$string['blockuserconfirmbutton'] = 'Block';
|
||||
$string['blocknoncontacts'] = 'Prevent non-contacts from messaging me';
|
||||
$string['cancelselection'] = 'Cancel message selection';
|
||||
$string['cannotsendmessages'] = 'Cannot send messages';
|
||||
$string['cantblockuser'] = 'You can\'t block {$a} because they have a role with permission to message all users.';
|
||||
$string['contactableprivacy'] = 'Accept messages from:';
|
||||
$string['contactableprivacy_onlycontacts'] = 'My contacts only';
|
||||
@@ -128,6 +129,7 @@ $string['nocontactsgetstarted'] = 'No contacts';
|
||||
$string['nogroupconversations'] = 'No group conversations';
|
||||
$string['noindividualconversations'] = 'No private conversations';
|
||||
$string['nomessagesfound'] = 'No messages were found';
|
||||
$string['nopermissiontosend'] = 'You do not have permission to send messages in this conversation';
|
||||
$string['noreply'] = 'Do not reply to this message';
|
||||
$string['noncontacts'] = 'Non-contacts';
|
||||
$string['nonotifications'] = 'You have no notifications';
|
||||
@@ -253,7 +255,6 @@ $string['successproviderupdate'] = '\'{$a}\' updated.';
|
||||
$string['togglemessagemenu'] = 'Toggle messaging drawer';
|
||||
$string['totalconversations'] = '{$a} total conversations';
|
||||
$string['touserdoesntexist'] = 'You cannot send a message to a user ID ({$a}) that doesn\'t exist.';
|
||||
$string['unabletomessage'] = 'You are unable to message this user';
|
||||
$string['unblock'] = 'Unblock';
|
||||
$string['unblockcontact'] = 'Unblock contact';
|
||||
$string['unblockuser'] = 'Unblock user';
|
||||
@@ -283,3 +284,6 @@ $string['yourcontactrequestpending'] = 'Your contact request is pending with {$a
|
||||
|
||||
// Deprecated since Moodle 5.0.
|
||||
$string['togglenotificationmenu'] = 'Toggle notifications menu';
|
||||
|
||||
// Deprecated since Moodle 5.1.
|
||||
$string['unabletomessage'] = 'You are unable to message this user';
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -362,6 +362,7 @@ function(
|
||||
newState = StateManager.setIsMuted(newState, conversation.ismuted);
|
||||
newState = StateManager.addMessages(newState, conversation.messages);
|
||||
newState = StateManager.setCanDeleteMessagesForAllUsers(newState, conversation.candeletemessagesforallusers);
|
||||
newState = StateManager.setCanSendMessageToConversation(newState, conversation.cansendmessagetoconversation);
|
||||
return newState;
|
||||
};
|
||||
|
||||
|
||||
@@ -62,7 +62,6 @@ define([], function() {
|
||||
CONTENT_MESSAGES_FOOTER_EDIT_MODE_CONTAINER: '[data-region="content-messages-footer-edit-mode-container"]',
|
||||
CONTENT_MESSAGES_FOOTER_REQUIRE_CONTACT_CONTAINER: '[data-region="content-messages-footer-require-contact-container"]',
|
||||
CONTENT_MESSAGES_FOOTER_REQUIRE_UNBLOCK_CONTAINER: '[data-region="content-messages-footer-require-unblock-container"]',
|
||||
CONTENT_MESSAGES_FOOTER_UNABLE_TO_MESSAGE_CONTAINER: '[data-region="content-messages-footer-unable-to-message"]',
|
||||
DAY_MESSAGES_CONTAINER: '[data-region="day-messages-container"]',
|
||||
DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE: '[data-region="delete-messages-for-all-users-toggle"]',
|
||||
DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE_CONTAINER: '[data-region="delete-messages-for-all-users-toggle-container"]',
|
||||
@@ -97,7 +96,9 @@ define([], function() {
|
||||
TEXT_CONTAINER: '[data-region="text-container"]',
|
||||
TIME_CREATED: '[data-region="time-created"]',
|
||||
TITLE: '[data-region="title"]',
|
||||
TOGGLE_EMOJI_PICKER_BUTTON: '[data-action="toggle-emoji-picker"]'
|
||||
TOGGLE_EMOJI_PICKER_BUTTON: '[data-action="toggle-emoji-picker"]',
|
||||
DAY_MESSAGE_UNABLE_TO_SEND_CONTAINER: '[data-region="day-message-unable-to-send-container"]',
|
||||
UNABLE_TO_MESSAGE_CONTAINER: '[data-region="unable-to-send-container"]',
|
||||
};
|
||||
|
||||
var TEMPLATES = {
|
||||
|
||||
@@ -374,7 +374,8 @@ function(
|
||||
// Handle adding or removing whole days.
|
||||
days: buildDaysPatch(current, daysDiff.missingFromB, daysDiff.missingFromA),
|
||||
// Handle updating messages that don't require adding/removing a whole day.
|
||||
messages: buildMessagesPatch(daysDiff.matches)
|
||||
messages: buildMessagesPatch(daysDiff.matches),
|
||||
unableToMessage: buildUnableToMessagePatch(state, newState),
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
@@ -1125,30 +1126,30 @@ function(
|
||||
*
|
||||
* @param {Object} state The current state.
|
||||
* @param {Object} newState The new state.
|
||||
* @return {Bool|Null}
|
||||
* @return {Bool}
|
||||
*/
|
||||
var buildUnableToMessage = function(state, newState) {
|
||||
var oldOtherUser = getOtherUserFromState(state);
|
||||
var newOtherUser = getOtherUserFromState(newState);
|
||||
|
||||
const buildUnableToMessagePatch = (state, newState) => {
|
||||
if (newState.type == Constants.CONVERSATION_TYPES.SELF) {
|
||||
// Users always can send message themselves on self-conversations.
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
const oldOtherUser = getOtherUserFromState(state);
|
||||
const newOtherUser = getOtherUserFromState(newState);
|
||||
|
||||
if (!oldOtherUser && !newOtherUser) {
|
||||
return null;
|
||||
return false;
|
||||
} else if (oldOtherUser && !newOtherUser) {
|
||||
return oldOtherUser.canmessage ? null : true;
|
||||
return !oldOtherUser.canmessage;
|
||||
} else if (!oldOtherUser && newOtherUser) {
|
||||
return newOtherUser.canmessage ? null : true;
|
||||
return !newOtherUser.canmessage;
|
||||
} else if (!oldOtherUser.canmessage && newOtherUser.canmessage) {
|
||||
return false;
|
||||
} else if (oldOtherUser.canmessage && !newOtherUser.canmessage) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
return !newState.canSendMessageToConversation;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1163,7 +1164,6 @@ function(
|
||||
var inEditMode = buildInEditMode(state, newState);
|
||||
var requireAddContact = buildRequireAddContact(state, newState);
|
||||
var requireUnblock = buildRequireUnblock(state, newState);
|
||||
var unableToMessage = buildUnableToMessage(state, newState);
|
||||
var showRequireAddContact = requireAddContact !== null ? requireAddContact.show && requireAddContact.hasMessages : null;
|
||||
var otherUser = getOtherUserFromState(newState);
|
||||
var generateReturnValue = function(checkValue, successReturn) {
|
||||
@@ -1179,8 +1179,6 @@ function(
|
||||
type: 'add-contact',
|
||||
user: otherUser
|
||||
};
|
||||
} else if (!otherUser.canmessage && (otherUser.requirescontact && !otherUser.iscontact)) {
|
||||
return {type: 'unable-to-message'};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1199,7 +1197,6 @@ function(
|
||||
var checks = [
|
||||
[loadingFirstMessages, {type: 'placeholder'}],
|
||||
[inEditMode, {type: 'edit-mode'}],
|
||||
[unableToMessage, {type: 'unable-to-message'}],
|
||||
[requireUnblock, {type: 'unblock'}],
|
||||
[showRequireAddContact, {type: 'add-contact', user: otherUser}]
|
||||
];
|
||||
@@ -1365,7 +1362,8 @@ function(
|
||||
isFavourite: buildIsFavourite,
|
||||
isMuted: buildIsMuted,
|
||||
showEmojiPicker: buildShowEmojiPicker,
|
||||
showEmojiAutoComplete: buildShowEmojiAutoComplete
|
||||
showEmojiAutoComplete: buildShowEmojiAutoComplete,
|
||||
unableToMessage: buildUnableToMessagePatch
|
||||
}
|
||||
};
|
||||
// These build functions are only applicable to private conversations.
|
||||
|
||||
@@ -89,6 +89,46 @@ function(
|
||||
return body.find(SELECTORS.SELF_CONVERSATION_MESSAGE_CONTAINER);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the unable to message container element.
|
||||
*
|
||||
* @param {Object} body Conversation body container element.
|
||||
* @return {Object} The unable to message container element.
|
||||
*/
|
||||
const getUnableToMessageContainer = (body) => {
|
||||
return body.find(SELECTORS.UNABLE_TO_MESSAGE_CONTAINER);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the message text area element.
|
||||
*
|
||||
* @param {Object} footer Conversation footer container element.
|
||||
* @return {Object} The message text area element.
|
||||
*/
|
||||
const getMessageTextArea = (footer) => {
|
||||
return footer.find(SELECTORS.MESSAGE_TEXT_AREA);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the send message button element.
|
||||
*
|
||||
* @param {Object} footer Conversation footer container element.
|
||||
* @return {Object} The send message button element.
|
||||
*/
|
||||
const getSendMessageButton = (footer) => {
|
||||
return footer.find(SELECTORS.SEND_MESSAGE_BUTTON);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the emoji picker button element.
|
||||
*
|
||||
* @param {Object} footer Conversation footer container element.
|
||||
* @return {Object} The emoji picker button element.
|
||||
*/
|
||||
const getEmojiPickerButton = (footer) => {
|
||||
return footer.find(SELECTORS.TOGGLE_EMOJI_PICKER_BUTTON);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the self-conversation message container element.
|
||||
*
|
||||
@@ -259,33 +299,6 @@ function(
|
||||
getFooterRequireUnblockContainer(footer).addClass('hidden');
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the footer Unable to message contact container element.
|
||||
*
|
||||
* @param {Object} footer Conversation footer container element.
|
||||
* @return {Object} The footer Unable to message contact container element.
|
||||
*/
|
||||
var getFooterUnableToMessageContainer = function(footer) {
|
||||
return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_UNABLE_TO_MESSAGE_CONTAINER);
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the footer Unable to message contact container element.
|
||||
*
|
||||
* @param {Object} footer Conversation footer container element.
|
||||
*/
|
||||
var showFooterUnableToMessage = function(footer) {
|
||||
getFooterUnableToMessageContainer(footer).removeClass('hidden');
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the footer Unable to message contact container element.
|
||||
*
|
||||
* @param {Object} footer Conversation footer container element.
|
||||
*/
|
||||
var hideFooterUnableToMessage = function(footer) {
|
||||
getFooterUnableToMessageContainer(footer).addClass('hidden');
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide all header elements.
|
||||
@@ -309,7 +322,6 @@ function(
|
||||
hideFooterPlaceholder(footer);
|
||||
hideFooterRequireContact(footer);
|
||||
hideFooterRequireUnblock(footer);
|
||||
hideFooterUnableToMessage(footer);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -368,6 +380,111 @@ function(
|
||||
getHeaderContent(header).addClass('hidden');
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the unable to message container.
|
||||
*
|
||||
* @param {Object} body Conversation body container element.
|
||||
*/
|
||||
const showUnableToMessage = (body) => {
|
||||
getUnableToMessageContainer(body).removeClass('hidden');
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the unable to message container.
|
||||
*
|
||||
* @param {Object} body Conversation body container element.
|
||||
*/
|
||||
const hideUnableToMessage = (body) => {
|
||||
getUnableToMessageContainer(body).addClass('hidden');
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable the emoji picker button.
|
||||
*
|
||||
* @param {Object} footer Conversation footer container element.
|
||||
*/
|
||||
const enableEmojiPickerButton = (footer) => {
|
||||
getEmojiPickerButton(footer).prop('disabled', false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable the send message button.
|
||||
*
|
||||
* @param {Object} footer Conversation footer container element.
|
||||
*/
|
||||
const enableSendMessageButton = (footer) => {
|
||||
getSendMessageButton(footer).prop('disabled', false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable the message text area.
|
||||
*
|
||||
* @param {Object} footer Conversation footer container element.
|
||||
*/
|
||||
const enableMessageTextArea = (footer) => {
|
||||
const messageTextArea = getMessageTextArea(footer);
|
||||
messageTextArea.prop('disabled', false);
|
||||
Aria.unhide(messageTextArea.get());
|
||||
|
||||
Str.get_string('writeamessage', 'core_message').done(function(string) {
|
||||
if (!messageTextArea.prop('disabled')) {
|
||||
messageTextArea.prop('placeholder', string);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable all footer content elements.
|
||||
*
|
||||
* @param {Object} footer Conversation footer container element.
|
||||
*/
|
||||
const enableAllFooterContentElements = (footer) => {
|
||||
enableEmojiPickerButton(footer);
|
||||
enableSendMessageButton(footer);
|
||||
enableMessageTextArea(footer);
|
||||
};
|
||||
|
||||
/**
|
||||
* Disable the emoji picker button.
|
||||
*
|
||||
* @param {Object} footer Conversation footer container element.
|
||||
*/
|
||||
const disableEmojiPickerButton = (footer) => {
|
||||
getEmojiPickerButton(footer).prop('disabled', true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Disable the send message button.
|
||||
*
|
||||
* @param {Object} footer Conversation footer container element.
|
||||
*/
|
||||
const disableSendMessageButton = (footer) => {
|
||||
getSendMessageButton(footer).prop('disabled', true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Disable the message text area.
|
||||
*
|
||||
* @param {Object} footer Conversation footer container element.
|
||||
*/
|
||||
const disableMessageTextArea = (footer) => {
|
||||
const messageTextArea = getMessageTextArea(footer);
|
||||
messageTextArea.prop('disabled', true);
|
||||
messageTextArea.removeAttr('placeholder');
|
||||
Aria.unhide(messageTextArea.get());
|
||||
};
|
||||
|
||||
/**
|
||||
* Disable all footer content elements.
|
||||
*
|
||||
* @param {Object} footer Conversation footer container element.
|
||||
*/
|
||||
const disableAllFooterContentElements = (footer) => {
|
||||
disableEmojiPickerButton(footer);
|
||||
disableSendMessageButton(footer);
|
||||
disableMessageTextArea(footer);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the header edit mode container element.
|
||||
*
|
||||
@@ -572,9 +689,10 @@ function(
|
||||
* @param {Object} footer The footer container element.
|
||||
* @param {Array} days Array of days containing messages.
|
||||
* @param {Object} datesCache Cache timestamps and their formatted date string.
|
||||
* @param {Boolean} isAbleToMessage Whether the user can send a message to the conversation.
|
||||
* @return {Promise} Days rendering promises.
|
||||
*/
|
||||
var renderAddDays = function(header, body, footer, days, datesCache) {
|
||||
var renderAddDays = function(header, body, footer, days, datesCache, isAbleToMessage) {
|
||||
var messagesContainer = getMessagesContainer(body);
|
||||
var daysRenderPromises = days.map(function(data) {
|
||||
var timestampDate = new Date(data.value.timestamp * 1000);
|
||||
@@ -589,6 +707,7 @@ function(
|
||||
// Wait until all of the rendering is done for each of the days
|
||||
// to ensure they are added to the page in the correct order.
|
||||
days.forEach(function(data, index) {
|
||||
// eslint-disable-next-line promise/no-nesting
|
||||
daysRenderPromises[index]
|
||||
.then(function(html) {
|
||||
if (data.before) {
|
||||
@@ -598,6 +717,12 @@ function(
|
||||
return messagesContainer.append(html);
|
||||
}
|
||||
})
|
||||
.always(function() {
|
||||
const showUnableToMessage = !isAbleToMessage && index === days.length - 1;
|
||||
messagesContainer.find(SELECTORS.DAY_MESSAGE_UNABLE_TO_SEND_CONTAINER)
|
||||
.last().toggleClass('hidden', !showUnableToMessage);
|
||||
hideUnableToMessage(body);
|
||||
})
|
||||
.catch(function() {
|
||||
// Fail silently.
|
||||
});
|
||||
@@ -823,7 +948,7 @@ function(
|
||||
|
||||
if (hasAddDays) {
|
||||
renderingPromises.push(datesCachePromise.then(function(datesCache) {
|
||||
return renderAddDays(header, body, footer, data.days.add, datesCache);
|
||||
return renderAddDays(header, body, footer, data.days.add, datesCache, !data.unableToMessage);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -919,8 +1044,6 @@ function(
|
||||
return showFooterContent(footer);
|
||||
case 'unblock':
|
||||
return showFooterRequireUnblock(footer);
|
||||
case 'unable-to-message':
|
||||
return showFooterUnableToMessage(footer);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1644,6 +1767,29 @@ function(
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Show or hide the unable to message container and enable or disable the footer messaging controls.
|
||||
*
|
||||
* @param {Object} header The header container element.
|
||||
* @param {Object} body The body container element.
|
||||
* @param {Object} footer The footer container element.
|
||||
* @param {Object} disable should the message be displayed?.
|
||||
* @return {Object|true} jQuery promise
|
||||
*/
|
||||
var renderUnableToMessage = function(header, body, footer, disable) {
|
||||
if (disable) {
|
||||
disableAllFooterContentElements(footer);
|
||||
if (!body.find(SELECTORS.DAY_MESSAGE_UNABLE_TO_SEND_CONTAINER).length) {
|
||||
showUnableToMessage(body);
|
||||
}
|
||||
} else {
|
||||
enableAllFooterContentElements(footer);
|
||||
hideUnableToMessage(body);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Show or hide the require add contact panel.
|
||||
*
|
||||
@@ -1684,6 +1830,8 @@ function(
|
||||
showHeaderPlaceholder(header);
|
||||
hideAllFooterElements(footer);
|
||||
showFooterPlaceholder(footer);
|
||||
enableAllFooterContentElements(footer);
|
||||
hideUnableToMessage(body);
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -1708,7 +1856,8 @@ function(
|
||||
confirmContactRequest: renderConfirmContactRequest,
|
||||
requireAddContact: renderRequireAddContact,
|
||||
selfConversationMessage: renderSelfConversationMessage,
|
||||
contactRequestSent: renderContactRequestSent
|
||||
contactRequestSent: renderContactRequestSent,
|
||||
unableToMessage: renderUnableToMessage,
|
||||
},
|
||||
{
|
||||
loadingMembers: renderLoadingMembers,
|
||||
|
||||
@@ -147,7 +147,8 @@ define(['jquery'], function($) {
|
||||
pendingDeleteConversation: false,
|
||||
selectedMessageIds: [],
|
||||
showEmojiAutoComplete: false,
|
||||
showEmojiPicker: false
|
||||
showEmojiPicker: false,
|
||||
canSendMessageToConversation: true,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -836,6 +837,19 @@ define(['jquery'], function($) {
|
||||
return newState;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set whether the user can send messages to the conversation.
|
||||
*
|
||||
* @param {Object} state Current state.
|
||||
* @param {Bool} value If it can send message to conversation.
|
||||
* @return {Object} New state.
|
||||
*/
|
||||
const setCanSendMessageToConversation = function(state, value) {
|
||||
const newState = cloneState(state);
|
||||
newState.canSendMessageToConversation = value;
|
||||
return newState;
|
||||
};
|
||||
|
||||
return {
|
||||
buildInitialState: buildInitialState,
|
||||
addMessages: addMessages,
|
||||
@@ -877,6 +891,7 @@ define(['jquery'], function($) {
|
||||
removeSelectedMessagesById: removeSelectedMessagesById,
|
||||
markMessagesAsRead: markMessagesAsRead,
|
||||
addContactRequests: addContactRequests,
|
||||
removeContactRequests: removeContactRequests
|
||||
removeContactRequests: removeContactRequests,
|
||||
setCanSendMessageToConversation: setCanSendMessageToConversation,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -771,6 +771,7 @@ class api {
|
||||
$conv->unreadcount = isset($unreadcounts[$conv->id]) ? $unreadcounts[$conv->id]->unreadcount : null;
|
||||
$conv->ismuted = $conversation->ismuted ? true : false;
|
||||
$conv->members = $members[$conv->id];
|
||||
$conv->cansendmessagetoconversation = self::can_send_message_to_conversation($userid, $conv->id);
|
||||
|
||||
// Add the most recent message information.
|
||||
$conv->messages = [];
|
||||
@@ -956,7 +957,8 @@ class api {
|
||||
'ismuted' => $ismuted,
|
||||
'members' => $members,
|
||||
'messages' => $messages['messages'],
|
||||
'candeletemessagesforallusers' => has_capability('moodle/site:deleteanymessage', $deleteallcontext)
|
||||
'candeletemessagesforallusers' => has_capability('moodle/site:deleteanymessage', $deleteallcontext),
|
||||
'cansendmessagetoconversation' => self::can_send_message_to_conversation($userid, $conversation->id),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -1043,6 +1043,8 @@ class core_message_external extends external_api {
|
||||
),
|
||||
'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
|
||||
'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
|
||||
'cansendmessagetoconversation' => new external_value(PARAM_BOOL,
|
||||
'If the user can send messages in the conversation', VALUE_DEFAULT, true),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,11 @@
|
||||
<div class="p-3 text-center hidden" data-region="self-conversation-message-container">
|
||||
<p class="m-0">{{#str}} selfconversation, core_message {{/str}}</p>
|
||||
<p class="fst-italic fw-light" data-region="text">{{#str}} selfconversationdefaultmessage, core_message {{/str}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-3 text-center hidden" data-region="unable-to-send-container">
|
||||
<p class="m-0">{{#str}} cannotsendmessages, core_message {{/str}}</p>
|
||||
<p class="fst-italic fw-light" data-region="text">{{#str}} nopermissiontosend, core_message {{/str}}</p>
|
||||
</div>
|
||||
<div class="hidden text-center p-3" data-region="more-messages-loading-icon-container">{{> core/loading }}</div>
|
||||
</div>
|
||||
<div class="p-4 w-100 h-100 hidden position-absolute z-index-1" data-region="confirm-dialogue-container" style="top: 0; background: rgba(0,0,0,0.3);">
|
||||
|
||||
@@ -38,4 +38,8 @@
|
||||
{{#messages}}
|
||||
{{> core_message/message_drawer_view_conversation_body_message }}
|
||||
{{/messages}}
|
||||
<div class="p-3 text-center hidden" data-region="day-message-unable-to-send-container">
|
||||
<p class="m-0">{{#str}} cannotsendmessages, core_message {{/str}}</p>
|
||||
<p class="fst-italic fw-light" data-region="text">{{#str}} nopermissiontosend, core_message {{/str}}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -53,9 +53,6 @@
|
||||
<div class="hidden bg-secondary p-sm-3" data-region="content-messages-footer-require-unblock-container">
|
||||
{{> core_message/message_drawer_view_conversation_footer_require_unblock }}
|
||||
</div>
|
||||
<div class="hidden bg-secondary p-sm-3" data-region="content-messages-footer-unable-to-message">
|
||||
{{> core_message/message_drawer_view_conversation_footer_unable_to_message }}
|
||||
</div>
|
||||
<div class="p-sm-2" data-region="placeholder-container">
|
||||
{{> core_message/message_drawer_view_conversation_footer_placeholder }}
|
||||
</div>
|
||||
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
{{!
|
||||
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/message_drawer_view_conversation_footer_unable_to_message
|
||||
|
||||
This template will render the footer content when the user is unable to message
|
||||
in a conversation in the message drawer.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* All data attributes are required
|
||||
|
||||
Context variables required for this template:
|
||||
* userid The logged in user id
|
||||
* urls The URLs for the popover
|
||||
|
||||
Example context (json):
|
||||
{}
|
||||
|
||||
}}
|
||||
|
||||
<div class="p-3 bg-white">
|
||||
<p class="text-muted" data-region="text">{{#str}} unabletomessage, core_message {{/str}}</p>
|
||||
</div>
|
||||
@@ -33,7 +33,7 @@ Feature: To be able to block users that we are able to or to see a message if we
|
||||
When I log in as "student2"
|
||||
And I open messaging
|
||||
And I select "Student 1" user in messaging
|
||||
Then I should see "You are unable to message this user"
|
||||
Then I should see "Cannot send message"
|
||||
|
||||
Scenario: Unable to block a user
|
||||
Given I log in as "student1"
|
||||
@@ -58,7 +58,7 @@ Feature: To be able to block users that we are able to or to see a message if we
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I select "Student 1" user in messaging
|
||||
And I should not see "You are unable to message this user"
|
||||
And I should not see "Cannot send message"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I select "Student 2" user in messaging
|
||||
|
||||
@@ -12,10 +12,12 @@ Feature: Message send messages
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
| student2 | Student | 2 | student2@example.com |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "groups" exist:
|
||||
| name | course | idnumber | enablemessaging |
|
||||
| Group 1 | C1 | G1 | 1 |
|
||||
@@ -96,3 +98,19 @@ Feature: Message send messages
|
||||
Then I should see "You have an unsent message. It will be lost if you leave this page."
|
||||
And I press "Send message"
|
||||
And I should see "What you doing?" in the "Student 2" "core_message > Message conversation"
|
||||
|
||||
Scenario: Student cannot reply to a message from a teacher not in their course
|
||||
Given I log in as "teacher1"
|
||||
And I open messaging
|
||||
And I send "Hi!" message to "Student 1" user
|
||||
And I am on "C1" course homepage
|
||||
And I navigate to course participants
|
||||
And I click on "Unenrol" "link" in the "student1" "table_row"
|
||||
And I click on "Unenrol" "button" in the "Unenrol" "dialogue"
|
||||
And I log in as "student1"
|
||||
When I open messaging
|
||||
And I select "Teacher 1" conversation in messaging
|
||||
Then I should see "Cannot send message"
|
||||
And the "disabled" attribute of "textarea[data-region='send-message-txt']" "css_element" should contain "true"
|
||||
And the "disabled" attribute of "button[data-action='send-message']" "css_element" should contain "true"
|
||||
And the "disabled" attribute of "button[data-action='toggle-emoji-picker']" "css_element" should contain "true"
|
||||
|
||||
@@ -5920,4 +5920,43 @@ final class externallib_test extends externallib_advanced_testcase {
|
||||
$result = external_api::clean_returnvalue(external\get_unsent_message::execute_returns(), $result);
|
||||
$this->assertEmpty($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests conversation messaging is restricted by each user’s messaging permission.
|
||||
*
|
||||
* @covers ::get_conversation
|
||||
*/
|
||||
public function test_get_conversation_send_message_permission(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create some users.
|
||||
$user1 = self::getDataGenerator()->create_user();
|
||||
$user2 = self::getDataGenerator()->create_user();
|
||||
$user3 = self::getDataGenerator()->create_user();
|
||||
|
||||
// Create a course and enrol user1 and user2.
|
||||
$course1 = $this->getDataGenerator()->create_course();
|
||||
$this->setAdminUser();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course1->id);
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course1->id);
|
||||
|
||||
// Conversation between two enrolled users.
|
||||
$conversation1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
|
||||
[$user1->id, $user2->id]);
|
||||
// Conversation involving a non-enrolled user.
|
||||
$conversation2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
|
||||
[$user1->id, $user3->id]);
|
||||
|
||||
// User2 should be able to send a message to user1.
|
||||
$this->setUser($user2);
|
||||
$conv = core_message_external::get_conversation($user2->id, $conversation1->id);
|
||||
$conv = external_api::clean_returnvalue(core_message_external::get_conversation_returns(), $conv);
|
||||
$this->assertTrue($conv['cansendmessagetoconversation']);
|
||||
|
||||
// User3 should not be able to send a message to user1.
|
||||
$this->setUser($user3);
|
||||
$conv = core_message_external::get_conversation($user3->id, $conversation2->id);
|
||||
$conv = external_api::clean_returnvalue(core_message_external::get_conversation_returns(), $conv);
|
||||
$this->assertFalse($conv['cansendmessagetoconversation']);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user