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

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year 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 };