@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
@@ -1,25 +1,21 @@
1
+
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="2a91768b-a0eb-5556-9154-f76d73b01c49")}catch(e){}}();
1
3
  import { z } from "zod";
2
- import { createTRPCRouter, protectedProcedure, protectedClassMemberProcedure, protectedTeacherProcedure } from "../trpc.js";
3
- import { TRPCError } from "@trpc/server";
4
- import { prisma } from "../lib/prisma.js";
5
- import { createDirectUploadFiles } from "../lib/fileUpload.js";
6
- // DEPRECATED: This schema is no longer used - files are uploaded directly to GCS
7
- // Use directFileSchema instead
4
+ import { createTRPCRouter, protectedProcedure, protectedClassMemberProcedure, protectedTeacherProcedure, } from "../trpc.js";
5
+ import { createFolderRecord, getFolder, getChildFolders, getFolderChildren, getRootFolder, uploadFilesToFolder, deleteFolderRecord, moveFolder, updateFolderRecord, getFolderParents, getFolderUploadUrls, } from "../services/folder.js";
8
6
  const createFolderSchema = z.object({
9
7
  name: z.string(),
10
8
  parentFolderId: z.string().optional(),
11
9
  color: z.string().optional(),
12
10
  });
13
- // New schema for direct file uploads (no base64 data)
14
11
  const directFileSchema = z.object({
15
12
  name: z.string(),
16
13
  type: z.string(),
17
14
  size: z.number(),
18
- // No data field - for direct file uploads
19
15
  });
20
16
  const uploadFilesToFolderSchema = z.object({
21
17
  folderId: z.string(),
22
- files: z.array(directFileSchema), // Use direct file schema
18
+ files: z.array(directFileSchema),
23
19
  });
24
20
  const getRootFolderSchema = z.object({
25
21
  classId: z.string(),
@@ -28,488 +24,43 @@ export const folderRouter = createTRPCRouter({
28
24
  create: protectedTeacherProcedure
29
25
  .input(createFolderSchema)
30
26
  .mutation(async ({ ctx, input }) => {
31
- const { classId, name, color } = input;
32
- let parentFolderId = input.parentFolderId || null;
33
27
  if (!ctx.user) {
34
- throw new TRPCError({
35
- code: "UNAUTHORIZED",
36
- message: "You must be logged in to create a folder",
37
- });
28
+ throw new Error("You must be logged in to create a folder");
38
29
  }
39
- // Verify user is a teacher of the class
40
- const classData = await prisma.class.findFirst({
41
- where: {
42
- id: classId,
43
- teachers: {
44
- some: {
45
- id: ctx.user.id,
46
- },
47
- },
48
- },
30
+ return createFolderRecord(ctx.user.id, {
31
+ classId: input.classId,
32
+ name: input.name,
33
+ parentFolderId: input.parentFolderId,
34
+ color: input.color,
49
35
  });
50
- if (!classData) {
51
- throw new TRPCError({
52
- code: "NOT_FOUND",
53
- message: "Class not found or you are not a teacher",
54
- });
55
- }
56
- // If no parent folder specified, find or create the class parent folder
57
- if (!parentFolderId) {
58
- let classParentFolder = await prisma.folder.findFirst({
59
- where: {
60
- classId: classId,
61
- parentFolderId: null,
62
- },
63
- });
64
- if (!classParentFolder) {
65
- // Create parent folder if it doesn't exist
66
- classParentFolder = await prisma.folder.create({
67
- data: {
68
- name: "Class Files",
69
- class: {
70
- connect: { id: classId },
71
- },
72
- ...(color && {
73
- color: color,
74
- }),
75
- },
76
- });
77
- }
78
- parentFolderId = classParentFolder.id;
79
- }
80
- else {
81
- // Check if specified parent folder exists and belongs to the class
82
- const parentFolder = await prisma.folder.findFirst({
83
- where: {
84
- id: parentFolderId,
85
- },
86
- });
87
- if (!parentFolder) {
88
- throw new TRPCError({
89
- code: "NOT_FOUND",
90
- message: "Parent folder not found",
91
- });
92
- }
93
- }
94
- const folder = await prisma.folder.create({
95
- data: {
96
- name,
97
- ...(parentFolderId && {
98
- parentFolder: {
99
- connect: { id: parentFolderId },
100
- },
101
- }),
102
- ...(color && {
103
- color: color,
104
- }),
105
- },
106
- include: {
107
- files: {
108
- select: {
109
- id: true,
110
- name: true,
111
- type: true,
112
- size: true,
113
- uploadedAt: true,
114
- user: {
115
- select: {
116
- id: true,
117
- username: true,
118
- },
119
- },
120
- },
121
- },
122
- childFolders: {
123
- select: {
124
- id: true,
125
- name: true,
126
- _count: {
127
- select: {
128
- files: true,
129
- childFolders: true,
130
- },
131
- },
132
- },
133
- },
134
- },
135
- });
136
- return folder;
137
36
  }),
138
37
  get: protectedClassMemberProcedure
139
- .input(z.object({
140
- folderId: z.string(),
141
- classId: z.string(),
142
- }))
143
- .query(async ({ ctx, input }) => {
144
- const { classId, folderId } = input;
145
- // Get specific folder
146
- const folder = await prisma.folder.findFirst({
147
- where: {
148
- id: folderId,
149
- },
150
- include: {
151
- files: {
152
- select: {
153
- id: true,
154
- name: true,
155
- type: true,
156
- size: true,
157
- uploadedAt: true,
158
- user: {
159
- select: {
160
- id: true,
161
- username: true,
162
- },
163
- },
164
- },
165
- orderBy: {
166
- uploadedAt: 'desc',
167
- },
168
- },
169
- childFolders: {
170
- select: {
171
- id: true,
172
- name: true,
173
- color: true,
174
- _count: {
175
- select: {
176
- files: true,
177
- childFolders: true,
178
- },
179
- },
180
- },
181
- orderBy: {
182
- name: 'asc',
183
- },
184
- },
185
- parentFolder: {
186
- select: {
187
- id: true,
188
- name: true,
189
- },
190
- },
191
- },
192
- });
193
- if (!folder) {
194
- throw new TRPCError({
195
- code: "NOT_FOUND",
196
- message: "Folder not found",
197
- });
198
- }
199
- return folder;
200
- }),
38
+ .input(z.object({ folderId: z.string(), classId: z.string() }))
39
+ .query(({ input }) => getFolder(input.folderId)),
201
40
  getChildFolders: protectedClassMemberProcedure
202
- .input(z.object({
203
- classId: z.string(),
204
- }))
205
- .query(async ({ ctx, input }) => {
206
- const { classId } = input;
207
- // Get the parent folder for the class (or create it if it doesn't exist)
208
- let parentFolder = await prisma.folder.findFirst({
209
- where: {
210
- classId: classId,
211
- parentFolderId: null,
212
- },
213
- });
214
- if (!parentFolder) {
215
- // Create parent folder if it doesn't exist
216
- parentFolder = await prisma.folder.create({
217
- data: {
218
- name: "Class Files",
219
- class: {
220
- connect: { id: classId },
221
- },
222
- },
223
- });
224
- }
225
- // Get all child folders of the parent
226
- const childFolders = await prisma.folder.findMany({
227
- where: {
228
- parentFolderId: parentFolder.id,
229
- },
230
- include: {
231
- files: {
232
- select: {
233
- id: true,
234
- name: true,
235
- type: true,
236
- size: true,
237
- uploadedAt: true,
238
- user: {
239
- select: {
240
- id: true,
241
- username: true,
242
- },
243
- },
244
- },
245
- orderBy: {
246
- uploadedAt: 'desc',
247
- },
248
- },
249
- childFolders: {
250
- select: {
251
- id: true,
252
- name: true,
253
- _count: {
254
- select: {
255
- files: true,
256
- childFolders: true,
257
- },
258
- },
259
- },
260
- orderBy: {
261
- name: 'asc',
262
- },
263
- },
264
- },
265
- orderBy: {
266
- name: 'asc',
267
- },
268
- });
269
- return childFolders;
270
- }),
41
+ .input(z.object({ classId: z.string() }))
42
+ .query(({ input }) => getChildFolders(input.classId)),
271
43
  getFolderChildren: protectedClassMemberProcedure
272
- .input(z.object({
273
- folderId: z.string(),
274
- classId: z.string(),
275
- }))
276
- .query(async ({ ctx, input }) => {
277
- const { folderId, classId } = input;
278
- // Get direct children of the specified folder
279
- const children = await prisma.folder.findMany({
280
- where: {
281
- parentFolderId: folderId,
282
- classId: classId,
283
- },
284
- include: {
285
- files: {
286
- select: {
287
- id: true,
288
- name: true,
289
- type: true,
290
- size: true,
291
- uploadedAt: true,
292
- user: {
293
- select: {
294
- id: true,
295
- username: true,
296
- },
297
- },
298
- },
299
- orderBy: {
300
- uploadedAt: 'desc',
301
- },
302
- },
303
- childFolders: {
304
- select: {
305
- id: true,
306
- name: true,
307
- color: true,
308
- _count: {
309
- select: {
310
- files: true,
311
- childFolders: true,
312
- },
313
- },
314
- },
315
- orderBy: {
316
- name: 'asc',
317
- },
318
- },
319
- },
320
- orderBy: {
321
- name: 'asc',
322
- },
323
- });
324
- return children;
325
- }),
44
+ .input(z.object({ folderId: z.string(), classId: z.string() }))
45
+ .query(({ input }) => getFolderChildren(input.folderId, input.classId)),
326
46
  getRootFolder: protectedClassMemberProcedure
327
47
  .input(getRootFolderSchema)
328
- .query(async ({ ctx, input }) => {
329
- const { classId } = input;
330
- // Get or create the parent folder for the class
331
- let parentFolder = await prisma.folder.findFirst({
332
- where: {
333
- classId: classId,
334
- parentFolderId: null,
335
- },
336
- });
337
- if (!parentFolder) {
338
- // Create parent folder if it doesn't exist
339
- parentFolder = await prisma.folder.create({
340
- data: {
341
- name: "Class Files",
342
- class: {
343
- connect: { id: classId },
344
- },
345
- },
346
- });
347
- }
348
- // Get the parent folder with its files and child folders
349
- const rootFolder = await prisma.folder.findFirst({
350
- where: {
351
- id: parentFolder.id,
352
- classId: classId,
353
- },
354
- include: {
355
- files: {
356
- select: {
357
- id: true,
358
- name: true,
359
- type: true,
360
- size: true,
361
- uploadedAt: true,
362
- user: {
363
- select: {
364
- id: true,
365
- username: true,
366
- },
367
- },
368
- },
369
- orderBy: {
370
- uploadedAt: 'desc',
371
- },
372
- },
373
- childFolders: {
374
- select: {
375
- id: true,
376
- name: true,
377
- color: true,
378
- files: {
379
- select: {
380
- id: true,
381
- },
382
- },
383
- childFolders: {
384
- select: {
385
- id: true,
386
- },
387
- },
388
- },
389
- orderBy: {
390
- name: 'asc',
391
- },
392
- },
393
- },
394
- });
395
- return rootFolder;
396
- }),
48
+ .query(({ input }) => getRootFolder(input.classId)),
397
49
  uploadFiles: protectedTeacherProcedure
398
50
  .input(uploadFilesToFolderSchema)
399
51
  .mutation(async ({ ctx, input }) => {
400
- const { classId, folderId, files } = input;
401
52
  if (!ctx.user) {
402
- throw new TRPCError({
403
- code: "UNAUTHORIZED",
404
- message: "You must be logged in to upload files",
405
- });
406
- }
407
- // Verify user is a teacher of the class
408
- const classData = await prisma.class.findFirst({
409
- where: {
410
- id: classId,
411
- teachers: {
412
- some: {
413
- id: ctx.user.id,
414
- },
415
- },
416
- },
417
- });
418
- if (!classData) {
419
- throw new TRPCError({
420
- code: "NOT_FOUND",
421
- message: "Class not found or you are not a teacher",
422
- });
423
- }
424
- // Verify folder exists and belongs to the class
425
- const folder = await prisma.folder.findFirst({
426
- where: {
427
- id: folderId,
428
- },
429
- });
430
- if (!folder) {
431
- throw new TRPCError({
432
- code: "NOT_FOUND",
433
- message: "Folder not found",
434
- });
53
+ throw new Error("You must be logged in to upload files");
435
54
  }
436
- // Upload files
437
- const uploadedFiles = await createDirectUploadFiles(files, ctx.user.id, folder.id);
438
- // Create file records in database
439
- // const fileRecords = await prisma.file.createMany({
440
- // data: uploadedFiles.map(file => ({
441
- // name: file.name,
442
- // type: file.type,
443
- // size: file.size,
444
- // path: file.path,
445
- // userId: ctx.user!.id,
446
- // folderId: folderId,
447
- // ...(file.thumbnailId && {
448
- // thumbnailId: file.thumbnailId,
449
- // }),
450
- // })),
451
- // });
452
- return {
453
- success: true,
454
- uploadedCount: uploadedFiles.length,
455
- };
55
+ return uploadFilesToFolder(ctx.user.id, input.classId, input.folderId, input.files);
456
56
  }),
457
57
  delete: protectedTeacherProcedure
458
- .input(z.object({
459
- classId: z.string(),
460
- folderId: z.string(),
461
- }))
58
+ .input(z.object({ classId: z.string(), folderId: z.string() }))
462
59
  .mutation(async ({ ctx, input }) => {
463
- const { classId, folderId } = input;
464
- // Verify user is a teacher of the class
465
- const classData = await prisma.class.findFirst({
466
- where: {
467
- id: classId,
468
- teachers: {
469
- some: {
470
- id: ctx.user.id,
471
- },
472
- },
473
- },
474
- });
475
- if (!classData) {
476
- throw new TRPCError({
477
- code: "FORBIDDEN",
478
- message: "Class not found or you are not a teacher",
479
- });
480
- }
481
- // Verify folder exists and belongs to the class
482
- const folder = await prisma.folder.findFirst({
483
- where: {
484
- id: folderId,
485
- classId: classId,
486
- },
487
- include: {
488
- _count: {
489
- select: {
490
- files: true,
491
- childFolders: true,
492
- },
493
- },
494
- },
495
- });
496
- if (!folder) {
497
- throw new TRPCError({
498
- code: "NOT_FOUND",
499
- message: "Folder not found",
500
- });
60
+ if (!ctx.user) {
61
+ throw new Error("You must be logged in to delete folders");
501
62
  }
502
- // Delete folder and all its contents (cascade)
503
- await prisma.folder.delete({
504
- where: {
505
- id: folderId,
506
- },
507
- });
508
- return {
509
- success: true,
510
- deletedFiles: folder._count.files,
511
- deletedFolders: folder._count.childFolders + 1, // +1 for the folder itself
512
- };
63
+ return deleteFolderRecord(ctx.user.id, input.classId, input.folderId);
513
64
  }),
514
65
  move: protectedTeacherProcedure
515
66
  .input(z.object({
@@ -518,125 +69,10 @@ export const folderRouter = createTRPCRouter({
518
69
  classId: z.string(),
519
70
  }))
520
71
  .mutation(async ({ ctx, input }) => {
521
- const { folderId, targetParentFolderId, classId } = input;
522
- // Verify user is a teacher of the class
523
- const classData = await prisma.class.findFirst({
524
- where: {
525
- id: classId,
526
- teachers: {
527
- some: {
528
- id: ctx.user.id,
529
- },
530
- },
531
- },
532
- });
533
- if (!classData) {
534
- throw new TRPCError({
535
- code: "FORBIDDEN",
536
- message: "You must be a teacher of this class to move folders",
537
- });
538
- }
539
- // Get the folder to move
540
- const folder = await prisma.folder.findFirst({
541
- where: {
542
- id: folderId,
543
- },
544
- });
545
- if (!folder) {
546
- throw new TRPCError({
547
- code: "NOT_FOUND",
548
- message: "Folder not found",
549
- });
550
- }
551
- // Prevent moving the root folder
552
- if (!folder.parentFolderId) {
553
- throw new TRPCError({
554
- code: "BAD_REQUEST",
555
- message: "Cannot move the root folder",
556
- });
557
- }
558
- // If target parent folder is specified, verify it exists and belongs to the class
559
- if (targetParentFolderId) {
560
- const targetParentFolder = await prisma.folder.findFirst({
561
- where: {
562
- id: targetParentFolderId,
563
- },
564
- });
565
- if (!targetParentFolder) {
566
- throw new TRPCError({
567
- code: "NOT_FOUND",
568
- message: "Target parent folder not found",
569
- });
570
- }
571
- // Prevent moving a folder into itself or its descendants
572
- if (targetParentFolderId === folderId) {
573
- throw new TRPCError({
574
- code: "BAD_REQUEST",
575
- message: "Cannot move a folder into itself",
576
- });
577
- }
578
- // Check if target is a descendant of the folder being moved
579
- let currentParent = targetParentFolder;
580
- while (currentParent?.parentFolderId) {
581
- if (currentParent.parentFolderId === folderId) {
582
- throw new TRPCError({
583
- code: "BAD_REQUEST",
584
- message: "Cannot move a folder into its descendant",
585
- });
586
- }
587
- currentParent = await prisma.folder.findUnique({
588
- where: { id: currentParent.parentFolderId },
589
- });
590
- if (!currentParent)
591
- break;
592
- }
593
- }
594
- else {
595
- // Moving to root - verify the folder isn't already at root
596
- if (!folder.parentFolderId) {
597
- throw new TRPCError({
598
- code: "BAD_REQUEST",
599
- message: "Folder is already at root level",
600
- });
601
- }
72
+ if (!ctx.user) {
73
+ throw new Error("You must be logged in to move folders");
602
74
  }
603
- // Move the folder
604
- const updatedFolder = await prisma.folder.update({
605
- where: { id: folderId },
606
- data: {
607
- parentFolderId: targetParentFolderId,
608
- },
609
- include: {
610
- files: {
611
- select: {
612
- id: true,
613
- name: true,
614
- type: true,
615
- size: true,
616
- uploadedAt: true,
617
- user: {
618
- select: {
619
- id: true,
620
- username: true,
621
- },
622
- },
623
- },
624
- },
625
- childFolders: {
626
- select: {
627
- id: true,
628
- name: true,
629
- _count: {
630
- select: {
631
- files: true,
632
- childFolders: true,
633
- },
634
- },
635
- },
636
- },
637
- },
638
- });
639
- return updatedFolder;
75
+ return moveFolder(ctx.user.id, input.folderId, input.targetParentFolderId, input.classId);
640
76
  }),
641
77
  update: protectedTeacherProcedure
642
78
  .input(z.object({
@@ -645,87 +81,10 @@ export const folderRouter = createTRPCRouter({
645
81
  color: z.string().optional(),
646
82
  classId: z.string(),
647
83
  }))
648
- .mutation(async ({ ctx, input }) => {
649
- const { folderId, name, color, classId } = input;
650
- // Get the folder
651
- const folder = await prisma.folder.findFirst({
652
- where: {
653
- id: folderId,
654
- },
655
- });
656
- if (!folder) {
657
- throw new TRPCError({
658
- code: "NOT_FOUND",
659
- message: "Folder not found",
660
- });
661
- }
662
- // Validate new name
663
- if (!name.trim()) {
664
- throw new TRPCError({
665
- code: "BAD_REQUEST",
666
- message: "Folder name cannot be empty",
667
- });
668
- }
669
- // Rename the folder
670
- const updatedFolder = await prisma.folder.update({
671
- where: { id: folderId },
672
- data: {
673
- name: name.trim(),
674
- ...(color && {
675
- color: color,
676
- }),
677
- },
678
- include: {
679
- files: {
680
- select: {
681
- id: true,
682
- name: true,
683
- type: true,
684
- size: true,
685
- uploadedAt: true,
686
- user: {
687
- select: {
688
- id: true,
689
- username: true,
690
- },
691
- },
692
- },
693
- },
694
- childFolders: {
695
- select: {
696
- id: true,
697
- name: true,
698
- _count: {
699
- select: {
700
- files: true,
701
- childFolders: true,
702
- },
703
- },
704
- },
705
- },
706
- },
707
- });
708
- return updatedFolder;
709
- }),
84
+ .mutation(({ input }) => updateFolderRecord(input.folderId, input.name, input.color, input.classId)),
710
85
  getParents: protectedProcedure
711
- .input(z.object({
712
- folderId: z.string(),
713
- }))
714
- .query(async ({ ctx, input }) => {
715
- const { folderId } = input;
716
- let currentParent = folderId;
717
- const parents = [];
718
- while (currentParent) {
719
- const parent = await prisma.folder.findFirst({
720
- where: {
721
- id: currentParent,
722
- },
723
- });
724
- currentParent = parent?.parentFolderId;
725
- parents.push(parent);
726
- }
727
- return parents;
728
- }),
86
+ .input(z.object({ folderId: z.string() }))
87
+ .query(({ input }) => getFolderParents(input.folderId)),
729
88
  getFolderUploadUrls: protectedTeacherProcedure
730
89
  .input(z.object({
731
90
  classId: z.string(),
@@ -733,72 +92,10 @@ export const folderRouter = createTRPCRouter({
733
92
  files: z.array(directFileSchema),
734
93
  }))
735
94
  .mutation(async ({ ctx, input }) => {
736
- const { classId, folderId, files } = input;
737
95
  if (!ctx.user) {
738
- throw new TRPCError({
739
- code: "UNAUTHORIZED",
740
- message: "You must be logged in to upload files",
741
- });
742
- }
743
- // Verify user is a teacher of the class
744
- const classData = await prisma.class.findFirst({
745
- where: {
746
- id: classId,
747
- teachers: {
748
- some: {
749
- id: ctx.user.id,
750
- },
751
- },
752
- },
753
- });
754
- if (!classData) {
755
- throw new TRPCError({
756
- code: "NOT_FOUND",
757
- message: "Class not found or you are not a teacher",
758
- });
759
- }
760
- // Verify folder exists
761
- const folder = await prisma.folder.findUnique({
762
- where: {
763
- id: folderId,
764
- },
765
- });
766
- if (!folder) {
767
- throw new TRPCError({
768
- code: "NOT_FOUND",
769
- message: "Folder not found",
770
- });
771
- }
772
- // Verify folder belongs to the class by traversing parent hierarchy
773
- // Only root folders have classId, child folders use parentFolderId
774
- let currentFolder = folder;
775
- let belongsToClass = false;
776
- while (currentFolder) {
777
- // Check if we've reached a root folder with the matching classId
778
- if (currentFolder.classId === classId) {
779
- belongsToClass = true;
780
- break;
781
- }
782
- // If this folder has a parent, traverse up
783
- if (currentFolder.parentFolderId) {
784
- currentFolder = await prisma.folder.findUnique({
785
- where: { id: currentFolder.parentFolderId },
786
- });
787
- }
788
- else {
789
- // Reached a root folder without matching classId
790
- break;
791
- }
792
- }
793
- if (!belongsToClass) {
794
- throw new TRPCError({
795
- code: "FORBIDDEN",
796
- message: "Folder does not belong to this class",
797
- });
96
+ throw new Error("You must be logged in to upload files");
798
97
  }
799
- // Create direct upload files
800
- const uploadFiles = await createDirectUploadFiles(files, ctx.user.id, folder.id);
801
- return uploadFiles;
98
+ return getFolderUploadUrls(ctx.user.id, input.classId, input.folderId, input.files);
802
99
  }),
803
100
  confirmFolderUpload: protectedTeacherProcedure
804
101
  .input(z.object({
@@ -806,17 +103,13 @@ export const folderRouter = createTRPCRouter({
806
103
  uploadSuccess: z.boolean(),
807
104
  }))
808
105
  .mutation(async ({ ctx, input }) => {
809
- const { fileId, uploadSuccess } = input;
810
106
  if (!ctx.user) {
811
- throw new TRPCError({
812
- code: "UNAUTHORIZED",
813
- message: "You must be logged in to confirm uploads",
814
- });
107
+ throw new Error("You must be logged in to confirm uploads");
815
108
  }
816
- // Import the confirmDirectUpload function
817
109
  const { confirmDirectUpload } = await import("../lib/fileUpload.js");
818
- // Confirm the upload
819
- await confirmDirectUpload(fileId, uploadSuccess);
110
+ await confirmDirectUpload(input.fileId, input.uploadSuccess);
820
111
  return { success: true };
821
112
  }),
822
113
  });
114
+ //# sourceMappingURL=folder.js.map
115
+ //# debugId=2a91768b-a0eb-5556-9154-f76d73b01c49