@studious-lms/server 1.2.33 → 1.2.35
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/routers/_app.d.ts +306 -188
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +2 -0
- package/dist/routers/announcement.d.ts +8 -4
- package/dist/routers/announcement.d.ts.map +1 -1
- package/dist/routers/announcement.js +9 -9
- package/dist/routers/comment.d.ts +124 -0
- package/dist/routers/comment.d.ts.map +1 -0
- package/dist/routers/comment.js +241 -0
- package/dist/routers/worksheet.d.ts +46 -113
- package/dist/routers/worksheet.d.ts.map +1 -1
- package/dist/routers/worksheet.js +90 -80
- package/package.json +1 -1
- package/prisma/schema.prisma +17 -9
- package/src/routers/_app.ts +2 -0
- package/src/routers/announcement.ts +12 -12
- package/src/routers/comment.ts +268 -0
- package/src/routers/worksheet.ts +92 -83
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export declare const worksheetRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
3
|
-
ctx: import("
|
|
3
|
+
ctx: import("../trpc.js").Context;
|
|
4
4
|
meta: object;
|
|
5
5
|
errorShape: {
|
|
6
6
|
data: {
|
|
7
7
|
zodError: z.typeToFlattenedError<any, string> | null;
|
|
8
|
-
prismaError: import("../utils/prismaErrorHandler").PrismaErrorInfo | null;
|
|
8
|
+
prismaError: import("../utils/prismaErrorHandler.js").PrismaErrorInfo | null;
|
|
9
9
|
code: import("@trpc/server").TRPC_ERROR_CODE_KEY;
|
|
10
10
|
httpStatus: number;
|
|
11
11
|
path?: string;
|
|
@@ -33,11 +33,12 @@ export declare const worksheetRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
33
33
|
questions: {
|
|
34
34
|
type: import(".prisma/client").$Enums.WorksheetQuestionType;
|
|
35
35
|
id: string;
|
|
36
|
-
options: import("@prisma/client/runtime/library").JsonValue | null;
|
|
36
|
+
options: import("@prisma/client/runtime/library.js").JsonValue | null;
|
|
37
37
|
createdAt: Date;
|
|
38
38
|
order: number | null;
|
|
39
|
-
markScheme: import("@prisma/client/runtime/library").JsonValue | null;
|
|
39
|
+
markScheme: import("@prisma/client/runtime/library.js").JsonValue | null;
|
|
40
40
|
updatedAt: Date;
|
|
41
|
+
points: number;
|
|
41
42
|
question: string;
|
|
42
43
|
worksheetId: string;
|
|
43
44
|
answer: string;
|
|
@@ -117,15 +118,17 @@ export declare const worksheetRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
117
118
|
answer: string;
|
|
118
119
|
options?: any;
|
|
119
120
|
markScheme?: any;
|
|
121
|
+
points?: number | undefined;
|
|
120
122
|
};
|
|
121
123
|
output: {
|
|
122
124
|
type: import(".prisma/client").$Enums.WorksheetQuestionType;
|
|
123
125
|
id: string;
|
|
124
|
-
options: import("@prisma/client/runtime/library").JsonValue | null;
|
|
126
|
+
options: import("@prisma/client/runtime/library.js").JsonValue | null;
|
|
125
127
|
createdAt: Date;
|
|
126
128
|
order: number | null;
|
|
127
|
-
markScheme: import("@prisma/client/runtime/library").JsonValue | null;
|
|
129
|
+
markScheme: import("@prisma/client/runtime/library.js").JsonValue | null;
|
|
128
130
|
updatedAt: Date;
|
|
131
|
+
points: number;
|
|
129
132
|
question: string;
|
|
130
133
|
worksheetId: string;
|
|
131
134
|
answer: string;
|
|
@@ -151,17 +154,19 @@ export declare const worksheetRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
151
154
|
type?: "ESSAY" | "MULTIPLE_CHOICE" | "TRUE_FALSE" | "SHORT_ANSWER" | "LONG_ANSWER" | "MATH_EXPRESSION" | undefined;
|
|
152
155
|
options?: any;
|
|
153
156
|
markScheme?: any;
|
|
157
|
+
points?: number | undefined;
|
|
154
158
|
question?: string | undefined;
|
|
155
159
|
answer?: string | undefined;
|
|
156
160
|
};
|
|
157
161
|
output: {
|
|
158
162
|
type: import(".prisma/client").$Enums.WorksheetQuestionType;
|
|
159
163
|
id: string;
|
|
160
|
-
options: import("@prisma/client/runtime/library").JsonValue | null;
|
|
164
|
+
options: import("@prisma/client/runtime/library.js").JsonValue | null;
|
|
161
165
|
createdAt: Date;
|
|
162
166
|
order: number | null;
|
|
163
|
-
markScheme: import("@prisma/client/runtime/library").JsonValue | null;
|
|
167
|
+
markScheme: import("@prisma/client/runtime/library.js").JsonValue | null;
|
|
164
168
|
updatedAt: Date;
|
|
169
|
+
points: number;
|
|
165
170
|
question: string;
|
|
166
171
|
worksheetId: string;
|
|
167
172
|
answer: string;
|
|
@@ -176,11 +181,12 @@ export declare const worksheetRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
176
181
|
output: {
|
|
177
182
|
type: import(".prisma/client").$Enums.WorksheetQuestionType;
|
|
178
183
|
id: string;
|
|
179
|
-
options: import("@prisma/client/runtime/library").JsonValue | null;
|
|
184
|
+
options: import("@prisma/client/runtime/library.js").JsonValue | null;
|
|
180
185
|
createdAt: Date;
|
|
181
186
|
order: number | null;
|
|
182
|
-
markScheme: import("@prisma/client/runtime/library").JsonValue | null;
|
|
187
|
+
markScheme: import("@prisma/client/runtime/library.js").JsonValue | null;
|
|
183
188
|
updatedAt: Date;
|
|
189
|
+
points: number;
|
|
184
190
|
question: string;
|
|
185
191
|
worksheetId: string;
|
|
186
192
|
answer: string;
|
|
@@ -198,11 +204,13 @@ export declare const worksheetRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
198
204
|
feedback: string | null;
|
|
199
205
|
studentId: string;
|
|
200
206
|
createdAt: Date;
|
|
201
|
-
updatedAt: Date;
|
|
207
|
+
updatedAt: Date | null;
|
|
208
|
+
points: number;
|
|
202
209
|
questionId: string;
|
|
203
210
|
response: string;
|
|
204
|
-
isCorrect: boolean;
|
|
205
211
|
studentWorksheetResponseId: string | null;
|
|
212
|
+
isCorrect: boolean;
|
|
213
|
+
markschemeState: import("@prisma/client/runtime/library.js").JsonValue | null;
|
|
206
214
|
}[];
|
|
207
215
|
} & {
|
|
208
216
|
id: string;
|
|
@@ -228,11 +236,13 @@ export declare const worksheetRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
228
236
|
feedback: string | null;
|
|
229
237
|
studentId: string;
|
|
230
238
|
createdAt: Date;
|
|
231
|
-
updatedAt: Date;
|
|
239
|
+
updatedAt: Date | null;
|
|
240
|
+
points: number;
|
|
232
241
|
questionId: string;
|
|
233
242
|
response: string;
|
|
234
|
-
isCorrect: boolean;
|
|
235
243
|
studentWorksheetResponseId: string | null;
|
|
244
|
+
isCorrect: boolean;
|
|
245
|
+
markschemeState: import("@prisma/client/runtime/library.js").JsonValue | null;
|
|
236
246
|
}[];
|
|
237
247
|
} & {
|
|
238
248
|
id: string;
|
|
@@ -256,54 +266,14 @@ export declare const worksheetRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
256
266
|
feedback: string | null;
|
|
257
267
|
studentId: string;
|
|
258
268
|
createdAt: Date;
|
|
259
|
-
updatedAt: Date;
|
|
269
|
+
updatedAt: Date | null;
|
|
270
|
+
points: number;
|
|
260
271
|
questionId: string;
|
|
261
272
|
response: string;
|
|
262
|
-
isCorrect: boolean;
|
|
263
273
|
studentWorksheetResponseId: string | null;
|
|
264
|
-
}[];
|
|
265
|
-
} & {
|
|
266
|
-
id: string;
|
|
267
|
-
submissionId: string | null;
|
|
268
|
-
studentId: string;
|
|
269
|
-
createdAt: Date;
|
|
270
|
-
updatedAt: Date;
|
|
271
|
-
submittedAt: Date | null;
|
|
272
|
-
submitted: boolean;
|
|
273
|
-
worksheetId: string;
|
|
274
|
-
};
|
|
275
|
-
meta: object;
|
|
276
|
-
}>;
|
|
277
|
-
getOrCreateWorksheetResponse: import("@trpc/server").TRPCMutationProcedure<{
|
|
278
|
-
input: {
|
|
279
|
-
studentId: string;
|
|
280
|
-
worksheetId: string;
|
|
281
|
-
};
|
|
282
|
-
output: {
|
|
283
|
-
responses: ({
|
|
284
|
-
question: {
|
|
285
|
-
type: import(".prisma/client").$Enums.WorksheetQuestionType;
|
|
286
|
-
id: string;
|
|
287
|
-
options: import("@prisma/client/runtime/library").JsonValue | null;
|
|
288
|
-
createdAt: Date;
|
|
289
|
-
order: number | null;
|
|
290
|
-
markScheme: import("@prisma/client/runtime/library").JsonValue | null;
|
|
291
|
-
updatedAt: Date;
|
|
292
|
-
question: string;
|
|
293
|
-
worksheetId: string;
|
|
294
|
-
answer: string;
|
|
295
|
-
};
|
|
296
|
-
} & {
|
|
297
|
-
id: string;
|
|
298
|
-
feedback: string | null;
|
|
299
|
-
studentId: string;
|
|
300
|
-
createdAt: Date;
|
|
301
|
-
updatedAt: Date;
|
|
302
|
-
questionId: string;
|
|
303
|
-
response: string;
|
|
304
274
|
isCorrect: boolean;
|
|
305
|
-
|
|
306
|
-
}
|
|
275
|
+
markschemeState: import("@prisma/client/runtime/library.js").JsonValue | null;
|
|
276
|
+
}[];
|
|
307
277
|
} & {
|
|
308
278
|
id: string;
|
|
309
279
|
submissionId: string | null;
|
|
@@ -316,71 +286,34 @@ export declare const worksheetRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
316
286
|
};
|
|
317
287
|
meta: object;
|
|
318
288
|
}>;
|
|
319
|
-
|
|
289
|
+
gradeAnswer: import("@trpc/server").TRPCMutationProcedure<{
|
|
320
290
|
input: {
|
|
321
|
-
|
|
291
|
+
questionId: string;
|
|
292
|
+
studentWorksheetResponseId: string;
|
|
293
|
+
isCorrect: boolean;
|
|
294
|
+
feedback?: string | undefined;
|
|
295
|
+
points?: number | undefined;
|
|
296
|
+
response?: string | undefined;
|
|
297
|
+
responseId?: string | undefined;
|
|
298
|
+
markschemeState?: any;
|
|
322
299
|
};
|
|
323
|
-
output:
|
|
324
|
-
student: {
|
|
325
|
-
id: string;
|
|
326
|
-
username: string;
|
|
327
|
-
profile: {
|
|
328
|
-
displayName: string | null;
|
|
329
|
-
profilePicture: string | null;
|
|
330
|
-
} | null;
|
|
331
|
-
};
|
|
332
|
-
responses: ({
|
|
333
|
-
question: {
|
|
334
|
-
type: import(".prisma/client").$Enums.WorksheetQuestionType;
|
|
335
|
-
id: string;
|
|
336
|
-
options: import("@prisma/client/runtime/library").JsonValue | null;
|
|
337
|
-
createdAt: Date;
|
|
338
|
-
order: number | null;
|
|
339
|
-
markScheme: import("@prisma/client/runtime/library").JsonValue | null;
|
|
340
|
-
updatedAt: Date;
|
|
341
|
-
question: string;
|
|
342
|
-
worksheetId: string;
|
|
343
|
-
answer: string;
|
|
344
|
-
};
|
|
345
|
-
} & {
|
|
346
|
-
id: string;
|
|
347
|
-
feedback: string | null;
|
|
348
|
-
studentId: string;
|
|
349
|
-
createdAt: Date;
|
|
350
|
-
updatedAt: Date;
|
|
351
|
-
questionId: string;
|
|
352
|
-
response: string;
|
|
353
|
-
isCorrect: boolean;
|
|
354
|
-
studentWorksheetResponseId: string | null;
|
|
355
|
-
})[];
|
|
356
|
-
} & {
|
|
357
|
-
id: string;
|
|
358
|
-
submissionId: string | null;
|
|
359
|
-
studentId: string;
|
|
360
|
-
createdAt: Date;
|
|
361
|
-
updatedAt: Date;
|
|
362
|
-
submittedAt: Date | null;
|
|
363
|
-
submitted: boolean;
|
|
364
|
-
worksheetId: string;
|
|
365
|
-
}) | null;
|
|
300
|
+
output: any;
|
|
366
301
|
meta: object;
|
|
367
302
|
}>;
|
|
368
|
-
|
|
303
|
+
addComment: import("@trpc/server").TRPCMutationProcedure<{
|
|
369
304
|
input: {
|
|
305
|
+
comment: string;
|
|
370
306
|
responseId: string;
|
|
371
|
-
isCorrect: boolean;
|
|
372
|
-
feedback?: string | undefined;
|
|
373
307
|
};
|
|
374
308
|
output: {
|
|
375
309
|
id: string;
|
|
376
|
-
|
|
377
|
-
studentId: string;
|
|
310
|
+
content: string;
|
|
378
311
|
createdAt: Date;
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
312
|
+
modifiedAt: Date | null;
|
|
313
|
+
announcementId: string | null;
|
|
314
|
+
parentCommentId: string | null;
|
|
315
|
+
authorId: string;
|
|
316
|
+
studentQuestionProgressId: string | null;
|
|
384
317
|
};
|
|
385
318
|
meta: object;
|
|
386
319
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worksheet.d.ts","sourceRoot":"","sources":["../../src/routers/worksheet.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,eAAe
|
|
1
|
+
{"version":3,"file":"worksheet.d.ts","sourceRoot":"","sources":["../../src/routers/worksheet.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBA8KA,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4UhC,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TRPCError } from "@trpc/server";
|
|
2
|
-
import { createTRPCRouter, protectedProcedure } from "
|
|
2
|
+
import { createTRPCRouter, protectedProcedure } from "../trpc.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
import { prisma } from "
|
|
4
|
+
import { prisma } from "../lib/prisma.js";
|
|
5
5
|
export const worksheetRouter = createTRPCRouter({
|
|
6
6
|
// Get a single worksheet with all questions
|
|
7
7
|
getWorksheet: protectedProcedure
|
|
@@ -15,6 +15,7 @@ export const worksheetRouter = createTRPCRouter({
|
|
|
15
15
|
include: {
|
|
16
16
|
questions: {
|
|
17
17
|
orderBy: { createdAt: 'asc' },
|
|
18
|
+
// select: { id: true, type: true, question: true, answer: true, points: true },
|
|
18
19
|
},
|
|
19
20
|
class: true,
|
|
20
21
|
},
|
|
@@ -95,12 +96,13 @@ export const worksheetRouter = createTRPCRouter({
|
|
|
95
96
|
worksheetId: z.string(),
|
|
96
97
|
question: z.string(),
|
|
97
98
|
answer: z.string(),
|
|
99
|
+
points: z.number().optional(),
|
|
98
100
|
options: z.any().optional(), // JSON field
|
|
99
101
|
markScheme: z.any().optional(), // JSON field
|
|
100
102
|
type: z.enum(['MULTIPLE_CHOICE', 'TRUE_FALSE', 'SHORT_ANSWER', 'LONG_ANSWER', 'MATH_EXPRESSION', 'ESSAY']),
|
|
101
103
|
}))
|
|
102
104
|
.mutation(async ({ ctx, input }) => {
|
|
103
|
-
const { worksheetId, question, answer, options, markScheme, type } = input;
|
|
105
|
+
const { worksheetId, question, points, answer, options, markScheme, type } = input;
|
|
104
106
|
const worksheet = await prisma.worksheet.findUnique({
|
|
105
107
|
where: { id: worksheetId },
|
|
106
108
|
});
|
|
@@ -111,6 +113,7 @@ export const worksheetRouter = createTRPCRouter({
|
|
|
111
113
|
data: {
|
|
112
114
|
worksheetId,
|
|
113
115
|
type,
|
|
116
|
+
points,
|
|
114
117
|
question,
|
|
115
118
|
answer,
|
|
116
119
|
options,
|
|
@@ -167,12 +170,13 @@ export const worksheetRouter = createTRPCRouter({
|
|
|
167
170
|
questionId: z.string(),
|
|
168
171
|
question: z.string().optional(),
|
|
169
172
|
answer: z.string().optional(),
|
|
173
|
+
points: z.number().optional(),
|
|
170
174
|
options: z.any().optional(), // JSON field
|
|
171
175
|
markScheme: z.any().optional(), // JSON field
|
|
172
176
|
type: z.enum(['MULTIPLE_CHOICE', 'TRUE_FALSE', 'SHORT_ANSWER', 'LONG_ANSWER', 'MATH_EXPRESSION', 'ESSAY']).optional(),
|
|
173
177
|
}))
|
|
174
178
|
.mutation(async ({ ctx, input }) => {
|
|
175
|
-
const { worksheetId, questionId, question, answer, options, markScheme, type } = input;
|
|
179
|
+
const { worksheetId, questionId, points, question, answer, options, markScheme, type } = input;
|
|
176
180
|
const worksheet = await prisma.worksheet.findUnique({
|
|
177
181
|
where: { id: worksheetId },
|
|
178
182
|
});
|
|
@@ -187,6 +191,7 @@ export const worksheetRouter = createTRPCRouter({
|
|
|
187
191
|
...(markScheme !== undefined && { markScheme }),
|
|
188
192
|
...(type !== undefined && { type }),
|
|
189
193
|
...(options !== undefined && { options }),
|
|
194
|
+
...(points !== undefined && { points }),
|
|
190
195
|
},
|
|
191
196
|
});
|
|
192
197
|
return updatedQuestion;
|
|
@@ -223,7 +228,7 @@ export const worksheetRouter = createTRPCRouter({
|
|
|
223
228
|
throw new TRPCError({ code: 'NOT_FOUND', message: 'Submission not found' });
|
|
224
229
|
}
|
|
225
230
|
// Find or create worksheet response for this submission
|
|
226
|
-
const
|
|
231
|
+
const worksheetResponse = await prisma.$transaction(async (tx) => {
|
|
227
232
|
// First check if a response exists
|
|
228
233
|
const existing = await tx.studentWorksheetResponse.findFirst({
|
|
229
234
|
where: {
|
|
@@ -250,7 +255,8 @@ export const worksheetRouter = createTRPCRouter({
|
|
|
250
255
|
});
|
|
251
256
|
return created;
|
|
252
257
|
});
|
|
253
|
-
|
|
258
|
+
console.log(worksheetResponse);
|
|
259
|
+
return worksheetResponse;
|
|
254
260
|
}),
|
|
255
261
|
answerQuestion: protectedProcedure
|
|
256
262
|
.input(z.object({
|
|
@@ -339,95 +345,99 @@ export const worksheetRouter = createTRPCRouter({
|
|
|
339
345
|
// You could integrate with an AI service to auto-grade certain question types
|
|
340
346
|
return submittedWorksheet;
|
|
341
347
|
}),
|
|
342
|
-
//
|
|
343
|
-
|
|
348
|
+
// Grade a student's answer
|
|
349
|
+
gradeAnswer: protectedProcedure
|
|
344
350
|
.input(z.object({
|
|
345
|
-
|
|
346
|
-
|
|
351
|
+
questionId: z.string(),
|
|
352
|
+
responseId: z.string().optional(), // StudentQuestionProgress ID (optional for upsert)
|
|
353
|
+
studentWorksheetResponseId: z.string(), // Required for linking to worksheet response
|
|
354
|
+
response: z.string().optional(), // The actual response text (needed if creating new)
|
|
355
|
+
isCorrect: z.boolean(),
|
|
356
|
+
feedback: z.string().optional(),
|
|
357
|
+
markschemeState: z.any().optional(),
|
|
358
|
+
points: z.number().optional(),
|
|
347
359
|
}))
|
|
348
360
|
.mutation(async ({ ctx, input }) => {
|
|
349
|
-
const {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
submitted: false, // Only get unsubmitted responses
|
|
356
|
-
},
|
|
357
|
-
include: {
|
|
358
|
-
responses: {
|
|
359
|
-
include: {
|
|
360
|
-
question: true,
|
|
361
|
-
},
|
|
362
|
-
},
|
|
363
|
-
},
|
|
364
|
-
});
|
|
365
|
-
// Create new response if none exists
|
|
366
|
-
if (!worksheetResponse) {
|
|
367
|
-
worksheetResponse = await prisma.studentWorksheetResponse.create({
|
|
361
|
+
const { responseId, questionId, studentWorksheetResponseId, response, isCorrect, feedback, markschemeState, points } = input;
|
|
362
|
+
let gradedResponse;
|
|
363
|
+
if (responseId) {
|
|
364
|
+
// Update existing progress by ID
|
|
365
|
+
gradedResponse = await prisma.studentQuestionProgress.update({
|
|
366
|
+
where: { id: responseId },
|
|
368
367
|
data: {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
responses: {
|
|
374
|
-
include: {
|
|
375
|
-
question: true,
|
|
376
|
-
},
|
|
377
|
-
},
|
|
368
|
+
isCorrect,
|
|
369
|
+
...(feedback !== undefined && { feedback }),
|
|
370
|
+
...(markschemeState !== undefined && { markschemeState }),
|
|
371
|
+
...(points !== undefined && { points }),
|
|
378
372
|
},
|
|
379
373
|
});
|
|
380
374
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
profilePicture: true,
|
|
401
|
-
},
|
|
402
|
-
},
|
|
403
|
-
},
|
|
375
|
+
else {
|
|
376
|
+
// Get the studentId from the worksheet response
|
|
377
|
+
const worksheetResponse = await prisma.studentWorksheetResponse.findUnique({
|
|
378
|
+
where: { id: studentWorksheetResponseId },
|
|
379
|
+
select: { studentId: true },
|
|
380
|
+
});
|
|
381
|
+
if (!worksheetResponse) {
|
|
382
|
+
throw new TRPCError({
|
|
383
|
+
code: 'NOT_FOUND',
|
|
384
|
+
message: 'Student worksheet response not found',
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
const { studentId } = worksheetResponse;
|
|
388
|
+
// Upsert - find or create the progress record
|
|
389
|
+
const existing = await prisma.studentQuestionProgress.findFirst({
|
|
390
|
+
where: {
|
|
391
|
+
studentId,
|
|
392
|
+
questionId,
|
|
393
|
+
studentWorksheetResponseId,
|
|
404
394
|
},
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
395
|
+
});
|
|
396
|
+
if (existing) {
|
|
397
|
+
// Update existing
|
|
398
|
+
gradedResponse = await prisma.studentQuestionProgress.update({
|
|
399
|
+
where: { id: existing.id },
|
|
400
|
+
data: {
|
|
401
|
+
isCorrect,
|
|
402
|
+
...(response !== undefined && { response }),
|
|
403
|
+
...(feedback !== undefined && { feedback }),
|
|
404
|
+
...(markschemeState !== undefined && { markschemeState }),
|
|
405
|
+
...(points !== undefined && { points }),
|
|
408
406
|
},
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
// Create new
|
|
411
|
+
gradedResponse = await prisma.studentQuestionProgress.create({
|
|
412
|
+
data: {
|
|
413
|
+
studentId,
|
|
414
|
+
questionId,
|
|
415
|
+
studentWorksheetResponseId,
|
|
416
|
+
response: response || '',
|
|
417
|
+
isCorrect,
|
|
418
|
+
...(feedback !== undefined && { feedback }),
|
|
419
|
+
...(markschemeState !== undefined && { markschemeState }),
|
|
420
|
+
...(points !== undefined && { points: points || 0 }),
|
|
421
|
+
},
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return gradedResponse;
|
|
414
426
|
}),
|
|
415
|
-
|
|
416
|
-
gradeAnswer: protectedProcedure
|
|
427
|
+
addComment: protectedProcedure
|
|
417
428
|
.input(z.object({
|
|
418
|
-
responseId: z.string(),
|
|
419
|
-
|
|
420
|
-
feedback: z.string().optional(),
|
|
429
|
+
responseId: z.string(),
|
|
430
|
+
comment: z.string(),
|
|
421
431
|
}))
|
|
422
432
|
.mutation(async ({ ctx, input }) => {
|
|
423
|
-
const { responseId,
|
|
424
|
-
const
|
|
425
|
-
where: { id: responseId },
|
|
433
|
+
const { responseId, comment } = input;
|
|
434
|
+
const newComment = await prisma.comment.create({
|
|
426
435
|
data: {
|
|
427
|
-
|
|
428
|
-
|
|
436
|
+
studentQuestionProgressId: responseId,
|
|
437
|
+
content: comment,
|
|
438
|
+
authorId: ctx.user.id,
|
|
429
439
|
},
|
|
430
440
|
});
|
|
431
|
-
return
|
|
441
|
+
return newComment;
|
|
432
442
|
}),
|
|
433
443
|
});
|
package/package.json
CHANGED
package/prisma/schema.prisma
CHANGED
|
@@ -108,7 +108,7 @@ model User {
|
|
|
108
108
|
sentMessages Message[] @relation("SentMessages")
|
|
109
109
|
mentions Mention[] @relation("UserMentions")
|
|
110
110
|
createdLabChats LabChat[] @relation("CreatedLabChats")
|
|
111
|
-
|
|
111
|
+
comments Comment[]
|
|
112
112
|
reactions Reaction[]
|
|
113
113
|
|
|
114
114
|
}
|
|
@@ -292,23 +292,25 @@ model Announcement {
|
|
|
292
292
|
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
293
293
|
classId String
|
|
294
294
|
attachments File[] @relation("AnnouncementAttachments")
|
|
295
|
-
comments
|
|
295
|
+
comments Comment[]
|
|
296
296
|
reactions Reaction[]
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
-
model
|
|
299
|
+
model Comment {
|
|
300
300
|
id String @id @default(uuid())
|
|
301
301
|
content String
|
|
302
302
|
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
|
|
303
303
|
authorId String
|
|
304
|
-
announcement Announcement @relation(fields: [announcementId], references: [id], onDelete: Cascade)
|
|
305
|
-
announcementId String
|
|
306
|
-
parentComment
|
|
304
|
+
announcement Announcement? @relation(fields: [announcementId], references: [id], onDelete: Cascade)
|
|
305
|
+
announcementId String?
|
|
306
|
+
parentComment Comment? @relation("CommentReplies", fields: [parentCommentId], references: [id], onDelete: Cascade)
|
|
307
307
|
parentCommentId String?
|
|
308
|
-
replies
|
|
308
|
+
replies Comment[] @relation("CommentReplies")
|
|
309
309
|
reactions Reaction[]
|
|
310
310
|
createdAt DateTime @default(now())
|
|
311
311
|
modifiedAt DateTime? @updatedAt
|
|
312
|
+
studentQuestionProgress StudentQuestionProgress? @relation("StudentQuestionProgressComments", fields: [studentQuestionProgressId], references: [id], onDelete: Cascade)
|
|
313
|
+
studentQuestionProgressId String?
|
|
312
314
|
}
|
|
313
315
|
|
|
314
316
|
model Reaction {
|
|
@@ -318,7 +320,7 @@ model Reaction {
|
|
|
318
320
|
userId String
|
|
319
321
|
announcement Announcement? @relation(fields: [announcementId], references: [id], onDelete: Cascade)
|
|
320
322
|
announcementId String?
|
|
321
|
-
comment
|
|
323
|
+
comment Comment? @relation(fields: [commentId], references: [id], onDelete: Cascade)
|
|
322
324
|
commentId String?
|
|
323
325
|
createdAt DateTime @default(now())
|
|
324
326
|
|
|
@@ -517,6 +519,7 @@ model WorksheetQuestion {
|
|
|
517
519
|
answer String
|
|
518
520
|
options Json? @default("{}")
|
|
519
521
|
markScheme Json? @default("{}")
|
|
522
|
+
points Int @default(0)
|
|
520
523
|
order Int? @default(0)
|
|
521
524
|
createdAt DateTime @default(now())
|
|
522
525
|
updatedAt DateTime @updatedAt
|
|
@@ -546,11 +549,16 @@ model StudentQuestionProgress {
|
|
|
546
549
|
question WorksheetQuestion @relation(fields: [questionId], references: [id], onDelete: Cascade)
|
|
547
550
|
response String
|
|
548
551
|
isCorrect Boolean @default(false)
|
|
552
|
+
markschemeState Json? @default("{}")
|
|
553
|
+
points Int @default(0)
|
|
554
|
+
comments Comment[] @relation("StudentQuestionProgressComments")
|
|
549
555
|
feedback String?
|
|
550
556
|
createdAt DateTime @default(now())
|
|
551
|
-
updatedAt DateTime @updatedAt
|
|
557
|
+
updatedAt DateTime? @updatedAt
|
|
552
558
|
studentWorksheetResponseId String?
|
|
553
559
|
studentWorksheetResponse StudentWorksheetResponse? @relation(fields: [studentWorksheetResponseId], references: [id], onDelete: Cascade)
|
|
560
|
+
|
|
561
|
+
@@index([studentId, questionId])
|
|
554
562
|
}
|
|
555
563
|
|
|
556
564
|
model SchoolDevelopementProgram {
|
package/src/routers/_app.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { messageRouter } from "./message.js";
|
|
|
18
18
|
import { labChatRouter } from "./labChat.js";
|
|
19
19
|
import { marketingRouter } from "./marketing.js";
|
|
20
20
|
import { worksheetRouter } from "./worksheet.js";
|
|
21
|
+
import { commentRouter } from "./comment.js";
|
|
21
22
|
|
|
22
23
|
export const appRouter = createTRPCRouter({
|
|
23
24
|
class: classRouter,
|
|
@@ -37,6 +38,7 @@ export const appRouter = createTRPCRouter({
|
|
|
37
38
|
labChat: labChatRouter,
|
|
38
39
|
marketing: marketingRouter,
|
|
39
40
|
worksheet: worksheetRouter,
|
|
41
|
+
comment: commentRouter,
|
|
40
42
|
});
|
|
41
43
|
|
|
42
44
|
// Export type router type definition
|