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.

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