diff --git a/install/data/defaults.json b/install/data/defaults.json index f5317337e3..12acc55fd6 100644 --- a/install/data/defaults.json +++ b/install/data/defaults.json @@ -64,6 +64,7 @@ "maximumAboutMeLength": 1000, "maximumUsersInChatRoom": 0, "maximumChatMessageLength": 1000, + "maximumChatRoomNameLength": 50, "maximumProfileImageSize": 256, "maximumCoverImageSize": 2048, "profileImageDimension": 200, diff --git a/public/language/en-GB/admin/settings/chat.json b/public/language/en-GB/admin/settings/chat.json index 67898611e7..e4946458bd 100644 --- a/public/language/en-GB/admin/settings/chat.json +++ b/public/language/en-GB/admin/settings/chat.json @@ -4,6 +4,7 @@ "disable-editing": "Disable chat message editing/deletion", "disable-editing-help": "Administrators and global moderators are exempt from this restriction", "max-length": "Maximum length of chat messages", + "max-chat-room-name-length": "Maximum length of chat room names", "max-room-size": "Maximum number of users in chat rooms", "delay": "Time between chat messages in milliseconds", "notification-delay": "Notification delay for chat messages. (0 for no delay)", diff --git a/public/language/en-GB/error.json b/public/language/en-GB/error.json index 06e49e4f12..a374787ea6 100644 --- a/public/language/en-GB/error.json +++ b/public/language/en-GB/error.json @@ -191,7 +191,7 @@ "chat-room-does-not-exist": "Chat room does not exist.", "cant-add-users-to-chat-room": "Can't add users to chat room.", "cant-remove-users-from-chat-room": "Can't remove users from chat room.", - "chat-room-name-too-long": "Chat room name too long.", + "chat-room-name-too-long": "Chat room name too long. Names can't be longer than %1 characters.", "already-voting-for-this-post": "You have already voted for this post.", "reputation-system-disabled": "Reputation system is disabled.", diff --git a/public/src/client/chats.js b/public/src/client/chats.js index d92d27a532..c8743f9d80 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -396,29 +396,30 @@ define('forum/chats', [ }); }; - Chats.addRenameHandler = function (roomId, buttonEl, roomName) { - let modal; - - buttonEl.on('click', function () { - app.parseAndTranslate('modals/rename-room', { - name: roomName || ajaxify.data.roomName, - }, function (html) { - modal = bootbox.dialog({ - title: '[[modules:chat.rename-room]]', - message: html, - onEscape: true, - buttons: { - save: { - label: '[[global:save]]', - className: 'btn-primary', - callback: function () { - api.put(`/chats/${roomId}`, { - name: modal.find('#roomName').val(), - }).catch(alerts.error); - }, + Chats.addRenameHandler = function (roomId, buttonEl) { + buttonEl.on('click', async function () { + const { roomName } = await api.get(`/chats/${roomId}`); + const html = await app.parseAndTranslate('modals/rename-room', { + name: roomName, + }); + const modal = bootbox.dialog({ + title: '[[modules:chat.rename-room]]', + message: html, + onEscape: true, + buttons: { + save: { + label: '[[global:save]]', + className: 'btn-primary', + callback: function () { + api.put(`/chats/${roomId}`, { + name: modal.find('#roomName').val(), + }).then(() => { + modal.modal('hide'); + }).catch(alerts.error); + return false; }, }, - }); + }, }); }); }; @@ -586,7 +587,15 @@ define('forum/chats', [ if (roomEl.length) { const titleEl = roomEl.find('[component="chat/room/title"]'); ajaxify.data.roomName = data.newName; - titleEl.text(data.newName); + titleEl.translateText(data.newName ? data.newName : ajaxify.data.usernames); + } + const titleEl = $(`[component="chat/main-wrapper"][data-roomid="${data.roomId}"] [component="chat/header/title"]`); + if (titleEl.length) { + titleEl.html( + data.newName ? + ` ${data.newName}` : + ajaxify.data.chatWithMessage + ); } }); diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index a932943e0a..31f81927a0 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -232,9 +232,18 @@ define('chat', [ }; module.onRoomRename = function (data) { - const newTitle = $('
').html(data.newName).text(); const modal = module.getModal(data.roomId); - modal.find('[component="chat/room/name"]').text(newTitle); + const titleEl = modal.find('[component="chat/room/name"]'); + const icon = titleEl.attr('data-icon'); + if (titleEl.length) { + titleEl.html( + data.newName ? + ` ${data.newName}` : + data.chatWithMessage + ); + } + + const newTitle = $('').html(data.newName).text(); taskbar.update('chat', modal.attr('data-uuid'), { title: newTitle, }); @@ -347,7 +356,7 @@ define('chat', [ }); Chats.addActionHandlers(chatModal.find('[component="chat/messages"]'), roomId); - Chats.addRenameHandler(roomId, chatModal.find('[data-action="rename"]'), data.roomName); + Chats.addRenameHandler(roomId, chatModal.find('[data-action="rename"]')); Chats.addLeaveHandler(roomId, chatModal.find('[data-action="leave"]')); Chats.addDeleteHandler(roomId, chatModal.find('[data-action="delete"]')); Chats.addSendHandlers(roomId, chatModal.find('.chat-input'), chatModal.find('[data-action="send"]')); diff --git a/src/api/chats.js b/src/api/chats.js index dc46ec522d..cf7bc6c7ee 100644 --- a/src/api/chats.js +++ b/src/api/chats.js @@ -103,17 +103,10 @@ chatsAPI.update = async (caller, data) => { } if (data.hasOwnProperty('name')) { - if (!data.name) { + if (!data.name && data.name !== '') { throw new Error('[[error:invalid-data]]'); } await messaging.renameRoom(caller.uid, data.roomId, data.name); - const ioRoom = require('../socket.io').in(`chat_room_${data.roomId}`); - if (ioRoom) { - ioRoom.emit('event:chats.roomRename', { - roomId: data.roomId, - newName: validator.escape(String(data.name)), - }); - } } const [roomData, isAdmin] = await Promise.all([ messaging.getRoomData(data.roomId), @@ -130,9 +123,20 @@ chatsAPI.update = async (caller, data) => { if (data.hasOwnProperty('notificationSetting') && isAdmin) { await db.setObjectField(`chat:room:${data.roomId}`, 'notificationSetting', data.notificationSetting); } - return messaging.loadRoom(caller.uid, { + const loadedRoom = await messaging.loadRoom(caller.uid, { roomId: data.roomId, }); + if (data.hasOwnProperty('name')) { + const ioRoom = require('../socket.io').in(`chat_room_${data.roomId}`); + if (ioRoom) { + ioRoom.emit('event:chats.roomRename', { + roomId: data.roomId, + newName: validator.escape(String(data.name)), + chatWithMessage: loadedRoom.chatWithMessage, + }); + } + } + return loadedRoom; }; chatsAPI.rename = async (caller, data) => { diff --git a/src/messaging/index.js b/src/messaging/index.js index 42cf331278..5199345720 100644 --- a/src/messaging/index.js +++ b/src/messaging/index.js @@ -213,8 +213,8 @@ Messaging.getRecentChats = async (callerUid, uid, start, stop) => { }); room.users = room.users.filter(user => user && parseInt(user.uid, 10)); room.lastUser = room.users[0]; - room.usernames = Messaging.generateUsernames(room.users, uid); - room.chatWithMessage = await Messaging.generateChatWithMessage(room.users, uid, results.settings.userLang); + room.usernames = Messaging.generateUsernames(room, uid); + room.chatWithMessage = await Messaging.generateChatWithMessage(room, uid, results.settings.userLang); } })); @@ -228,21 +228,21 @@ Messaging.getRecentChats = async (callerUid, uid, start, stop) => { }); }; -Messaging.generateUsernames = function (users, excludeUid) { - users = users.filter(u => u && parseInt(u.uid, 10) !== excludeUid); +Messaging.generateUsernames = function (room, excludeUid) { + const users = room.users.filter(u => u && parseInt(u.uid, 10) !== excludeUid); const usernames = users.map(u => u.username); if (users.length > 3) { return translator.compile( 'modules:chat.usernames-and-x-others', usernames.slice(0, 2).join(', '), - usernames.length - 2 + room.userCount - 2 ); } return usernames.join(', '); }; -Messaging.generateChatWithMessage = async function (users, callerUid, userLang) { - users = users.filter(u => u && parseInt(u.uid, 10) !== callerUid); +Messaging.generateChatWithMessage = async function (room, callerUid, userLang) { + const users = room.users.filter(u => u && parseInt(u.uid, 10) !== callerUid); const usernames = users.map(u => `${u.username}`); let compiled = ''; if (!users.length) { @@ -252,7 +252,7 @@ Messaging.generateChatWithMessage = async function (users, callerUid, userLang) compiled = translator.compile( 'modules:chat.chat-with-usernames-and-x-others', usernames.slice(0, 2).join(', '), - usernames.length - 2 + room.userCount - 2 ); } else { compiled = translator.compile( diff --git a/src/messaging/rooms.js b/src/messaging/rooms.js index 51c76c6ce9..5428489f42 100644 --- a/src/messaging/rooms.js +++ b/src/messaging/rooms.js @@ -78,6 +78,10 @@ module.exports = function (Messaging) { if (Array.isArray(data)) { // old usage second param used to be toUids data = { uids: data }; } + if (data.hasOwnProperty('roomName')) { + checkRoomName(data.roomName); + } + const now = Date.now(); const roomId = await db.incrObjectField('global', 'nextChatRoomId'); const room = { @@ -87,7 +91,7 @@ module.exports = function (Messaging) { }; if (data.hasOwnProperty('roomName') && data.roomName) { - room.roomName = String(data.roomName); + room.roomName = String(data.roomName).trim(); } if (Array.isArray(data.groups) && data.groups.length) { room.groups = JSON.stringify(data.groups); @@ -397,13 +401,8 @@ module.exports = function (Messaging) { }; Messaging.renameRoom = async function (uid, roomId, newName) { - if (!newName) { - throw new Error('[[error:invalid-data]]'); - } - newName = newName.trim(); - if (newName.length > 75) { - throw new Error('[[error:chat-room-name-too-long]]'); - } + newName = String(newName).trim(); + checkRoomName(newName); const payload = await plugins.hooks.fire('filter:chat.renameRoom', { uid: uid, @@ -424,6 +423,15 @@ module.exports = function (Messaging) { }); }; + function checkRoomName(roomName) { + if (!roomName && roomName !== '') { + throw new Error('[[error:invalid-room-name]]'); + } + if (roomName.length > meta.config.maximumChatRoomNameLength) { + throw new Error(`[[error:chat-room-name-too-long, ${meta.config.maximumChatRoomNameLength}]]`); + } + } + Messaging.canReply = async (roomId, uid) => { const inRoom = await db.isSortedSetMember(`chat:room:${roomId}:uids`, uid); const data = await plugins.hooks.fire('filter:messaging.canReply', { uid: uid, roomId: roomId, inRoom: inRoom, canReply: inRoom }); @@ -517,8 +525,8 @@ module.exports = function (Messaging) { room.canReply = canReply; room.groupChat = room.hasOwnProperty('groupChat') ? room.groupChat : users.length > 2; room.icon = Messaging.getRoomIcon(room); - room.usernames = Messaging.generateUsernames(users, uid); - room.chatWithMessage = await Messaging.generateChatWithMessage(users, uid, settings.userLang); + room.usernames = Messaging.generateUsernames(room, uid); + room.chatWithMessage = await Messaging.generateChatWithMessage(room, uid, settings.userLang); room.maximumUsersInChatRoom = meta.config.maximumUsersInChatRoom; room.maximumChatMessageLength = meta.config.maximumChatMessageLength; room.showUserInput = !room.maximumUsersInChatRoom || room.maximumUsersInChatRoom > 2; diff --git a/src/views/admin/settings/chat.tpl b/src/views/admin/settings/chat.tpl index 59a32445bd..62fbd3c199 100644 --- a/src/views/admin/settings/chat.tpl +++ b/src/views/admin/settings/chat.tpl @@ -31,6 +31,11 @@ +