@studious-lms/server 1.7.0 → 1.9.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.
Files changed (212) hide show
  1. package/dist/middleware/security.d.ts.map +1 -1
  2. package/dist/middleware/security.js +3 -3
  3. package/dist/middleware/security.js.map +1 -1
  4. package/dist/models/access.d.ts +21 -66
  5. package/dist/models/access.d.ts.map +1 -1
  6. package/dist/models/access.js +10 -26
  7. package/dist/models/access.js.map +1 -1
  8. package/dist/models/agenda.d.ts +4 -2
  9. package/dist/models/agenda.d.ts.map +1 -1
  10. package/dist/models/announcement.d.ts +4 -3
  11. package/dist/models/announcement.d.ts.map +1 -1
  12. package/dist/models/announcement.js +2 -3
  13. package/dist/models/announcement.js.map +1 -1
  14. package/dist/models/assignment.d.ts +40 -33
  15. package/dist/models/assignment.d.ts.map +1 -1
  16. package/dist/models/auth.d.ts +2 -4
  17. package/dist/models/auth.d.ts.map +1 -1
  18. package/dist/models/auth.js +2 -3
  19. package/dist/models/auth.js.map +1 -1
  20. package/dist/models/class.d.ts +34 -6
  21. package/dist/models/class.d.ts.map +1 -1
  22. package/dist/models/class.js +15 -2
  23. package/dist/models/class.js.map +1 -1
  24. package/dist/models/cloudStorage.d.ts +153 -0
  25. package/dist/models/cloudStorage.d.ts.map +1 -0
  26. package/dist/models/cloudStorage.js +295 -0
  27. package/dist/models/cloudStorage.js.map +1 -0
  28. package/dist/models/comment.d.ts +0 -24
  29. package/dist/models/comment.d.ts.map +1 -1
  30. package/dist/models/comment.js +2 -6
  31. package/dist/models/comment.js.map +1 -1
  32. package/dist/models/conversation.d.ts +22 -22
  33. package/dist/models/department.d.ts +154 -0
  34. package/dist/models/department.d.ts.map +1 -0
  35. package/dist/models/department.js +135 -0
  36. package/dist/models/department.js.map +1 -0
  37. package/dist/models/event.d.ts +10 -4
  38. package/dist/models/event.d.ts.map +1 -1
  39. package/dist/models/event.js +2 -5
  40. package/dist/models/event.js.map +1 -1
  41. package/dist/models/file.d.ts +52 -36
  42. package/dist/models/file.d.ts.map +1 -1
  43. package/dist/models/file.js +4 -42
  44. package/dist/models/file.js.map +1 -1
  45. package/dist/models/folder.d.ts +47 -0
  46. package/dist/models/folder.d.ts.map +1 -1
  47. package/dist/models/labChat.d.ts +11 -9
  48. package/dist/models/labChat.d.ts.map +1 -1
  49. package/dist/models/message.d.ts +46 -12
  50. package/dist/models/message.d.ts.map +1 -1
  51. package/dist/models/message.js +19 -10
  52. package/dist/models/message.js.map +1 -1
  53. package/dist/models/newtonChat.d.ts +2 -1
  54. package/dist/models/newtonChat.d.ts.map +1 -1
  55. package/dist/models/school.d.ts +45 -12
  56. package/dist/models/school.d.ts.map +1 -1
  57. package/dist/models/school.js +19 -2
  58. package/dist/models/school.js.map +1 -1
  59. package/dist/models/section.d.ts +2 -1
  60. package/dist/models/section.d.ts.map +1 -1
  61. package/dist/models/tag.d.ts +117 -0
  62. package/dist/models/tag.d.ts.map +1 -0
  63. package/dist/models/tag.js +113 -0
  64. package/dist/models/tag.js.map +1 -0
  65. package/dist/models/worksheet.d.ts +3 -0
  66. package/dist/models/worksheet.d.ts.map +1 -1
  67. package/dist/pipelines/aiLabChatContract.d.ts +8 -8
  68. package/dist/routers/_app.d.ts +6704 -5222
  69. package/dist/routers/_app.d.ts.map +1 -1
  70. package/dist/routers/_app.js +8 -2
  71. package/dist/routers/_app.js.map +1 -1
  72. package/dist/routers/agenda.d.ts +4 -2
  73. package/dist/routers/agenda.d.ts.map +1 -1
  74. package/dist/routers/announcement.d.ts.map +1 -1
  75. package/dist/routers/announcement.js +3 -5
  76. package/dist/routers/announcement.js.map +1 -1
  77. package/dist/routers/assignment.d.ts +49 -40
  78. package/dist/routers/assignment.d.ts.map +1 -1
  79. package/dist/routers/assignment.js +2 -3
  80. package/dist/routers/assignment.js.map +1 -1
  81. package/dist/routers/class.d.ts +92 -19
  82. package/dist/routers/class.d.ts.map +1 -1
  83. package/dist/routers/class.js +5 -2
  84. package/dist/routers/class.js.map +1 -1
  85. package/dist/routers/conversation.d.ts +5 -5
  86. package/dist/routers/department.d.ts +293 -0
  87. package/dist/routers/department.d.ts.map +1 -0
  88. package/dist/routers/department.js +93 -0
  89. package/dist/routers/department.js.map +1 -0
  90. package/dist/routers/event.d.ts +4 -3
  91. package/dist/routers/event.d.ts.map +1 -1
  92. package/dist/routers/file.d.ts +10 -8
  93. package/dist/routers/file.d.ts.map +1 -1
  94. package/dist/routers/file.js +26 -17
  95. package/dist/routers/file.js.map +1 -1
  96. package/dist/routers/folder.d.ts +163 -186
  97. package/dist/routers/folder.d.ts.map +1 -1
  98. package/dist/routers/folder.js +102 -88
  99. package/dist/routers/folder.js.map +1 -1
  100. package/dist/routers/labChat.d.ts +13 -4
  101. package/dist/routers/labChat.d.ts.map +1 -1
  102. package/dist/routers/message.d.ts +20 -2
  103. package/dist/routers/message.d.ts.map +1 -1
  104. package/dist/routers/newtonChat.d.ts +10 -1
  105. package/dist/routers/newtonChat.d.ts.map +1 -1
  106. package/dist/routers/permissions.d.ts +120 -0
  107. package/dist/routers/permissions.d.ts.map +1 -0
  108. package/dist/routers/permissions.js +50 -0
  109. package/dist/routers/permissions.js.map +1 -0
  110. package/dist/routers/school.d.ts +160 -17
  111. package/dist/routers/school.d.ts.map +1 -1
  112. package/dist/routers/school.js +46 -3
  113. package/dist/routers/school.js.map +1 -1
  114. package/dist/routers/tag.d.ts +119 -0
  115. package/dist/routers/tag.d.ts.map +1 -0
  116. package/dist/routers/tag.js +52 -0
  117. package/dist/routers/tag.js.map +1 -0
  118. package/dist/routers/worksheet.d.ts +1 -0
  119. package/dist/routers/worksheet.d.ts.map +1 -1
  120. package/dist/seedDatabase.d.ts +0 -1
  121. package/dist/seedDatabase.d.ts.map +1 -1
  122. package/dist/services/agenda.d.ts +4 -2
  123. package/dist/services/agenda.d.ts.map +1 -1
  124. package/dist/services/assignment.d.ts +49 -40
  125. package/dist/services/assignment.d.ts.map +1 -1
  126. package/dist/services/class.d.ts +92 -19
  127. package/dist/services/class.d.ts.map +1 -1
  128. package/dist/services/class.js +92 -5
  129. package/dist/services/class.js.map +1 -1
  130. package/dist/services/conversation.d.ts +5 -5
  131. package/dist/services/department.d.ts +200 -0
  132. package/dist/services/department.d.ts.map +1 -0
  133. package/dist/services/department.js +368 -0
  134. package/dist/services/department.js.map +1 -0
  135. package/dist/services/event.d.ts +4 -3
  136. package/dist/services/event.d.ts.map +1 -1
  137. package/dist/services/file.d.ts +105 -3
  138. package/dist/services/file.d.ts.map +1 -1
  139. package/dist/services/file.js +167 -41
  140. package/dist/services/file.js.map +1 -1
  141. package/dist/services/folder.d.ts +220 -149
  142. package/dist/services/folder.d.ts.map +1 -1
  143. package/dist/services/folder.js +326 -196
  144. package/dist/services/folder.js.map +1 -1
  145. package/dist/services/labChat.d.ts +13 -4
  146. package/dist/services/labChat.d.ts.map +1 -1
  147. package/dist/services/labChat.js +4 -3
  148. package/dist/services/labChat.js.map +1 -1
  149. package/dist/services/message.d.ts +20 -2
  150. package/dist/services/message.d.ts.map +1 -1
  151. package/dist/services/message.js +7 -23
  152. package/dist/services/message.js.map +1 -1
  153. package/dist/services/newtonChat.d.ts +9 -0
  154. package/dist/services/newtonChat.d.ts.map +1 -1
  155. package/dist/services/newtonChat.js +4 -3
  156. package/dist/services/newtonChat.js.map +1 -1
  157. package/dist/services/permissions.d.ts +188 -0
  158. package/dist/services/permissions.d.ts.map +1 -0
  159. package/dist/services/permissions.js +661 -0
  160. package/dist/services/permissions.js.map +1 -0
  161. package/dist/services/school.d.ts +142 -15
  162. package/dist/services/school.d.ts.map +1 -1
  163. package/dist/services/school.js +308 -54
  164. package/dist/services/school.js.map +1 -1
  165. package/dist/services/tag.d.ts +71 -0
  166. package/dist/services/tag.d.ts.map +1 -0
  167. package/dist/services/tag.js +178 -0
  168. package/dist/services/tag.js.map +1 -0
  169. package/dist/services/worksheet.d.ts +1 -0
  170. package/dist/services/worksheet.d.ts.map +1 -1
  171. package/dist/utils/aiUser.d.ts.map +1 -1
  172. package/dist/utils/aiUser.js +2 -3
  173. package/dist/utils/aiUser.js.map +1 -1
  174. package/package.json +1 -1
  175. package/prisma/migrations/20260509220000_institution_overhaul/migration.sql +184 -0
  176. package/prisma/migrations/20260510170000_add_folder_permissions/migration.sql +93 -0
  177. package/prisma/schema.prisma +193 -35
  178. package/src/middleware/security.ts +1 -1
  179. package/src/models/access.ts +8 -24
  180. package/src/models/announcement.ts +0 -1
  181. package/src/models/auth.ts +0 -1
  182. package/src/models/class.ts +13 -0
  183. package/src/models/cloudStorage.ts +327 -0
  184. package/src/models/comment.ts +0 -4
  185. package/src/models/department.ts +159 -0
  186. package/src/models/event.ts +0 -3
  187. package/src/models/file.ts +2 -40
  188. package/src/models/message.ts +19 -5
  189. package/src/models/school.ts +26 -0
  190. package/src/models/tag.ts +140 -0
  191. package/src/routers/_app.ts +6 -0
  192. package/src/routers/announcement.ts +1 -3
  193. package/src/routers/assignment.ts +0 -1
  194. package/src/routers/class.ts +3 -0
  195. package/src/routers/department.ts +174 -0
  196. package/src/routers/file.ts +29 -26
  197. package/src/routers/folder.ts +127 -118
  198. package/src/routers/permissions.ts +71 -0
  199. package/src/routers/school.ts +83 -0
  200. package/src/routers/tag.ts +78 -0
  201. package/src/services/class.ts +109 -4
  202. package/src/services/department.ts +478 -0
  203. package/src/services/file.ts +172 -43
  204. package/src/services/folder.ts +399 -237
  205. package/src/services/labChat.ts +2 -1
  206. package/src/services/message.ts +5 -21
  207. package/src/services/newtonChat.ts +2 -1
  208. package/src/services/permissions.ts +778 -0
  209. package/src/services/school.ts +369 -57
  210. package/src/services/tag.ts +229 -0
  211. package/src/utils/aiUser.ts +0 -1
  212. package/tests/unit/services/permissions.test.ts +463 -0
@@ -1 +1 @@
1
- {"version":3,"file":"security.d.ts","sourceRoot":"/","sources":["middleware/security.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,cAAc,sDAWzB,CAAC;AAGH,eAAO,MAAM,WAAW,sDAQtB,CAAC;AAGH,eAAO,MAAM,aAAa,sDAOxB,CAAC;AAGH,eAAO,MAAM,YAAY,sFAwBomF,CAAC,2BAA5nF,CAAC"}
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"/","sources":["middleware/security.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,cAAc,sDAWzB,CAAC;AAGH,eAAO,MAAM,WAAW,sDAQtB,CAAC;AAGH,eAAO,MAAM,aAAa,sDAOxB,CAAC;AAGH,eAAO,MAAM,YAAY,sFAwBmmF,CAAC,2BAA3nF,CAAC"}
@@ -1,5 +1,5 @@
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]="e27a3dc9-6e2a-5b94-b404-01bf23ea1d5f")}catch(e){}}();
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]="47d2d7ec-bf41-5da8-a7f7-78b133efc204")}catch(e){}}();
3
3
  import helmet from 'helmet';
4
4
  import rateLimit from 'express-rate-limit';
5
5
  const isDevelopment = process.env.NODE_ENV === 'development';
@@ -18,7 +18,7 @@ const rateLimitHandler = (req, res) => {
18
18
  // General API rate limiter - applies to all routes
19
19
  export const generalLimiter = rateLimit({
20
20
  windowMs: 10 * 60 * 1000, // 10 minutes
21
- max: 100, // Limit each IP to 100 requests per windowMs
21
+ max: 1000, // Limit each IP to 100 requests per windowMs
22
22
  message: 'Too many requests from this IP, please try again later.',
23
23
  standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
24
24
  legacyHeaders: false, // Disable the `X-RateLimit-*` headers
@@ -74,4 +74,4 @@ export const helmetConfig = helmet({
74
74
  },
75
75
  });
76
76
  //# sourceMappingURL=security.js.map
77
- //# debugId=e27a3dc9-6e2a-5b94-b404-01bf23ea1d5f
77
+ //# debugId=47d2d7ec-bf41-5da8-a7f7-78b133efc204
@@ -1 +1 @@
1
- {"version":3,"file":"security.js","sources":["middleware/security.ts"],"sourceRoot":"/","sourcesContent":["import helmet from 'helmet';\nimport rateLimit from 'express-rate-limit';\nimport type { Request, Response } from 'express';\n\nconst isDevelopment = process.env.NODE_ENV === 'development';\n\n// Custom handler for rate limit errors that returns JSON\n// This format can be intercepted on the frontend with:\n// error.data?.code === 'TOO_MANY_REQUESTS' || error.data?.httpStatus === 429\nconst rateLimitHandler = (req: Request, res: Response) => {\n // Return JSON structure that can be intercepted on frontend with:\n // error.data?.code === 'TOO_MANY_REQUESTS' || error.data?.httpStatus === 429\n // When tRPC wraps this, the response body becomes error.data, so we put code/httpStatus at top level\n res.status(429).json({\n code: 'TOO_MANY_REQUESTS',\n message: 'Too many requests, please try again later.',\n });\n};\n\n// General API rate limiter - applies to all routes\nexport const generalLimiter = rateLimit({\n windowMs: 10 * 60 * 1000, // 10 minutes\n max: 100, // Limit each IP to 100 requests per windowMs\n message: 'Too many requests from this IP, please try again later.',\n standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers\n legacyHeaders: false, // Disable the `X-RateLimit-*` headers\n handler: rateLimitHandler,\n skip: (req) => {\n // Skip rate limiting for health checks\n return req.path === '/health' || req.method === 'OPTIONS';\n },\n});\n\n// Stricter rate limiter for authentication endpoints\nexport const authLimiter = rateLimit({\n windowMs: 5 * 60 * 1000, // 5 minutes\n max: 5, // Limit each IP to 5 login attempts per windowMs\n message: 'Too many authentication attempts, please try again later.',\n standardHeaders: true,\n legacyHeaders: false,\n skipSuccessfulRequests: true, // Don't count successful requests\n handler: rateLimitHandler,\n});\n\n// File upload rate limiter\nexport const uploadLimiter = rateLimit({\n windowMs: 30 * 60 * 1000, // 30 minutes\n max: 50, // Limit each IP to 50 uploads per hour\n message: 'Too many file uploads, please try again later.',\n standardHeaders: true,\n legacyHeaders: false,\n handler: rateLimitHandler,\n});\n\n// Helmet configuration\nexport const helmetConfig = helmet({\n contentSecurityPolicy: {\n directives: {\n defaultSrc: [\"'self'\"],\n styleSrc: [\"'self'\", \"'unsafe-inline'\"], // Allow inline styles for tRPC panel\n // Allow inline scripts only in development (for tRPC panel)\n // In production, keep strict CSP without unsafe-inline\n scriptSrc: isDevelopment \n ? [\"'self'\", \"'unsafe-inline'\"] \n : [\"'self'\"],\n imgSrc: [\"'self'\", \"data:\", \"https:\"], // Allow images from any HTTPS source\n connectSrc: [\"'self'\", \"https://*.sentry.io\"], // Allow Sentry connections\n fontSrc: [\"'self'\", \"data:\"],\n objectSrc: [\"'none'\"],\n mediaSrc: [\"'self'\"],\n frameSrc: [\"'none'\"],\n },\n },\n crossOriginEmbedderPolicy: false, // Disable if you need to embed resources\n hsts: {\n maxAge: 31536000, // 1 year\n includeSubDomains: true,\n preload: true,\n },\n});"],"names":[],"mappings":";;AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,SAAS,MAAM,oBAAoB,CAAC;AAG3C,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,CAAC;AAE7D,yDAAyD;AACzD,uDAAuD;AACvD,6EAA6E;AAC7E,MAAM,gBAAgB,GAAG,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IACvD,kEAAkE;IAClE,6EAA6E;IAC7E,qGAAqG;IACrG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACnB,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,4CAA4C;KACtD,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,mDAAmD;AACnD,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;IACtC,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,aAAa;IACvC,GAAG,EAAE,GAAG,EAAE,6CAA6C;IACvD,OAAO,EAAE,yDAAyD;IAClE,eAAe,EAAE,IAAI,EAAE,sDAAsD;IAC7E,aAAa,EAAE,KAAK,EAAE,sCAAsC;IAC5D,OAAO,EAAE,gBAAgB;IACzB,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE;QACZ,uCAAuC;QACvC,OAAO,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC;IAC5D,CAAC;CACF,CAAC,CAAC;AAEH,qDAAqD;AACrD,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC;IACnC,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,YAAY;IACrC,GAAG,EAAE,CAAC,EAAE,iDAAiD;IACzD,OAAO,EAAE,2DAA2D;IACpE,eAAe,EAAE,IAAI;IACrB,aAAa,EAAE,KAAK;IACpB,sBAAsB,EAAE,IAAI,EAAE,kCAAkC;IAChE,OAAO,EAAE,gBAAgB;CAC1B,CAAC,CAAC;AAEH,2BAA2B;AAC3B,MAAM,CAAC,MAAM,aAAa,GAAG,SAAS,CAAC;IACrC,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,aAAa;IACvC,GAAG,EAAE,EAAE,EAAE,uCAAuC;IAChD,OAAO,EAAE,gDAAgD;IACzD,eAAe,EAAE,IAAI;IACrB,aAAa,EAAE,KAAK;IACpB,OAAO,EAAE,gBAAgB;CAC1B,CAAC,CAAC;AAEH,uBAAuB;AACvB,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC;IACjC,qBAAqB,EAAE;QACrB,UAAU,EAAE;YACV,UAAU,EAAE,CAAC,QAAQ,CAAC;YACtB,QAAQ,EAAE,CAAC,QAAQ,EAAE,iBAAiB,CAAC,EAAE,qCAAqC;YAC9E,4DAA4D;YAC5D,uDAAuD;YACvD,SAAS,EAAE,aAAa;gBACtB,CAAC,CAAC,CAAC,QAAQ,EAAE,iBAAiB,CAAC;gBAC/B,CAAC,CAAC,CAAC,QAAQ,CAAC;YACd,MAAM,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,qCAAqC;YAC5E,UAAU,EAAE,CAAC,QAAQ,EAAE,qBAAqB,CAAC,EAAE,2BAA2B;YAC1E,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;YAC5B,SAAS,EAAE,CAAC,QAAQ,CAAC;YACrB,QAAQ,EAAE,CAAC,QAAQ,CAAC;YACpB,QAAQ,EAAE,CAAC,QAAQ,CAAC;SACrB;KACF;IACD,yBAAyB,EAAE,KAAK,EAAE,yCAAyC;IAC3E,IAAI,EAAE;QACJ,MAAM,EAAE,QAAQ,EAAE,SAAS;QAC3B,iBAAiB,EAAE,IAAI;QACvB,OAAO,EAAE,IAAI;KACd;CACF,CAAC,CAAC","debug_id":"e27a3dc9-6e2a-5b94-b404-01bf23ea1d5f"}
1
+ {"version":3,"file":"security.js","sources":["middleware/security.ts"],"sourceRoot":"/","sourcesContent":["import helmet from 'helmet';\nimport rateLimit from 'express-rate-limit';\nimport type { Request, Response } from 'express';\n\nconst isDevelopment = process.env.NODE_ENV === 'development';\n\n// Custom handler for rate limit errors that returns JSON\n// This format can be intercepted on the frontend with:\n// error.data?.code === 'TOO_MANY_REQUESTS' || error.data?.httpStatus === 429\nconst rateLimitHandler = (req: Request, res: Response) => {\n // Return JSON structure that can be intercepted on frontend with:\n // error.data?.code === 'TOO_MANY_REQUESTS' || error.data?.httpStatus === 429\n // When tRPC wraps this, the response body becomes error.data, so we put code/httpStatus at top level\n res.status(429).json({\n code: 'TOO_MANY_REQUESTS',\n message: 'Too many requests, please try again later.',\n });\n};\n\n// General API rate limiter - applies to all routes\nexport const generalLimiter = rateLimit({\n windowMs: 10 * 60 * 1000, // 10 minutes\n max: 1000, // Limit each IP to 100 requests per windowMs\n message: 'Too many requests from this IP, please try again later.',\n standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers\n legacyHeaders: false, // Disable the `X-RateLimit-*` headers\n handler: rateLimitHandler,\n skip: (req) => {\n // Skip rate limiting for health checks\n return req.path === '/health' || req.method === 'OPTIONS';\n },\n});\n\n// Stricter rate limiter for authentication endpoints\nexport const authLimiter = rateLimit({\n windowMs: 5 * 60 * 1000, // 5 minutes\n max: 5, // Limit each IP to 5 login attempts per windowMs\n message: 'Too many authentication attempts, please try again later.',\n standardHeaders: true,\n legacyHeaders: false,\n skipSuccessfulRequests: true, // Don't count successful requests\n handler: rateLimitHandler,\n});\n\n// File upload rate limiter\nexport const uploadLimiter = rateLimit({\n windowMs: 30 * 60 * 1000, // 30 minutes\n max: 50, // Limit each IP to 50 uploads per hour\n message: 'Too many file uploads, please try again later.',\n standardHeaders: true,\n legacyHeaders: false,\n handler: rateLimitHandler,\n});\n\n// Helmet configuration\nexport const helmetConfig = helmet({\n contentSecurityPolicy: {\n directives: {\n defaultSrc: [\"'self'\"],\n styleSrc: [\"'self'\", \"'unsafe-inline'\"], // Allow inline styles for tRPC panel\n // Allow inline scripts only in development (for tRPC panel)\n // In production, keep strict CSP without unsafe-inline\n scriptSrc: isDevelopment \n ? [\"'self'\", \"'unsafe-inline'\"] \n : [\"'self'\"],\n imgSrc: [\"'self'\", \"data:\", \"https:\"], // Allow images from any HTTPS source\n connectSrc: [\"'self'\", \"https://*.sentry.io\"], // Allow Sentry connections\n fontSrc: [\"'self'\", \"data:\"],\n objectSrc: [\"'none'\"],\n mediaSrc: [\"'self'\"],\n frameSrc: [\"'none'\"],\n },\n },\n crossOriginEmbedderPolicy: false, // Disable if you need to embed resources\n hsts: {\n maxAge: 31536000, // 1 year\n includeSubDomains: true,\n preload: true,\n },\n});"],"names":[],"mappings":";;AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,SAAS,MAAM,oBAAoB,CAAC;AAG3C,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,CAAC;AAE7D,yDAAyD;AACzD,uDAAuD;AACvD,6EAA6E;AAC7E,MAAM,gBAAgB,GAAG,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IACvD,kEAAkE;IAClE,6EAA6E;IAC7E,qGAAqG;IACrG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACnB,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,4CAA4C;KACtD,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,mDAAmD;AACnD,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;IACtC,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,aAAa;IACvC,GAAG,EAAE,IAAI,EAAE,6CAA6C;IACxD,OAAO,EAAE,yDAAyD;IAClE,eAAe,EAAE,IAAI,EAAE,sDAAsD;IAC7E,aAAa,EAAE,KAAK,EAAE,sCAAsC;IAC5D,OAAO,EAAE,gBAAgB;IACzB,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE;QACZ,uCAAuC;QACvC,OAAO,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC;IAC5D,CAAC;CACF,CAAC,CAAC;AAEH,qDAAqD;AACrD,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC;IACnC,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,YAAY;IACrC,GAAG,EAAE,CAAC,EAAE,iDAAiD;IACzD,OAAO,EAAE,2DAA2D;IACpE,eAAe,EAAE,IAAI;IACrB,aAAa,EAAE,KAAK;IACpB,sBAAsB,EAAE,IAAI,EAAE,kCAAkC;IAChE,OAAO,EAAE,gBAAgB;CAC1B,CAAC,CAAC;AAEH,2BAA2B;AAC3B,MAAM,CAAC,MAAM,aAAa,GAAG,SAAS,CAAC;IACrC,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,aAAa;IACvC,GAAG,EAAE,EAAE,EAAE,uCAAuC;IAChD,OAAO,EAAE,gDAAgD;IACzD,eAAe,EAAE,IAAI;IACrB,aAAa,EAAE,KAAK;IACpB,OAAO,EAAE,gBAAgB;CAC1B,CAAC,CAAC;AAEH,uBAAuB;AACvB,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC;IACjC,qBAAqB,EAAE;QACrB,UAAU,EAAE;YACV,UAAU,EAAE,CAAC,QAAQ,CAAC;YACtB,QAAQ,EAAE,CAAC,QAAQ,EAAE,iBAAiB,CAAC,EAAE,qCAAqC;YAC9E,4DAA4D;YAC5D,uDAAuD;YACvD,SAAS,EAAE,aAAa;gBACtB,CAAC,CAAC,CAAC,QAAQ,EAAE,iBAAiB,CAAC;gBAC/B,CAAC,CAAC,CAAC,QAAQ,CAAC;YACd,MAAM,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,qCAAqC;YAC5E,UAAU,EAAE,CAAC,QAAQ,EAAE,qBAAqB,CAAC,EAAE,2BAA2B;YAC1E,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;YAC5B,SAAS,EAAE,CAAC,QAAQ,CAAC;YACrB,QAAQ,EAAE,CAAC,QAAQ,CAAC;YACpB,QAAQ,EAAE,CAAC,QAAQ,CAAC;SACrB;KACF;IACD,yBAAyB,EAAE,KAAK,EAAE,yCAAyC;IAC3E,IAAI,EAAE;QACJ,MAAM,EAAE,QAAQ,EAAE,SAAS;QAC3B,iBAAiB,EAAE,IAAI;QACvB,OAAO,EAAE,IAAI;KACd;CACF,CAAC,CAAC","debug_id":"47d2d7ec-bf41-5da8-a7f7-78b133efc204"}
@@ -2,6 +2,19 @@
2
2
  * Shared class access filters.
3
3
  */
4
4
  export declare const schoolAdminForClassWhere: (userId: string) => {
5
+ school: {
6
+ is: {
7
+ memberships: {
8
+ some: {
9
+ userId: string;
10
+ role: "ADMIN";
11
+ status: "ACTIVE";
12
+ };
13
+ };
14
+ };
15
+ };
16
+ };
17
+ export declare const classTeacherOrSchoolAdminWhere: (userId: string) => {
5
18
  OR: ({
6
19
  school: {
7
20
  is: {
@@ -12,51 +25,8 @@ export declare const schoolAdminForClassWhere: (userId: string) => {
12
25
  status: "ACTIVE";
13
26
  };
14
27
  };
15
- users?: undefined;
16
28
  };
17
29
  };
18
- } | {
19
- school: {
20
- is: {
21
- users: {
22
- some: {
23
- id: string;
24
- role: "ADMIN";
25
- };
26
- };
27
- memberships?: undefined;
28
- };
29
- };
30
- })[];
31
- };
32
- export declare const classTeacherOrSchoolAdminWhere: (userId: string) => {
33
- OR: ({
34
- OR: ({
35
- school: {
36
- is: {
37
- memberships: {
38
- some: {
39
- userId: string;
40
- role: "ADMIN";
41
- status: "ACTIVE";
42
- };
43
- };
44
- users?: undefined;
45
- };
46
- };
47
- } | {
48
- school: {
49
- is: {
50
- users: {
51
- some: {
52
- id: string;
53
- role: "ADMIN";
54
- };
55
- };
56
- memberships?: undefined;
57
- };
58
- };
59
- })[];
60
30
  } | {
61
31
  teachers: {
62
32
  some: {
@@ -67,32 +37,17 @@ export declare const classTeacherOrSchoolAdminWhere: (userId: string) => {
67
37
  };
68
38
  export declare const classMemberOrSchoolAdminWhere: (userId: string) => {
69
39
  OR: ({
70
- OR: ({
71
- school: {
72
- is: {
73
- memberships: {
74
- some: {
75
- userId: string;
76
- role: "ADMIN";
77
- status: "ACTIVE";
78
- };
79
- };
80
- users?: undefined;
81
- };
82
- };
83
- } | {
84
- school: {
85
- is: {
86
- users: {
87
- some: {
88
- id: string;
89
- role: "ADMIN";
90
- };
40
+ school: {
41
+ is: {
42
+ memberships: {
43
+ some: {
44
+ userId: string;
45
+ role: "ADMIN";
46
+ status: "ACTIVE";
91
47
  };
92
- memberships?: undefined;
93
48
  };
94
49
  };
95
- })[];
50
+ };
96
51
  } | {
97
52
  teachers: {
98
53
  some: {
@@ -1 +1 @@
1
- {"version":3,"file":"access.d.ts","sourceRoot":"/","sources":["models/access.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,wBAAwB,GAAI,QAAQ,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BrD,CAAC;AAEH,eAAO,MAAM,8BAA8B,GAAI,QAAQ,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAK3D,CAAC;AAEH,eAAO,MAAM,6BAA6B,GAAI,QAAQ,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAM1D,CAAC"}
1
+ {"version":3,"file":"access.d.ts","sourceRoot":"/","sources":["models/access.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,wBAAwB,GAAI,QAAQ,MAAM;;;;;;;;;;;;CAYrD,CAAC;AAEH,eAAO,MAAM,8BAA8B,GAAI,QAAQ,MAAM;;;;;;;;;;;;;;;;;;;;CAK3D,CAAC;AAEH,eAAO,MAAM,6BAA6B,GAAI,QAAQ,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAM1D,CAAC"}
@@ -2,35 +2,19 @@
2
2
  * Shared class access filters.
3
3
  */
4
4
 
5
- !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]="7b5148ef-61c8-512a-bcea-eacfc9066ef7")}catch(e){}}();
5
+ !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]="b65c6e67-304e-5332-a128-b7d7a28437e7")}catch(e){}}();
6
6
  export const schoolAdminForClassWhere = (userId) => ({
7
- OR: [
8
- {
9
- school: {
10
- is: {
11
- memberships: {
12
- some: {
13
- userId,
14
- role: "ADMIN",
15
- status: "ACTIVE",
16
- },
17
- },
7
+ school: {
8
+ is: {
9
+ memberships: {
10
+ some: {
11
+ userId,
12
+ role: "ADMIN",
13
+ status: "ACTIVE",
18
14
  },
19
15
  },
20
16
  },
21
- {
22
- school: {
23
- is: {
24
- users: {
25
- some: {
26
- id: userId,
27
- role: "ADMIN",
28
- },
29
- },
30
- },
31
- },
32
- },
33
- ],
17
+ },
34
18
  });
35
19
  export const classTeacherOrSchoolAdminWhere = (userId) => ({
36
20
  OR: [
@@ -46,4 +30,4 @@ export const classMemberOrSchoolAdminWhere = (userId) => ({
46
30
  ],
47
31
  });
48
32
  //# sourceMappingURL=access.js.map
49
- //# debugId=7b5148ef-61c8-512a-bcea-eacfc9066ef7
33
+ //# debugId=b65c6e67-304e-5332-a128-b7d7a28437e7
@@ -1 +1 @@
1
- {"version":3,"file":"access.js","sources":["models/access.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Shared class access filters.\n */\n\nexport const schoolAdminForClassWhere = (userId: string) => ({\n OR: [\n {\n school: {\n is: {\n memberships: {\n some: {\n userId,\n role: \"ADMIN\" as const,\n status: \"ACTIVE\" as const,\n },\n },\n },\n },\n },\n {\n school: {\n is: {\n users: {\n some: {\n id: userId,\n role: \"ADMIN\" as const,\n },\n },\n },\n },\n },\n ],\n});\n\nexport const classTeacherOrSchoolAdminWhere = (userId: string) => ({\n OR: [\n { teachers: { some: { id: userId } } },\n schoolAdminForClassWhere(userId),\n ],\n});\n\nexport const classMemberOrSchoolAdminWhere = (userId: string) => ({\n OR: [\n { teachers: { some: { id: userId } } },\n { students: { some: { id: userId } } },\n schoolAdminForClassWhere(userId),\n ],\n});\n"],"names":[],"mappings":"AAAA;;GAEG;;;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,CAAC;IAC3D,EAAE,EAAE;QACF;YACE,MAAM,EAAE;gBACN,EAAE,EAAE;oBACF,WAAW,EAAE;wBACX,IAAI,EAAE;4BACJ,MAAM;4BACN,IAAI,EAAE,OAAgB;4BACtB,MAAM,EAAE,QAAiB;yBAC1B;qBACF;iBACF;aACF;SACF;QACD;YACE,MAAM,EAAE;gBACN,EAAE,EAAE;oBACF,KAAK,EAAE;wBACL,IAAI,EAAE;4BACJ,EAAE,EAAE,MAAM;4BACV,IAAI,EAAE,OAAgB;yBACvB;qBACF;iBACF;aACF;SACF;KACF;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,CAAC;IACjE,EAAE,EAAE;QACF,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACtC,wBAAwB,CAAC,MAAM,CAAC;KACjC;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,CAAC;IAChE,EAAE,EAAE;QACF,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACtC,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACtC,wBAAwB,CAAC,MAAM,CAAC;KACjC;CACF,CAAC,CAAC","debug_id":"7b5148ef-61c8-512a-bcea-eacfc9066ef7"}
1
+ {"version":3,"file":"access.js","sources":["models/access.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Shared class access filters.\n */\n\nexport const schoolAdminForClassWhere = (userId: string) => ({\n school: {\n is: {\n memberships: {\n some: {\n userId,\n role: \"ADMIN\" as const,\n status: \"ACTIVE\" as const,\n },\n },\n },\n },\n});\n\nexport const classTeacherOrSchoolAdminWhere = (userId: string) => ({\n OR: [\n { teachers: { some: { id: userId } } },\n schoolAdminForClassWhere(userId),\n ],\n});\n\nexport const classMemberOrSchoolAdminWhere = (userId: string) => ({\n OR: [\n { teachers: { some: { id: userId } } },\n { students: { some: { id: userId } } },\n schoolAdminForClassWhere(userId),\n ],\n});\n"],"names":[],"mappings":"AAAA;;GAEG;;;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,CAAC;IAC3D,MAAM,EAAE;QACN,EAAE,EAAE;YACF,WAAW,EAAE;gBACX,IAAI,EAAE;oBACJ,MAAM;oBACN,IAAI,EAAE,OAAgB;oBACtB,MAAM,EAAE,QAAiB;iBAC1B;aACF;SACF;KACF;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,CAAC;IACjE,EAAE,EAAE;QACF,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACtC,wBAAwB,CAAC,MAAM,CAAC;KACjC;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,CAAC;IAChE,EAAE,EAAE;QACF,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACtC,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACtC,wBAAwB,CAAC,MAAM,CAAC;KACjC;CACF,CAAC,CAAC","debug_id":"b65c6e67-304e-5332-a128-b7d7a28437e7"}
@@ -8,13 +8,14 @@ export declare function findPersonalEvents(userId: string, rangeStart: Date, ran
8
8
  color: string | null;
9
9
  section: string;
10
10
  syllabus: string | null;
11
+ departmentId: string | null;
11
12
  } | null;
12
13
  assignmentsAttached: {
13
14
  type: import(".prisma/client").$Enums.AssignmentType;
14
15
  id: string;
15
16
  createdAt: Date | null;
16
- modifiedAt: Date | null;
17
17
  classId: string;
18
+ modifiedAt: Date | null;
18
19
  title: string;
19
20
  instructions: string;
20
21
  dueDate: Date;
@@ -56,13 +57,14 @@ export declare function findClassEvents(userId: string, rangeStart: Date, rangeE
56
57
  color: string | null;
57
58
  section: string;
58
59
  syllabus: string | null;
60
+ departmentId: string | null;
59
61
  } | null;
60
62
  assignmentsAttached: {
61
63
  type: import(".prisma/client").$Enums.AssignmentType;
62
64
  id: string;
63
65
  createdAt: Date | null;
64
- modifiedAt: Date | null;
65
66
  classId: string;
67
+ modifiedAt: Date | null;
66
68
  title: string;
67
69
  instructions: string;
68
70
  dueDate: Date;
@@ -1 +1 @@
1
- {"version":3,"file":"agenda.d.ts","sourceRoot":"/","sources":["models/agenda.ts"],"names":[],"mappings":"AAKA,kEAAkE;AAClE,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,IAAI,EAChB,QAAQ,EAAE,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAaf;AAED,8DAA8D;AAC9D,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,IAAI,EAChB,QAAQ,EAAE,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAiBf"}
1
+ {"version":3,"file":"agenda.d.ts","sourceRoot":"/","sources":["models/agenda.ts"],"names":[],"mappings":"AAKA,kEAAkE;AAClE,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,IAAI,EAChB,QAAQ,EAAE,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAaf;AAED,8DAA8D;AAC9D,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,IAAI,EAChB,QAAQ,EAAE,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAiBf"}
@@ -100,6 +100,7 @@ export declare function findAnnouncementWithClass(id: string): import(".prisma/c
100
100
  } & {
101
101
  name: string;
102
102
  id: string;
103
+ description: string | null;
103
104
  logoId: string | null;
104
105
  subdomain: string | null;
105
106
  createdAt: Date;
@@ -111,7 +112,6 @@ export declare function findAnnouncementWithClass(id: string): import(".prisma/c
111
112
  email: string;
112
113
  password: string;
113
114
  verified: boolean;
114
- role: import(".prisma/client").$Enums.UserRole;
115
115
  schoolId: string | null;
116
116
  }[];
117
117
  } & {
@@ -122,6 +122,7 @@ export declare function findAnnouncementWithClass(id: string): import(".prisma/c
122
122
  color: string | null;
123
123
  section: string;
124
124
  syllabus: string | null;
125
+ departmentId: string | null;
125
126
  };
126
127
  attachments: {
127
128
  path: string;
@@ -137,8 +138,8 @@ export declare function findAnnouncementWithClass(id: string): import(".prisma/c
137
138
  } & {
138
139
  id: string;
139
140
  createdAt: Date;
140
- modifiedAt: Date | null;
141
141
  classId: string;
142
+ modifiedAt: Date | null;
142
143
  teacherId: string;
143
144
  remarks: string;
144
145
  }) | null, null, import("@prisma/client/runtime/library.js").DefaultArgs, {
@@ -260,8 +261,8 @@ export declare function updateAnnouncement(id: string, data: {
260
261
  export declare function deleteAnnouncement(id: string): import(".prisma/client").Prisma.Prisma__AnnouncementClient<{
261
262
  id: string;
262
263
  createdAt: Date;
263
- modifiedAt: Date | null;
264
264
  classId: string;
265
+ modifiedAt: Date | null;
265
266
  teacherId: string;
266
267
  remarks: string;
267
268
  }, never, import("@prisma/client/runtime/library.js").DefaultArgs, {
@@ -1 +1 @@
1
- {"version":3,"file":"announcement.d.ts","sourceRoot":"/","sources":["models/announcement.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6B9B,CAAC;AAEF,0CAA0C;AAC1C,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;KAWzD;AAED,6CAA6C;AAC7C,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAKvE;AAED,yEAAyE;AACzE,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCnD;AAED,8BAA8B;AAC9B,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GASA;AAED,uCAAuC;AACvC,wBAAgB,6BAA6B,CAC3C,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,OAAO,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE;QAAE,EAAE,EAAE;YAAE,EAAE,EAAE,MAAM,EAAE,CAAA;SAAE,CAAA;KAAE,CAAC;CACvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAcF;AAED,mCAAmC;AACnC,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAMxE;AAED,8BAA8B;AAC9B,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;GAI5C"}
1
+ {"version":3,"file":"announcement.d.ts","sourceRoot":"/","sources":["models/announcement.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6B9B,CAAC;AAEF,0CAA0C;AAC1C,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;KAWzD;AAED,6CAA6C;AAC7C,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAKvE;AAED,yEAAyE;AACzE,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCnD;AAED,8BAA8B;AAC9B,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GASA;AAED,uCAAuC;AACvC,wBAAgB,6BAA6B,CAC3C,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,OAAO,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE;QAAE,EAAE,EAAE;YAAE,EAAE,EAAE,MAAM,EAAE,CAAA;SAAE,CAAA;KAAE,CAAC;CACvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAcF;AAED,mCAAmC;AACnC,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAMxE;AAED,8BAA8B;AAC9B,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;GAI5C"}
@@ -2,7 +2,7 @@
2
2
  * Announcement model – announcements, attachments, comments.
3
3
  */
4
4
 
5
- !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]="fff848bf-ce06-59fe-83ea-7a9d6e208421")}catch(e){}}();
5
+ !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]="13cd5c13-3abf-5ea9-9021-98ba4c1cc38d")}catch(e){}}();
6
6
  import { prisma } from "../lib/prisma.js";
7
7
  export const announcementSelect = {
8
8
  id: true,
@@ -65,7 +65,6 @@ export function findAnnouncementWithClass(id) {
65
65
  school: {
66
66
  include: {
67
67
  users: {
68
- where: { role: "ADMIN" },
69
68
  select: { id: true },
70
69
  },
71
70
  memberships: {
@@ -134,4 +133,4 @@ export function deleteAnnouncement(id) {
134
133
  });
135
134
  }
136
135
  //# sourceMappingURL=announcement.js.map
137
- //# debugId=fff848bf-ce06-59fe-83ea-7a9d6e208421
136
+ //# debugId=13cd5c13-3abf-5ea9-9021-98ba4c1cc38d
@@ -1 +1 @@
1
- {"version":3,"file":"announcement.js","sources":["models/announcement.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Announcement model – announcements, attachments, comments.\n */\nimport { prisma } from \"../lib/prisma.js\";\n\nexport const announcementSelect = {\n id: true,\n teacher: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n profilePictureThumbnail: true,\n },\n },\n },\n },\n remarks: true,\n createdAt: true,\n modifiedAt: true,\n attachments: {\n select: {\n id: true,\n name: true,\n type: true,\n size: true,\n path: true,\n uploadedAt: true,\n thumbnailId: true,\n },\n },\n};\n\n/** @returns Announcements for a class. */\nexport function findAnnouncementsByClassId(classId: string) {\n return prisma.announcement.findMany({\n where: { classId },\n select: {\n ...announcementSelect,\n _count: {\n select: { comments: true },\n },\n },\n orderBy: { createdAt: \"desc\" },\n });\n}\n\n/** @returns Announcement by ID and class. */\nexport function findAnnouncementByIdAndClass(id: string, classId: string) {\n return prisma.announcement.findFirst({\n where: { id, classId },\n select: announcementSelect,\n });\n}\n\n/** @returns Announcement by ID with class teachers and school admins. */\nexport function findAnnouncementWithClass(id: string) {\n return prisma.announcement.findUnique({\n where: { id },\n include: {\n class: {\n include: {\n teachers: true,\n school: {\n include: {\n users: {\n where: { role: \"ADMIN\" as const },\n select: { id: true },\n },\n memberships: {\n where: {\n role: \"ADMIN\" as const,\n status: \"ACTIVE\" as const,\n },\n select: { userId: true },\n },\n },\n },\n },\n },\n attachments: {\n select: {\n id: true,\n name: true,\n type: true,\n path: true,\n size: true,\n uploadStatus: true,\n thumbnail: { select: { path: true } },\n },\n },\n },\n });\n}\n\n/** Create an announcement. */\nexport function createAnnouncement(data: {\n remarks: string;\n teacherId: string;\n classId: string;\n}) {\n return prisma.announcement.create({\n data: {\n remarks: data.remarks,\n teacher: { connect: { id: data.teacherId } },\n class: { connect: { id: data.classId } },\n },\n select: announcementSelect,\n });\n}\n\n/** Update announcement attachments. */\nexport function updateAnnouncementAttachments(\n id: string,\n data: {\n connect?: { id: string }[];\n deleteMany?: { id: { in: string[] } };\n }\n) {\n return prisma.announcement.update({\n where: { id },\n data: {\n ...(data.connect?.length && {\n attachments: { connect: data.connect },\n }),\n ...(data.deleteMany && {\n attachments: { deleteMany: data.deleteMany },\n }),\n },\n select: announcementSelect,\n });\n}\n\n/** Update announcement remarks. */\nexport function updateAnnouncement(id: string, data: { remarks?: string }) {\n return prisma.announcement.update({\n where: { id },\n data,\n select: announcementSelect,\n });\n}\n\n/** Delete an announcement. */\nexport function deleteAnnouncement(id: string) {\n return prisma.announcement.delete({\n where: { id },\n });\n}\n"],"names":[],"mappings":"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","debug_id":"fff848bf-ce06-59fe-83ea-7a9d6e208421"}
1
+ {"version":3,"file":"announcement.js","sources":["models/announcement.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Announcement model – announcements, attachments, comments.\n */\nimport { prisma } from \"../lib/prisma.js\";\n\nexport const announcementSelect = {\n id: true,\n teacher: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n profilePictureThumbnail: true,\n },\n },\n },\n },\n remarks: true,\n createdAt: true,\n modifiedAt: true,\n attachments: {\n select: {\n id: true,\n name: true,\n type: true,\n size: true,\n path: true,\n uploadedAt: true,\n thumbnailId: true,\n },\n },\n};\n\n/** @returns Announcements for a class. */\nexport function findAnnouncementsByClassId(classId: string) {\n return prisma.announcement.findMany({\n where: { classId },\n select: {\n ...announcementSelect,\n _count: {\n select: { comments: true },\n },\n },\n orderBy: { createdAt: \"desc\" },\n });\n}\n\n/** @returns Announcement by ID and class. */\nexport function findAnnouncementByIdAndClass(id: string, classId: string) {\n return prisma.announcement.findFirst({\n where: { id, classId },\n select: announcementSelect,\n });\n}\n\n/** @returns Announcement by ID with class teachers and school admins. */\nexport function findAnnouncementWithClass(id: string) {\n return prisma.announcement.findUnique({\n where: { id },\n include: {\n class: {\n include: {\n teachers: true,\n school: {\n include: {\n users: {\n select: { id: true },\n },\n memberships: {\n where: {\n role: \"ADMIN\" as const,\n status: \"ACTIVE\" as const,\n },\n select: { userId: true },\n },\n },\n },\n },\n },\n attachments: {\n select: {\n id: true,\n name: true,\n type: true,\n path: true,\n size: true,\n uploadStatus: true,\n thumbnail: { select: { path: true } },\n },\n },\n },\n });\n}\n\n/** Create an announcement. */\nexport function createAnnouncement(data: {\n remarks: string;\n teacherId: string;\n classId: string;\n}) {\n return prisma.announcement.create({\n data: {\n remarks: data.remarks,\n teacher: { connect: { id: data.teacherId } },\n class: { connect: { id: data.classId } },\n },\n select: announcementSelect,\n });\n}\n\n/** Update announcement attachments. */\nexport function updateAnnouncementAttachments(\n id: string,\n data: {\n connect?: { id: string }[];\n deleteMany?: { id: { in: string[] } };\n }\n) {\n return prisma.announcement.update({\n where: { id },\n data: {\n ...(data.connect?.length && {\n attachments: { connect: data.connect },\n }),\n ...(data.deleteMany && {\n attachments: { deleteMany: data.deleteMany },\n }),\n },\n select: announcementSelect,\n });\n}\n\n/** Update announcement remarks. */\nexport function updateAnnouncement(id: string, data: { remarks?: string }) {\n return prisma.announcement.update({\n where: { id },\n data,\n select: announcementSelect,\n });\n}\n\n/** Delete an announcement. */\nexport function deleteAnnouncement(id: string) {\n return prisma.announcement.delete({\n where: { id },\n });\n}\n"],"names":[],"mappings":"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","debug_id":"13cd5c13-3abf-5ea9-9021-98ba4c1cc38d"}