|
|
const { ApiKey } = require("../models/apiKeys");const { Document } = require("../models/documents");const { EventLogs } = require("../models/eventLogs");const { Invite } = require("../models/invite");const { SystemSettings } = require("../models/systemSettings");const { Telemetry } = require("../models/telemetry");const { User } = require("../models/user");const { DocumentVectors } = require("../models/vectors");const { Workspace } = require("../models/workspace");const { WorkspaceChats } = require("../models/workspaceChats");const { getVectorDbClass, getEmbeddingEngineSelection,} = require("../utils/helpers");const { validRoleSelection, canModifyAdmin, validCanModify,} = require("../utils/helpers/admin");const { reqBody, userFromSession, safeJsonParse } = require("../utils/http");const { strictMultiUserRoleValid, flexUserRoleValid, ROLES,} = require("../utils/middleware/multiUserProtected");const { validatedRequest } = require("../utils/middleware/validatedRequest");const ImportedPlugin = require("../utils/agents/imported");
function adminEndpoints(app) { if (!app) return;
app.get( "/admin/users", [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])], async (_request, response) => { try { console.log("调用了调用了admin/users"); const users = await User.where(); response.status(200).json({ users }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
app.post( "/admin/users/new", [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])], async (request, response) => { try { const currUser = await userFromSession(request, response); const newUserParams = reqBody(request); const roleValidation = validRoleSelection(currUser, newUserParams);
if (!roleValidation.valid) { response .status(200) .json({ user: null, error: roleValidation.error }); return; }
const { user: newUser, error } = await User.create(newUserParams); if (!!newUser) { await EventLogs.logEvent( "user_created", { userName: newUser.username, createdBy: currUser.username, }, currUser.id ); }
response.status(200).json({ user: newUser, error }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
// app.post(
// "/admin/users/new",
// [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])],
// async (request, response) => {
// try {
// const currUser = await userFromSession(request, response);
// const newUserParams = reqBody(request);
// const roleValidation = validRoleSelection(currUser, newUserParams);
//
// // 验证角色权限
// if (!roleValidation.valid) {
// response
// .status(200)
// .json({ user: null, error: roleValidation.error });
// return;
// }
//
// // 使用事务确保原子性
// const result = await prisma.$transaction(async (prisma) => {
// // 1. 创建用户
// const newUser = await prisma.users.create({
// data: newUserParams,
// });
//
// // 2. 将用户和组织机构关联到 dept_users 表
// if (newUserParams.deptId) {
// await prisma.dept_users.create({
// data: {
// deptId: newUserParams.deptId,
// userId: newUser.id,
// createdAt: new Date(),
// updatedAt: new Date(),
// },
// });
// }
//
// // 3. 记录事件日志
// await EventLogs.logEvent(
// "user_created",
// {
// userName: newUser.username,
// createdBy: currUser.username,
// },
// currUser.id
// );
//
// return { user: newUser, error: null };
// });
//
// // 返回成功响应
// response.status(200).json(result);
// } catch (e) {
// console.error(e);
// response.status(500).json({ user: null, error: e.message });
// }
// }
// );
app.post( "/admin/user/:id", [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])], async (request, response) => { try { const currUser = await userFromSession(request, response); const { id } = request.params; const updates = reqBody(request); const user = await User.get({ id: Number(id) });
const canModify = validCanModify(currUser, user); if (!canModify.valid) { response.status(200).json({ success: false, error: canModify.error }); return; }
const roleValidation = validRoleSelection(currUser, updates); if (!roleValidation.valid) { response .status(200) .json({ success: false, error: roleValidation.error }); return; }
const validAdminRoleModification = await canModifyAdmin(user, updates); if (!validAdminRoleModification.valid) { response .status(200) .json({ success: false, error: validAdminRoleModification.error }); return; }
const { success, error } = await User.update(id, updates); response.status(200).json({ success, error }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
app.delete( "/admin/user/:id", [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])], async (request, response) => { try { const currUser = await userFromSession(request, response); const { id } = request.params; const user = await User.get({ id: Number(id) });
const canModify = validCanModify(currUser, user); if (!canModify.valid) { response.status(200).json({ success: false, error: canModify.error }); return; }
await User.delete({ id: Number(id) }); await EventLogs.logEvent( "user_deleted", { userName: user.username, deletedBy: currUser.username, }, currUser.id ); response.status(200).json({ success: true, error: null }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
app.get( "/admin/invites", [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])], async (_request, response) => { try { const invites = await Invite.whereWithUsers(); response.status(200).json({ invites }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
app.post( "/admin/invite/new", [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])], async (request, response) => { try { const user = await userFromSession(request, response); const body = reqBody(request); const { invite, error } = await Invite.create({ createdByUserId: user.id, workspaceIds: body?.workspaceIds || [], });
await EventLogs.logEvent( "invite_created", { inviteCode: invite.code, createdBy: response.locals?.user?.username, }, response.locals?.user?.id ); response.status(200).json({ invite, error }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
app.delete( "/admin/invite/:id", [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])], async (request, response) => { try { const { id } = request.params; const { success, error } = await Invite.deactivate(id); await EventLogs.logEvent( "invite_deleted", { deletedBy: response.locals?.user?.username }, response.locals?.user?.id ); response.status(200).json({ success, error }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
app.get( "/admin/workspaces", [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])], async (_request, response) => { try { const workspaces = await Workspace.whereWithUsers(); response.status(200).json({ workspaces }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
app.get( "/admin/workspaces/:workspaceId/users", [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])], async (request, response) => { try { const { workspaceId } = request.params; const users = await Workspace.workspaceUsers(workspaceId); response.status(200).json({ users }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
app.post( "/admin/workspaces/new", [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])], async (request, response) => { try { const user = await userFromSession(request, response); const { name } = reqBody(request); const { workspace, message: error } = await Workspace.new( name, user.id ); response.status(200).json({ workspace, error }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
app.post( "/admin/workspaces/:workspaceId/update-users", [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])], async (request, response) => { try { const { workspaceId } = request.params; const { userIds } = reqBody(request); const { success, error } = await Workspace.updateUsers( workspaceId, userIds ); response.status(200).json({ success, error }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
app.delete( "/admin/workspaces/:id", [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])], async (request, response) => { try { const { id } = request.params; const VectorDb = getVectorDbClass(); const workspace = await Workspace.get({ id: Number(id) }); if (!workspace) { response.sendStatus(404).end(); return; }
await WorkspaceChats.delete({ workspaceId: Number(workspace.id) }); await DocumentVectors.deleteForWorkspace(Number(workspace.id)); await Document.delete({ workspaceId: Number(workspace.id) }); await Workspace.delete({ id: Number(workspace.id) }); try { await VectorDb["delete-namespace"]({ namespace: workspace.slug }); } catch (e) { console.error(e.message); }
response.status(200).json({ success: true, error: null }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
// System preferences but only by array of labels
app.get( "/admin/system-preferences-for", [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])], async (request, response) => { try { const requestedSettings = {}; const labels = request.query.labels?.split(",") || []; const needEmbedder = [ "text_splitter_chunk_size", "max_embed_chunk_size", ]; const noRecord = [ "max_embed_chunk_size", "agent_sql_connections", "imported_agent_skills", "feature_flags", "meta_page_title", "meta_page_favicon", ];
for (const label of labels) { // Skip any settings that are not explicitly defined as public
if (!SystemSettings.publicFields.includes(label)) continue;
// Only get the embedder if the setting actually needs it
let embedder = needEmbedder.includes(label) ? getEmbeddingEngineSelection() : null; // Only get the record from db if the setting actually needs it
let setting = noRecord.includes(label) ? null : await SystemSettings.get({ label });
switch (label) { case "footer_data": requestedSettings[label] = setting?.value ?? JSON.stringify([]); break; case "support_email": requestedSettings[label] = setting?.value || null; break; case "text_splitter_chunk_size": requestedSettings[label] = setting?.value || embedder?.embeddingMaxChunkLength || null; break; case "text_splitter_chunk_overlap": requestedSettings[label] = setting?.value || null; break; case "max_embed_chunk_size": requestedSettings[label] = embedder?.embeddingMaxChunkLength || 1000; break; case "agent_search_provider": requestedSettings[label] = setting?.value || null; break; case "agent_sql_connections": requestedSettings[label] = await SystemSettings.brief.agent_sql_connections(); break; case "default_agent_skills": requestedSettings[label] = safeJsonParse(setting?.value, []); break; case "disabled_agent_skills": requestedSettings[label] = safeJsonParse(setting?.value, []); break; case "imported_agent_skills": requestedSettings[label] = ImportedPlugin.listImportedPlugins(); break; case "custom_app_name": requestedSettings[label] = setting?.value || null; break; case "feature_flags": requestedSettings[label] = (await SystemSettings.getFeatureFlags()) || {}; break; case "meta_page_title": requestedSettings[label] = await SystemSettings.getValueOrFallback({ label }, null); break; case "meta_page_favicon": requestedSettings[label] = await SystemSettings.getValueOrFallback({ label }, null); break; default: break; } }
response.status(200).json({ settings: requestedSettings }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
// TODO: Delete this endpoint
// DEPRECATED - use /admin/system-preferences-for instead with ?labels=... comma separated string of labels
app.get( "/admin/system-preferences", [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])], async (_, response) => { try { const embedder = getEmbeddingEngineSelection(); const settings = { footer_data: (await SystemSettings.get({ label: "footer_data" }))?.value || JSON.stringify([]), support_email: (await SystemSettings.get({ label: "support_email" }))?.value || null, text_splitter_chunk_size: (await SystemSettings.get({ label: "text_splitter_chunk_size" })) ?.value || embedder?.embeddingMaxChunkLength || null, text_splitter_chunk_overlap: (await SystemSettings.get({ label: "text_splitter_chunk_overlap" })) ?.value || null, max_embed_chunk_size: embedder?.embeddingMaxChunkLength || 1000, agent_search_provider: (await SystemSettings.get({ label: "agent_search_provider" })) ?.value || null, agent_sql_connections: await SystemSettings.brief.agent_sql_connections(), default_agent_skills: safeJsonParse( (await SystemSettings.get({ label: "default_agent_skills" })) ?.value, [] ) || [], disabled_agent_skills: safeJsonParse( (await SystemSettings.get({ label: "disabled_agent_skills" })) ?.value, [] ) || [], imported_agent_skills: ImportedPlugin.listImportedPlugins(), custom_app_name: (await SystemSettings.get({ label: "custom_app_name" }))?.value || null, feature_flags: (await SystemSettings.getFeatureFlags()) || {}, meta_page_title: await SystemSettings.getValueOrFallback( { label: "meta_page_title" }, null ), meta_page_favicon: await SystemSettings.getValueOrFallback( { label: "meta_page_favicon" }, null ), }; response.status(200).json({ settings }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
app.post( "/admin/system-preferences", [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])], async (request, response) => { try { const updates = reqBody(request); await SystemSettings.updateSettings(updates); response.status(200).json({ success: true, error: null }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
app.get( "/admin/api-keys", [validatedRequest, strictMultiUserRoleValid([ROLES.admin])], async (_request, response) => { try { const apiKeys = await ApiKey.whereWithUser({}); return response.status(200).json({ apiKeys, error: null, }); } catch (error) { console.error(error); response.status(500).json({ apiKey: null, error: "Could not find an API Keys.", }); } } );
app.post( "/admin/generate-api-key", [validatedRequest, strictMultiUserRoleValid([ROLES.admin])], async (request, response) => { try { const user = await userFromSession(request, response); const { apiKey, error } = await ApiKey.create(user.id);
await Telemetry.sendTelemetry("api_key_created"); await EventLogs.logEvent( "api_key_created", { createdBy: user?.username }, user?.id ); return response.status(200).json({ apiKey, error, }); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );
app.delete( "/admin/delete-api-key/:id", [validatedRequest, strictMultiUserRoleValid([ROLES.admin])], async (request, response) => { try { const { id } = request.params; await ApiKey.delete({ id: Number(id) });
await EventLogs.logEvent( "api_key_deleted", { deletedBy: response.locals?.user?.username }, response?.locals?.user?.id ); return response.status(200).end(); } catch (e) { console.error(e); response.sendStatus(500).end(); } } );}
module.exports = { adminEndpoints };
|