@studious-lms/server 1.1.24 → 1.2.26
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/lib/fileUpload.d.ts +2 -2
- package/dist/lib/fileUpload.d.ts.map +1 -1
- package/dist/lib/fileUpload.js +76 -14
- package/dist/lib/googleCloudStorage.d.ts +7 -0
- package/dist/lib/googleCloudStorage.d.ts.map +1 -1
- package/dist/lib/googleCloudStorage.js +19 -0
- package/dist/lib/notificationHandler.d.ts +25 -0
- package/dist/lib/notificationHandler.d.ts.map +1 -0
- package/dist/lib/notificationHandler.js +28 -0
- package/dist/routers/_app.d.ts +818 -78
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/announcement.d.ts +290 -3
- package/dist/routers/announcement.d.ts.map +1 -1
- package/dist/routers/announcement.js +896 -10
- package/dist/routers/assignment.d.ts +70 -4
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/assignment.js +265 -131
- package/dist/routers/auth.js +1 -1
- package/dist/routers/file.d.ts +2 -0
- package/dist/routers/file.d.ts.map +1 -1
- package/dist/routers/file.js +9 -6
- package/dist/routers/labChat.d.ts.map +1 -1
- package/dist/routers/labChat.js +13 -5
- package/dist/routers/notifications.d.ts +8 -8
- package/dist/routers/section.d.ts +16 -0
- package/dist/routers/section.d.ts.map +1 -1
- package/dist/routers/section.js +139 -30
- package/dist/seedDatabase.d.ts +2 -2
- package/dist/seedDatabase.d.ts.map +1 -1
- package/dist/seedDatabase.js +2 -1
- package/dist/utils/logger.d.ts +1 -0
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +27 -2
- package/package.json +2 -2
- package/prisma/migrations/20251109122857_annuoncements_comments/migration.sql +30 -0
- package/prisma/migrations/20251109135555_reactions_announcements_comments/migration.sql +35 -0
- package/prisma/schema.prisma +50 -0
- package/src/lib/fileUpload.ts +79 -14
- package/src/lib/googleCloudStorage.ts +19 -0
- package/src/lib/notificationHandler.ts +36 -0
- package/src/routers/announcement.ts +1007 -10
- package/src/routers/assignment.ts +230 -82
- package/src/routers/auth.ts +1 -1
- package/src/routers/file.ts +10 -7
- package/src/routers/labChat.ts +15 -6
- package/src/routers/section.ts +158 -36
- package/src/seedDatabase.ts +2 -1
- package/src/utils/logger.ts +29 -2
- package/tests/setup.ts +3 -9
package/dist/lib/fileUpload.d.ts
CHANGED
|
@@ -49,7 +49,7 @@ export declare function getFileUrl(filePath: string): Promise<string>;
|
|
|
49
49
|
* @param submissionId Optional submission ID to associate the file with
|
|
50
50
|
* @returns The direct upload file information with signed URL
|
|
51
51
|
*/
|
|
52
|
-
export declare function createDirectUploadFile(file: DirectFileData, userId: string, directory?: string, assignmentId?: string, submissionId?: string): Promise<DirectUploadFile>;
|
|
52
|
+
export declare function createDirectUploadFile(file: DirectFileData, userId: string, directory?: string, assignmentId?: string, submissionId?: string, announcementId?: string): Promise<DirectUploadFile>;
|
|
53
53
|
/**
|
|
54
54
|
* Confirms a direct upload was successful
|
|
55
55
|
* @param fileId The ID of the file record
|
|
@@ -72,5 +72,5 @@ export declare function updateUploadProgress(fileId: string, progress: number):
|
|
|
72
72
|
* @param submissionId Optional submission ID to associate files with
|
|
73
73
|
* @returns Array of direct upload file information
|
|
74
74
|
*/
|
|
75
|
-
export declare function createDirectUploadFiles(files: DirectFileData[], userId: string, directory?: string, assignmentId?: string, submissionId?: string): Promise<DirectUploadFile[]>;
|
|
75
|
+
export declare function createDirectUploadFiles(files: DirectFileData[], userId: string, directory?: string, assignmentId?: string, submissionId?: string, announcementId?: string): Promise<DirectUploadFile[]>;
|
|
76
76
|
//# sourceMappingURL=fileUpload.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileUpload.d.ts","sourceRoot":"","sources":["../../src/lib/fileUpload.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAEd;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAEd;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,IAAI,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAKD;;GAEG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,YAAY,CAAC,CAKvB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,QAAQ,EAAE,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CAKzB;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUlE;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"fileUpload.d.ts","sourceRoot":"","sources":["../../src/lib/fileUpload.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAEd;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAEd;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,IAAI,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAKD;;GAEG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,YAAY,CAAC,CAKvB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,QAAQ,EAAE,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CAKzB;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUlE;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,MAAM,EACrB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,gBAAgB,CAAC,CA8F3B;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,OAAO,EACtB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CA+Df;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CA8Bf;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,cAAc,EAAE,EACvB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,MAAM,EACrB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAiB7B"}
|
package/dist/lib/fileUpload.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { TRPCError } from "@trpc/server";
|
|
2
2
|
import { v4 as uuidv4 } from "uuid";
|
|
3
|
-
import { getSignedUrl } from "./googleCloudStorage.js";
|
|
3
|
+
import { getSignedUrl, objectExists } from "./googleCloudStorage.js";
|
|
4
4
|
import { prisma } from "./prisma.js";
|
|
5
|
+
import { logger } from "../utils/logger.js";
|
|
5
6
|
// DEPRECATED: These functions are no longer used - files are uploaded directly to GCS
|
|
6
7
|
// Use createDirectUploadFile() and createDirectUploadFiles() instead
|
|
7
8
|
/**
|
|
@@ -48,7 +49,7 @@ export async function getFileUrl(filePath) {
|
|
|
48
49
|
* @param submissionId Optional submission ID to associate the file with
|
|
49
50
|
* @returns The direct upload file information with signed URL
|
|
50
51
|
*/
|
|
51
|
-
export async function createDirectUploadFile(file, userId, directory, assignmentId, submissionId) {
|
|
52
|
+
export async function createDirectUploadFile(file, userId, directory, assignmentId, submissionId, announcementId) {
|
|
52
53
|
try {
|
|
53
54
|
// Validate file extension matches MIME type
|
|
54
55
|
const fileExtension = file.name.split('.').pop()?.toLowerCase();
|
|
@@ -105,6 +106,11 @@ export async function createDirectUploadFile(file, userId, directory, assignment
|
|
|
105
106
|
submission: {
|
|
106
107
|
connect: { id: submissionId }
|
|
107
108
|
}
|
|
109
|
+
}),
|
|
110
|
+
...(announcementId && {
|
|
111
|
+
announcement: {
|
|
112
|
+
connect: { id: announcementId }
|
|
113
|
+
}
|
|
108
114
|
})
|
|
109
115
|
},
|
|
110
116
|
});
|
|
@@ -120,7 +126,11 @@ export async function createDirectUploadFile(file, userId, directory, assignment
|
|
|
120
126
|
};
|
|
121
127
|
}
|
|
122
128
|
catch (error) {
|
|
123
|
-
|
|
129
|
+
logger.error('Error creating direct upload file:', { error: error instanceof Error ? {
|
|
130
|
+
name: error.name,
|
|
131
|
+
message: error.message,
|
|
132
|
+
stack: error.stack,
|
|
133
|
+
} : error });
|
|
124
134
|
throw new TRPCError({
|
|
125
135
|
code: 'INTERNAL_SERVER_ERROR',
|
|
126
136
|
message: 'Failed to create direct upload file',
|
|
@@ -135,15 +145,48 @@ export async function createDirectUploadFile(file, userId, directory, assignment
|
|
|
135
145
|
*/
|
|
136
146
|
export async function confirmDirectUpload(fileId, uploadSuccess, errorMessage) {
|
|
137
147
|
try {
|
|
148
|
+
// First fetch the file record to get the object path
|
|
149
|
+
const fileRecord = await prisma.file.findUnique({
|
|
150
|
+
where: { id: fileId },
|
|
151
|
+
select: { path: true }
|
|
152
|
+
});
|
|
153
|
+
if (!fileRecord) {
|
|
154
|
+
throw new TRPCError({
|
|
155
|
+
code: 'NOT_FOUND',
|
|
156
|
+
message: 'File record not found',
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
let actualUploadSuccess = uploadSuccess;
|
|
160
|
+
let actualErrorMessage = errorMessage;
|
|
161
|
+
// If uploadSuccess is true, verify the object actually exists in GCS
|
|
162
|
+
if (uploadSuccess) {
|
|
163
|
+
try {
|
|
164
|
+
const exists = await objectExists(process.env.GOOGLE_CLOUD_BUCKET_NAME, fileRecord.path);
|
|
165
|
+
if (!exists) {
|
|
166
|
+
actualUploadSuccess = false;
|
|
167
|
+
actualErrorMessage = 'File upload reported as successful but object not found in Google Cloud Storage';
|
|
168
|
+
logger.error(`File upload verification failed for ${fileId}: object ${fileRecord.path} not found in GCS`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
logger.error(`Error verifying file existence in GCS for ${fileId}:`, { error: error instanceof Error ? {
|
|
173
|
+
name: error.name,
|
|
174
|
+
message: error.message,
|
|
175
|
+
stack: error.stack,
|
|
176
|
+
} : error });
|
|
177
|
+
actualUploadSuccess = false;
|
|
178
|
+
actualErrorMessage = 'Failed to verify file existence in Google Cloud Storage';
|
|
179
|
+
}
|
|
180
|
+
}
|
|
138
181
|
const updateData = {
|
|
139
|
-
uploadStatus:
|
|
140
|
-
uploadProgress:
|
|
182
|
+
uploadStatus: actualUploadSuccess ? 'COMPLETED' : 'FAILED',
|
|
183
|
+
uploadProgress: actualUploadSuccess ? 100 : 0,
|
|
141
184
|
};
|
|
142
|
-
if (!
|
|
143
|
-
updateData.uploadError =
|
|
185
|
+
if (!actualUploadSuccess && actualErrorMessage) {
|
|
186
|
+
updateData.uploadError = actualErrorMessage;
|
|
144
187
|
updateData.uploadRetryCount = { increment: 1 };
|
|
145
188
|
}
|
|
146
|
-
if (
|
|
189
|
+
if (actualUploadSuccess) {
|
|
147
190
|
updateData.uploadedAt = new Date();
|
|
148
191
|
}
|
|
149
192
|
await prisma.file.update({
|
|
@@ -152,7 +195,7 @@ export async function confirmDirectUpload(fileId, uploadSuccess, errorMessage) {
|
|
|
152
195
|
});
|
|
153
196
|
}
|
|
154
197
|
catch (error) {
|
|
155
|
-
|
|
198
|
+
logger.error('Error confirming direct upload:', { error });
|
|
156
199
|
throw new TRPCError({
|
|
157
200
|
code: 'INTERNAL_SERVER_ERROR',
|
|
158
201
|
message: 'Failed to confirm upload',
|
|
@@ -166,16 +209,31 @@ export async function confirmDirectUpload(fileId, uploadSuccess, errorMessage) {
|
|
|
166
209
|
*/
|
|
167
210
|
export async function updateUploadProgress(fileId, progress) {
|
|
168
211
|
try {
|
|
212
|
+
// await prisma.file.update({
|
|
213
|
+
// where: { id: fileId },
|
|
214
|
+
// data: {
|
|
215
|
+
// uploadStatus: 'UPLOADING',
|
|
216
|
+
// uploadProgress: Math.min(100, Math.max(0, progress))
|
|
217
|
+
// }
|
|
218
|
+
// });
|
|
219
|
+
const current = await prisma.file.findUnique({ where: { id: fileId }, select: { uploadStatus: true } });
|
|
220
|
+
if (!current || ['COMPLETED', 'FAILED', 'CANCELLED'].includes(current.uploadStatus))
|
|
221
|
+
return;
|
|
222
|
+
const clamped = Math.min(100, Math.max(0, progress));
|
|
169
223
|
await prisma.file.update({
|
|
170
224
|
where: { id: fileId },
|
|
171
225
|
data: {
|
|
172
226
|
uploadStatus: 'UPLOADING',
|
|
173
|
-
uploadProgress:
|
|
227
|
+
uploadProgress: clamped
|
|
174
228
|
}
|
|
175
229
|
});
|
|
176
230
|
}
|
|
177
231
|
catch (error) {
|
|
178
|
-
|
|
232
|
+
logger.error('Error updating upload progress:', { error: error instanceof Error ? {
|
|
233
|
+
name: error.name,
|
|
234
|
+
message: error.message,
|
|
235
|
+
stack: error.stack,
|
|
236
|
+
} : error });
|
|
179
237
|
throw new TRPCError({
|
|
180
238
|
code: 'INTERNAL_SERVER_ERROR',
|
|
181
239
|
message: 'Failed to update upload progress',
|
|
@@ -191,13 +249,17 @@ export async function updateUploadProgress(fileId, progress) {
|
|
|
191
249
|
* @param submissionId Optional submission ID to associate files with
|
|
192
250
|
* @returns Array of direct upload file information
|
|
193
251
|
*/
|
|
194
|
-
export async function createDirectUploadFiles(files, userId, directory, assignmentId, submissionId) {
|
|
252
|
+
export async function createDirectUploadFiles(files, userId, directory, assignmentId, submissionId, announcementId) {
|
|
195
253
|
try {
|
|
196
|
-
const uploadPromises = files.map(file => createDirectUploadFile(file, userId, directory, assignmentId, submissionId));
|
|
254
|
+
const uploadPromises = files.map(file => createDirectUploadFile(file, userId, directory, assignmentId, submissionId, announcementId));
|
|
197
255
|
return await Promise.all(uploadPromises);
|
|
198
256
|
}
|
|
199
257
|
catch (error) {
|
|
200
|
-
|
|
258
|
+
logger.error('Error creating direct upload files:', { error: error instanceof Error ? {
|
|
259
|
+
name: error.name,
|
|
260
|
+
message: error.message,
|
|
261
|
+
stack: error.stack,
|
|
262
|
+
} : error });
|
|
201
263
|
throw new TRPCError({
|
|
202
264
|
code: 'INTERNAL_SERVER_ERROR',
|
|
203
265
|
message: 'Failed to create direct upload files',
|
|
@@ -10,4 +10,11 @@ export declare function getSignedUrl(filePath: string, action?: 'read' | 'write'
|
|
|
10
10
|
* @param filePath The path of the file to delete
|
|
11
11
|
*/
|
|
12
12
|
export declare function deleteFile(filePath: string): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Checks if an object exists in Google Cloud Storage
|
|
15
|
+
* @param bucketName The name of the bucket (unused, uses default bucket)
|
|
16
|
+
* @param objectPath The path of the object to check
|
|
17
|
+
* @returns Promise<boolean> True if the object exists, false otherwise
|
|
18
|
+
*/
|
|
19
|
+
export declare function objectExists(bucketName: string, objectPath: string): Promise<boolean>;
|
|
13
20
|
//# sourceMappingURL=googleCloudStorage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"googleCloudStorage.d.ts","sourceRoot":"","sources":["../../src/lib/googleCloudStorage.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,MAAM,wCAAwD,CAAC;AAQ5E;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,GAAG,OAAgB,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsB7H;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhE"}
|
|
1
|
+
{"version":3,"file":"googleCloudStorage.d.ts","sourceRoot":"","sources":["../../src/lib/googleCloudStorage.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,MAAM,wCAAwD,CAAC;AAQ5E;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,GAAG,OAAgB,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsB7H;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhE;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAW3F"}
|
|
@@ -57,3 +57,22 @@ export async function deleteFile(filePath) {
|
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Checks if an object exists in Google Cloud Storage
|
|
62
|
+
* @param bucketName The name of the bucket (unused, uses default bucket)
|
|
63
|
+
* @param objectPath The path of the object to check
|
|
64
|
+
* @returns Promise<boolean> True if the object exists, false otherwise
|
|
65
|
+
*/
|
|
66
|
+
export async function objectExists(bucketName, objectPath) {
|
|
67
|
+
try {
|
|
68
|
+
const [exists] = await bucket.file(objectPath).exists();
|
|
69
|
+
return exists;
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error('Error checking if object exists in Google Cloud Storage:', error);
|
|
73
|
+
throw new TRPCError({
|
|
74
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
75
|
+
message: 'Failed to check object existence',
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface notificationData {
|
|
2
|
+
title: string;
|
|
3
|
+
content: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function sendNotification(receiver: string, data: notificationData): Promise<{
|
|
6
|
+
id: string;
|
|
7
|
+
title: string;
|
|
8
|
+
content: string;
|
|
9
|
+
createdAt: Date;
|
|
10
|
+
senderId: string | null;
|
|
11
|
+
receiverId: string;
|
|
12
|
+
read: boolean;
|
|
13
|
+
}>;
|
|
14
|
+
export declare function sendNotifications(receiverIds: Array<string>, data: notificationData): Promise<import(".prisma/client").Prisma.BatchPayload>;
|
|
15
|
+
export declare function markRead(id: string, read?: boolean): Promise<{
|
|
16
|
+
id: string;
|
|
17
|
+
title: string;
|
|
18
|
+
content: string;
|
|
19
|
+
createdAt: Date;
|
|
20
|
+
senderId: string | null;
|
|
21
|
+
receiverId: string;
|
|
22
|
+
read: boolean;
|
|
23
|
+
}>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=notificationHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notificationHandler.d.ts","sourceRoot":"","sources":["../../src/lib/notificationHandler.ts"],"names":[],"mappings":"AAEA,UAAU,gBAAgB;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAA;CAClB;AAED,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB;;;;;;;;GAS9E;AAED,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,gBAAgB,yDASzF;AAED,wBAAsB,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,OAAc;;;;;;;;GAM9D"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { prisma } from "./prisma.js";
|
|
2
|
+
export async function sendNotification(receiver, data) {
|
|
3
|
+
const notification = await prisma.notification.create({
|
|
4
|
+
data: {
|
|
5
|
+
receiverId: receiver,
|
|
6
|
+
title: data.title,
|
|
7
|
+
content: data.content,
|
|
8
|
+
},
|
|
9
|
+
});
|
|
10
|
+
return notification;
|
|
11
|
+
}
|
|
12
|
+
export async function sendNotifications(receiverIds, data) {
|
|
13
|
+
const notifications = await prisma.notification.createMany({
|
|
14
|
+
data: receiverIds.map(receiverId => ({
|
|
15
|
+
receiverId: receiverId,
|
|
16
|
+
title: data.title,
|
|
17
|
+
content: data.content,
|
|
18
|
+
})),
|
|
19
|
+
});
|
|
20
|
+
return notifications;
|
|
21
|
+
}
|
|
22
|
+
export async function markRead(id, read = true) {
|
|
23
|
+
const notification = await prisma.notification.update({
|
|
24
|
+
where: { id },
|
|
25
|
+
data: { read: read },
|
|
26
|
+
});
|
|
27
|
+
return notification;
|
|
28
|
+
}
|