feat: `GET /chats/:roomId/users` [breaking]

isekai-main
Julian Lam 3 years ago
parent d5fd098ecf
commit 6eea6451d2

@ -140,6 +140,8 @@ paths:
$ref: 'write/chats.yaml'
/chats/{roomId}:
$ref: 'write/chats/roomId.yaml'
/chats/{roomId}/users:
$ref: 'write/chats/roomId/users.yaml'
/chats/{roomId}/{mid}:
$ref: 'write/chats/roomId/mid.yaml'
/flags/:

@ -0,0 +1,61 @@
get:
tags:
- chats
summary: get chat room users
description: This operation retrieves the users in a chat room message
parameters:
- in: path
name: roomId
schema:
type: number
required: true
description: a valid chat room id
example: 1
responses:
'200':
description: Users successfully retrieved
content:
application/json:
schema:
type: object
properties:
status:
$ref: ../../../components/schemas/Status.yaml#/Status
response:
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

@ -308,20 +308,15 @@ define('forum/chats', [
};
Chats.refreshParticipantsList = function (roomId, modal) {
socket.emit('modules.chats.getUsersInRoom', { roomId: roomId }, function (err, users) {
const listEl = modal.find('.list-group');
if (err) {
return translator.translate('[[error:invalid-data]]', function (translated) {
listEl.find('li').text(translated);
});
}
app.parseAndTranslate('partials/modals/manage_room_users', {
users: users,
}, function (html) {
api.get(`/chats/${roomId}/users`, {}).then(({ users }) => {
app.parseAndTranslate('partials/modals/manage_room_users', { users }, function (html) {
listEl.html(html);
});
}).catch(() => {
translator.translate('[[error:invalid-data]]', function (translated) {
listEl.find('li').text(translated);
});
});
};

@ -72,3 +72,14 @@ chatsAPI.rename = async (caller, data) => {
roomId: data.roomId,
});
};
chatsAPI.users = async (caller, data) => {
const [isOwner, users] = await Promise.all([
messaging.isRoomOwner(caller.uid, data.roomId),
messaging.getUsersInRoom(data.roomId, 0, -1),
]);
users.forEach((user) => {
user.canKick = (parseInt(user.uid, 10) !== parseInt(caller.uid, 10)) && isOwner;
});
return { users };
};

@ -54,7 +54,10 @@ Chats.rename = async (req, res) => {
};
Chats.users = async (req, res) => {
// ...
const users = await api.chats.users(req, {
...req.params,
});
helpers.formatApiResponse(200, res, users);
};
Chats.invite = async (req, res) => {

@ -19,7 +19,7 @@ module.exports = function () {
setupApiRoute(router, 'put', '/:roomId', [...middlewares, middleware.assert.room, middleware.checkRequired.bind(null, ['name'])], controllers.write.chats.rename);
// 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, 'delete', '/:roomId/users', [...middlewares, middleware.assert.room, middleware.checkRequired.bind(null, ['uids'])], controllers.write.chats.kick);

@ -84,21 +84,17 @@ SocketModules.chats.loadRoom = async function (socket, data) {
};
SocketModules.chats.getUsersInRoom = async function (socket, data) {
sockets.warnDeprecated(socket, 'GET /api/v3/chats/:roomId/user');
if (!data || !data.roomId) {
throw new Error('[[error:invalid-data]]');
}
const [isUserInRoom, isOwner, userData] = await Promise.all([
Messaging.isUserInRoom(socket.uid, data.roomId),
Messaging.isRoomOwner(socket.uid, data.roomId),
Messaging.getUsersInRoom(data.roomId, 0, -1),
]);
const isUserInRoom = await Messaging.isUserInRoom(socket.uid, data.roomId);
if (!isUserInRoom) {
throw new Error('[[error:no-privileges]]');
}
userData.forEach((user) => {
user.canKick = (parseInt(user.uid, 10) !== parseInt(socket.uid, 10)) && isOwner;
});
return userData;
return api.chats.users(socket, data);
};
SocketModules.chats.addUserToRoom = async function (socket, data) {

@ -22,6 +22,7 @@ describe('Messaging Library', () => {
const mocks = {
users: {
foo: {}, // the admin
bar: {},
baz: {}, // the user with chat restriction enabled
herp: {},
},
@ -53,10 +54,12 @@ describe('Messaging Library', () => {
// Create 3 users: 1 admin, 2 regular
({
foo: mocks.users.foo.uid,
bar: mocks.users.bar.uid,
baz: mocks.users.baz.uid,
herp: mocks.users.herp.uid,
} = await utils.promiseParallel({
foo: User.create({ username: 'foo', password: 'barbar' }), // admin
bar: User.create({ username: 'bar', password: 'bazbaz' }), // admin
baz: User.create({ username: 'baz', password: 'quuxquux' }), // restricted user
herp: User.create({ username: 'herp', password: 'derpderp' }), // a regular user
}));
@ -65,6 +68,7 @@ describe('Messaging Library', () => {
await User.setSetting(mocks.users.baz.uid, 'restrictChat', '1');
({ jar: mocks.users.foo.jar, csrf_token: mocks.users.foo.csrf } = await util.promisify(helpers.loginUser)('foo', 'barbar'));
({ jar: mocks.users.bar.jar, csrf_token: mocks.users.bar.csrf } = await util.promisify(helpers.loginUser)('bar', 'bazbaz'));
({ jar: mocks.users.baz.jar, csrf_token: mocks.users.baz.csrf } = await util.promisify(helpers.loginUser)('baz', 'quuxquux'));
({ jar: mocks.users.herp.jar, csrf_token: mocks.users.herp.csrf } = await util.promisify(helpers.loginUser)('herp', 'derpderp'));
@ -190,17 +194,16 @@ describe('Messaging Library', () => {
});
it('should get users in room', async () => {
const data = await socketModules.chats.getUsersInRoom({ uid: mocks.users.foo.uid }, { roomId: roomId });
assert(Array.isArray(data));
assert.strictEqual(data.length, 3);
const { body } = await callv3API('get', `/chats/${roomId}/users`, {}, 'foo');
assert(Array.isArray(body.response.users));
assert.strictEqual(body.response.users.length, 3);
console.log(body.response.users);
});
it('should throw error if user is not in room', async () => {
try {
const data = await socketModules.chats.getUsersInRoom({ uid: 123123123 }, { roomId: roomId });
} catch (err) {
assert.equal(err.message, '[[error:no-privileges]]');
}
const { statusCode, body } = await callv3API('get', `/chats/${roomId}/users`, {}, 'bar');
assert.strictEqual(statusCode, 403);
assert.equal(body.status.message, await translator.translate('[[error:no-privileges]]'));
});
it('should fail to add users to room if max is reached', (done) => {

Loading…
Cancel
Save