@studious-lms/server 1.4.4 → 1.4.6
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/index.js +3 -17
- package/dist/index.js.map +1 -1
- package/dist/lib/config/cors.d.ts.map +1 -1
- package/dist/lib/config/cors.js +8 -3
- package/dist/lib/config/cors.js.map +1 -1
- package/dist/models/comment.d.ts +163 -0
- package/dist/models/comment.d.ts.map +1 -1
- package/dist/models/comment.js +145 -3
- package/dist/models/comment.js.map +1 -1
- package/dist/models/conversation.d.ts +22 -0
- package/dist/models/conversation.d.ts.map +1 -1
- package/dist/models/conversation.js +13 -2
- package/dist/models/conversation.js.map +1 -1
- package/dist/models/labChat.d.ts +3 -0
- package/dist/models/labChat.d.ts.map +1 -1
- package/dist/models/message.d.ts +2 -0
- package/dist/models/message.d.ts.map +1 -1
- package/dist/models/newtonChat.d.ts +1 -0
- package/dist/models/newtonChat.d.ts.map +1 -1
- package/dist/models/worksheet.d.ts +2 -0
- package/dist/models/worksheet.d.ts.map +1 -1
- package/dist/pipelines/aiLabChat.d.ts.map +1 -1
- package/dist/pipelines/aiLabChat.js +4 -3
- package/dist/pipelines/aiLabChat.js.map +1 -1
- package/dist/routers/_app.d.ts +665 -1
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +4 -2
- package/dist/routers/_app.js.map +1 -1
- package/dist/routers/announcement.d.ts +8 -0
- package/dist/routers/announcement.d.ts.map +1 -1
- package/dist/routers/assignment.d.ts +230 -0
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/assignment.js +207 -2
- package/dist/routers/assignment.js.map +1 -1
- package/dist/routers/comment.d.ts +37 -0
- package/dist/routers/comment.d.ts.map +1 -1
- package/dist/routers/comment.js +14 -5
- package/dist/routers/comment.js.map +1 -1
- package/dist/routers/conversation.d.ts +14 -0
- package/dist/routers/conversation.d.ts.map +1 -1
- package/dist/routers/conversation.js +6 -3
- package/dist/routers/conversation.js.map +1 -1
- package/dist/routers/labChat.d.ts +2 -0
- package/dist/routers/labChat.d.ts.map +1 -1
- package/dist/routers/search.d.ts +41 -0
- package/dist/routers/search.d.ts.map +1 -0
- package/dist/routers/search.js +15 -0
- package/dist/routers/search.js.map +1 -0
- package/dist/routers/worksheet.d.ts +2 -0
- package/dist/routers/worksheet.d.ts.map +1 -1
- package/dist/services/comment.d.ts +28 -2
- package/dist/services/comment.d.ts.map +1 -1
- package/dist/services/comment.js +97 -19
- package/dist/services/comment.js.map +1 -1
- package/dist/services/conversation.d.ts +8 -0
- package/dist/services/conversation.d.ts.map +1 -1
- package/dist/services/conversation.js +24 -6
- package/dist/services/conversation.js.map +1 -1
- package/dist/services/labChat.d.ts +2 -0
- package/dist/services/labChat.d.ts.map +1 -1
- package/dist/services/message.d.ts.map +1 -1
- package/dist/services/message.js +9 -2
- package/dist/services/message.js.map +1 -1
- package/dist/services/search.d.ts +21 -0
- package/dist/services/search.d.ts.map +1 -0
- package/dist/services/search.js +352 -0
- package/dist/services/search.js.map +1 -0
- package/dist/services/worksheet.d.ts +2 -0
- package/dist/services/worksheet.d.ts.map +1 -1
- package/package.json +1 -1
- package/prisma/migrations/20260417083000_add_conversation_member_hidden_at/migration.sql +2 -0
- package/prisma/migrations/20260502230500_assignment_submission_comments/migration.sql +60 -0
- package/prisma/schema.prisma +10 -0
- package/src/index.ts +1 -17
- package/src/lib/config/cors.ts +8 -1
- package/src/models/comment.ts +148 -1
- package/src/models/conversation.ts +12 -0
- package/src/pipelines/aiLabChat.ts +2 -1
- package/src/routers/_app.ts +2 -0
- package/src/routers/assignment.ts +224 -1
- package/src/routers/comment.ts +19 -2
- package/src/routers/conversation.ts +7 -0
- package/src/routers/search.ts +14 -0
- package/src/services/comment.ts +113 -18
- package/src/services/conversation.ts +27 -3
- package/src/services/message.ts +8 -0
- package/src/services/search.ts +397 -0
- package/tests/lib/cors.test.ts +13 -1
- package/tests/routers/assignment.test.ts +68 -2
- package/tests/routers/comment.test.ts +42 -1
- package/tests/routers/conversation.test.ts +114 -2
- package/tests/routers/search.test.ts +109 -0
- package/vercel.json +8 -0
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/** Get a comment by ID. */
|
|
2
|
-
export declare function getComment(id: string): Promise<{
|
|
2
|
+
export declare function getComment(userId: string, id: string): Promise<{
|
|
3
3
|
id: string;
|
|
4
|
+
assignmentId: string | null;
|
|
5
|
+
submissionId: string | null;
|
|
6
|
+
announcementId: string | null;
|
|
4
7
|
reactions: {
|
|
5
8
|
type: import(".prisma/client").$Enums.ReactionType;
|
|
6
9
|
user: {
|
|
@@ -16,6 +19,7 @@ export declare function getComment(id: string): Promise<{
|
|
|
16
19
|
createdAt: Date;
|
|
17
20
|
modifiedAt: Date | null;
|
|
18
21
|
content: string;
|
|
22
|
+
parentCommentId: string | null;
|
|
19
23
|
author: {
|
|
20
24
|
id: string;
|
|
21
25
|
username: string;
|
|
@@ -27,7 +31,7 @@ export declare function getComment(id: string): Promise<{
|
|
|
27
31
|
};
|
|
28
32
|
}>;
|
|
29
33
|
/** Get all replies to a comment. */
|
|
30
|
-
export declare function getReplies(commentId: string): Promise<({
|
|
34
|
+
export declare function getReplies(userId: string, commentId: string): Promise<({
|
|
31
35
|
author: {
|
|
32
36
|
id: string;
|
|
33
37
|
username: string;
|
|
@@ -40,6 +44,8 @@ export declare function getReplies(commentId: string): Promise<({
|
|
|
40
44
|
} & {
|
|
41
45
|
status: import(".prisma/client").$Enums.GenerationStatus | null;
|
|
42
46
|
id: string;
|
|
47
|
+
assignmentId: string | null;
|
|
48
|
+
submissionId: string | null;
|
|
43
49
|
announcementId: string | null;
|
|
44
50
|
createdAt: Date;
|
|
45
51
|
modifiedAt: Date | null;
|
|
@@ -52,6 +58,22 @@ export declare function getReplies(commentId: string): Promise<({
|
|
|
52
58
|
export declare function replyToComment(userId: string, parentCommentId: string, content: string): Promise<{
|
|
53
59
|
status: import(".prisma/client").$Enums.GenerationStatus | null;
|
|
54
60
|
id: string;
|
|
61
|
+
assignmentId: string | null;
|
|
62
|
+
submissionId: string | null;
|
|
63
|
+
announcementId: string | null;
|
|
64
|
+
createdAt: Date;
|
|
65
|
+
modifiedAt: Date | null;
|
|
66
|
+
content: string;
|
|
67
|
+
authorId: string;
|
|
68
|
+
parentCommentId: string | null;
|
|
69
|
+
studentQuestionProgressId: string | null;
|
|
70
|
+
}>;
|
|
71
|
+
/** Update a comment authored by the user. */
|
|
72
|
+
export declare function updateComment(userId: string, id: string, content: string): Promise<{
|
|
73
|
+
status: import(".prisma/client").$Enums.GenerationStatus | null;
|
|
74
|
+
id: string;
|
|
75
|
+
assignmentId: string | null;
|
|
76
|
+
submissionId: string | null;
|
|
55
77
|
announcementId: string | null;
|
|
56
78
|
createdAt: Date;
|
|
57
79
|
modifiedAt: Date | null;
|
|
@@ -60,6 +82,10 @@ export declare function replyToComment(userId: string, parentCommentId: string,
|
|
|
60
82
|
parentCommentId: string | null;
|
|
61
83
|
studentQuestionProgressId: string | null;
|
|
62
84
|
}>;
|
|
85
|
+
/** Delete a comment authored by the user or moderated by a class teacher. */
|
|
86
|
+
export declare function deleteComment(userId: string, id: string): Promise<{
|
|
87
|
+
success: boolean;
|
|
88
|
+
}>;
|
|
63
89
|
/** Add or update a reaction (emoji) on a comment. */
|
|
64
90
|
export declare function addReaction(userId: string, commentId: string, type: string): Promise<{
|
|
65
91
|
reaction: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comment.d.ts","sourceRoot":"/","sources":["services/comment.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"comment.d.ts","sourceRoot":"/","sources":["services/comment.ts"],"names":[],"mappings":"AAoFA,2BAA2B;AAC3B,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAU1D;AAED,oCAAoC;AACpC,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;MAGjE;AAED,6CAA6C;AAC7C,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM;;;;;;;;;;;;GAYhB;AAED,6CAA6C;AAC7C,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;;;;;GAa9E;AAED,6EAA6E;AAC7E,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;;GAW7D;AAED,qDAAqD;AACrD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM;;;;;;;;;;;;;;;;;;;GAMb;AAED,6CAA6C;AAC7C,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;GAWrE;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;;;;;;;;;GAuBnE"}
|
package/dist/services/comment.js
CHANGED
|
@@ -1,12 +1,69 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Comment service – get comments, replies, and reactions.
|
|
2
|
+
* Comment service – get comments, replies, and reactions.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
!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]="
|
|
5
|
+
!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]="2f340cd4-2a5e-59d9-8448-05f1acff840a")}catch(e){}}();
|
|
6
6
|
import { TRPCError } from "@trpc/server";
|
|
7
|
-
import {
|
|
7
|
+
import { prisma } from "../lib/prisma.js";
|
|
8
|
+
import { findCommentById, findRepliesByCommentId, createComment, findReactionByUserAndComment, upsertReaction, deleteReactionById, findCommentWithContext, getReactionCountsByCommentId, } from "../models/comment.js";
|
|
9
|
+
function getCommentClass(comment) {
|
|
10
|
+
return (comment.announcement?.class ??
|
|
11
|
+
comment.assignment?.class ??
|
|
12
|
+
comment.submission?.assignment?.class ??
|
|
13
|
+
comment.studentQuestionProgress?.studentWorksheetResponse?.submission?.assignment?.class ??
|
|
14
|
+
comment.parentComment?.announcement?.class ??
|
|
15
|
+
comment.parentComment?.assignment?.class ??
|
|
16
|
+
comment.parentComment?.submission?.assignment?.class ??
|
|
17
|
+
comment.parentComment?.studentQuestionProgress?.studentWorksheetResponse?.submission?.assignment?.class ??
|
|
18
|
+
null);
|
|
19
|
+
}
|
|
20
|
+
function getPrivateStudentId(comment) {
|
|
21
|
+
return (comment.submission?.studentId ??
|
|
22
|
+
comment.studentQuestionProgress?.studentWorksheetResponse?.submission?.studentId ??
|
|
23
|
+
comment.studentQuestionProgress?.studentId ??
|
|
24
|
+
comment.parentComment?.submission?.studentId ??
|
|
25
|
+
comment.parentComment?.studentQuestionProgress?.studentWorksheetResponse?.submission?.studentId ??
|
|
26
|
+
comment.parentComment?.studentQuestionProgress?.studentId ??
|
|
27
|
+
null);
|
|
28
|
+
}
|
|
29
|
+
function isClassTeacher(comment, userId) {
|
|
30
|
+
return getCommentClass(comment)?.teachers?.some((teacher) => teacher.id === userId) ?? false;
|
|
31
|
+
}
|
|
32
|
+
function isClassMember(comment, userId) {
|
|
33
|
+
const classData = getCommentClass(comment);
|
|
34
|
+
return (classData?.teachers?.some((teacher) => teacher.id === userId) ||
|
|
35
|
+
classData?.students?.some((student) => student.id === userId) ||
|
|
36
|
+
false);
|
|
37
|
+
}
|
|
38
|
+
function canReadComment(comment, userId) {
|
|
39
|
+
const privateStudentId = getPrivateStudentId(comment);
|
|
40
|
+
if (privateStudentId) {
|
|
41
|
+
return privateStudentId === userId || isClassTeacher(comment, userId);
|
|
42
|
+
}
|
|
43
|
+
return isClassMember(comment, userId);
|
|
44
|
+
}
|
|
45
|
+
function canDeleteComment(comment, userId) {
|
|
46
|
+
return comment.authorId === userId || isClassTeacher(comment, userId);
|
|
47
|
+
}
|
|
48
|
+
async function requireCommentAccess(commentId, userId) {
|
|
49
|
+
const comment = await findCommentWithContext(commentId);
|
|
50
|
+
if (!comment) {
|
|
51
|
+
throw new TRPCError({
|
|
52
|
+
code: "NOT_FOUND",
|
|
53
|
+
message: "Comment not found",
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if (!canReadComment(comment, userId)) {
|
|
57
|
+
throw new TRPCError({
|
|
58
|
+
code: "FORBIDDEN",
|
|
59
|
+
message: "You do not have access to this comment",
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return comment;
|
|
63
|
+
}
|
|
8
64
|
/** Get a comment by ID. */
|
|
9
|
-
export async function getComment(id) {
|
|
65
|
+
export async function getComment(userId, id) {
|
|
66
|
+
await requireCommentAccess(id, userId);
|
|
10
67
|
const comment = await findCommentById(id);
|
|
11
68
|
if (!comment) {
|
|
12
69
|
throw new TRPCError({
|
|
@@ -17,31 +74,58 @@ export async function getComment(id) {
|
|
|
17
74
|
return comment;
|
|
18
75
|
}
|
|
19
76
|
/** Get all replies to a comment. */
|
|
20
|
-
export async function getReplies(commentId) {
|
|
77
|
+
export async function getReplies(userId, commentId) {
|
|
78
|
+
await requireCommentAccess(commentId, userId);
|
|
21
79
|
return findRepliesByCommentId(commentId);
|
|
22
80
|
}
|
|
23
81
|
/** Create a reply to an existing comment. */
|
|
24
82
|
export async function replyToComment(userId, parentCommentId, content) {
|
|
83
|
+
const parentComment = await requireCommentAccess(parentCommentId, userId);
|
|
25
84
|
return createComment({
|
|
26
85
|
parentCommentId,
|
|
27
86
|
content,
|
|
28
87
|
authorId: userId,
|
|
88
|
+
announcementId: parentComment.announcementId,
|
|
89
|
+
assignmentId: parentComment.assignmentId,
|
|
90
|
+
submissionId: parentComment.submissionId,
|
|
91
|
+
studentQuestionProgressId: parentComment.studentQuestionProgressId,
|
|
29
92
|
});
|
|
30
93
|
}
|
|
31
|
-
/**
|
|
32
|
-
export async function
|
|
33
|
-
const comment = await
|
|
34
|
-
if (
|
|
94
|
+
/** Update a comment authored by the user. */
|
|
95
|
+
export async function updateComment(userId, id, content) {
|
|
96
|
+
const comment = await requireCommentAccess(id, userId);
|
|
97
|
+
if (comment.authorId !== userId) {
|
|
35
98
|
throw new TRPCError({
|
|
36
|
-
code: "
|
|
37
|
-
message: "
|
|
99
|
+
code: "FORBIDDEN",
|
|
100
|
+
message: "Only the comment author can update this comment",
|
|
38
101
|
});
|
|
39
102
|
}
|
|
103
|
+
return prisma.comment.update({
|
|
104
|
+
where: { id },
|
|
105
|
+
data: { content },
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/** Delete a comment authored by the user or moderated by a class teacher. */
|
|
109
|
+
export async function deleteComment(userId, id) {
|
|
110
|
+
const comment = await requireCommentAccess(id, userId);
|
|
111
|
+
if (!canDeleteComment(comment, userId)) {
|
|
112
|
+
throw new TRPCError({
|
|
113
|
+
code: "FORBIDDEN",
|
|
114
|
+
message: "Only the comment author or class teachers can delete comments",
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
await prisma.comment.delete({ where: { id } });
|
|
118
|
+
return { success: true };
|
|
119
|
+
}
|
|
120
|
+
/** Add or update a reaction (emoji) on a comment. */
|
|
121
|
+
export async function addReaction(userId, commentId, type) {
|
|
122
|
+
await requireCommentAccess(commentId, userId);
|
|
40
123
|
const reaction = await upsertReaction({ userId, commentId, type });
|
|
41
124
|
return { reaction };
|
|
42
125
|
}
|
|
43
126
|
/** Remove user's reaction from a comment. */
|
|
44
127
|
export async function removeReaction(userId, commentId) {
|
|
128
|
+
await requireCommentAccess(commentId, userId);
|
|
45
129
|
const reaction = await findReactionByUserAndComment(userId, commentId);
|
|
46
130
|
if (!reaction) {
|
|
47
131
|
throw new TRPCError({
|
|
@@ -53,13 +137,7 @@ export async function removeReaction(userId, commentId) {
|
|
|
53
137
|
return { success: true };
|
|
54
138
|
}
|
|
55
139
|
export async function getReactions(userId, commentId) {
|
|
56
|
-
|
|
57
|
-
if (!comment) {
|
|
58
|
-
throw new TRPCError({
|
|
59
|
-
code: "NOT_FOUND",
|
|
60
|
-
message: "Comment not found",
|
|
61
|
-
});
|
|
62
|
-
}
|
|
140
|
+
await requireCommentAccess(commentId, userId);
|
|
63
141
|
const reactionCounts = await getReactionCountsByCommentId(commentId);
|
|
64
142
|
const userReaction = await findReactionByUserAndComment(userId, commentId);
|
|
65
143
|
const counts = {
|
|
@@ -80,4 +158,4 @@ export async function getReactions(userId, commentId) {
|
|
|
80
158
|
};
|
|
81
159
|
}
|
|
82
160
|
//# sourceMappingURL=comment.js.map
|
|
83
|
-
//# debugId=
|
|
161
|
+
//# debugId=2f340cd4-2a5e-59d9-8448-05f1acff840a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comment.js","sources":["services/comment.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Comment service – get comments, replies, and reactions. Used for announcements and worksheets.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport {\n findCommentById,\n findRepliesByCommentId,\n createComment,\n findReactionByUserAndComment,\n upsertReaction,\n deleteReactionById,\n findCommentWithAnnouncement,\n getReactionCountsByCommentId,\n} from \"../models/comment.js\";\n\n/** Get a comment by ID. */\nexport async function getComment(id: string) {\n const comment = await findCommentById(id);\n if (!comment) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Comment not found\",\n });\n }\n return comment;\n}\n\n/** Get all replies to a comment. */\nexport async function getReplies(commentId: string) {\n return findRepliesByCommentId(commentId);\n}\n\n/** Create a reply to an existing comment. */\nexport async function replyToComment(\n userId: string,\n parentCommentId: string,\n content: string\n) {\n return createComment({\n parentCommentId,\n content,\n authorId: userId,\n });\n}\n\n/** Add or update a reaction (emoji) on a comment. */\nexport async function addReaction(\n userId: string,\n commentId: string,\n type: string\n) {\n const comment = await findCommentById(commentId);\n if (!comment) {\n throw new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: \"Unexpected error\",\n });\n }\n\n const reaction = await upsertReaction({ userId, commentId, type });\n return { reaction };\n}\n\n/** Remove user's reaction from a comment. */\nexport async function removeReaction(userId: string, commentId: string) {\n const reaction = await findReactionByUserAndComment(userId, commentId);\n if (!reaction) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Reaction not found\",\n });\n }\n await deleteReactionById(reaction.id);\n return { success: true };\n}\n\nexport async function getReactions(userId: string, commentId: string) {\n const comment = await findCommentWithAnnouncement(commentId);\n if (!comment) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Comment not found\",\n });\n }\n\n const reactionCounts = await getReactionCountsByCommentId(commentId);\n const userReaction = await findReactionByUserAndComment(userId, commentId);\n\n const counts = {\n THUMBSUP: 0,\n CELEBRATE: 0,\n CARE: 0,\n HEART: 0,\n IDEA: 0,\n HAPPY: 0,\n };\n reactionCounts.forEach((item) => {\n counts[item.type as keyof typeof counts] = item._count.type;\n });\n\n return {\n counts,\n userReaction: userReaction?.type || null,\n total: reactionCounts.reduce((sum, item) => sum + item._count.type, 0),\n };\n}\n"],"names":[],"mappings":"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","debug_id":"381af507-0513-5413-ae9b-6bcb211761ee"}
|
|
1
|
+
{"version":3,"file":"comment.js","sources":["services/comment.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Comment service – get comments, replies, and reactions.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { prisma } from \"../lib/prisma.js\";\nimport {\n findCommentById,\n findRepliesByCommentId,\n createComment,\n findReactionByUserAndComment,\n upsertReaction,\n deleteReactionById,\n findCommentWithContext,\n getReactionCountsByCommentId,\n} from \"../models/comment.js\";\n\nfunction getCommentClass(comment: any) {\n return (\n comment.announcement?.class ??\n comment.assignment?.class ??\n comment.submission?.assignment?.class ??\n comment.studentQuestionProgress?.studentWorksheetResponse?.submission?.assignment?.class ??\n comment.parentComment?.announcement?.class ??\n comment.parentComment?.assignment?.class ??\n comment.parentComment?.submission?.assignment?.class ??\n comment.parentComment?.studentQuestionProgress?.studentWorksheetResponse?.submission?.assignment?.class ??\n null\n );\n}\n\nfunction getPrivateStudentId(comment: any) {\n return (\n comment.submission?.studentId ??\n comment.studentQuestionProgress?.studentWorksheetResponse?.submission?.studentId ??\n comment.studentQuestionProgress?.studentId ??\n comment.parentComment?.submission?.studentId ??\n comment.parentComment?.studentQuestionProgress?.studentWorksheetResponse?.submission?.studentId ??\n comment.parentComment?.studentQuestionProgress?.studentId ??\n null\n );\n}\n\nfunction isClassTeacher(comment: any, userId: string) {\n return getCommentClass(comment)?.teachers?.some((teacher: { id: string }) => teacher.id === userId) ?? false;\n}\n\nfunction isClassMember(comment: any, userId: string) {\n const classData = getCommentClass(comment);\n return (\n classData?.teachers?.some((teacher: { id: string }) => teacher.id === userId) ||\n classData?.students?.some((student: { id: string }) => student.id === userId) ||\n false\n );\n}\n\nfunction canReadComment(comment: any, userId: string) {\n const privateStudentId = getPrivateStudentId(comment);\n if (privateStudentId) {\n return privateStudentId === userId || isClassTeacher(comment, userId);\n }\n return isClassMember(comment, userId);\n}\n\nfunction canDeleteComment(comment: any, userId: string) {\n return comment.authorId === userId || isClassTeacher(comment, userId);\n}\n\nasync function requireCommentAccess(commentId: string, userId: string) {\n const comment = await findCommentWithContext(commentId);\n if (!comment) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Comment not found\",\n });\n }\n if (!canReadComment(comment, userId)) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You do not have access to this comment\",\n });\n }\n return comment;\n}\n\n/** Get a comment by ID. */\nexport async function getComment(userId: string, id: string) {\n await requireCommentAccess(id, userId);\n const comment = await findCommentById(id);\n if (!comment) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Comment not found\",\n });\n }\n return comment;\n}\n\n/** Get all replies to a comment. */\nexport async function getReplies(userId: string, commentId: string) {\n await requireCommentAccess(commentId, userId);\n return findRepliesByCommentId(commentId);\n}\n\n/** Create a reply to an existing comment. */\nexport async function replyToComment(\n userId: string,\n parentCommentId: string,\n content: string\n) {\n const parentComment = await requireCommentAccess(parentCommentId, userId);\n return createComment({\n parentCommentId,\n content,\n authorId: userId,\n announcementId: parentComment.announcementId,\n assignmentId: parentComment.assignmentId,\n submissionId: parentComment.submissionId,\n studentQuestionProgressId: parentComment.studentQuestionProgressId,\n });\n}\n\n/** Update a comment authored by the user. */\nexport async function updateComment(userId: string, id: string, content: string) {\n const comment = await requireCommentAccess(id, userId);\n if (comment.authorId !== userId) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only the comment author can update this comment\",\n });\n }\n\n return prisma.comment.update({\n where: { id },\n data: { content },\n });\n}\n\n/** Delete a comment authored by the user or moderated by a class teacher. */\nexport async function deleteComment(userId: string, id: string) {\n const comment = await requireCommentAccess(id, userId);\n if (!canDeleteComment(comment, userId)) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only the comment author or class teachers can delete comments\",\n });\n }\n\n await prisma.comment.delete({ where: { id } });\n return { success: true };\n}\n\n/** Add or update a reaction (emoji) on a comment. */\nexport async function addReaction(\n userId: string,\n commentId: string,\n type: string\n) {\n await requireCommentAccess(commentId, userId);\n\n const reaction = await upsertReaction({ userId, commentId, type });\n return { reaction };\n}\n\n/** Remove user's reaction from a comment. */\nexport async function removeReaction(userId: string, commentId: string) {\n await requireCommentAccess(commentId, userId);\n const reaction = await findReactionByUserAndComment(userId, commentId);\n if (!reaction) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Reaction not found\",\n });\n }\n await deleteReactionById(reaction.id);\n return { success: true };\n}\n\nexport async function getReactions(userId: string, commentId: string) {\n await requireCommentAccess(commentId, userId);\n\n const reactionCounts = await getReactionCountsByCommentId(commentId);\n const userReaction = await findReactionByUserAndComment(userId, commentId);\n\n const counts = {\n THUMBSUP: 0,\n CELEBRATE: 0,\n CARE: 0,\n HEART: 0,\n IDEA: 0,\n HAPPY: 0,\n };\n reactionCounts.forEach((item) => {\n counts[item.type as keyof typeof counts] = item._count.type;\n });\n\n return {\n counts,\n userReaction: userReaction?.type || null,\n total: reactionCounts.reduce((sum, item) => sum + item._count.type, 0),\n };\n}\n"],"names":[],"mappings":"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","debug_id":"2f340cd4-2a5e-59d9-8448-05f1acff840a"}
|
|
@@ -24,6 +24,7 @@ export declare function listConversations(userId: string): Promise<{
|
|
|
24
24
|
conversationId: string;
|
|
25
25
|
role: import(".prisma/client").$Enums.ConversationRole;
|
|
26
26
|
joinedAt: Date;
|
|
27
|
+
hiddenAt: Date | null;
|
|
27
28
|
lastViewedAt: Date | null;
|
|
28
29
|
lastViewedMentionAt: Date | null;
|
|
29
30
|
})[];
|
|
@@ -47,6 +48,9 @@ export declare function listConversations(userId: string): Promise<{
|
|
|
47
48
|
unreadCount: number;
|
|
48
49
|
unreadMentionCount: number;
|
|
49
50
|
}[]>;
|
|
51
|
+
export declare function hideConversation(userId: string, conversationId: string): Promise<{
|
|
52
|
+
success: boolean;
|
|
53
|
+
}>;
|
|
50
54
|
/** Create a DM or group conversation with the given members. */
|
|
51
55
|
export declare function createConversationRecord(userId: string, type: "DM" | "GROUP", name: string | undefined, memberIds: string[]): Promise<{
|
|
52
56
|
members: ({
|
|
@@ -64,6 +68,7 @@ export declare function createConversationRecord(userId: string, type: "DM" | "G
|
|
|
64
68
|
conversationId: string;
|
|
65
69
|
role: import(".prisma/client").$Enums.ConversationRole;
|
|
66
70
|
joinedAt: Date;
|
|
71
|
+
hiddenAt: Date | null;
|
|
67
72
|
lastViewedAt: Date | null;
|
|
68
73
|
lastViewedMentionAt: Date | null;
|
|
69
74
|
})[];
|
|
@@ -91,6 +96,7 @@ export declare function getConversation(userId: string, conversationId: string):
|
|
|
91
96
|
conversationId: string;
|
|
92
97
|
role: import(".prisma/client").$Enums.ConversationRole;
|
|
93
98
|
joinedAt: Date;
|
|
99
|
+
hiddenAt: Date | null;
|
|
94
100
|
lastViewedAt: Date | null;
|
|
95
101
|
lastViewedMentionAt: Date | null;
|
|
96
102
|
})[];
|
|
@@ -118,6 +124,7 @@ export declare function addMemberToConversation(userId: string, conversationId:
|
|
|
118
124
|
conversationId: string;
|
|
119
125
|
role: import(".prisma/client").$Enums.ConversationRole;
|
|
120
126
|
joinedAt: Date;
|
|
127
|
+
hiddenAt: Date | null;
|
|
121
128
|
lastViewedAt: Date | null;
|
|
122
129
|
lastViewedMentionAt: Date | null;
|
|
123
130
|
})[];
|
|
@@ -145,6 +152,7 @@ export declare function removeMemberFromConversation(userId: string, conversatio
|
|
|
145
152
|
conversationId: string;
|
|
146
153
|
role: import(".prisma/client").$Enums.ConversationRole;
|
|
147
154
|
joinedAt: Date;
|
|
155
|
+
hiddenAt: Date | null;
|
|
148
156
|
lastViewedAt: Date | null;
|
|
149
157
|
lastViewedMentionAt: Date | null;
|
|
150
158
|
})[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.d.ts","sourceRoot":"/","sources":["services/conversation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"conversation.d.ts","sourceRoot":"/","sources":["services/conversation.ts"],"names":[],"mappings":"AAmBA,gEAAgE;AAChE,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAuDrD;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM;;GAY5E;AAED,gEAAgE;AAChE,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,IAAI,GAAG,OAAO,EACpB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,SAAS,EAAE,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEpB;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;GAavB;AAED,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BvB;AAED,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;GAejB"}
|
|
@@ -3,13 +3,20 @@
|
|
|
3
3
|
* Handles member management and unread counts.
|
|
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]="1e016f9f-4be7-566a-a3f9-ad63c2a0ada1")}catch(e){}}();
|
|
7
7
|
import { TRPCError } from "@trpc/server";
|
|
8
|
-
import { findConversationsByUserId, countUnreadMessages, countUnreadMentions, findUserByUsername, findDmConversationsByUserId, findUsersByIdsOrUsernames, createConversation, findConversationByIdAndMember, createConversationMember, deleteConversationMember, } from "../models/conversation.js";
|
|
8
|
+
import { findConversationsByUserId, countUnreadMessages, countUnreadMentions, findUserByUsername, findDmConversationsByUserId, findUsersByIdsOrUsernames, createConversation, findConversationByIdAndMember, createConversationMember, hideConversationMember, deleteConversationMember, } from "../models/conversation.js";
|
|
9
9
|
/** List user's conversations with unread and mention counts. */
|
|
10
10
|
export async function listConversations(userId) {
|
|
11
11
|
const conversations = await findConversationsByUserId(userId);
|
|
12
|
-
const
|
|
12
|
+
const visibleConversations = conversations.filter((conversation) => {
|
|
13
|
+
const userMembership = conversation.members.find((member) => member.userId === userId);
|
|
14
|
+
if (!userMembership?.hiddenAt) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
return conversation.updatedAt > userMembership.hiddenAt;
|
|
18
|
+
});
|
|
19
|
+
const conversationsWithUnread = await Promise.all(visibleConversations.map(async (conversation) => {
|
|
13
20
|
const userMembership = conversation.members.find((m) => m.userId === userId);
|
|
14
21
|
const lastViewedAt = userMembership?.lastViewedAt;
|
|
15
22
|
const lastViewedMentionAt = userMembership?.lastViewedMentionAt;
|
|
@@ -35,6 +42,17 @@ export async function listConversations(userId) {
|
|
|
35
42
|
}));
|
|
36
43
|
return conversationsWithUnread;
|
|
37
44
|
}
|
|
45
|
+
export async function hideConversation(userId, conversationId) {
|
|
46
|
+
const conversation = await findConversationByIdAndMember(conversationId, userId);
|
|
47
|
+
if (!conversation) {
|
|
48
|
+
throw new TRPCError({
|
|
49
|
+
code: "FORBIDDEN",
|
|
50
|
+
message: "Not a member of this conversation",
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
await hideConversationMember(userId, conversationId);
|
|
54
|
+
return { success: true };
|
|
55
|
+
}
|
|
38
56
|
/** Create a DM or group conversation with the given members. */
|
|
39
57
|
export async function createConversationRecord(userId, type, name, memberIds) {
|
|
40
58
|
if (type === "GROUP" && !name) {
|
|
@@ -50,11 +68,11 @@ export async function createConversationRecord(userId, type, name, memberIds) {
|
|
|
50
68
|
});
|
|
51
69
|
}
|
|
52
70
|
if (type === "DM") {
|
|
53
|
-
const targetUser = await
|
|
71
|
+
const [targetUser] = await findUsersByIdsOrUsernames([memberIds[0]]);
|
|
54
72
|
if (!targetUser) {
|
|
55
73
|
throw new TRPCError({
|
|
56
74
|
code: "BAD_REQUEST",
|
|
57
|
-
message: `User
|
|
75
|
+
message: `User not found`,
|
|
58
76
|
});
|
|
59
77
|
}
|
|
60
78
|
const existingDMs = await findDmConversationsByUserId(userId);
|
|
@@ -135,4 +153,4 @@ export async function removeMemberFromConversation(userId, conversationId, membe
|
|
|
135
153
|
return conversation;
|
|
136
154
|
}
|
|
137
155
|
//# sourceMappingURL=conversation.js.map
|
|
138
|
-
//# debugId=
|
|
156
|
+
//# debugId=1e016f9f-4be7-566a-a3f9-ad63c2a0ada1
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.js","sources":["services/conversation.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Conversation service – list, create, and manage DM/group conversations.\n * Handles member management and unread counts.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport {\n findConversationsByUserId,\n countUnreadMessages,\n countUnreadMentions,\n findUserByUsername,\n findDmConversationsByUserId,\n findUsersByIdsOrUsernames,\n createConversation,\n findConversationByIdAndMember,\n createConversationMember,\n deleteConversationMember,\n} from \"../models/conversation.js\";\n\n/** List user's conversations with unread and mention counts. */\nexport async function listConversations(userId: string) {\n const conversations = await findConversationsByUserId(userId);\n\n const conversationsWithUnread = await Promise.all(\n conversations.map(async (conversation) => {\n const userMembership = conversation.members.find(\n (m) => m.userId === userId\n );\n const lastViewedAt = userMembership?.lastViewedAt;\n const lastViewedMentionAt = userMembership?.lastViewedMentionAt;\n\n const unreadCount = await countUnreadMessages(\n conversation.id,\n userId,\n lastViewedAt ?? undefined\n );\n\n const mentionCutoffTime =\n lastViewedMentionAt && lastViewedAt\n ? lastViewedMentionAt > lastViewedAt\n ? lastViewedMentionAt\n : lastViewedAt\n : lastViewedMentionAt || lastViewedAt;\n\n const unreadMentionCount = await countUnreadMentions(\n conversation.id,\n userId,\n mentionCutoffTime ?? undefined\n );\n\n return {\n id: conversation.id,\n type: conversation.type,\n name: conversation.name,\n createdAt: conversation.createdAt,\n updatedAt: conversation.updatedAt,\n labChat: conversation.labChat,\n members: conversation.members,\n lastMessage: conversation.messages[0] || null,\n unreadCount,\n unreadMentionCount,\n };\n })\n );\n\n return conversationsWithUnread;\n}\n\n/** Create a DM or group conversation with the given members. */\nexport async function createConversationRecord(\n userId: string,\n type: \"DM\" | \"GROUP\",\n name: string | undefined,\n memberIds: string[]\n) {\n if (type === \"GROUP\" && !name) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Group conversations must have a name\",\n });\n }\n\n if (type === \"DM\" && memberIds.length !== 1) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"DM conversations must have exactly one other member\",\n });\n }\n\n if (type === \"DM\") {\n const targetUser = await findUserByUsername(memberIds[0]);\n if (!targetUser) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: `User \"${memberIds[0]}\" not found`,\n });\n }\n\n const existingDMs = await findDmConversationsByUserId(userId);\n const existingDM = existingDMs.find((conv) => {\n const memberUserIds = conv.members.map((m) => m.userId);\n return (\n memberUserIds.length === 2 &&\n memberUserIds.includes(userId) &&\n memberUserIds.includes(targetUser.id)\n );\n });\n\n if (existingDM) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: `A conversation with ${targetUser.username} already exists`,\n });\n }\n }\n\n const members = await findUsersByIdsOrUsernames(memberIds);\n type Member = (typeof members)[number];\n const uniqueMembers = Array.from(\n new Map(members.map((m) => [m.id, m] as [string, Member])).values()\n );\n\n if (uniqueMembers.length !== memberIds.length) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"One or more members not found\",\n });\n }\n\n const toAddIds = memberIds\n .map((id) =>\n uniqueMembers.find((m) => m.id === id || m.username === id)?.id\n )\n .filter(Boolean) as string[];\n\n return createConversation({\n type,\n name,\n members: [\n { userId, role: type === \"GROUP\" ? \"ADMIN\" : \"MEMBER\" },\n ...toAddIds.map((uid) => ({ userId: uid, role: \"MEMBER\" })),\n ],\n });\n}\n\nexport async function getConversation(\n userId: string,\n conversationId: string\n) {\n const conversation = await findConversationByIdAndMember(\n conversationId,\n userId\n );\n if (!conversation) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Conversation not found or access denied\",\n });\n }\n return conversation;\n}\n\nexport async function addMemberToConversation(\n userId: string,\n conversationId: string,\n memberUsername: string\n) {\n const conversation = await findConversationByIdAndMember(\n conversationId,\n userId\n );\n if (!conversation) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Conversation not found or access denied\",\n });\n }\n\n const member = await findUserByUsername(memberUsername);\n if (!member) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Member not found\",\n });\n }\n\n await createConversationMember({\n userId: member.id,\n conversationId,\n role: \"MEMBER\",\n });\n\n return conversation;\n}\n\nexport async function removeMemberFromConversation(\n userId: string,\n conversationId: string,\n memberId: string\n) {\n const conversation = await findConversationByIdAndMember(\n conversationId,\n userId\n );\n if (!conversation) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Conversation not found or access denied\",\n });\n }\n\n await deleteConversationMember(memberId, conversationId);\n return conversation;\n}\n"],"names":[],"mappings":"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","debug_id":"4ed19abe-3dc1-5bea-9dac-6a700dc76438"}
|
|
1
|
+
{"version":3,"file":"conversation.js","sources":["services/conversation.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Conversation service – list, create, and manage DM/group conversations.\n * Handles member management and unread counts.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport {\n findConversationsByUserId,\n countUnreadMessages,\n countUnreadMentions,\n findUserByUsername,\n findDmConversationsByUserId,\n findUsersByIdsOrUsernames,\n createConversation,\n findConversationByIdAndMember,\n createConversationMember,\n hideConversationMember,\n deleteConversationMember,\n} from \"../models/conversation.js\";\n\n/** List user's conversations with unread and mention counts. */\nexport async function listConversations(userId: string) {\n const conversations = await findConversationsByUserId(userId);\n const visibleConversations = conversations.filter((conversation) => {\n const userMembership = conversation.members.find((member) => member.userId === userId);\n\n if (!userMembership?.hiddenAt) {\n return true;\n }\n\n return conversation.updatedAt > userMembership.hiddenAt;\n });\n\n const conversationsWithUnread = await Promise.all(\n visibleConversations.map(async (conversation) => {\n const userMembership = conversation.members.find(\n (m) => m.userId === userId\n );\n const lastViewedAt = userMembership?.lastViewedAt;\n const lastViewedMentionAt = userMembership?.lastViewedMentionAt;\n\n const unreadCount = await countUnreadMessages(\n conversation.id,\n userId,\n lastViewedAt ?? undefined\n );\n\n const mentionCutoffTime =\n lastViewedMentionAt && lastViewedAt\n ? lastViewedMentionAt > lastViewedAt\n ? lastViewedMentionAt\n : lastViewedAt\n : lastViewedMentionAt || lastViewedAt;\n\n const unreadMentionCount = await countUnreadMentions(\n conversation.id,\n userId,\n mentionCutoffTime ?? undefined\n );\n\n return {\n id: conversation.id,\n type: conversation.type,\n name: conversation.name,\n createdAt: conversation.createdAt,\n updatedAt: conversation.updatedAt,\n labChat: conversation.labChat,\n members: conversation.members,\n lastMessage: conversation.messages[0] || null,\n unreadCount,\n unreadMentionCount,\n };\n })\n );\n\n return conversationsWithUnread;\n}\n\nexport async function hideConversation(userId: string, conversationId: string) {\n const conversation = await findConversationByIdAndMember(conversationId, userId);\n if (!conversation) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Not a member of this conversation\",\n });\n }\n\n await hideConversationMember(userId, conversationId);\n\n return { success: true };\n}\n\n/** Create a DM or group conversation with the given members. */\nexport async function createConversationRecord(\n userId: string,\n type: \"DM\" | \"GROUP\",\n name: string | undefined,\n memberIds: string[]\n) {\n if (type === \"GROUP\" && !name) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Group conversations must have a name\",\n });\n }\n\n if (type === \"DM\" && memberIds.length !== 1) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"DM conversations must have exactly one other member\",\n });\n }\n\n if (type === \"DM\") {\n const [targetUser] = await findUsersByIdsOrUsernames([memberIds[0]]);\n if (!targetUser) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: `User not found`,\n });\n }\n\n const existingDMs = await findDmConversationsByUserId(userId);\n const existingDM = existingDMs.find((conv) => {\n const memberUserIds = conv.members.map((m) => m.userId);\n return (\n memberUserIds.length === 2 &&\n memberUserIds.includes(userId) &&\n memberUserIds.includes(targetUser.id)\n );\n });\n\n if (existingDM) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: `A conversation with ${targetUser.username} already exists`,\n });\n }\n }\n\n const members = await findUsersByIdsOrUsernames(memberIds);\n type Member = (typeof members)[number];\n const uniqueMembers = Array.from(\n new Map(members.map((m) => [m.id, m] as [string, Member])).values()\n );\n\n if (uniqueMembers.length !== memberIds.length) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"One or more members not found\",\n });\n }\n\n const toAddIds = memberIds\n .map((id) =>\n uniqueMembers.find((m) => m.id === id || m.username === id)?.id\n )\n .filter(Boolean) as string[];\n\n return createConversation({\n type,\n name,\n members: [\n { userId, role: type === \"GROUP\" ? \"ADMIN\" : \"MEMBER\" },\n ...toAddIds.map((uid) => ({ userId: uid, role: \"MEMBER\" })),\n ],\n });\n}\n\nexport async function getConversation(\n userId: string,\n conversationId: string\n) {\n const conversation = await findConversationByIdAndMember(\n conversationId,\n userId\n );\n if (!conversation) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Conversation not found or access denied\",\n });\n }\n return conversation;\n}\n\nexport async function addMemberToConversation(\n userId: string,\n conversationId: string,\n memberUsername: string\n) {\n const conversation = await findConversationByIdAndMember(\n conversationId,\n userId\n );\n if (!conversation) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Conversation not found or access denied\",\n });\n }\n\n const member = await findUserByUsername(memberUsername);\n if (!member) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Member not found\",\n });\n }\n\n await createConversationMember({\n userId: member.id,\n conversationId,\n role: \"MEMBER\",\n });\n\n return conversation;\n}\n\nexport async function removeMemberFromConversation(\n userId: string,\n conversationId: string,\n memberId: string\n) {\n const conversation = await findConversationByIdAndMember(\n conversationId,\n userId\n );\n if (!conversation) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Conversation not found or access denied\",\n });\n }\n\n await deleteConversationMember(memberId, conversationId);\n return conversation;\n}\n"],"names":[],"mappings":"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","debug_id":"1e016f9f-4be7-566a-a3f9-ad63c2a0ada1"}
|
|
@@ -26,6 +26,7 @@ export declare function createLabChat(userId: string, input: {
|
|
|
26
26
|
conversationId: string;
|
|
27
27
|
role: import(".prisma/client").$Enums.ConversationRole;
|
|
28
28
|
joinedAt: Date;
|
|
29
|
+
hiddenAt: Date | null;
|
|
29
30
|
lastViewedAt: Date | null;
|
|
30
31
|
lastViewedMentionAt: Date | null;
|
|
31
32
|
})[];
|
|
@@ -78,6 +79,7 @@ export declare function getLabChat(userId: string, labChatId: string): Promise<{
|
|
|
78
79
|
conversationId: string;
|
|
79
80
|
role: import(".prisma/client").$Enums.ConversationRole;
|
|
80
81
|
joinedAt: Date;
|
|
82
|
+
hiddenAt: Date | null;
|
|
81
83
|
lastViewedAt: Date | null;
|
|
82
84
|
lastViewedMentionAt: Date | null;
|
|
83
85
|
})[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"labChat.d.ts","sourceRoot":"/","sources":["services/labChat.ts"],"names":[],"mappings":"AA2BA,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
|
|
1
|
+
{"version":3,"file":"labChat.d.ts","sourceRoot":"/","sources":["services/labChat.ts"],"names":[],"mappings":"AA2BA,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsH3D;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCjE;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;;;;;;;;;;;;;;;;;;;;GAuIF;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;GAiDpE;AAED,8FAA8F;AAC9F,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;GAiFxE"}
|
|
@@ -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;AAmB7C,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;;;;;;;;;;;;;;;;;;;;cAoCyB,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;;;;;;;;;;;;;;;;;;;;
|
|
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;AAmB7C,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;;;;;;;;;;;;;;;;;;;;cAoCyB,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;;;;;;;;;;;;;;;;;;;;GAgIF;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;;;;;;;;;;;;;;;GAmHF;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;;GA6HF;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,5 +1,5 @@
|
|
|
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]="181d07f5-4bad-5e9c-a71e-3c354adb855b")}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";
|
|
@@ -156,6 +156,13 @@ export async function sendMessage(userId, input) {
|
|
|
156
156
|
})),
|
|
157
157
|
});
|
|
158
158
|
}
|
|
159
|
+
await tx.conversationMember.updateMany({
|
|
160
|
+
where: {
|
|
161
|
+
conversationId,
|
|
162
|
+
hiddenAt: { not: null },
|
|
163
|
+
},
|
|
164
|
+
data: { hiddenAt: null },
|
|
165
|
+
});
|
|
159
166
|
await tx.conversation.update({
|
|
160
167
|
where: { id: conversationId },
|
|
161
168
|
data: { updatedAt: new Date() },
|
|
@@ -537,4 +544,4 @@ export async function getUnreadCount(userId, conversationId) {
|
|
|
537
544
|
return { unreadCount, unreadMentionCount };
|
|
538
545
|
}
|
|
539
546
|
//# sourceMappingURL=message.js.map
|
|
540
|
-
//# debugId=
|
|
547
|
+
//# debugId=181d07f5-4bad-5e9c-a71e-3c354adb855b
|