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