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.

614 lines
19 KiB

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