@studious-lms/server 1.7.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/middleware/security.d.ts.map +1 -1
- package/dist/middleware/security.js +3 -3
- package/dist/middleware/security.js.map +1 -1
- package/dist/models/access.d.ts +21 -66
- package/dist/models/access.d.ts.map +1 -1
- package/dist/models/access.js +10 -26
- package/dist/models/access.js.map +1 -1
- package/dist/models/agenda.d.ts +4 -2
- package/dist/models/agenda.d.ts.map +1 -1
- package/dist/models/announcement.d.ts +4 -3
- package/dist/models/announcement.d.ts.map +1 -1
- package/dist/models/announcement.js +2 -3
- package/dist/models/announcement.js.map +1 -1
- package/dist/models/assignment.d.ts +40 -33
- package/dist/models/assignment.d.ts.map +1 -1
- package/dist/models/auth.d.ts +2 -4
- package/dist/models/auth.d.ts.map +1 -1
- package/dist/models/auth.js +2 -3
- package/dist/models/auth.js.map +1 -1
- package/dist/models/class.d.ts +34 -6
- package/dist/models/class.d.ts.map +1 -1
- package/dist/models/class.js +15 -2
- package/dist/models/class.js.map +1 -1
- package/dist/models/cloudStorage.d.ts +153 -0
- package/dist/models/cloudStorage.d.ts.map +1 -0
- package/dist/models/cloudStorage.js +295 -0
- package/dist/models/cloudStorage.js.map +1 -0
- package/dist/models/comment.d.ts +0 -24
- package/dist/models/comment.d.ts.map +1 -1
- package/dist/models/comment.js +2 -6
- package/dist/models/comment.js.map +1 -1
- package/dist/models/conversation.d.ts +22 -22
- package/dist/models/department.d.ts +154 -0
- package/dist/models/department.d.ts.map +1 -0
- package/dist/models/department.js +135 -0
- package/dist/models/department.js.map +1 -0
- package/dist/models/event.d.ts +10 -4
- package/dist/models/event.d.ts.map +1 -1
- package/dist/models/event.js +2 -5
- package/dist/models/event.js.map +1 -1
- package/dist/models/file.d.ts +52 -36
- package/dist/models/file.d.ts.map +1 -1
- package/dist/models/file.js +4 -42
- package/dist/models/file.js.map +1 -1
- package/dist/models/folder.d.ts +47 -0
- package/dist/models/folder.d.ts.map +1 -1
- package/dist/models/labChat.d.ts +11 -9
- package/dist/models/labChat.d.ts.map +1 -1
- package/dist/models/message.d.ts +46 -12
- package/dist/models/message.d.ts.map +1 -1
- package/dist/models/message.js +19 -10
- package/dist/models/message.js.map +1 -1
- package/dist/models/newtonChat.d.ts +2 -1
- package/dist/models/newtonChat.d.ts.map +1 -1
- package/dist/models/school.d.ts +45 -12
- package/dist/models/school.d.ts.map +1 -1
- package/dist/models/school.js +19 -2
- package/dist/models/school.js.map +1 -1
- package/dist/models/section.d.ts +2 -1
- package/dist/models/section.d.ts.map +1 -1
- package/dist/models/tag.d.ts +117 -0
- package/dist/models/tag.d.ts.map +1 -0
- package/dist/models/tag.js +113 -0
- package/dist/models/tag.js.map +1 -0
- package/dist/models/worksheet.d.ts +3 -0
- package/dist/models/worksheet.d.ts.map +1 -1
- package/dist/pipelines/aiLabChatContract.d.ts +8 -8
- package/dist/routers/_app.d.ts +6704 -5222
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +8 -2
- package/dist/routers/_app.js.map +1 -1
- package/dist/routers/agenda.d.ts +4 -2
- package/dist/routers/agenda.d.ts.map +1 -1
- package/dist/routers/announcement.d.ts.map +1 -1
- package/dist/routers/announcement.js +3 -5
- package/dist/routers/announcement.js.map +1 -1
- package/dist/routers/assignment.d.ts +49 -40
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/assignment.js +2 -3
- package/dist/routers/assignment.js.map +1 -1
- package/dist/routers/class.d.ts +92 -19
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/class.js +5 -2
- package/dist/routers/class.js.map +1 -1
- package/dist/routers/conversation.d.ts +5 -5
- package/dist/routers/department.d.ts +293 -0
- package/dist/routers/department.d.ts.map +1 -0
- package/dist/routers/department.js +93 -0
- package/dist/routers/department.js.map +1 -0
- package/dist/routers/event.d.ts +4 -3
- package/dist/routers/event.d.ts.map +1 -1
- package/dist/routers/file.d.ts +10 -8
- package/dist/routers/file.d.ts.map +1 -1
- package/dist/routers/file.js +26 -17
- package/dist/routers/file.js.map +1 -1
- package/dist/routers/folder.d.ts +163 -186
- package/dist/routers/folder.d.ts.map +1 -1
- package/dist/routers/folder.js +102 -88
- package/dist/routers/folder.js.map +1 -1
- package/dist/routers/labChat.d.ts +13 -4
- package/dist/routers/labChat.d.ts.map +1 -1
- package/dist/routers/message.d.ts +20 -2
- package/dist/routers/message.d.ts.map +1 -1
- package/dist/routers/newtonChat.d.ts +10 -1
- package/dist/routers/newtonChat.d.ts.map +1 -1
- package/dist/routers/permissions.d.ts +120 -0
- package/dist/routers/permissions.d.ts.map +1 -0
- package/dist/routers/permissions.js +50 -0
- package/dist/routers/permissions.js.map +1 -0
- package/dist/routers/school.d.ts +160 -17
- package/dist/routers/school.d.ts.map +1 -1
- package/dist/routers/school.js +46 -3
- package/dist/routers/school.js.map +1 -1
- package/dist/routers/tag.d.ts +119 -0
- package/dist/routers/tag.d.ts.map +1 -0
- package/dist/routers/tag.js +52 -0
- package/dist/routers/tag.js.map +1 -0
- package/dist/routers/worksheet.d.ts +1 -0
- package/dist/routers/worksheet.d.ts.map +1 -1
- package/dist/seedDatabase.d.ts +0 -1
- package/dist/seedDatabase.d.ts.map +1 -1
- package/dist/services/agenda.d.ts +4 -2
- package/dist/services/agenda.d.ts.map +1 -1
- package/dist/services/assignment.d.ts +49 -40
- package/dist/services/assignment.d.ts.map +1 -1
- package/dist/services/class.d.ts +92 -19
- package/dist/services/class.d.ts.map +1 -1
- package/dist/services/class.js +92 -5
- package/dist/services/class.js.map +1 -1
- package/dist/services/conversation.d.ts +5 -5
- package/dist/services/department.d.ts +200 -0
- package/dist/services/department.d.ts.map +1 -0
- package/dist/services/department.js +368 -0
- package/dist/services/department.js.map +1 -0
- package/dist/services/event.d.ts +4 -3
- package/dist/services/event.d.ts.map +1 -1
- package/dist/services/file.d.ts +105 -3
- package/dist/services/file.d.ts.map +1 -1
- package/dist/services/file.js +167 -41
- package/dist/services/file.js.map +1 -1
- package/dist/services/folder.d.ts +220 -149
- package/dist/services/folder.d.ts.map +1 -1
- package/dist/services/folder.js +326 -196
- package/dist/services/folder.js.map +1 -1
- package/dist/services/labChat.d.ts +13 -4
- package/dist/services/labChat.d.ts.map +1 -1
- package/dist/services/labChat.js +4 -3
- package/dist/services/labChat.js.map +1 -1
- package/dist/services/message.d.ts +20 -2
- package/dist/services/message.d.ts.map +1 -1
- package/dist/services/message.js +7 -23
- package/dist/services/message.js.map +1 -1
- package/dist/services/newtonChat.d.ts +9 -0
- package/dist/services/newtonChat.d.ts.map +1 -1
- package/dist/services/newtonChat.js +4 -3
- package/dist/services/newtonChat.js.map +1 -1
- package/dist/services/permissions.d.ts +188 -0
- package/dist/services/permissions.d.ts.map +1 -0
- package/dist/services/permissions.js +661 -0
- package/dist/services/permissions.js.map +1 -0
- package/dist/services/school.d.ts +142 -15
- package/dist/services/school.d.ts.map +1 -1
- package/dist/services/school.js +308 -54
- package/dist/services/school.js.map +1 -1
- package/dist/services/tag.d.ts +71 -0
- package/dist/services/tag.d.ts.map +1 -0
- package/dist/services/tag.js +178 -0
- package/dist/services/tag.js.map +1 -0
- package/dist/services/worksheet.d.ts +1 -0
- package/dist/services/worksheet.d.ts.map +1 -1
- package/dist/utils/aiUser.d.ts.map +1 -1
- package/dist/utils/aiUser.js +2 -3
- package/dist/utils/aiUser.js.map +1 -1
- package/package.json +1 -1
- package/prisma/migrations/20260509220000_institution_overhaul/migration.sql +184 -0
- package/prisma/migrations/20260510170000_add_folder_permissions/migration.sql +93 -0
- package/prisma/schema.prisma +193 -35
- package/src/middleware/security.ts +1 -1
- package/src/models/access.ts +8 -24
- package/src/models/announcement.ts +0 -1
- package/src/models/auth.ts +0 -1
- package/src/models/class.ts +13 -0
- package/src/models/cloudStorage.ts +327 -0
- package/src/models/comment.ts +0 -4
- package/src/models/department.ts +159 -0
- package/src/models/event.ts +0 -3
- package/src/models/file.ts +2 -40
- package/src/models/message.ts +19 -5
- package/src/models/school.ts +26 -0
- package/src/models/tag.ts +140 -0
- package/src/routers/_app.ts +6 -0
- package/src/routers/announcement.ts +1 -3
- package/src/routers/assignment.ts +0 -1
- package/src/routers/class.ts +3 -0
- package/src/routers/department.ts +174 -0
- package/src/routers/file.ts +29 -26
- package/src/routers/folder.ts +127 -118
- package/src/routers/permissions.ts +71 -0
- package/src/routers/school.ts +83 -0
- package/src/routers/tag.ts +78 -0
- package/src/services/class.ts +109 -4
- package/src/services/department.ts +478 -0
- package/src/services/file.ts +172 -43
- package/src/services/folder.ts +399 -237
- package/src/services/labChat.ts +2 -1
- package/src/services/message.ts +5 -21
- package/src/services/newtonChat.ts +2 -1
- package/src/services/permissions.ts +778 -0
- package/src/services/school.ts +369 -57
- package/src/services/tag.ts +229 -0
- package/src/utils/aiUser.ts +0 -1
- package/tests/unit/services/permissions.test.ts +463 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"folder.js","sources":["services/folder.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Folder service – CRUD for class folders, file uploads, and folder hierarchy.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport {\n findClassWithTeacher,\n findFolderById,\n findOrCreateRootFolder,\n createFolder,\n findFolderWithContents,\n findChildFolders,\n findRootFolderWithContents,\n findFolderByIdWithCount,\n deleteFolderById,\n updateFolderParent,\n updateFolder,\n findFolderByIdForTraversal,\n} from \"../models/folder.js\";\nimport { createDirectUploadFiles } from \"../lib/fileUpload.js\";\n\n/** Create a folder in a class. Teacher-only. */\nexport async function createFolderRecord(\n userId: string,\n input: {\n classId: string;\n name: string;\n parentFolderId?: string | null;\n color?: string;\n }\n) {\n const classData = await findClassWithTeacher(input.classId, userId);\n if (!classData) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Class not found or you are not a teacher\",\n });\n }\n\n let parentFolderId = input.parentFolderId;\n if (!parentFolderId) {\n const root = await findOrCreateRootFolder(input.classId);\n parentFolderId = root.id;\n } else {\n const parentFolder = await findFolderById(parentFolderId);\n if (!parentFolder) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Parent folder not found\",\n });\n }\n }\n\n return createFolder({\n name: input.name,\n parentFolderId,\n color: input.color,\n });\n}\n\n/** Get folder with its contents (subfolders and files). */\nexport async function getFolder(folderId: string) {\n const folder = await findFolderWithContents(folderId);\n if (!folder) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Folder not found\",\n });\n }\n return folder;\n}\n\nexport async function getChildFolders(classId: string) {\n const root = await findOrCreateRootFolder(classId);\n return findChildFolders(root.id);\n}\n\nexport async function getFolderChildren(folderId: string, classId: string) {\n return findChildFolders(folderId);\n}\n\nexport async function getRootFolder(classId: string) {\n const root = await findOrCreateRootFolder(classId);\n const rootWithContents = await findRootFolderWithContents(classId);\n if (!rootWithContents) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Root folder not found\",\n });\n }\n return rootWithContents;\n}\n\nexport async function uploadFilesToFolder(\n userId: string,\n classId: string,\n folderId: string,\n files: { name: string; type: string; size: number }[]\n) {\n const classData = await findClassWithTeacher(classId, userId);\n if (!classData) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Class not found or you are not a teacher\",\n });\n }\n\n const folder = await findFolderById(folderId);\n if (!folder) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Folder not found\",\n });\n }\n\n const uploadedFiles = await createDirectUploadFiles(files, userId, folderId);\n return {\n success: true,\n uploadedCount: uploadedFiles.length,\n };\n}\n\nexport async function deleteFolderRecord(\n userId: string,\n classId: string,\n folderId: string\n) {\n const classData = await findClassWithTeacher(classId, userId);\n if (!classData) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Class not found or you are not a teacher\",\n });\n }\n\n const folder = await findFolderByIdWithCount(folderId);\n if (!folder) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Folder not found\",\n });\n }\n\n // Verify folder belongs to class (traverse to root)\n let currentId: string | null = folderId;\n let belongsToClass = false;\n while (currentId) {\n const current = await findFolderByIdForTraversal(currentId);\n if (!current) break;\n if (current.classId === classId) {\n belongsToClass = true;\n break;\n }\n currentId = current.parentFolderId;\n }\n if (!belongsToClass) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Folder does not belong to this class\",\n });\n }\n\n await deleteFolderById(folderId);\n return {\n success: true,\n deletedFiles: folder._count.files,\n deletedFolders: folder._count.childFolders + 1,\n };\n}\n\nexport async function moveFolder(\n userId: string,\n folderId: string,\n targetParentFolderId: string,\n classId: string\n) {\n const classData = await findClassWithTeacher(classId, userId);\n if (!classData) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You must be a teacher of this class to move folders\",\n });\n }\n\n const folder = await findFolderById(folderId);\n if (!folder) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Folder not found\",\n });\n }\n\n if (!folder.parentFolderId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Cannot move the root folder\",\n });\n }\n\n if (targetParentFolderId) {\n const targetParent = await findFolderByIdForTraversal(targetParentFolderId);\n if (!targetParent) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Target parent folder not found\",\n });\n }\n\n if (targetParentFolderId === folderId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Cannot move a folder into itself\",\n });\n }\n\n let currentParent: typeof targetParent | null = targetParent;\n while (currentParent?.parentFolderId) {\n if (currentParent.parentFolderId === folderId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Cannot move a folder into its descendant\",\n });\n }\n currentParent = await findFolderByIdForTraversal(currentParent.parentFolderId);\n if (!currentParent) break;\n }\n }\n\n return updateFolderParent(folderId, targetParentFolderId);\n}\n\nexport async function updateFolderRecord(\n folderId: string,\n name: string,\n color: string | undefined,\n classId: string\n) {\n const folder = await findFolderById(folderId);\n if (!folder) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Folder not found\",\n });\n }\n\n if (!name.trim()) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Folder name cannot be empty\",\n });\n }\n\n return updateFolder(folderId, {\n name: name.trim(),\n ...(color && { color }),\n });\n}\n\nexport async function getFolderParents(folderId: string) {\n const parents: Awaited<ReturnType<typeof findFolderByIdForTraversal>>[] = [];\n let currentId: string | null = folderId;\n\n while (currentId) {\n const folder = await findFolderByIdForTraversal(currentId);\n if (!folder) break;\n parents.push(folder);\n currentId = folder.parentFolderId;\n }\n\n return parents;\n}\n\nexport async function getFolderUploadUrls(\n userId: string,\n classId: string,\n folderId: string,\n files: { name: string; type: string; size: number }[]\n) {\n const classData = await findClassWithTeacher(classId, userId);\n if (!classData) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Class not found or you are not a teacher\",\n });\n }\n\n const folder = await findFolderById(folderId);\n if (!folder) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Folder not found\",\n });\n }\n\n let currentFolder: typeof folder | null = folder;\n let belongsToClass = false;\n while (currentFolder) {\n if (currentFolder.classId === classId) {\n belongsToClass = true;\n break;\n }\n if (currentFolder.parentFolderId) {\n currentFolder = await findFolderByIdForTraversal(currentFolder.parentFolderId);\n } else {\n break;\n }\n }\n\n if (!belongsToClass) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Folder does not belong to this class\",\n });\n }\n\n return createDirectUploadFiles(files, userId, folderId);\n}\n"],"names":[],"mappings":"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","debug_id":"4875a835-3cd4-5fcf-8e19-868d405dfe96"}
|
|
1
|
+
{"version":3,"file":"folder.js","sources":["services/folder.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Folder service — single source of truth for folders across every scope.\n *\n * A `Folder` can live inside one of four scopes (see `models/cloudStorage.ts`):\n * class files, school storage, school documents, or a user's personal storage.\n * Permissions and ownership are derived from the scope by walking up the tree\n * to the root, so callers can either pass a `scope` (when there is no folder\n * id yet, e.g. browsing the root) or just a `folderId` (everything else).\n *\n * The class files page and the global cloud-storage view both consume these\n * endpoints — no duplicate routers.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { prisma } from \"../lib/prisma.js\";\nimport {\n CloudScope,\n createSubFolder,\n deleteFolderById,\n findFolderById,\n findFolderWithContents,\n findOrCreateScopeRoot,\n listFolderBreadcrumbs,\n renameFolder,\n resolveFolderScope,\n} from \"../models/cloudStorage.js\";\nimport {\n createDirectUploadFiles,\n type DirectFileData,\n confirmDirectUpload,\n} from \"../lib/fileUpload.js\";\nimport {\n type AccessLevel,\n getScopeDefault,\n listSharedWithMe,\n requireFolderAccess as requireFolderAccessResolved,\n} from \"./permissions.js\";\n\ninterface AccessResult {\n scope: CloudScope;\n canWrite: boolean;\n /**\n * True when the viewer's access comes through an explicit grant rather than\n * scope membership. Used by `browseFolder` to surface a \"Shared with me\"\n * heading instead of the underlying scope's title — the grantee shouldn't\n * see the folder labelled with the owner's scope.\n */\n viaGrant: boolean;\n}\n\n/**\n * Scope-default-only check: used when there is no folder id yet (browsing or\n * creating at the scope root). Does *not* consult explicit grants — those only\n * apply to specific folders. Explicit-grant access to sub-folders surfaces via\n * the \"Shared with me\" virtual scope, not by being a scope member.\n */\nasync function requireScopeAccess(\n userId: string,\n scope: CloudScope,\n level: AccessLevel\n): Promise<AccessResult> {\n if (scope.kind === \"CLASS\") {\n const classExists = await prisma.class.findFirst({\n where: { id: scope.classId },\n select: { id: true },\n });\n if (!classExists) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Class not found\" });\n }\n }\n const granted = await getScopeDefault(userId, scope);\n if (!granted) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message:\n scope.kind === \"CLASS\"\n ? \"You don't have access to this class\"\n : scope.kind === \"SCHOOL_STORAGE\"\n ? \"You aren't a member of this institution\"\n : \"You can only access your own personal storage\",\n });\n }\n if (level === \"WRITE\" && granted !== \"WRITE\") {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message:\n scope.kind === \"CLASS\"\n ? \"Only class teachers can modify class files\"\n : \"Only teachers and admins can modify institution storage\",\n });\n }\n // Scope-default-only path; access cannot be via a grant here.\n return { scope, canWrite: granted === \"WRITE\", viaGrant: false };\n}\n\n/**\n * Folder-level access check. Delegates to the central resolver which consults\n * explicit grants in addition to the scope default. Returns the scope and a\n * canWrite flag indicating whether the user has WRITE here (used by the UI to\n * gate the \"New folder\" / \"Upload\" buttons during a READ-level browse).\n *\n * Pass `mutatesSelf: true` for actions that target the folder itself (rename,\n * delete, move-this-folder). Drive-style: explicit grants don't authorize\n * those — only scope-default WRITE does. Mutations of children should NOT\n * pass this flag.\n */\nexport async function requireFolderAccess(\n userId: string,\n folderId: string,\n level: AccessLevel,\n opts: { mutatesSelf?: boolean } = {}\n): Promise<AccessResult> {\n const result = await requireFolderAccessResolved(userId, folderId, level, opts);\n if (!result.scope) {\n // resolveFolderScope returns null only for missing folders; the resolver\n // would have already thrown NOT_FOUND in that case.\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Folder not found\" });\n }\n let canWrite = result.scopeDefault === \"WRITE\";\n if (!canWrite && level !== \"WRITE\") {\n // We came in with READ; check whether the user *also* has WRITE so the UI\n // can show the right affordances. Cheaper to do this only when needed.\n try {\n await requireFolderAccessResolved(userId, folderId, \"WRITE\");\n canWrite = true;\n } catch {\n canWrite = false;\n }\n } else if (level === \"WRITE\") {\n canWrite = true;\n }\n return { scope: result.scope, canWrite, viaGrant: result.viaGrant };\n}\n\nfunction scopesEqual(a: CloudScope, b: CloudScope): boolean {\n if (a.kind !== b.kind) return false;\n switch (a.kind) {\n case \"CLASS\":\n return a.classId === (b as typeof a).classId;\n case \"SCHOOL_STORAGE\":\n return a.schoolId === (b as typeof a).schoolId;\n case \"PERSONAL\":\n return a.userId === (b as typeof a).userId;\n }\n}\n\n/** Browse a folder. Pass `folderId` to drill into a specific folder, or a `scope` to land on its root. */\nexport async function browseFolder(\n userId: string,\n input: { folderId: string } | { scope: CloudScope }\n) {\n let scope: CloudScope;\n let folderId: string | undefined;\n let canWrite: boolean;\n let viaGrant: boolean;\n\n if (\"folderId\" in input) {\n folderId = input.folderId;\n // `requireFolderAccess` consults explicit grants in addition to the scope\n // default, so users can drill into folders shared with them via \"Shared\n // with me\" without being scope members.\n const access = await requireFolderAccess(userId, folderId, \"READ\");\n scope = access.scope;\n canWrite = access.canWrite;\n viaGrant = access.viaGrant;\n } else {\n scope = input.scope;\n const access = await requireScopeAccess(userId, scope, \"READ\");\n canWrite = access.canWrite;\n viaGrant = false;\n }\n\n const targetId = folderId ?? (await findOrCreateScopeRoot(scope)).id;\n\n const [folder, breadcrumbs] = await Promise.all([\n findFolderWithContents(targetId),\n listFolderBreadcrumbs(targetId, userId),\n ]);\n\n if (!folder) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Folder not found\" });\n }\n\n return {\n folder,\n breadcrumbs,\n canWrite,\n scope,\n /**\n * When the viewer's access comes through an explicit grant (not scope\n * membership), the UI should label the root as \"Shared with me\" rather\n * than the underlying scope's title. The grantee may not even be a\n * member of that scope — showing \"My Files\" or \"Class Files\" would be\n * misleading. Null when the viewer is a regular scope member.\n */\n displayRoot: viaGrant\n ? { kind: \"SHARED_WITH_ME\" as const, name: \"Shared with me\" }\n : null,\n };\n}\n\n/**\n * Drive-style \"Shared with me\" — surfaces every top-most folder/file the user\n * has an explicit grant on (filtering out anything already covered by their\n * scope defaults). Shaped like a folder so the existing folder-browser UI can\n * render it without special cases.\n *\n * The pseudo-folder has a synthetic id (`shared-with-me`) and the foreign-key\n * columns set to null — the UI should never try to mutate it directly. The\n * union shape matches `browseFolder`'s return type so the same client query\n * can render either.\n */\nexport async function browseSharedWithMe(userId: string) {\n const { folders } = await listSharedWithMe(userId);\n return {\n folder: {\n id: \"shared-with-me\",\n name: \"Shared with me\",\n color: null,\n classId: null,\n schoolStorageId: null,\n personalOwnerId: null,\n scope: \"GENERIC\" as const,\n parentFolderId: null,\n parentFolder: null,\n childFolders: folders.map((f) => ({\n id: f.id,\n name: f.name,\n color: f.color,\n _count: { files: 0, childFolders: 0 },\n })),\n // No file-level grants in v1 — files always live under a granted folder.\n files: [] as {\n id: string;\n name: string;\n type: string;\n size: number | null;\n path: string;\n uploadedAt: Date | null;\n user: { id: string; username: string } | null;\n }[],\n },\n breadcrumbs: [{ id: \"shared-with-me\", name: \"Shared with me\" }],\n canWrite: false,\n scope: { kind: \"PERSONAL\" as const, userId } satisfies CloudScope,\n /** Same `displayRoot` shape as `browseFolder` so the client union is uniform. */\n displayRoot: {\n kind: \"SHARED_WITH_ME\" as const,\n name: \"Shared with me\",\n },\n };\n}\n\nexport async function getRootFolder(userId: string, scope: CloudScope) {\n const result = await browseFolder(userId, { scope });\n return result.folder;\n}\n\nexport async function getFolder(userId: string, folderId: string) {\n const result = await browseFolder(userId, { folderId });\n return result.folder;\n}\n\nexport async function getFolderBreadcrumbs(userId: string, folderId: string) {\n await requireFolderAccess(userId, folderId, \"READ\");\n return listFolderBreadcrumbs(folderId);\n}\n\nexport async function getFolderParents(userId: string, folderId: string) {\n // Permission: user can read this folder.\n await requireFolderAccess(userId, folderId, \"READ\");\n const breadcrumbs = await listFolderBreadcrumbs(folderId);\n // Existing API returned full folder records — re-fetch them.\n return Promise.all(\n breadcrumbs.map((b) => findFolderById(b.id))\n );\n}\n\nexport async function createFolderRecord(\n userId: string,\n input: {\n name: string;\n parentFolderId?: string | null;\n color?: string;\n scope?: CloudScope;\n }\n) {\n let parentId: string;\n if (input.parentFolderId) {\n parentId = input.parentFolderId;\n await requireFolderAccess(userId, parentId, \"WRITE\");\n } else {\n if (!input.scope) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"scope is required when parentFolderId is omitted\",\n });\n }\n await requireScopeAccess(userId, input.scope, \"WRITE\");\n parentId = (await findOrCreateScopeRoot(input.scope)).id;\n }\n return createSubFolder({\n name: input.name.trim(),\n parentFolderId: parentId,\n color: input.color,\n });\n}\n\nexport async function updateFolderRecord(\n userId: string,\n input: { folderId: string; name?: string; color?: string }\n) {\n const folder = await findFolderById(input.folderId);\n if (!folder) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Folder not found\" });\n }\n if (!folder.parentFolderId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Cannot rename a root folder\",\n });\n }\n // Rename targets the folder itself — Drive-style guard reserves this for\n // scope-default WRITE (explicit grants don't authorize renaming the share).\n await requireFolderAccess(userId, input.folderId, \"WRITE\", {\n mutatesSelf: true,\n });\n return renameFolder(\n input.folderId,\n input.name?.trim() ?? folder.name,\n input.color\n );\n}\n\nexport async function deleteFolder(userId: string, folderId: string) {\n const folder = await findFolderById(folderId);\n if (!folder) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Folder not found\" });\n }\n if (!folder.parentFolderId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Cannot delete a root folder\",\n });\n }\n // Delete targets the folder itself — same Drive-style guard as rename.\n await requireFolderAccess(userId, folderId, \"WRITE\", { mutatesSelf: true });\n await deleteFolderById(folderId);\n return { success: true };\n}\n\nexport async function moveFolder(\n userId: string,\n input: { folderId: string; targetParentFolderId: string }\n) {\n if (input.folderId === input.targetParentFolderId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Cannot move a folder into itself\",\n });\n }\n const [sourceScope, targetScope] = await Promise.all([\n resolveFolderScope(input.folderId),\n resolveFolderScope(input.targetParentFolderId),\n ]);\n if (!sourceScope || !targetScope) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Folder not found\" });\n }\n if (!scopesEqual(sourceScope, targetScope)) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Cannot move folders between scopes\",\n });\n }\n // Moving the folder targets it (and the new parent's contents). Source-side\n // is mutates-self; target-side is regular WRITE on the new parent.\n await requireFolderAccess(userId, input.folderId, \"WRITE\", {\n mutatesSelf: true,\n });\n await requireFolderAccess(userId, input.targetParentFolderId, \"WRITE\");\n\n // Don't let a folder land under one of its own descendants.\n let cursor: string | null = input.targetParentFolderId;\n while (cursor) {\n if (cursor === input.folderId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Cannot move a folder into its own descendant\",\n });\n }\n const node = await prisma.folder.findUnique({\n where: { id: cursor },\n select: { parentFolderId: true },\n });\n cursor = node?.parentFolderId ?? null;\n }\n\n await prisma.folder.update({\n where: { id: input.folderId },\n data: { parentFolderId: input.targetParentFolderId },\n });\n return { success: true };\n}\n\nexport async function getFolderUploadUrls(\n userId: string,\n input: { folderId: string; files: DirectFileData[] }\n) {\n await requireFolderAccess(userId, input.folderId, \"WRITE\");\n return createDirectUploadFiles(input.files, userId, input.folderId);\n}\n\nexport async function confirmFolderUpload(\n _userId: string,\n input: { fileId: string; uploadSuccess: boolean; errorMessage?: string }\n) {\n // Permission was already checked at upload-url issuance — the file record\n // exists with PENDING status, and the user holds the session id needed to\n // PUT bytes. Confirming flips status, so we just trust the call.\n await confirmDirectUpload(\n input.fileId,\n input.uploadSuccess,\n input.errorMessage\n );\n return { success: true };\n}\n\n/** What scopes can this user pick from in cloud-storage UIs? */\nexport async function listUserScopes(userId: string) {\n const memberships = await prisma.schoolMembership.findMany({\n where: { userId, status: \"ACTIVE\" },\n select: {\n role: true,\n school: {\n select: { id: true, name: true, logoId: true },\n },\n },\n orderBy: { createdAt: \"asc\" },\n });\n\n const classes = await prisma.class.findMany({\n where: {\n OR: [\n { teachers: { some: { id: userId } } },\n { students: { some: { id: userId } } },\n ],\n },\n select: {\n id: true,\n name: true,\n subject: true,\n section: true,\n color: true,\n schoolId: true,\n },\n orderBy: { name: \"asc\" },\n });\n\n // Light counts for the \"Shared with me\" bucket so the UI can hide the entry\n // when there's nothing to show. Cheap to compute — just counts top-most\n // grants, not folder/file metadata.\n const sharedWithMe = await listSharedWithMe(userId);\n\n return {\n personal: { kind: \"PERSONAL\" as const, userId },\n schools: memberships.map((m) => ({\n id: m.school.id,\n name: m.school.name,\n logoId: m.school.logoId,\n role: m.role,\n })),\n classes,\n sharedWithMe: {\n kind: \"SHARED_WITH_ME\" as const,\n folderCount: sharedWithMe.folders.length,\n fileCount: sharedWithMe.files.length,\n },\n };\n}\n"],"names":[],"mappings":"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","debug_id":"338c145a-d8eb-5931-9a42-2a9c7c9acc94"}
|
|
@@ -22,8 +22,8 @@ export declare function createLabChat(userId: string, input: {
|
|
|
22
22
|
};
|
|
23
23
|
} & {
|
|
24
24
|
id: string;
|
|
25
|
-
role: import(".prisma/client").$Enums.ConversationRole;
|
|
26
25
|
userId: string;
|
|
26
|
+
role: import(".prisma/client").$Enums.ConversationRole;
|
|
27
27
|
conversationId: string;
|
|
28
28
|
joinedAt: Date;
|
|
29
29
|
hiddenAt: Date | null;
|
|
@@ -50,8 +50,8 @@ export declare function createLabChat(userId: string, input: {
|
|
|
50
50
|
id: string;
|
|
51
51
|
createdAt: Date;
|
|
52
52
|
updatedAt: Date;
|
|
53
|
-
conversationId: string;
|
|
54
53
|
classId: string;
|
|
54
|
+
conversationId: string;
|
|
55
55
|
title: string;
|
|
56
56
|
createdById: string;
|
|
57
57
|
}>;
|
|
@@ -75,8 +75,8 @@ export declare function getLabChat(userId: string, labChatId: string): Promise<{
|
|
|
75
75
|
};
|
|
76
76
|
} & {
|
|
77
77
|
id: string;
|
|
78
|
-
role: import(".prisma/client").$Enums.ConversationRole;
|
|
79
78
|
userId: string;
|
|
79
|
+
role: import(".prisma/client").$Enums.ConversationRole;
|
|
80
80
|
conversationId: string;
|
|
81
81
|
joinedAt: Date;
|
|
82
82
|
hiddenAt: Date | null;
|
|
@@ -103,8 +103,8 @@ export declare function getLabChat(userId: string, labChatId: string): Promise<{
|
|
|
103
103
|
id: string;
|
|
104
104
|
createdAt: Date;
|
|
105
105
|
updatedAt: Date;
|
|
106
|
-
conversationId: string;
|
|
107
106
|
classId: string;
|
|
107
|
+
conversationId: string;
|
|
108
108
|
title: string;
|
|
109
109
|
createdById: string;
|
|
110
110
|
}>;
|
|
@@ -163,9 +163,18 @@ export declare function postToLabChat(userId: string, input: {
|
|
|
163
163
|
} | null;
|
|
164
164
|
};
|
|
165
165
|
attachments: {
|
|
166
|
+
path: string;
|
|
166
167
|
type: string;
|
|
167
168
|
name: string;
|
|
168
169
|
id: string;
|
|
170
|
+
size: number | null;
|
|
171
|
+
uploadedAt: Date | null;
|
|
172
|
+
uploadStatus: import(".prisma/client").$Enums.UploadStatus;
|
|
173
|
+
thumbnailId: string | null;
|
|
174
|
+
thumbnail: {
|
|
175
|
+
path: string;
|
|
176
|
+
id: string;
|
|
177
|
+
} | null;
|
|
169
178
|
}[];
|
|
170
179
|
mentionedUserIds: string[];
|
|
171
180
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"labChat.d.ts","sourceRoot":"/","sources":["services/labChat.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"labChat.d.ts","sourceRoot":"/","sources":["services/labChat.ts"],"names":[],"mappings":"AA6BA,sFAAsF;AACtF,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiI3D;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCjE;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAqBjE;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+JF;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;GAiDpE;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;GAiGxE"}
|
package/dist/services/labChat.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* trigger AI responses, and broadcast via Pusher.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
6
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="cc39fd7c-6d0d-5f42-9fd5-2f11bde711b3")}catch(e){}}();
|
|
7
7
|
import { TRPCError } from "@trpc/server";
|
|
8
8
|
import { JobStatus } from "@prisma/client";
|
|
9
9
|
import { prisma } from "../lib/prisma.js";
|
|
@@ -14,6 +14,7 @@ import { createPendingAIMessage } from "../utils/inference.js";
|
|
|
14
14
|
import { logger } from "../utils/logger.js";
|
|
15
15
|
import { enqueueRunJob } from "../workers/queues.js";
|
|
16
16
|
import { claimMessageAttachments, ensureMessageHasContentOrAttachments, } from "./message.js";
|
|
17
|
+
import { messageFileSelect } from "../models/message.js";
|
|
17
18
|
/** Create a lab chat with conversation and teacher members. Broadcasts via Pusher. */
|
|
18
19
|
export async function createLabChat(userId, input) {
|
|
19
20
|
const { classId, title, context } = input;
|
|
@@ -248,7 +249,7 @@ export async function postToLabChat(userId, input) {
|
|
|
248
249
|
},
|
|
249
250
|
},
|
|
250
251
|
attachments: {
|
|
251
|
-
select:
|
|
252
|
+
select: messageFileSelect,
|
|
252
253
|
},
|
|
253
254
|
},
|
|
254
255
|
});
|
|
@@ -465,4 +466,4 @@ export async function rerunLastResponse(userId, labChatId) {
|
|
|
465
466
|
return { success: true };
|
|
466
467
|
}
|
|
467
468
|
//# sourceMappingURL=labChat.js.map
|
|
468
|
-
//# debugId=
|
|
469
|
+
//# debugId=cc39fd7c-6d0d-5f42-9fd5-2f11bde711b3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"labChat.js","sources":["services/labChat.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Lab chat service – AI-powered lab conversations. Create lab chats, post messages,\n * trigger AI responses, and broadcast via Pusher.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { JobStatus } from \"@prisma/client\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { chatChannel, teacherChannel, pusher } from \"../lib/pusher.js\";\nimport {\n findClassWithTeachersForLab,\n findLabChatByMember,\n findLabChatByTeacher,\n findLabChatById,\n findClassMembership,\n findLabChatsByClass,\n findLabChatForPost,\n findLabChatForDelete,\n findMentionedMemberships,\n} from \"../models/labChat.js\";\nimport { getAIUserId, isAIUser } from \"../utils/aiUser.js\";\nimport { createPendingAIMessage } from \"../utils/inference.js\";\nimport { logger } from \"../utils/logger.js\";\nimport { enqueueRunJob } from \"../workers/queues.js\";\nimport {\n claimMessageAttachments,\n ensureMessageHasContentOrAttachments,\n} from \"./message.js\";\n\n/** Create a lab chat with conversation and teacher members. Broadcasts via Pusher. */\nexport async function createLabChat(\n userId: string,\n input: { classId: string; title: string; context: string }\n) {\n const { classId, title, context } = input;\n\n const classWithTeachers = await findClassWithTeachersForLab(classId, userId);\n if (!classWithTeachers) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Not a teacher in this class\",\n });\n }\n\n try {\n JSON.parse(context);\n } catch {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Context must be valid JSON\",\n });\n }\n\n const result = await prisma.$transaction(async (tx) => {\n const conversation = await tx.conversation.create({\n data: {\n type: \"GROUP\",\n name: `Lab: ${title}`,\n displayInChat: false,\n },\n });\n\n const teacherMembers = classWithTeachers.teachers.map((t) => ({\n userId: t.id,\n role: \"ADMIN\" as const,\n }));\n\n await tx.conversationMember.createMany({\n data: teacherMembers.map((member) => ({\n userId: member.userId,\n conversationId: conversation.id,\n role: member.role,\n })),\n });\n\n const labChat = await tx.labChat.create({\n data: {\n title,\n context,\n classId,\n conversationId: conversation.id,\n createdById: userId,\n },\n include: {\n conversation: {\n include: {\n members: {\n include: {\n user: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n },\n },\n },\n },\n },\n },\n },\n },\n createdBy: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n },\n },\n },\n },\n class: {\n select: {\n id: true,\n name: true,\n subject: true,\n section: true,\n },\n },\n },\n });\n\n return labChat;\n });\n\n // Create the AI introduction placeholder *outside* the transaction (the\n // helper triggers Pusher and we don't want a tx rollback to leave a\n // dangling broadcast). The pipeline will fill this row in.\n try {\n const aiPlaceholder = await createPendingAIMessage(result.conversationId);\n await enqueueRunJob(\n \"AI_LAB_CHAT\",\n { conversationId: result.conversationId, aiMessageId: aiPlaceholder.id },\n { classId, userId },\n );\n } catch (error) {\n logger.error(\"Failed to enqueue lab chat introduction\", {\n error,\n labChatId: result.id,\n conversationId: result.conversationId,\n });\n }\n\n try {\n await pusher.trigger(teacherChannel(classId), \"lab-chat-created\", {\n id: result.id,\n title: result.title,\n classId: result.classId,\n conversationId: result.conversationId,\n createdBy: result.createdBy,\n createdAt: result.createdAt,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab chat creation:\", error);\n }\n\n return result;\n}\n\nexport async function getLabChat(userId: string, labChatId: string) {\n let labChat = await findLabChatByMember(labChatId, userId);\n\n if (!labChat) {\n const labChatForTeacher = await findLabChatByTeacher(labChatId, userId);\n if (labChatForTeacher) {\n await prisma.conversationMember.create({\n data: {\n userId,\n conversationId: labChatForTeacher.conversation.id,\n role: \"ADMIN\",\n },\n });\n labChat = await findLabChatById(labChatId);\n }\n }\n\n if (!labChat) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Lab chat not found or access denied\",\n });\n }\n\n // The AI placeholder row IS the pending generation marker now — its\n // status flips PENDING → COMPLETED / FAILED as the pipeline runs.\n const pendingMessage = await prisma.message.findFirst({\n where: {\n conversationId: labChat.conversationId,\n status: JobStatus.PENDING,\n senderId: getAIUserId(),\n },\n orderBy: { createdAt: \"desc\" },\n select: { id: true },\n });\n\n return {\n ...labChat,\n pendingGenerationMessageId: pendingMessage?.id ?? null,\n };\n}\n\nexport async function listLabChats(userId: string, classId: string) {\n const classMembership = await findClassMembership(classId, userId);\n if (!classMembership) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Not a member of this class\",\n });\n }\n\n const labChats = await findLabChatsByClass(classId);\n return labChats.map((labChat) => ({\n id: labChat.id,\n title: labChat.title,\n classId: labChat.classId,\n conversationId: labChat.conversationId,\n createdBy: labChat.createdBy,\n createdAt: labChat.createdAt,\n updatedAt: labChat.updatedAt,\n lastMessage: labChat.conversation.messages[0] || null,\n messageCount: labChat.conversation._count.messages,\n }));\n}\n\nexport async function postToLabChat(\n userId: string,\n input: {\n labChatId: string;\n content: string;\n mentionedUserIds?: string[];\n fileIds?: string[];\n }\n) {\n const { labChatId, content, mentionedUserIds = [], fileIds = [] } = input;\n\n const labChat = await findLabChatForPost(labChatId, userId);\n if (!labChat) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Lab chat not found or access denied\",\n });\n }\n\n if (mentionedUserIds.length > 0) {\n const mentionedMemberships = await findMentionedMemberships(\n labChat.conversationId,\n mentionedUserIds\n );\n if (mentionedMemberships.length !== mentionedUserIds.length) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Some mentioned users are not members of this lab chat\",\n });\n }\n }\n\n ensureMessageHasContentOrAttachments(content, fileIds);\n const normalizedContent = content.trim();\n\n const result = await prisma.$transaction(async (tx) => {\n const message = await tx.message.create({\n data: {\n content: normalizedContent,\n senderId: userId,\n conversationId: labChat.conversationId,\n },\n });\n\n await claimMessageAttachments(\n tx,\n userId,\n labChat.conversationId,\n message.id,\n fileIds\n );\n\n if (mentionedUserIds.length > 0) {\n await tx.mention.createMany({\n data: mentionedUserIds.map((mentionedUserId) => ({\n messageId: message.id,\n userId: mentionedUserId,\n })),\n });\n }\n\n await tx.labChat.update({\n where: { id: labChatId },\n data: { updatedAt: new Date() },\n });\n\n return tx.message.findUniqueOrThrow({\n where: { id: message.id },\n include: {\n sender: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n },\n },\n },\n },\n attachments: {\n select: { id: true, name: true, type: true },\n },\n },\n });\n });\n\n try {\n await pusher.trigger(\n chatChannel(labChat.conversationId),\n \"new-message\",\n {\n id: result.id,\n content: result.content,\n senderId: result.senderId,\n conversationId: result.conversationId,\n status: result.status,\n createdAt: result.createdAt,\n sender: result.sender,\n attachments: result.attachments ?? [],\n mentionedUserIds,\n meta: {},\n }\n );\n } catch (error) {\n console.error(\"Failed to broadcast lab chat message:\", error);\n }\n\n if (!isAIUser(userId)) {\n // Create the AI placeholder post-tx so a transaction rollback can never\n // leave a dangling PENDING bubble. The placeholder broadcast IS the\n // \"AI is thinking...\" indicator inline in the chat; the teacher-channel\n // event below drives the lab list \"AI busy in this lab\" pill.\n let aiPlaceholderId: string | null = null;\n try {\n const aiPlaceholder = await createPendingAIMessage(labChat.conversationId);\n aiPlaceholderId = aiPlaceholder.id;\n } catch (error) {\n logger.error(\"Failed to create AI placeholder for lab response\", {\n error,\n labChatId,\n teacherMessageId: result.id,\n conversationId: labChat.conversationId,\n });\n }\n\n try {\n await pusher.trigger(teacherChannel(labChat.classId), \"lab-response-pending\", {\n labChatId,\n messageId: aiPlaceholderId ?? result.id,\n conversationId: labChat.conversationId,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab response pending:\", error);\n }\n\n if (aiPlaceholderId) {\n try {\n await enqueueRunJob(\n \"AI_LAB_CHAT\",\n { conversationId: labChat.conversationId, aiMessageId: aiPlaceholderId },\n { classId: labChat.classId, userId },\n );\n } catch (error) {\n logger.error(\"Failed to enqueue lab response\", {\n error,\n labChatId,\n aiMessageId: aiPlaceholderId,\n conversationId: labChat.conversationId,\n });\n }\n }\n }\n\n return {\n id: result.id,\n content: result.content,\n senderId: result.senderId,\n conversationId: result.conversationId,\n status: result.status,\n createdAt: result.createdAt,\n sender: result.sender,\n attachments: result.attachments ?? [],\n mentionedUserIds,\n };\n}\n\nexport async function deleteLabChat(userId: string, labChatId: string) {\n const labChat = await findLabChatForDelete(labChatId, userId);\n if (!labChat) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Lab chat not found or not the creator\",\n });\n }\n\n await prisma.$transaction(async (tx) => {\n await tx.mention.deleteMany({\n where: {\n message: {\n conversationId: labChat.conversationId,\n },\n },\n });\n\n await tx.message.deleteMany({\n where: {\n conversationId: labChat.conversationId,\n },\n });\n\n await tx.conversationMember.deleteMany({\n where: {\n conversationId: labChat.conversationId,\n },\n });\n\n await tx.labChat.delete({\n where: { id: labChatId },\n });\n\n await tx.conversation.delete({\n where: { id: labChat.conversationId },\n });\n });\n\n try {\n await pusher.trigger(teacherChannel(labChat.classId), \"lab-chat-deleted\", {\n labChatId,\n classId: labChat.classId,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab chat deletion:\", error);\n }\n\n return { success: true };\n}\n\n/**\n * Rerun the last AI response in a lab chat.\n *\n * The AI message bubble is reused (not deleted): we flip it back to\n * PENDING and clear its content so the existing message id stays stable\n * for the client. The pipeline then refills it.\n */\nexport async function rerunLastResponse(userId: string, labChatId: string) {\n const labChat = await findLabChatForPost(labChatId, userId);\n if (!labChat) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Lab chat not found or access denied\",\n });\n }\n\n const messages = await prisma.message.findMany({\n where: { conversationId: labChat.conversationId },\n orderBy: { createdAt: \"desc\" },\n take: 10,\n select: { id: true, content: true, senderId: true, createdAt: true },\n });\n\n const lastMessage = messages[0];\n if (!lastMessage) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"No messages to rerun\",\n });\n }\n\n if (!isAIUser(lastMessage.senderId)) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Last message is not from AI – nothing to rerun\",\n });\n }\n\n const teacherMessage = messages.find((m) => !isAIUser(m.senderId));\n if (!teacherMessage) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"No teacher message found to rerun from\",\n });\n }\n\n const reusedAiMessage = await prisma.message.update({\n where: { id: lastMessage.id },\n data: {\n content: \"\",\n status: JobStatus.PENDING,\n meta: {},\n },\n select: { id: true, conversationId: true, status: true, content: true, senderId: true, createdAt: true },\n });\n\n // Tell the chat UI the existing AI bubble is regenerating — content\n // cleared, status flipped back to PENDING, same id.\n try {\n await pusher.trigger(chatChannel(labChat.conversationId), \"message-updated\", {\n id: reusedAiMessage.id,\n content: reusedAiMessage.content,\n senderId: reusedAiMessage.senderId,\n conversationId: reusedAiMessage.conversationId,\n status: reusedAiMessage.status,\n createdAt: reusedAiMessage.createdAt,\n sender: {\n id: reusedAiMessage.senderId,\n username: 'Newton_AI',\n profile: { displayName: 'Newton AI', profilePicture: null },\n },\n mentionedUserIds: [],\n meta: {},\n attachments: [],\n });\n } catch (error) {\n console.error(\"Failed to broadcast AI message rerun reset:\", error);\n }\n try {\n await pusher.trigger(teacherChannel(labChat.classId), \"lab-response-pending\", {\n labChatId,\n messageId: reusedAiMessage.id,\n conversationId: labChat.conversationId,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab response pending:\", error);\n }\n\n try {\n await enqueueRunJob(\n \"AI_LAB_CHAT\",\n { conversationId: labChat.conversationId, aiMessageId: reusedAiMessage.id },\n { classId: labChat.classId, userId },\n );\n } catch (error) {\n logger.error(\"Failed to enqueue lab response rerun\", {\n error,\n labChatId,\n aiMessageId: reusedAiMessage.id,\n conversationId: labChat.conversationId,\n });\n }\n\n return { success: true };\n}\n"],"names":[],"mappings":"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","debug_id":"ed2a451c-ef85-522a-a235-58f49dd2708f"}
|
|
1
|
+
{"version":3,"file":"labChat.js","sources":["services/labChat.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Lab chat service – AI-powered lab conversations. Create lab chats, post messages,\n * trigger AI responses, and broadcast via Pusher.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { JobStatus } from \"@prisma/client\";\nimport { prisma } from \"../lib/prisma.js\";\nimport { chatChannel, teacherChannel, pusher } from \"../lib/pusher.js\";\nimport {\n findClassWithTeachersForLab,\n findLabChatByMember,\n findLabChatByTeacher,\n findLabChatById,\n findClassMembership,\n findLabChatsByClass,\n findLabChatForPost,\n findLabChatForDelete,\n findMentionedMemberships,\n} from \"../models/labChat.js\";\nimport { getAIUserId, isAIUser } from \"../utils/aiUser.js\";\nimport { createPendingAIMessage } from \"../utils/inference.js\";\nimport { logger } from \"../utils/logger.js\";\nimport { enqueueRunJob } from \"../workers/queues.js\";\nimport {\n claimMessageAttachments,\n ensureMessageHasContentOrAttachments,\n} from \"./message.js\";\nimport { messageFileSelect } from \"../models/message.js\";\n\n/** Create a lab chat with conversation and teacher members. Broadcasts via Pusher. */\nexport async function createLabChat(\n userId: string,\n input: { classId: string; title: string; context: string }\n) {\n const { classId, title, context } = input;\n\n const classWithTeachers = await findClassWithTeachersForLab(classId, userId);\n if (!classWithTeachers) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Not a teacher in this class\",\n });\n }\n\n try {\n JSON.parse(context);\n } catch {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Context must be valid JSON\",\n });\n }\n\n const result = await prisma.$transaction(async (tx) => {\n const conversation = await tx.conversation.create({\n data: {\n type: \"GROUP\",\n name: `Lab: ${title}`,\n displayInChat: false,\n },\n });\n\n const teacherMembers = classWithTeachers.teachers.map((t) => ({\n userId: t.id,\n role: \"ADMIN\" as const,\n }));\n\n await tx.conversationMember.createMany({\n data: teacherMembers.map((member) => ({\n userId: member.userId,\n conversationId: conversation.id,\n role: member.role,\n })),\n });\n\n const labChat = await tx.labChat.create({\n data: {\n title,\n context,\n classId,\n conversationId: conversation.id,\n createdById: userId,\n },\n include: {\n conversation: {\n include: {\n members: {\n include: {\n user: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n },\n },\n },\n },\n },\n },\n },\n },\n createdBy: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n },\n },\n },\n },\n class: {\n select: {\n id: true,\n name: true,\n subject: true,\n section: true,\n },\n },\n },\n });\n\n return labChat;\n });\n\n // Create the AI introduction placeholder *outside* the transaction (the\n // helper triggers Pusher and we don't want a tx rollback to leave a\n // dangling broadcast). The pipeline will fill this row in.\n try {\n const aiPlaceholder = await createPendingAIMessage(result.conversationId);\n await enqueueRunJob(\n \"AI_LAB_CHAT\",\n { conversationId: result.conversationId, aiMessageId: aiPlaceholder.id },\n { classId, userId },\n );\n } catch (error) {\n logger.error(\"Failed to enqueue lab chat introduction\", {\n error,\n labChatId: result.id,\n conversationId: result.conversationId,\n });\n }\n\n try {\n await pusher.trigger(teacherChannel(classId), \"lab-chat-created\", {\n id: result.id,\n title: result.title,\n classId: result.classId,\n conversationId: result.conversationId,\n createdBy: result.createdBy,\n createdAt: result.createdAt,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab chat creation:\", error);\n }\n\n return result;\n}\n\nexport async function getLabChat(userId: string, labChatId: string) {\n let labChat = await findLabChatByMember(labChatId, userId);\n\n if (!labChat) {\n const labChatForTeacher = await findLabChatByTeacher(labChatId, userId);\n if (labChatForTeacher) {\n await prisma.conversationMember.create({\n data: {\n userId,\n conversationId: labChatForTeacher.conversation.id,\n role: \"ADMIN\",\n },\n });\n labChat = await findLabChatById(labChatId);\n }\n }\n\n if (!labChat) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Lab chat not found or access denied\",\n });\n }\n\n // The AI placeholder row IS the pending generation marker now — its\n // status flips PENDING → COMPLETED / FAILED as the pipeline runs.\n const pendingMessage = await prisma.message.findFirst({\n where: {\n conversationId: labChat.conversationId,\n status: JobStatus.PENDING,\n senderId: getAIUserId(),\n },\n orderBy: { createdAt: \"desc\" },\n select: { id: true },\n });\n\n return {\n ...labChat,\n pendingGenerationMessageId: pendingMessage?.id ?? null,\n };\n}\n\nexport async function listLabChats(userId: string, classId: string) {\n const classMembership = await findClassMembership(classId, userId);\n if (!classMembership) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Not a member of this class\",\n });\n }\n\n const labChats = await findLabChatsByClass(classId);\n return labChats.map((labChat) => ({\n id: labChat.id,\n title: labChat.title,\n classId: labChat.classId,\n conversationId: labChat.conversationId,\n createdBy: labChat.createdBy,\n createdAt: labChat.createdAt,\n updatedAt: labChat.updatedAt,\n lastMessage: labChat.conversation.messages[0] || null,\n messageCount: labChat.conversation._count.messages,\n }));\n}\n\nexport async function postToLabChat(\n userId: string,\n input: {\n labChatId: string;\n content: string;\n mentionedUserIds?: string[];\n fileIds?: string[];\n }\n) {\n const { labChatId, content, mentionedUserIds = [], fileIds = [] } = input;\n\n const labChat = await findLabChatForPost(labChatId, userId);\n if (!labChat) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Lab chat not found or access denied\",\n });\n }\n\n if (mentionedUserIds.length > 0) {\n const mentionedMemberships = await findMentionedMemberships(\n labChat.conversationId,\n mentionedUserIds\n );\n if (mentionedMemberships.length !== mentionedUserIds.length) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Some mentioned users are not members of this lab chat\",\n });\n }\n }\n\n ensureMessageHasContentOrAttachments(content, fileIds);\n const normalizedContent = content.trim();\n\n const result = await prisma.$transaction(async (tx) => {\n const message = await tx.message.create({\n data: {\n content: normalizedContent,\n senderId: userId,\n conversationId: labChat.conversationId,\n },\n });\n\n await claimMessageAttachments(\n tx,\n userId,\n labChat.conversationId,\n message.id,\n fileIds\n );\n\n if (mentionedUserIds.length > 0) {\n await tx.mention.createMany({\n data: mentionedUserIds.map((mentionedUserId) => ({\n messageId: message.id,\n userId: mentionedUserId,\n })),\n });\n }\n\n await tx.labChat.update({\n where: { id: labChatId },\n data: { updatedAt: new Date() },\n });\n\n return tx.message.findUniqueOrThrow({\n where: { id: message.id },\n include: {\n sender: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n },\n },\n },\n },\n attachments: {\n select: messageFileSelect,\n },\n },\n });\n });\n\n try {\n await pusher.trigger(\n chatChannel(labChat.conversationId),\n \"new-message\",\n {\n id: result.id,\n content: result.content,\n senderId: result.senderId,\n conversationId: result.conversationId,\n status: result.status,\n createdAt: result.createdAt,\n sender: result.sender,\n attachments: result.attachments ?? [],\n mentionedUserIds,\n meta: {},\n }\n );\n } catch (error) {\n console.error(\"Failed to broadcast lab chat message:\", error);\n }\n\n if (!isAIUser(userId)) {\n // Create the AI placeholder post-tx so a transaction rollback can never\n // leave a dangling PENDING bubble. The placeholder broadcast IS the\n // \"AI is thinking...\" indicator inline in the chat; the teacher-channel\n // event below drives the lab list \"AI busy in this lab\" pill.\n let aiPlaceholderId: string | null = null;\n try {\n const aiPlaceholder = await createPendingAIMessage(labChat.conversationId);\n aiPlaceholderId = aiPlaceholder.id;\n } catch (error) {\n logger.error(\"Failed to create AI placeholder for lab response\", {\n error,\n labChatId,\n teacherMessageId: result.id,\n conversationId: labChat.conversationId,\n });\n }\n\n try {\n await pusher.trigger(teacherChannel(labChat.classId), \"lab-response-pending\", {\n labChatId,\n messageId: aiPlaceholderId ?? result.id,\n conversationId: labChat.conversationId,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab response pending:\", error);\n }\n\n if (aiPlaceholderId) {\n try {\n await enqueueRunJob(\n \"AI_LAB_CHAT\",\n { conversationId: labChat.conversationId, aiMessageId: aiPlaceholderId },\n { classId: labChat.classId, userId },\n );\n } catch (error) {\n logger.error(\"Failed to enqueue lab response\", {\n error,\n labChatId,\n aiMessageId: aiPlaceholderId,\n conversationId: labChat.conversationId,\n });\n }\n }\n }\n\n return {\n id: result.id,\n content: result.content,\n senderId: result.senderId,\n conversationId: result.conversationId,\n status: result.status,\n createdAt: result.createdAt,\n sender: result.sender,\n attachments: result.attachments ?? [],\n mentionedUserIds,\n };\n}\n\nexport async function deleteLabChat(userId: string, labChatId: string) {\n const labChat = await findLabChatForDelete(labChatId, userId);\n if (!labChat) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Lab chat not found or not the creator\",\n });\n }\n\n await prisma.$transaction(async (tx) => {\n await tx.mention.deleteMany({\n where: {\n message: {\n conversationId: labChat.conversationId,\n },\n },\n });\n\n await tx.message.deleteMany({\n where: {\n conversationId: labChat.conversationId,\n },\n });\n\n await tx.conversationMember.deleteMany({\n where: {\n conversationId: labChat.conversationId,\n },\n });\n\n await tx.labChat.delete({\n where: { id: labChatId },\n });\n\n await tx.conversation.delete({\n where: { id: labChat.conversationId },\n });\n });\n\n try {\n await pusher.trigger(teacherChannel(labChat.classId), \"lab-chat-deleted\", {\n labChatId,\n classId: labChat.classId,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab chat deletion:\", error);\n }\n\n return { success: true };\n}\n\n/**\n * Rerun the last AI response in a lab chat.\n *\n * The AI message bubble is reused (not deleted): we flip it back to\n * PENDING and clear its content so the existing message id stays stable\n * for the client. The pipeline then refills it.\n */\nexport async function rerunLastResponse(userId: string, labChatId: string) {\n const labChat = await findLabChatForPost(labChatId, userId);\n if (!labChat) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Lab chat not found or access denied\",\n });\n }\n\n const messages = await prisma.message.findMany({\n where: { conversationId: labChat.conversationId },\n orderBy: { createdAt: \"desc\" },\n take: 10,\n select: { id: true, content: true, senderId: true, createdAt: true },\n });\n\n const lastMessage = messages[0];\n if (!lastMessage) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"No messages to rerun\",\n });\n }\n\n if (!isAIUser(lastMessage.senderId)) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Last message is not from AI – nothing to rerun\",\n });\n }\n\n const teacherMessage = messages.find((m) => !isAIUser(m.senderId));\n if (!teacherMessage) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"No teacher message found to rerun from\",\n });\n }\n\n const reusedAiMessage = await prisma.message.update({\n where: { id: lastMessage.id },\n data: {\n content: \"\",\n status: JobStatus.PENDING,\n meta: {},\n },\n select: { id: true, conversationId: true, status: true, content: true, senderId: true, createdAt: true },\n });\n\n // Tell the chat UI the existing AI bubble is regenerating — content\n // cleared, status flipped back to PENDING, same id.\n try {\n await pusher.trigger(chatChannel(labChat.conversationId), \"message-updated\", {\n id: reusedAiMessage.id,\n content: reusedAiMessage.content,\n senderId: reusedAiMessage.senderId,\n conversationId: reusedAiMessage.conversationId,\n status: reusedAiMessage.status,\n createdAt: reusedAiMessage.createdAt,\n sender: {\n id: reusedAiMessage.senderId,\n username: 'Newton_AI',\n profile: { displayName: 'Newton AI', profilePicture: null },\n },\n mentionedUserIds: [],\n meta: {},\n attachments: [],\n });\n } catch (error) {\n console.error(\"Failed to broadcast AI message rerun reset:\", error);\n }\n try {\n await pusher.trigger(teacherChannel(labChat.classId), \"lab-response-pending\", {\n labChatId,\n messageId: reusedAiMessage.id,\n conversationId: labChat.conversationId,\n });\n } catch (error) {\n console.error(\"Failed to broadcast lab response pending:\", error);\n }\n\n try {\n await enqueueRunJob(\n \"AI_LAB_CHAT\",\n { conversationId: labChat.conversationId, aiMessageId: reusedAiMessage.id },\n { classId: labChat.classId, userId },\n );\n } catch (error) {\n logger.error(\"Failed to enqueue lab response rerun\", {\n error,\n labChatId,\n aiMessageId: reusedAiMessage.id,\n conversationId: labChat.conversationId,\n });\n }\n\n return { success: true };\n}\n"],"names":[],"mappings":"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","debug_id":"cc39fd7c-6d0d-5f42-9fd5-2f11bde711b3"}
|
|
@@ -44,9 +44,18 @@ export declare function listMessages(userId: string, input: {
|
|
|
44
44
|
};
|
|
45
45
|
status: import(".prisma/client").$Enums.JobStatus | null;
|
|
46
46
|
attachments: {
|
|
47
|
-
|
|
48
|
-
name: string;
|
|
47
|
+
path: string;
|
|
49
48
|
type: string;
|
|
49
|
+
name: string;
|
|
50
|
+
id: string;
|
|
51
|
+
size: number | null;
|
|
52
|
+
uploadedAt: Date | null;
|
|
53
|
+
uploadStatus: import(".prisma/client").$Enums.UploadStatus;
|
|
54
|
+
thumbnailId: string | null;
|
|
55
|
+
thumbnail: {
|
|
56
|
+
path: string;
|
|
57
|
+
id: string;
|
|
58
|
+
} | null;
|
|
50
59
|
}[];
|
|
51
60
|
meta: Record<string, unknown>;
|
|
52
61
|
mentions: {
|
|
@@ -84,9 +93,18 @@ export declare function sendMessage(userId: string, input: {
|
|
|
84
93
|
} | null;
|
|
85
94
|
};
|
|
86
95
|
attachments: {
|
|
96
|
+
path: string;
|
|
87
97
|
type: string;
|
|
88
98
|
name: string;
|
|
89
99
|
id: string;
|
|
100
|
+
size: number | null;
|
|
101
|
+
uploadedAt: Date | null;
|
|
102
|
+
uploadStatus: import(".prisma/client").$Enums.UploadStatus;
|
|
103
|
+
thumbnailId: string | null;
|
|
104
|
+
thumbnail: {
|
|
105
|
+
path: string;
|
|
106
|
+
id: string;
|
|
107
|
+
} | null;
|
|
90
108
|
}[];
|
|
91
109
|
mentionedUserIds: string[];
|
|
92
110
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.d.ts","sourceRoot":"/","sources":["services/message.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"message.d.ts","sourceRoot":"/","sources":["services/message.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAoB7C,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,MAAM,EAAO,QAQvB;AAED,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,MAAM,CAAC,iBAAiB,EAC5B,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,MAAM,EAAO,iBA2BvB;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACvD,8DAmBF;AAED,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;;;GAuCF;AAED,oEAAoE;AACpE,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAiCyB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;;GAMlD;AAED,oFAAoF;AACpF,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkIF;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;;;;;;;;;;;;;;;;GAqHF;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;GAuDpE;AAUD,mFAAmF;AACnF,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,YAAY,GAAG,WAAW,GAAG,SAAS,CAAC;IAC7C,KAAK,EAAE,MAAM,CAAC;CACf;;GA8HF;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM;;GA+BtE;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM;;GAgCvB;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM;;;GA8BvB"}
|
package/dist/services/message.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="a0453833-3ac8-5c02-9d64-8a457397f108")}catch(e){}}();
|
|
3
3
|
import { TRPCError } from "@trpc/server";
|
|
4
4
|
import { prisma } from "../lib/prisma.js";
|
|
5
5
|
import { chatChannel, pusher } from "../lib/pusher.js";
|
|
6
6
|
import { confirmDirectUpload, createDirectUploadFiles, } from "../lib/fileUpload.js";
|
|
7
7
|
import { logger } from "../utils/logger.js";
|
|
8
|
-
import { findConversationMembership, findMessages, findMentionedMemberships, findMessageById, findMessageByIdMinimal, countUnreadMessages, countUnreadMentions, } from "../models/message.js";
|
|
8
|
+
import { findConversationMembership, findMessages, findMentionedMemberships, findMessageById, findMessageByIdMinimal, countUnreadMessages, countUnreadMentions, messageFileSelect, } from "../models/message.js";
|
|
9
9
|
export function ensureMessageHasContentOrAttachments(content, fileIds = []) {
|
|
10
10
|
if (!content.trim() && fileIds.length === 0) {
|
|
11
11
|
throw new TRPCError({
|
|
@@ -56,18 +56,6 @@ export async function confirmMessageUpload(userId, input) {
|
|
|
56
56
|
message: "Not a member of this conversation",
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
|
-
if (input.uploadSuccess) {
|
|
60
|
-
await prisma.$transaction(async (tx) => {
|
|
61
|
-
await tx.file.update({
|
|
62
|
-
where: { id: input.fileId },
|
|
63
|
-
data: { uploadStatus: "FAILED", uploadError: input.errorMessage },
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
throw new TRPCError({
|
|
67
|
-
code: "INTERNAL_SERVER_ERROR",
|
|
68
|
-
message: "Failed to confirm upload",
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
59
|
const file = await prisma.file.findFirst({
|
|
72
60
|
where: {
|
|
73
61
|
id: input.fileId,
|
|
@@ -119,11 +107,7 @@ export async function listMessages(userId, input) {
|
|
|
119
107
|
createdAt: message.createdAt,
|
|
120
108
|
sender: message.sender,
|
|
121
109
|
status: message.status,
|
|
122
|
-
attachments: message.attachments
|
|
123
|
-
id: a.id,
|
|
124
|
-
name: a.name,
|
|
125
|
-
type: a.type,
|
|
126
|
-
})),
|
|
110
|
+
attachments: message.attachments,
|
|
127
111
|
meta: message.meta,
|
|
128
112
|
mentions: message.mentions.map((m) => ({ user: m.user })),
|
|
129
113
|
mentionsMe: message.mentions.some((m) => m.userId === userId),
|
|
@@ -196,7 +180,7 @@ export async function sendMessage(userId, input) {
|
|
|
196
180
|
},
|
|
197
181
|
},
|
|
198
182
|
attachments: {
|
|
199
|
-
select:
|
|
183
|
+
select: messageFileSelect,
|
|
200
184
|
},
|
|
201
185
|
},
|
|
202
186
|
});
|
|
@@ -283,7 +267,7 @@ export async function updateMessage(userId, input) {
|
|
|
283
267
|
},
|
|
284
268
|
},
|
|
285
269
|
attachments: {
|
|
286
|
-
select:
|
|
270
|
+
select: messageFileSelect,
|
|
287
271
|
},
|
|
288
272
|
},
|
|
289
273
|
});
|
|
@@ -450,7 +434,7 @@ export async function markSuggestionCreated(userId, input) {
|
|
|
450
434
|
},
|
|
451
435
|
},
|
|
452
436
|
},
|
|
453
|
-
attachments: { select:
|
|
437
|
+
attachments: { select: messageFileSelect },
|
|
454
438
|
mentions: { select: { userId: true } },
|
|
455
439
|
},
|
|
456
440
|
});
|
|
@@ -562,4 +546,4 @@ export async function getUnreadCount(userId, conversationId) {
|
|
|
562
546
|
return { unreadCount, unreadMentionCount };
|
|
563
547
|
}
|
|
564
548
|
//# sourceMappingURL=message.js.map
|
|
565
|
-
//# debugId=
|
|
549
|
+
//# debugId=a0453833-3ac8-5c02-9d64-8a457397f108
|