From b61e814787142a462b90b4948df5e9b67fd318a6 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 1 Nov 2023 14:43:47 -0400 Subject: [PATCH] refactor(socket.io): deprecate socketGroups.loadMore in favour of api.groups.list --- public/openapi/write/groups.yaml | 75 ++++++++++++++++++++++++++++++++ src/api/groups.js | 9 ++++ src/controllers/write/groups.js | 4 ++ src/routes/write/groups.js | 1 + src/socket.io/groups.js | 12 ++--- 5 files changed, 96 insertions(+), 5 deletions(-) diff --git a/public/openapi/write/groups.yaml b/public/openapi/write/groups.yaml index 8d325c758e..432e474f8a 100644 --- a/public/openapi/write/groups.yaml +++ b/public/openapi/write/groups.yaml @@ -1,3 +1,78 @@ +get: + tags: + - groups + summary: list groups + description: This operation returns a list of user groups. The number of groups returned is hardcoded to 10. + parameters: + - in: query + name: 'after' + schema: + type: number + required: false + description: An offset used to display a different subset of groups. + example: '0' + - in: query + name: 'sort' + schema: + type: string + enum: ['date', 'count'] + required: false + description: Changes how the returned groups are sorted. By default, will return groups in alphanumeric order. + example: 'date' + responses: + '200': + description: user groups successfully listed + content: + application/json: + schema: + type: object + properties: + status: + $ref: ../components/schemas/Status.yaml#/Status + response: + type: object + properties: + groups: + type: array + items: + allOf: + - $ref: ../components/schemas/GroupObject.yaml#/GroupDataObject + - type: object + properties: + members: + type: array + items: + type: object + properties: + uid: + type: number + description: A user identifier + example: 1 + username: + type: string + description: A friendly name for a given user account + example: Dragon Fruit + userslug: + type: string + description: An URL-safe variant of the username (i.e. lower-cased, spaces removed, etc.) + example: dragon-fruit + displayname: + type: string + description: This is either username or fullname depending on forum and user settings + example: Dragon Fruit + '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 + example: D + '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: '#9c27b0' + truncated: + type: boolean + description: Whether this returned member list is a subset of the total membership + nextStart: + type: number post: tags: - groups diff --git a/src/api/groups.js b/src/api/groups.js index 9bd08b5afc..3b0ecb7b10 100644 --- a/src/api/groups.js +++ b/src/api/groups.js @@ -12,6 +12,15 @@ const slugify = require('../slugify'); const groupsAPI = module.exports; +groupsAPI.list = async (caller, data) => { + const groupsPerPage = 10; + const start = parseInt(data.after || 0, 10); + const stop = start + groupsPerPage - 1; + const groupData = await groups.getGroupsBySort(data.sort, start, stop); + + return { groups: groupData, nextStart: stop + 1 }; +}; + groupsAPI.create = async function (caller, data) { if (!caller.uid) { throw new Error('[[error:no-privileges]]'); diff --git a/src/controllers/write/groups.js b/src/controllers/write/groups.js index a8abd56404..8e18450139 100644 --- a/src/controllers/write/groups.js +++ b/src/controllers/write/groups.js @@ -6,6 +6,10 @@ const helpers = require('../helpers'); const Groups = module.exports; +Groups.list = async (req, res) => { + helpers.formatApiResponse(200, res, await api.groups.list(req, { ...req.query })); +}; + Groups.exists = async (req, res) => { helpers.formatApiResponse(200, res); }; diff --git a/src/routes/write/groups.js b/src/routes/write/groups.js index f2ee86eab6..d6f78217c9 100644 --- a/src/routes/write/groups.js +++ b/src/routes/write/groups.js @@ -10,6 +10,7 @@ const { setupApiRoute } = routeHelpers; module.exports = function () { const middlewares = [middleware.ensureLoggedIn]; + setupApiRoute(router, 'get', '/', [], controllers.write.groups.list); setupApiRoute(router, 'post', '/', [...middlewares, middleware.checkRequired.bind(null, ['name'])], controllers.write.groups.create); setupApiRoute(router, 'head', '/:slug', [middleware.assert.group], controllers.write.groups.exists); setupApiRoute(router, 'put', '/:slug', [...middlewares, middleware.assert.group], controllers.write.groups.update); diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index d34eec366e..2f3d45dc7a 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -4,6 +4,9 @@ const groups = require('../groups'); const user = require('../user'); const utils = require('../utils'); const privileges = require('../privileges'); +const api = require('../api'); + +const sockets = require('.'); const SocketGroups = module.exports; @@ -26,15 +29,14 @@ SocketGroups.search = async (socket, data) => { }; SocketGroups.loadMore = async (socket, data) => { + sockets.warnDeprecated(socket, 'GET /api/v3/groups'); + + // These restrictions were left behind for websocket specific calls, the API is more flexible and requires no params if (!data.sort || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0) { throw new Error('[[error:invalid-data]]'); } - const groupsPerPage = 10; - const start = parseInt(data.after, 10); - const stop = start + groupsPerPage - 1; - const groupData = await groups.getGroupsBySort(data.sort, start, stop); - return { groups: groupData, nextStart: stop + 1 }; + return api.groups.list(socket, data); }; SocketGroups.searchMembers = async (socket, data) => {