2017-02-18 01:56:23 -07:00
|
|
|
'use strict';
|
2017-02-18 02:28:54 -07:00
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
const validator = require('validator');
|
2015-12-23 11:27:34 +02:00
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
const db = require('../database');
|
|
|
|
|
const meta = require('../meta');
|
|
|
|
|
const notifications = require('../notifications');
|
|
|
|
|
const plugins = require('../plugins');
|
|
|
|
|
const Messaging = require('../messaging');
|
|
|
|
|
const utils = require('../utils');
|
2020-04-01 22:03:31 -04:00
|
|
|
const server = require('./index');
|
2019-09-15 02:14:51 -04:00
|
|
|
const user = require('../user');
|
|
|
|
|
const privileges = require('../privileges');
|
2015-12-16 13:35:24 +02:00
|
|
|
|
2021-12-13 14:02:02 -05:00
|
|
|
const sockets = require('.');
|
|
|
|
|
const api = require('../api');
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
const SocketModules = module.exports;
|
2017-05-20 20:03:41 -04:00
|
|
|
|
|
|
|
|
SocketModules.chats = {};
|
|
|
|
|
SocketModules.settings = {};
|
2014-01-10 16:00:03 -05:00
|
|
|
|
|
|
|
|
/* Chat */
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.getRaw = async function (socket, data) {
|
2017-11-29 11:46:30 -05:00
|
|
|
if (!data || !data.hasOwnProperty('mid')) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2015-12-11 12:07:02 -05:00
|
|
|
}
|
2019-09-15 02:14:51 -04:00
|
|
|
const roomId = await Messaging.getMessageField(data.mid, 'roomId');
|
|
|
|
|
const [isAdmin, hasMessage, inRoom] = await Promise.all([
|
|
|
|
|
user.isAdministrator(socket.uid),
|
2021-02-03 23:59:08 -07:00
|
|
|
db.isSortedSetMember(`uid:${socket.uid}:chat:room:${roomId}:mids`, data.mid),
|
2019-09-15 02:14:51 -04:00
|
|
|
Messaging.isUserInRoom(socket.uid, roomId),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
if (!isAdmin && (!inRoom || !hasMessage)) {
|
|
|
|
|
throw new Error('[[error:not-allowed]]');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return await Messaging.getMessageField(data.mid, 'content');
|
2015-12-11 12:07:02 -05:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.isDnD = async function (socket, uid) {
|
2021-02-03 23:59:08 -07:00
|
|
|
const status = await db.getObjectField(`user:${uid}`, 'status');
|
2019-09-15 02:14:51 -04:00
|
|
|
return status === 'dnd';
|
2017-04-14 10:08:50 -04:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.newRoom = async function (socket, data) {
|
2021-12-13 14:02:02 -05:00
|
|
|
sockets.warnDeprecated(socket, 'POST /api/v3/chats');
|
|
|
|
|
|
2015-12-16 11:15:43 +02:00
|
|
|
if (!data) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2015-12-16 11:15:43 +02:00
|
|
|
}
|
2016-09-07 18:48:00 +03:00
|
|
|
|
2021-12-13 14:02:02 -05:00
|
|
|
const roomObj = await api.chats.create(socket, {
|
|
|
|
|
uids: [data.touid],
|
|
|
|
|
});
|
|
|
|
|
return roomObj.roomId;
|
2015-12-16 11:15:43 +02:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.send = async function (socket, data) {
|
2021-12-14 11:01:05 -05:00
|
|
|
sockets.warnDeprecated(socket, 'POST /api/v3/chats/:roomId');
|
|
|
|
|
|
2016-10-03 20:35:36 +03:00
|
|
|
if (!data || !data.roomId || !socket.uid) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2014-01-17 12:55:38 -05:00
|
|
|
}
|
2014-01-10 16:00:03 -05:00
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
const canChat = await privileges.global.can('chat', socket.uid);
|
|
|
|
|
if (!canChat) {
|
|
|
|
|
throw new Error('[[error:no-privileges]]');
|
|
|
|
|
}
|
2014-10-03 15:28:46 -04:00
|
|
|
|
2021-12-14 11:01:05 -05:00
|
|
|
return api.chats.post(socket, data);
|
|
|
|
|
};
|
2016-09-07 18:48:00 +03:00
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.loadRoom = async function (socket, data) {
|
2021-12-14 10:32:41 -05:00
|
|
|
sockets.warnDeprecated(socket, 'GET /api/v3/chats/:roomId');
|
|
|
|
|
|
2015-12-16 13:35:24 +02:00
|
|
|
if (!data || !data.roomId) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2015-12-16 13:35:24 +02:00
|
|
|
}
|
2015-12-23 11:27:34 +02:00
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
return await Messaging.loadRoom(socket.uid, data);
|
2015-12-16 13:35:24 +02:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.getUsersInRoom = async function (socket, data) {
|
2021-12-21 11:05:27 -05:00
|
|
|
sockets.warnDeprecated(socket, 'GET /api/v3/chats/:roomId/users');
|
2021-12-20 17:04:16 -05:00
|
|
|
|
2018-01-06 12:03:52 -05:00
|
|
|
if (!data || !data.roomId) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2018-01-06 12:03:52 -05:00
|
|
|
}
|
2021-12-20 17:04:16 -05:00
|
|
|
const isUserInRoom = await Messaging.isUserInRoom(socket.uid, data.roomId);
|
2020-01-22 11:46:26 -05:00
|
|
|
if (!isUserInRoom) {
|
|
|
|
|
throw new Error('[[error:no-privileges]]');
|
|
|
|
|
}
|
2021-12-20 17:04:16 -05:00
|
|
|
|
|
|
|
|
return api.chats.users(socket, data);
|
2018-01-06 12:03:52 -05:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.addUserToRoom = async function (socket, data) {
|
2021-12-21 11:05:27 -05:00
|
|
|
sockets.warnDeprecated(socket, 'POST /api/v3/chats/:roomId/users');
|
|
|
|
|
|
2015-12-16 13:35:24 +02:00
|
|
|
if (!data || !data.roomId || !data.username) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const canChat = await privileges.global.can('chat', socket.uid);
|
|
|
|
|
if (!canChat) {
|
|
|
|
|
throw new Error('[[error:no-privileges]]');
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-21 11:05:27 -05:00
|
|
|
// Revised API now takes uids, not usernames
|
|
|
|
|
data.uids = [await user.getUidByUsername(data.username)];
|
|
|
|
|
delete data.username;
|
2019-09-15 02:14:51 -04:00
|
|
|
|
2021-12-21 11:05:27 -05:00
|
|
|
await api.chats.invite(socket, data);
|
2015-12-16 13:35:24 +02:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.removeUserFromRoom = async function (socket, data) {
|
2021-12-22 09:58:52 -05:00
|
|
|
sockets.warnDeprecated(socket, 'DELETE /api/v3/chats/:roomId/users OR DELETE /api/v3/chats/:roomId/users/:uid');
|
|
|
|
|
|
2015-12-16 13:35:24 +02:00
|
|
|
if (!data || !data.roomId) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
|
|
|
|
}
|
2018-04-30 12:35:17 -04:00
|
|
|
|
2021-12-22 09:58:52 -05:00
|
|
|
// Revised API can accept multiple uids now
|
|
|
|
|
data.uids = [data.uid];
|
|
|
|
|
delete data.uid;
|
|
|
|
|
|
|
|
|
|
await api.chats.kick(socket, data);
|
2015-12-16 13:35:24 +02:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.leave = async function (socket, roomid) {
|
2016-01-08 12:34:09 +02:00
|
|
|
if (!socket.uid || !roomid) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2016-01-08 12:34:09 +02:00
|
|
|
}
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
await Messaging.leaveRoom([socket.uid], roomid);
|
2016-01-08 12:34:09 +02:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.edit = async function (socket, data) {
|
2021-12-20 11:30:43 -05:00
|
|
|
sockets.warnDeprecated(socket, 'PUT /api/v3/chats/:roomId/:mid');
|
|
|
|
|
|
2017-05-20 20:03:41 -04:00
|
|
|
if (!data || !data.roomId || !data.message) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2015-12-11 12:07:02 -05:00
|
|
|
}
|
2019-09-15 02:14:51 -04:00
|
|
|
await Messaging.canEdit(data.mid, socket.uid);
|
|
|
|
|
await Messaging.editMessage(socket.uid, data.mid, data.roomId, data.message);
|
2015-12-11 12:07:02 -05:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.delete = async function (socket, data) {
|
2021-12-20 15:00:43 -05:00
|
|
|
sockets.warnDeprecated(socket, 'DELETE /api/v3/chats/:roomId/:mid');
|
|
|
|
|
|
2015-12-15 14:10:32 +02:00
|
|
|
if (!data || !data.roomId || !data.messageId) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2015-12-11 12:07:02 -05:00
|
|
|
}
|
2019-09-15 02:14:51 -04:00
|
|
|
await Messaging.canDelete(data.messageId, socket.uid);
|
2020-02-14 23:26:54 -05:00
|
|
|
await Messaging.deleteMessage(data.messageId, socket.uid);
|
2015-12-16 11:15:43 +02:00
|
|
|
};
|
2015-12-11 12:07:02 -05:00
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.restore = async function (socket, data) {
|
2021-12-20 15:00:43 -05:00
|
|
|
sockets.warnDeprecated(socket, 'POST /api/v3/chats/:roomId/:mid');
|
|
|
|
|
|
2017-12-18 14:45:06 -05:00
|
|
|
if (!data || !data.roomId || !data.messageId) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2017-12-18 14:45:06 -05:00
|
|
|
}
|
2019-09-15 02:14:51 -04:00
|
|
|
await Messaging.canDelete(data.messageId, socket.uid);
|
2020-02-14 23:26:54 -05:00
|
|
|
await Messaging.restoreMessage(data.messageId, socket.uid);
|
2017-12-18 14:45:06 -05:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.canMessage = async function (socket, roomId) {
|
|
|
|
|
await Messaging.canMessageRoom(socket.uid, roomId);
|
2014-01-10 16:00:03 -05:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.markRead = async function (socket, roomId) {
|
2017-05-20 20:03:41 -04:00
|
|
|
if (!socket.uid || !roomId) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
|
|
|
|
}
|
|
|
|
|
const [uidsInRoom] = await Promise.all([
|
|
|
|
|
Messaging.getUidsInRoom(roomId, 0, -1),
|
|
|
|
|
Messaging.markRead(socket.uid, roomId),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
Messaging.pushUnreadCount(socket.uid);
|
2021-02-03 23:59:08 -07:00
|
|
|
server.in(`uid_${socket.uid}`).emit('event:chats.markedAsRead', { roomId: roomId });
|
2019-09-15 02:14:51 -04:00
|
|
|
|
|
|
|
|
if (!uidsInRoom.includes(String(socket.uid))) {
|
|
|
|
|
return;
|
2016-10-03 20:35:36 +03:00
|
|
|
}
|
2019-09-15 02:14:51 -04:00
|
|
|
|
|
|
|
|
// Mark notification read
|
|
|
|
|
const nids = uidsInRoom.filter(uid => parseInt(uid, 10) !== socket.uid)
|
2021-02-03 23:59:08 -07:00
|
|
|
.map(uid => `chat_${uid}_${roomId}`);
|
2019-09-15 02:14:51 -04:00
|
|
|
|
|
|
|
|
await notifications.markReadMultiple(nids, socket.uid);
|
|
|
|
|
await user.notifications.pushCount(socket.uid);
|
2014-07-19 10:33:27 -04:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.markAllRead = async function (socket) {
|
|
|
|
|
await Messaging.markAllRead(socket.uid);
|
|
|
|
|
Messaging.pushUnreadCount(socket.uid);
|
2016-03-11 13:38:52 +02:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.renameRoom = async function (socket, data) {
|
2021-12-15 10:59:58 -05:00
|
|
|
sockets.warnDeprecated(socket, 'PUT /api/v3/chats/:roomId');
|
|
|
|
|
|
2017-05-20 20:03:41 -04:00
|
|
|
if (!data || !data.roomId || !data.newName) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2015-12-23 11:27:34 +02:00
|
|
|
}
|
2021-12-15 10:59:58 -05:00
|
|
|
|
|
|
|
|
data.name = data.newName;
|
|
|
|
|
delete data.newName;
|
|
|
|
|
await api.chats.rename(socket, data);
|
2015-12-23 11:27:34 +02:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.getRecentChats = async function (socket, data) {
|
2016-10-03 20:35:36 +03:00
|
|
|
if (!data || !utils.isNumber(data.after) || !utils.isNumber(data.uid)) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2014-09-15 16:26:25 -04:00
|
|
|
}
|
2019-09-15 02:14:51 -04:00
|
|
|
const start = parseInt(data.after, 10);
|
|
|
|
|
const stop = start + 9;
|
|
|
|
|
return await Messaging.getRecentChats(socket.uid, data.uid, start, stop);
|
2014-01-10 16:00:03 -05:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.hasPrivateChat = async function (socket, uid) {
|
2018-11-17 22:31:39 -05:00
|
|
|
if (socket.uid <= 0 || uid <= 0) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2016-01-18 15:35:24 +02:00
|
|
|
}
|
2019-09-15 02:14:51 -04:00
|
|
|
return await Messaging.hasPrivateChat(socket.uid, uid);
|
2016-01-18 15:35:24 +02:00
|
|
|
};
|
2014-01-10 16:00:03 -05:00
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.getMessages = async function (socket, data) {
|
2017-05-20 20:03:41 -04:00
|
|
|
if (!socket.uid || !data || !data.uid || !data.roomId) {
|
2019-09-15 02:14:51 -04:00
|
|
|
throw new Error('[[error:invalid-data]]');
|
2016-09-20 16:58:50 +03:00
|
|
|
}
|
2016-10-02 15:17:22 +03:00
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
return await Messaging.getMessages({
|
2016-10-03 20:35:36 +03:00
|
|
|
callerUid: socket.uid,
|
2016-09-20 16:58:50 +03:00
|
|
|
uid: data.uid,
|
|
|
|
|
roomId: data.roomId,
|
2016-10-02 15:17:22 +03:00
|
|
|
start: parseInt(data.start, 10) || 0,
|
2017-02-17 19:31:21 -07:00
|
|
|
count: 50,
|
2019-09-15 02:14:51 -04:00
|
|
|
});
|
2016-09-20 16:58:50 +03:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
SocketModules.chats.getIP = async function (socket, mid) {
|
2019-09-17 18:02:52 +00:00
|
|
|
const allowed = await privileges.global.can('view:users:info', socket.uid);
|
2019-09-15 02:14:51 -04:00
|
|
|
if (!allowed) {
|
|
|
|
|
throw new Error('[[error:no-privilege]]');
|
|
|
|
|
}
|
|
|
|
|
return await Messaging.getMessageField(mid, 'ip');
|
2018-05-31 15:05:12 -04:00
|
|
|
};
|
|
|
|
|
|
2019-09-15 02:14:51 -04:00
|
|
|
require('../promisify')(SocketModules);
|