You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

669 lines
21 KiB

11 months ago
10 months ago
11 months ago
10 months ago
11 months ago
11 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
11 months ago
  1. const { ApiKey } = require("../models/apiKeys");
  2. const { Document } = require("../models/documents");
  3. const { EventLogs } = require("../models/eventLogs");
  4. const { Invite } = require("../models/invite");
  5. const { SystemSettings } = require("../models/systemSettings");
  6. const { Telemetry } = require("../models/telemetry");
  7. const { User } = require("../models/user");
  8. const { DeptUsers } = require("../models/deptUsers");
  9. const { DocumentVectors } = require("../models/vectors");
  10. const { Workspace } = require("../models/workspace");
  11. const { WorkspaceChats } = require("../models/workspaceChats");
  12. const prisma = require("../utils/prisma");
  13. const {
  14. getVectorDbClass,
  15. getEmbeddingEngineSelection,
  16. } = require("../utils/helpers");
  17. const {
  18. validRoleSelection,
  19. canModifyAdmin,
  20. validCanModify,
  21. } = require("../utils/helpers/admin");
  22. const { reqBody, userFromSession, safeJsonParse } = require("../utils/http");
  23. const {
  24. strictMultiUserRoleValid,
  25. flexUserRoleValid,
  26. ROLES,
  27. } = require("../utils/middleware/multiUserProtected");
  28. const { validatedRequest } = require("../utils/middleware/validatedRequest");
  29. const ImportedPlugin = require("../utils/agents/imported");
  30. function adminEndpoints(app) {
  31. if (!app) return;
  32. app.get(
  33. "/admin/users",
  34. [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])],
  35. async (_request, response) => {
  36. try {
  37. console.log("调用了调用了admin/users");
  38. const users = await User.where();
  39. response.status(200).json({ users });
  40. } catch (e) {
  41. console.error(e);
  42. response.sendStatus(500).end();
  43. }
  44. }
  45. );
  46. app.post(
  47. "/admin/users/new",
  48. [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])],
  49. async (request, response) => {
  50. try {
  51. const currUser = await userFromSession(request, response);
  52. const newUserParams = reqBody(request);
  53. const roleValidation = validRoleSelection(currUser, newUserParams);
  54. if (!roleValidation.valid) {
  55. response
  56. .status(200)
  57. .json({ user: null, error: roleValidation.error });
  58. return;
  59. }
  60. const { user: newUser, error } = await User.create(newUserParams);
  61. if (!!newUser) {
  62. await EventLogs.logEvent(
  63. "user_created",
  64. {
  65. userName: newUser.username,
  66. createdBy: currUser.username,
  67. },
  68. currUser.id
  69. );
  70. }
  71. response.status(200).json({ user: newUser, error });
  72. } catch (e) {
  73. console.error(e);
  74. response.sendStatus(500).end();
  75. }
  76. }
  77. );
  78. app.post(
  79. "/admin/users/add/:deptId",
  80. [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])],
  81. async (request, response) => {
  82. try {
  83. const currUser = await userFromSession(request, response);
  84. const { deptId } = request.params;
  85. const newUserParams = reqBody(request);
  86. const roleValidation = validRoleSelection(currUser, newUserParams);
  87. if (!roleValidation.valid) {
  88. return response.status(400).json({ error: roleValidation.error });
  89. }
  90. await prisma.$transaction(async (prisma) => {
  91. try {
  92. // 创建新用户(使用事务中的 prisma 实例)
  93. const { user: newUser, error } = await User.createNew(newUserParams, prisma);
  94. console.log("newUser", newUser);
  95. console.log("error", error);
  96. if (error) {
  97. throw new Error(`用户创建失败: ${error}`);
  98. }
  99. console.log("newUser===================", newUser);
  100. // 创建部门用户关联(使用事务中的 prisma 实例)
  101. const deptUser = await DeptUsers.createNew({
  102. data: { userId: newUser.id, deptId: deptId },
  103. }, prisma);
  104. console.log("deptUser:================", deptUser);
  105. // 记录事件日志(使用事务中的 prisma 实例)
  106. await EventLogs.logEventNew(
  107. "user_created",
  108. { userName: newUser.username, createdBy: currUser.username },
  109. currUser.id,
  110. prisma
  111. );
  112. // 返回成功响应
  113. response.status(200).json({ user: newUser, error: null });
  114. } catch (error) {
  115. console.error("事务内部错误:", error.message);
  116. throw error; // 重新抛出错误,确保事务回滚
  117. }
  118. });
  119. } catch (e) {
  120. console.error("Error creating user and dept user association:", e);
  121. response.status(500).json({ error: "Internal Server Error" });
  122. }
  123. }
  124. );
  125. // app.post(
  126. // "/admin/users/new",
  127. // [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])],
  128. // async (request, response) => {
  129. // try {
  130. // const currUser = await userFromSession(request, response);
  131. // const newUserParams = reqBody(request);
  132. // const roleValidation = validRoleSelection(currUser, newUserParams);
  133. //
  134. // // 验证角色权限
  135. // if (!roleValidation.valid) {
  136. // response
  137. // .status(200)
  138. // .json({ user: null, error: roleValidation.error });
  139. // return;
  140. // }
  141. //
  142. // // 使用事务确保原子性
  143. // const result = await prisma.$transaction(async (prisma) => {
  144. // // 1. 创建用户
  145. // const newUser = await prisma.users.create({
  146. // data: newUserParams,
  147. // });
  148. //
  149. // // 2. 将用户和组织机构关联到 dept_users 表
  150. // if (newUserParams.deptId) {
  151. // await prisma.dept_users.create({
  152. // data: {
  153. // deptId: newUserParams.deptId,
  154. // userId: newUser.id,
  155. // createdAt: new Date(),
  156. // updatedAt: new Date(),
  157. // },
  158. // });
  159. // }
  160. //
  161. // // 3. 记录事件日志
  162. // await EventLogs.logEvent(
  163. // "user_created",
  164. // {
  165. // userName: newUser.username,
  166. // createdBy: currUser.username,
  167. // },
  168. // currUser.id
  169. // );
  170. //
  171. // return { user: newUser, error: null };
  172. // });
  173. //
  174. // // 返回成功响应
  175. // response.status(200).json(result);
  176. // } catch (e) {
  177. // console.error(e);
  178. // response.status(500).json({ user: null, error: e.message });
  179. // }
  180. // }
  181. // );
  182. app.post(
  183. "/admin/user/:id",
  184. [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])],
  185. async (request, response) => {
  186. try {
  187. const currUser = await userFromSession(request, response);
  188. const { id } = request.params;
  189. const updates = reqBody(request);
  190. const user = await User.get({ id: Number(id) });
  191. const canModify = validCanModify(currUser, user);
  192. if (!canModify.valid) {
  193. response.status(200).json({ success: false, error: canModify.error });
  194. return;
  195. }
  196. const roleValidation = validRoleSelection(currUser, updates);
  197. if (!roleValidation.valid) {
  198. response
  199. .status(200)
  200. .json({ success: false, error: roleValidation.error });
  201. return;
  202. }
  203. const validAdminRoleModification = await canModifyAdmin(user, updates);
  204. if (!validAdminRoleModification.valid) {
  205. response
  206. .status(200)
  207. .json({ success: false, error: validAdminRoleModification.error });
  208. return;
  209. }
  210. const { success, error } = await User.update(id, updates);
  211. response.status(200).json({ success, error });
  212. } catch (e) {
  213. console.error(e);
  214. response.sendStatus(500).end();
  215. }
  216. }
  217. );
  218. app.delete(
  219. "/admin/user/:id",
  220. [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])],
  221. async (request, response) => {
  222. try {
  223. const currUser = await userFromSession(request, response);
  224. const { id } = request.params;
  225. const user = await User.get({ id: Number(id) });
  226. const canModify = validCanModify(currUser, user);
  227. if (!canModify.valid) {
  228. response.status(200).json({ success: false, error: canModify.error });
  229. return;
  230. }
  231. await User.delete({ id: Number(id) });
  232. await EventLogs.logEvent(
  233. "user_deleted",
  234. {
  235. userName: user.username,
  236. deletedBy: currUser.username,
  237. },
  238. currUser.id
  239. );
  240. response.status(200).json({ success: true, error: null });
  241. } catch (e) {
  242. console.error(e);
  243. response.sendStatus(500).end();
  244. }
  245. }
  246. );
  247. app.get(
  248. "/admin/invites",
  249. [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])],
  250. async (_request, response) => {
  251. try {
  252. const invites = await Invite.whereWithUsers();
  253. response.status(200).json({ invites });
  254. } catch (e) {
  255. console.error(e);
  256. response.sendStatus(500).end();
  257. }
  258. }
  259. );
  260. app.post(
  261. "/admin/invite/new",
  262. [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])],
  263. async (request, response) => {
  264. try {
  265. const user = await userFromSession(request, response);
  266. const body = reqBody(request);
  267. const { invite, error } = await Invite.create({
  268. createdByUserId: user.id,
  269. workspaceIds: body?.workspaceIds || [],
  270. });
  271. await EventLogs.logEvent(
  272. "invite_created",
  273. {
  274. inviteCode: invite.code,
  275. createdBy: response.locals?.user?.username,
  276. },
  277. response.locals?.user?.id
  278. );
  279. response.status(200).json({ invite, error });
  280. } catch (e) {
  281. console.error(e);
  282. response.sendStatus(500).end();
  283. }
  284. }
  285. );
  286. app.delete(
  287. "/admin/invite/:id",
  288. [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])],
  289. async (request, response) => {
  290. try {
  291. const { id } = request.params;
  292. const { success, error } = await Invite.deactivate(id);
  293. await EventLogs.logEvent(
  294. "invite_deleted",
  295. { deletedBy: response.locals?.user?.username },
  296. response.locals?.user?.id
  297. );
  298. response.status(200).json({ success, error });
  299. } catch (e) {
  300. console.error(e);
  301. response.sendStatus(500).end();
  302. }
  303. }
  304. );
  305. app.get(
  306. "/admin/workspaces",
  307. [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])],
  308. async (_request, response) => {
  309. try {
  310. const workspaces = await Workspace.whereWithUsers();
  311. response.status(200).json({ workspaces });
  312. } catch (e) {
  313. console.error(e);
  314. response.sendStatus(500).end();
  315. }
  316. }
  317. );
  318. app.get(
  319. "/admin/workspaces/:workspaceId/users",
  320. [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])],
  321. async (request, response) => {
  322. try {
  323. const { workspaceId } = request.params;
  324. const users = await Workspace.workspaceUsers(workspaceId);
  325. response.status(200).json({ users });
  326. } catch (e) {
  327. console.error(e);
  328. response.sendStatus(500).end();
  329. }
  330. }
  331. );
  332. app.post(
  333. "/admin/workspaces/new",
  334. [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])],
  335. async (request, response) => {
  336. try {
  337. const user = await userFromSession(request, response);
  338. const { name } = reqBody(request);
  339. const { workspace, message: error } = await Workspace.new(
  340. name,
  341. user.id
  342. );
  343. response.status(200).json({ workspace, error });
  344. } catch (e) {
  345. console.error(e);
  346. response.sendStatus(500).end();
  347. }
  348. }
  349. );
  350. app.post(
  351. "/admin/workspaces/:workspaceId/update-users",
  352. [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])],
  353. async (request, response) => {
  354. try {
  355. const { workspaceId } = request.params;
  356. const { userIds } = reqBody(request);
  357. const { success, error } = await Workspace.updateUsers(
  358. workspaceId,
  359. userIds
  360. );
  361. response.status(200).json({ success, error });
  362. } catch (e) {
  363. console.error(e);
  364. response.sendStatus(500).end();
  365. }
  366. }
  367. );
  368. app.delete(
  369. "/admin/workspaces/:id",
  370. [validatedRequest, strictMultiUserRoleValid([ROLES.admin, ROLES.manager])],
  371. async (request, response) => {
  372. try {
  373. const { id } = request.params;
  374. const VectorDb = getVectorDbClass();
  375. const workspace = await Workspace.get({ id: Number(id) });
  376. if (!workspace) {
  377. response.sendStatus(404).end();
  378. return;
  379. }
  380. await WorkspaceChats.delete({ workspaceId: Number(workspace.id) });
  381. await DocumentVectors.deleteForWorkspace(Number(workspace.id));
  382. await Document.delete({ workspaceId: Number(workspace.id) });
  383. await Workspace.delete({ id: Number(workspace.id) });
  384. try {
  385. await VectorDb["delete-namespace"]({ namespace: workspace.slug });
  386. } catch (e) {
  387. console.error(e.message);
  388. }
  389. response.status(200).json({ success: true, error: null });
  390. } catch (e) {
  391. console.error(e);
  392. response.sendStatus(500).end();
  393. }
  394. }
  395. );
  396. // System preferences but only by array of labels
  397. app.get(
  398. "/admin/system-preferences-for",
  399. [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
  400. async (request, response) => {
  401. try {
  402. const requestedSettings = {};
  403. const labels = request.query.labels?.split(",") || [];
  404. const needEmbedder = [
  405. "text_splitter_chunk_size",
  406. "max_embed_chunk_size",
  407. ];
  408. const noRecord = [
  409. "max_embed_chunk_size",
  410. "agent_sql_connections",
  411. "imported_agent_skills",
  412. "feature_flags",
  413. "meta_page_title",
  414. "meta_page_favicon",
  415. ];
  416. for (const label of labels) {
  417. // Skip any settings that are not explicitly defined as public
  418. if (!SystemSettings.publicFields.includes(label)) continue;
  419. // Only get the embedder if the setting actually needs it
  420. let embedder = needEmbedder.includes(label)
  421. ? getEmbeddingEngineSelection()
  422. : null;
  423. // Only get the record from db if the setting actually needs it
  424. let setting = noRecord.includes(label)
  425. ? null
  426. : await SystemSettings.get({ label });
  427. switch (label) {
  428. case "footer_data":
  429. requestedSettings[label] = setting?.value ?? JSON.stringify([]);
  430. break;
  431. case "support_email":
  432. requestedSettings[label] = setting?.value || null;
  433. break;
  434. case "text_splitter_chunk_size":
  435. requestedSettings[label] =
  436. setting?.value || embedder?.embeddingMaxChunkLength || null;
  437. break;
  438. case "text_splitter_chunk_overlap":
  439. requestedSettings[label] = setting?.value || null;
  440. break;
  441. case "max_embed_chunk_size":
  442. requestedSettings[label] =
  443. embedder?.embeddingMaxChunkLength || 1000;
  444. break;
  445. case "agent_search_provider":
  446. requestedSettings[label] = setting?.value || null;
  447. break;
  448. case "agent_sql_connections":
  449. requestedSettings[label] =
  450. await SystemSettings.brief.agent_sql_connections();
  451. break;
  452. case "default_agent_skills":
  453. requestedSettings[label] = safeJsonParse(setting?.value, []);
  454. break;
  455. case "disabled_agent_skills":
  456. requestedSettings[label] = safeJsonParse(setting?.value, []);
  457. break;
  458. case "imported_agent_skills":
  459. requestedSettings[label] = ImportedPlugin.listImportedPlugins();
  460. break;
  461. case "custom_app_name":
  462. requestedSettings[label] = setting?.value || null;
  463. break;
  464. case "feature_flags":
  465. requestedSettings[label] =
  466. (await SystemSettings.getFeatureFlags()) || {};
  467. break;
  468. case "meta_page_title":
  469. requestedSettings[label] =
  470. await SystemSettings.getValueOrFallback({ label }, null);
  471. break;
  472. case "meta_page_favicon":
  473. requestedSettings[label] =
  474. await SystemSettings.getValueOrFallback({ label }, null);
  475. break;
  476. default:
  477. break;
  478. }
  479. }
  480. response.status(200).json({ settings: requestedSettings });
  481. } catch (e) {
  482. console.error(e);
  483. response.sendStatus(500).end();
  484. }
  485. }
  486. );
  487. // TODO: Delete this endpoint
  488. // DEPRECATED - use /admin/system-preferences-for instead with ?labels=... comma separated string of labels
  489. app.get(
  490. "/admin/system-preferences",
  491. [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
  492. async (_, response) => {
  493. try {
  494. const embedder = getEmbeddingEngineSelection();
  495. const settings = {
  496. footer_data:
  497. (await SystemSettings.get({ label: "footer_data" }))?.value ||
  498. JSON.stringify([]),
  499. support_email:
  500. (await SystemSettings.get({ label: "support_email" }))?.value ||
  501. null,
  502. text_splitter_chunk_size:
  503. (await SystemSettings.get({ label: "text_splitter_chunk_size" }))
  504. ?.value ||
  505. embedder?.embeddingMaxChunkLength ||
  506. null,
  507. text_splitter_chunk_overlap:
  508. (await SystemSettings.get({ label: "text_splitter_chunk_overlap" }))
  509. ?.value || null,
  510. max_embed_chunk_size: embedder?.embeddingMaxChunkLength || 1000,
  511. agent_search_provider:
  512. (await SystemSettings.get({ label: "agent_search_provider" }))
  513. ?.value || null,
  514. agent_sql_connections:
  515. await SystemSettings.brief.agent_sql_connections(),
  516. default_agent_skills:
  517. safeJsonParse(
  518. (await SystemSettings.get({ label: "default_agent_skills" }))
  519. ?.value,
  520. []
  521. ) || [],
  522. disabled_agent_skills:
  523. safeJsonParse(
  524. (await SystemSettings.get({ label: "disabled_agent_skills" }))
  525. ?.value,
  526. []
  527. ) || [],
  528. imported_agent_skills: ImportedPlugin.listImportedPlugins(),
  529. custom_app_name:
  530. (await SystemSettings.get({ label: "custom_app_name" }))?.value ||
  531. null,
  532. feature_flags: (await SystemSettings.getFeatureFlags()) || {},
  533. meta_page_title: await SystemSettings.getValueOrFallback(
  534. { label: "meta_page_title" },
  535. null
  536. ),
  537. meta_page_favicon: await SystemSettings.getValueOrFallback(
  538. { label: "meta_page_favicon" },
  539. null
  540. ),
  541. };
  542. response.status(200).json({ settings });
  543. } catch (e) {
  544. console.error(e);
  545. response.sendStatus(500).end();
  546. }
  547. }
  548. );
  549. app.post(
  550. "/admin/system-preferences",
  551. [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
  552. async (request, response) => {
  553. try {
  554. const updates = reqBody(request);
  555. await SystemSettings.updateSettings(updates);
  556. response.status(200).json({ success: true, error: null });
  557. } catch (e) {
  558. console.error(e);
  559. response.sendStatus(500).end();
  560. }
  561. }
  562. );
  563. app.get(
  564. "/admin/api-keys",
  565. [validatedRequest, strictMultiUserRoleValid([ROLES.admin])],
  566. async (_request, response) => {
  567. try {
  568. const apiKeys = await ApiKey.whereWithUser({});
  569. return response.status(200).json({
  570. apiKeys,
  571. error: null,
  572. });
  573. } catch (error) {
  574. console.error(error);
  575. response.status(500).json({
  576. apiKey: null,
  577. error: "Could not find an API Keys.",
  578. });
  579. }
  580. }
  581. );
  582. app.post(
  583. "/admin/generate-api-key",
  584. [validatedRequest, strictMultiUserRoleValid([ROLES.admin])],
  585. async (request, response) => {
  586. try {
  587. const user = await userFromSession(request, response);
  588. const { apiKey, error } = await ApiKey.create(user.id);
  589. await Telemetry.sendTelemetry("api_key_created");
  590. await EventLogs.logEvent(
  591. "api_key_created",
  592. { createdBy: user?.username },
  593. user?.id
  594. );
  595. return response.status(200).json({
  596. apiKey,
  597. error,
  598. });
  599. } catch (e) {
  600. console.error(e);
  601. response.sendStatus(500).end();
  602. }
  603. }
  604. );
  605. app.delete(
  606. "/admin/delete-api-key/:id",
  607. [validatedRequest, strictMultiUserRoleValid([ROLES.admin])],
  608. async (request, response) => {
  609. try {
  610. const { id } = request.params;
  611. await ApiKey.delete({ id: Number(id) });
  612. await EventLogs.logEvent(
  613. "api_key_deleted",
  614. { deletedBy: response.locals?.user?.username },
  615. response?.locals?.user?.id
  616. );
  617. return response.status(200).end();
  618. } catch (e) {
  619. console.error(e);
  620. response.sendStatus(500).end();
  621. }
  622. }
  623. );
  624. }
  625. module.exports = { adminEndpoints };