@studious-lms/server 1.4.5 → 1.4.7
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/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/access.d.ts +112 -0
- package/dist/models/access.d.ts.map +1 -0
- package/dist/models/access.js +49 -0
- package/dist/models/access.js.map +1 -0
- package/dist/models/announcement.d.ts +17 -2
- package/dist/models/announcement.d.ts.map +1 -1
- package/dist/models/announcement.js +21 -4
- package/dist/models/announcement.js.map +1 -1
- package/dist/models/assignment.d.ts +37 -37
- package/dist/models/assignment.d.ts.map +1 -1
- package/dist/models/assignment.js +15 -15
- package/dist/models/assignment.js.map +1 -1
- package/dist/models/attendance.d.ts +1 -1
- package/dist/models/attendance.d.ts.map +1 -1
- package/dist/models/attendance.js +6 -5
- package/dist/models/attendance.js.map +1 -1
- package/dist/models/auth.d.ts +5 -5
- package/dist/models/auth.d.ts.map +1 -1
- package/dist/models/auth.js +7 -11
- package/dist/models/auth.js.map +1 -1
- package/dist/models/class.d.ts +26 -26
- package/dist/models/class.d.ts.map +1 -1
- package/dist/models/class.js +7 -11
- package/dist/models/class.js.map +1 -1
- package/dist/models/comment.d.ts +233 -6
- package/dist/models/comment.d.ts.map +1 -1
- package/dist/models/comment.js +133 -3
- package/dist/models/comment.js.map +1 -1
- package/dist/models/conversation.d.ts +7 -7
- package/dist/models/event.d.ts +52 -3
- package/dist/models/event.d.ts.map +1 -1
- package/dist/models/event.js +56 -6
- package/dist/models/event.js.map +1 -1
- package/dist/models/file.d.ts +178 -103
- package/dist/models/file.d.ts.map +1 -1
- package/dist/models/file.js +54 -14
- package/dist/models/file.js.map +1 -1
- package/dist/models/folder.d.ts +22 -22
- package/dist/models/folder.d.ts.map +1 -1
- package/dist/models/folder.js +5 -4
- package/dist/models/folder.js.map +1 -1
- package/dist/models/labChat.d.ts +20 -20
- package/dist/models/labChat.d.ts.map +1 -1
- package/dist/models/labChat.js +8 -10
- package/dist/models/labChat.js.map +1 -1
- package/dist/models/marketing.d.ts +1 -1
- package/dist/models/message.d.ts +6 -6
- package/dist/models/newtonChat.d.ts +5 -5
- package/dist/models/school.d.ts +361 -0
- package/dist/models/school.d.ts.map +1 -0
- package/dist/models/school.js +314 -0
- package/dist/models/school.js.map +1 -0
- package/dist/models/section.d.ts +1 -1
- package/dist/models/section.d.ts.map +1 -1
- package/dist/models/section.js +5 -4
- package/dist/models/section.js.map +1 -1
- package/dist/models/user.d.ts +4 -4
- package/dist/models/worksheet.d.ts +67 -65
- package/dist/models/worksheet.d.ts.map +1 -1
- package/dist/models/worksheet.js +6 -14
- package/dist/models/worksheet.js.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/pipelines/gradeWorksheet.d.ts +2 -2
- package/dist/pipelines/pdfToWorksheet.d.ts +1 -1
- package/dist/routers/_app.d.ts +2462 -1104
- 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 +13 -5
- package/dist/routers/announcement.d.ts.map +1 -1
- package/dist/routers/announcement.js +25 -5
- package/dist/routers/announcement.js.map +1 -1
- package/dist/routers/assignment.d.ts +266 -36
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/assignment.js +221 -3
- package/dist/routers/assignment.js.map +1 -1
- package/dist/routers/class.d.ts +21 -20
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/class.js +3 -2
- package/dist/routers/class.js.map +1 -1
- package/dist/routers/comment.d.ts +40 -3
- 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 +6 -6
- package/dist/routers/event.d.ts +21 -2
- package/dist/routers/event.d.ts.map +1 -1
- package/dist/routers/file.d.ts +2 -2
- package/dist/routers/folder.d.ts +24 -24
- package/dist/routers/labChat.d.ts +7 -7
- package/dist/routers/school.d.ts +384 -0
- package/dist/routers/school.d.ts.map +1 -0
- package/dist/routers/school.js +79 -0
- package/dist/routers/school.js.map +1 -0
- package/dist/routers/search.d.ts +1 -1
- package/dist/routers/worksheet.d.ts +23 -21
- package/dist/routers/worksheet.d.ts.map +1 -1
- package/dist/services/announcement.d.ts.map +1 -1
- package/dist/services/announcement.js +10 -6
- package/dist/services/announcement.js.map +1 -1
- package/dist/services/assignment.d.ts +36 -36
- package/dist/services/class.d.ts +20 -19
- package/dist/services/class.d.ts.map +1 -1
- package/dist/services/class.js +22 -3
- package/dist/services/class.js.map +1 -1
- package/dist/services/comment.d.ts +31 -5
- package/dist/services/comment.d.ts.map +1 -1
- package/dist/services/comment.js +102 -19
- package/dist/services/comment.js.map +1 -1
- package/dist/services/conversation.d.ts +6 -6
- package/dist/services/event.d.ts +21 -2
- package/dist/services/event.d.ts.map +1 -1
- package/dist/services/event.js +11 -7
- package/dist/services/event.js.map +1 -1
- package/dist/services/file.d.ts +2 -2
- package/dist/services/file.d.ts.map +1 -1
- package/dist/services/file.js +17 -8
- package/dist/services/file.js.map +1 -1
- package/dist/services/folder.d.ts +24 -24
- package/dist/services/labChat.d.ts +7 -7
- package/dist/services/school.d.ts +299 -0
- package/dist/services/school.d.ts.map +1 -0
- package/dist/services/school.js +225 -0
- package/dist/services/school.js.map +1 -0
- package/dist/services/worksheet.d.ts +23 -21
- package/dist/services/worksheet.d.ts.map +1 -1
- package/package.json +1 -1
- package/prisma/migrations/20260502230500_assignment_submission_comments/migration.sql +60 -0
- package/prisma/migrations/20260504071500_school_memberships/migration.sql +81 -0
- package/prisma/schema.prisma +75 -2
- package/src/lib/config/cors.ts +8 -1
- package/src/models/access.ts +48 -0
- package/src/models/announcement.ts +19 -2
- package/src/models/assignment.ts +17 -13
- package/src/models/attendance.ts +4 -3
- package/src/models/auth.ts +8 -9
- package/src/models/class.ts +8 -9
- package/src/models/comment.ts +137 -1
- package/src/models/event.ts +54 -4
- package/src/models/file.ts +53 -12
- package/src/models/folder.ts +3 -2
- package/src/models/labChat.ts +9 -8
- package/src/models/school.ts +361 -0
- package/src/models/section.ts +3 -2
- package/src/models/worksheet.ts +7 -12
- package/src/pipelines/aiLabChat.ts +2 -1
- package/src/routers/_app.ts +2 -0
- package/src/routers/announcement.ts +30 -4
- package/src/routers/assignment.ts +243 -2
- package/src/routers/class.ts +1 -0
- package/src/routers/comment.ts +19 -2
- package/src/routers/school.ts +122 -0
- package/src/services/announcement.ts +12 -4
- package/src/services/class.ts +25 -2
- package/src/services/comment.ts +122 -18
- package/src/services/event.ts +23 -6
- package/src/services/file.ts +20 -6
- package/src/services/school.ts +308 -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/vercel.json +8 -0
package/src/models/assignment.ts
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
* Assignment model – assignments, submissions, attachments.
|
|
3
3
|
*/
|
|
4
4
|
import { prisma } from "../lib/prisma.js";
|
|
5
|
+
import {
|
|
6
|
+
classMemberOrSchoolAdminWhere,
|
|
7
|
+
classTeacherOrSchoolAdminWhere,
|
|
8
|
+
schoolAdminForClassWhere,
|
|
9
|
+
} from "./access.js";
|
|
5
10
|
|
|
6
11
|
const assignmentGetInclude = {
|
|
7
12
|
submissions: {
|
|
@@ -57,7 +62,13 @@ export function findAssignmentWithDetails(id: string) {
|
|
|
57
62
|
/** @returns Assignment with attachments for delete. */
|
|
58
63
|
export function findAssignmentForDelete(id: string, teacherId: string) {
|
|
59
64
|
return prisma.assignment.findFirst({
|
|
60
|
-
where: {
|
|
65
|
+
where: {
|
|
66
|
+
id,
|
|
67
|
+
OR: [
|
|
68
|
+
{ teacherId },
|
|
69
|
+
{ class: schoolAdminForClassWhere(teacherId) },
|
|
70
|
+
],
|
|
71
|
+
},
|
|
61
72
|
include: {
|
|
62
73
|
attachments: { include: { thumbnail: true } },
|
|
63
74
|
submissions: {
|
|
@@ -115,12 +126,7 @@ export function findSubmissionByIdForClassMember(submissionId: string, classId:
|
|
|
115
126
|
id: submissionId,
|
|
116
127
|
assignment: {
|
|
117
128
|
classId,
|
|
118
|
-
class:
|
|
119
|
-
OR: [
|
|
120
|
-
{ teachers: { some: { id: userId } } },
|
|
121
|
-
{ students: { some: { id: userId } } },
|
|
122
|
-
],
|
|
123
|
-
},
|
|
129
|
+
class: classMemberOrSchoolAdminWhere(userId),
|
|
124
130
|
},
|
|
125
131
|
},
|
|
126
132
|
include: {
|
|
@@ -148,9 +154,7 @@ export function findSubmissionForUpdate(submissionId: string, userId: string) {
|
|
|
148
154
|
{ studentId: userId },
|
|
149
155
|
{
|
|
150
156
|
assignment: {
|
|
151
|
-
class:
|
|
152
|
-
teachers: { some: { id: userId } },
|
|
153
|
-
},
|
|
157
|
+
class: classTeacherOrSchoolAdminWhere(userId),
|
|
154
158
|
},
|
|
155
159
|
},
|
|
156
160
|
],
|
|
@@ -204,7 +208,7 @@ export function findAssignmentWithClassForTeacher(assignmentId: string, teacherI
|
|
|
204
208
|
return prisma.assignment.findFirst({
|
|
205
209
|
where: {
|
|
206
210
|
id: assignmentId,
|
|
207
|
-
class:
|
|
211
|
+
class: classTeacherOrSchoolAdminWhere(teacherId),
|
|
208
212
|
},
|
|
209
213
|
include: { class: true },
|
|
210
214
|
});
|
|
@@ -216,7 +220,7 @@ export function findSubmissionsByAssignmentForTeacher(assignmentId: string, teac
|
|
|
216
220
|
where: {
|
|
217
221
|
assignment: {
|
|
218
222
|
id: assignmentId,
|
|
219
|
-
class:
|
|
223
|
+
class: classTeacherOrSchoolAdminWhere(teacherId),
|
|
220
224
|
},
|
|
221
225
|
},
|
|
222
226
|
include: {
|
|
@@ -251,7 +255,7 @@ export function findSubmissionForTeacherUpdate(submissionId: string, teacherId:
|
|
|
251
255
|
where: {
|
|
252
256
|
id: submissionId,
|
|
253
257
|
assignment: {
|
|
254
|
-
class:
|
|
258
|
+
class: classTeacherOrSchoolAdminWhere(teacherId),
|
|
255
259
|
},
|
|
256
260
|
},
|
|
257
261
|
include: {
|
package/src/models/attendance.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Attendance model – attendance records, present/late/absent students per event.
|
|
3
3
|
*/
|
|
4
4
|
import { prisma } from "../lib/prisma.js";
|
|
5
|
+
import { classTeacherOrSchoolAdminWhere } from "./access.js";
|
|
5
6
|
|
|
6
7
|
const attendanceInclude = {
|
|
7
8
|
event: {
|
|
@@ -105,12 +106,12 @@ export function findClassWithStudents(classId: string) {
|
|
|
105
106
|
});
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
/** @returns Class if user is a teacher. */
|
|
109
|
+
/** @returns Class if user is a teacher or school admin. */
|
|
109
110
|
export function findClassWithTeacher(classId: string, teacherId: string) {
|
|
110
|
-
return prisma.class.
|
|
111
|
+
return prisma.class.findFirst({
|
|
111
112
|
where: {
|
|
112
113
|
id: classId,
|
|
113
|
-
|
|
114
|
+
...classTeacherOrSchoolAdminWhere(teacherId),
|
|
114
115
|
},
|
|
115
116
|
});
|
|
116
117
|
}
|
package/src/models/auth.ts
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
import { SessionType } from "@prisma/client";
|
|
6
6
|
import { getRedis } from "../lib/redis.js";
|
|
7
7
|
import { prisma } from "../lib/prisma.js";
|
|
8
|
+
import {
|
|
9
|
+
classMemberOrSchoolAdminWhere,
|
|
10
|
+
classTeacherOrSchoolAdminWhere,
|
|
11
|
+
} from "./access.js";
|
|
8
12
|
|
|
9
13
|
const AUTH_SESSION_CACHE_PREFIX = "auth-session:";
|
|
10
14
|
|
|
@@ -246,9 +250,7 @@ export async function findUserBySessionToken(token: string) {
|
|
|
246
250
|
/** @returns Class IDs where user is a teacher. */
|
|
247
251
|
export function findTeacherClassesByUserId(userId: string) {
|
|
248
252
|
return prisma.class.findMany({
|
|
249
|
-
where:
|
|
250
|
-
teachers: { some: { id: userId } },
|
|
251
|
-
},
|
|
253
|
+
where: classTeacherOrSchoolAdminWhere(userId),
|
|
252
254
|
select: { id: true },
|
|
253
255
|
});
|
|
254
256
|
}
|
|
@@ -258,20 +260,17 @@ export function findClassWithMember(classId: string, userId: string) {
|
|
|
258
260
|
return prisma.class.findFirst({
|
|
259
261
|
where: {
|
|
260
262
|
id: classId,
|
|
261
|
-
|
|
262
|
-
{ students: { some: { id: userId } } },
|
|
263
|
-
{ teachers: { some: { id: userId } } },
|
|
264
|
-
],
|
|
263
|
+
...classMemberOrSchoolAdminWhere(userId),
|
|
265
264
|
},
|
|
266
265
|
});
|
|
267
266
|
}
|
|
268
267
|
|
|
269
|
-
/** @returns Class if user is a teacher. */
|
|
268
|
+
/** @returns Class if user is a teacher or school admin. */
|
|
270
269
|
export function findClassWithTeacher(classId: string, teacherId: string) {
|
|
271
270
|
return prisma.class.findFirst({
|
|
272
271
|
where: {
|
|
273
272
|
id: classId,
|
|
274
|
-
|
|
273
|
+
...classTeacherOrSchoolAdminWhere(teacherId),
|
|
275
274
|
},
|
|
276
275
|
});
|
|
277
276
|
}
|
package/src/models/class.ts
CHANGED
|
@@ -10,6 +10,10 @@ import type { PrismaClient, WorksheetQuestion } from "@prisma/client";
|
|
|
10
10
|
import { prisma } from "../lib/prisma.js";
|
|
11
11
|
import { v4 as uuidv4 } from 'uuid';
|
|
12
12
|
import { copyFile } from "../lib/googleCloudStorage.js";
|
|
13
|
+
import {
|
|
14
|
+
classMemberOrSchoolAdminWhere,
|
|
15
|
+
classTeacherOrSchoolAdminWhere,
|
|
16
|
+
} from "./access.js";
|
|
13
17
|
|
|
14
18
|
const classIncludeForGetAll = {
|
|
15
19
|
assignments: {
|
|
@@ -55,7 +59,7 @@ const classIncludeForGetAll = {
|
|
|
55
59
|
/** @returns Classes where user is a teacher. */
|
|
56
60
|
export function findTeacherClasses(userId: string) {
|
|
57
61
|
return prisma.class.findMany({
|
|
58
|
-
where:
|
|
62
|
+
where: classTeacherOrSchoolAdminWhere(userId),
|
|
59
63
|
include: classIncludeForGetAll,
|
|
60
64
|
});
|
|
61
65
|
}
|
|
@@ -68,12 +72,12 @@ export function findStudentClasses(userId: string) {
|
|
|
68
72
|
});
|
|
69
73
|
}
|
|
70
74
|
|
|
71
|
-
/** @returns Class if user is a teacher. */
|
|
75
|
+
/** @returns Class if user is a teacher or school admin. */
|
|
72
76
|
export function isTeacherInClass(classId: string, userId: string) {
|
|
73
77
|
return prisma.class.findFirst({
|
|
74
78
|
where: {
|
|
75
79
|
id: classId,
|
|
76
|
-
|
|
80
|
+
...classTeacherOrSchoolAdminWhere(userId),
|
|
77
81
|
},
|
|
78
82
|
});
|
|
79
83
|
}
|
|
@@ -218,12 +222,7 @@ export function findClassWithAssignments(
|
|
|
218
222
|
where: {
|
|
219
223
|
id: classId,
|
|
220
224
|
...(options.userId
|
|
221
|
-
?
|
|
222
|
-
OR: [
|
|
223
|
-
{ students: { some: { id: options.userId } } },
|
|
224
|
-
{ teachers: { some: { id: options.userId } } },
|
|
225
|
-
],
|
|
226
|
-
}
|
|
225
|
+
? classMemberOrSchoolAdminWhere(options.userId)
|
|
227
226
|
: {}),
|
|
228
227
|
},
|
|
229
228
|
include: {
|
package/src/models/comment.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Comment model – comments, replies, and reactions
|
|
2
|
+
* Comment model – comments, replies, and reactions.
|
|
3
3
|
*/
|
|
4
4
|
import { prisma } from "../lib/prisma.js";
|
|
5
5
|
import type { ReactionType } from "@prisma/client";
|
|
@@ -7,6 +7,10 @@ import type { ReactionType } from "@prisma/client";
|
|
|
7
7
|
export const commentSelect = {
|
|
8
8
|
id: true,
|
|
9
9
|
content: true,
|
|
10
|
+
announcementId: true,
|
|
11
|
+
assignmentId: true,
|
|
12
|
+
submissionId: true,
|
|
13
|
+
parentCommentId: true,
|
|
10
14
|
createdAt: true,
|
|
11
15
|
modifiedAt: true,
|
|
12
16
|
author: {
|
|
@@ -42,6 +46,27 @@ export const commentSelect = {
|
|
|
42
46
|
},
|
|
43
47
|
} as const;
|
|
44
48
|
|
|
49
|
+
const commentClassAuthSelect = {
|
|
50
|
+
id: true,
|
|
51
|
+
teachers: { select: { id: true } },
|
|
52
|
+
students: { select: { id: true } },
|
|
53
|
+
school: {
|
|
54
|
+
select: {
|
|
55
|
+
users: {
|
|
56
|
+
where: { role: "ADMIN" as const },
|
|
57
|
+
select: { id: true },
|
|
58
|
+
},
|
|
59
|
+
memberships: {
|
|
60
|
+
where: {
|
|
61
|
+
role: "ADMIN" as const,
|
|
62
|
+
status: "ACTIVE" as const,
|
|
63
|
+
},
|
|
64
|
+
select: { userId: true },
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
} as const;
|
|
69
|
+
|
|
45
70
|
/** @returns Comment by ID with author and reactions. */
|
|
46
71
|
export function findCommentById(id: string) {
|
|
47
72
|
return prisma.comment.findUnique({
|
|
@@ -77,6 +102,10 @@ export function createComment(data: {
|
|
|
77
102
|
parentCommentId: string;
|
|
78
103
|
content: string;
|
|
79
104
|
authorId: string;
|
|
105
|
+
announcementId?: string | null;
|
|
106
|
+
assignmentId?: string | null;
|
|
107
|
+
submissionId?: string | null;
|
|
108
|
+
studentQuestionProgressId?: string | null;
|
|
80
109
|
}) {
|
|
81
110
|
return prisma.comment.create({
|
|
82
111
|
data,
|
|
@@ -142,6 +171,113 @@ export function findCommentWithAnnouncement(commentId: string) {
|
|
|
142
171
|
});
|
|
143
172
|
}
|
|
144
173
|
|
|
174
|
+
/** @returns Comment with the owning class context for authorization. */
|
|
175
|
+
export function findCommentWithContext(commentId: string) {
|
|
176
|
+
return prisma.comment.findUnique({
|
|
177
|
+
where: { id: commentId },
|
|
178
|
+
include: {
|
|
179
|
+
announcement: {
|
|
180
|
+
select: {
|
|
181
|
+
class: {
|
|
182
|
+
select: commentClassAuthSelect,
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
assignment: {
|
|
187
|
+
select: {
|
|
188
|
+
class: {
|
|
189
|
+
select: commentClassAuthSelect,
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
submission: {
|
|
194
|
+
select: {
|
|
195
|
+
studentId: true,
|
|
196
|
+
assignment: {
|
|
197
|
+
select: {
|
|
198
|
+
class: {
|
|
199
|
+
select: commentClassAuthSelect,
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
studentQuestionProgress: {
|
|
206
|
+
select: {
|
|
207
|
+
studentId: true,
|
|
208
|
+
studentWorksheetResponse: {
|
|
209
|
+
select: {
|
|
210
|
+
submission: {
|
|
211
|
+
select: {
|
|
212
|
+
studentId: true,
|
|
213
|
+
assignment: {
|
|
214
|
+
select: {
|
|
215
|
+
class: {
|
|
216
|
+
select: commentClassAuthSelect,
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
parentComment: {
|
|
227
|
+
include: {
|
|
228
|
+
announcement: {
|
|
229
|
+
select: {
|
|
230
|
+
class: {
|
|
231
|
+
select: commentClassAuthSelect,
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
assignment: {
|
|
236
|
+
select: {
|
|
237
|
+
class: {
|
|
238
|
+
select: commentClassAuthSelect,
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
submission: {
|
|
243
|
+
select: {
|
|
244
|
+
studentId: true,
|
|
245
|
+
assignment: {
|
|
246
|
+
select: {
|
|
247
|
+
class: {
|
|
248
|
+
select: commentClassAuthSelect,
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
studentQuestionProgress: {
|
|
255
|
+
select: {
|
|
256
|
+
studentId: true,
|
|
257
|
+
studentWorksheetResponse: {
|
|
258
|
+
select: {
|
|
259
|
+
submission: {
|
|
260
|
+
select: {
|
|
261
|
+
studentId: true,
|
|
262
|
+
assignment: {
|
|
263
|
+
select: {
|
|
264
|
+
class: {
|
|
265
|
+
select: commentClassAuthSelect,
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
145
281
|
/** @returns Reaction counts by type for a comment. */
|
|
146
282
|
export function getReactionCountsByCommentId(commentId: string) {
|
|
147
283
|
return prisma.reaction.groupBy({
|
package/src/models/event.ts
CHANGED
|
@@ -2,9 +2,29 @@
|
|
|
2
2
|
* Event model – calendar events, assignment attachment/detachment.
|
|
3
3
|
*/
|
|
4
4
|
import { prisma } from "../lib/prisma.js";
|
|
5
|
+
import { classTeacherOrSchoolAdminWhere } from "./access.js";
|
|
5
6
|
|
|
6
7
|
const eventGetInclude = {
|
|
7
|
-
class:
|
|
8
|
+
class: {
|
|
9
|
+
include: {
|
|
10
|
+
teachers: { select: { id: true } },
|
|
11
|
+
school: {
|
|
12
|
+
include: {
|
|
13
|
+
users: {
|
|
14
|
+
where: { role: "ADMIN" as const },
|
|
15
|
+
select: { id: true },
|
|
16
|
+
},
|
|
17
|
+
memberships: {
|
|
18
|
+
where: {
|
|
19
|
+
role: "ADMIN" as const,
|
|
20
|
+
status: "ACTIVE" as const,
|
|
21
|
+
},
|
|
22
|
+
select: { userId: true },
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
8
28
|
user: true,
|
|
9
29
|
assignmentsAttached: {
|
|
10
30
|
select: {
|
|
@@ -50,12 +70,12 @@ export function findEventById(id: string) {
|
|
|
50
70
|
});
|
|
51
71
|
}
|
|
52
72
|
|
|
53
|
-
/** @returns Class if user is a teacher. */
|
|
73
|
+
/** @returns Class if user is a teacher or school admin. */
|
|
54
74
|
export function findClassWithTeachers(classId: string, teacherId: string) {
|
|
55
|
-
return prisma.class.
|
|
75
|
+
return prisma.class.findFirst({
|
|
56
76
|
where: {
|
|
57
77
|
id: classId,
|
|
58
|
-
|
|
78
|
+
...classTeacherOrSchoolAdminWhere(teacherId),
|
|
59
79
|
},
|
|
60
80
|
});
|
|
61
81
|
}
|
|
@@ -111,6 +131,21 @@ export function findEventWithClass(eventId: string) {
|
|
|
111
131
|
class: {
|
|
112
132
|
include: {
|
|
113
133
|
teachers: { select: { id: true } },
|
|
134
|
+
school: {
|
|
135
|
+
include: {
|
|
136
|
+
users: {
|
|
137
|
+
where: { role: "ADMIN" as const },
|
|
138
|
+
select: { id: true },
|
|
139
|
+
},
|
|
140
|
+
memberships: {
|
|
141
|
+
where: {
|
|
142
|
+
role: "ADMIN" as const,
|
|
143
|
+
status: "ACTIVE" as const,
|
|
144
|
+
},
|
|
145
|
+
select: { userId: true },
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
},
|
|
114
149
|
},
|
|
115
150
|
},
|
|
116
151
|
},
|
|
@@ -125,6 +160,21 @@ export function findAssignmentWithClass(assignmentId: string) {
|
|
|
125
160
|
class: {
|
|
126
161
|
include: {
|
|
127
162
|
teachers: { select: { id: true } },
|
|
163
|
+
school: {
|
|
164
|
+
include: {
|
|
165
|
+
users: {
|
|
166
|
+
where: { role: "ADMIN" as const },
|
|
167
|
+
select: { id: true },
|
|
168
|
+
},
|
|
169
|
+
memberships: {
|
|
170
|
+
where: {
|
|
171
|
+
role: "ADMIN" as const,
|
|
172
|
+
status: "ACTIVE" as const,
|
|
173
|
+
},
|
|
174
|
+
select: { userId: true },
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
},
|
|
128
178
|
},
|
|
129
179
|
},
|
|
130
180
|
},
|
package/src/models/file.ts
CHANGED
|
@@ -3,6 +3,26 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { prisma } from "../lib/prisma.js";
|
|
5
5
|
|
|
6
|
+
const classFileAccessInclude = {
|
|
7
|
+
students: true,
|
|
8
|
+
teachers: true,
|
|
9
|
+
school: {
|
|
10
|
+
include: {
|
|
11
|
+
users: {
|
|
12
|
+
where: { role: "ADMIN" as const },
|
|
13
|
+
select: { id: true },
|
|
14
|
+
},
|
|
15
|
+
memberships: {
|
|
16
|
+
where: {
|
|
17
|
+
role: "ADMIN" as const,
|
|
18
|
+
status: "ACTIVE" as const,
|
|
19
|
+
},
|
|
20
|
+
select: { userId: true },
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
} as const;
|
|
25
|
+
|
|
6
26
|
/** @returns File with assignment, submission, annotations, folder, announcement for permission checks. */
|
|
7
27
|
export function findFileById(fileId: string) {
|
|
8
28
|
return prisma.file.findUnique({
|
|
@@ -11,10 +31,7 @@ export function findFileById(fileId: string) {
|
|
|
11
31
|
assignment: {
|
|
12
32
|
include: {
|
|
13
33
|
class: {
|
|
14
|
-
include:
|
|
15
|
-
students: true,
|
|
16
|
-
teachers: true,
|
|
17
|
-
},
|
|
34
|
+
include: classFileAccessInclude,
|
|
18
35
|
},
|
|
19
36
|
},
|
|
20
37
|
},
|
|
@@ -26,6 +43,21 @@ export function findFileById(fileId: string) {
|
|
|
26
43
|
class: {
|
|
27
44
|
include: {
|
|
28
45
|
teachers: true,
|
|
46
|
+
school: {
|
|
47
|
+
include: {
|
|
48
|
+
users: {
|
|
49
|
+
where: { role: "ADMIN" as const },
|
|
50
|
+
select: { id: true },
|
|
51
|
+
},
|
|
52
|
+
memberships: {
|
|
53
|
+
where: {
|
|
54
|
+
role: "ADMIN" as const,
|
|
55
|
+
status: "ACTIVE" as const,
|
|
56
|
+
},
|
|
57
|
+
select: { userId: true },
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
29
61
|
},
|
|
30
62
|
},
|
|
31
63
|
},
|
|
@@ -40,6 +72,21 @@ export function findFileById(fileId: string) {
|
|
|
40
72
|
class: {
|
|
41
73
|
include: {
|
|
42
74
|
teachers: true,
|
|
75
|
+
school: {
|
|
76
|
+
include: {
|
|
77
|
+
users: {
|
|
78
|
+
where: { role: "ADMIN" as const },
|
|
79
|
+
select: { id: true },
|
|
80
|
+
},
|
|
81
|
+
memberships: {
|
|
82
|
+
where: {
|
|
83
|
+
role: "ADMIN" as const,
|
|
84
|
+
status: "ACTIVE" as const,
|
|
85
|
+
},
|
|
86
|
+
select: { userId: true },
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
},
|
|
43
90
|
},
|
|
44
91
|
},
|
|
45
92
|
},
|
|
@@ -49,20 +96,14 @@ export function findFileById(fileId: string) {
|
|
|
49
96
|
folder: {
|
|
50
97
|
include: {
|
|
51
98
|
class: {
|
|
52
|
-
include:
|
|
53
|
-
students: true,
|
|
54
|
-
teachers: true,
|
|
55
|
-
},
|
|
99
|
+
include: classFileAccessInclude,
|
|
56
100
|
},
|
|
57
101
|
},
|
|
58
102
|
},
|
|
59
103
|
announcement: {
|
|
60
104
|
include: {
|
|
61
105
|
class: {
|
|
62
|
-
include:
|
|
63
|
-
students: true,
|
|
64
|
-
teachers: true,
|
|
65
|
-
},
|
|
106
|
+
include: classFileAccessInclude,
|
|
66
107
|
},
|
|
67
108
|
},
|
|
68
109
|
},
|
package/src/models/folder.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Folder model – class folders, hierarchy, contents. Teacher permission checks.
|
|
3
3
|
*/
|
|
4
4
|
import { prisma } from "../lib/prisma.js";
|
|
5
|
+
import { classTeacherOrSchoolAdminWhere } from "./access.js";
|
|
5
6
|
|
|
6
7
|
const fileSelect = {
|
|
7
8
|
id: true,
|
|
@@ -19,12 +20,12 @@ const childFolderSelect = {
|
|
|
19
20
|
_count: { select: { files: true, childFolders: true } },
|
|
20
21
|
};
|
|
21
22
|
|
|
22
|
-
/** @returns Class if user is a teacher. */
|
|
23
|
+
/** @returns Class if user is a teacher or school admin. */
|
|
23
24
|
export function findClassWithTeacher(classId: string, teacherId: string) {
|
|
24
25
|
return prisma.class.findFirst({
|
|
25
26
|
where: {
|
|
26
27
|
id: classId,
|
|
27
|
-
|
|
28
|
+
...classTeacherOrSchoolAdminWhere(teacherId),
|
|
28
29
|
},
|
|
29
30
|
});
|
|
30
31
|
}
|
package/src/models/labChat.ts
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* Lab chat model – AI lab conversations, members, posts. Teacher/student access.
|
|
3
3
|
*/
|
|
4
4
|
import { prisma } from "../lib/prisma.js";
|
|
5
|
+
import {
|
|
6
|
+
classMemberOrSchoolAdminWhere,
|
|
7
|
+
classTeacherOrSchoolAdminWhere,
|
|
8
|
+
} from "./access.js";
|
|
5
9
|
|
|
6
10
|
const labChatInclude = {
|
|
7
11
|
conversation: {
|
|
@@ -51,7 +55,7 @@ export function findClassWithTeachersForLab(classId: string, teacherId: string)
|
|
|
51
55
|
return prisma.class.findFirst({
|
|
52
56
|
where: {
|
|
53
57
|
id: classId,
|
|
54
|
-
|
|
58
|
+
...classTeacherOrSchoolAdminWhere(teacherId),
|
|
55
59
|
},
|
|
56
60
|
include: {
|
|
57
61
|
students: {
|
|
@@ -95,13 +99,13 @@ export function findLabChatByMember(labChatId: string, userId: string) {
|
|
|
95
99
|
});
|
|
96
100
|
}
|
|
97
101
|
|
|
98
|
-
/** @returns Lab chat if user is class teacher. */
|
|
102
|
+
/** @returns Lab chat if user is class teacher or school admin. */
|
|
99
103
|
export function findLabChatByTeacher(labChatId: string, userId: string) {
|
|
100
104
|
return prisma.labChat.findFirst({
|
|
101
105
|
where: {
|
|
102
106
|
id: labChatId,
|
|
103
107
|
class: {
|
|
104
|
-
|
|
108
|
+
...classTeacherOrSchoolAdminWhere(userId),
|
|
105
109
|
},
|
|
106
110
|
},
|
|
107
111
|
include: {
|
|
@@ -118,15 +122,12 @@ export function findLabChatById(labChatId: string) {
|
|
|
118
122
|
});
|
|
119
123
|
}
|
|
120
124
|
|
|
121
|
-
/** @returns Class if user is student or
|
|
125
|
+
/** @returns Class if user is student, teacher, or school admin. */
|
|
122
126
|
export function findClassMembership(classId: string, userId: string) {
|
|
123
127
|
return prisma.class.findFirst({
|
|
124
128
|
where: {
|
|
125
129
|
id: classId,
|
|
126
|
-
|
|
127
|
-
{ students: { some: { id: userId } } },
|
|
128
|
-
{ teachers: { some: { id: userId } } },
|
|
129
|
-
],
|
|
130
|
+
...classMemberOrSchoolAdminWhere(userId),
|
|
130
131
|
},
|
|
131
132
|
});
|
|
132
133
|
}
|