diff --git a/install/package.json b/install/package.json index 22780744ef..a53a4ab873 100644 --- a/install/package.json +++ b/install/package.json @@ -75,7 +75,7 @@ "nodebb-plugin-spam-be-gone": "0.5.3", "nodebb-rewards-essentials": "0.0.11", "nodebb-theme-lavender": "5.0.4", - "nodebb-theme-persona": "9.0.11", + "nodebb-theme-persona": "9.0.12", "nodebb-theme-slick": "1.2.3", "nodebb-theme-vanilla": "10.0.10", "nodebb-widget-essentials": "4.0.4", diff --git a/public/language/en-GB/modules.json b/public/language/en-GB/modules.json index b88bf9e865..63a464e916 100644 --- a/public/language/en-GB/modules.json +++ b/public/language/en-GB/modules.json @@ -32,6 +32,7 @@ "chat.leave-help": "Leaving this chat will remove you from future correspondence in this chat. If you are re-added in the future, you will not see any chat history from prior to your re-joining.", "chat.in-room": "In this room", "chat.kick": "Kick", + "chat.show-ip": "Show IP", "composer.compose": "Compose", "composer.show_preview": "Show Preview", diff --git a/public/src/client/chats.js b/public/src/client/chats.js index 51651853b9..244542ead6 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -57,6 +57,20 @@ define('forum/chats', [ Chats.addLeaveHandler(ajaxify.data.roomId, components.get('chat/controls').find('[data-action="leave"]')); Chats.addScrollHandler(ajaxify.data.roomId, ajaxify.data.uid, $('.chat-content')); Chats.addCharactersLeftHandler($('[component="chat/main-wrapper"]')); + Chats.addIPHandler($('[component="chat/main-wrapper"]')); + }; + + Chats.addIPHandler = function (container) { + container.on('click', '.chat-ip-button', function () { + var ipEl = $(this).parent(); + var mid = ipEl.parents('[data-mid]').attr('data-mid'); + socket.emit('modules.chats.getIP', mid, function (err, ip) { + if (err) { + return app.alertError(err); + } + ipEl.html(ip); + }); + }); }; Chats.addPopoutHandler = function () { diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index d06db2ce2e..c803043da0 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -246,6 +246,7 @@ define('chat', [ Chats.addScrollHandler(chatModal.attr('data-roomid'), data.uid, chatModal.find('.chat-content')); Chats.addCharactersLeftHandler(chatModal); + Chats.addIPHandler(chatModal); taskbar.push('chat', chatModal.attr('data-uuid'), { title: data.roomName || (data.users.length ? data.users[0].username : ''), diff --git a/src/controllers/accounts/chats.js b/src/controllers/accounts/chats.js index 103af601ce..409e71d12f 100644 --- a/src/controllers/accounts/chats.js +++ b/src/controllers/accounts/chats.js @@ -67,6 +67,9 @@ chatsController.get = function (req, res, callback) { roomId: req.params.roomid, isNew: false, }), + isAdminOrGlobalMod: function (next) { + user.isAdminOrGlobalMod(req.uid, next); + }, }, next); }, function (data) { @@ -89,7 +92,7 @@ chatsController.get = function (req, res, callback) { room.maximumUsersInChatRoom = parseInt(meta.config.maximumUsersInChatRoom, 10) || 0; room.maximumChatMessageLength = parseInt(meta.config.maximumChatMessageLength, 10) || 1000; room.showUserInput = !room.maximumUsersInChatRoom || room.maximumUsersInChatRoom > 2; - + room.isAdminOrGlobalMod = data.isAdminOrGlobalMod; res.render('chats', room); }, ], callback); diff --git a/src/messaging.js b/src/messaging.js index c9cf356c7b..ba9e794b30 100644 --- a/src/messaging.js +++ b/src/messaging.js @@ -59,11 +59,7 @@ Messaging.getMessages = function (params, callback) { // Filter out deleted messages unless you're the sender of said message messageData = messageData.filter(function (messageData) { - if (messageData.deleted && parseInt(messageData.fromuid, 10) !== parseInt(params.uid, 10)) { - return false; - } - - return true; + return (!messageData.deleted || parseInt(messageData.fromuid, 10) === parseInt(params.uid, 10)); }); next(null, messageData); @@ -87,7 +83,6 @@ Messaging.parse = function (message, fromuid, uid, roomId, isNew, callback) { return callback(err); } - var messageData = { message: message, parsed: parsed, diff --git a/src/messaging/create.js b/src/messaging/create.js index 252989e5c7..bcee2f4f5d 100644 --- a/src/messaging/create.js +++ b/src/messaging/create.js @@ -8,20 +8,20 @@ var db = require('../database'); var user = require('../user'); module.exports = function (Messaging) { - Messaging.sendMessage = function (uid, roomId, content, timestamp, callback) { + Messaging.sendMessage = function (data, callback) { async.waterfall([ function (next) { - Messaging.checkContent(content, next); + Messaging.checkContent(data.content, next); }, function (next) { - Messaging.isUserInRoom(uid, roomId, next); + Messaging.isUserInRoom(data.uid, data.roomId, next); }, function (inRoom, next) { if (!inRoom) { return next(new Error('[[error:not-allowed]]')); } - Messaging.addMessage(uid, roomId, content, timestamp, next); + Messaging.addMessage(data, next); }, ], callback); }; @@ -39,14 +39,14 @@ module.exports = function (Messaging) { callback(); }; - Messaging.addMessage = function (fromuid, roomId, content, timestamp, callback) { + Messaging.addMessage = function (data, callback) { var mid; var message; var isNewSet; async.waterfall([ function (next) { - Messaging.checkContent(content, next); + Messaging.checkContent(data.content, next); }, function (next) { db.incrObjectField('global', 'nextMid', next); @@ -54,12 +54,15 @@ module.exports = function (Messaging) { function (_mid, next) { mid = _mid; message = { - content: String(content), - timestamp: timestamp, - fromuid: fromuid, - roomId: roomId, + content: String(data.content), + timestamp: data.timestamp, + fromuid: data.uid, + roomId: data.roomId, deleted: 0, }; + if (data.ip) { + message.ip = data.ip; + } plugins.fireHook('filter:messaging.save', message, next); }, @@ -67,27 +70,27 @@ module.exports = function (Messaging) { db.setObject('message:' + mid, message, next); }, function (next) { - Messaging.isNewSet(fromuid, roomId, timestamp, next); + Messaging.isNewSet(data.uid, data.roomId, data.timestamp, next); }, function (_isNewSet, next) { isNewSet = _isNewSet; - db.getSortedSetRange('chat:room:' + roomId + ':uids', 0, -1, next); + db.getSortedSetRange('chat:room:' + data.roomId + ':uids', 0, -1, next); }, function (uids, next) { - user.blocks.filterUids(fromuid, uids, next); + user.blocks.filterUids(data.uid, uids, next); }, function (uids, next) { async.parallel([ - async.apply(Messaging.addRoomToUsers, roomId, uids, timestamp), - async.apply(Messaging.addMessageToUsers, roomId, uids, mid, timestamp), - async.apply(Messaging.markUnread, uids, roomId), - async.apply(Messaging.addUsersToRoom, fromuid, [fromuid], roomId), + async.apply(Messaging.addRoomToUsers, data.roomId, uids, data.timestamp), + async.apply(Messaging.addMessageToUsers, data.roomId, uids, mid, data.timestamp), + async.apply(Messaging.markUnread, uids, data.roomId), + async.apply(Messaging.addUsersToRoom, data.uid, [data.uid], data.roomId), ], next); }, function (results, next) { async.parallel({ - markRead: async.apply(Messaging.markRead, fromuid, roomId), - messages: async.apply(Messaging.getMessagesData, [mid], fromuid, roomId, true), + markRead: async.apply(Messaging.markRead, data.uid, data.roomId), + messages: async.apply(Messaging.getMessagesData, [mid], data.uid, data.roomId, true), }, next); }, function (results, next) { @@ -97,7 +100,7 @@ module.exports = function (Messaging) { results.messages[0].newSet = isNewSet; results.messages[0].mid = mid; - results.messages[0].roomId = roomId; + results.messages[0].roomId = data.roomId; next(null, results.messages[0]); }, ], callback); diff --git a/src/messaging/data.js b/src/messaging/data.js index aa269d19c9..89f97f62c7 100644 --- a/src/messaging/data.js +++ b/src/messaging/data.js @@ -44,6 +44,7 @@ module.exports = function (Messaging) { messages = _messages.map(function (msg, idx) { if (msg) { msg.messageId = parseInt(mids[idx], 10); + msg.ip = undefined; } return msg; }).filter(Boolean); diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index 08b6d12f4c..70f7aa8719 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -118,7 +118,13 @@ SocketModules.chats.send = function (socket, data, callback) { Messaging.canMessageRoom(socket.uid, data.roomId, next); }, function (next) { - Messaging.sendMessage(socket.uid, data.roomId, data.message, Date.now(), next); + Messaging.sendMessage({ + uid: socket.uid, + roomId: data.roomId, + content: data.message, + timestamp: Date.now(), + ip: socket.ip, + }, next); }, function (message, next) { Messaging.notifyUsersInRoom(socket.uid, data.roomId, message); @@ -171,6 +177,9 @@ SocketModules.chats.loadRoom = function (socket, data, callback) { roomId: data.roomId, isNew: false, }), + isAdminOrGlobalMod: function (next) { + user.isAdminOrGlobalMod(socket.uid, next); + }, }, next); }, function (results, next) { @@ -183,6 +192,7 @@ SocketModules.chats.loadRoom = function (socket, data, callback) { results.roomData.maximumUsersInChatRoom = parseInt(meta.config.maximumUsersInChatRoom, 10) || 0; results.roomData.maximumChatMessageLength = parseInt(meta.config.maximumChatMessageLength, 10) || 1000; results.roomData.showUserInput = !results.roomData.maximumUsersInChatRoom || results.roomData.maximumUsersInChatRoom > 2; + results.roomData.isAdminOrGlobalMod = results.isAdminOrGlobalMod; next(null, results.roomData); }, ], callback); @@ -438,6 +448,20 @@ SocketModules.chats.getMessages = function (socket, data, callback) { Messaging.getMessages(params, callback); }; +SocketModules.chats.getIP = function (socket, mid, callback) { + async.waterfall([ + function (next) { + user.isAdminOrGlobalMod(socket.uid, next); + }, + function (allowed, next) { + if (!allowed) { + return next(new Error('[[error:no-privilege]]')); + } + Messaging.getMessageField(mid, 'ip', next); + }, + ], callback); +}; + /* Sounds */ SocketModules.sounds.getUserSoundMap = function getUserSoundMap(socket, data, callback) { meta.sounds.getUserSoundMap(socket.uid, callback);