@studious-lms/server 1.1.24 → 1.2.6

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 (485) hide show
  1. package/.coderabbit.yaml +9 -0
  2. package/.env.example +53 -0
  3. package/.env.test.example +37 -0
  4. package/README.md +34 -7
  5. package/dist/exportType.d.ts.map +1 -1
  6. package/dist/exportType.js +4 -0
  7. package/dist/exportType.js.map +1 -0
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +212 -51
  11. package/dist/index.js.map +1 -0
  12. package/dist/instrument.d.ts +2 -0
  13. package/dist/instrument.d.ts.map +1 -0
  14. package/dist/instrument.js +18 -0
  15. package/dist/instrument.js.map +1 -0
  16. package/dist/lib/config/env.d.ts +190 -0
  17. package/dist/lib/config/env.d.ts.map +1 -0
  18. package/dist/lib/config/env.js +121 -0
  19. package/dist/lib/config/env.js.map +1 -0
  20. package/dist/lib/fileUpload.d.ts +2 -2
  21. package/dist/lib/fileUpload.d.ts.map +1 -1
  22. package/dist/lib/fileUpload.js +82 -15
  23. package/dist/lib/fileUpload.js.map +1 -0
  24. package/dist/lib/googleCloudStorage.d.ts +13 -0
  25. package/dist/lib/googleCloudStorage.d.ts.map +1 -1
  26. package/dist/lib/googleCloudStorage.js +45 -6
  27. package/dist/lib/googleCloudStorage.js.map +1 -0
  28. package/dist/lib/jsonConversion.d.ts.map +1 -1
  29. package/dist/lib/jsonConversion.js +16 -14
  30. package/dist/lib/jsonConversion.js.map +1 -0
  31. package/dist/lib/jsonStyles.d.ts.map +1 -1
  32. package/dist/lib/jsonStyles.js +4 -0
  33. package/dist/lib/jsonStyles.js.map +1 -0
  34. package/dist/lib/notificationHandler.d.ts +25 -0
  35. package/dist/lib/notificationHandler.d.ts.map +1 -0
  36. package/dist/lib/notificationHandler.js +32 -0
  37. package/dist/lib/notificationHandler.js.map +1 -0
  38. package/dist/lib/prisma.d.ts +2 -2
  39. package/dist/lib/prisma.d.ts.map +1 -1
  40. package/dist/lib/prisma.js +24 -1
  41. package/dist/lib/prisma.js.map +1 -0
  42. package/dist/lib/pusher.d.ts +4 -1
  43. package/dist/lib/pusher.d.ts.map +1 -1
  44. package/dist/lib/pusher.js +14 -6
  45. package/dist/lib/pusher.js.map +1 -0
  46. package/dist/lib/redis.d.ts +5 -0
  47. package/dist/lib/redis.d.ts.map +1 -0
  48. package/dist/lib/redis.js +53 -0
  49. package/dist/lib/redis.js.map +1 -0
  50. package/dist/lib/thumbnailGenerator.d.ts +0 -21
  51. package/dist/lib/thumbnailGenerator.d.ts.map +1 -1
  52. package/dist/lib/thumbnailGenerator.js +159 -158
  53. package/dist/lib/thumbnailGenerator.js.map +1 -0
  54. package/dist/middleware/auth.d.ts.map +1 -1
  55. package/dist/middleware/auth.js +41 -93
  56. package/dist/middleware/auth.js.map +1 -0
  57. package/dist/middleware/logging.d.ts.map +1 -1
  58. package/dist/middleware/logging.js +4 -0
  59. package/dist/middleware/logging.js.map +1 -0
  60. package/dist/middleware/security.d.ts +5 -0
  61. package/dist/middleware/security.d.ts.map +1 -0
  62. package/dist/middleware/security.js +77 -0
  63. package/dist/middleware/security.js.map +1 -0
  64. package/dist/models/agenda.d.ts +97 -0
  65. package/dist/models/agenda.d.ts.map +1 -0
  66. package/dist/models/agenda.js +40 -0
  67. package/dist/models/agenda.js.map +1 -0
  68. package/dist/models/announcement.d.ts +223 -0
  69. package/dist/models/announcement.d.ts.map +1 -0
  70. package/dist/models/announcement.js +120 -0
  71. package/dist/models/announcement.js.map +1 -0
  72. package/dist/models/assignment.d.ts +1292 -0
  73. package/dist/models/assignment.d.ts.map +1 -0
  74. package/dist/models/assignment.js +309 -0
  75. package/dist/models/assignment.js.map +1 -0
  76. package/dist/models/attendance.d.ts +180 -0
  77. package/dist/models/attendance.d.ts.map +1 -0
  78. package/dist/models/attendance.js +188 -0
  79. package/dist/models/attendance.js.map +1 -0
  80. package/dist/models/auth.d.ts +153 -0
  81. package/dist/models/auth.d.ts.map +1 -0
  82. package/dist/models/auth.js +217 -0
  83. package/dist/models/auth.js.map +1 -0
  84. package/dist/models/class.d.ts +439 -0
  85. package/dist/models/class.d.ts.map +1 -0
  86. package/dist/models/class.js +546 -0
  87. package/dist/models/class.js.map +1 -0
  88. package/dist/models/comment.d.ts +171 -0
  89. package/dist/models/comment.d.ts.map +1 -0
  90. package/dist/models/comment.js +138 -0
  91. package/dist/models/comment.js.map +1 -0
  92. package/dist/models/conversation.d.ts +164 -0
  93. package/dist/models/conversation.d.ts.map +1 -0
  94. package/dist/models/conversation.js +175 -0
  95. package/dist/models/conversation.js.map +1 -0
  96. package/dist/models/event.d.ts +295 -0
  97. package/dist/models/event.d.ts.map +1 -0
  98. package/dist/models/event.js +145 -0
  99. package/dist/models/event.js.map +1 -0
  100. package/dist/models/file.d.ts +536 -0
  101. package/dist/models/file.d.ts.map +1 -0
  102. package/dist/models/file.js +126 -0
  103. package/dist/models/file.js.map +1 -0
  104. package/dist/models/folder.d.ts +295 -0
  105. package/dist/models/folder.d.ts.map +1 -0
  106. package/dist/models/folder.js +202 -0
  107. package/dist/models/folder.js.map +1 -0
  108. package/dist/models/labChat.d.ts +243 -0
  109. package/dist/models/labChat.d.ts.map +1 -0
  110. package/dist/models/labChat.js +204 -0
  111. package/dist/models/labChat.js.map +1 -0
  112. package/dist/models/marketing.d.ts +72 -0
  113. package/dist/models/marketing.d.ts.map +1 -0
  114. package/dist/models/marketing.js +26 -0
  115. package/dist/models/marketing.js.map +1 -0
  116. package/dist/models/message.d.ts +100 -0
  117. package/dist/models/message.d.ts.map +1 -0
  118. package/dist/models/message.js +131 -0
  119. package/dist/models/message.js.map +1 -0
  120. package/dist/models/newtonChat.d.ts +72 -0
  121. package/dist/models/newtonChat.d.ts.map +1 -0
  122. package/dist/models/newtonChat.js +61 -0
  123. package/dist/models/newtonChat.js.map +1 -0
  124. package/dist/models/notification.d.ts +65 -0
  125. package/dist/models/notification.d.ts.map +1 -0
  126. package/dist/models/notification.js +46 -0
  127. package/dist/models/notification.js.map +1 -0
  128. package/dist/models/section.d.ts +102 -0
  129. package/dist/models/section.d.ts.map +1 -0
  130. package/dist/models/section.js +83 -0
  131. package/dist/models/section.js.map +1 -0
  132. package/dist/models/user.d.ts +39 -0
  133. package/dist/models/user.d.ts.map +1 -0
  134. package/dist/models/user.js +38 -0
  135. package/dist/models/user.js.map +1 -0
  136. package/dist/models/worksheet.d.ts +460 -0
  137. package/dist/models/worksheet.d.ts.map +1 -0
  138. package/dist/models/worksheet.js +200 -0
  139. package/dist/models/worksheet.js.map +1 -0
  140. package/dist/pipelines/aiLabChat.d.ts +21 -0
  141. package/dist/pipelines/aiLabChat.d.ts.map +1 -0
  142. package/dist/pipelines/aiLabChat.js +460 -0
  143. package/dist/pipelines/aiLabChat.js.map +1 -0
  144. package/dist/pipelines/aiNewtonChat.d.ts +30 -0
  145. package/dist/pipelines/aiNewtonChat.d.ts.map +1 -0
  146. package/dist/pipelines/aiNewtonChat.js +289 -0
  147. package/dist/pipelines/aiNewtonChat.js.map +1 -0
  148. package/dist/pipelines/gradeWorksheet.d.ts +30 -0
  149. package/dist/pipelines/gradeWorksheet.d.ts.map +1 -0
  150. package/dist/pipelines/gradeWorksheet.js +252 -0
  151. package/dist/pipelines/gradeWorksheet.js.map +1 -0
  152. package/dist/routers/_app.d.ts +6403 -3741
  153. package/dist/routers/_app.d.ts.map +1 -1
  154. package/dist/routers/_app.js +10 -0
  155. package/dist/routers/_app.js.map +1 -0
  156. package/dist/routers/agenda.d.ts +58 -6
  157. package/dist/routers/agenda.d.ts.map +1 -1
  158. package/dist/routers/agenda.js +6 -58
  159. package/dist/routers/agenda.js.map +1 -0
  160. package/dist/routers/announcement.d.ts +325 -6
  161. package/dist/routers/announcement.d.ts.map +1 -1
  162. package/dist/routers/announcement.js +547 -57
  163. package/dist/routers/announcement.js.map +1 -0
  164. package/dist/routers/assignment.d.ts +431 -318
  165. package/dist/routers/assignment.d.ts.map +1 -1
  166. package/dist/routers/assignment.js +104 -1559
  167. package/dist/routers/assignment.js.map +1 -0
  168. package/dist/routers/attendance.d.ts +20 -9
  169. package/dist/routers/attendance.d.ts.map +1 -1
  170. package/dist/routers/attendance.js +10 -263
  171. package/dist/routers/attendance.js.map +1 -0
  172. package/dist/routers/auth.d.ts +21 -1
  173. package/dist/routers/auth.d.ts.map +1 -1
  174. package/dist/routers/auth.js +37 -241
  175. package/dist/routers/auth.js.map +1 -0
  176. package/dist/routers/class.d.ts +198 -68
  177. package/dist/routers/class.d.ts.map +1 -1
  178. package/dist/routers/class.js +88 -909
  179. package/dist/routers/class.js.map +1 -0
  180. package/dist/routers/comment.d.ts +153 -0
  181. package/dist/routers/comment.d.ts.map +1 -0
  182. package/dist/routers/comment.js +58 -0
  183. package/dist/routers/comment.js.map +1 -0
  184. package/dist/routers/conversation.d.ts +73 -3
  185. package/dist/routers/conversation.d.ts.map +1 -1
  186. package/dist/routers/conversation.js +23 -265
  187. package/dist/routers/conversation.js.map +1 -0
  188. package/dist/routers/event.d.ts +46 -37
  189. package/dist/routers/event.d.ts.map +1 -1
  190. package/dist/routers/event.js +15 -431
  191. package/dist/routers/event.js.map +1 -0
  192. package/dist/routers/file.d.ts +4 -2
  193. package/dist/routers/file.d.ts.map +1 -1
  194. package/dist/routers/file.js +11 -295
  195. package/dist/routers/file.js.map +1 -0
  196. package/dist/routers/folder.d.ts +21 -14
  197. package/dist/routers/folder.d.ts.map +1 -1
  198. package/dist/routers/folder.js +36 -743
  199. package/dist/routers/folder.js.map +1 -0
  200. package/dist/routers/labChat.d.ts +12 -9
  201. package/dist/routers/labChat.d.ts.map +1 -1
  202. package/dist/routers/labChat.js +21 -877
  203. package/dist/routers/labChat.js.map +1 -0
  204. package/dist/routers/marketing.d.ts +2 -2
  205. package/dist/routers/marketing.d.ts.map +1 -1
  206. package/dist/routers/marketing.js +9 -54
  207. package/dist/routers/marketing.js.map +1 -0
  208. package/dist/routers/message.d.ts +2 -1
  209. package/dist/routers/message.d.ts.map +1 -1
  210. package/dist/routers/message.js +29 -519
  211. package/dist/routers/message.js.map +1 -0
  212. package/dist/routers/newtonChat.d.ts +55 -0
  213. package/dist/routers/newtonChat.d.ts.map +1 -0
  214. package/dist/routers/newtonChat.js +22 -0
  215. package/dist/routers/newtonChat.js.map +1 -0
  216. package/dist/routers/notifications.d.ts +8 -8
  217. package/dist/routers/notifications.d.ts.map +1 -1
  218. package/dist/routers/notifications.js +20 -81
  219. package/dist/routers/notifications.js.map +1 -0
  220. package/dist/routers/section.d.ts +37 -6
  221. package/dist/routers/section.d.ts.map +1 -1
  222. package/dist/routers/section.js +26 -167
  223. package/dist/routers/section.js.map +1 -0
  224. package/dist/routers/user.d.ts +1 -1
  225. package/dist/routers/user.d.ts.map +1 -1
  226. package/dist/routers/user.js +34 -204
  227. package/dist/routers/user.js.map +1 -0
  228. package/dist/routers/worksheet.d.ts +362 -0
  229. package/dist/routers/worksheet.d.ts.map +1 -0
  230. package/dist/routers/worksheet.js +153 -0
  231. package/dist/routers/worksheet.js.map +1 -0
  232. package/dist/seedDatabase.d.ts +2 -3
  233. package/dist/seedDatabase.d.ts.map +1 -1
  234. package/dist/seedDatabase.js +311 -289
  235. package/dist/seedDatabase.js.map +1 -0
  236. package/dist/server/pipelines/aiLabChat.d.ts +21 -0
  237. package/dist/server/pipelines/aiLabChat.d.ts.map +1 -0
  238. package/dist/server/pipelines/aiLabChat.js +456 -0
  239. package/dist/server/pipelines/aiLabChat.js.map +1 -0
  240. package/dist/server/pipelines/aiNewtonChat.d.ts +30 -0
  241. package/dist/server/pipelines/aiNewtonChat.d.ts.map +1 -0
  242. package/dist/server/pipelines/aiNewtonChat.js +285 -0
  243. package/dist/server/pipelines/aiNewtonChat.js.map +1 -0
  244. package/dist/server/pipelines/gradeWorksheet.d.ts +30 -0
  245. package/dist/server/pipelines/gradeWorksheet.d.ts.map +1 -0
  246. package/dist/server/pipelines/gradeWorksheet.js +248 -0
  247. package/dist/server/pipelines/gradeWorksheet.js.map +1 -0
  248. package/dist/services/agenda.d.ts +100 -0
  249. package/dist/services/agenda.d.ts.map +1 -0
  250. package/dist/services/agenda.js +21 -0
  251. package/dist/services/agenda.js.map +1 -0
  252. package/dist/services/announcement.d.ts +135 -0
  253. package/dist/services/announcement.d.ts.map +1 -0
  254. package/dist/services/announcement.js +223 -0
  255. package/dist/services/announcement.js.map +1 -0
  256. package/dist/services/assignment.d.ts +1462 -0
  257. package/dist/services/assignment.d.ts.map +1 -0
  258. package/dist/services/assignment.js +898 -0
  259. package/dist/services/assignment.js.map +1 -0
  260. package/dist/services/attendance.d.ts +93 -0
  261. package/dist/services/attendance.d.ts.map +1 -0
  262. package/dist/services/attendance.js +61 -0
  263. package/dist/services/attendance.js.map +1 -0
  264. package/dist/services/auth.d.ts +68 -0
  265. package/dist/services/auth.d.ts.map +1 -0
  266. package/dist/services/auth.js +218 -0
  267. package/dist/services/auth.js.map +1 -0
  268. package/dist/services/class.d.ts +621 -0
  269. package/dist/services/class.d.ts.map +1 -0
  270. package/dist/services/class.js +474 -0
  271. package/dist/services/class.js.map +1 -0
  272. package/dist/services/comment.d.ts +100 -0
  273. package/dist/services/comment.d.ts.map +1 -0
  274. package/dist/services/comment.js +83 -0
  275. package/dist/services/comment.js.map +1 -0
  276. package/dist/services/conversation.d.ts +159 -0
  277. package/dist/services/conversation.d.ts.map +1 -0
  278. package/dist/services/conversation.js +138 -0
  279. package/dist/services/conversation.js.map +1 -0
  280. package/dist/services/event.d.ts +216 -0
  281. package/dist/services/event.d.ts.map +1 -0
  282. package/dist/services/event.js +168 -0
  283. package/dist/services/event.js.map +1 -0
  284. package/dist/services/file.d.ts +74 -0
  285. package/dist/services/file.d.ts.map +1 -0
  286. package/dist/services/file.js +133 -0
  287. package/dist/services/file.js.map +1 -0
  288. package/dist/services/folder.d.ts +239 -0
  289. package/dist/services/folder.d.ts.map +1 -0
  290. package/dist/services/folder.js +248 -0
  291. package/dist/services/folder.js.map +1 -0
  292. package/dist/services/labChat.d.ts +165 -0
  293. package/dist/services/labChat.d.ts.map +1 -0
  294. package/dist/services/labChat.js +289 -0
  295. package/dist/services/labChat.js.map +1 -0
  296. package/dist/services/marketing.d.ts +50 -0
  297. package/dist/services/marketing.d.ts.map +1 -0
  298. package/dist/services/marketing.js +32 -0
  299. package/dist/services/marketing.js.map +1 -0
  300. package/dist/services/message.d.ts +95 -0
  301. package/dist/services/message.d.ts.map +1 -0
  302. package/dist/services/message.js +350 -0
  303. package/dist/services/message.js.map +1 -0
  304. package/dist/services/newtonChat.d.ts +22 -0
  305. package/dist/services/newtonChat.d.ts.map +1 -0
  306. package/dist/services/newtonChat.js +174 -0
  307. package/dist/services/newtonChat.js.map +1 -0
  308. package/dist/services/notification.d.ts +65 -0
  309. package/dist/services/notification.d.ts.map +1 -0
  310. package/dist/services/notification.js +33 -0
  311. package/dist/services/notification.js.map +1 -0
  312. package/dist/services/section.d.ts +53 -0
  313. package/dist/services/section.d.ts.map +1 -0
  314. package/dist/services/section.js +199 -0
  315. package/dist/services/section.js.map +1 -0
  316. package/dist/services/user.d.ts +48 -0
  317. package/dist/services/user.d.ts.map +1 -0
  318. package/dist/services/user.js +141 -0
  319. package/dist/services/user.js.map +1 -0
  320. package/dist/services/worksheet.d.ts +239 -0
  321. package/dist/services/worksheet.d.ts.map +1 -0
  322. package/dist/services/worksheet.js +235 -0
  323. package/dist/services/worksheet.js.map +1 -0
  324. package/dist/socket/handlers.d.ts.map +1 -1
  325. package/dist/socket/handlers.js +4 -0
  326. package/dist/socket/handlers.js.map +1 -0
  327. package/dist/trpc.d.ts.map +1 -1
  328. package/dist/trpc.js +4 -0
  329. package/dist/trpc.js.map +1 -0
  330. package/dist/types/trpc.d.ts.map +1 -1
  331. package/dist/types/trpc.js +4 -0
  332. package/dist/types/trpc.js.map +1 -0
  333. package/dist/utils/aiUser.d.ts +1 -3
  334. package/dist/utils/aiUser.d.ts.map +1 -1
  335. package/dist/utils/aiUser.js +8 -3
  336. package/dist/utils/aiUser.js.map +1 -0
  337. package/dist/utils/email.d.ts +12 -1
  338. package/dist/utils/email.d.ts.map +1 -1
  339. package/dist/utils/email.js +26 -4
  340. package/dist/utils/email.js.map +1 -0
  341. package/dist/utils/generateInviteCode.d.ts +1 -2
  342. package/dist/utils/generateInviteCode.d.ts.map +1 -1
  343. package/dist/utils/generateInviteCode.js +5 -2
  344. package/dist/utils/generateInviteCode.js.map +1 -0
  345. package/dist/utils/inference.d.ts +8 -0
  346. package/dist/utils/inference.d.ts.map +1 -1
  347. package/dist/utils/inference.js +78 -10
  348. package/dist/utils/inference.js.map +1 -0
  349. package/dist/utils/logger.d.ts +4 -0
  350. package/dist/utils/logger.d.ts.map +1 -1
  351. package/dist/utils/logger.js +35 -3
  352. package/dist/utils/logger.js.map +1 -0
  353. package/dist/utils/prismaErrorHandler.d.ts.map +1 -1
  354. package/dist/utils/prismaErrorHandler.js +7 -0
  355. package/dist/utils/prismaErrorHandler.js.map +1 -0
  356. package/dist/utils/prismaWrapper.d.ts +1 -0
  357. package/dist/utils/prismaWrapper.d.ts.map +1 -1
  358. package/dist/utils/prismaWrapper.js +8 -0
  359. package/dist/utils/prismaWrapper.js.map +1 -0
  360. package/docker-compose.yml +19 -0
  361. package/package.json +21 -4
  362. package/prisma/migrations/20251109122857_annuoncements_comments/migration.sql +30 -0
  363. package/prisma/migrations/20251109135555_reactions_announcements_comments/migration.sql +35 -0
  364. package/prisma/schema.prisma +180 -12
  365. package/scripts/test-pre-push.ts +14 -0
  366. package/src/index.ts +247 -52
  367. package/src/instrument.ts +15 -0
  368. package/src/lib/config/env.ts +132 -0
  369. package/src/lib/fileUpload.ts +81 -16
  370. package/src/lib/googleCloudStorage.ts +42 -6
  371. package/src/lib/jsonConversion.ts +12 -14
  372. package/src/lib/prisma.ts +23 -2
  373. package/src/lib/pusher.ts +11 -6
  374. package/src/lib/redis.ts +56 -0
  375. package/src/lib/thumbnailGenerator.ts +170 -168
  376. package/src/middleware/auth.ts +86 -137
  377. package/src/middleware/security.ts +80 -0
  378. package/src/models/agenda.ts +46 -0
  379. package/src/models/announcement.ts +134 -0
  380. package/src/models/assignment.ts +322 -0
  381. package/src/models/attendance.ts +208 -0
  382. package/src/models/auth.ts +247 -0
  383. package/src/models/class.ts +598 -0
  384. package/src/models/comment.ts +152 -0
  385. package/src/models/conversation.ts +200 -0
  386. package/src/models/event.ts +177 -0
  387. package/src/models/file.ts +129 -0
  388. package/src/models/folder.ts +225 -0
  389. package/src/models/labChat.ts +213 -0
  390. package/src/models/marketing.ts +45 -0
  391. package/src/models/message.ts +153 -0
  392. package/src/models/newtonChat.ts +70 -0
  393. package/src/models/notification.ts +54 -0
  394. package/src/models/section.ts +98 -0
  395. package/src/models/user.ts +47 -0
  396. package/src/models/worksheet.ts +294 -0
  397. package/src/pipelines/aiLabChat.ts +511 -0
  398. package/src/pipelines/aiNewtonChat.ts +347 -0
  399. package/src/pipelines/gradeWorksheet.ts +286 -0
  400. package/src/routers/_app.ts +6 -0
  401. package/src/routers/agenda.ts +3 -61
  402. package/src/routers/announcement.ts +622 -57
  403. package/src/routers/assignment.ts +157 -1688
  404. package/src/routers/attendance.ts +16 -277
  405. package/src/routers/auth.ts +79 -313
  406. package/src/routers/class.ts +265 -1038
  407. package/src/routers/comment.ts +76 -0
  408. package/src/routers/conversation.ts +53 -284
  409. package/src/routers/event.ts +50 -481
  410. package/src/routers/file.ts +45 -341
  411. package/src/routers/folder.ts +107 -836
  412. package/src/routers/labChat.ts +29 -960
  413. package/src/routers/marketing.ts +35 -77
  414. package/src/routers/message.ts +45 -571
  415. package/src/routers/newtonChat.ts +36 -0
  416. package/src/routers/notifications.ts +32 -82
  417. package/src/routers/section.ts +58 -200
  418. package/src/routers/user.ts +49 -226
  419. package/src/routers/worksheet.ts +252 -0
  420. package/src/seedDatabase.ts +330 -290
  421. package/src/services/agenda.ts +21 -0
  422. package/src/services/announcement.ts +290 -0
  423. package/src/services/assignment.ts +1198 -0
  424. package/src/services/attendance.ts +85 -0
  425. package/src/services/auth.ts +277 -0
  426. package/src/services/class.ts +622 -0
  427. package/src/services/comment.ts +106 -0
  428. package/src/services/conversation.ts +213 -0
  429. package/src/services/event.ts +231 -0
  430. package/src/services/file.ts +167 -0
  431. package/src/services/folder.ts +316 -0
  432. package/src/services/labChat.ts +352 -0
  433. package/src/services/marketing.ts +57 -0
  434. package/src/services/message.ts +461 -0
  435. package/src/services/newtonChat.ts +222 -0
  436. package/src/services/notification.ts +50 -0
  437. package/src/services/section.ts +283 -0
  438. package/src/services/user.ts +172 -0
  439. package/src/services/worksheet.ts +358 -0
  440. package/src/trpc.ts +4 -0
  441. package/src/utils/aiUser.ts +4 -3
  442. package/src/utils/email.ts +33 -4
  443. package/src/utils/generateInviteCode.ts +1 -3
  444. package/src/utils/inference.ts +89 -10
  445. package/src/utils/logger.ts +33 -3
  446. package/src/utils/prismaErrorHandler.ts +3 -0
  447. package/src/utils/prismaWrapper.ts +4 -0
  448. package/tests/globalSetup.ts +62 -0
  449. package/tests/helpers.ts +22 -0
  450. package/tests/middleware/security.test.ts +42 -0
  451. package/tests/routers/agenda.test.ts +138 -0
  452. package/tests/routers/announcement.test.ts +490 -0
  453. package/tests/routers/assignment.test.ts +837 -0
  454. package/tests/routers/attendance.test.ts +160 -0
  455. package/tests/routers/auth.test.ts +171 -0
  456. package/tests/{class.test.ts → routers/class.test.ts} +163 -92
  457. package/tests/routers/comment.test.ts +126 -0
  458. package/tests/routers/conversation.test.ts +145 -0
  459. package/tests/routers/event.test.ts +289 -0
  460. package/tests/routers/folder.test.ts +178 -0
  461. package/tests/routers/labChat.test.ts +115 -0
  462. package/tests/routers/marketing.test.ts +59 -0
  463. package/tests/routers/message.test.ts +123 -0
  464. package/tests/routers/notification.test.ts +69 -0
  465. package/tests/routers/section.test.ts +208 -0
  466. package/tests/server/rateLimit.test.ts +73 -0
  467. package/tests/setup.ts +39 -65
  468. package/tests/user.test.ts +136 -0
  469. package/tests/utils/aiUser.test.ts +22 -0
  470. package/tests/utils/generateInviteCode.test.ts +24 -0
  471. package/tests/utils/logger.test.ts +74 -0
  472. package/tests/utils/prismaErrorHandler.test.ts +101 -0
  473. package/tests/utils/prismaWrapper.test.ts +82 -0
  474. package/tests/worksheet.test.ts +181 -0
  475. package/tsconfig.json +9 -2
  476. package/vitest.config.ts +30 -1
  477. package/vitest.unit.config.ts +21 -0
  478. package/API_SPECIFICATION.md +0 -1597
  479. package/BASE64_REMOVAL_SUMMARY.md +0 -164
  480. package/CHAT_API_SPEC.md +0 -579
  481. package/LAB_CHAT_API_SPEC.md +0 -518
  482. package/dist/routers/school.d.ts +0 -208
  483. package/dist/routers/school.d.ts.map +0 -1
  484. package/dist/routers/school.js +0 -481
  485. package/tests/auth.test.ts +0 -25
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Folder model – class folders, hierarchy, contents. Teacher permission checks.
3
+ */
4
+ import { prisma } from "../lib/prisma.js";
5
+
6
+ const fileSelect = {
7
+ id: true,
8
+ name: true,
9
+ type: true,
10
+ size: true,
11
+ uploadedAt: true,
12
+ user: { select: { id: true, username: true } },
13
+ };
14
+
15
+ const childFolderSelect = {
16
+ id: true,
17
+ name: true,
18
+ color: true,
19
+ _count: { select: { files: true, childFolders: true } },
20
+ };
21
+
22
+ /** @returns Class if user is a teacher. */
23
+ export function findClassWithTeacher(classId: string, teacherId: string) {
24
+ return prisma.class.findFirst({
25
+ where: {
26
+ id: classId,
27
+ teachers: { some: { id: teacherId } },
28
+ },
29
+ });
30
+ }
31
+
32
+ /** @returns Folder by ID. */
33
+ export function findFolderById(folderId: string) {
34
+ return prisma.folder.findFirst({
35
+ where: { id: folderId },
36
+ });
37
+ }
38
+
39
+ /** @returns Folder with class. */
40
+ export function findFolderByIdWithClass(folderId: string) {
41
+ return prisma.folder.findUnique({
42
+ where: { id: folderId },
43
+ include: { class: true },
44
+ });
45
+ }
46
+
47
+ /** @returns Root folder for a class. */
48
+ export function findRootFolderByClassId(classId: string) {
49
+ return prisma.folder.findFirst({
50
+ where: {
51
+ classId,
52
+ parentFolderId: null,
53
+ },
54
+ });
55
+ }
56
+
57
+ /** Get or create root folder for a class. */
58
+ export async function findOrCreateRootFolder(classId: string) {
59
+ let parent = await findRootFolderByClassId(classId);
60
+ if (!parent) {
61
+ parent = await prisma.folder.create({
62
+ data: {
63
+ name: "Class Files",
64
+ class: { connect: { id: classId } },
65
+ },
66
+ });
67
+ }
68
+ return parent;
69
+ }
70
+
71
+ /** Create a folder. */
72
+ export function createFolder(data: {
73
+ name: string;
74
+ parentFolderId?: string | null;
75
+ classId?: string;
76
+ color?: string;
77
+ }) {
78
+ return prisma.folder.create({
79
+ data: {
80
+ name: data.name,
81
+ ...(data.parentFolderId && {
82
+ parentFolder: { connect: { id: data.parentFolderId } },
83
+ }),
84
+ ...(data.classId && { class: { connect: { id: data.classId } } }),
85
+ ...(data.color && { color: data.color }),
86
+ },
87
+ include: {
88
+ files: {
89
+ select: fileSelect,
90
+ orderBy: { uploadedAt: "desc" as const },
91
+ },
92
+ childFolders: {
93
+ select: childFolderSelect,
94
+ orderBy: { name: "asc" as const },
95
+ },
96
+ },
97
+ });
98
+ }
99
+
100
+ const folderIncludeWithFiles = {
101
+ files: {
102
+ select: fileSelect,
103
+ orderBy: { uploadedAt: "desc" as const },
104
+ },
105
+ childFolders: {
106
+ select: childFolderSelect,
107
+ orderBy: { name: "asc" as const },
108
+ },
109
+ parentFolder: { select: { id: true, name: true } },
110
+ };
111
+
112
+ /** @returns Folder with files and child folders. */
113
+ export function findFolderWithContents(folderId: string) {
114
+ return prisma.folder.findFirst({
115
+ where: { id: folderId },
116
+ include: folderIncludeWithFiles,
117
+ });
118
+ }
119
+
120
+ /** @returns Direct child folders. */
121
+ export function findChildFolders(parentFolderId: string) {
122
+ return prisma.folder.findMany({
123
+ where: { parentFolderId },
124
+ include: {
125
+ files: {
126
+ select: fileSelect,
127
+ orderBy: { uploadedAt: "desc" as const },
128
+ },
129
+ childFolders: {
130
+ select: childFolderSelect,
131
+ orderBy: { name: "asc" as const },
132
+ },
133
+ },
134
+ orderBy: { name: "asc" },
135
+ });
136
+ }
137
+
138
+ /** @returns Root folder with contents for a class. */
139
+ export function findRootFolderWithContents(classId: string) {
140
+ return prisma.folder.findFirst({
141
+ where: { classId, parentFolderId: null },
142
+ include: {
143
+ files: {
144
+ select: fileSelect,
145
+ orderBy: { uploadedAt: "desc" as const },
146
+ },
147
+ childFolders: {
148
+ select: {
149
+ ...childFolderSelect,
150
+ files: { select: { id: true } },
151
+ childFolders: { select: { id: true } },
152
+ },
153
+ orderBy: { name: "asc" as const },
154
+ },
155
+ },
156
+ });
157
+ }
158
+
159
+ /** @returns Folder with file/folder counts. */
160
+ export function findFolderWithCount(folderId: string, classId: string) {
161
+ return prisma.folder.findFirst({
162
+ where: { id: folderId, classId },
163
+ include: {
164
+ _count: { select: { files: true, childFolders: true } },
165
+ },
166
+ });
167
+ }
168
+
169
+ /** @returns Folder with file/folder counts. */
170
+ export function findFolderByIdWithCount(folderId: string) {
171
+ return prisma.folder.findFirst({
172
+ where: { id: folderId },
173
+ include: {
174
+ _count: { select: { files: true, childFolders: true } },
175
+ },
176
+ });
177
+ }
178
+
179
+ /** Delete a folder. */
180
+ export function deleteFolderById(folderId: string) {
181
+ return prisma.folder.delete({
182
+ where: { id: folderId },
183
+ });
184
+ }
185
+
186
+ /** Move folder to new parent. */
187
+ export function updateFolderParent(folderId: string, parentFolderId: string) {
188
+ return prisma.folder.update({
189
+ where: { id: folderId },
190
+ data: { parentFolderId },
191
+ include: {
192
+ files: { select: fileSelect },
193
+ childFolders: { select: childFolderSelect },
194
+ },
195
+ });
196
+ }
197
+
198
+ /** Update folder name and color. */
199
+ export function updateFolder(
200
+ folderId: string,
201
+ data: { name?: string; color?: string }
202
+ ) {
203
+ return prisma.folder.update({
204
+ where: { id: folderId },
205
+ data,
206
+ include: {
207
+ files: { select: fileSelect },
208
+ childFolders: { select: childFolderSelect },
209
+ },
210
+ });
211
+ }
212
+
213
+ /** @returns Folder for path traversal. */
214
+ export function findFolderByIdForTraversal(id: string) {
215
+ return prisma.folder.findUnique({
216
+ where: { id },
217
+ });
218
+ }
219
+
220
+ /** @returns Folder by ID. */
221
+ export function findFolderParents(folderId: string) {
222
+ return prisma.folder.findFirst({
223
+ where: { id: folderId },
224
+ });
225
+ }
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Lab chat model – AI lab conversations, members, posts. Teacher/student access.
3
+ */
4
+ import { prisma } from "../lib/prisma.js";
5
+
6
+ const labChatInclude = {
7
+ conversation: {
8
+ include: {
9
+ members: {
10
+ include: {
11
+ user: {
12
+ select: {
13
+ id: true,
14
+ username: true,
15
+ profile: {
16
+ select: {
17
+ displayName: true,
18
+ profilePicture: true,
19
+ },
20
+ },
21
+ },
22
+ },
23
+ },
24
+ },
25
+ },
26
+ },
27
+ createdBy: {
28
+ select: {
29
+ id: true,
30
+ username: true,
31
+ profile: {
32
+ select: {
33
+ displayName: true,
34
+ profilePicture: true,
35
+ },
36
+ },
37
+ },
38
+ },
39
+ class: {
40
+ select: {
41
+ id: true,
42
+ name: true,
43
+ subject: true,
44
+ section: true,
45
+ },
46
+ },
47
+ };
48
+
49
+ /** @returns Class with students and teachers for lab creation. */
50
+ export function findClassWithTeachersForLab(classId: string, teacherId: string) {
51
+ return prisma.class.findFirst({
52
+ where: {
53
+ id: classId,
54
+ teachers: { some: { id: teacherId } },
55
+ },
56
+ include: {
57
+ students: {
58
+ select: {
59
+ id: true,
60
+ username: true,
61
+ profile: {
62
+ select: {
63
+ displayName: true,
64
+ profilePicture: true,
65
+ },
66
+ },
67
+ },
68
+ },
69
+ teachers: {
70
+ select: {
71
+ id: true,
72
+ username: true,
73
+ profile: {
74
+ select: {
75
+ displayName: true,
76
+ profilePicture: true,
77
+ },
78
+ },
79
+ },
80
+ },
81
+ },
82
+ });
83
+ }
84
+
85
+ /** @returns Lab chat if user is a conversation member. */
86
+ export function findLabChatByMember(labChatId: string, userId: string) {
87
+ return prisma.labChat.findFirst({
88
+ where: {
89
+ id: labChatId,
90
+ conversation: {
91
+ members: { some: { userId } },
92
+ },
93
+ },
94
+ include: labChatInclude,
95
+ });
96
+ }
97
+
98
+ /** @returns Lab chat if user is class teacher. */
99
+ export function findLabChatByTeacher(labChatId: string, userId: string) {
100
+ return prisma.labChat.findFirst({
101
+ where: {
102
+ id: labChatId,
103
+ class: {
104
+ teachers: { some: { id: userId } },
105
+ },
106
+ },
107
+ include: {
108
+ conversation: { select: { id: true } },
109
+ },
110
+ });
111
+ }
112
+
113
+ /** @returns Lab chat by ID. */
114
+ export function findLabChatById(labChatId: string) {
115
+ return prisma.labChat.findFirst({
116
+ where: { id: labChatId },
117
+ include: labChatInclude,
118
+ });
119
+ }
120
+
121
+ /** @returns Class if user is student or teacher. */
122
+ export function findClassMembership(classId: string, userId: string) {
123
+ return prisma.class.findFirst({
124
+ where: {
125
+ id: classId,
126
+ OR: [
127
+ { students: { some: { id: userId } } },
128
+ { teachers: { some: { id: userId } } },
129
+ ],
130
+ },
131
+ });
132
+ }
133
+
134
+ /** @returns Lab chats for a class. */
135
+ export function findLabChatsByClass(classId: string) {
136
+ return prisma.labChat.findMany({
137
+ where: { classId },
138
+ include: {
139
+ createdBy: {
140
+ select: {
141
+ id: true,
142
+ username: true,
143
+ profile: {
144
+ select: {
145
+ displayName: true,
146
+ },
147
+ },
148
+ },
149
+ },
150
+ conversation: {
151
+ include: {
152
+ messages: {
153
+ orderBy: { createdAt: "desc" as const },
154
+ take: 1,
155
+ include: {
156
+ sender: {
157
+ select: {
158
+ id: true,
159
+ username: true,
160
+ profile: {
161
+ select: {
162
+ displayName: true,
163
+ },
164
+ },
165
+ },
166
+ },
167
+ },
168
+ },
169
+ _count: { select: { messages: true } },
170
+ },
171
+ },
172
+ },
173
+ orderBy: { createdAt: "desc" as const },
174
+ });
175
+ }
176
+
177
+ /** @returns Lab chat if user can post (member or teacher). */
178
+ export function findLabChatForPost(labChatId: string, userId: string) {
179
+ return prisma.labChat.findFirst({
180
+ where: {
181
+ id: labChatId,
182
+ conversation: {
183
+ members: { some: { userId } },
184
+ },
185
+ },
186
+ include: {
187
+ conversation: { select: { id: true } },
188
+ },
189
+ });
190
+ }
191
+
192
+ /** @returns Lab chat if user can delete (teacher). */
193
+ export function findLabChatForDelete(labChatId: string, userId: string) {
194
+ return prisma.labChat.findFirst({
195
+ where: {
196
+ id: labChatId,
197
+ createdById: userId,
198
+ },
199
+ });
200
+ }
201
+
202
+ /** @returns Conversation members for mentioned user IDs. */
203
+ export function findMentionedMemberships(
204
+ conversationId: string,
205
+ userIds: string[]
206
+ ) {
207
+ return prisma.conversationMember.findMany({
208
+ where: {
209
+ conversationId,
210
+ userId: { in: userIds },
211
+ },
212
+ });
213
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Marketing model – school development programs, early access requests.
3
+ */
4
+ import { prisma } from "../lib/prisma.js";
5
+
6
+ /** Create a school development program application. */
7
+ export function createSchoolDevelopmentProgram(data: {
8
+ id: string;
9
+ name: string;
10
+ type: string;
11
+ address: string;
12
+ city: string;
13
+ country: string;
14
+ numberOfStudents: number;
15
+ numberOfTeachers: number;
16
+ website?: string;
17
+ contactName?: string;
18
+ contactRole?: string;
19
+ contactEmail?: string;
20
+ contactPhone?: string;
21
+ eligibilityInformation?: string;
22
+ whyHelp?: string;
23
+ additionalInformation?: string;
24
+ }) {
25
+ return prisma.schoolDevelopementProgram.create({
26
+ data,
27
+ });
28
+ }
29
+
30
+ /** @returns School development program by ID. */
31
+ export function findSchoolDevelopmentProgramById(id: string) {
32
+ return prisma.schoolDevelopementProgram.findUnique({
33
+ where: { id },
34
+ });
35
+ }
36
+
37
+ /** Create an early access request. */
38
+ export function createEarlyAccessRequest(data: {
39
+ email: string;
40
+ institutionSize: string;
41
+ }) {
42
+ return prisma.earlyAccessRequest.create({
43
+ data,
44
+ });
45
+ }
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Message model – messages, attachments, mentions, unread counts.
3
+ */
4
+ import { prisma } from "../lib/prisma.js";
5
+
6
+ const messageInclude = {
7
+ attachments: {
8
+ select: {
9
+ id: true,
10
+ name: true,
11
+ type: true,
12
+ },
13
+ },
14
+ sender: {
15
+ select: {
16
+ id: true,
17
+ username: true,
18
+ profile: {
19
+ select: {
20
+ displayName: true,
21
+ profilePicture: true,
22
+ },
23
+ },
24
+ },
25
+ },
26
+ mentions: {
27
+ include: {
28
+ user: {
29
+ select: {
30
+ id: true,
31
+ username: true,
32
+ profile: {
33
+ select: {
34
+ displayName: true,
35
+ },
36
+ },
37
+ },
38
+ },
39
+ },
40
+ },
41
+ };
42
+
43
+ const senderSelect = {
44
+ id: true,
45
+ username: true,
46
+ profile: {
47
+ select: {
48
+ displayName: true,
49
+ profilePicture: true,
50
+ },
51
+ },
52
+ };
53
+
54
+ /** @returns User's membership in a conversation. */
55
+ export function findConversationMembership(conversationId: string, userId: string) {
56
+ return prisma.conversationMember.findFirst({
57
+ where: {
58
+ conversationId,
59
+ userId,
60
+ },
61
+ });
62
+ }
63
+
64
+ /** @returns Messages in conversation with cursor pagination. */
65
+ export function findMessages(
66
+ conversationId: string,
67
+ options: {
68
+ cursor?: Date;
69
+ limit: number;
70
+ }
71
+ ) {
72
+ return prisma.message.findMany({
73
+ where: {
74
+ conversationId,
75
+ ...(options.cursor && {
76
+ createdAt: { lt: options.cursor },
77
+ }),
78
+ },
79
+ include: messageInclude,
80
+ orderBy: { createdAt: "desc" as const },
81
+ take: options.limit + 1,
82
+ });
83
+ }
84
+
85
+ /** @returns Memberships for mentioned users. */
86
+ export function findMentionedMemberships(
87
+ conversationId: string,
88
+ userIds: string[]
89
+ ) {
90
+ return prisma.conversationMember.findMany({
91
+ where: {
92
+ conversationId,
93
+ userId: { in: userIds },
94
+ },
95
+ });
96
+ }
97
+
98
+ /** @returns Message by ID with sender. */
99
+ export function findMessageById(messageId: string) {
100
+ return prisma.message.findUnique({
101
+ where: { id: messageId },
102
+ include: {
103
+ sender: {
104
+ select: senderSelect,
105
+ },
106
+ },
107
+ });
108
+ }
109
+
110
+ /** @returns Message by ID with minimal sender. */
111
+ export function findMessageByIdMinimal(messageId: string) {
112
+ return prisma.message.findUnique({
113
+ where: { id: messageId },
114
+ include: {
115
+ sender: {
116
+ select: { id: true, username: true },
117
+ },
118
+ },
119
+ });
120
+ }
121
+
122
+ /** Count messages in conversation after date, excluding sender's own. */
123
+ export function countUnreadMessages(
124
+ conversationId: string,
125
+ userId: string,
126
+ after?: Date
127
+ ) {
128
+ return prisma.message.count({
129
+ where: {
130
+ conversationId,
131
+ senderId: { not: userId },
132
+ ...(after && { createdAt: { gt: after } }),
133
+ },
134
+ });
135
+ }
136
+
137
+ /** Count mentions of user in conversation after date. */
138
+ export function countUnreadMentions(
139
+ conversationId: string,
140
+ userId: string,
141
+ after?: Date
142
+ ) {
143
+ return prisma.mention.count({
144
+ where: {
145
+ userId,
146
+ message: {
147
+ conversationId,
148
+ senderId: { not: userId },
149
+ ...(after && { createdAt: { gt: after } }),
150
+ },
151
+ },
152
+ });
153
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Newton chat model – tutor conversations linked to submissions.
3
+ */
4
+ import { prisma } from "../lib/prisma.js";
5
+
6
+ /** @returns Class if user is a student. */
7
+ export function findClassWithStudent(classId: string, studentId: string) {
8
+ return prisma.class.findFirst({
9
+ where: {
10
+ id: classId,
11
+ students: { some: { id: studentId } },
12
+ },
13
+ });
14
+ }
15
+
16
+ /** @returns Submission for assignment and student. */
17
+ export function findSubmissionByAssignmentAndStudent(
18
+ assignmentId: string,
19
+ studentId: string
20
+ ) {
21
+ return prisma.submission.findFirst({
22
+ where: {
23
+ assignmentId,
24
+ studentId,
25
+ },
26
+ });
27
+ }
28
+
29
+ /** @returns Newton chat if user is a member, with conversation and assignment. */
30
+ export function findNewtonChatByIdAndMember(
31
+ newtonChatId: string,
32
+ userId: string
33
+ ) {
34
+ return prisma.newtonChat.findFirst({
35
+ where: {
36
+ id: newtonChatId,
37
+ conversation: {
38
+ members: { some: { userId } },
39
+ },
40
+ },
41
+ include: {
42
+ conversation: { select: { id: true } },
43
+ submission: {
44
+ include: {
45
+ assignment: {
46
+ select: {
47
+ id: true,
48
+ title: true,
49
+ instructions: true,
50
+ class: { select: { subject: true } },
51
+ },
52
+ },
53
+ },
54
+ },
55
+ },
56
+ });
57
+ }
58
+
59
+ /** @returns Conversation members for given user IDs. */
60
+ export function findConversationMembersByUserIds(
61
+ conversationId: string,
62
+ userIds: string[]
63
+ ) {
64
+ return prisma.conversationMember.findMany({
65
+ where: {
66
+ conversationId,
67
+ userId: { in: userIds },
68
+ },
69
+ });
70
+ }