@studious-lms/server 1.1.14 → 1.1.15

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.
@@ -0,0 +1,537 @@
1
+ import { PDFDocument, PDFFont, RGB, StandardFonts, last, rgb } from 'pdf-lib'
2
+ import { writeFile } from 'fs'
3
+ import { DocumentBlock, FormatTypes, Fonts } from './jsonStyles'
4
+
5
+ export async function createPdf(blocks: DocumentBlock[]) {
6
+ console.log('createPdf: Starting PDF creation with', blocks.length, 'blocks');
7
+ try {
8
+ const pdfDoc = await PDFDocument.create()
9
+ console.log('createPdf: PDFDocument created successfully');
10
+ const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman)
11
+ const courierFont = await pdfDoc.embedFont(StandardFonts.Courier)
12
+ const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica)
13
+ const helveticaBoldFont = await pdfDoc.embedFont(StandardFonts.HelveticaBold)
14
+ const helveticaItalicFont = await pdfDoc.embedFont(StandardFonts.HelveticaOblique)
15
+ const helveticaBoldItalicFont = await pdfDoc.embedFont(StandardFonts.HelveticaBoldOblique)
16
+
17
+ const defaultFont = helveticaFont
18
+ const defaultParagraphSpacing = 10;
19
+ const defaultLineHeight = 1.3
20
+ const defaultFontSize = 12
21
+ const defaultIndentWidth = 14
22
+ const defaultPadding = 10
23
+
24
+ const headingColor = rgb(0.1, 0.1, 0.1)
25
+ const paragraphColor = rgb(0.15, 0.15, 0.15)
26
+
27
+ const FONTS: Record<number, PDFFont> = {
28
+ [Fonts.TIMES_ROMAN]: timesRomanFont,
29
+ [Fonts.COURIER]: courierFont,
30
+ [Fonts.HELVETICA]: helveticaFont,
31
+ [Fonts.HELVETICA_BOLD]: helveticaBoldFont,
32
+ [Fonts.HELVETICA_ITALIC]: helveticaItalicFont,
33
+ [Fonts.HELVETICA_BOLD_ITALIC]: helveticaBoldItalicFont,
34
+ }
35
+
36
+ const STYLE_PRESETS: Record<number,
37
+ { fontSize: number; lineHeight: number; paragraphSpacing?: number; font?: PDFFont; color?: RGB; background?: RGB }> =
38
+ {
39
+ [FormatTypes.HEADER_1]: { fontSize: 28, lineHeight: 1.35, font: helveticaBoldFont, color: headingColor },
40
+ [FormatTypes.HEADER_2]: { fontSize: 22, lineHeight: 1.35, font: helveticaBoldFont, color: headingColor },
41
+ [FormatTypes.HEADER_3]: { fontSize: 18, lineHeight: 1.35, font: helveticaBoldFont, color: headingColor },
42
+ [FormatTypes.HEADER_4]: { fontSize: 16, lineHeight: 1.3, font: helveticaBoldFont, color: headingColor },
43
+ [FormatTypes.HEADER_5]: { fontSize: 14, lineHeight: 1.3, font: helveticaBoldFont, color: headingColor },
44
+ [FormatTypes.HEADER_6]: { fontSize: 12, lineHeight: 1.3, font: helveticaBoldFont, color: headingColor },
45
+ [FormatTypes.QUOTE]: { fontSize: 14, lineHeight: 1.5, color: rgb(0.35, 0.35, 0.35) },
46
+ [FormatTypes.CODE_BLOCK]: { fontSize: 12, lineHeight: 1.6, font: courierFont, color: rgb(0.1, 0.1, 0.1), background: rgb(0.95, 0.95, 0.95) },
47
+ [FormatTypes.PARAGRAPH]: { fontSize: 12, lineHeight: 1.3, color: paragraphColor },
48
+ [FormatTypes.BULLET]: { fontSize: 12, lineHeight: 1.3, color: paragraphColor },
49
+ [FormatTypes.NUMBERED]: { fontSize: 12, lineHeight: 1.3, color: paragraphColor },
50
+ [FormatTypes.TABLE]: { fontSize: 12, lineHeight: 1.3, color: paragraphColor },
51
+ [FormatTypes.IMAGE]: { fontSize: 12, lineHeight: 1.3 },
52
+ }
53
+
54
+ const hexToRgb = (hex) => {
55
+ if (hex.length == 7) {
56
+ const r = parseInt(hex.slice(1, 3), 16) / 255.0;
57
+ const g = parseInt(hex.slice(3, 5), 16) / 255.0;
58
+ const b = parseInt(hex.slice(5, 7), 16) / 255.0;
59
+ return rgb(r, g, b);
60
+ } else if (hex.length == 4) {
61
+ const r = parseInt(hex.slice(1, 2), 16) / 15.0;
62
+ const g = parseInt(hex.slice(2, 3), 16) / 15.0;
63
+ const b = parseInt(hex.slice(3, 4), 16) / 15.0;
64
+ return rgb(r, g, b);
65
+ } else { return rgb(0.0, 0.0, 0.0) };
66
+ };
67
+
68
+ const colorParse = (color) => {
69
+ if (typeof color === 'string') {
70
+ return hexToRgb(color)
71
+ } else {
72
+ return color
73
+ }
74
+ }
75
+
76
+ // Function to replace Unicode characters that can't be encoded by WinAnsi
77
+ const sanitizeText = (text: string): string => {
78
+ return text
79
+ .replace(/→/g, '->') // Right arrow
80
+ .replace(/←/g, '<-') // Left arrow
81
+ .replace(/↑/g, '^') // Up arrow
82
+ .replace(/↓/g, 'v') // Down arrow
83
+ .replace(/•/g, '*') // Bullet point
84
+ .replace(/–/g, '-') // En dash
85
+ .replace(/—/g, '--') // Em dash
86
+ .replace(/'/g, "'") // Left single quote
87
+ .replace(/'/g, "'") // Right single quote
88
+ .replace(/"/g, '"') // Left double quote
89
+ .replace(/"/g, '"') // Right double quote
90
+ .replace(/…/g, '...') // Ellipsis
91
+ .replace(/°/g, ' degrees') // Degree symbol
92
+ .replace(/±/g, '+/-') // Plus-minus
93
+ .replace(/×/g, 'x') // Multiplication sign
94
+ .replace(/÷/g, '/') // Division sign
95
+ // Add more replacements as needed
96
+ }
97
+
98
+ let page = pdfDoc.addPage()
99
+ let { width, height } = page.getSize()
100
+ const { marginTop, marginBottom, marginLeft, marginRight } = { marginTop: 50, marginBottom: 50, marginLeft: 50, marginRight: 50 }
101
+
102
+ const maxTextWidth = () => width - marginLeft - marginRight
103
+
104
+ const wrapText = (text: string, font: any, fontSize: number, maxWidth: number): string[] => {
105
+ if (!text) return ['']
106
+ const words = text.split(/\s+/)
107
+ const lines: string[] = []
108
+ let current = ''
109
+
110
+ const measure = (t: string) => font.widthOfTextAtSize(t, fontSize)
111
+
112
+ const pushCurrent = () => {
113
+ if (current.length > 0) {
114
+ lines.push(current)
115
+ current = ''
116
+ }
117
+ }
118
+
119
+ for (let i = 0; i < words.length; i++) {
120
+ const word = words[i]
121
+ if (current.length === 0) {
122
+ // If a single word is too long, hard-break it
123
+ if (measure(word) > maxWidth) {
124
+ let chunk = ''
125
+ for (const ch of word) {
126
+ const test = chunk + ch
127
+ if (measure(test) > maxWidth && chunk.length > 0) {
128
+ lines.push(chunk)
129
+ chunk = ch
130
+ } else {
131
+ chunk = test
132
+ }
133
+ }
134
+ current = chunk
135
+ } else {
136
+ current = word
137
+ }
138
+ } else {
139
+ const test = current + ' ' + word
140
+ if (measure(test) <= maxWidth) {
141
+ current = test
142
+ } else {
143
+ pushCurrent()
144
+ // start new line with this word; hard-break if needed
145
+ if (measure(word) > maxWidth) {
146
+ let chunk = ''
147
+ for (const ch of word) {
148
+ const t2 = chunk + ch
149
+ if (measure(t2) > maxWidth && chunk.length > 0) {
150
+ lines.push(chunk)
151
+ chunk = ch
152
+ } else {
153
+ chunk = t2
154
+ }
155
+ }
156
+ current = chunk
157
+ } else {
158
+ current = word
159
+ }
160
+ }
161
+ }
162
+ }
163
+ pushCurrent()
164
+ return lines
165
+ }
166
+
167
+ let y = height - marginTop
168
+ let lastLineHeight = -1
169
+ console.log('createPdf: Starting to process', blocks.length, 'blocks');
170
+ for (let i = 0; i < blocks.length; i++) {
171
+ const block = blocks[i];
172
+ console.log(`createPdf: Processing block ${i + 1}/${blocks.length}, format: ${block.format}, content type: ${typeof block.content}`);
173
+ try {
174
+ const preset = STYLE_PRESETS[block.format] || { fontSize: defaultFontSize, lineHeight: defaultLineHeight }
175
+
176
+ const userLineHeight = (block as any).metadata?.lineHeight
177
+
178
+ const fontSize = (block as any).metadata?.fontSize || preset.fontSize
179
+ const lineHeight = (userLineHeight ? fontSize * userLineHeight : fontSize * preset.lineHeight)
180
+ const paragraphSpacing = (block as any).metadata?.paragraphSpacing || defaultParagraphSpacing
181
+ const indentWidth = (block as any).metadata?.indentWidth || defaultIndentWidth
182
+
183
+ const paddingX = (block as any).metadata?.paddingX || defaultPadding
184
+ const paddingY = (block as any).metadata?.paddingY || defaultPadding
185
+
186
+ const font = FONTS[(block as any).metadata?.font] || preset.font || defaultFont // Broken
187
+ const color = colorParse((block as any).metadata?.color || preset.color || rgb(0.0, 0.0, 0.0))
188
+ const background = colorParse((block as any).metadata?.background || preset.background || rgb(1.0, 1.0, 1.0))
189
+
190
+ if (lastLineHeight >= 0) {
191
+ y -= lineHeight - lastLineHeight
192
+ } else {
193
+ y -= fontSize
194
+ }
195
+
196
+ const ensureSpace = (needed: number) => {
197
+ if (y - needed < marginBottom) {
198
+ page = pdfDoc.addPage()
199
+ ; ({ width, height } = page.getSize())
200
+ y = height - marginTop - fontSize
201
+ lastLineHeight = -1
202
+ return true
203
+ } else { return false }
204
+ }
205
+
206
+ const drawParagraph = (text: string) => {
207
+ const sanitizedText = sanitizeText(text)
208
+ const lines = wrapText(sanitizedText, font, fontSize, maxTextWidth())
209
+ for (const line of lines) {
210
+ ensureSpace(lineHeight)
211
+ page.drawText(line, {
212
+ x: marginLeft,
213
+ y: y,
214
+ size: fontSize,
215
+ font: font,
216
+ color: color,
217
+ })
218
+ y -= lineHeight
219
+ }
220
+ }
221
+
222
+ const drawHeading = (text: string, align?: 'left' | 'center' | 'right') => {
223
+ const sanitizedText = sanitizeText(text)
224
+ const lines = wrapText(sanitizedText, font, fontSize, maxTextWidth())
225
+ for (const line of lines) {
226
+ ensureSpace(lineHeight)
227
+ let x = marginLeft
228
+ if (align === 'center') {
229
+ const tw = font.widthOfTextAtSize(line, fontSize)
230
+ x = marginLeft + (maxTextWidth() - tw) / 2
231
+ } else if (align === 'right') {
232
+ const tw = font.widthOfTextAtSize(line, fontSize)
233
+ x = marginLeft + maxTextWidth() - tw
234
+ }
235
+ page.drawText(line, {
236
+ x,
237
+ y: y,
238
+ size: fontSize,
239
+ font: font,
240
+ color: color,
241
+ })
242
+ y -= lineHeight
243
+ }
244
+ }
245
+
246
+ const drawBulletList = (items: string[]) => {
247
+ const bulletIndent = indentWidth
248
+ const gap = 8
249
+ const contentWidth = maxTextWidth() - (bulletIndent + gap)
250
+ for (const item of items) {
251
+ const sanitizedItem = sanitizeText(item)
252
+ const lines = wrapText(sanitizedItem, font, fontSize, contentWidth)
253
+ ensureSpace(lineHeight)
254
+ // Bullet glyph (use ASCII bullet instead of Unicode)
255
+ page.drawText('*', {
256
+ x: marginLeft + gap,
257
+ y: y,
258
+ size: fontSize,
259
+ font: font,
260
+ color: color,
261
+ })
262
+ // First line
263
+ page.drawText(lines[0], {
264
+ x: marginLeft + bulletIndent + gap,
265
+ y: y,
266
+ size: fontSize,
267
+ font: font,
268
+ color: color,
269
+ })
270
+ y -= lineHeight
271
+ // Continuation lines with hanging indent
272
+ for (let i = 1; i < lines.length; i++) {
273
+ ensureSpace(lineHeight)
274
+ page.drawText(lines[i], {
275
+ x: marginLeft + bulletIndent + gap,
276
+ y: y,
277
+ size: fontSize,
278
+ font: font,
279
+ color: color,
280
+ })
281
+ y -= lineHeight
282
+ }
283
+ }
284
+ }
285
+
286
+ const drawNumberedList = (items: string[]) => {
287
+ const numberIndent = indentWidth
288
+ const gap = 8
289
+ const contentWidth = maxTextWidth() - (numberIndent + gap)
290
+ let index = 1
291
+ for (const item of items) {
292
+ const numLabel = `${index}.`
293
+ const numWidth = font.widthOfTextAtSize(numLabel, fontSize)
294
+ const sanitizedItem = sanitizeText(item)
295
+ const lines = wrapText(sanitizedItem, font, fontSize, contentWidth)
296
+ ensureSpace(lineHeight)
297
+ page.drawText(numLabel, {
298
+ x: marginLeft + gap,
299
+ y: y,
300
+ size: fontSize,
301
+ font: font,
302
+ color: color,
303
+ })
304
+ page.drawText(lines[0], {
305
+ x: marginLeft + Math.max(numberIndent, numWidth + 6) + gap,
306
+ y: y,
307
+ size: fontSize,
308
+ font: font,
309
+ color: color,
310
+ })
311
+ y -= lineHeight
312
+ for (let i = 1; i < lines.length; i++) {
313
+ ensureSpace(lineHeight)
314
+ page.drawText(lines[i], {
315
+ x: marginLeft + Math.max(numberIndent, numWidth + 6) + gap,
316
+ y: y,
317
+ size: fontSize,
318
+ font: font,
319
+ color: color,
320
+ })
321
+ y -= lineHeight
322
+ }
323
+ index++
324
+ }
325
+ }
326
+
327
+ const drawQuote = (text: string) => {
328
+ const ruleWidth = 2
329
+ const ruleGap = 8
330
+ const contentX = marginLeft + ruleWidth + ruleGap
331
+ const contentWidth = maxTextWidth() - (ruleWidth + ruleGap)
332
+ const sanitizedText = sanitizeText(text)
333
+ const lines = wrapText(sanitizedText, font, fontSize, contentWidth)
334
+ const totalHeight = lines.length * lineHeight + fontSize
335
+ var remainingHeight = totalHeight
336
+ for (const line of lines) {
337
+ let pageAdded = ensureSpace(lineHeight)
338
+ if (pageAdded || remainingHeight == totalHeight) {
339
+ let blockHeight = Math.floor(Math.min(remainingHeight, y - marginBottom) / lineHeight) * lineHeight // Get remaining height on page
340
+ page.drawRectangle({
341
+ x: marginLeft,
342
+ y: y + lineHeight,
343
+ width: ruleWidth,
344
+ height: -blockHeight - lineHeight + fontSize,
345
+ color: color,
346
+ })
347
+ remainingHeight -= blockHeight + lineHeight - fontSize
348
+ }
349
+ page.drawText(line, {
350
+ x: contentX,
351
+ y: y,
352
+ size: fontSize,
353
+ font: font,
354
+ color: color,
355
+ })
356
+ y -= lineHeight
357
+ }
358
+ y -= lineHeight - fontSize
359
+ }
360
+
361
+ const drawCodeBlock = (textLines: string[]) => {
362
+ const codeFont = font
363
+
364
+ // Detect indentation patterns
365
+ const detectIndentation = (lines: string[]) => {
366
+ let tabCount = 0
367
+ let spaceCount = 0
368
+ let minSpaces = Infinity
369
+
370
+ for (const line of lines) {
371
+ if (line.trim().length === 0) continue // Skip empty lines
372
+
373
+ const leadingWhitespace = line.match(/^(\s*)/)?.[1] || ''
374
+ if (leadingWhitespace.includes('\t')) {
375
+ tabCount++
376
+ } else if (leadingWhitespace.length > 0) {
377
+ spaceCount++
378
+ minSpaces = Math.min(minSpaces, leadingWhitespace.length)
379
+ }
380
+ }
381
+
382
+ // Determine indentation strategy
383
+ if (tabCount > spaceCount) {
384
+ return { type: 'tab', width: indentWidth }
385
+ } else if (spaceCount > 0) {
386
+ // Use the most common space count, or default to 4
387
+ const commonSpaces = minSpaces === Infinity ? 4 : minSpaces
388
+ return { type: 'space', width: commonSpaces * (fontSize * 0.6) } // Approximate space width
389
+ } else {
390
+ return { type: 'space', width: fontSize * 2.4 } // Default 4 spaces
391
+ }
392
+ }
393
+
394
+ const indentInfo = detectIndentation(textLines)
395
+
396
+ // Process lines with indentation
397
+ const processedLines: { text: string; indentLevel: number; originalLine: string }[] = []
398
+
399
+ for (const line of textLines) {
400
+ const leadingWhitespace = line.match(/^(\s*)/)?.[1] || ''
401
+ let indentLevel = 0
402
+
403
+ if (indentInfo.type === 'tab') {
404
+ indentLevel = leadingWhitespace.split('\t').length - 1
405
+ } else {
406
+ // Count spaces, grouping by the detected space width
407
+ const spaceWidth = indentInfo.width / (fontSize * 0.6) // Convert back to space count
408
+ indentLevel = Math.floor(leadingWhitespace.length / spaceWidth)
409
+ }
410
+
411
+ processedLines.push({
412
+ text: line.trim(),
413
+ indentLevel,
414
+ originalLine: line
415
+ })
416
+ }
417
+
418
+ // Wrap each processed line separately to preserve line breaks and indentation
419
+ const wrappedLines: { text: string; indentLevel: number; isContinuation: boolean }[] = []
420
+ const contentW = maxTextWidth() - paddingX * 2
421
+
422
+ for (const processedLine of processedLines) {
423
+ if (processedLine.text.length === 0) {
424
+ // Empty line - preserve as empty line
425
+ wrappedLines.push({
426
+ text: '',
427
+ indentLevel: processedLine.indentLevel,
428
+ isContinuation: false
429
+ })
430
+ } else {
431
+ const parts = wrapText(processedLine.text, codeFont, fontSize, contentW)
432
+ for (let i = 0; i < parts.length; i++) {
433
+ wrappedLines.push({
434
+ text: parts[i],
435
+ indentLevel: processedLine.indentLevel,
436
+ isContinuation: i > 0
437
+ })
438
+ }
439
+ }
440
+ }
441
+
442
+ const totalHeight = wrappedLines.length * lineHeight + paddingY * 2
443
+ var remainingHeight = totalHeight
444
+ y -= paddingY
445
+
446
+ for (const wrappedLine of wrappedLines) {
447
+ let pageAdded = ensureSpace(lineHeight + paddingY)
448
+ if (pageAdded || remainingHeight == totalHeight) {
449
+ let blockHeight = Math.floor(Math.min(remainingHeight, y - marginBottom - paddingY) / lineHeight) * lineHeight
450
+ page.drawRectangle({
451
+ x: marginLeft,
452
+ y: y + fontSize,
453
+ width: maxTextWidth(),
454
+ height: -blockHeight - paddingY * 2,
455
+ color: background,
456
+ })
457
+ remainingHeight -= blockHeight
458
+ y -= paddingY
459
+ }
460
+
461
+ // Calculate indentation offset
462
+ const indentOffset = wrappedLine.indentLevel * indentInfo.width
463
+
464
+ page.drawText(wrappedLine.text, {
465
+ x: marginLeft + paddingX + indentOffset,
466
+ y: y,
467
+ size: fontSize,
468
+ font: codeFont,
469
+ color: color,
470
+ })
471
+ y -= lineHeight
472
+ }
473
+ y -= paddingY
474
+ }
475
+
476
+ // Render by block format
477
+ switch (block.format) {
478
+ case FormatTypes.HEADER_1:
479
+ case FormatTypes.HEADER_2:
480
+ case FormatTypes.HEADER_3:
481
+ case FormatTypes.HEADER_4:
482
+ case FormatTypes.HEADER_5:
483
+ case FormatTypes.HEADER_6: {
484
+ const align = (block as any).metadata?.align as 'left' | 'center' | 'right' | undefined
485
+ drawHeading(String(block.content), align)
486
+ break
487
+ }
488
+ case FormatTypes.BULLET: {
489
+ const items = Array.isArray(block.content) ? block.content.map(String) : [String(block.content)]
490
+ drawBulletList(items)
491
+ break
492
+ }
493
+ case FormatTypes.NUMBERED: {
494
+ const items = Array.isArray(block.content) ? block.content.map(String) : [String(block.content)]
495
+ drawNumberedList(items)
496
+ break
497
+ }
498
+ case FormatTypes.QUOTE: {
499
+ drawQuote(String(block.content))
500
+ break
501
+ }
502
+ case FormatTypes.CODE_BLOCK: {
503
+ const lines = Array.isArray(block.content) ? block.content.map(String) : String(block.content).split('\n')
504
+ drawCodeBlock(lines)
505
+ break
506
+ }
507
+ default: {
508
+ if (typeof block.content === 'string') {
509
+ drawParagraph(block.content)
510
+ } else {
511
+ for (const c of block.content) {
512
+ drawParagraph(String(c))
513
+ }
514
+ }
515
+ }
516
+ }
517
+ console.log(`createPdf: Successfully processed block ${i + 1}`);
518
+ y -= paragraphSpacing
519
+ lastLineHeight = lineHeight
520
+ } catch (blockError) {
521
+ console.error(`createPdf: Error processing block ${i + 1}:`, blockError);
522
+ throw blockError;
523
+ }
524
+ }
525
+
526
+ console.log('createPdf: About to save PDF document');
527
+ const pdfBytes = await pdfDoc.save()
528
+ console.log('createPdf: PDF saved successfully, bytes length:', pdfBytes.length);
529
+ // writeFile('output.pdf', pdfBytes, () => {
530
+ // console.log('PDF created successfully') // Still only saves file, no API yet
531
+ // })
532
+ return pdfBytes
533
+ } catch (error) {
534
+ console.error('createPdf: Error during PDF creation:', error);
535
+ throw error;
536
+ }
537
+ }
@@ -0,0 +1,36 @@
1
+ // -----------------------------
2
+ // Basic format enums and interfaces
3
+ // -----------------------------
4
+ export enum FormatTypes {
5
+ HEADER_1,
6
+ HEADER_2,
7
+ HEADER_3,
8
+ HEADER_4,
9
+ HEADER_5,
10
+ HEADER_6,
11
+ PARAGRAPH,
12
+ BULLET,
13
+ NUMBERED,
14
+ TABLE,
15
+ IMAGE,
16
+ CODE_BLOCK,
17
+ QUOTE,
18
+ }
19
+
20
+
21
+ export enum Fonts {
22
+ TIMES_ROMAN,
23
+ COURIER,
24
+ HELVETICA,
25
+ HELVETICA_BOLD,
26
+ HELVETICA_ITALIC,
27
+ HELVETICA_BOLD_ITALIC,
28
+ }
29
+
30
+
31
+ // Each content block in a document
32
+ export interface DocumentBlock {
33
+ format: FormatTypes;
34
+ content: string | string[]; // can be text, list items, etc. string as html / mrkdown
35
+ metadata?: Record<string, any>; // optional extra formatting info (e.g. alignment)
36
+ }
@@ -89,6 +89,15 @@ export const classRouter = createTRPCRouter({
89
89
  .query(async ({ ctx, input }) => {
90
90
  const { classId } = input;
91
91
 
92
+ const isTeacher = await prisma.class.findFirst({
93
+ where: {
94
+ id: classId,
95
+ teachers: {
96
+ some: { id: ctx.user?.id },
97
+ },
98
+ },
99
+ });
100
+
92
101
  const classData = await prisma.class.findUnique({
93
102
  where: {
94
103
  id: classId,
@@ -169,9 +178,11 @@ export const classRouter = createTRPCRouter({
169
178
  },
170
179
  },
171
180
  submissions: {
172
- // where: {
173
- // studentId: ctx.user?.id,
174
- // },
181
+ ...(!isTeacher && {
182
+ where: {
183
+ studentId: ctx.user?.id,
184
+ },
185
+ }),
175
186
  select: {
176
187
  studentId: true,
177
188
  id: true,