diff --git a/server/endpoints/api/admin/index.js b/server/endpoints/api/admin/index.js index c165a9cc02..18f59ee872 100644 --- a/server/endpoints/api/admin/index.js +++ b/server/endpoints/api/admin/index.js @@ -4,6 +4,7 @@ const { SystemSettings } = require("../../../models/systemSettings"); const { User } = require("../../../models/user"); const { Workspace } = require("../../../models/workspace"); const { WorkspaceChats } = require("../../../models/workspaceChats"); +const { WorkspaceUser } = require("../../../models/workspaceUsers"); const { canModifyAdmin } = require("../../../utils/helpers/admin"); const { multiUserMode, reqBody } = require("../../../utils/http"); const { validApiKey } = require("../../../utils/middleware/validApiKey"); @@ -420,6 +421,7 @@ function apiAdminEndpoints(app) { } } ); + app.get( "/v1/admin/workspaces/:workspaceId/users", [validApiKey], @@ -474,12 +476,14 @@ function apiAdminEndpoints(app) { } } ); + app.post( "/v1/admin/workspaces/:workspaceId/update-users", [validApiKey], async (request, response) => { /* #swagger.tags = ['Admin'] + #swagger.deprecated = true #swagger.parameters['workspaceId'] = { in: 'path', description: 'id of the workspace in the database.', @@ -539,6 +543,130 @@ function apiAdminEndpoints(app) { } } ); + + app.post( + "/v1/admin/workspaces/:workspaceSlug/manage-users", + [validApiKey], + async (request, response) => { + /* + #swagger.tags = ['Admin'] + #swagger.parameters['workspaceSlug'] = { + in: 'path', + description: 'slug of the workspace in the database', + required: true, + type: 'string' + } + #swagger.description = 'Set workspace permissions to be accessible by the given user ids and admins. Methods are disabled until multi user mode is enabled via the UI.' + #swagger.requestBody = { + description: 'Array of user ids who will be given access to the target workspace. reset will remove all existing users from the workspace and only add the new users - default false.', + required: true, + content: { + "application/json": { + example: { + userIds: [1,2,4,12], + reset: false + } + } + } + } + #swagger.responses[200] = { + content: { + "application/json": { + schema: { + type: 'object', + example: { + success: true, + error: null, + users: [ + {"userId": 1, "username": "main-admin", "role": "admin"}, + {"userId": 2, "username": "sample-sam", "role": "default"} + ] + } + } + } + } + } + #swagger.responses[403] = { + schema: { + "$ref": "#/definitions/InvalidAPIKey" + } + } + #swagger.responses[401] = { + description: "Instance is not in Multi-User mode. Method denied", + } + */ + try { + if (!multiUserMode(response)) { + response.sendStatus(401).end(); + return; + } + + const { workspaceSlug } = request.params; + const { userIds: _uids, reset = false } = reqBody(request); + const userIds = ( + await User.where({ id: { in: _uids.map(Number) } }) + ).map((user) => user.id); + const workspace = await Workspace.get({ slug: String(workspaceSlug) }); + const workspaceUsers = await Workspace.workspaceUsers(workspace.id); + + if (!workspace) { + response + .status(404) + .json({ + success: false, + error: `Workspace ${workspaceSlug} not found`, + users: workspaceUsers, + }); + return; + } + + if (userIds.length === 0) { + response + .status(404) + .json({ + success: false, + error: `No valid user IDs provided.`, + users: workspaceUsers, + }); + return; + } + + // Reset all users in the workspace and add the new users as the only users in the workspace + if (reset) { + const { success, error } = await Workspace.updateUsers( + workspace.id, + userIds + ); + return response + .status(200) + .json({ + success, + error, + users: await Workspace.workspaceUsers(workspace.id), + }); + } + + // Add new users to the workspace if they are not already in the workspace + const existingUserIds = workspaceUsers.map((user) => user.userId); + const usersToAdd = userIds.filter( + (userId) => !existingUserIds.includes(userId) + ); + if (usersToAdd.length > 0) + await WorkspaceUser.createManyUsers(usersToAdd, workspace.id); + response + .status(200) + .json({ + success: true, + error: null, + users: await Workspace.workspaceUsers(workspace.id), + }); + } catch (e) { + console.error(e); + response.sendStatus(500).end(); + } + } + ); + app.post( "/v1/admin/workspace-chats", [validApiKey], diff --git a/server/models/workspace.js b/server/models/workspace.js index 47734ddd51..5bc9301948 100644 --- a/server/models/workspace.js +++ b/server/models/workspace.js @@ -243,6 +243,11 @@ const Workspace = { } }, + /** + * Get all users for a workspace. + * @param {number} workspaceId - The ID of the workspace to get users for. + * @returns {Promise>} A promise that resolves to an array of user objects. + */ workspaceUsers: async function (workspaceId) { try { const users = ( @@ -270,6 +275,12 @@ const Workspace = { } }, + /** + * Update the users for a workspace. Will remove all existing users and replace them with the new list. + * @param {number} workspaceId - The ID of the workspace to update. + * @param {number[]} userIds - An array of user IDs to add to the workspace. + * @returns {Promise<{success: boolean, error: string | null}>} A promise that resolves to an object containing the success status and an error message if applicable. + */ updateUsers: async function (workspaceId, userIds = []) { try { await WorkspaceUser.delete({ workspace_id: Number(workspaceId) }); diff --git a/server/models/workspaceUsers.js b/server/models/workspaceUsers.js index 5f66a1add4..c27dc858a0 100644 --- a/server/models/workspaceUsers.js +++ b/server/models/workspaceUsers.js @@ -17,6 +17,12 @@ const WorkspaceUser = { return; }, + /** + * Create many workspace users. + * @param {Array} userIds - An array of user IDs to create workspace users for. + * @param {number} workspaceId - The ID of the workspace to create workspace users for. + * @returns {Promise} A promise that resolves when the workspace users are created. + */ createManyUsers: async function (userIds = [], workspaceId) { if (userIds.length === 0) return; try { diff --git a/server/swagger/openapi.json b/server/swagger/openapi.json index 230398ada5..505d579628 100644 --- a/server/swagger/openapi.json +++ b/server/swagger/openapi.json @@ -635,6 +635,95 @@ } } } + }, + "deprecated": true + } + }, + "/v1/admin/workspaces/{workspaceSlug}/manage-users": { + "post": { + "tags": [ + "Admin" + ], + "description": "Set workspace permissions to be accessible by the given user ids and admins. Methods are disabled until multi user mode is enabled via the UI.", + "parameters": [ + { + "name": "workspaceSlug", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "slug of the workspace in the database" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "example": { + "success": true, + "error": null, + "users": [ + { + "userId": 1, + "username": "main-admin", + "role": "admin" + }, + { + "userId": 2, + "username": "sample-sam", + "role": "default" + } + ] + } + } + } + } + }, + "401": { + "description": "Instance is not in Multi-User mode. Method denied" + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidAPIKey" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/InvalidAPIKey" + } + } + } + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + }, + "requestBody": { + "description": "Array of user ids who will be given access to the target workspace. reset will remove all existing users from the workspace and only add the new users - default false.", + "required": true, + "content": { + "application/json": { + "example": { + "userIds": [ + 1, + 2, + 4, + 12 + ], + "reset": false + } + } + } } } },