@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,481 +0,0 @@
1
- import { z } from 'zod';
2
- import { createTRPCRouter, protectedProcedure } from '../trpc';
3
- import { prisma } from '../lib/prisma';
4
- import { TRPCError } from '@trpc/server';
5
- import { UserRole } from '@prisma/client';
6
- import { transport } from '../utils/email';
7
- import { generateInviteCode } from '../utils/generateInviteCode';
8
- import { hash } from 'bcryptjs';
9
- export const schoolRouter = createTRPCRouter({
10
- // Create a new school
11
- createSchool: protectedProcedure
12
- .input(z.object({
13
- name: z.string().min(1),
14
- subdomain: z.string().regex(/^[a-z0-9-]+$/, 'Subdomain can only contain lowercase letters, numbers, and hyphens')
15
- }))
16
- .mutation(async ({ input, ctx }) => {
17
- if (!ctx.user) {
18
- throw new TRPCError({
19
- code: 'UNAUTHORIZED',
20
- message: 'User must be authenticated'
21
- });
22
- }
23
- // Check if subdomain is already taken
24
- const existingSchool = await prisma.school.findUnique({
25
- where: { subdomain: input.subdomain }
26
- });
27
- if (existingSchool) {
28
- throw new TRPCError({
29
- code: 'CONFLICT',
30
- message: 'This subdomain is already taken'
31
- });
32
- }
33
- // Create a placeholder file for the logo
34
- const placeholderLogo = await prisma.file.create({
35
- data: {
36
- name: 'placeholder-logo',
37
- path: '/placeholder-logo.png',
38
- type: 'image/png',
39
- userId: ctx.user.id
40
- }
41
- });
42
- // Create the school
43
- const school = await prisma.school.create({
44
- data: {
45
- name: input.name,
46
- subdomain: input.subdomain,
47
- logoId: placeholderLogo.id,
48
- users: {
49
- connect: { id: ctx.user.id }
50
- }
51
- }
52
- });
53
- // Update the user to be an admin of this school
54
- await prisma.user.update({
55
- where: { id: ctx.user.id },
56
- data: {
57
- role: UserRole.ADMIN,
58
- schoolId: school.id
59
- }
60
- });
61
- return school;
62
- }),
63
- // Check if user is admin of the school
64
- checkAdmin: protectedProcedure
65
- .input(z.object({ schoolId: z.string() }))
66
- .query(async ({ input, ctx }) => {
67
- if (!ctx.user) {
68
- throw new TRPCError({
69
- code: 'UNAUTHORIZED',
70
- message: 'User must be authenticated'
71
- });
72
- }
73
- const user = await prisma.user.findFirst({
74
- where: {
75
- id: ctx.user.id,
76
- schoolId: input.schoolId,
77
- role: UserRole.ADMIN
78
- }
79
- });
80
- if (!user) {
81
- throw new TRPCError({
82
- code: 'FORBIDDEN',
83
- message: 'You must be a school admin to access this'
84
- });
85
- }
86
- return true;
87
- }),
88
- // Get all users in a school
89
- getUsers: protectedProcedure
90
- .input(z.object({
91
- schoolId: z.string(),
92
- role: z.enum(['STUDENT', 'TEACHER', 'ADMIN', 'NONE']).optional()
93
- }))
94
- .query(async ({ input, ctx }) => {
95
- if (!ctx.user) {
96
- throw new TRPCError({
97
- code: 'UNAUTHORIZED',
98
- message: 'User must be authenticated'
99
- });
100
- }
101
- // Check admin permission
102
- const isAdmin = await prisma.user.findFirst({
103
- where: {
104
- id: ctx.user.id,
105
- schoolId: input.schoolId,
106
- role: UserRole.ADMIN
107
- }
108
- });
109
- if (!isAdmin) {
110
- throw new TRPCError({ code: 'FORBIDDEN' });
111
- }
112
- return prisma.user.findMany({
113
- where: {
114
- schoolId: input.schoolId,
115
- ...(input.role && { role: input.role })
116
- },
117
- select: {
118
- id: true,
119
- username: true,
120
- email: true,
121
- role: true,
122
- verified: true,
123
- profile: true
124
- },
125
- orderBy: [
126
- { role: 'asc' },
127
- { username: 'asc' }
128
- ]
129
- });
130
- }),
131
- // Create a new user
132
- createUser: protectedProcedure
133
- .input(z.object({
134
- schoolId: z.string(),
135
- email: z.string().email(),
136
- username: z.string().min(3),
137
- role: z.enum(['STUDENT', 'TEACHER', 'ADMIN', 'NONE']),
138
- sendInvite: z.boolean().default(true)
139
- }))
140
- .mutation(async ({ input, ctx }) => {
141
- // Check admin permission
142
- const isAdmin = await prisma.user.findFirst({
143
- where: {
144
- id: ctx.user.id,
145
- schoolId: input.schoolId,
146
- role: UserRole.ADMIN
147
- }
148
- });
149
- if (!isAdmin) {
150
- throw new TRPCError({ code: 'FORBIDDEN' });
151
- }
152
- // Check if user already exists
153
- const existingUser = await prisma.user.findFirst({
154
- where: {
155
- OR: [
156
- { email: input.email },
157
- { username: input.username }
158
- ]
159
- }
160
- });
161
- if (existingUser) {
162
- throw new TRPCError({
163
- code: 'CONFLICT',
164
- message: 'User with this email or username already exists'
165
- });
166
- }
167
- // Generate temporary password
168
- const tempPassword = generateInviteCode();
169
- const hashedPassword = await hash(tempPassword, 10);
170
- const user = await prisma.user.create({
171
- data: {
172
- email: input.email,
173
- username: input.username,
174
- password: hashedPassword,
175
- role: input.role,
176
- schoolId: input.schoolId,
177
- verified: false
178
- }
179
- });
180
- // Send invite email
181
- if (input.sendInvite) {
182
- await transport.sendMail({
183
- from: process.env.EMAIL_FROM || 'noreply@studious.app',
184
- to: input.email,
185
- subject: 'Welcome to Studious',
186
- text: `You have been invited to join Studious. Your temporary password is: ${tempPassword}\n\nPlease change your password after logging in.`
187
- });
188
- }
189
- return user;
190
- }),
191
- // Bulk create users from JSON
192
- bulkCreateUsers: protectedProcedure
193
- .input(z.object({
194
- schoolId: z.string(),
195
- users: z.array(z.object({
196
- email: z.string().email(),
197
- username: z.string().min(3),
198
- role: z.enum(['STUDENT', 'TEACHER', 'ADMIN', 'NONE'])
199
- }))
200
- }))
201
- .mutation(async ({ input, ctx }) => {
202
- if (!ctx.user) {
203
- throw new TRPCError({
204
- code: 'UNAUTHORIZED',
205
- message: 'User must be authenticated'
206
- });
207
- }
208
- // Check admin permission
209
- const isAdmin = await prisma.user.findFirst({
210
- where: {
211
- id: ctx.user.id,
212
- schoolId: input.schoolId,
213
- role: UserRole.ADMIN
214
- }
215
- });
216
- if (!isAdmin) {
217
- throw new TRPCError({ code: 'FORBIDDEN' });
218
- }
219
- const results = [];
220
- const errors = [];
221
- for (const userData of input.users) {
222
- try {
223
- const tempPassword = generateInviteCode();
224
- const hashedPassword = await hash(tempPassword, 10);
225
- const user = await prisma.user.create({
226
- data: {
227
- email: userData.email,
228
- username: userData.username,
229
- password: hashedPassword,
230
- role: userData.role,
231
- schoolId: input.schoolId,
232
- verified: false
233
- }
234
- });
235
- // Send invite email
236
- await transport.sendMail({
237
- from: process.env.EMAIL_FROM || 'noreply@studious.app',
238
- to: userData.email,
239
- subject: 'Welcome to Studious',
240
- text: `You have been invited to join Studious. Your temporary password is: ${tempPassword}\n\nPlease change your password after logging in.`
241
- });
242
- results.push({ success: true, user });
243
- }
244
- catch (error) {
245
- errors.push({
246
- email: userData.email,
247
- error: error instanceof Error ? error.message : 'Unknown error'
248
- });
249
- }
250
- }
251
- return { results, errors };
252
- }),
253
- // Update user
254
- updateUser: protectedProcedure
255
- .input(z.object({
256
- userId: z.string(),
257
- schoolId: z.string(),
258
- role: z.enum(['STUDENT', 'TEACHER', 'ADMIN', 'NONE']).optional(),
259
- verified: z.boolean().optional()
260
- }))
261
- .mutation(async ({ input, ctx }) => {
262
- if (!ctx.user) {
263
- throw new TRPCError({
264
- code: 'UNAUTHORIZED',
265
- message: 'User must be authenticated'
266
- });
267
- }
268
- // Check admin permission
269
- const isAdmin = await prisma.user.findFirst({
270
- where: {
271
- id: ctx.user.id,
272
- schoolId: input.schoolId,
273
- role: UserRole.ADMIN
274
- }
275
- });
276
- if (!isAdmin) {
277
- throw new TRPCError({ code: 'FORBIDDEN' });
278
- }
279
- return prisma.user.update({
280
- where: { id: input.userId },
281
- data: {
282
- ...(input.role && { role: input.role }),
283
- ...(input.verified !== undefined && { verified: input.verified })
284
- }
285
- });
286
- }),
287
- // Delete user
288
- deleteUser: protectedProcedure
289
- .input(z.object({
290
- userId: z.string(),
291
- schoolId: z.string()
292
- }))
293
- .mutation(async ({ input, ctx }) => {
294
- if (!ctx.user) {
295
- throw new TRPCError({
296
- code: 'UNAUTHORIZED',
297
- message: 'User must be authenticated'
298
- });
299
- }
300
- // Check admin permission
301
- const isAdmin = await prisma.user.findFirst({
302
- where: {
303
- id: ctx.user.id,
304
- schoolId: input.schoolId,
305
- role: UserRole.ADMIN
306
- }
307
- });
308
- if (!isAdmin) {
309
- throw new TRPCError({ code: 'FORBIDDEN' });
310
- }
311
- // Don't allow deleting yourself
312
- if (input.userId === ctx.user.id) {
313
- throw new TRPCError({
314
- code: 'BAD_REQUEST',
315
- message: 'You cannot delete yourself'
316
- });
317
- }
318
- return prisma.user.delete({
319
- where: { id: input.userId }
320
- });
321
- }),
322
- // Get school info
323
- getSchool: protectedProcedure
324
- .input(z.object({ schoolId: z.string() }))
325
- .query(async ({ input }) => {
326
- return prisma.school.findUnique({
327
- where: { id: input.schoolId },
328
- include: {
329
- logo: true,
330
- _count: {
331
- select: {
332
- users: true,
333
- classes: true
334
- }
335
- }
336
- }
337
- });
338
- }),
339
- // Update school settings
340
- updateSchool: protectedProcedure
341
- .input(z.object({
342
- schoolId: z.string(),
343
- name: z.string().optional(),
344
- subdomain: z.string().optional(),
345
- logoId: z.string().optional()
346
- }))
347
- .mutation(async ({ input, ctx }) => {
348
- if (!ctx.user) {
349
- throw new TRPCError({
350
- code: 'UNAUTHORIZED',
351
- message: 'User must be authenticated'
352
- });
353
- }
354
- // Check admin permission
355
- const isAdmin = await prisma.user.findFirst({
356
- where: {
357
- id: ctx.user.id,
358
- schoolId: input.schoolId,
359
- role: UserRole.ADMIN
360
- }
361
- });
362
- if (!isAdmin) {
363
- throw new TRPCError({ code: 'FORBIDDEN' });
364
- }
365
- const updateData = {};
366
- if (input.name)
367
- updateData.name = input.name;
368
- if (input.subdomain)
369
- updateData.subdomain = input.subdomain;
370
- if (input.logoId)
371
- updateData.logoId = input.logoId;
372
- return prisma.school.update({
373
- where: { id: input.schoolId },
374
- data: updateData
375
- });
376
- }),
377
- // Get all classes in school
378
- getClasses: protectedProcedure
379
- .input(z.object({ schoolId: z.string() }))
380
- .query(async ({ input, ctx }) => {
381
- if (!ctx.user) {
382
- throw new TRPCError({
383
- code: 'UNAUTHORIZED',
384
- message: 'User must be authenticated'
385
- });
386
- }
387
- // Check if user belongs to school
388
- const user = await prisma.user.findFirst({
389
- where: {
390
- id: ctx.user.id,
391
- schoolId: input.schoolId
392
- }
393
- });
394
- if (!user) {
395
- throw new TRPCError({ code: 'FORBIDDEN' });
396
- }
397
- return prisma.class.findMany({
398
- where: { schoolId: input.schoolId },
399
- include: {
400
- _count: {
401
- select: {
402
- students: true,
403
- teachers: true,
404
- assignments: true
405
- }
406
- }
407
- },
408
- orderBy: { name: 'asc' }
409
- });
410
- }),
411
- // Send bulk email
412
- sendBulkEmail: protectedProcedure
413
- .input(z.object({
414
- schoolId: z.string(),
415
- subject: z.string(),
416
- content: z.string(),
417
- recipientRole: z.enum(['ALL', 'STUDENT', 'TEACHER', 'ADMIN']).optional(),
418
- recipientIds: z.array(z.string()).optional()
419
- }))
420
- .mutation(async ({ input, ctx }) => {
421
- if (!ctx.user) {
422
- throw new TRPCError({
423
- code: 'UNAUTHORIZED',
424
- message: 'User must be authenticated'
425
- });
426
- }
427
- // Check admin permission
428
- const isAdmin = await prisma.user.findFirst({
429
- where: {
430
- id: ctx.user.id,
431
- schoolId: input.schoolId,
432
- role: UserRole.ADMIN
433
- }
434
- });
435
- if (!isAdmin) {
436
- throw new TRPCError({ code: 'FORBIDDEN' });
437
- }
438
- // Get recipients
439
- let recipients = [];
440
- if (input.recipientIds && input.recipientIds.length > 0) {
441
- recipients = await prisma.user.findMany({
442
- where: {
443
- id: { in: input.recipientIds },
444
- schoolId: input.schoolId
445
- },
446
- select: { email: true }
447
- });
448
- }
449
- else {
450
- const whereClause = { schoolId: input.schoolId };
451
- if (input.recipientRole && input.recipientRole !== 'ALL') {
452
- whereClause.role = input.recipientRole;
453
- }
454
- recipients = await prisma.user.findMany({
455
- where: whereClause,
456
- select: { email: true }
457
- });
458
- }
459
- // Send emails
460
- const results = [];
461
- for (const recipient of recipients) {
462
- try {
463
- await transport.sendMail({
464
- from: process.env.EMAIL_FROM || 'noreply@studious.app',
465
- to: recipient.email,
466
- subject: input.subject,
467
- text: input.content
468
- });
469
- results.push({ email: recipient.email, success: true });
470
- }
471
- catch (error) {
472
- results.push({
473
- email: recipient.email,
474
- success: false,
475
- error: error instanceof Error ? error.message : 'Unknown error'
476
- });
477
- }
478
- }
479
- return results;
480
- })
481
- });
@@ -1,36 +0,0 @@
1
- import { prisma } from "./prisma.js";
2
-
3
- interface notificationData {
4
- title: string,
5
- content: string
6
- }
7
-
8
- export async function sendNotification(receiver: string, data: notificationData) {
9
- const notification = await prisma.notification.create({
10
- data: {
11
- receiverId: receiver,
12
- title: data.title,
13
- content: data.content,
14
- },
15
- });
16
- return notification;
17
- }
18
-
19
- export async function sendNotifications(receiverIds: Array<string>, data: notificationData) {
20
- const notifications = await prisma.notification.createMany({
21
- data: receiverIds.map(receiverId => ({
22
- receiverId: receiverId,
23
- title: data.title,
24
- content: data.content,
25
- })),
26
- });
27
- return notifications;
28
- }
29
-
30
- export async function markRead(id: string, read: boolean = true) {
31
- const notification = await prisma.notification.update({
32
- where: {id},
33
- data: {read: read},
34
- });
35
- return notification;
36
- }
@@ -1,25 +0,0 @@
1
- import { test, expect } from 'vitest';
2
- import { appRouter } from '../src/routers/_app';
3
- import { createTRPCContext } from '../src/trpc';
4
- import { prisma } from '../src/lib/prisma';
5
- import { caller, login1, login2, session1, session2, user1Caller, verification1, verification2 } from './setup';
6
-
7
- test('registration', async () => {
8
- expect(session1).toBeDefined();
9
- expect(session2).toBeDefined();
10
- });
11
-
12
- test('email verification', async () => {
13
- expect(verification1).toBeDefined();
14
- expect(verification2).toBeDefined();
15
- });
16
-
17
- test('login', async () => {
18
- expect(login1).toBeDefined();
19
- expect(login2).toBeDefined();
20
- });
21
-
22
- test('logout', async () => {
23
- const logout = await user1Caller.auth.logout();
24
- expect(logout).toBeDefined();
25
- });