@studious-lms/server 1.6.0 → 1.8.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.
Files changed (212) hide show
  1. package/dist/models/access.d.ts +21 -66
  2. package/dist/models/access.d.ts.map +1 -1
  3. package/dist/models/access.js +10 -26
  4. package/dist/models/access.js.map +1 -1
  5. package/dist/models/agenda.d.ts +2 -0
  6. package/dist/models/agenda.d.ts.map +1 -1
  7. package/dist/models/announcement.d.ts +2 -1
  8. package/dist/models/announcement.d.ts.map +1 -1
  9. package/dist/models/announcement.js +2 -3
  10. package/dist/models/announcement.js.map +1 -1
  11. package/dist/models/assignment.d.ts +7 -0
  12. package/dist/models/assignment.d.ts.map +1 -1
  13. package/dist/models/auth.d.ts +2 -4
  14. package/dist/models/auth.d.ts.map +1 -1
  15. package/dist/models/auth.js +2 -3
  16. package/dist/models/auth.js.map +1 -1
  17. package/dist/models/class.d.ts +32 -4
  18. package/dist/models/class.d.ts.map +1 -1
  19. package/dist/models/class.js +15 -2
  20. package/dist/models/class.js.map +1 -1
  21. package/dist/models/cloudStorage.d.ts +140 -0
  22. package/dist/models/cloudStorage.d.ts.map +1 -0
  23. package/dist/models/cloudStorage.js +175 -0
  24. package/dist/models/cloudStorage.js.map +1 -0
  25. package/dist/models/comment.d.ts +0 -24
  26. package/dist/models/comment.d.ts.map +1 -1
  27. package/dist/models/comment.js +2 -6
  28. package/dist/models/comment.js.map +1 -1
  29. package/dist/models/conversation.d.ts +38 -22
  30. package/dist/models/conversation.d.ts.map +1 -1
  31. package/dist/models/conversation.js +50 -2
  32. package/dist/models/conversation.js.map +1 -1
  33. package/dist/models/department.d.ts +154 -0
  34. package/dist/models/department.d.ts.map +1 -0
  35. package/dist/models/department.js +135 -0
  36. package/dist/models/department.js.map +1 -0
  37. package/dist/models/event.d.ts +7 -1
  38. package/dist/models/event.d.ts.map +1 -1
  39. package/dist/models/event.js +2 -5
  40. package/dist/models/event.js.map +1 -1
  41. package/dist/models/file.d.ts +25 -10
  42. package/dist/models/file.d.ts.map +1 -1
  43. package/dist/models/file.js +2 -5
  44. package/dist/models/file.js.map +1 -1
  45. package/dist/models/folder.d.ts +47 -0
  46. package/dist/models/folder.d.ts.map +1 -1
  47. package/dist/models/labChat.d.ts +5 -3
  48. package/dist/models/labChat.d.ts.map +1 -1
  49. package/dist/models/message.d.ts +46 -12
  50. package/dist/models/message.d.ts.map +1 -1
  51. package/dist/models/message.js +19 -10
  52. package/dist/models/message.js.map +1 -1
  53. package/dist/models/newtonChat.d.ts +2 -1
  54. package/dist/models/newtonChat.d.ts.map +1 -1
  55. package/dist/models/school.d.ts +45 -12
  56. package/dist/models/school.d.ts.map +1 -1
  57. package/dist/models/school.js +19 -2
  58. package/dist/models/school.js.map +1 -1
  59. package/dist/models/section.d.ts +1 -0
  60. package/dist/models/section.d.ts.map +1 -1
  61. package/dist/models/tag.d.ts +117 -0
  62. package/dist/models/tag.d.ts.map +1 -0
  63. package/dist/models/tag.js +113 -0
  64. package/dist/models/tag.js.map +1 -0
  65. package/dist/models/worksheet.d.ts +3 -0
  66. package/dist/models/worksheet.d.ts.map +1 -1
  67. package/dist/pipelines/aiLabChatContract.d.ts +8 -8
  68. package/dist/routers/_app.d.ts +3556 -2298
  69. package/dist/routers/_app.d.ts.map +1 -1
  70. package/dist/routers/_app.js +6 -2
  71. package/dist/routers/_app.js.map +1 -1
  72. package/dist/routers/agenda.d.ts +2 -0
  73. package/dist/routers/agenda.d.ts.map +1 -1
  74. package/dist/routers/announcement.d.ts.map +1 -1
  75. package/dist/routers/announcement.js +3 -5
  76. package/dist/routers/announcement.js.map +1 -1
  77. package/dist/routers/assignment.d.ts +18 -9
  78. package/dist/routers/assignment.d.ts.map +1 -1
  79. package/dist/routers/assignment.js +2 -3
  80. package/dist/routers/assignment.js.map +1 -1
  81. package/dist/routers/class.d.ts +87 -14
  82. package/dist/routers/class.d.ts.map +1 -1
  83. package/dist/routers/class.js +5 -2
  84. package/dist/routers/class.js.map +1 -1
  85. package/dist/routers/conversation.d.ts +20 -5
  86. package/dist/routers/conversation.d.ts.map +1 -1
  87. package/dist/routers/conversation.js +6 -3
  88. package/dist/routers/conversation.js.map +1 -1
  89. package/dist/routers/department.d.ts +293 -0
  90. package/dist/routers/department.d.ts.map +1 -0
  91. package/dist/routers/department.js +93 -0
  92. package/dist/routers/department.js.map +1 -0
  93. package/dist/routers/event.d.ts +2 -1
  94. package/dist/routers/event.d.ts.map +1 -1
  95. package/dist/routers/file.d.ts +8 -6
  96. package/dist/routers/file.d.ts.map +1 -1
  97. package/dist/routers/file.js +26 -17
  98. package/dist/routers/file.js.map +1 -1
  99. package/dist/routers/folder.d.ts +139 -186
  100. package/dist/routers/folder.d.ts.map +1 -1
  101. package/dist/routers/folder.js +82 -90
  102. package/dist/routers/folder.js.map +1 -1
  103. package/dist/routers/labChat.d.ts +11 -2
  104. package/dist/routers/labChat.d.ts.map +1 -1
  105. package/dist/routers/message.d.ts +20 -2
  106. package/dist/routers/message.d.ts.map +1 -1
  107. package/dist/routers/newtonChat.d.ts +9 -0
  108. package/dist/routers/newtonChat.d.ts.map +1 -1
  109. package/dist/routers/school.d.ts +160 -17
  110. package/dist/routers/school.d.ts.map +1 -1
  111. package/dist/routers/school.js +46 -3
  112. package/dist/routers/school.js.map +1 -1
  113. package/dist/routers/tag.d.ts +119 -0
  114. package/dist/routers/tag.d.ts.map +1 -0
  115. package/dist/routers/tag.js +52 -0
  116. package/dist/routers/tag.js.map +1 -0
  117. package/dist/routers/worksheet.d.ts +1 -0
  118. package/dist/routers/worksheet.d.ts.map +1 -1
  119. package/dist/seedDatabase.d.ts +0 -1
  120. package/dist/seedDatabase.d.ts.map +1 -1
  121. package/dist/services/agenda.d.ts +2 -0
  122. package/dist/services/agenda.d.ts.map +1 -1
  123. package/dist/services/assignment.d.ts +18 -9
  124. package/dist/services/assignment.d.ts.map +1 -1
  125. package/dist/services/assignment.js +4 -4
  126. package/dist/services/assignment.js.map +1 -1
  127. package/dist/services/class.d.ts +87 -14
  128. package/dist/services/class.d.ts.map +1 -1
  129. package/dist/services/class.js +91 -4
  130. package/dist/services/class.js.map +1 -1
  131. package/dist/services/conversation.d.ts +21 -5
  132. package/dist/services/conversation.d.ts.map +1 -1
  133. package/dist/services/conversation.js +22 -3
  134. package/dist/services/conversation.js.map +1 -1
  135. package/dist/services/department.d.ts +200 -0
  136. package/dist/services/department.d.ts.map +1 -0
  137. package/dist/services/department.js +368 -0
  138. package/dist/services/department.js.map +1 -0
  139. package/dist/services/event.d.ts +2 -1
  140. package/dist/services/event.d.ts.map +1 -1
  141. package/dist/services/file.d.ts +85 -0
  142. package/dist/services/file.d.ts.map +1 -1
  143. package/dist/services/file.js +92 -2
  144. package/dist/services/file.js.map +1 -1
  145. package/dist/services/folder.d.ts +125 -149
  146. package/dist/services/folder.d.ts.map +1 -1
  147. package/dist/services/folder.js +258 -199
  148. package/dist/services/folder.js.map +1 -1
  149. package/dist/services/labChat.d.ts +11 -2
  150. package/dist/services/labChat.d.ts.map +1 -1
  151. package/dist/services/labChat.js +8 -7
  152. package/dist/services/labChat.js.map +1 -1
  153. package/dist/services/message.d.ts +20 -2
  154. package/dist/services/message.d.ts.map +1 -1
  155. package/dist/services/message.js +7 -23
  156. package/dist/services/message.js.map +1 -1
  157. package/dist/services/newtonChat.d.ts +9 -0
  158. package/dist/services/newtonChat.d.ts.map +1 -1
  159. package/dist/services/newtonChat.js +7 -6
  160. package/dist/services/newtonChat.js.map +1 -1
  161. package/dist/services/school.d.ts +142 -15
  162. package/dist/services/school.d.ts.map +1 -1
  163. package/dist/services/school.js +308 -54
  164. package/dist/services/school.js.map +1 -1
  165. package/dist/services/tag.d.ts +71 -0
  166. package/dist/services/tag.d.ts.map +1 -0
  167. package/dist/services/tag.js +178 -0
  168. package/dist/services/tag.js.map +1 -0
  169. package/dist/services/worksheet.d.ts +1 -0
  170. package/dist/services/worksheet.d.ts.map +1 -1
  171. package/dist/utils/aiUser.d.ts.map +1 -1
  172. package/dist/utils/aiUser.js +2 -3
  173. package/dist/utils/aiUser.js.map +1 -1
  174. package/package.json +1 -1
  175. package/prisma/migrations/20260509220000_institution_overhaul/migration.sql +184 -0
  176. package/prisma/schema.prisma +119 -35
  177. package/src/models/access.ts +8 -24
  178. package/src/models/announcement.ts +0 -1
  179. package/src/models/auth.ts +0 -1
  180. package/src/models/class.ts +13 -0
  181. package/src/models/cloudStorage.ts +194 -0
  182. package/src/models/comment.ts +0 -4
  183. package/src/models/conversation.ts +54 -0
  184. package/src/models/department.ts +159 -0
  185. package/src/models/event.ts +0 -3
  186. package/src/models/file.ts +0 -3
  187. package/src/models/message.ts +19 -5
  188. package/src/models/school.ts +26 -0
  189. package/src/models/tag.ts +140 -0
  190. package/src/routers/_app.ts +4 -0
  191. package/src/routers/announcement.ts +1 -3
  192. package/src/routers/assignment.ts +0 -1
  193. package/src/routers/class.ts +3 -0
  194. package/src/routers/conversation.ts +7 -0
  195. package/src/routers/department.ts +174 -0
  196. package/src/routers/file.ts +29 -26
  197. package/src/routers/folder.ts +100 -121
  198. package/src/routers/school.ts +83 -0
  199. package/src/routers/tag.ts +78 -0
  200. package/src/services/assignment.ts +2 -3
  201. package/src/services/class.ts +108 -3
  202. package/src/services/conversation.ts +30 -0
  203. package/src/services/department.ts +478 -0
  204. package/src/services/file.ts +100 -0
  205. package/src/services/folder.ts +313 -240
  206. package/src/services/labChat.ts +7 -6
  207. package/src/services/message.ts +5 -21
  208. package/src/services/newtonChat.ts +5 -5
  209. package/src/services/school.ts +369 -57
  210. package/src/services/tag.ts +229 -0
  211. package/src/utils/aiUser.ts +0 -1
  212. package/tests/integration/routers/conversation.test.ts +121 -2
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Tag service — institution-scoped tag CRUD and assignment to taggable
3
+ * targets (users, classes, rubrics, boundaries).
4
+ */
5
+ import { TRPCError } from "@trpc/server";
6
+ import { prisma } from "../lib/prisma.js";
7
+ import {
8
+ attachTagToTarget,
9
+ createTag,
10
+ deleteTag,
11
+ detachTagFromTarget,
12
+ getTag,
13
+ listTagsAttachedTo,
14
+ listTagsForSchool,
15
+ type TagTarget,
16
+ updateTag,
17
+ } from "../models/tag.js";
18
+ import {
19
+ findActiveSchoolAdminMembership,
20
+ findSchoolMembership,
21
+ } from "../models/school.js";
22
+
23
+ async function requireAdmin(schoolId: string, userId: string) {
24
+ const membership = await findActiveSchoolAdminMembership(schoolId, userId);
25
+ if (!membership) {
26
+ throw new TRPCError({
27
+ code: "FORBIDDEN",
28
+ message: "Only school admins can manage tags",
29
+ });
30
+ }
31
+ }
32
+
33
+ async function requireMember(schoolId: string, userId: string) {
34
+ const membership = await findSchoolMembership(schoolId, userId);
35
+ if (!membership || membership.status !== "ACTIVE") {
36
+ throw new TRPCError({
37
+ code: "FORBIDDEN",
38
+ message: "You aren't a member of this institution",
39
+ });
40
+ }
41
+ return membership;
42
+ }
43
+
44
+ export async function listTags(
45
+ userId: string,
46
+ input: { schoolId: string; departmentId?: string | null }
47
+ ) {
48
+ await requireMember(input.schoolId, userId);
49
+ return listTagsForSchool(input.schoolId, {
50
+ departmentId: input.departmentId,
51
+ });
52
+ }
53
+
54
+ export async function createTagRecord(
55
+ userId: string,
56
+ input: {
57
+ schoolId: string;
58
+ departmentId?: string | null;
59
+ name: string;
60
+ color?: string;
61
+ }
62
+ ) {
63
+ await requireAdmin(input.schoolId, userId);
64
+ if (input.departmentId) {
65
+ const dept = await prisma.department.findUnique({
66
+ where: { id: input.departmentId },
67
+ select: { schoolId: true },
68
+ });
69
+ if (!dept || dept.schoolId !== input.schoolId) {
70
+ throw new TRPCError({
71
+ code: "BAD_REQUEST",
72
+ message: "Department does not belong to this institution",
73
+ });
74
+ }
75
+ }
76
+ return createTag(input);
77
+ }
78
+
79
+ export async function updateTagRecord(
80
+ userId: string,
81
+ input: {
82
+ tagId: string;
83
+ name?: string;
84
+ color?: string;
85
+ departmentId?: string | null;
86
+ }
87
+ ) {
88
+ const tag = await getTag(input.tagId);
89
+ if (!tag) {
90
+ throw new TRPCError({ code: "NOT_FOUND", message: "Tag not found" });
91
+ }
92
+ await requireAdmin(tag.schoolId, userId);
93
+ if (input.departmentId) {
94
+ const dept = await prisma.department.findUnique({
95
+ where: { id: input.departmentId },
96
+ select: { schoolId: true },
97
+ });
98
+ if (!dept || dept.schoolId !== tag.schoolId) {
99
+ throw new TRPCError({
100
+ code: "BAD_REQUEST",
101
+ message: "Department does not belong to this institution",
102
+ });
103
+ }
104
+ }
105
+ return updateTag(input.tagId, {
106
+ name: input.name,
107
+ color: input.color,
108
+ departmentId: input.departmentId,
109
+ });
110
+ }
111
+
112
+ export async function deleteTagRecord(userId: string, tagId: string) {
113
+ const tag = await getTag(tagId);
114
+ if (!tag) {
115
+ throw new TRPCError({ code: "NOT_FOUND", message: "Tag not found" });
116
+ }
117
+ await requireAdmin(tag.schoolId, userId);
118
+ await deleteTag(tagId);
119
+ return { success: true };
120
+ }
121
+
122
+ async function ensureTargetInScope(
123
+ schoolId: string,
124
+ target: TagTarget,
125
+ targetId: string
126
+ ) {
127
+ switch (target) {
128
+ case "USER": {
129
+ const inSchool = await prisma.schoolMembership.findFirst({
130
+ where: { schoolId, userId: targetId, status: "ACTIVE" },
131
+ select: { id: true },
132
+ });
133
+ if (!inSchool) {
134
+ throw new TRPCError({
135
+ code: "BAD_REQUEST",
136
+ message: "User is not in this institution",
137
+ });
138
+ }
139
+ return;
140
+ }
141
+ case "CLASS": {
142
+ const inSchool = await prisma.class.findFirst({
143
+ where: { id: targetId, schoolId },
144
+ select: { id: true },
145
+ });
146
+ if (!inSchool) {
147
+ throw new TRPCError({
148
+ code: "BAD_REQUEST",
149
+ message: "Class is not in this institution",
150
+ });
151
+ }
152
+ return;
153
+ }
154
+ case "RUBRIC": {
155
+ const inSchool = await prisma.markScheme.findFirst({
156
+ where: {
157
+ id: targetId,
158
+ OR: [
159
+ { class: { schoolId } },
160
+ { department: { schoolId } },
161
+ ],
162
+ },
163
+ select: { id: true },
164
+ });
165
+ if (!inSchool) {
166
+ throw new TRPCError({
167
+ code: "BAD_REQUEST",
168
+ message: "Rubric is not in this institution",
169
+ });
170
+ }
171
+ return;
172
+ }
173
+ case "BOUNDARY": {
174
+ const inSchool = await prisma.gradingBoundary.findFirst({
175
+ where: {
176
+ id: targetId,
177
+ OR: [
178
+ { class: { schoolId } },
179
+ { department: { schoolId } },
180
+ ],
181
+ },
182
+ select: { id: true },
183
+ });
184
+ if (!inSchool) {
185
+ throw new TRPCError({
186
+ code: "BAD_REQUEST",
187
+ message: "Boundary is not in this institution",
188
+ });
189
+ }
190
+ return;
191
+ }
192
+ }
193
+ }
194
+
195
+ export async function attachTag(
196
+ userId: string,
197
+ input: { tagId: string; target: TagTarget; targetId: string }
198
+ ) {
199
+ const tag = await getTag(input.tagId);
200
+ if (!tag) {
201
+ throw new TRPCError({ code: "NOT_FOUND", message: "Tag not found" });
202
+ }
203
+ await requireMember(tag.schoolId, userId);
204
+ await ensureTargetInScope(tag.schoolId, input.target, input.targetId);
205
+ return attachTagToTarget(input);
206
+ }
207
+
208
+ export async function detachTag(
209
+ userId: string,
210
+ input: { tagId: string; target: TagTarget; targetId: string }
211
+ ) {
212
+ const tag = await getTag(input.tagId);
213
+ if (!tag) {
214
+ throw new TRPCError({ code: "NOT_FOUND", message: "Tag not found" });
215
+ }
216
+ await requireMember(tag.schoolId, userId);
217
+ return detachTagFromTarget(input);
218
+ }
219
+
220
+ export async function getAttachedTags(
221
+ userId: string,
222
+ input: { target: TagTarget; targetId: string }
223
+ ) {
224
+ const tags = await listTagsAttachedTo(input.target, input.targetId);
225
+ if (tags[0]) {
226
+ await requireMember(tags[0].schoolId, userId);
227
+ }
228
+ return tags;
229
+ }
@@ -26,7 +26,6 @@ export async function ensureAIUserExists(): Promise<void> {
26
26
  email: 'ai@studious-lms.com',
27
27
  password: 'ai-system-user', // Not used for login
28
28
  verified: true,
29
- role: 'NONE', // Special role for AI
30
29
  profile: {
31
30
  create: {
32
31
  displayName: 'AI Assistant',
@@ -1,4 +1,4 @@
1
- import { test, expect, describe, beforeAll } from 'vitest';
1
+ import { test, expect, describe, beforeAll, afterAll } from 'vitest';
2
2
  import { prisma } from '../../../src/lib/prisma';
3
3
  import { user1Caller, user2Caller, user3Caller } from '../setup';
4
4
  import { expectUnauth } from '../helpers';
@@ -7,16 +7,19 @@ describe('Conversation Router', () => {
7
7
  let dmConversation: any;
8
8
  let groupConversation: any;
9
9
  let user1Id: string;
10
+ let user2Id: string;
10
11
  let user3Id: string;
11
12
  let hideConversationCounter = 0;
12
13
 
13
14
  beforeAll(async () => {
14
- const [user1Profile, user3Profile] = await Promise.all([
15
+ const [user1Profile, user2Profile, user3Profile] = await Promise.all([
15
16
  user1Caller.user.getProfile(),
17
+ user2Caller.user.getProfile(),
16
18
  user3Caller.user.getProfile(),
17
19
  ]);
18
20
 
19
21
  user1Id = user1Profile.id;
22
+ user2Id = user2Profile.id;
20
23
  user3Id = user3Profile.id;
21
24
  });
22
25
 
@@ -89,6 +92,122 @@ describe('Conversation Router', () => {
89
92
  });
90
93
  });
91
94
 
95
+ describe('searchMembers', () => {
96
+ let schoolId: string;
97
+ let previousUser2DisplayName: string | null = null;
98
+ let user2ProfileExisted = false;
99
+
100
+ beforeAll(async () => {
101
+ const existingProfile = await prisma.userProfile.findUnique({
102
+ where: { userId: user2Id },
103
+ select: { displayName: true },
104
+ });
105
+ user2ProfileExisted = Boolean(existingProfile);
106
+ previousUser2DisplayName = existingProfile?.displayName ?? null;
107
+
108
+ const school = await prisma.school.create({
109
+ data: {
110
+ name: 'Conversation Search School',
111
+ memberships: {
112
+ create: [
113
+ { userId: user1Id, role: 'TEACHER', status: 'ACTIVE' },
114
+ { userId: user2Id, role: 'STUDENT', status: 'ACTIVE' },
115
+ ],
116
+ },
117
+ },
118
+ });
119
+ schoolId = school.id;
120
+
121
+ await prisma.userProfile.upsert({
122
+ where: { userId: user2Id },
123
+ update: { displayName: 'Searchable Student' },
124
+ create: { userId: user2Id, displayName: 'Searchable Student' },
125
+ });
126
+ });
127
+
128
+ test('should search active institution members by username', async () => {
129
+ const results = await user1Caller.conversation.searchMembers({
130
+ query: 'testuser2',
131
+ });
132
+
133
+ expect(results.map((user) => user.id)).toContain(user2Id);
134
+ expect(results.map((user) => user.id)).not.toContain(user1Id);
135
+ expect(results.map((user) => user.id)).not.toContain(user3Id);
136
+ });
137
+
138
+ test('should not search active institution members for one-character queries', async () => {
139
+ const results = await user1Caller.conversation.searchMembers({
140
+ query: 't',
141
+ });
142
+
143
+ expect(results).toEqual([]);
144
+ });
145
+
146
+ test('should search active institution members by display name', async () => {
147
+ const results = await user1Caller.conversation.searchMembers({
148
+ query: 'searchable',
149
+ });
150
+
151
+ expect(results).toEqual(
152
+ expect.arrayContaining([
153
+ expect.objectContaining({
154
+ id: user2Id,
155
+ username: 'testuser2',
156
+ profile: expect.objectContaining({
157
+ displayName: 'Searchable Student',
158
+ }),
159
+ }),
160
+ ]),
161
+ );
162
+ });
163
+
164
+ test('should not expose users outside the requester institution', async () => {
165
+ const results = await user1Caller.conversation.searchMembers({
166
+ query: 'testuser3',
167
+ });
168
+
169
+ expect(results).toEqual([]);
170
+ });
171
+
172
+ test('should not expose inactive members from the requester institution', async () => {
173
+ await prisma.schoolMembership.create({
174
+ data: {
175
+ schoolId,
176
+ userId: user3Id,
177
+ role: 'STUDENT',
178
+ status: 'INACTIVE',
179
+ },
180
+ });
181
+
182
+ const results = await user1Caller.conversation.searchMembers({
183
+ query: 'testuser3',
184
+ });
185
+
186
+ expect(results).toEqual([]);
187
+ });
188
+
189
+ test('should return no institution search results for users without an active school', async () => {
190
+ const results = await user3Caller.conversation.searchMembers({
191
+ query: 'testuser1',
192
+ });
193
+
194
+ expect(results).toEqual([]);
195
+ });
196
+
197
+ afterAll(async () => {
198
+ if (user2ProfileExisted) {
199
+ await prisma.userProfile.update({
200
+ where: { userId: user2Id },
201
+ data: { displayName: previousUser2DisplayName },
202
+ });
203
+ } else {
204
+ await prisma.userProfile.deleteMany({ where: { userId: user2Id } });
205
+ }
206
+
207
+ await prisma.school.delete({ where: { id: schoolId } });
208
+ });
209
+ });
210
+
92
211
  describe('get', () => {
93
212
  test('should get conversation by ID', async () => {
94
213
  const conversation = await user1Caller.conversation.get({