@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
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attendance service – get and update class attendance records.
|
|
3
|
+
* Auto-creates attendance records for events that don't have them yet.
|
|
4
|
+
*/
|
|
5
|
+
import { TRPCError } from "@trpc/server";
|
|
6
|
+
import {
|
|
7
|
+
findClassWithStudents,
|
|
8
|
+
findClassWithTeacher,
|
|
9
|
+
findEventsByClassId,
|
|
10
|
+
findAttendanceByEventId,
|
|
11
|
+
findAttendanceByClassAndEvent,
|
|
12
|
+
findManyAttendance,
|
|
13
|
+
createAttendance,
|
|
14
|
+
createAttendanceForEvent,
|
|
15
|
+
updateAttendance,
|
|
16
|
+
} from "../models/attendance.js";
|
|
17
|
+
|
|
18
|
+
/** Get attendance for a class (optionally filtered by event). Creates missing records. */
|
|
19
|
+
export async function getAttendance(classId: string, eventId?: string) {
|
|
20
|
+
const classData = await findClassWithStudents(classId);
|
|
21
|
+
if (!classData) {
|
|
22
|
+
throw new TRPCError({
|
|
23
|
+
code: "UNAUTHORIZED",
|
|
24
|
+
message: "You are not authorized to view this class's attendance",
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const events = await findEventsByClassId(classId);
|
|
29
|
+
const studentIds = classData.students.map((s) => s.id);
|
|
30
|
+
|
|
31
|
+
for (const event of events) {
|
|
32
|
+
const existing = await findAttendanceByEventId(event.id);
|
|
33
|
+
if (!existing) {
|
|
34
|
+
await createAttendanceForEvent({
|
|
35
|
+
classId,
|
|
36
|
+
eventId: event.id,
|
|
37
|
+
presentIds: studentIds,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return findManyAttendance(classId, eventId);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Update attendance record (present/late/absent). Teacher-only. */
|
|
46
|
+
export async function updateAttendanceRecord(
|
|
47
|
+
userId: string,
|
|
48
|
+
classId: string,
|
|
49
|
+
eventId: string | null | undefined,
|
|
50
|
+
attendance: {
|
|
51
|
+
present: { id: string; username: string }[];
|
|
52
|
+
late: { id: string; username: string }[];
|
|
53
|
+
absent: { id: string; username: string }[];
|
|
54
|
+
}
|
|
55
|
+
) {
|
|
56
|
+
const classData = await findClassWithTeacher(classId, userId);
|
|
57
|
+
if (!classData) {
|
|
58
|
+
throw new TRPCError({
|
|
59
|
+
code: "UNAUTHORIZED",
|
|
60
|
+
message: "You are not authorized to update this class's attendance",
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const existing = await findAttendanceByClassAndEvent(classId, eventId ?? null);
|
|
65
|
+
|
|
66
|
+
const presentIds = attendance.present.map((s) => s.id);
|
|
67
|
+
const lateIds = attendance.late.map((s) => s.id);
|
|
68
|
+
const absentIds = attendance.absent.map((s) => s.id);
|
|
69
|
+
|
|
70
|
+
if (!existing) {
|
|
71
|
+
return createAttendance({
|
|
72
|
+
classId,
|
|
73
|
+
eventId: eventId ?? null,
|
|
74
|
+
presentIds,
|
|
75
|
+
lateIds,
|
|
76
|
+
absentIds,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return updateAttendance(existing.id, {
|
|
81
|
+
presentIds,
|
|
82
|
+
lateIds,
|
|
83
|
+
absentIds,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth service – user registration, login, logout, verification, and password reset.
|
|
3
|
+
* Handles session creation, Redis caching, and email notifications.
|
|
4
|
+
*/
|
|
5
|
+
import { TRPCError } from "@trpc/server";
|
|
6
|
+
import { v4 as uuidv4 } from "uuid";
|
|
7
|
+
import { compare, hash } from "bcryptjs";
|
|
8
|
+
import { sendMail } from "../utils/email.js";
|
|
9
|
+
import { prismaWrapper } from "../utils/prismaWrapper.js";
|
|
10
|
+
import { env } from "../lib/config/env.js";
|
|
11
|
+
import { logger } from "../utils/logger.js";
|
|
12
|
+
import {
|
|
13
|
+
findUserByUsername,
|
|
14
|
+
findUserByUsernameOrEmail,
|
|
15
|
+
findUserByEmail,
|
|
16
|
+
findUserById,
|
|
17
|
+
createUser,
|
|
18
|
+
createSession,
|
|
19
|
+
deleteSessionsByUserId,
|
|
20
|
+
deleteShortLivedSessionsByUserId,
|
|
21
|
+
deleteUserById,
|
|
22
|
+
findSessionById,
|
|
23
|
+
findSessionByIdWithUser,
|
|
24
|
+
updateUserVerified,
|
|
25
|
+
updateUserPassword,
|
|
26
|
+
deleteSessionById,
|
|
27
|
+
} from "../models/auth.js";
|
|
28
|
+
import { getRedis } from "../lib/redis.js";
|
|
29
|
+
|
|
30
|
+
/** Register a new user, create verification session, and send verification email. */
|
|
31
|
+
export async function register(input: {
|
|
32
|
+
username: string;
|
|
33
|
+
email: string;
|
|
34
|
+
password: string;
|
|
35
|
+
}) {
|
|
36
|
+
const { username, email, password } = input;
|
|
37
|
+
|
|
38
|
+
const existingUser = await prismaWrapper.findFirst(
|
|
39
|
+
() => findUserByUsernameOrEmail(username, email),
|
|
40
|
+
"checking for existing user during registration"
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (existingUser && existingUser.verified) {
|
|
44
|
+
if (existingUser.username === username) {
|
|
45
|
+
throw new TRPCError({
|
|
46
|
+
code: "CONFLICT",
|
|
47
|
+
message: "Username already exists",
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
if (existingUser.email === email) {
|
|
51
|
+
throw new TRPCError({
|
|
52
|
+
code: "CONFLICT",
|
|
53
|
+
message: "Email already exists",
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
} else if (existingUser && !existingUser.verified) {
|
|
57
|
+
await prismaWrapper.deleteMany(
|
|
58
|
+
() => deleteSessionsByUserId(existingUser.id),
|
|
59
|
+
"deleting existing sessions for unverified user"
|
|
60
|
+
);
|
|
61
|
+
await prismaWrapper.delete(
|
|
62
|
+
() => deleteUserById(existingUser.id),
|
|
63
|
+
"deleting unverified user"
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const user = await prismaWrapper.create(
|
|
68
|
+
async () =>
|
|
69
|
+
createUser({
|
|
70
|
+
username,
|
|
71
|
+
email,
|
|
72
|
+
password: await hash(password, 10),
|
|
73
|
+
verified: true,
|
|
74
|
+
}),
|
|
75
|
+
"creating new user during registration"
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const verificationToken = await prismaWrapper.create(
|
|
79
|
+
() =>
|
|
80
|
+
createSession({
|
|
81
|
+
id: uuidv4(),
|
|
82
|
+
userId: user.id,
|
|
83
|
+
expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30),
|
|
84
|
+
}),
|
|
85
|
+
"creating verification token"
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
await sendMail({
|
|
90
|
+
from: "hello@studious.sh",
|
|
91
|
+
to: user.email,
|
|
92
|
+
subject: "Verify your email",
|
|
93
|
+
text: `Click the link to verify your email: ${env.NEXT_PUBLIC_APP_URL}/verify/${verificationToken.id}`,
|
|
94
|
+
});
|
|
95
|
+
} catch (err) {
|
|
96
|
+
logger.error("Failed to send verification email", {
|
|
97
|
+
email: user.email,
|
|
98
|
+
err,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return { user: { id: user.id, username: user.username } };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Authenticate user by username/password, create session, and cache in Redis. */
|
|
106
|
+
export async function login(input: { username: string; password: string }) {
|
|
107
|
+
const { username, password } = input;
|
|
108
|
+
|
|
109
|
+
const user = await findUserByUsername(username);
|
|
110
|
+
if (!user) {
|
|
111
|
+
throw new TRPCError({
|
|
112
|
+
code: "UNAUTHORIZED",
|
|
113
|
+
message: "Invalid username or password",
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!(await compare(password, user.password))) {
|
|
118
|
+
throw new TRPCError({
|
|
119
|
+
code: "UNAUTHORIZED",
|
|
120
|
+
message: "Invalid username or password",
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!user.verified) {
|
|
125
|
+
return {
|
|
126
|
+
verified: false,
|
|
127
|
+
user: { email: user.email },
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const session = await createSession({
|
|
132
|
+
id: uuidv4(),
|
|
133
|
+
userId: user.id,
|
|
134
|
+
expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30),
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const cachePayload = JSON.stringify({ id: user.id, username: user.username });
|
|
138
|
+
const ttlSeconds = 30 * 24 * 60 * 60; // 30 days, match session expiry
|
|
139
|
+
const r = getRedis();
|
|
140
|
+
if (r) await r.setex(`session:${session.id}`, ttlSeconds, cachePayload);
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
token: session.id,
|
|
144
|
+
user: { id: user.id, username: user.username },
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Delete all sessions for a user (logs them out everywhere). */
|
|
149
|
+
export async function logout(userId: string) {
|
|
150
|
+
await deleteSessionsByUserId(userId);
|
|
151
|
+
return { success: true };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Verify user exists and return profile. Used for session validation. */
|
|
155
|
+
export async function check(userId: string) {
|
|
156
|
+
const user = await findUserById(userId);
|
|
157
|
+
if (!user) {
|
|
158
|
+
throw new TRPCError({
|
|
159
|
+
code: "NOT_FOUND",
|
|
160
|
+
message: "User not found",
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return { user };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Resend verification email. Replaces existing sessions and sends new link. */
|
|
167
|
+
export async function resendVerificationEmail(email: string) {
|
|
168
|
+
const user = await findUserByEmail(email);
|
|
169
|
+
if (!user) {
|
|
170
|
+
throw new TRPCError({
|
|
171
|
+
code: "NOT_FOUND",
|
|
172
|
+
message: "User not found",
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
await deleteSessionsByUserId(user.id);
|
|
177
|
+
|
|
178
|
+
const verificationToken = await createSession({
|
|
179
|
+
id: uuidv4(),
|
|
180
|
+
userId: user.id,
|
|
181
|
+
expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30),
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
await sendMail({
|
|
186
|
+
from: "hello@studious.sh",
|
|
187
|
+
to: user.email,
|
|
188
|
+
subject: "Verify your email",
|
|
189
|
+
text: `Click the link to verify your email: ${env.NEXT_PUBLIC_APP_URL}/verify/${verificationToken.id}`,
|
|
190
|
+
});
|
|
191
|
+
} catch (err) {
|
|
192
|
+
logger.error("Failed to send verification email", {
|
|
193
|
+
email: user.email,
|
|
194
|
+
err,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return { success: true };
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** Verify email via token. Marks user as verified and deletes the session. */
|
|
202
|
+
export async function verify(token: string) {
|
|
203
|
+
const session = await findSessionById(token);
|
|
204
|
+
if (!session) {
|
|
205
|
+
throw new TRPCError({
|
|
206
|
+
code: "NOT_FOUND",
|
|
207
|
+
message: "Session not found",
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (session.expiresAt && session.expiresAt < new Date()) {
|
|
212
|
+
throw new TRPCError({
|
|
213
|
+
code: "UNAUTHORIZED",
|
|
214
|
+
message: "Session expired",
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
await updateUserVerified(session.userId!, true);
|
|
219
|
+
await deleteSessionById(token);
|
|
220
|
+
return { success: true };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Send password reset email. Silently succeeds if email not found (security). */
|
|
224
|
+
export async function requestPasswordReset(email: string) {
|
|
225
|
+
const user = await findUserByEmail(email);
|
|
226
|
+
if (!user) {
|
|
227
|
+
return { success: true };
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const twoHoursFromNow = new Date(Date.now() + 1000 * 60 * 60 * 2);
|
|
231
|
+
await deleteShortLivedSessionsByUserId(user.id, twoHoursFromNow);
|
|
232
|
+
|
|
233
|
+
const resetToken = await createSession({
|
|
234
|
+
id: uuidv4(),
|
|
235
|
+
userId: user.id,
|
|
236
|
+
expiresAt: new Date(Date.now() + 1000 * 60 * 60),
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
try {
|
|
240
|
+
await sendMail({
|
|
241
|
+
from: "hello@studious.sh",
|
|
242
|
+
to: user.email,
|
|
243
|
+
subject: "Reset your password",
|
|
244
|
+
text: `Click the link to reset your password: ${env.NEXT_PUBLIC_APP_URL}/reset-password/${resetToken.id}`,
|
|
245
|
+
});
|
|
246
|
+
} catch (err) {
|
|
247
|
+
logger.error("Failed to send password reset email", {
|
|
248
|
+
email: user.email,
|
|
249
|
+
err,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return { success: true };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Reset password using token from email. Validates token and updates password. */
|
|
257
|
+
export async function resetPassword(token: string, password: string) {
|
|
258
|
+
const session = await findSessionByIdWithUser(token);
|
|
259
|
+
if (!session || !session.userId) {
|
|
260
|
+
throw new TRPCError({
|
|
261
|
+
code: "NOT_FOUND",
|
|
262
|
+
message: "Invalid or expired reset token",
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (session.expiresAt && session.expiresAt < new Date()) {
|
|
267
|
+
await deleteSessionById(token);
|
|
268
|
+
throw new TRPCError({
|
|
269
|
+
code: "UNAUTHORIZED",
|
|
270
|
+
message: "Reset token has expired",
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
await updateUserPassword(session.userId, await hash(password, 10));
|
|
275
|
+
await deleteSessionById(token);
|
|
276
|
+
return { success: true };
|
|
277
|
+
}
|