@studious-lms/server 1.7.0 → 1.9.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/dist/middleware/security.d.ts.map +1 -1
- package/dist/middleware/security.js +3 -3
- package/dist/middleware/security.js.map +1 -1
- package/dist/models/access.d.ts +21 -66
- package/dist/models/access.d.ts.map +1 -1
- package/dist/models/access.js +10 -26
- package/dist/models/access.js.map +1 -1
- package/dist/models/agenda.d.ts +4 -2
- package/dist/models/agenda.d.ts.map +1 -1
- package/dist/models/announcement.d.ts +4 -3
- package/dist/models/announcement.d.ts.map +1 -1
- package/dist/models/announcement.js +2 -3
- package/dist/models/announcement.js.map +1 -1
- package/dist/models/assignment.d.ts +40 -33
- package/dist/models/assignment.d.ts.map +1 -1
- package/dist/models/auth.d.ts +2 -4
- package/dist/models/auth.d.ts.map +1 -1
- package/dist/models/auth.js +2 -3
- package/dist/models/auth.js.map +1 -1
- package/dist/models/class.d.ts +34 -6
- package/dist/models/class.d.ts.map +1 -1
- package/dist/models/class.js +15 -2
- package/dist/models/class.js.map +1 -1
- package/dist/models/cloudStorage.d.ts +153 -0
- package/dist/models/cloudStorage.d.ts.map +1 -0
- package/dist/models/cloudStorage.js +295 -0
- package/dist/models/cloudStorage.js.map +1 -0
- package/dist/models/comment.d.ts +0 -24
- package/dist/models/comment.d.ts.map +1 -1
- package/dist/models/comment.js +2 -6
- package/dist/models/comment.js.map +1 -1
- package/dist/models/conversation.d.ts +22 -22
- package/dist/models/department.d.ts +154 -0
- package/dist/models/department.d.ts.map +1 -0
- package/dist/models/department.js +135 -0
- package/dist/models/department.js.map +1 -0
- package/dist/models/event.d.ts +10 -4
- package/dist/models/event.d.ts.map +1 -1
- package/dist/models/event.js +2 -5
- package/dist/models/event.js.map +1 -1
- package/dist/models/file.d.ts +52 -36
- package/dist/models/file.d.ts.map +1 -1
- package/dist/models/file.js +4 -42
- package/dist/models/file.js.map +1 -1
- package/dist/models/folder.d.ts +47 -0
- package/dist/models/folder.d.ts.map +1 -1
- package/dist/models/labChat.d.ts +11 -9
- package/dist/models/labChat.d.ts.map +1 -1
- package/dist/models/message.d.ts +46 -12
- package/dist/models/message.d.ts.map +1 -1
- package/dist/models/message.js +19 -10
- package/dist/models/message.js.map +1 -1
- package/dist/models/newtonChat.d.ts +2 -1
- package/dist/models/newtonChat.d.ts.map +1 -1
- package/dist/models/school.d.ts +45 -12
- package/dist/models/school.d.ts.map +1 -1
- package/dist/models/school.js +19 -2
- package/dist/models/school.js.map +1 -1
- package/dist/models/section.d.ts +2 -1
- package/dist/models/section.d.ts.map +1 -1
- package/dist/models/tag.d.ts +117 -0
- package/dist/models/tag.d.ts.map +1 -0
- package/dist/models/tag.js +113 -0
- package/dist/models/tag.js.map +1 -0
- package/dist/models/worksheet.d.ts +3 -0
- package/dist/models/worksheet.d.ts.map +1 -1
- package/dist/pipelines/aiLabChatContract.d.ts +8 -8
- package/dist/routers/_app.d.ts +6704 -5222
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +8 -2
- package/dist/routers/_app.js.map +1 -1
- package/dist/routers/agenda.d.ts +4 -2
- package/dist/routers/agenda.d.ts.map +1 -1
- package/dist/routers/announcement.d.ts.map +1 -1
- package/dist/routers/announcement.js +3 -5
- package/dist/routers/announcement.js.map +1 -1
- package/dist/routers/assignment.d.ts +49 -40
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/assignment.js +2 -3
- package/dist/routers/assignment.js.map +1 -1
- package/dist/routers/class.d.ts +92 -19
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/class.js +5 -2
- package/dist/routers/class.js.map +1 -1
- package/dist/routers/conversation.d.ts +5 -5
- package/dist/routers/department.d.ts +293 -0
- package/dist/routers/department.d.ts.map +1 -0
- package/dist/routers/department.js +93 -0
- package/dist/routers/department.js.map +1 -0
- package/dist/routers/event.d.ts +4 -3
- package/dist/routers/event.d.ts.map +1 -1
- package/dist/routers/file.d.ts +10 -8
- package/dist/routers/file.d.ts.map +1 -1
- package/dist/routers/file.js +26 -17
- package/dist/routers/file.js.map +1 -1
- package/dist/routers/folder.d.ts +163 -186
- package/dist/routers/folder.d.ts.map +1 -1
- package/dist/routers/folder.js +102 -88
- package/dist/routers/folder.js.map +1 -1
- package/dist/routers/labChat.d.ts +13 -4
- package/dist/routers/labChat.d.ts.map +1 -1
- package/dist/routers/message.d.ts +20 -2
- package/dist/routers/message.d.ts.map +1 -1
- package/dist/routers/newtonChat.d.ts +10 -1
- package/dist/routers/newtonChat.d.ts.map +1 -1
- package/dist/routers/permissions.d.ts +120 -0
- package/dist/routers/permissions.d.ts.map +1 -0
- package/dist/routers/permissions.js +50 -0
- package/dist/routers/permissions.js.map +1 -0
- package/dist/routers/school.d.ts +160 -17
- package/dist/routers/school.d.ts.map +1 -1
- package/dist/routers/school.js +46 -3
- package/dist/routers/school.js.map +1 -1
- package/dist/routers/tag.d.ts +119 -0
- package/dist/routers/tag.d.ts.map +1 -0
- package/dist/routers/tag.js +52 -0
- package/dist/routers/tag.js.map +1 -0
- package/dist/routers/worksheet.d.ts +1 -0
- package/dist/routers/worksheet.d.ts.map +1 -1
- package/dist/seedDatabase.d.ts +0 -1
- package/dist/seedDatabase.d.ts.map +1 -1
- package/dist/services/agenda.d.ts +4 -2
- package/dist/services/agenda.d.ts.map +1 -1
- package/dist/services/assignment.d.ts +49 -40
- package/dist/services/assignment.d.ts.map +1 -1
- package/dist/services/class.d.ts +92 -19
- package/dist/services/class.d.ts.map +1 -1
- package/dist/services/class.js +92 -5
- package/dist/services/class.js.map +1 -1
- package/dist/services/conversation.d.ts +5 -5
- package/dist/services/department.d.ts +200 -0
- package/dist/services/department.d.ts.map +1 -0
- package/dist/services/department.js +368 -0
- package/dist/services/department.js.map +1 -0
- package/dist/services/event.d.ts +4 -3
- package/dist/services/event.d.ts.map +1 -1
- package/dist/services/file.d.ts +105 -3
- package/dist/services/file.d.ts.map +1 -1
- package/dist/services/file.js +167 -41
- package/dist/services/file.js.map +1 -1
- package/dist/services/folder.d.ts +220 -149
- package/dist/services/folder.d.ts.map +1 -1
- package/dist/services/folder.js +326 -196
- package/dist/services/folder.js.map +1 -1
- package/dist/services/labChat.d.ts +13 -4
- package/dist/services/labChat.d.ts.map +1 -1
- package/dist/services/labChat.js +4 -3
- package/dist/services/labChat.js.map +1 -1
- package/dist/services/message.d.ts +20 -2
- package/dist/services/message.d.ts.map +1 -1
- package/dist/services/message.js +7 -23
- package/dist/services/message.js.map +1 -1
- package/dist/services/newtonChat.d.ts +9 -0
- package/dist/services/newtonChat.d.ts.map +1 -1
- package/dist/services/newtonChat.js +4 -3
- package/dist/services/newtonChat.js.map +1 -1
- package/dist/services/permissions.d.ts +188 -0
- package/dist/services/permissions.d.ts.map +1 -0
- package/dist/services/permissions.js +661 -0
- package/dist/services/permissions.js.map +1 -0
- package/dist/services/school.d.ts +142 -15
- package/dist/services/school.d.ts.map +1 -1
- package/dist/services/school.js +308 -54
- package/dist/services/school.js.map +1 -1
- package/dist/services/tag.d.ts +71 -0
- package/dist/services/tag.d.ts.map +1 -0
- package/dist/services/tag.js +178 -0
- package/dist/services/tag.js.map +1 -0
- package/dist/services/worksheet.d.ts +1 -0
- package/dist/services/worksheet.d.ts.map +1 -1
- package/dist/utils/aiUser.d.ts.map +1 -1
- package/dist/utils/aiUser.js +2 -3
- package/dist/utils/aiUser.js.map +1 -1
- package/package.json +1 -1
- package/prisma/migrations/20260509220000_institution_overhaul/migration.sql +184 -0
- package/prisma/migrations/20260510170000_add_folder_permissions/migration.sql +93 -0
- package/prisma/schema.prisma +193 -35
- package/src/middleware/security.ts +1 -1
- package/src/models/access.ts +8 -24
- package/src/models/announcement.ts +0 -1
- package/src/models/auth.ts +0 -1
- package/src/models/class.ts +13 -0
- package/src/models/cloudStorage.ts +327 -0
- package/src/models/comment.ts +0 -4
- package/src/models/department.ts +159 -0
- package/src/models/event.ts +0 -3
- package/src/models/file.ts +2 -40
- package/src/models/message.ts +19 -5
- package/src/models/school.ts +26 -0
- package/src/models/tag.ts +140 -0
- package/src/routers/_app.ts +6 -0
- package/src/routers/announcement.ts +1 -3
- package/src/routers/assignment.ts +0 -1
- package/src/routers/class.ts +3 -0
- package/src/routers/department.ts +174 -0
- package/src/routers/file.ts +29 -26
- package/src/routers/folder.ts +127 -118
- package/src/routers/permissions.ts +71 -0
- package/src/routers/school.ts +83 -0
- package/src/routers/tag.ts +78 -0
- package/src/services/class.ts +109 -4
- package/src/services/department.ts +478 -0
- package/src/services/file.ts +172 -43
- package/src/services/folder.ts +399 -237
- package/src/services/labChat.ts +2 -1
- package/src/services/message.ts +5 -21
- package/src/services/newtonChat.ts +2 -1
- package/src/services/permissions.ts +778 -0
- package/src/services/school.ts +369 -57
- package/src/services/tag.ts +229 -0
- package/src/utils/aiUser.ts +0 -1
- package/tests/unit/services/permissions.test.ts +463 -0
|
@@ -20,8 +20,8 @@ export declare function listConversations(userId: string): Promise<{
|
|
|
20
20
|
};
|
|
21
21
|
} & {
|
|
22
22
|
id: string;
|
|
23
|
-
role: import(".prisma/client").$Enums.ConversationRole;
|
|
24
23
|
userId: string;
|
|
24
|
+
role: import(".prisma/client").$Enums.ConversationRole;
|
|
25
25
|
conversationId: string;
|
|
26
26
|
joinedAt: Date;
|
|
27
27
|
hiddenAt: Date | null;
|
|
@@ -81,8 +81,8 @@ export declare function createConversationRecord(userId: string, type: "DM" | "G
|
|
|
81
81
|
};
|
|
82
82
|
} & {
|
|
83
83
|
id: string;
|
|
84
|
-
role: import(".prisma/client").$Enums.ConversationRole;
|
|
85
84
|
userId: string;
|
|
85
|
+
role: import(".prisma/client").$Enums.ConversationRole;
|
|
86
86
|
conversationId: string;
|
|
87
87
|
joinedAt: Date;
|
|
88
88
|
hiddenAt: Date | null;
|
|
@@ -109,8 +109,8 @@ export declare function getConversation(userId: string, conversationId: string):
|
|
|
109
109
|
};
|
|
110
110
|
} & {
|
|
111
111
|
id: string;
|
|
112
|
-
role: import(".prisma/client").$Enums.ConversationRole;
|
|
113
112
|
userId: string;
|
|
113
|
+
role: import(".prisma/client").$Enums.ConversationRole;
|
|
114
114
|
conversationId: string;
|
|
115
115
|
joinedAt: Date;
|
|
116
116
|
hiddenAt: Date | null;
|
|
@@ -137,8 +137,8 @@ export declare function addMemberToConversation(userId: string, conversationId:
|
|
|
137
137
|
};
|
|
138
138
|
} & {
|
|
139
139
|
id: string;
|
|
140
|
-
role: import(".prisma/client").$Enums.ConversationRole;
|
|
141
140
|
userId: string;
|
|
141
|
+
role: import(".prisma/client").$Enums.ConversationRole;
|
|
142
142
|
conversationId: string;
|
|
143
143
|
joinedAt: Date;
|
|
144
144
|
hiddenAt: Date | null;
|
|
@@ -165,8 +165,8 @@ export declare function removeMemberFromConversation(userId: string, conversatio
|
|
|
165
165
|
};
|
|
166
166
|
} & {
|
|
167
167
|
id: string;
|
|
168
|
-
role: import(".prisma/client").$Enums.ConversationRole;
|
|
169
168
|
userId: string;
|
|
169
|
+
role: import(".prisma/client").$Enums.ConversationRole;
|
|
170
170
|
conversationId: string;
|
|
171
171
|
joinedAt: Date;
|
|
172
172
|
hiddenAt: Date | null;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
export declare function listDepartments(userId: string, schoolId: string): Promise<{
|
|
2
|
+
name: string;
|
|
3
|
+
id: string;
|
|
4
|
+
description: string | null;
|
|
5
|
+
createdAt: Date;
|
|
6
|
+
updatedAt: Date;
|
|
7
|
+
schoolId: string;
|
|
8
|
+
color: string | null;
|
|
9
|
+
_count: {
|
|
10
|
+
tags: number;
|
|
11
|
+
classes: number;
|
|
12
|
+
members: number;
|
|
13
|
+
rubricTemplates: number;
|
|
14
|
+
boundaryTemplates: number;
|
|
15
|
+
};
|
|
16
|
+
}[]>;
|
|
17
|
+
export declare function listMyDepartments(userId: string, schoolId: string): Promise<{
|
|
18
|
+
name: string;
|
|
19
|
+
id: string;
|
|
20
|
+
description: string | null;
|
|
21
|
+
createdAt: Date;
|
|
22
|
+
updatedAt: Date;
|
|
23
|
+
schoolId: string;
|
|
24
|
+
color: string | null;
|
|
25
|
+
}[]>;
|
|
26
|
+
export declare function getDepartmentDetails(userId: string, departmentId: string): Promise<{
|
|
27
|
+
name: string;
|
|
28
|
+
id: string;
|
|
29
|
+
description: string | null;
|
|
30
|
+
createdAt: Date;
|
|
31
|
+
updatedAt: Date;
|
|
32
|
+
schoolId: string;
|
|
33
|
+
color: string | null;
|
|
34
|
+
tags: {
|
|
35
|
+
name: string;
|
|
36
|
+
id: string;
|
|
37
|
+
color: string;
|
|
38
|
+
}[];
|
|
39
|
+
classes: {
|
|
40
|
+
name: string;
|
|
41
|
+
id: string;
|
|
42
|
+
subject: string;
|
|
43
|
+
color: string | null;
|
|
44
|
+
section: string;
|
|
45
|
+
}[];
|
|
46
|
+
members: {
|
|
47
|
+
id: string;
|
|
48
|
+
username: string;
|
|
49
|
+
email: string;
|
|
50
|
+
profile: {
|
|
51
|
+
displayName: string | null;
|
|
52
|
+
profilePicture: string | null;
|
|
53
|
+
profilePictureThumbnail: string | null;
|
|
54
|
+
} | null;
|
|
55
|
+
}[];
|
|
56
|
+
rubricTemplates: {
|
|
57
|
+
name: string | null;
|
|
58
|
+
id: string;
|
|
59
|
+
structured: string;
|
|
60
|
+
}[];
|
|
61
|
+
boundaryTemplates: {
|
|
62
|
+
name: string | null;
|
|
63
|
+
id: string;
|
|
64
|
+
structured: string;
|
|
65
|
+
}[];
|
|
66
|
+
}>;
|
|
67
|
+
export declare function createDepartmentRecord(userId: string, input: {
|
|
68
|
+
schoolId: string;
|
|
69
|
+
name: string;
|
|
70
|
+
description?: string;
|
|
71
|
+
color?: string;
|
|
72
|
+
}): Promise<{
|
|
73
|
+
name: string;
|
|
74
|
+
id: string;
|
|
75
|
+
description: string | null;
|
|
76
|
+
createdAt: Date;
|
|
77
|
+
updatedAt: Date;
|
|
78
|
+
schoolId: string;
|
|
79
|
+
color: string | null;
|
|
80
|
+
}>;
|
|
81
|
+
export declare function updateDepartmentRecord(userId: string, input: {
|
|
82
|
+
departmentId: string;
|
|
83
|
+
name?: string;
|
|
84
|
+
description?: string | null;
|
|
85
|
+
color?: string;
|
|
86
|
+
}): Promise<{
|
|
87
|
+
name: string;
|
|
88
|
+
id: string;
|
|
89
|
+
description: string | null;
|
|
90
|
+
createdAt: Date;
|
|
91
|
+
updatedAt: Date;
|
|
92
|
+
schoolId: string;
|
|
93
|
+
color: string | null;
|
|
94
|
+
}>;
|
|
95
|
+
export declare function deleteDepartmentRecord(userId: string, departmentId: string): Promise<{
|
|
96
|
+
success: boolean;
|
|
97
|
+
}>;
|
|
98
|
+
export declare function addMembersToDepartment(userId: string, input: {
|
|
99
|
+
departmentId: string;
|
|
100
|
+
userIds: string[];
|
|
101
|
+
}): Promise<{
|
|
102
|
+
id: string;
|
|
103
|
+
}>;
|
|
104
|
+
export declare function removeMemberFromDepartment(userId: string, input: {
|
|
105
|
+
departmentId: string;
|
|
106
|
+
memberId: string;
|
|
107
|
+
}): Promise<{
|
|
108
|
+
id: string;
|
|
109
|
+
}>;
|
|
110
|
+
/** Department template authoring (rubrics + boundaries). */
|
|
111
|
+
export declare function createRubricTemplate(userId: string, input: {
|
|
112
|
+
departmentId: string;
|
|
113
|
+
name: string;
|
|
114
|
+
structured: string;
|
|
115
|
+
}): Promise<{
|
|
116
|
+
name: string | null;
|
|
117
|
+
id: string;
|
|
118
|
+
departmentId: string | null;
|
|
119
|
+
structured: string;
|
|
120
|
+
}>;
|
|
121
|
+
export declare function updateRubricTemplate(userId: string, input: {
|
|
122
|
+
templateId: string;
|
|
123
|
+
name?: string;
|
|
124
|
+
structured?: string;
|
|
125
|
+
}): Promise<{
|
|
126
|
+
name: string | null;
|
|
127
|
+
id: string;
|
|
128
|
+
departmentId: string | null;
|
|
129
|
+
classId: string | null;
|
|
130
|
+
structured: string;
|
|
131
|
+
}>;
|
|
132
|
+
export declare function deleteRubricTemplate(userId: string, templateId: string): Promise<{
|
|
133
|
+
name: string | null;
|
|
134
|
+
id: string;
|
|
135
|
+
departmentId: string | null;
|
|
136
|
+
classId: string | null;
|
|
137
|
+
structured: string;
|
|
138
|
+
}>;
|
|
139
|
+
export declare function createBoundaryTemplate(userId: string, input: {
|
|
140
|
+
departmentId: string;
|
|
141
|
+
name: string;
|
|
142
|
+
structured: string;
|
|
143
|
+
}): Promise<{
|
|
144
|
+
name: string | null;
|
|
145
|
+
id: string;
|
|
146
|
+
departmentId: string | null;
|
|
147
|
+
structured: string;
|
|
148
|
+
}>;
|
|
149
|
+
export declare function updateBoundaryTemplate(userId: string, input: {
|
|
150
|
+
templateId: string;
|
|
151
|
+
name?: string;
|
|
152
|
+
structured?: string;
|
|
153
|
+
}): Promise<{
|
|
154
|
+
name: string | null;
|
|
155
|
+
id: string;
|
|
156
|
+
departmentId: string | null;
|
|
157
|
+
classId: string | null;
|
|
158
|
+
structured: string;
|
|
159
|
+
}>;
|
|
160
|
+
export declare function deleteBoundaryTemplate(userId: string, templateId: string): Promise<{
|
|
161
|
+
name: string | null;
|
|
162
|
+
id: string;
|
|
163
|
+
departmentId: string | null;
|
|
164
|
+
classId: string | null;
|
|
165
|
+
structured: string;
|
|
166
|
+
}>;
|
|
167
|
+
/**
|
|
168
|
+
* Apply a department template to a class by *copying* the structured payload
|
|
169
|
+
* into a class-scoped record. Teacher-only (the class teacher).
|
|
170
|
+
*/
|
|
171
|
+
export declare function applyRubricTemplate(userId: string, input: {
|
|
172
|
+
classId: string;
|
|
173
|
+
templateId: string;
|
|
174
|
+
}): Promise<{
|
|
175
|
+
name: string | null;
|
|
176
|
+
id: string;
|
|
177
|
+
departmentId: string | null;
|
|
178
|
+
classId: string | null;
|
|
179
|
+
structured: string;
|
|
180
|
+
}>;
|
|
181
|
+
export declare function applyBoundaryTemplate(userId: string, input: {
|
|
182
|
+
classId: string;
|
|
183
|
+
templateId: string;
|
|
184
|
+
}): Promise<{
|
|
185
|
+
name: string | null;
|
|
186
|
+
id: string;
|
|
187
|
+
departmentId: string | null;
|
|
188
|
+
classId: string | null;
|
|
189
|
+
structured: string;
|
|
190
|
+
}>;
|
|
191
|
+
/** Helper used by the auto-tag flow on class creation. */
|
|
192
|
+
export declare function setClassDepartment(userId: string, input: {
|
|
193
|
+
classId: string;
|
|
194
|
+
departmentId: string | null;
|
|
195
|
+
}): Promise<{
|
|
196
|
+
id: string;
|
|
197
|
+
departmentId: string | null;
|
|
198
|
+
}>;
|
|
199
|
+
export declare function checkDepartmentMember(userId: string, departmentId: string): Promise<boolean>;
|
|
200
|
+
//# sourceMappingURL=department.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"department.d.ts","sourceRoot":"/","sources":["services/department.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Department service — admin CRUD, members, and template management for
|
|
3
|
+
* department-level rubrics and grading boundaries.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="a61f9d68-eb30-571c-908d-8c1fb445f85c")}catch(e){}}();
|
|
7
|
+
import { TRPCError } from "@trpc/server";
|
|
8
|
+
import { prisma } from "../lib/prisma.js";
|
|
9
|
+
import { addDepartmentMembers, createDepartment, deleteDepartment, findDepartmentMembership, getDepartment, listDepartmentsForSchool, listDepartmentsForUser, removeDepartmentMember, updateDepartment, } from "../models/department.js";
|
|
10
|
+
import { findActiveSchoolAdminMembership, findSchoolMembership, } from "../models/school.js";
|
|
11
|
+
async function requireAdmin(schoolId, userId) {
|
|
12
|
+
const membership = await findActiveSchoolAdminMembership(schoolId, userId);
|
|
13
|
+
if (!membership) {
|
|
14
|
+
throw new TRPCError({
|
|
15
|
+
code: "FORBIDDEN",
|
|
16
|
+
message: "Only school admins can manage departments",
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async function requireMember(schoolId, userId) {
|
|
21
|
+
const membership = await findSchoolMembership(schoolId, userId);
|
|
22
|
+
if (!membership || membership.status !== "ACTIVE") {
|
|
23
|
+
throw new TRPCError({
|
|
24
|
+
code: "FORBIDDEN",
|
|
25
|
+
message: "You aren't a member of this institution",
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export async function listDepartments(userId, schoolId) {
|
|
30
|
+
await requireMember(schoolId, userId);
|
|
31
|
+
return listDepartmentsForSchool(schoolId);
|
|
32
|
+
}
|
|
33
|
+
export async function listMyDepartments(userId, schoolId) {
|
|
34
|
+
await requireMember(schoolId, userId);
|
|
35
|
+
return listDepartmentsForUser(userId, schoolId);
|
|
36
|
+
}
|
|
37
|
+
export async function getDepartmentDetails(userId, departmentId) {
|
|
38
|
+
const department = await getDepartment(departmentId);
|
|
39
|
+
if (!department) {
|
|
40
|
+
throw new TRPCError({
|
|
41
|
+
code: "NOT_FOUND",
|
|
42
|
+
message: "Department not found",
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
await requireMember(department.schoolId, userId);
|
|
46
|
+
return department;
|
|
47
|
+
}
|
|
48
|
+
export async function createDepartmentRecord(userId, input) {
|
|
49
|
+
await requireAdmin(input.schoolId, userId);
|
|
50
|
+
return createDepartment(input);
|
|
51
|
+
}
|
|
52
|
+
export async function updateDepartmentRecord(userId, input) {
|
|
53
|
+
const department = await getDepartment(input.departmentId);
|
|
54
|
+
if (!department) {
|
|
55
|
+
throw new TRPCError({
|
|
56
|
+
code: "NOT_FOUND",
|
|
57
|
+
message: "Department not found",
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
await requireAdmin(department.schoolId, userId);
|
|
61
|
+
return updateDepartment(input.departmentId, {
|
|
62
|
+
name: input.name,
|
|
63
|
+
description: input.description,
|
|
64
|
+
color: input.color,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export async function deleteDepartmentRecord(userId, departmentId) {
|
|
68
|
+
const department = await getDepartment(departmentId);
|
|
69
|
+
if (!department) {
|
|
70
|
+
throw new TRPCError({
|
|
71
|
+
code: "NOT_FOUND",
|
|
72
|
+
message: "Department not found",
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
await requireAdmin(department.schoolId, userId);
|
|
76
|
+
await deleteDepartment(departmentId);
|
|
77
|
+
return { success: true };
|
|
78
|
+
}
|
|
79
|
+
export async function addMembersToDepartment(userId, input) {
|
|
80
|
+
const department = await getDepartment(input.departmentId);
|
|
81
|
+
if (!department) {
|
|
82
|
+
throw new TRPCError({
|
|
83
|
+
code: "NOT_FOUND",
|
|
84
|
+
message: "Department not found",
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
await requireAdmin(department.schoolId, userId);
|
|
88
|
+
// Members must already be in the institution.
|
|
89
|
+
const memberships = await prisma.schoolMembership.findMany({
|
|
90
|
+
where: {
|
|
91
|
+
schoolId: department.schoolId,
|
|
92
|
+
userId: { in: input.userIds },
|
|
93
|
+
status: "ACTIVE",
|
|
94
|
+
},
|
|
95
|
+
select: { userId: true },
|
|
96
|
+
});
|
|
97
|
+
const validIds = new Set(memberships.map((m) => m.userId));
|
|
98
|
+
const validUserIds = input.userIds.filter((id) => validIds.has(id));
|
|
99
|
+
if (validUserIds.length === 0) {
|
|
100
|
+
throw new TRPCError({
|
|
101
|
+
code: "BAD_REQUEST",
|
|
102
|
+
message: "None of the supplied users are institution members",
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return addDepartmentMembers(input.departmentId, validUserIds);
|
|
106
|
+
}
|
|
107
|
+
export async function removeMemberFromDepartment(userId, input) {
|
|
108
|
+
const department = await getDepartment(input.departmentId);
|
|
109
|
+
if (!department) {
|
|
110
|
+
throw new TRPCError({
|
|
111
|
+
code: "NOT_FOUND",
|
|
112
|
+
message: "Department not found",
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
await requireAdmin(department.schoolId, userId);
|
|
116
|
+
return removeDepartmentMember(input.departmentId, input.memberId);
|
|
117
|
+
}
|
|
118
|
+
/** Department template authoring (rubrics + boundaries). */
|
|
119
|
+
export async function createRubricTemplate(userId, input) {
|
|
120
|
+
const department = await getDepartment(input.departmentId);
|
|
121
|
+
if (!department) {
|
|
122
|
+
throw new TRPCError({
|
|
123
|
+
code: "NOT_FOUND",
|
|
124
|
+
message: "Department not found",
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
await requireAdmin(department.schoolId, userId);
|
|
128
|
+
return prisma.markScheme.create({
|
|
129
|
+
data: {
|
|
130
|
+
name: input.name,
|
|
131
|
+
structured: input.structured.replace(/\\n/g, "\n"),
|
|
132
|
+
department: { connect: { id: input.departmentId } },
|
|
133
|
+
},
|
|
134
|
+
select: { id: true, name: true, structured: true, departmentId: true },
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
export async function updateRubricTemplate(userId, input) {
|
|
138
|
+
const template = await prisma.markScheme.findUnique({
|
|
139
|
+
where: { id: input.templateId },
|
|
140
|
+
select: { departmentId: true, department: { select: { schoolId: true } } },
|
|
141
|
+
});
|
|
142
|
+
if (!template?.departmentId || !template.department) {
|
|
143
|
+
throw new TRPCError({
|
|
144
|
+
code: "NOT_FOUND",
|
|
145
|
+
message: "Template not found",
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
await requireAdmin(template.department.schoolId, userId);
|
|
149
|
+
return prisma.markScheme.update({
|
|
150
|
+
where: { id: input.templateId },
|
|
151
|
+
data: {
|
|
152
|
+
...(input.name !== undefined ? { name: input.name } : {}),
|
|
153
|
+
...(input.structured !== undefined
|
|
154
|
+
? { structured: input.structured.replace(/\\n/g, "\n") }
|
|
155
|
+
: {}),
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
export async function deleteRubricTemplate(userId, templateId) {
|
|
160
|
+
const template = await prisma.markScheme.findUnique({
|
|
161
|
+
where: { id: templateId },
|
|
162
|
+
select: { departmentId: true, department: { select: { schoolId: true } } },
|
|
163
|
+
});
|
|
164
|
+
if (!template?.departmentId || !template.department) {
|
|
165
|
+
throw new TRPCError({
|
|
166
|
+
code: "NOT_FOUND",
|
|
167
|
+
message: "Template not found",
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
await requireAdmin(template.department.schoolId, userId);
|
|
171
|
+
return prisma.markScheme.delete({ where: { id: templateId } });
|
|
172
|
+
}
|
|
173
|
+
export async function createBoundaryTemplate(userId, input) {
|
|
174
|
+
const department = await getDepartment(input.departmentId);
|
|
175
|
+
if (!department) {
|
|
176
|
+
throw new TRPCError({
|
|
177
|
+
code: "NOT_FOUND",
|
|
178
|
+
message: "Department not found",
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
await requireAdmin(department.schoolId, userId);
|
|
182
|
+
return prisma.gradingBoundary.create({
|
|
183
|
+
data: {
|
|
184
|
+
name: input.name,
|
|
185
|
+
structured: input.structured.replace(/\\n/g, "\n"),
|
|
186
|
+
department: { connect: { id: input.departmentId } },
|
|
187
|
+
},
|
|
188
|
+
select: { id: true, name: true, structured: true, departmentId: true },
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
export async function updateBoundaryTemplate(userId, input) {
|
|
192
|
+
const template = await prisma.gradingBoundary.findUnique({
|
|
193
|
+
where: { id: input.templateId },
|
|
194
|
+
select: { departmentId: true, department: { select: { schoolId: true } } },
|
|
195
|
+
});
|
|
196
|
+
if (!template?.departmentId || !template.department) {
|
|
197
|
+
throw new TRPCError({
|
|
198
|
+
code: "NOT_FOUND",
|
|
199
|
+
message: "Template not found",
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
await requireAdmin(template.department.schoolId, userId);
|
|
203
|
+
return prisma.gradingBoundary.update({
|
|
204
|
+
where: { id: input.templateId },
|
|
205
|
+
data: {
|
|
206
|
+
...(input.name !== undefined ? { name: input.name } : {}),
|
|
207
|
+
...(input.structured !== undefined
|
|
208
|
+
? { structured: input.structured.replace(/\\n/g, "\n") }
|
|
209
|
+
: {}),
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
export async function deleteBoundaryTemplate(userId, templateId) {
|
|
214
|
+
const template = await prisma.gradingBoundary.findUnique({
|
|
215
|
+
where: { id: templateId },
|
|
216
|
+
select: { departmentId: true, department: { select: { schoolId: true } } },
|
|
217
|
+
});
|
|
218
|
+
if (!template?.departmentId || !template.department) {
|
|
219
|
+
throw new TRPCError({
|
|
220
|
+
code: "NOT_FOUND",
|
|
221
|
+
message: "Template not found",
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
await requireAdmin(template.department.schoolId, userId);
|
|
225
|
+
return prisma.gradingBoundary.delete({ where: { id: templateId } });
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Apply a department template to a class by *copying* the structured payload
|
|
229
|
+
* into a class-scoped record. Teacher-only (the class teacher).
|
|
230
|
+
*/
|
|
231
|
+
export async function applyRubricTemplate(userId, input) {
|
|
232
|
+
const cls = await prisma.class.findFirst({
|
|
233
|
+
where: {
|
|
234
|
+
id: input.classId,
|
|
235
|
+
OR: [
|
|
236
|
+
{ teachers: { some: { id: userId } } },
|
|
237
|
+
{
|
|
238
|
+
school: {
|
|
239
|
+
memberships: {
|
|
240
|
+
some: { userId, role: "ADMIN", status: "ACTIVE" },
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
},
|
|
246
|
+
select: { id: true, departmentId: true },
|
|
247
|
+
});
|
|
248
|
+
if (!cls) {
|
|
249
|
+
throw new TRPCError({
|
|
250
|
+
code: "FORBIDDEN",
|
|
251
|
+
message: "You don't have permission to apply templates to this class",
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
const template = await prisma.markScheme.findUnique({
|
|
255
|
+
where: { id: input.templateId },
|
|
256
|
+
select: { id: true, structured: true, departmentId: true, name: true },
|
|
257
|
+
});
|
|
258
|
+
if (!template?.departmentId) {
|
|
259
|
+
throw new TRPCError({
|
|
260
|
+
code: "NOT_FOUND",
|
|
261
|
+
message: "Template not found",
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
if (cls.departmentId && cls.departmentId !== template.departmentId) {
|
|
265
|
+
throw new TRPCError({
|
|
266
|
+
code: "FORBIDDEN",
|
|
267
|
+
message: "This template belongs to a different department than the class",
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
return prisma.markScheme.create({
|
|
271
|
+
data: {
|
|
272
|
+
class: { connect: { id: input.classId } },
|
|
273
|
+
structured: template.structured,
|
|
274
|
+
name: template.name,
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
export async function applyBoundaryTemplate(userId, input) {
|
|
279
|
+
const cls = await prisma.class.findFirst({
|
|
280
|
+
where: {
|
|
281
|
+
id: input.classId,
|
|
282
|
+
OR: [
|
|
283
|
+
{ teachers: { some: { id: userId } } },
|
|
284
|
+
{
|
|
285
|
+
school: {
|
|
286
|
+
memberships: {
|
|
287
|
+
some: { userId, role: "ADMIN", status: "ACTIVE" },
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
],
|
|
292
|
+
},
|
|
293
|
+
select: { id: true, departmentId: true },
|
|
294
|
+
});
|
|
295
|
+
if (!cls) {
|
|
296
|
+
throw new TRPCError({
|
|
297
|
+
code: "FORBIDDEN",
|
|
298
|
+
message: "You don't have permission to apply templates to this class",
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
const template = await prisma.gradingBoundary.findUnique({
|
|
302
|
+
where: { id: input.templateId },
|
|
303
|
+
select: { id: true, structured: true, departmentId: true, name: true },
|
|
304
|
+
});
|
|
305
|
+
if (!template?.departmentId) {
|
|
306
|
+
throw new TRPCError({
|
|
307
|
+
code: "NOT_FOUND",
|
|
308
|
+
message: "Template not found",
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
if (cls.departmentId && cls.departmentId !== template.departmentId) {
|
|
312
|
+
throw new TRPCError({
|
|
313
|
+
code: "FORBIDDEN",
|
|
314
|
+
message: "This template belongs to a different department than the class",
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
return prisma.gradingBoundary.create({
|
|
318
|
+
data: {
|
|
319
|
+
class: { connect: { id: input.classId } },
|
|
320
|
+
structured: template.structured,
|
|
321
|
+
name: template.name,
|
|
322
|
+
},
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
/** Helper used by the auto-tag flow on class creation. */
|
|
326
|
+
export async function setClassDepartment(userId, input) {
|
|
327
|
+
const cls = await prisma.class.findFirst({
|
|
328
|
+
where: {
|
|
329
|
+
id: input.classId,
|
|
330
|
+
OR: [
|
|
331
|
+
{ teachers: { some: { id: userId } } },
|
|
332
|
+
{
|
|
333
|
+
school: {
|
|
334
|
+
memberships: {
|
|
335
|
+
some: { userId, role: "ADMIN", status: "ACTIVE" },
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
},
|
|
341
|
+
select: { id: true, schoolId: true },
|
|
342
|
+
});
|
|
343
|
+
if (!cls?.schoolId) {
|
|
344
|
+
throw new TRPCError({
|
|
345
|
+
code: "BAD_REQUEST",
|
|
346
|
+
message: "Class is not affiliated with an institution",
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
if (input.departmentId) {
|
|
350
|
+
const dept = await getDepartment(input.departmentId);
|
|
351
|
+
if (!dept || dept.schoolId !== cls.schoolId) {
|
|
352
|
+
throw new TRPCError({
|
|
353
|
+
code: "BAD_REQUEST",
|
|
354
|
+
message: "Department does not belong to this institution",
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return prisma.class.update({
|
|
359
|
+
where: { id: input.classId },
|
|
360
|
+
data: { departmentId: input.departmentId },
|
|
361
|
+
select: { id: true, departmentId: true },
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
export async function checkDepartmentMember(userId, departmentId) {
|
|
365
|
+
return Boolean(await findDepartmentMembership(departmentId, userId));
|
|
366
|
+
}
|
|
367
|
+
//# sourceMappingURL=department.js.map
|
|
368
|
+
//# debugId=a61f9d68-eb30-571c-908d-8c1fb445f85c
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"department.js","sources":["services/department.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Department service — admin CRUD, members, and template management for\n * department-level rubrics and grading boundaries.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { prisma } from \"../lib/prisma.js\";\nimport {\n addDepartmentMembers,\n createDepartment,\n deleteDepartment,\n findDepartmentMembership,\n getDepartment,\n listDepartmentsForSchool,\n listDepartmentsForUser,\n removeDepartmentMember,\n updateDepartment,\n} from \"../models/department.js\";\nimport {\n findActiveSchoolAdminMembership,\n findSchoolMembership,\n} from \"../models/school.js\";\n\nasync function requireAdmin(schoolId: string, userId: string) {\n const membership = await findActiveSchoolAdminMembership(schoolId, userId);\n if (!membership) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only school admins can manage departments\",\n });\n }\n}\n\nasync function requireMember(schoolId: string, userId: string) {\n const membership = await findSchoolMembership(schoolId, userId);\n if (!membership || membership.status !== \"ACTIVE\") {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You aren't a member of this institution\",\n });\n }\n}\n\nexport async function listDepartments(\n userId: string,\n schoolId: string\n) {\n await requireMember(schoolId, userId);\n return listDepartmentsForSchool(schoolId);\n}\n\nexport async function listMyDepartments(\n userId: string,\n schoolId: string\n) {\n await requireMember(schoolId, userId);\n return listDepartmentsForUser(userId, schoolId);\n}\n\nexport async function getDepartmentDetails(\n userId: string,\n departmentId: string\n) {\n const department = await getDepartment(departmentId);\n if (!department) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Department not found\",\n });\n }\n await requireMember(department.schoolId, userId);\n return department;\n}\n\nexport async function createDepartmentRecord(\n userId: string,\n input: {\n schoolId: string;\n name: string;\n description?: string;\n color?: string;\n }\n) {\n await requireAdmin(input.schoolId, userId);\n return createDepartment(input);\n}\n\nexport async function updateDepartmentRecord(\n userId: string,\n input: {\n departmentId: string;\n name?: string;\n description?: string | null;\n color?: string;\n }\n) {\n const department = await getDepartment(input.departmentId);\n if (!department) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Department not found\",\n });\n }\n await requireAdmin(department.schoolId, userId);\n return updateDepartment(input.departmentId, {\n name: input.name,\n description: input.description,\n color: input.color,\n });\n}\n\nexport async function deleteDepartmentRecord(\n userId: string,\n departmentId: string\n) {\n const department = await getDepartment(departmentId);\n if (!department) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Department not found\",\n });\n }\n await requireAdmin(department.schoolId, userId);\n await deleteDepartment(departmentId);\n return { success: true };\n}\n\nexport async function addMembersToDepartment(\n userId: string,\n input: { departmentId: string; userIds: string[] }\n) {\n const department = await getDepartment(input.departmentId);\n if (!department) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Department not found\",\n });\n }\n await requireAdmin(department.schoolId, userId);\n\n // Members must already be in the institution.\n const memberships = await prisma.schoolMembership.findMany({\n where: {\n schoolId: department.schoolId,\n userId: { in: input.userIds },\n status: \"ACTIVE\",\n },\n select: { userId: true },\n });\n const validIds = new Set(memberships.map((m) => m.userId));\n const validUserIds = input.userIds.filter((id) => validIds.has(id));\n\n if (validUserIds.length === 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"None of the supplied users are institution members\",\n });\n }\n return addDepartmentMembers(input.departmentId, validUserIds);\n}\n\nexport async function removeMemberFromDepartment(\n userId: string,\n input: { departmentId: string; memberId: string }\n) {\n const department = await getDepartment(input.departmentId);\n if (!department) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Department not found\",\n });\n }\n await requireAdmin(department.schoolId, userId);\n return removeDepartmentMember(input.departmentId, input.memberId);\n}\n\n/** Department template authoring (rubrics + boundaries). */\nexport async function createRubricTemplate(\n userId: string,\n input: { departmentId: string; name: string; structured: string }\n) {\n const department = await getDepartment(input.departmentId);\n if (!department) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Department not found\",\n });\n }\n await requireAdmin(department.schoolId, userId);\n return prisma.markScheme.create({\n data: {\n name: input.name,\n structured: input.structured.replace(/\\\\n/g, \"\\n\"),\n department: { connect: { id: input.departmentId } },\n },\n select: { id: true, name: true, structured: true, departmentId: true },\n });\n}\n\nexport async function updateRubricTemplate(\n userId: string,\n input: {\n templateId: string;\n name?: string;\n structured?: string;\n }\n) {\n const template = await prisma.markScheme.findUnique({\n where: { id: input.templateId },\n select: { departmentId: true, department: { select: { schoolId: true } } },\n });\n if (!template?.departmentId || !template.department) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Template not found\",\n });\n }\n await requireAdmin(template.department.schoolId, userId);\n return prisma.markScheme.update({\n where: { id: input.templateId },\n data: {\n ...(input.name !== undefined ? { name: input.name } : {}),\n ...(input.structured !== undefined\n ? { structured: input.structured.replace(/\\\\n/g, \"\\n\") }\n : {}),\n },\n });\n}\n\nexport async function deleteRubricTemplate(\n userId: string,\n templateId: string\n) {\n const template = await prisma.markScheme.findUnique({\n where: { id: templateId },\n select: { departmentId: true, department: { select: { schoolId: true } } },\n });\n if (!template?.departmentId || !template.department) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Template not found\",\n });\n }\n await requireAdmin(template.department.schoolId, userId);\n return prisma.markScheme.delete({ where: { id: templateId } });\n}\n\nexport async function createBoundaryTemplate(\n userId: string,\n input: { departmentId: string; name: string; structured: string }\n) {\n const department = await getDepartment(input.departmentId);\n if (!department) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Department not found\",\n });\n }\n await requireAdmin(department.schoolId, userId);\n return prisma.gradingBoundary.create({\n data: {\n name: input.name,\n structured: input.structured.replace(/\\\\n/g, \"\\n\"),\n department: { connect: { id: input.departmentId } },\n },\n select: { id: true, name: true, structured: true, departmentId: true },\n });\n}\n\nexport async function updateBoundaryTemplate(\n userId: string,\n input: {\n templateId: string;\n name?: string;\n structured?: string;\n }\n) {\n const template = await prisma.gradingBoundary.findUnique({\n where: { id: input.templateId },\n select: { departmentId: true, department: { select: { schoolId: true } } },\n });\n if (!template?.departmentId || !template.department) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Template not found\",\n });\n }\n await requireAdmin(template.department.schoolId, userId);\n return prisma.gradingBoundary.update({\n where: { id: input.templateId },\n data: {\n ...(input.name !== undefined ? { name: input.name } : {}),\n ...(input.structured !== undefined\n ? { structured: input.structured.replace(/\\\\n/g, \"\\n\") }\n : {}),\n },\n });\n}\n\nexport async function deleteBoundaryTemplate(\n userId: string,\n templateId: string\n) {\n const template = await prisma.gradingBoundary.findUnique({\n where: { id: templateId },\n select: { departmentId: true, department: { select: { schoolId: true } } },\n });\n if (!template?.departmentId || !template.department) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Template not found\",\n });\n }\n await requireAdmin(template.department.schoolId, userId);\n return prisma.gradingBoundary.delete({ where: { id: templateId } });\n}\n\n/**\n * Apply a department template to a class by *copying* the structured payload\n * into a class-scoped record. Teacher-only (the class teacher).\n */\nexport async function applyRubricTemplate(\n userId: string,\n input: { classId: string; templateId: string }\n) {\n const cls = await prisma.class.findFirst({\n where: {\n id: input.classId,\n OR: [\n { teachers: { some: { id: userId } } },\n {\n school: {\n memberships: {\n some: { userId, role: \"ADMIN\", status: \"ACTIVE\" },\n },\n },\n },\n ],\n },\n select: { id: true, departmentId: true },\n });\n if (!cls) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You don't have permission to apply templates to this class\",\n });\n }\n\n const template = await prisma.markScheme.findUnique({\n where: { id: input.templateId },\n select: { id: true, structured: true, departmentId: true, name: true },\n });\n if (!template?.departmentId) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Template not found\",\n });\n }\n if (cls.departmentId && cls.departmentId !== template.departmentId) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message:\n \"This template belongs to a different department than the class\",\n });\n }\n\n return prisma.markScheme.create({\n data: {\n class: { connect: { id: input.classId } },\n structured: template.structured,\n name: template.name,\n },\n });\n}\n\nexport async function applyBoundaryTemplate(\n userId: string,\n input: { classId: string; templateId: string }\n) {\n const cls = await prisma.class.findFirst({\n where: {\n id: input.classId,\n OR: [\n { teachers: { some: { id: userId } } },\n {\n school: {\n memberships: {\n some: { userId, role: \"ADMIN\", status: \"ACTIVE\" },\n },\n },\n },\n ],\n },\n select: { id: true, departmentId: true },\n });\n if (!cls) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You don't have permission to apply templates to this class\",\n });\n }\n\n const template = await prisma.gradingBoundary.findUnique({\n where: { id: input.templateId },\n select: { id: true, structured: true, departmentId: true, name: true },\n });\n if (!template?.departmentId) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Template not found\",\n });\n }\n if (cls.departmentId && cls.departmentId !== template.departmentId) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message:\n \"This template belongs to a different department than the class\",\n });\n }\n\n return prisma.gradingBoundary.create({\n data: {\n class: { connect: { id: input.classId } },\n structured: template.structured,\n name: template.name,\n },\n });\n}\n\n/** Helper used by the auto-tag flow on class creation. */\nexport async function setClassDepartment(\n userId: string,\n input: { classId: string; departmentId: string | null }\n) {\n const cls = await prisma.class.findFirst({\n where: {\n id: input.classId,\n OR: [\n { teachers: { some: { id: userId } } },\n {\n school: {\n memberships: {\n some: { userId, role: \"ADMIN\", status: \"ACTIVE\" },\n },\n },\n },\n ],\n },\n select: { id: true, schoolId: true },\n });\n if (!cls?.schoolId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Class is not affiliated with an institution\",\n });\n }\n\n if (input.departmentId) {\n const dept = await getDepartment(input.departmentId);\n if (!dept || dept.schoolId !== cls.schoolId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Department does not belong to this institution\",\n });\n }\n }\n return prisma.class.update({\n where: { id: input.classId },\n data: { departmentId: input.departmentId },\n select: { id: true, departmentId: true },\n });\n}\n\nexport async function checkDepartmentMember(\n userId: string,\n departmentId: string\n) {\n return Boolean(await findDepartmentMembership(departmentId, userId));\n}\n"],"names":[],"mappings":"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","debug_id":"a61f9d68-eb30-571c-908d-8c1fb445f85c"}
|