mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-17 11:11:04 +01:00
feat: POST /chats/:roomId/users
This commit is contained in:
@@ -94,6 +94,44 @@ MessageObject:
|
|||||||
type: boolean
|
type: boolean
|
||||||
cleanedContent:
|
cleanedContent:
|
||||||
type: string
|
type: string
|
||||||
|
RoomUserList:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
users:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
uid:
|
||||||
|
type: number
|
||||||
|
description: A user identifier
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
description: A friendly name for a given user account
|
||||||
|
picture:
|
||||||
|
nullable: true
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
displayname:
|
||||||
|
type: string
|
||||||
|
description: This is either username or fullname depending on forum and user settings
|
||||||
|
icon:text:
|
||||||
|
type: string
|
||||||
|
description: A single-letter representation of a username. This is used in the
|
||||||
|
auto-generated icon given to users
|
||||||
|
without an avatar
|
||||||
|
icon:bgColor:
|
||||||
|
type: string
|
||||||
|
description: A six-character hexadecimal colour code assigned to the user. This
|
||||||
|
value is used in conjunction with
|
||||||
|
`icon:text` for the user's
|
||||||
|
auto-generated icon
|
||||||
|
example: "#f44336"
|
||||||
|
isOwner:
|
||||||
|
type: boolean
|
||||||
|
canKick:
|
||||||
|
type: boolean
|
||||||
RoomObjectFull:
|
RoomObjectFull:
|
||||||
# Messaging.loadRoom
|
# Messaging.loadRoom
|
||||||
allOf:
|
allOf:
|
||||||
|
|||||||
@@ -22,40 +22,43 @@ get:
|
|||||||
status:
|
status:
|
||||||
$ref: ../../../components/schemas/Status.yaml#/Status
|
$ref: ../../../components/schemas/Status.yaml#/Status
|
||||||
response:
|
response:
|
||||||
type: object
|
$ref: ../../../components/schemas/Chats.yaml#/RoomUserList
|
||||||
properties:
|
post:
|
||||||
users:
|
tags:
|
||||||
type: array
|
- chats
|
||||||
items:
|
summary: add users to chat room
|
||||||
type: object
|
description: This operation invites users to a chat room
|
||||||
properties:
|
parameters:
|
||||||
uid:
|
- in: path
|
||||||
type: number
|
name: roomId
|
||||||
description: A user identifier
|
schema:
|
||||||
username:
|
type: number
|
||||||
type: string
|
required: true
|
||||||
description: A friendly name for a given user account
|
description: a valid chat room id
|
||||||
picture:
|
example: 1
|
||||||
nullable: true
|
requestBody:
|
||||||
type: string
|
required: true
|
||||||
status:
|
content:
|
||||||
type: string
|
application/json:
|
||||||
displayname:
|
schema:
|
||||||
type: string
|
type: object
|
||||||
description: This is either username or fullname depending on forum and user settings
|
properties:
|
||||||
icon:text:
|
uids:
|
||||||
type: string
|
type: array
|
||||||
description: A single-letter representation of a username. This is used in the
|
description: A list of valid uids
|
||||||
auto-generated icon given to users
|
example: [2]
|
||||||
without an avatar
|
items:
|
||||||
icon:bgColor:
|
type: number
|
||||||
type: string
|
description: A valid uid
|
||||||
description: A six-character hexadecimal colour code assigned to the user. This
|
responses:
|
||||||
value is used in conjunction with
|
'200':
|
||||||
`icon:text` for the user's
|
description: users successfully invited to chat room
|
||||||
auto-generated icon
|
content:
|
||||||
example: "#f44336"
|
application/json:
|
||||||
isOwner:
|
schema:
|
||||||
type: boolean
|
type: object
|
||||||
canKick:
|
properties:
|
||||||
type: boolean
|
status:
|
||||||
|
$ref: ../../../components/schemas/Status.yaml#/Status
|
||||||
|
response:
|
||||||
|
$ref: ../../../components/schemas/Chats.yaml#/RoomUserList
|
||||||
@@ -244,18 +244,15 @@ define('forum/chats', [
|
|||||||
require(['autocomplete', 'translator'], function (autocomplete, translator) {
|
require(['autocomplete', 'translator'], function (autocomplete, translator) {
|
||||||
autocomplete.user(searchInput, function (event, selected) {
|
autocomplete.user(searchInput, function (event, selected) {
|
||||||
errorEl.text('');
|
errorEl.text('');
|
||||||
socket.emit('modules.chats.addUserToRoom', {
|
api.post(`/chats/${roomId}/users`, {
|
||||||
roomId: roomId,
|
uids: [selected.item.user.uid],
|
||||||
username: selected.item.user.name,
|
}).then((body) => {
|
||||||
}, function (err) {
|
Chats.refreshParticipantsList(roomId, modal, body);
|
||||||
if (err) {
|
|
||||||
translator.translate(err.message, function (translated) {
|
|
||||||
errorEl.text(translated);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Chats.refreshParticipantsList(roomId, modal);
|
|
||||||
searchInput.val('');
|
searchInput.val('');
|
||||||
|
}).catch((err) => {
|
||||||
|
translator.translate(err.message, function (translated) {
|
||||||
|
errorEl.text(translated);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -307,16 +304,21 @@ define('forum/chats', [
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Chats.refreshParticipantsList = function (roomId, modal) {
|
Chats.refreshParticipantsList = async (roomId, modal, data) => {
|
||||||
const listEl = modal.find('.list-group');
|
const listEl = modal.find('.list-group');
|
||||||
api.get(`/chats/${roomId}/users`, {}).then(({ users }) => {
|
|
||||||
app.parseAndTranslate('partials/modals/manage_room_users', { users }, function (html) {
|
if (!data) {
|
||||||
listEl.html(html);
|
try {
|
||||||
});
|
data = await api.get(`/chats/${roomId}/users`, {});
|
||||||
}).catch(() => {
|
} catch (err) {
|
||||||
translator.translate('[[error:invalid-data]]', function (translated) {
|
translator.translate('[[error:invalid-data]]', function (translated) {
|
||||||
listEl.find('li').text(translated);
|
listEl.find('li').text(translated);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app.parseAndTranslate('partials/modals/manage_room_users', data, function (html) {
|
||||||
|
listEl.html(html);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -83,3 +83,21 @@ chatsAPI.users = async (caller, data) => {
|
|||||||
});
|
});
|
||||||
return { users };
|
return { users };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
chatsAPI.invite = async (caller, data) => {
|
||||||
|
const userCount = await messaging.getUserCountInRoom(data.roomId);
|
||||||
|
const maxUsers = meta.config.maximumUsersInChatRoom;
|
||||||
|
if (maxUsers && userCount >= maxUsers) {
|
||||||
|
throw new Error('[[error:cant-add-more-users-to-chat-room]]');
|
||||||
|
}
|
||||||
|
|
||||||
|
const uidsExist = await user.exists(data.uids);
|
||||||
|
if (!uidsExist.every(Boolean)) {
|
||||||
|
throw new Error('[[error:no-user]]');
|
||||||
|
}
|
||||||
|
await Promise.all(data.uids.map(async uid => messaging.canMessageUser(caller.uid, uid)));
|
||||||
|
await messaging.addUsersToRoom(caller.uid, data.uids, data.roomId);
|
||||||
|
|
||||||
|
delete data.uids;
|
||||||
|
return chatsAPI.users(caller, data);
|
||||||
|
};
|
||||||
|
|||||||
@@ -61,7 +61,12 @@ Chats.users = async (req, res) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Chats.invite = async (req, res) => {
|
Chats.invite = async (req, res) => {
|
||||||
// ...
|
const users = await api.chats.invite(req, {
|
||||||
|
...req.body,
|
||||||
|
roomId: req.params.roomId,
|
||||||
|
});
|
||||||
|
|
||||||
|
helpers.formatApiResponse(200, res, users);
|
||||||
};
|
};
|
||||||
|
|
||||||
Chats.kick = async (req, res) => {
|
Chats.kick = async (req, res) => {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ module.exports = function () {
|
|||||||
// no route for room deletion, noted here just in case...
|
// no route for room deletion, noted here just in case...
|
||||||
|
|
||||||
setupApiRoute(router, 'get', '/:roomId/users', [...middlewares, middleware.assert.room], controllers.write.chats.users);
|
setupApiRoute(router, 'get', '/:roomId/users', [...middlewares, middleware.assert.room], controllers.write.chats.users);
|
||||||
// setupApiRoute(router, 'put', '/:roomId/users', [...middlewares, middleware.assert.room, middleware.checkRequired.bind(null, ['uids'])], controllers.write.chats.invite);
|
setupApiRoute(router, 'post', '/:roomId/users', [...middlewares, middleware.assert.room, middleware.checkRequired.bind(null, ['uids'])], controllers.write.chats.invite);
|
||||||
// setupApiRoute(router, 'delete', '/:roomId/users', [...middlewares, middleware.assert.room, middleware.checkRequired.bind(null, ['uids'])], controllers.write.chats.kick);
|
// setupApiRoute(router, 'delete', '/:roomId/users', [...middlewares, middleware.assert.room, middleware.checkRequired.bind(null, ['uids'])], controllers.write.chats.kick);
|
||||||
|
|
||||||
setupApiRoute(router, 'get', '/:roomId/:mid', [...middlewares, middleware.assert.room, middleware.assert.message], controllers.write.chats.messages.get);
|
setupApiRoute(router, 'get', '/:roomId/:mid', [...middlewares, middleware.assert.room, middleware.assert.message], controllers.write.chats.messages.get);
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ SocketModules.chats.loadRoom = async function (socket, data) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
SocketModules.chats.getUsersInRoom = async function (socket, data) {
|
SocketModules.chats.getUsersInRoom = async function (socket, data) {
|
||||||
sockets.warnDeprecated(socket, 'GET /api/v3/chats/:roomId/user');
|
sockets.warnDeprecated(socket, 'GET /api/v3/chats/:roomId/users');
|
||||||
|
|
||||||
if (!data || !data.roomId) {
|
if (!data || !data.roomId) {
|
||||||
throw new Error('[[error:invalid-data]]');
|
throw new Error('[[error:invalid-data]]');
|
||||||
@@ -98,6 +98,8 @@ SocketModules.chats.getUsersInRoom = async function (socket, data) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
SocketModules.chats.addUserToRoom = async function (socket, data) {
|
SocketModules.chats.addUserToRoom = async function (socket, data) {
|
||||||
|
sockets.warnDeprecated(socket, 'POST /api/v3/chats/:roomId/users');
|
||||||
|
|
||||||
if (!data || !data.roomId || !data.username) {
|
if (!data || !data.roomId || !data.username) {
|
||||||
throw new Error('[[error:invalid-data]]');
|
throw new Error('[[error:invalid-data]]');
|
||||||
}
|
}
|
||||||
@@ -107,18 +109,11 @@ SocketModules.chats.addUserToRoom = async function (socket, data) {
|
|||||||
throw new Error('[[error:no-privileges]]');
|
throw new Error('[[error:no-privileges]]');
|
||||||
}
|
}
|
||||||
|
|
||||||
const userCount = await Messaging.getUserCountInRoom(data.roomId);
|
// Revised API now takes uids, not usernames
|
||||||
const maxUsers = meta.config.maximumUsersInChatRoom;
|
data.uids = [await user.getUidByUsername(data.username)];
|
||||||
if (maxUsers && userCount >= maxUsers) {
|
delete data.username;
|
||||||
throw new Error('[[error:cant-add-more-users-to-chat-room]]');
|
|
||||||
}
|
|
||||||
|
|
||||||
const uid = await user.getUidByUsername(data.username);
|
await api.chats.invite(socket, data);
|
||||||
if (!uid) {
|
|
||||||
throw new Error('[[error:no-user]]');
|
|
||||||
}
|
|
||||||
await Messaging.canMessageUser(socket.uid, uid);
|
|
||||||
await Messaging.addUsersToRoom(socket.uid, [uid], data.roomId);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
SocketModules.chats.removeUserFromRoom = async function (socket, data) {
|
SocketModules.chats.removeUserFromRoom = async function (socket, data) {
|
||||||
|
|||||||
@@ -88,17 +88,13 @@ describe('Messaging Library', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT allow messages to be sent to a restricted user', (done) => {
|
it('should NOT allow messages to be sent to a restricted user', async () => {
|
||||||
User.setSetting(mocks.users.baz.uid, 'restrictChat', '1', (err) => {
|
await User.setSetting(mocks.users.baz.uid, 'restrictChat', '1');
|
||||||
assert.ifError(err);
|
try {
|
||||||
Messaging.canMessageUser(mocks.users.herp.uid, mocks.users.baz.uid, (err) => {
|
await Messaging.canMessageUser(mocks.users.herp.uid, mocks.users.baz.uid);
|
||||||
assert.strictEqual(err.message, '[[error:chat-restricted]]');
|
} catch (err) {
|
||||||
socketModules.chats.addUserToRoom({ uid: mocks.users.herp.uid }, { roomId: 1, username: 'baz' }, (err) => {
|
assert.strictEqual(err.message, '[[error:chat-restricted]]');
|
||||||
assert.equal(err.message, '[[error:chat-restricted]]');
|
}
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should always allow admins through', (done) => {
|
it('should always allow admins through', (done) => {
|
||||||
@@ -169,35 +165,26 @@ describe('Messaging Library', () => {
|
|||||||
assert.equal(body2.status.message, await translator.translate('[[error:cant-edit-chat-message]]'));
|
assert.equal(body2.status.message, await translator.translate('[[error:cant-edit-chat-message]]'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail to add user to room with invalid data', (done) => {
|
it('should fail to add user to room with invalid data', async () => {
|
||||||
socketModules.chats.addUserToRoom({ uid: mocks.users.foo.uid }, null, (err) => {
|
let { statusCode, body } = await callv3API('post', `/chats/${roomId}/users`, {}, 'foo');
|
||||||
assert.equal(err.message, '[[error:invalid-data]]');
|
assert.strictEqual(statusCode, 400);
|
||||||
socketModules.chats.addUserToRoom({ uid: mocks.users.foo.uid }, { roomId: null }, (err) => {
|
assert.strictEqual(body.status.message, await translator.translate('[[error:required-parameters-missing, uids]]'));
|
||||||
assert.equal(err.message, '[[error:invalid-data]]');
|
|
||||||
socketModules.chats.addUserToRoom({ uid: mocks.users.foo.uid }, { roomId: roomId, username: null }, (err) => {
|
({ statusCode, body } = await callv3API('post', `/chats/${roomId}/users`, { uids: [null] }, 'foo'));
|
||||||
assert.equal(err.message, '[[error:invalid-data]]');
|
assert.strictEqual(statusCode, 400);
|
||||||
done();
|
assert.strictEqual(body.status.message, await translator.translate('[[error:no-user]]'));
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add a user to room', (done) => {
|
it('should add a user to room', async () => {
|
||||||
socketModules.chats.addUserToRoom({ uid: mocks.users.foo.uid }, { roomId: roomId, username: 'herp' }, (err) => {
|
await callv3API('post', `/chats/${roomId}/users`, { uids: [mocks.users.herp.uid] }, 'foo');
|
||||||
assert.ifError(err);
|
const isInRoom = await Messaging.isUserInRoom(mocks.users.herp.uid, roomId);
|
||||||
Messaging.isUserInRoom(mocks.users.herp.uid, roomId, (err, isInRoom) => {
|
assert(isInRoom);
|
||||||
assert.ifError(err);
|
|
||||||
assert(isInRoom);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get users in room', async () => {
|
it('should get users in room', async () => {
|
||||||
const { body } = await callv3API('get', `/chats/${roomId}/users`, {}, 'foo');
|
const { body } = await callv3API('get', `/chats/${roomId}/users`, {}, 'foo');
|
||||||
assert(Array.isArray(body.response.users));
|
assert(Array.isArray(body.response.users));
|
||||||
assert.strictEqual(body.response.users.length, 3);
|
assert.strictEqual(body.response.users.length, 3);
|
||||||
console.log(body.response.users);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw error if user is not in room', async () => {
|
it('should throw error if user is not in room', async () => {
|
||||||
@@ -206,27 +193,24 @@ describe('Messaging Library', () => {
|
|||||||
assert.equal(body.status.message, await translator.translate('[[error:no-privileges]]'));
|
assert.equal(body.status.message, await translator.translate('[[error:no-privileges]]'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail to add users to room if max is reached', (done) => {
|
it('should fail to add users to room if max is reached', async () => {
|
||||||
meta.config.maximumUsersInChatRoom = 2;
|
meta.config.maximumUsersInChatRoom = 2;
|
||||||
socketModules.chats.addUserToRoom({ uid: mocks.users.foo.uid }, { roomId: roomId, username: 'test' }, (err) => {
|
const { statusCode, body } = await callv3API('post', `/chats/${roomId}/users`, { uids: [mocks.users.bar.uid] }, 'foo');
|
||||||
assert.equal(err.message, '[[error:cant-add-more-users-to-chat-room]]');
|
assert.strictEqual(statusCode, 400);
|
||||||
meta.config.maximumUsersInChatRoom = 0;
|
assert.equal(body.status.message, await translator.translate('[[error:cant-add-more-users-to-chat-room]]'));
|
||||||
done();
|
meta.config.maximumUsersInChatRoom = 0;
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail to add users to room if user does not exist', (done) => {
|
it('should fail to add users to room if user does not exist', async () => {
|
||||||
socketModules.chats.addUserToRoom({ uid: mocks.users.foo.uid }, { roomId: roomId, username: 'doesnotexist' }, (err) => {
|
const { statusCode, body } = await callv3API('post', `/chats/${roomId}/users`, { uids: [98237498234] }, 'foo');
|
||||||
assert.equal(err.message, '[[error:no-user]]');
|
assert.strictEqual(statusCode, 400);
|
||||||
done();
|
assert.strictEqual(body.status.message, await translator.translate('[[error:no-user]]'));
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail to add self to room', (done) => {
|
it('should fail to add self to room', async () => {
|
||||||
socketModules.chats.addUserToRoom({ uid: mocks.users.foo.uid }, { roomId: roomId, username: 'foo' }, (err) => {
|
const { statusCode, body } = await callv3API('post', `/chats/${roomId}/users`, { uids: [mocks.users.foo.uid] }, 'foo');
|
||||||
assert.equal(err.message, '[[error:cant-chat-with-yourself]]');
|
assert.strictEqual(statusCode, 400);
|
||||||
done();
|
assert.strictEqual(body.status.message, await translator.translate('[[error:cant-chat-with-yourself]]'));
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail to leave room with invalid data', (done) => {
|
it('should fail to leave room with invalid data', (done) => {
|
||||||
@@ -286,7 +270,7 @@ describe('Messaging Library', () => {
|
|||||||
uids: [mocks.users.foo.uid],
|
uids: [mocks.users.foo.uid],
|
||||||
}, 'herp');
|
}, 'herp');
|
||||||
|
|
||||||
await util.promisify(socketModules.chats.addUserToRoom)({ uid: mocks.users.herp.uid }, { roomId: body.response.roomId, username: 'baz' });
|
await callv3API('post', `/chats/${body.response.roomId}/users`, { uids: [mocks.users.baz.uid] }, 'herp');
|
||||||
await util.promisify(socketModules.chats.leave)({ uid: mocks.users.herp.uid }, body.response.roomId);
|
await util.promisify(socketModules.chats.leave)({ uid: mocks.users.herp.uid }, body.response.roomId);
|
||||||
|
|
||||||
const data = await Messaging.getRoomData(body.response.roomId);
|
const data = await Messaging.getRoomData(body.response.roomId);
|
||||||
@@ -348,9 +332,7 @@ describe('Messaging Library', () => {
|
|||||||
assert.equal(err.message, '[[error:cant-remove-last-user]]');
|
assert.equal(err.message, '[[error:cant-remove-last-user]]');
|
||||||
}
|
}
|
||||||
|
|
||||||
await util.promisify(
|
await callv3API('post', `/chats/${roomId}/users`, { uids: [mocks.users.baz.uid] }, 'foo');
|
||||||
socketModules.chats.addUserToRoom
|
|
||||||
)({ uid: mocks.users.foo.uid }, { roomId: roomId, username: 'baz' });
|
|
||||||
await util.promisify(
|
await util.promisify(
|
||||||
socketModules.chats.removeUserFromRoom
|
socketModules.chats.removeUserFromRoom
|
||||||
)({ uid: mocks.users.foo.uid }, { roomId: roomId, uid: mocks.users.herp.uid });
|
)({ uid: mocks.users.foo.uid }, { roomId: roomId, uid: mocks.users.herp.uid });
|
||||||
@@ -437,7 +419,7 @@ describe('Messaging Library', () => {
|
|||||||
const { roomId } = body.response;
|
const { roomId } = body.response;
|
||||||
assert(roomId);
|
assert(roomId);
|
||||||
|
|
||||||
await socketModules.chats.addUserToRoom({ uid: mocks.users.foo.uid }, { roomId: roomId, username: 'herp' });
|
await callv3API('post', `/chats/${roomId}/users`, { uids: [mocks.users.herp.uid] }, 'foo');
|
||||||
await db.sortedSetAdd('users:online', Date.now() - ((meta.config.onlineCutoff * 60000) + 50000), mocks.users.herp.uid);
|
await db.sortedSetAdd('users:online', Date.now() - ((meta.config.onlineCutoff * 60000) + 50000), mocks.users.herp.uid);
|
||||||
|
|
||||||
await callv3API('post', `/chats/${roomId}`, { roomId: roomId, message: 'second chat message **bold** text' }, 'foo');
|
await callv3API('post', `/chats/${roomId}`, { roomId: roomId, message: 'second chat message **bold** text' }, 'foo');
|
||||||
@@ -626,7 +608,7 @@ describe('Messaging Library', () => {
|
|||||||
let mid;
|
let mid;
|
||||||
let mid2;
|
let mid2;
|
||||||
before(async () => {
|
before(async () => {
|
||||||
await socketModules.chats.addUserToRoom({ uid: mocks.users.foo.uid }, { roomId: roomId, username: 'baz' });
|
await callv3API('post', `/chats/${roomId}/users`, { uids: [mocks.users.baz.uid] }, 'foo');
|
||||||
let { body } = await callv3API('post', `/chats/${roomId}`, { roomId: roomId, message: 'first chat message' }, 'foo');
|
let { body } = await callv3API('post', `/chats/${roomId}`, { roomId: roomId, message: 'first chat message' }, 'foo');
|
||||||
mid = body.response.mid;
|
mid = body.response.mid;
|
||||||
({ body } = await callv3API('post', `/chats/${roomId}`, { roomId: roomId, message: 'second chat message' }, 'baz'));
|
({ body } = await callv3API('post', `/chats/${roomId}`, { roomId: roomId, message: 'second chat message' }, 'baz'));
|
||||||
|
|||||||
Reference in New Issue
Block a user