@goscribe/server 1.1.6 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +43 -0
- package/dist/routers/_app.d.ts +1 -1
- package/dist/routers/auth.js +9 -3
- package/dist/routers/workspace.d.ts +1 -1
- package/dist/routers/workspace.js +1 -1
- package/package.json +2 -1
- package/prisma/schema.prisma +46 -0
- package/src/lib/ai-session.ts +117 -63
- package/src/lib/constants.ts +14 -0
- package/src/lib/email.ts +46 -0
- package/src/lib/inference.ts +1 -1
- package/src/lib/logger.ts +26 -9
- package/src/lib/pusher.ts +4 -4
- package/src/lib/retry.ts +61 -0
- package/src/lib/storage.ts +2 -2
- package/src/lib/workspace-access.ts +13 -0
- package/src/routers/_app.ts +2 -0
- package/src/routers/annotations.ts +186 -0
- package/src/routers/auth.ts +98 -9
- package/src/routers/flashcards.ts +7 -13
- package/src/routers/podcast.ts +24 -28
- package/src/routers/studyguide.ts +68 -74
- package/src/routers/worksheets.ts +11 -14
- package/src/routers/workspace.ts +275 -272
- package/src/server.ts +4 -2
- package/src/services/flashcard-progress.service.ts +3 -6
- package/src/routers/meetingsummary.ts +0 -416
package/src/routers/podcast.ts
CHANGED
|
@@ -6,13 +6,9 @@ import inference from '../lib/inference.js';
|
|
|
6
6
|
import { uploadToSupabase, generateSignedUrl, deleteFromSupabase } from '../lib/storage.js';
|
|
7
7
|
import PusherService from '../lib/pusher.js';
|
|
8
8
|
import { aiSessionService } from '../lib/ai-session.js';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
PODCAST_EPISODE: 'PODCAST_EPISODE',
|
|
13
|
-
STUDY_GUIDE: 'STUDY_GUIDE',
|
|
14
|
-
FLASHCARD_SET: 'FLASHCARD_SET',
|
|
15
|
-
} as const;
|
|
9
|
+
import { ArtifactType } from '../lib/constants.js';
|
|
10
|
+
import { workspaceAccessFilter } from '../lib/workspace-access.js';
|
|
11
|
+
import { logger } from '../lib/logger.js';
|
|
16
12
|
|
|
17
13
|
// Podcast segment schema
|
|
18
14
|
const podcastSegmentSchema = z.object({
|
|
@@ -94,9 +90,9 @@ export const podcast = router({
|
|
|
94
90
|
orderBy: { updatedAt: 'desc' },
|
|
95
91
|
});
|
|
96
92
|
|
|
97
|
-
|
|
93
|
+
logger.debug(`Found ${artifacts.length} podcast artifacts`);
|
|
98
94
|
artifacts.forEach((artifact, i) => {
|
|
99
|
-
|
|
95
|
+
logger.debug(` Podcast ${i + 1}: "${artifact.title}" - ${artifact.podcastSegments.length} segments`);
|
|
100
96
|
});
|
|
101
97
|
|
|
102
98
|
// Transform to include segments with fresh signed URLs
|
|
@@ -126,7 +122,7 @@ export const podcast = router({
|
|
|
126
122
|
order: segment.order,
|
|
127
123
|
};
|
|
128
124
|
} catch (error) {
|
|
129
|
-
|
|
125
|
+
logger.error(`Failed to generate signed URL for segment ${segment.id}:`, error);
|
|
130
126
|
return {
|
|
131
127
|
id: segment.id,
|
|
132
128
|
title: segment.title,
|
|
@@ -154,10 +150,10 @@ export const podcast = router({
|
|
|
154
150
|
let metadata = null;
|
|
155
151
|
if (latestVersion) {
|
|
156
152
|
try {
|
|
157
|
-
|
|
153
|
+
logger.debug(latestVersion.data)
|
|
158
154
|
metadata = podcastMetadataSchema.parse(latestVersion.data);
|
|
159
155
|
} catch (error) {
|
|
160
|
-
|
|
156
|
+
logger.error('Failed to parse podcast metadata:', error);
|
|
161
157
|
}
|
|
162
158
|
}
|
|
163
159
|
|
|
@@ -191,7 +187,7 @@ export const podcast = router({
|
|
|
191
187
|
where: {
|
|
192
188
|
id: input.episodeId,
|
|
193
189
|
type: ArtifactType.PODCAST_EPISODE,
|
|
194
|
-
workspace:
|
|
190
|
+
workspace: workspaceAccessFilter(ctx.session.user.id)
|
|
195
191
|
},
|
|
196
192
|
include: {
|
|
197
193
|
versions: {
|
|
@@ -204,18 +200,18 @@ export const podcast = router({
|
|
|
204
200
|
},
|
|
205
201
|
});
|
|
206
202
|
|
|
207
|
-
|
|
203
|
+
logger.debug(episode)
|
|
208
204
|
|
|
209
205
|
if (!episode) throw new TRPCError({ code: 'NOT_FOUND' });
|
|
210
206
|
|
|
211
207
|
const latestVersion = episode.versions[0];
|
|
212
208
|
if (!latestVersion) throw new TRPCError({ code: 'NOT_FOUND', message: 'No version found' });
|
|
213
209
|
|
|
214
|
-
|
|
210
|
+
logger.debug(latestVersion)
|
|
215
211
|
try {
|
|
216
212
|
const metadata = podcastMetadataSchema.parse(latestVersion.data);
|
|
217
213
|
} catch (error) {
|
|
218
|
-
|
|
214
|
+
logger.error('Failed to parse podcast metadata:', error);
|
|
219
215
|
}
|
|
220
216
|
const metadata = podcastMetadataSchema.parse(latestVersion.data);
|
|
221
217
|
|
|
@@ -240,7 +236,7 @@ export const podcast = router({
|
|
|
240
236
|
order: segment.order,
|
|
241
237
|
};
|
|
242
238
|
} catch (error) {
|
|
243
|
-
|
|
239
|
+
logger.error(`Failed to generate signed URL for segment ${segment.id}:`, error);
|
|
244
240
|
return {
|
|
245
241
|
id: segment.id,
|
|
246
242
|
title: segment.title,
|
|
@@ -444,7 +440,7 @@ export const podcast = router({
|
|
|
444
440
|
|
|
445
441
|
} catch (audioError) {
|
|
446
442
|
const errorMessage = audioError instanceof Error ? audioError.message : 'Unknown error';
|
|
447
|
-
|
|
443
|
+
logger.error(`❌ Error generating audio for segment ${i + 1}:`, {
|
|
448
444
|
title: segment.title,
|
|
449
445
|
error: errorMessage,
|
|
450
446
|
stack: audioError instanceof Error ? audioError.stack : undefined,
|
|
@@ -471,7 +467,7 @@ export const podcast = router({
|
|
|
471
467
|
|
|
472
468
|
// Check if any segments were successfully generated
|
|
473
469
|
if (segments.length === 0) {
|
|
474
|
-
|
|
470
|
+
logger.error('No segments were successfully generated');
|
|
475
471
|
await PusherService.emitError(input.workspaceId,
|
|
476
472
|
`Failed to generate any segments. ${failedSegments.length} segment(s) failed.`,
|
|
477
473
|
'podcast'
|
|
@@ -539,7 +535,7 @@ export const podcast = router({
|
|
|
539
535
|
}
|
|
540
536
|
episodeSummary = JSON.parse(jsonMatch[0]);
|
|
541
537
|
} catch (parseError) {
|
|
542
|
-
|
|
538
|
+
logger.error('Failed to parse summary response:', summaryContent);
|
|
543
539
|
await PusherService.emitTaskComplete(input.workspaceId, 'podcast_summary_error', {
|
|
544
540
|
error: 'Failed to parse summary response'
|
|
545
541
|
});
|
|
@@ -633,7 +629,7 @@ export const podcast = router({
|
|
|
633
629
|
|
|
634
630
|
} catch (error) {
|
|
635
631
|
|
|
636
|
-
|
|
632
|
+
logger.error('Error generating podcast episode:', error);
|
|
637
633
|
|
|
638
634
|
await ctx.db.artifact.delete({
|
|
639
635
|
where: {
|
|
@@ -663,7 +659,7 @@ export const podcast = router({
|
|
|
663
659
|
where: {
|
|
664
660
|
id: input.episodeId,
|
|
665
661
|
type: ArtifactType.PODCAST_EPISODE,
|
|
666
|
-
workspace:
|
|
662
|
+
workspace: workspaceAccessFilter(ctx.session.user.id)
|
|
667
663
|
},
|
|
668
664
|
include: {
|
|
669
665
|
versions: {
|
|
@@ -714,7 +710,7 @@ export const podcast = router({
|
|
|
714
710
|
where: {
|
|
715
711
|
id: input.episodeId,
|
|
716
712
|
type: ArtifactType.PODCAST_EPISODE,
|
|
717
|
-
workspace:
|
|
713
|
+
workspace: workspaceAccessFilter(ctx.session.user.id)
|
|
718
714
|
},
|
|
719
715
|
include: {
|
|
720
716
|
versions: {
|
|
@@ -766,7 +762,7 @@ export const podcast = router({
|
|
|
766
762
|
where: {
|
|
767
763
|
id: input.episodeId,
|
|
768
764
|
type: ArtifactType.PODCAST_EPISODE,
|
|
769
|
-
workspace:
|
|
765
|
+
workspace: workspaceAccessFilter(ctx.session.user.id)
|
|
770
766
|
},
|
|
771
767
|
include: {
|
|
772
768
|
versions: {
|
|
@@ -796,7 +792,7 @@ export const podcast = router({
|
|
|
796
792
|
try {
|
|
797
793
|
await deleteFromSupabase(segment.objectKey);
|
|
798
794
|
} catch (error) {
|
|
799
|
-
|
|
795
|
+
logger.error(`Failed to delete audio file ${segment.objectKey}:`, error);
|
|
800
796
|
}
|
|
801
797
|
}
|
|
802
798
|
}
|
|
@@ -825,7 +821,7 @@ export const podcast = router({
|
|
|
825
821
|
return true;
|
|
826
822
|
|
|
827
823
|
} catch (error) {
|
|
828
|
-
|
|
824
|
+
logger.error('Error deleting episode:', error);
|
|
829
825
|
await PusherService.emitError(episode.workspaceId, `Failed to delete episode: ${error instanceof Error ? error.message : 'Unknown error'}`, 'podcast');
|
|
830
826
|
throw new TRPCError({
|
|
831
827
|
code: 'INTERNAL_SERVER_ERROR',
|
|
@@ -842,7 +838,7 @@ export const podcast = router({
|
|
|
842
838
|
where: {
|
|
843
839
|
id: input.segmentId,
|
|
844
840
|
artifact: {
|
|
845
|
-
workspace:
|
|
841
|
+
workspace: workspaceAccessFilter(ctx.session.user.id)
|
|
846
842
|
}
|
|
847
843
|
},
|
|
848
844
|
include: {
|
|
@@ -858,7 +854,7 @@ export const podcast = router({
|
|
|
858
854
|
try {
|
|
859
855
|
audioUrl = await generateSignedUrl(segment.objectKey, 24); // 24 hours
|
|
860
856
|
} catch (error) {
|
|
861
|
-
|
|
857
|
+
logger.error(`Failed to generate signed URL for segment ${segment.id}:`, error);
|
|
862
858
|
}
|
|
863
859
|
}
|
|
864
860
|
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { TRPCError } from '@trpc/server';
|
|
3
3
|
import { router, authedProcedure } from '../trpc.js';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
// Mirror Prisma enum to avoid direct type import
|
|
7
|
-
const ArtifactType = {
|
|
8
|
-
STUDY_GUIDE: 'STUDY_GUIDE',
|
|
9
|
-
} as const;
|
|
4
|
+
import { ArtifactType } from '../lib/constants.js';
|
|
5
|
+
import { workspaceAccessFilter } from '../lib/workspace-access.js';
|
|
10
6
|
|
|
11
7
|
const initializeEditorJsEmptyBlock = () => ({
|
|
12
8
|
time: Date.now(),
|
|
@@ -14,7 +10,7 @@ const initializeEditorJsEmptyBlock = () => ({
|
|
|
14
10
|
{
|
|
15
11
|
id: 'initial',
|
|
16
12
|
type: 'paragraph',
|
|
17
|
-
data: { text: '
|
|
13
|
+
data: { text: 'Upload some files to begin creating your revision workspace...' },
|
|
18
14
|
},
|
|
19
15
|
],
|
|
20
16
|
version: '2.27.0',
|
|
@@ -34,14 +30,13 @@ export const studyguide = router({
|
|
|
34
30
|
where: {
|
|
35
31
|
workspaceId: input.workspaceId!,
|
|
36
32
|
type: ArtifactType.STUDY_GUIDE,
|
|
37
|
-
workspace:
|
|
33
|
+
workspace: workspaceAccessFilter(ctx.session.user.id),
|
|
38
34
|
},
|
|
39
35
|
include: {
|
|
40
36
|
versions: { orderBy: { version: 'desc' }, take: 1 },
|
|
41
37
|
},
|
|
42
38
|
});
|
|
43
39
|
|
|
44
|
-
console.log('artifact', artifact);
|
|
45
40
|
if (!artifact) {
|
|
46
41
|
artifact = await ctx.db.artifact.create({
|
|
47
42
|
data: {
|
|
@@ -67,78 +62,77 @@ export const studyguide = router({
|
|
|
67
62
|
}),
|
|
68
63
|
|
|
69
64
|
// Edit study guide content by creating a new version, or create if doesn't exist
|
|
70
|
-
edit: authedProcedure
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
65
|
+
// edit: authedProcedure
|
|
66
|
+
// .input(
|
|
67
|
+
// z.object({
|
|
68
|
+
// workspaceId: z.string(),
|
|
69
|
+
// studyGuideId: z.string().optional(),
|
|
70
|
+
// content: z.string().min(1),
|
|
71
|
+
// data: z.record(z.string(), z.unknown()).optional(),
|
|
72
|
+
// title: z.string().min(1).optional(),
|
|
73
|
+
// })
|
|
74
|
+
// )
|
|
75
|
+
// .mutation(async ({ ctx, input }) => {
|
|
76
|
+
// let artifact;
|
|
82
77
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
78
|
+
// if (input.studyGuideId) {
|
|
79
|
+
// // Try to find existing study guide
|
|
80
|
+
// artifact = await ctx.db.artifact.findFirst({
|
|
81
|
+
// where: {
|
|
82
|
+
// id: input.studyGuideId,
|
|
83
|
+
// type: ArtifactType.STUDY_GUIDE,
|
|
84
|
+
// workspace: workspaceAccessFilter(ctx.session.user.id),
|
|
85
|
+
// },
|
|
86
|
+
// });
|
|
87
|
+
// } else {
|
|
88
|
+
// // Find by workspace if no specific studyGuideId provided
|
|
89
|
+
// artifact = await ctx.db.artifact.findFirst({
|
|
90
|
+
// where: {
|
|
91
|
+
// workspaceId: input.workspaceId,
|
|
92
|
+
// type: ArtifactType.STUDY_GUIDE,
|
|
93
|
+
// workspace: workspaceAccessFilter(ctx.session.user.id),
|
|
94
|
+
// },
|
|
95
|
+
// });
|
|
96
|
+
// }
|
|
102
97
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
98
|
+
// // If no study guide found, create a new one
|
|
99
|
+
// if (!artifact) {
|
|
100
|
+
// artifact = await ctx.db.artifact.create({
|
|
101
|
+
// data: {
|
|
102
|
+
// workspaceId: input.workspaceId,
|
|
103
|
+
// type: ArtifactType.STUDY_GUIDE,
|
|
104
|
+
// title: 'Study Guide',
|
|
105
|
+
// createdById: ctx.session.user.id,
|
|
106
|
+
// },
|
|
107
|
+
// });
|
|
108
|
+
// }
|
|
114
109
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
110
|
+
// const last = await ctx.db.artifactVersion.findFirst({
|
|
111
|
+
// where: { artifactId: artifact.id },
|
|
112
|
+
// orderBy: { version: 'desc' },
|
|
113
|
+
// });
|
|
119
114
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
115
|
+
// if (input.title && input.title !== artifact.title) {
|
|
116
|
+
// await ctx.db.artifact.update({
|
|
117
|
+
// where: { id: artifact.id },
|
|
118
|
+
// data: { title: input.title },
|
|
119
|
+
// });
|
|
120
|
+
// }
|
|
127
121
|
|
|
128
|
-
|
|
122
|
+
// const nextVersion = (last?.version ?? 0) + 1;
|
|
129
123
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
124
|
+
// const version = await ctx.db.artifactVersion.create({
|
|
125
|
+
// data: {
|
|
126
|
+
// artifactId: artifact.id,
|
|
127
|
+
// content: input.content,
|
|
128
|
+
// data: input.data ?? undefined,
|
|
129
|
+
// version: nextVersion,
|
|
130
|
+
// createdById: ctx.session.user.id,
|
|
131
|
+
// },
|
|
132
|
+
// });
|
|
139
133
|
|
|
140
|
-
|
|
141
|
-
|
|
134
|
+
// return { artifactId: artifact.id, version };
|
|
135
|
+
// }),
|
|
142
136
|
});
|
|
143
137
|
|
|
144
138
|
|
|
@@ -4,11 +4,8 @@ import { router, authedProcedure } from '../trpc.js';
|
|
|
4
4
|
import { aiSessionService } from '../lib/ai-session.js';
|
|
5
5
|
import PusherService from '../lib/pusher.js';
|
|
6
6
|
import { logger } from '../lib/logger.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const ArtifactType = {
|
|
10
|
-
WORKSHEET: 'WORKSHEET',
|
|
11
|
-
} as const;
|
|
7
|
+
import { ArtifactType } from '../lib/constants.js';
|
|
8
|
+
import { workspaceAccessFilter } from '../lib/workspace-access.js';
|
|
12
9
|
|
|
13
10
|
const Difficulty = {
|
|
14
11
|
EASY: 'EASY',
|
|
@@ -130,7 +127,7 @@ export const worksheets = router({
|
|
|
130
127
|
where: {
|
|
131
128
|
id: input.worksheetId,
|
|
132
129
|
type: ArtifactType.WORKSHEET,
|
|
133
|
-
workspace:
|
|
130
|
+
workspace: workspaceAccessFilter(ctx.session.user.id),
|
|
134
131
|
},
|
|
135
132
|
include: { questions: true },
|
|
136
133
|
orderBy: { updatedAt: 'desc' },
|
|
@@ -181,7 +178,7 @@ export const worksheets = router({
|
|
|
181
178
|
}))
|
|
182
179
|
.mutation(async ({ ctx, input }) => {
|
|
183
180
|
const worksheet = await ctx.db.artifact.findFirst({
|
|
184
|
-
where: { id: input.worksheetId, type: ArtifactType.WORKSHEET, workspace:
|
|
181
|
+
where: { id: input.worksheetId, type: ArtifactType.WORKSHEET, workspace: workspaceAccessFilter(ctx.session.user.id) },
|
|
185
182
|
});
|
|
186
183
|
if (!worksheet) throw new TRPCError({ code: 'NOT_FOUND' });
|
|
187
184
|
return ctx.db.worksheetQuestion.create({
|
|
@@ -210,7 +207,7 @@ export const worksheets = router({
|
|
|
210
207
|
}))
|
|
211
208
|
.mutation(async ({ ctx, input }) => {
|
|
212
209
|
const q = await ctx.db.worksheetQuestion.findFirst({
|
|
213
|
-
where: { id: input.worksheetQuestionId, artifact: { type: ArtifactType.WORKSHEET, workspace:
|
|
210
|
+
where: { id: input.worksheetQuestionId, artifact: { type: ArtifactType.WORKSHEET, workspace: workspaceAccessFilter(ctx.session.user.id) } },
|
|
214
211
|
});
|
|
215
212
|
if (!q) throw new TRPCError({ code: 'NOT_FOUND' });
|
|
216
213
|
return ctx.db.worksheetQuestion.update({
|
|
@@ -231,7 +228,7 @@ export const worksheets = router({
|
|
|
231
228
|
.input(z.object({ worksheetQuestionId: z.string() }))
|
|
232
229
|
.mutation(async ({ ctx, input }) => {
|
|
233
230
|
const q = await ctx.db.worksheetQuestion.findFirst({
|
|
234
|
-
where: { id: input.worksheetQuestionId, artifact: { workspace:
|
|
231
|
+
where: { id: input.worksheetQuestionId, artifact: { workspace: workspaceAccessFilter(ctx.session.user.id) } },
|
|
235
232
|
});
|
|
236
233
|
if (!q) throw new TRPCError({ code: 'NOT_FOUND' });
|
|
237
234
|
await ctx.db.worksheetQuestion.delete({ where: { id: input.worksheetQuestionId } });
|
|
@@ -253,7 +250,7 @@ export const worksheets = router({
|
|
|
253
250
|
id: input.problemId,
|
|
254
251
|
artifact: {
|
|
255
252
|
type: ArtifactType.WORKSHEET,
|
|
256
|
-
workspace:
|
|
253
|
+
workspace: workspaceAccessFilter(ctx.session.user.id),
|
|
257
254
|
},
|
|
258
255
|
},
|
|
259
256
|
});
|
|
@@ -297,7 +294,7 @@ export const worksheets = router({
|
|
|
297
294
|
where: {
|
|
298
295
|
id: input.worksheetId,
|
|
299
296
|
type: ArtifactType.WORKSHEET,
|
|
300
|
-
workspace:
|
|
297
|
+
workspace: workspaceAccessFilter(ctx.session.user.id),
|
|
301
298
|
},
|
|
302
299
|
});
|
|
303
300
|
if (!worksheet) throw new TRPCError({ code: 'NOT_FOUND' });
|
|
@@ -342,7 +339,7 @@ export const worksheets = router({
|
|
|
342
339
|
where: {
|
|
343
340
|
id,
|
|
344
341
|
type: ArtifactType.WORKSHEET,
|
|
345
|
-
workspace:
|
|
342
|
+
workspace: workspaceAccessFilter(ctx.session.user.id),
|
|
346
343
|
},
|
|
347
344
|
});
|
|
348
345
|
if (!existingWorksheet) throw new TRPCError({ code: 'NOT_FOUND' });
|
|
@@ -388,7 +385,7 @@ export const worksheets = router({
|
|
|
388
385
|
.input(z.object({ id: z.string() }))
|
|
389
386
|
.mutation(async ({ ctx, input }) => {
|
|
390
387
|
const deleted = await ctx.db.artifact.deleteMany({
|
|
391
|
-
where: { id: input.id, type: ArtifactType.WORKSHEET, workspace:
|
|
388
|
+
where: { id: input.id, type: ArtifactType.WORKSHEET, workspace: workspaceAccessFilter(ctx.session.user.id) },
|
|
392
389
|
});
|
|
393
390
|
if (deleted.count === 0) throw new TRPCError({ code: 'NOT_FOUND' });
|
|
394
391
|
return true;
|
|
@@ -484,7 +481,7 @@ export const worksheets = router({
|
|
|
484
481
|
answer: z.string().min(1),
|
|
485
482
|
}))
|
|
486
483
|
.mutation(async ({ ctx, input }) => {
|
|
487
|
-
const worksheet = await ctx.db.artifact.findFirst({ where: { id: input.worksheetId, type: ArtifactType.WORKSHEET, workspace:
|
|
484
|
+
const worksheet = await ctx.db.artifact.findFirst({ where: { id: input.worksheetId, type: ArtifactType.WORKSHEET, workspace: workspaceAccessFilter(ctx.session.user.id) }, include: { workspace: true } });
|
|
488
485
|
if (!worksheet) throw new TRPCError({ code: 'NOT_FOUND' });
|
|
489
486
|
const question = await ctx.db.worksheetQuestion.findFirst({ where: { id: input.questionId, artifactId: input.worksheetId } });
|
|
490
487
|
if (!question) throw new TRPCError({ code: 'NOT_FOUND' });
|