diff --git a/public/openapi/write/chats/roomId/users.yaml b/public/openapi/write/chats/roomId/users.yaml index 150bccfab5..c96366509f 100644 --- a/public/openapi/write/chats/roomId/users.yaml +++ b/public/openapi/write/chats/roomId/users.yaml @@ -65,8 +65,8 @@ post: delete: tags: - chats - summary: remove users from chat room - description: This operation removes (kicks) a user from a chat room + summary: leave/remove users from chat room + description: This operation removes (kicks) multiple user from a chat room, or leaves the chat room if the requested user is the same as the calling user. parameters: - in: path name: roomId diff --git a/public/openapi/write/chats/roomId/users/uid.yaml b/public/openapi/write/chats/roomId/users/uid.yaml index 96b31eb907..964c71c41c 100644 --- a/public/openapi/write/chats/roomId/users/uid.yaml +++ b/public/openapi/write/chats/roomId/users/uid.yaml @@ -1,7 +1,7 @@ delete: tags: - chats - summary: remove one user from chat room + summary: leave/remove one user from chat room description: This operation removes (kicks) a single user from a chat room parameters: - in: path diff --git a/public/src/client/chats.js b/public/src/client/chats.js index 29e89aefe7..e199ca4110 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -278,11 +278,7 @@ define('forum/chats', [ message: '
[[modules:chat.leave-prompt]]
[[modules:chat.leave-help]]
', callback: function (ok) { if (ok) { - socket.emit('modules.chats.leave', roomId, function (err) { - if (err) { - alerts.error(err); - } - + api.delete(`/chats/${roomId}/users/${app.user.uid}`, {}).then(() => { // Return user to chats page. If modal, close modal. const modal = buttonEl.parents('.chat-modal'); if (modal.length) { @@ -290,7 +286,7 @@ define('forum/chats', [ } else { ajaxify.go('chats'); } - }); + }).catch(alerts.error); } }, }); @@ -384,10 +380,7 @@ define('forum/chats', [ Chats.leave = function (el) { const roomId = el.attr('data-roomid'); - socket.emit('modules.chats.leave', roomId, function (err) { - if (err) { - return alerts.error(err); - } + api.delete(`/chats/${roomId}/users/${app.user.uid}`, {}).then(() => { if (parseInt(roomId, 10) === parseInt(ajaxify.data.roomId, 10)) { ajaxify.go('user/' + ajaxify.data.userslug + '/chats'); } else { @@ -398,7 +391,7 @@ define('forum/chats', [ if (modal.length) { chatModule.close(modal); } - }); + }).catch(alerts.error); }; Chats.switchChat = function (roomid) { diff --git a/src/api/chats.js b/src/api/chats.js index 4f8660ea2a..0ab920aa42 100644 --- a/src/api/chats.js +++ b/src/api/chats.js @@ -108,7 +108,12 @@ chatsAPI.kick = async (caller, data) => { throw new Error('[[error:no-user]]'); } - await messaging.removeUsersFromRoom(caller.uid, data.uids, data.roomId); + // Additional checks if kicking vs leaving + if (data.uids.length === 1 && parseInt(data.uids[0], 10) === caller.uid) { + await messaging.leaveRoom([caller.uid], data.roomId); + } else { + await messaging.removeUsersFromRoom(caller.uid, data.uids, data.roomId); + } delete data.uids; return chatsAPI.users(caller, data); diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js index 0b6be7e34b..4e9b31a225 100644 --- a/src/socket.io/modules.js +++ b/src/socket.io/modules.js @@ -131,6 +131,8 @@ SocketModules.chats.removeUserFromRoom = async function (socket, data) { }; SocketModules.chats.leave = async function (socket, roomid) { + sockets.warnDeprecated(socket, 'DELETE /api/v3/chats/:roomId/users OR DELETE /api/v3/chats/:roomId/users/:uid'); + if (!socket.uid || !roomid) { throw new Error('[[error:invalid-data]]'); } diff --git a/test/messaging.js b/test/messaging.js index 6158a8a2e2..bc4fb2372e 100644 --- a/test/messaging.js +++ b/test/messaging.js @@ -213,29 +213,22 @@ describe('Messaging Library', () => { assert.strictEqual(body.status.message, await translator.translate('[[error:cant-chat-with-yourself]]')); }); - it('should fail to leave room with invalid data', (done) => { - socketModules.chats.leave({ uid: null }, roomId, (err) => { - assert.equal(err.message, '[[error:invalid-data]]'); - socketModules.chats.leave({ uid: mocks.users.foo.uid }, null, (err) => { - assert.equal(err.message, '[[error:invalid-data]]'); - done(); - }); - }); + it('should fail to leave room with invalid data', async () => { + let { statusCode, body } = await callv3API('delete', `/chats/${roomId}/users`, {}, 'foo'); + assert.strictEqual(statusCode, 400); + assert.strictEqual(body.status.message, await translator.translate('[[error:required-parameters-missing, uids]]')); + + ({ statusCode, body } = await callv3API('delete', `/chats/${roomId}/users`, { uids: [98237423] }, 'foo')); + assert.strictEqual(statusCode, 400); + assert.strictEqual(body.status.message, await translator.translate('[[error:no-user]]')); }); - it('should leave the chat room', (done) => { - socketModules.chats.leave({ uid: mocks.users.baz.uid }, roomId, (err) => { - assert.ifError(err); - Messaging.isUserInRoom(mocks.users.baz.uid, roomId, (err, isUserInRoom) => { - assert.ifError(err); - assert.equal(isUserInRoom, false); - Messaging.getRoomData(roomId, (err, data) => { - assert.ifError(err); - assert.equal(data.owner, mocks.users.foo.uid); - done(); - }); - }); - }); + it('should leave the chat room', async () => { + await callv3API('delete', `/chats/${roomId}/users/${mocks.users.baz.uid}`, {}, 'baz'); + const isUserInRoom = await Messaging.isUserInRoom(mocks.users.baz.uid, roomId); + assert.equal(isUserInRoom, false); + const data = await Messaging.getRoomData(roomId); + assert.equal(data.owner, mocks.users.foo.uid); }); it('should send a user-leave system message when a user leaves the chat room', (done) => { @@ -253,16 +246,21 @@ describe('Messaging Library', () => { ); }); - it('should send not a user-leave system message when a user tries to leave a room they are not in', async () => { - await socketModules.chats.leave({ uid: mocks.users.baz.uid }, roomId); + it('should not send a user-leave system message when a user tries to leave a room they are not in', async () => { + await callv3API('delete', `/chats/${roomId}/users/${mocks.users.baz.uid}`, {}, 'baz'); const messages = await socketModules.chats.getMessages( { uid: mocks.users.foo.uid }, { uid: mocks.users.foo.uid, roomId: roomId, start: 0 } ); assert.equal(messages.length, 4); - const message = messages.pop(); + let message = messages.pop(); assert.strictEqual(message.system, true); assert.strictEqual(message.content, 'user-leave'); + + // The message before should still be a user-join + message = messages.pop(); + assert.strictEqual(message.system, true); + assert.strictEqual(message.content, 'user-join'); }); it('should change owner when owner leaves room', async () => { @@ -605,7 +603,7 @@ describe('Messaging Library', () => { }); after(async () => { - await socketModules.chats.leave({ uid: mocks.users.baz.uid }, roomId); + await callv3API('delete', `/chats/${roomId}/users/${mocks.users.baz.uid}`, {}, 'baz'); }); it('should fail to edit message with invalid data', async () => {