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.

144 lines
3.9 KiB

11 months ago
  1. const prisma = require("../utils/prisma");
  2. const slugifyModule = require("slugify");
  3. const { v4: uuidv4 } = require("uuid");
  4. const WorkspaceThread = {
  5. defaultName: "Thread",
  6. writable: ["name"],
  7. /**
  8. * The default Slugify module requires some additional mapping to prevent downstream issues
  9. * if the user is able to define a slug externally. We have to block non-escapable URL chars
  10. * so that is the slug is rendered it doesn't break the URL or UI when visited.
  11. * @param {...any} args - slugify args for npm package.
  12. * @returns {string}
  13. */
  14. slugify: function (...args) {
  15. slugifyModule.extend({
  16. "+": " plus ",
  17. "!": " bang ",
  18. "@": " at ",
  19. "*": " splat ",
  20. ".": " dot ",
  21. ":": "",
  22. "~": "",
  23. "(": "",
  24. ")": "",
  25. "'": "",
  26. '"': "",
  27. "|": "",
  28. });
  29. return slugifyModule(...args);
  30. },
  31. new: async function (workspace, userId = null, data = {}) {
  32. try {
  33. const thread = await prisma.workspace_threads.create({
  34. data: {
  35. name: data.name ? String(data.name) : this.defaultName,
  36. slug: data.slug
  37. ? this.slugify(data.slug, { lowercase: true })
  38. : uuidv4(),
  39. user_id: userId ? Number(userId) : null,
  40. workspace_id: workspace.id,
  41. },
  42. });
  43. return { thread, message: null };
  44. } catch (error) {
  45. console.error(error.message);
  46. return { thread: null, message: error.message };
  47. }
  48. },
  49. update: async function (prevThread = null, data = {}) {
  50. if (!prevThread) throw new Error("No thread id provided for update");
  51. const validData = {};
  52. Object.entries(data).forEach(([key, value]) => {
  53. if (!this.writable.includes(key)) return;
  54. validData[key] = value;
  55. });
  56. if (Object.keys(validData).length === 0)
  57. return { thread: prevThread, message: "No valid fields to update!" };
  58. try {
  59. const thread = await prisma.workspace_threads.update({
  60. where: { id: prevThread.id },
  61. data: validData,
  62. });
  63. return { thread, message: null };
  64. } catch (error) {
  65. console.error(error.message);
  66. return { thread: null, message: error.message };
  67. }
  68. },
  69. get: async function (clause = {}) {
  70. try {
  71. const thread = await prisma.workspace_threads.findFirst({
  72. where: clause,
  73. });
  74. return thread || null;
  75. } catch (error) {
  76. console.error(error.message);
  77. return null;
  78. }
  79. },
  80. delete: async function (clause = {}) {
  81. try {
  82. await prisma.workspace_threads.deleteMany({
  83. where: clause,
  84. });
  85. return true;
  86. } catch (error) {
  87. console.error(error.message);
  88. return false;
  89. }
  90. },
  91. where: async function (clause = {}, limit = null, orderBy = null) {
  92. try {
  93. const results = await prisma.workspace_threads.findMany({
  94. where: clause,
  95. ...(limit !== null ? { take: limit } : {}),
  96. ...(orderBy !== null ? { orderBy } : {}),
  97. });
  98. return results;
  99. } catch (error) {
  100. console.error(error.message);
  101. return [];
  102. }
  103. },
  104. // Will fire on first message (included or not) for a thread and rename the thread with the newName prop.
  105. autoRenameThread: async function ({
  106. workspace = null,
  107. thread = null,
  108. user = null,
  109. newName = null,
  110. onRename = null,
  111. }) {
  112. if (!workspace || !thread || !newName) return false;
  113. if (thread.name !== this.defaultName) return false; // don't rename if already named.
  114. const { WorkspaceChats } = require("./workspaceChats");
  115. const chatCount = await WorkspaceChats.count({
  116. workspaceId: workspace.id,
  117. user_id: user?.id || null,
  118. thread_id: thread.id,
  119. });
  120. if (chatCount !== 1) return { renamed: false, thread };
  121. const { thread: updatedThread } = await this.update(thread, {
  122. name: newName,
  123. });
  124. onRename?.(updatedThread);
  125. return true;
  126. },
  127. };
  128. module.exports = { WorkspaceThread };