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
+ }
+ }
+ }
}
}
},