@studious-lms/server 1.1.26 → 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 (486) 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 +15 -5
  23. package/dist/lib/fileUpload.js.map +1 -0
  24. package/dist/lib/googleCloudStorage.d.ts +6 -0
  25. package/dist/lib/googleCloudStorage.d.ts.map +1 -1
  26. package/dist/lib/googleCloudStorage.js +26 -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 +2 -2
  35. package/dist/lib/notificationHandler.d.ts.map +1 -1
  36. package/dist/lib/notificationHandler.js +4 -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 +6438 -3910
  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 +543 -77
  163. package/dist/routers/announcement.js.map +1 -0
  164. package/dist/routers/assignment.d.ts +419 -357
  165. package/dist/routers/assignment.d.ts.map +1 -1
  166. package/dist/routers/assignment.js +100 -1689
  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 -298
  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 -885
  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 +23 -8
  221. package/dist/routers/section.d.ts.map +1 -1
  222. package/dist/routers/section.js +23 -273
  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 +309 -288
  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 +3 -0
  350. package/dist/utils/logger.d.ts.map +1 -1
  351. package/dist/utils/logger.js +8 -1
  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 +13 -6
  370. package/src/lib/googleCloudStorage.ts +23 -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 +616 -79
  403. package/src/routers/assignment.ts +148 -1827
  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 -344
  411. package/src/routers/folder.ts +107 -836
  412. package/src/routers/labChat.ts +29 -969
  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 -322
  418. package/src/routers/user.ts +49 -226
  419. package/src/routers/worksheet.ts +252 -0
  420. package/src/seedDatabase.ts +328 -289
  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 +4 -1
  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 -59
  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/src/lib/notificationHandler.ts +0 -36
  486. package/tests/auth.test.ts +0 -25
@@ -1,45 +1,33 @@
1
- import { TRPCError } from '@trpc/server';
2
- import { prisma } from '../lib/prisma.js';
3
- import type { MiddlewareContext } from '../types/trpc.js';
1
+ import { TRPCError } from "@trpc/server";
2
+ import * as Sentry from "@sentry/node";
3
+ import type { MiddlewareContext } from "../types/trpc.js";
4
+ import {
5
+ findUserBySessionToken,
6
+ findTeacherClassesByUserId,
7
+ findClassWithMember,
8
+ findClassWithTeacher,
9
+ } from "../models/auth.js";
4
10
 
5
11
  export const createAuthMiddleware = (t: any) => {
6
-
7
- // Auth middleware
8
12
  const isAuthed = t.middleware(async ({ next, ctx }: MiddlewareContext) => {
9
- const startTime = Date.now();
10
- // Get user from request headers
11
- const userHeader = ctx.req.headers['x-user'];
13
+ const userHeader = ctx.req.headers["x-user"];
12
14
 
13
15
  if (!userHeader) {
14
16
  throw new TRPCError({
15
- code: 'UNAUTHORIZED',
16
- message: 'Not authenticated - no token found',
17
+ code: "UNAUTHORIZED",
18
+ message: "Not authenticated - no token found",
17
19
  });
18
20
  }
19
21
 
20
22
  try {
21
- const token = typeof userHeader === 'string' ? userHeader : userHeader[0];
22
-
23
- // Find user by session token
24
- const user = await prisma.user.findFirst({
25
- where: {
26
- sessions: {
27
- some: {
28
- id: token
29
- }
30
- }
31
- },
32
- select: {
33
- id: true,
34
- username: true,
35
- // institutionId: true,
36
- }
37
- });
23
+ const token =
24
+ typeof userHeader === "string" ? userHeader : userHeader[0];
25
+ const user = await findUserBySessionToken(token);
38
26
 
39
27
  if (!user) {
40
28
  throw new TRPCError({
41
- code: 'UNAUTHORIZED',
42
- message: 'Invalid or expired session',
29
+ code: "UNAUTHORIZED",
30
+ message: "Invalid or expired session",
43
31
  });
44
32
  }
45
33
 
@@ -50,135 +38,96 @@ export const createAuthMiddleware = (t: any) => {
50
38
  },
51
39
  });
52
40
  } catch (error) {
53
- console.log(error)
41
+ if (error instanceof TRPCError) {
42
+ throw error;
43
+ }
44
+ Sentry.captureException(error);
45
+ console.error(error);
54
46
  throw new TRPCError({
55
- code: 'UNAUTHORIZED',
56
- message: 'Invalid user data',
47
+ code: "INTERNAL_SERVER_ERROR",
48
+ message: "Internal server error",
57
49
  });
58
50
  }
59
51
  });
60
52
 
61
- // Add computed flags middleware
62
- const addComputedFlags = t.middleware(async ({ next, ctx }: MiddlewareContext) => {
63
- if (!ctx.user) {
64
- throw new TRPCError({
65
- code: 'UNAUTHORIZED',
66
- message: 'Not authenticated',
67
- });
68
- }
69
-
70
- // Get all classes where user is a teacher
71
- const teacherClasses = await prisma.class.findMany({
72
- where: {
73
- teachers: {
74
- some: {
75
- id: ctx.user.id
76
- }
77
- }
78
- },
79
- select: {
80
- id: true
81
- }
82
- });
83
-
84
- return next({
85
- ctx: {
86
- ...ctx,
87
- isTeacher: teacherClasses.length > 0,
88
- teacherClassIds: teacherClasses.map((c: { id: string }) => c.id)
53
+ const addComputedFlags = t.middleware(
54
+ async ({ next, ctx }: MiddlewareContext) => {
55
+ if (!ctx.user) {
56
+ throw new TRPCError({
57
+ code: "UNAUTHORIZED",
58
+ message: "Not authenticated",
59
+ });
89
60
  }
90
- });
91
- });
92
61
 
93
- // Student middleware
94
- const isMemberInClass = t.middleware(async ({ next, ctx, input }: MiddlewareContext) => {
95
- if (!ctx.user) {
96
- throw new TRPCError({
97
- code: 'UNAUTHORIZED',
98
- message: 'Not authenticated',
99
- });
100
- }
101
-
102
- const classId = (input as { classId: string })?.classId;
62
+ const teacherClasses = await findTeacherClassesByUserId(ctx.user.id);
103
63
 
104
- if (!classId) {
105
- throw new TRPCError({
106
- code: 'BAD_REQUEST',
107
- message: 'classId is required',
64
+ return next({
65
+ ctx: {
66
+ ...ctx,
67
+ isTeacher: teacherClasses.length > 0,
68
+ teacherClassIds: teacherClasses.map((c) => c.id),
69
+ },
108
70
  });
109
71
  }
72
+ );
110
73
 
111
- const isMember = await prisma.class.findFirst({
112
- where: {
113
- id: classId,
114
- OR: [
115
- {
116
- students: {
117
- some: {
118
- id: ctx.user.id
119
- }
120
- }
121
- },
122
- {
123
- teachers: {
124
- some: {
125
- id: ctx.user.id
126
- }
127
- }
128
- }
129
- ]
74
+ const isMemberInClass = t.middleware(
75
+ async ({ next, ctx, input }: MiddlewareContext) => {
76
+ if (!ctx.user) {
77
+ throw new TRPCError({
78
+ code: "UNAUTHORIZED",
79
+ message: "Not authenticated",
80
+ });
130
81
  }
131
- });
132
-
133
- if (!isMember) {
134
- throw new TRPCError({
135
- code: 'FORBIDDEN',
136
- message: 'Not a member in this class',
137
- });
138
- }
139
82
 
140
- return next();
141
- });
83
+ const classId = (input as { classId: string })?.classId;
84
+ if (!classId) {
85
+ throw new TRPCError({
86
+ code: "BAD_REQUEST",
87
+ message: "classId is required",
88
+ });
89
+ }
142
90
 
143
- // Teacher middleware
144
- const isTeacherInClass = t.middleware(async ({ next, ctx, input }: MiddlewareContext) => {
145
- if (!ctx.user) {
146
- throw new TRPCError({
147
- code: 'UNAUTHORIZED',
148
- message: 'Not authenticated',
149
- });
150
- }
91
+ const isMember = await findClassWithMember(classId, ctx.user.id);
92
+ if (!isMember) {
93
+ throw new TRPCError({
94
+ code: "FORBIDDEN",
95
+ message: "Not a member in this class",
96
+ });
97
+ }
151
98
 
152
- const classId = input.classId;
153
- if (!classId) {
154
- throw new TRPCError({
155
- code: 'BAD_REQUEST',
156
- message: 'classId is required',
157
- });
99
+ return next();
158
100
  }
101
+ );
159
102
 
160
- const isTeacher = await prisma.class.findFirst({
161
- where: {
162
- id: classId,
163
- teachers: {
164
- some: {
165
- id: ctx.user.id
166
- }
167
- }
103
+ const isTeacherInClass = t.middleware(
104
+ async ({ next, ctx, input }: MiddlewareContext) => {
105
+ if (!ctx.user) {
106
+ throw new TRPCError({
107
+ code: "UNAUTHORIZED",
108
+ message: "Not authenticated",
109
+ });
168
110
  }
169
- });
170
111
 
112
+ const classId = (input as { classId: string })?.classId;
113
+ if (!classId) {
114
+ throw new TRPCError({
115
+ code: "BAD_REQUEST",
116
+ message: "classId is required",
117
+ });
118
+ }
171
119
 
120
+ const isTeacher = await findClassWithTeacher(classId, ctx.user.id);
121
+ if (!isTeacher) {
122
+ throw new TRPCError({
123
+ code: "FORBIDDEN",
124
+ message: "Not a teacher in this class",
125
+ });
126
+ }
172
127
 
173
- if (!isTeacher) {
174
- throw new TRPCError({
175
- code: 'FORBIDDEN',
176
- message: 'Not a teacher in this class',
177
- });
128
+ return next();
178
129
  }
179
-
180
- return next();
181
- });
130
+ );
182
131
 
183
132
  return {
184
133
  isAuthed,
@@ -186,4 +135,4 @@ export const createAuthMiddleware = (t: any) => {
186
135
  isMemberInClass,
187
136
  isTeacherInClass,
188
137
  };
189
- };
138
+ };
@@ -0,0 +1,80 @@
1
+ import helmet from 'helmet';
2
+ import rateLimit from 'express-rate-limit';
3
+ import type { Request, Response } from 'express';
4
+
5
+ const isDevelopment = process.env.NODE_ENV === 'development';
6
+
7
+ // Custom handler for rate limit errors that returns JSON
8
+ // This format can be intercepted on the frontend with:
9
+ // error.data?.code === 'TOO_MANY_REQUESTS' || error.data?.httpStatus === 429
10
+ const rateLimitHandler = (req: Request, res: Response) => {
11
+ // Return JSON structure that can be intercepted on frontend with:
12
+ // error.data?.code === 'TOO_MANY_REQUESTS' || error.data?.httpStatus === 429
13
+ // When tRPC wraps this, the response body becomes error.data, so we put code/httpStatus at top level
14
+ res.status(429).json({
15
+ code: 'TOO_MANY_REQUESTS',
16
+ message: 'Too many requests, please try again later.',
17
+ });
18
+ };
19
+
20
+ // General API rate limiter - applies to all routes
21
+ export const generalLimiter = rateLimit({
22
+ windowMs: 10 * 60, // 10 minutes
23
+ max: 100, // Limit each IP to 100 requests per windowMs
24
+ message: 'Too many requests from this IP, please try again later.',
25
+ standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
26
+ legacyHeaders: false, // Disable the `X-RateLimit-*` headers
27
+ handler: rateLimitHandler,
28
+ skip: (req) => {
29
+ // Skip rate limiting for health checks
30
+ return req.path === '/health' || req.method === 'OPTIONS';
31
+ },
32
+ });
33
+
34
+ // Stricter rate limiter for authentication endpoints
35
+ export const authLimiter = rateLimit({
36
+ windowMs: 5 * 60 * 1000, // 5 minutes
37
+ max: 5, // Limit each IP to 5 login attempts per windowMs
38
+ message: 'Too many authentication attempts, please try again later.',
39
+ standardHeaders: true,
40
+ legacyHeaders: false,
41
+ skipSuccessfulRequests: true, // Don't count successful requests
42
+ handler: rateLimitHandler,
43
+ });
44
+
45
+ // File upload rate limiter
46
+ export const uploadLimiter = rateLimit({
47
+ windowMs: 30 * 60 * 1000, // 30 minutes
48
+ max: 50, // Limit each IP to 50 uploads per hour
49
+ message: 'Too many file uploads, please try again later.',
50
+ standardHeaders: true,
51
+ legacyHeaders: false,
52
+ handler: rateLimitHandler,
53
+ });
54
+
55
+ // Helmet configuration
56
+ export const helmetConfig = helmet({
57
+ contentSecurityPolicy: {
58
+ directives: {
59
+ defaultSrc: ["'self'"],
60
+ styleSrc: ["'self'", "'unsafe-inline'"], // Allow inline styles for tRPC panel
61
+ // Allow inline scripts only in development (for tRPC panel)
62
+ // In production, keep strict CSP without unsafe-inline
63
+ scriptSrc: isDevelopment
64
+ ? ["'self'", "'unsafe-inline'"]
65
+ : ["'self'"],
66
+ imgSrc: ["'self'", "data:", "https:"], // Allow images from any HTTPS source
67
+ connectSrc: ["'self'", "https://*.sentry.io"], // Allow Sentry connections
68
+ fontSrc: ["'self'", "data:"],
69
+ objectSrc: ["'none'"],
70
+ mediaSrc: ["'self'"],
71
+ frameSrc: ["'none'"],
72
+ },
73
+ },
74
+ crossOriginEmbedderPolicy: false, // Disable if you need to embed resources
75
+ hsts: {
76
+ maxAge: 31536000, // 1 year
77
+ includeSubDomains: true,
78
+ preload: true,
79
+ },
80
+ });
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Agenda model – personal and class events for a date range.
3
+ */
4
+ import { prisma } from "../lib/prisma.js";
5
+
6
+ /** @returns Personal events (no class) for user in date range. */
7
+ export function findPersonalEvents(
8
+ userId: string,
9
+ rangeStart: Date,
10
+ rangeEnd: Date,
11
+ ) {
12
+ return prisma.event.findMany({
13
+ where: {
14
+ userId,
15
+ startTime: { gte: rangeStart, lte: rangeEnd },
16
+ class: { is: null },
17
+ },
18
+ include: {
19
+ assignmentsAttached: true,
20
+ class: true,
21
+ },
22
+ });
23
+ }
24
+
25
+ /** @returns Class events for user's classes in date range. */
26
+ export function findClassEvents(
27
+ userId: string,
28
+ rangeStart: Date,
29
+ rangeEnd: Date,
30
+ ) {
31
+ return prisma.event.findMany({
32
+ where: {
33
+ class: {
34
+ OR: [
35
+ { teachers: { some: { id: userId } } },
36
+ { students: { some: { id: userId } } },
37
+ ],
38
+ },
39
+ startTime: { gte: rangeStart, lte: rangeEnd },
40
+ },
41
+ include: {
42
+ assignmentsAttached: true,
43
+ class: true,
44
+ },
45
+ });
46
+ }
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Announcement model – announcements, attachments, comments.
3
+ */
4
+ import { prisma } from "../lib/prisma.js";
5
+
6
+ export const announcementSelect = {
7
+ id: true,
8
+ teacher: {
9
+ select: {
10
+ id: true,
11
+ username: true,
12
+ profile: {
13
+ select: {
14
+ displayName: true,
15
+ profilePicture: true,
16
+ profilePictureThumbnail: true,
17
+ },
18
+ },
19
+ },
20
+ },
21
+ remarks: true,
22
+ createdAt: true,
23
+ modifiedAt: true,
24
+ attachments: {
25
+ select: {
26
+ id: true,
27
+ name: true,
28
+ type: true,
29
+ size: true,
30
+ path: true,
31
+ uploadedAt: true,
32
+ thumbnailId: true,
33
+ },
34
+ },
35
+ };
36
+
37
+ /** @returns Announcements for a class. */
38
+ export function findAnnouncementsByClassId(classId: string) {
39
+ return prisma.announcement.findMany({
40
+ where: { classId },
41
+ select: {
42
+ ...announcementSelect,
43
+ _count: {
44
+ select: { comments: true },
45
+ },
46
+ },
47
+ orderBy: { createdAt: "desc" },
48
+ });
49
+ }
50
+
51
+ /** @returns Announcement by ID and class. */
52
+ export function findAnnouncementByIdAndClass(id: string, classId: string) {
53
+ return prisma.announcement.findFirst({
54
+ where: { id, classId },
55
+ select: announcementSelect,
56
+ });
57
+ }
58
+
59
+ /** @returns Announcement by ID with class and teachers. */
60
+ export function findAnnouncementWithClass(id: string) {
61
+ return prisma.announcement.findUnique({
62
+ where: { id },
63
+ include: {
64
+ class: {
65
+ include: { teachers: true },
66
+ },
67
+ attachments: {
68
+ select: {
69
+ id: true,
70
+ name: true,
71
+ type: true,
72
+ path: true,
73
+ size: true,
74
+ uploadStatus: true,
75
+ thumbnail: { select: { path: true } },
76
+ },
77
+ },
78
+ },
79
+ });
80
+ }
81
+
82
+ /** Create an announcement. */
83
+ export function createAnnouncement(data: {
84
+ remarks: string;
85
+ teacherId: string;
86
+ classId: string;
87
+ }) {
88
+ return prisma.announcement.create({
89
+ data: {
90
+ remarks: data.remarks,
91
+ teacher: { connect: { id: data.teacherId } },
92
+ class: { connect: { id: data.classId } },
93
+ },
94
+ select: announcementSelect,
95
+ });
96
+ }
97
+
98
+ /** Update announcement attachments. */
99
+ export function updateAnnouncementAttachments(
100
+ id: string,
101
+ data: {
102
+ connect?: { id: string }[];
103
+ deleteMany?: { id: { in: string[] } };
104
+ }
105
+ ) {
106
+ return prisma.announcement.update({
107
+ where: { id },
108
+ data: {
109
+ ...(data.connect?.length && {
110
+ attachments: { connect: data.connect },
111
+ }),
112
+ ...(data.deleteMany && {
113
+ attachments: { deleteMany: data.deleteMany },
114
+ }),
115
+ },
116
+ select: announcementSelect,
117
+ });
118
+ }
119
+
120
+ /** Update announcement remarks. */
121
+ export function updateAnnouncement(id: string, data: { remarks?: string }) {
122
+ return prisma.announcement.update({
123
+ where: { id },
124
+ data,
125
+ select: announcementSelect,
126
+ });
127
+ }
128
+
129
+ /** Delete an announcement. */
130
+ export function deleteAnnouncement(id: string) {
131
+ return prisma.announcement.delete({
132
+ where: { id },
133
+ });
134
+ }