@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,115 +1,129 @@
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]="2a91768b-a0eb-5556-9154-f76d73b01c49")}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]="f76c8e6f-19ba-5dd6-9a07-530a455a8b5f")}catch(e){}}();
3
3
  import { z } from "zod";
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";
6
- const createFolderSchema = z.object({
7
- name: z.string(),
8
- parentFolderId: z.string().optional(),
9
- color: z.string().optional(),
10
- });
4
+ import { createTRPCRouter, protectedProcedure, } from "../trpc.js";
5
+ import { browseFolder, browseSharedWithMe, confirmFolderUpload, createFolderRecord, deleteFolder, getFolder, getFolderParents, getFolderUploadUrls, getRootFolder, listUserScopes, moveFolder, updateFolderRecord, } from "../services/folder.js";
6
+ import { listSharedWithMe } from "../services/permissions.js";
11
7
  const directFileSchema = z.object({
12
8
  name: z.string(),
13
9
  type: z.string(),
14
10
  size: z.number(),
15
11
  });
16
- const uploadFilesToFolderSchema = z.object({
17
- folderId: z.string(),
18
- files: z.array(directFileSchema),
19
- });
20
- const getRootFolderSchema = z.object({
21
- classId: z.string(),
22
- });
12
+ /**
13
+ * Cloud scope discriminator. Folders live under one of:
14
+ * - CLASS: a class shared-files area
15
+ * - SCHOOL_STORAGE: institution-wide files
16
+ * - PERSONAL: a single user's storage
17
+ *
18
+ * All folder operations identify the location they apply to with either a
19
+ * `folderId` (for an existing folder) or a `scope` (when no folder exists yet,
20
+ * e.g. browsing a scope root). There is no `classId` shorthand — use
21
+ * `{ scope: { kind: "CLASS", classId } }` instead.
22
+ */
23
+ const cloudScopeSchema = z.discriminatedUnion("kind", [
24
+ z.object({ kind: z.literal("CLASS"), classId: z.string() }),
25
+ z.object({ kind: z.literal("SCHOOL_STORAGE"), schoolId: z.string() }),
26
+ z.object({ kind: z.literal("PERSONAL"), userId: z.string() }),
27
+ ]);
28
+ /**
29
+ * Extended scope schema for `browse` only. SHARED_WITH_ME is a *virtual*
30
+ * scope — it has no root row in the `Folder` table and you can't create
31
+ * folders inside it directly. It just collects every top-most explicit grant
32
+ * the user holds for "Shared with me"-style display.
33
+ */
34
+ const browseScopeSchema = z.discriminatedUnion("kind", [
35
+ z.object({ kind: z.literal("CLASS"), classId: z.string() }),
36
+ z.object({ kind: z.literal("SCHOOL_STORAGE"), schoolId: z.string() }),
37
+ z.object({ kind: z.literal("PERSONAL"), userId: z.string() }),
38
+ z.object({ kind: z.literal("SHARED_WITH_ME") }),
39
+ ]);
23
40
  export const folderRouter = createTRPCRouter({
24
- create: protectedTeacherProcedure
25
- .input(createFolderSchema)
26
- .mutation(async ({ ctx, input }) => {
27
- if (!ctx.user) {
28
- throw new Error("You must be logged in to create a folder");
41
+ /** Browse a folder (or scope root) with breadcrumbs and access flag. */
42
+ browse: protectedProcedure
43
+ .input(z.union([
44
+ z.object({ folderId: z.string() }),
45
+ z.object({ scope: browseScopeSchema }),
46
+ ]))
47
+ .query(({ ctx, input }) => {
48
+ if ("scope" in input && input.scope.kind === "SHARED_WITH_ME") {
49
+ return browseSharedWithMe(ctx.user.id);
29
50
  }
30
- return createFolderRecord(ctx.user.id, {
31
- classId: input.classId,
32
- name: input.name,
33
- parentFolderId: input.parentFolderId,
34
- color: input.color,
35
- });
51
+ return browseFolder(ctx.user.id, "scope" in input
52
+ ? { scope: input.scope }
53
+ : input);
36
54
  }),
37
- get: protectedClassMemberProcedure
38
- .input(z.object({ folderId: z.string(), classId: z.string() }))
39
- .query(({ input }) => getFolder(input.folderId)),
40
- getChildFolders: protectedClassMemberProcedure
41
- .input(z.object({ classId: z.string() }))
42
- .query(({ input }) => getChildFolders(input.classId)),
43
- getFolderChildren: protectedClassMemberProcedure
44
- .input(z.object({ folderId: z.string(), classId: z.string() }))
45
- .query(({ input }) => getFolderChildren(input.folderId, input.classId)),
46
- getRootFolder: protectedClassMemberProcedure
47
- .input(getRootFolderSchema)
48
- .query(({ input }) => getRootFolder(input.classId)),
49
- uploadFiles: protectedTeacherProcedure
50
- .input(uploadFilesToFolderSchema)
51
- .mutation(async ({ ctx, input }) => {
52
- if (!ctx.user) {
53
- throw new Error("You must be logged in to upload files");
54
- }
55
- return uploadFilesToFolder(ctx.user.id, input.classId, input.folderId, input.files);
56
- }),
57
- delete: protectedTeacherProcedure
58
- .input(z.object({ classId: z.string(), folderId: z.string() }))
59
- .mutation(async ({ ctx, input }) => {
60
- if (!ctx.user) {
61
- throw new Error("You must be logged in to delete folders");
62
- }
63
- return deleteFolderRecord(ctx.user.id, input.classId, input.folderId);
64
- }),
65
- move: protectedTeacherProcedure
55
+ /** Top-most folders/files explicitly shared with the caller (Drive-style). */
56
+ listSharedWithMe: protectedProcedure.query(({ ctx }) => listSharedWithMe(ctx.user.id)),
57
+ /** What scopes can this user pick from in the cloud-storage UI? */
58
+ listScopes: protectedProcedure.query(({ ctx }) => listUserScopes(ctx.user.id)),
59
+ /** Root folder for any scope (no folderId). */
60
+ getRootFolder: protectedProcedure
61
+ .input(z.object({ scope: cloudScopeSchema }))
62
+ .query(({ ctx, input }) => getRootFolder(ctx.user.id, input.scope)),
63
+ get: protectedProcedure
64
+ .input(z.object({ folderId: z.string() }))
65
+ .query(({ ctx, input }) => getFolder(ctx.user.id, input.folderId)),
66
+ getParents: protectedProcedure
67
+ .input(z.object({ folderId: z.string() }))
68
+ .query(({ ctx, input }) => getFolderParents(ctx.user.id, input.folderId)),
69
+ create: protectedProcedure
66
70
  .input(z.object({
67
- folderId: z.string(),
68
- targetParentFolderId: z.string(),
69
- classId: z.string(),
71
+ name: z.string().min(1),
72
+ parentFolderId: z.string().nullable().optional(),
73
+ color: z.string().optional(),
74
+ scope: cloudScopeSchema.optional(),
70
75
  }))
71
- .mutation(async ({ ctx, input }) => {
72
- if (!ctx.user) {
73
- throw new Error("You must be logged in to move folders");
74
- }
75
- return moveFolder(ctx.user.id, input.folderId, input.targetParentFolderId, input.classId);
76
- }),
77
- update: protectedTeacherProcedure
76
+ .mutation(({ ctx, input }) => createFolderRecord(ctx.user.id, {
77
+ name: input.name,
78
+ parentFolderId: input.parentFolderId ?? undefined,
79
+ color: input.color,
80
+ scope: input.scope,
81
+ })),
82
+ update: protectedProcedure
78
83
  .input(z.object({
79
84
  folderId: z.string(),
80
- name: z.string(),
85
+ name: z.string().optional(),
81
86
  color: z.string().optional(),
82
- classId: z.string(),
83
87
  }))
84
- .mutation(({ input }) => updateFolderRecord(input.folderId, input.name, input.color, input.classId)),
85
- getParents: protectedProcedure
88
+ .mutation(({ ctx, input }) => updateFolderRecord(ctx.user.id, {
89
+ folderId: input.folderId,
90
+ name: input.name,
91
+ color: input.color,
92
+ })),
93
+ delete: protectedProcedure
86
94
  .input(z.object({ folderId: z.string() }))
87
- .query(({ input }) => getFolderParents(input.folderId)),
88
- getFolderUploadUrls: protectedTeacherProcedure
95
+ .mutation(({ ctx, input }) => deleteFolder(ctx.user.id, input.folderId)),
96
+ move: protectedProcedure
97
+ .input(z.object({
98
+ folderId: z.string(),
99
+ targetParentFolderId: z.string(),
100
+ }))
101
+ .mutation(({ ctx, input }) => moveFolder(ctx.user.id, {
102
+ folderId: input.folderId,
103
+ targetParentFolderId: input.targetParentFolderId,
104
+ })),
105
+ /** Get signed upload URLs for direct-to-GCS upload. */
106
+ getFolderUploadUrls: protectedProcedure
89
107
  .input(z.object({
90
- classId: z.string(),
91
108
  folderId: z.string(),
92
109
  files: z.array(directFileSchema),
93
110
  }))
94
- .mutation(async ({ ctx, input }) => {
95
- if (!ctx.user) {
96
- throw new Error("You must be logged in to upload files");
97
- }
98
- return getFolderUploadUrls(ctx.user.id, input.classId, input.folderId, input.files);
99
- }),
100
- confirmFolderUpload: protectedTeacherProcedure
111
+ .mutation(({ ctx, input }) => getFolderUploadUrls(ctx.user.id, {
112
+ folderId: input.folderId,
113
+ files: input.files,
114
+ })),
115
+ /** Acknowledge a direct upload completed (or failed). */
116
+ confirmFolderUpload: protectedProcedure
101
117
  .input(z.object({
102
118
  fileId: z.string(),
103
119
  uploadSuccess: z.boolean(),
120
+ errorMessage: z.string().optional(),
104
121
  }))
105
- .mutation(async ({ ctx, input }) => {
106
- if (!ctx.user) {
107
- throw new Error("You must be logged in to confirm uploads");
108
- }
109
- const { confirmDirectUpload } = await import("../lib/fileUpload.js");
110
- await confirmDirectUpload(input.fileId, input.uploadSuccess);
111
- return { success: true };
112
- }),
122
+ .mutation(({ ctx, input }) => confirmFolderUpload(ctx.user.id, {
123
+ fileId: input.fileId,
124
+ uploadSuccess: input.uploadSuccess,
125
+ errorMessage: input.errorMessage,
126
+ })),
113
127
  });
114
128
  //# sourceMappingURL=folder.js.map
115
- //# debugId=2a91768b-a0eb-5556-9154-f76d73b01c49
129
+ //# debugId=f76c8e6f-19ba-5dd6-9a07-530a455a8b5f
@@ -1 +1 @@
1
- {"version":3,"file":"folder.js","sources":["routers/folder.ts"],"sourceRoot":"/","sourcesContent":["import { z } from \"zod\";\nimport {\n createTRPCRouter,\n protectedProcedure,\n protectedClassMemberProcedure,\n protectedTeacherProcedure,\n} from \"../trpc.js\";\nimport {\n createFolderRecord,\n getFolder,\n getChildFolders,\n getFolderChildren,\n getRootFolder,\n uploadFilesToFolder,\n deleteFolderRecord,\n moveFolder,\n updateFolderRecord,\n getFolderParents,\n getFolderUploadUrls,\n} from \"../services/folder.js\";\n\nconst createFolderSchema = z.object({\n name: z.string(),\n parentFolderId: z.string().optional(),\n color: z.string().optional(),\n});\n\nconst directFileSchema = z.object({\n name: z.string(),\n type: z.string(),\n size: z.number(),\n});\n\nconst uploadFilesToFolderSchema = z.object({\n folderId: z.string(),\n files: z.array(directFileSchema),\n});\n\nconst getRootFolderSchema = z.object({\n classId: z.string(),\n});\n\nexport const folderRouter = createTRPCRouter({\n create: protectedTeacherProcedure\n .input(createFolderSchema)\n .mutation(async ({ ctx, input }) => {\n if (!ctx.user) {\n throw new Error(\"You must be logged in to create a folder\");\n }\n return createFolderRecord(ctx.user.id, {\n classId: input.classId,\n name: input.name,\n parentFolderId: input.parentFolderId,\n color: input.color,\n });\n }),\n\n get: protectedClassMemberProcedure\n .input(z.object({ folderId: z.string(), classId: z.string() }))\n .query(({ input }) => getFolder(input.folderId)),\n\n getChildFolders: protectedClassMemberProcedure\n .input(z.object({ classId: z.string() }))\n .query(({ input }) => getChildFolders(input.classId)),\n\n getFolderChildren: protectedClassMemberProcedure\n .input(z.object({ folderId: z.string(), classId: z.string() }))\n .query(({ input }) =>\n getFolderChildren(input.folderId, input.classId)\n ),\n\n getRootFolder: protectedClassMemberProcedure\n .input(getRootFolderSchema)\n .query(({ input }) => getRootFolder(input.classId)),\n\n uploadFiles: protectedTeacherProcedure\n .input(uploadFilesToFolderSchema)\n .mutation(async ({ ctx, input }) => {\n if (!ctx.user) {\n throw new Error(\"You must be logged in to upload files\");\n }\n return uploadFilesToFolder(\n ctx.user.id,\n input.classId,\n input.folderId,\n input.files\n );\n }),\n\n delete: protectedTeacherProcedure\n .input(z.object({ classId: z.string(), folderId: z.string() }))\n .mutation(async ({ ctx, input }) => {\n if (!ctx.user) {\n throw new Error(\"You must be logged in to delete folders\");\n }\n return deleteFolderRecord(ctx.user.id, input.classId, input.folderId);\n }),\n\n move: protectedTeacherProcedure\n .input(\n z.object({\n folderId: z.string(),\n targetParentFolderId: z.string(),\n classId: z.string(),\n })\n )\n .mutation(async ({ ctx, input }) => {\n if (!ctx.user) {\n throw new Error(\"You must be logged in to move folders\");\n }\n return moveFolder(\n ctx.user.id,\n input.folderId,\n input.targetParentFolderId,\n input.classId\n );\n }),\n\n update: protectedTeacherProcedure\n .input(\n z.object({\n folderId: z.string(),\n name: z.string(),\n color: z.string().optional(),\n classId: z.string(),\n })\n )\n .mutation(({ input }) =>\n updateFolderRecord(\n input.folderId,\n input.name,\n input.color,\n input.classId\n )\n ),\n\n getParents: protectedProcedure\n .input(z.object({ folderId: z.string() }))\n .query(({ input }) => getFolderParents(input.folderId)),\n\n getFolderUploadUrls: protectedTeacherProcedure\n .input(\n z.object({\n classId: z.string(),\n folderId: z.string(),\n files: z.array(directFileSchema),\n })\n )\n .mutation(async ({ ctx, input }) => {\n if (!ctx.user) {\n throw new Error(\"You must be logged in to upload files\");\n }\n return getFolderUploadUrls(\n ctx.user.id,\n input.classId,\n input.folderId,\n input.files\n );\n }),\n\n confirmFolderUpload: protectedTeacherProcedure\n .input(\n z.object({\n fileId: z.string(),\n uploadSuccess: z.boolean(),\n })\n )\n .mutation(async ({ ctx, input }) => {\n if (!ctx.user) {\n throw new Error(\"You must be logged in to confirm uploads\");\n }\n const { confirmDirectUpload } = await import(\"../lib/fileUpload.js\");\n await confirmDirectUpload(input.fileId, input.uploadSuccess);\n return { success: true };\n }),\n});\n"],"names":[],"mappings":"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","debug_id":"2a91768b-a0eb-5556-9154-f76d73b01c49"}
1
+ {"version":3,"file":"folder.js","sources":["routers/folder.ts"],"sourceRoot":"/","sourcesContent":["import { z } from \"zod\";\nimport {\n createTRPCRouter,\n protectedProcedure,\n} from \"../trpc.js\";\nimport {\n browseFolder,\n browseSharedWithMe,\n confirmFolderUpload,\n createFolderRecord,\n deleteFolder,\n getFolder,\n getFolderParents,\n getFolderUploadUrls,\n getRootFolder,\n listUserScopes,\n moveFolder,\n updateFolderRecord,\n} from \"../services/folder.js\";\nimport { listSharedWithMe } from \"../services/permissions.js\";\n\nconst directFileSchema = z.object({\n name: z.string(),\n type: z.string(),\n size: z.number(),\n});\n\n/**\n * Cloud scope discriminator. Folders live under one of:\n * - CLASS: a class shared-files area\n * - SCHOOL_STORAGE: institution-wide files\n * - PERSONAL: a single user's storage\n *\n * All folder operations identify the location they apply to with either a\n * `folderId` (for an existing folder) or a `scope` (when no folder exists yet,\n * e.g. browsing a scope root). There is no `classId` shorthand — use\n * `{ scope: { kind: \"CLASS\", classId } }` instead.\n */\nconst cloudScopeSchema = z.discriminatedUnion(\"kind\", [\n z.object({ kind: z.literal(\"CLASS\"), classId: z.string() }),\n z.object({ kind: z.literal(\"SCHOOL_STORAGE\"), schoolId: z.string() }),\n z.object({ kind: z.literal(\"PERSONAL\"), userId: z.string() }),\n]);\n\n/**\n * Extended scope schema for `browse` only. SHARED_WITH_ME is a *virtual*\n * scope — it has no root row in the `Folder` table and you can't create\n * folders inside it directly. It just collects every top-most explicit grant\n * the user holds for \"Shared with me\"-style display.\n */\nconst browseScopeSchema = z.discriminatedUnion(\"kind\", [\n z.object({ kind: z.literal(\"CLASS\"), classId: z.string() }),\n z.object({ kind: z.literal(\"SCHOOL_STORAGE\"), schoolId: z.string() }),\n z.object({ kind: z.literal(\"PERSONAL\"), userId: z.string() }),\n z.object({ kind: z.literal(\"SHARED_WITH_ME\") }),\n]);\n\nexport const folderRouter = createTRPCRouter({\n /** Browse a folder (or scope root) with breadcrumbs and access flag. */\n browse: protectedProcedure\n .input(\n z.union([\n z.object({ folderId: z.string() }),\n z.object({ scope: browseScopeSchema }),\n ])\n )\n .query(({ ctx, input }) => {\n if (\"scope\" in input && input.scope.kind === \"SHARED_WITH_ME\") {\n return browseSharedWithMe(ctx.user!.id);\n }\n return browseFolder(\n ctx.user!.id,\n \"scope\" in input\n ? { scope: input.scope as Exclude<typeof input.scope, { kind: \"SHARED_WITH_ME\" }> }\n : input\n );\n }),\n\n /** Top-most folders/files explicitly shared with the caller (Drive-style). */\n listSharedWithMe: protectedProcedure.query(({ ctx }) =>\n listSharedWithMe(ctx.user!.id)\n ),\n\n /** What scopes can this user pick from in the cloud-storage UI? */\n listScopes: protectedProcedure.query(({ ctx }) =>\n listUserScopes(ctx.user!.id)\n ),\n\n /** Root folder for any scope (no folderId). */\n getRootFolder: protectedProcedure\n .input(z.object({ scope: cloudScopeSchema }))\n .query(({ ctx, input }) => getRootFolder(ctx.user!.id, input.scope)),\n\n get: protectedProcedure\n .input(z.object({ folderId: z.string() }))\n .query(({ ctx, input }) => getFolder(ctx.user!.id, input.folderId)),\n\n getParents: protectedProcedure\n .input(z.object({ folderId: z.string() }))\n .query(({ ctx, input }) => getFolderParents(ctx.user!.id, input.folderId)),\n\n create: protectedProcedure\n .input(\n z.object({\n name: z.string().min(1),\n parentFolderId: z.string().nullable().optional(),\n color: z.string().optional(),\n scope: cloudScopeSchema.optional(),\n })\n )\n .mutation(({ ctx, input }) =>\n createFolderRecord(ctx.user!.id, {\n name: input.name,\n parentFolderId: input.parentFolderId ?? undefined,\n color: input.color,\n scope: input.scope,\n })\n ),\n\n update: protectedProcedure\n .input(\n z.object({\n folderId: z.string(),\n name: z.string().optional(),\n color: z.string().optional(),\n })\n )\n .mutation(({ ctx, input }) =>\n updateFolderRecord(ctx.user!.id, {\n folderId: input.folderId,\n name: input.name,\n color: input.color,\n })\n ),\n\n delete: protectedProcedure\n .input(z.object({ folderId: z.string() }))\n .mutation(({ ctx, input }) => deleteFolder(ctx.user!.id, input.folderId)),\n\n move: protectedProcedure\n .input(\n z.object({\n folderId: z.string(),\n targetParentFolderId: z.string(),\n })\n )\n .mutation(({ ctx, input }) =>\n moveFolder(ctx.user!.id, {\n folderId: input.folderId,\n targetParentFolderId: input.targetParentFolderId,\n })\n ),\n\n /** Get signed upload URLs for direct-to-GCS upload. */\n getFolderUploadUrls: protectedProcedure\n .input(\n z.object({\n folderId: z.string(),\n files: z.array(directFileSchema),\n })\n )\n .mutation(({ ctx, input }) =>\n getFolderUploadUrls(ctx.user!.id, {\n folderId: input.folderId,\n files: input.files,\n })\n ),\n\n /** Acknowledge a direct upload completed (or failed). */\n confirmFolderUpload: protectedProcedure\n .input(\n z.object({\n fileId: z.string(),\n uploadSuccess: z.boolean(),\n errorMessage: z.string().optional(),\n })\n )\n .mutation(({ ctx, input }) =>\n confirmFolderUpload(ctx.user!.id, {\n fileId: input.fileId,\n uploadSuccess: input.uploadSuccess,\n errorMessage: input.errorMessage,\n })\n ),\n});\n"],"names":[],"mappings":"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","debug_id":"f76c8e6f-19ba-5dd6-9a07-530a455a8b5f"}
@@ -41,8 +41,8 @@ export declare const labChatRouter: import("@trpc/server").TRPCBuiltRouter<{
41
41
  };
42
42
  } & {
43
43
  id: string;
44
- role: import(".prisma/client").$Enums.ConversationRole;
45
44
  userId: string;
45
+ role: import(".prisma/client").$Enums.ConversationRole;
46
46
  conversationId: string;
47
47
  joinedAt: Date;
48
48
  hiddenAt: Date | null;
@@ -69,8 +69,8 @@ export declare const labChatRouter: import("@trpc/server").TRPCBuiltRouter<{
69
69
  id: string;
70
70
  createdAt: Date;
71
71
  updatedAt: Date;
72
- conversationId: string;
73
72
  classId: string;
73
+ conversationId: string;
74
74
  title: string;
75
75
  createdById: string;
76
76
  };
@@ -100,8 +100,8 @@ export declare const labChatRouter: import("@trpc/server").TRPCBuiltRouter<{
100
100
  };
101
101
  } & {
102
102
  id: string;
103
- role: import(".prisma/client").$Enums.ConversationRole;
104
103
  userId: string;
104
+ role: import(".prisma/client").$Enums.ConversationRole;
105
105
  conversationId: string;
106
106
  joinedAt: Date;
107
107
  hiddenAt: Date | null;
@@ -128,8 +128,8 @@ export declare const labChatRouter: import("@trpc/server").TRPCBuiltRouter<{
128
128
  id: string;
129
129
  createdAt: Date;
130
130
  updatedAt: Date;
131
- conversationId: string;
132
131
  classId: string;
132
+ conversationId: string;
133
133
  title: string;
134
134
  createdById: string;
135
135
  };
@@ -198,9 +198,18 @@ export declare const labChatRouter: import("@trpc/server").TRPCBuiltRouter<{
198
198
  } | null;
199
199
  };
200
200
  attachments: {
201
+ path: string;
201
202
  type: string;
202
203
  name: string;
203
204
  id: string;
205
+ size: number | null;
206
+ uploadedAt: Date | null;
207
+ uploadStatus: import(".prisma/client").$Enums.UploadStatus;
208
+ thumbnailId: string | null;
209
+ thumbnail: {
210
+ path: string;
211
+ id: string;
212
+ } | null;
204
213
  }[];
205
214
  mentionedUserIds: string[];
206
215
  };
@@ -1 +1 @@
1
- {"version":3,"file":"labChat.d.ts","sourceRoot":"/","sources":["routers/labChat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAWxB,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDxB,CAAC"}
1
+ {"version":3,"file":"labChat.d.ts","sourceRoot":"/","sources":["routers/labChat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAWxB,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDxB,CAAC"}
@@ -39,9 +39,18 @@ export declare const messageRouter: import("@trpc/server").TRPCBuiltRouter<{
39
39
  };
40
40
  status: import(".prisma/client").$Enums.JobStatus | null;
41
41
  attachments: {
42
- id: string;
43
- name: string;
42
+ path: string;
44
43
  type: string;
44
+ name: string;
45
+ id: string;
46
+ size: number | null;
47
+ uploadedAt: Date | null;
48
+ uploadStatus: import(".prisma/client").$Enums.UploadStatus;
49
+ thumbnailId: string | null;
50
+ thumbnail: {
51
+ path: string;
52
+ id: string;
53
+ } | null;
45
54
  }[];
46
55
  meta: Record<string, unknown>;
47
56
  mentions: {
@@ -82,9 +91,18 @@ export declare const messageRouter: import("@trpc/server").TRPCBuiltRouter<{
82
91
  } | null;
83
92
  };
84
93
  attachments: {
94
+ path: string;
85
95
  type: string;
86
96
  name: string;
87
97
  id: string;
98
+ size: number | null;
99
+ uploadedAt: Date | null;
100
+ uploadStatus: import(".prisma/client").$Enums.UploadStatus;
101
+ thumbnailId: string | null;
102
+ thumbnail: {
103
+ path: string;
104
+ id: string;
105
+ } | null;
88
106
  }[];
89
107
  mentionedUserIds: string[];
90
108
  };
@@ -1 +1 @@
1
- {"version":3,"file":"message.d.ts","sourceRoot":"/","sources":["routers/message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAexB,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqHxB,CAAC"}
1
+ {"version":3,"file":"message.d.ts","sourceRoot":"/","sources":["routers/message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAexB,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqHxB,CAAC"}
@@ -18,8 +18,8 @@ export declare const newtonChatRouter: import("@trpc/server").TRPCBuiltRouter<{
18
18
  }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
19
19
  getTutorConversation: import("@trpc/server").TRPCQueryProcedure<{
20
20
  input: {
21
- assignmentId: string;
22
21
  classId: string;
22
+ assignmentId: string;
23
23
  };
24
24
  output: {
25
25
  conversationId: string;
@@ -50,9 +50,18 @@ export declare const newtonChatRouter: import("@trpc/server").TRPCBuiltRouter<{
50
50
  } | null;
51
51
  };
52
52
  attachments: {
53
+ path: string;
53
54
  type: string;
54
55
  name: string;
55
56
  id: string;
57
+ size: number | null;
58
+ uploadedAt: Date | null;
59
+ uploadStatus: import(".prisma/client").$Enums.UploadStatus;
60
+ thumbnailId: string | null;
61
+ thumbnail: {
62
+ path: string;
63
+ id: string;
64
+ } | null;
56
65
  }[];
57
66
  mentionedUserIds: string[];
58
67
  };
@@ -1 +1 @@
1
- {"version":3,"file":"newtonChat.d.ts","sourceRoot":"/","sources":["routers/newtonChat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8B3B,CAAC"}
1
+ {"version":3,"file":"newtonChat.d.ts","sourceRoot":"/","sources":["routers/newtonChat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8B3B,CAAC"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Permissions router. Backs the "Share" dialog and the "Shared with me" view.
3
+ *
4
+ * Permission semantics live in `services/permissions.ts`; this router is just
5
+ * a thin Zod-validated tRPC surface over those helpers.
6
+ *
7
+ * v1 grants only on folders. Files inherit from their parent folder. Adding
8
+ * file-level grants later is a non-breaking, additive change.
9
+ */
10
+ import { z } from "zod";
11
+ import { type PermissionPrincipalInput } from "../services/permissions.js";
12
+ export declare const permissionsRouter: import("@trpc/server").TRPCBuiltRouter<{
13
+ ctx: import("../trpc.js").Context;
14
+ meta: object;
15
+ errorShape: {
16
+ data: {
17
+ zodError: z.typeToFlattenedError<any, string> | null;
18
+ prismaError: import("../utils/prismaErrorHandler.js").PrismaErrorInfo | null;
19
+ code: import("@trpc/server").TRPC_ERROR_CODE_KEY;
20
+ httpStatus: number;
21
+ path?: string;
22
+ stack?: string;
23
+ };
24
+ message: string;
25
+ code: import("@trpc/server").TRPC_ERROR_CODE_NUMBER;
26
+ };
27
+ transformer: false;
28
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
29
+ /** List all explicit grants on a folder. Caller must have WRITE. */
30
+ list: import("@trpc/server").TRPCQueryProcedure<{
31
+ input: {
32
+ folderId: string;
33
+ };
34
+ output: ({
35
+ school: {
36
+ name: string;
37
+ id: string;
38
+ } | null;
39
+ user: {
40
+ id: string;
41
+ username: string;
42
+ email: string;
43
+ } | null;
44
+ class: {
45
+ name: string;
46
+ id: string;
47
+ section: string;
48
+ } | null;
49
+ department: {
50
+ name: string;
51
+ id: string;
52
+ color: string | null;
53
+ } | null;
54
+ tag: {
55
+ name: string;
56
+ id: string;
57
+ color: string;
58
+ } | null;
59
+ } & {
60
+ level: import(".prisma/client").$Enums.PermissionLevel;
61
+ id: string;
62
+ createdAt: Date;
63
+ schoolId: string | null;
64
+ userId: string | null;
65
+ departmentId: string | null;
66
+ folderId: string;
67
+ principalType: import(".prisma/client").$Enums.PermissionPrincipalType;
68
+ tagId: string | null;
69
+ classId: string | null;
70
+ grantedById: string;
71
+ })[];
72
+ meta: object;
73
+ }>;
74
+ /** Create a new explicit grant on a folder. */
75
+ grant: import("@trpc/server").TRPCMutationProcedure<{
76
+ input: {
77
+ level: "READ" | "WRITE";
78
+ folderId: string;
79
+ principal: PermissionPrincipalInput;
80
+ };
81
+ output: {
82
+ level: import(".prisma/client").$Enums.PermissionLevel;
83
+ id: string;
84
+ createdAt: Date;
85
+ schoolId: string | null;
86
+ userId: string | null;
87
+ departmentId: string | null;
88
+ folderId: string;
89
+ principalType: import(".prisma/client").$Enums.PermissionPrincipalType;
90
+ tagId: string | null;
91
+ classId: string | null;
92
+ grantedById: string;
93
+ };
94
+ meta: object;
95
+ }>;
96
+ /** Remove an explicit grant. Allowed for the granter or anyone with WRITE on the folder. */
97
+ revoke: import("@trpc/server").TRPCMutationProcedure<{
98
+ input: {
99
+ permissionId: string;
100
+ };
101
+ output: {
102
+ success: boolean;
103
+ };
104
+ meta: object;
105
+ }>;
106
+ /** Drive-style "Shared with me" — top-most folders explicitly granted to the caller. */
107
+ listSharedWithMe: import("@trpc/server").TRPCQueryProcedure<{
108
+ input: void;
109
+ output: {
110
+ folders: {
111
+ id: string;
112
+ name: string;
113
+ color: string | null;
114
+ }[];
115
+ files: never[];
116
+ };
117
+ meta: object;
118
+ }>;
119
+ }>>;
120
+ //# sourceMappingURL=permissions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.d.ts","sourceRoot":"/","sources":["routers/permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAKL,KAAK,wBAAwB,EAC9B,MAAM,4BAA4B,CAAC;AAiBpC,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;IAC5B,oEAAoE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAOpE,+CAA+C;;;;;;;;;;;;;;;;;;;;;;IAiB/C,4FAA4F;;;;;;;;;;IAO5F,wFAAwF;;;;;;;;;;;;;GAIxF,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Permissions router. Backs the "Share" dialog and the "Shared with me" view.
3
+ *
4
+ * Permission semantics live in `services/permissions.ts`; this router is just
5
+ * a thin Zod-validated tRPC surface over those helpers.
6
+ *
7
+ * v1 grants only on folders. Files inherit from their parent folder. Adding
8
+ * file-level grants later is a non-breaking, additive change.
9
+ */
10
+
11
+ !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]="dccc1159-4761-5abc-bf19-947124f66887")}catch(e){}}();
12
+ import { z } from "zod";
13
+ import { createTRPCRouter, protectedProcedure } from "../trpc.js";
14
+ import { grantPermission, listPermissions, listSharedWithMe, revokePermission, } from "../services/permissions.js";
15
+ const principalSchema = z.discriminatedUnion("kind", [
16
+ z.object({ kind: z.literal("USER"), userId: z.string() }),
17
+ z.object({ kind: z.literal("TAG"), tagId: z.string() }),
18
+ z.object({ kind: z.literal("CLASS"), classId: z.string() }),
19
+ z.object({ kind: z.literal("CLASS_TEACHERS"), classId: z.string() }),
20
+ z.object({ kind: z.literal("CLASS_STUDENTS"), classId: z.string() }),
21
+ z.object({ kind: z.literal("DEPARTMENT"), departmentId: z.string() }),
22
+ z.object({ kind: z.literal("SCHOOL"), schoolId: z.string() }),
23
+ ]);
24
+ const levelSchema = z.enum(["READ", "WRITE"]);
25
+ export const permissionsRouter = createTRPCRouter({
26
+ /** List all explicit grants on a folder. Caller must have WRITE. */
27
+ list: protectedProcedure
28
+ .input(z.object({ folderId: z.string() }))
29
+ .query(({ ctx, input }) => listPermissions(ctx.user.id, input.folderId)),
30
+ /** Create a new explicit grant on a folder. */
31
+ grant: protectedProcedure
32
+ .input(z.object({
33
+ folderId: z.string(),
34
+ principal: principalSchema,
35
+ level: levelSchema,
36
+ }))
37
+ .mutation(({ ctx, input }) => grantPermission(ctx.user.id, {
38
+ folderId: input.folderId,
39
+ principal: input.principal,
40
+ level: input.level,
41
+ })),
42
+ /** Remove an explicit grant. Allowed for the granter or anyone with WRITE on the folder. */
43
+ revoke: protectedProcedure
44
+ .input(z.object({ permissionId: z.string() }))
45
+ .mutation(({ ctx, input }) => revokePermission(ctx.user.id, input.permissionId)),
46
+ /** Drive-style "Shared with me" — top-most folders explicitly granted to the caller. */
47
+ listSharedWithMe: protectedProcedure.query(({ ctx }) => listSharedWithMe(ctx.user.id)),
48
+ });
49
+ //# sourceMappingURL=permissions.js.map
50
+ //# debugId=dccc1159-4761-5abc-bf19-947124f66887
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.js","sources":["routers/permissions.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Permissions router. Backs the \"Share\" dialog and the \"Shared with me\" view.\n *\n * Permission semantics live in `services/permissions.ts`; this router is just\n * a thin Zod-validated tRPC surface over those helpers.\n *\n * v1 grants only on folders. Files inherit from their parent folder. Adding\n * file-level grants later is a non-breaking, additive change.\n */\nimport { z } from \"zod\";\nimport { createTRPCRouter, protectedProcedure } from \"../trpc.js\";\nimport {\n grantPermission,\n listPermissions,\n listSharedWithMe,\n revokePermission,\n type PermissionPrincipalInput,\n} from \"../services/permissions.js\";\n\nconst principalSchema: z.ZodType<PermissionPrincipalInput> = z.discriminatedUnion(\n \"kind\",\n [\n z.object({ kind: z.literal(\"USER\"), userId: z.string() }),\n z.object({ kind: z.literal(\"TAG\"), tagId: z.string() }),\n z.object({ kind: z.literal(\"CLASS\"), classId: z.string() }),\n z.object({ kind: z.literal(\"CLASS_TEACHERS\"), classId: z.string() }),\n z.object({ kind: z.literal(\"CLASS_STUDENTS\"), classId: z.string() }),\n z.object({ kind: z.literal(\"DEPARTMENT\"), departmentId: z.string() }),\n z.object({ kind: z.literal(\"SCHOOL\"), schoolId: z.string() }),\n ]\n);\n\nconst levelSchema = z.enum([\"READ\", \"WRITE\"]);\n\nexport const permissionsRouter = createTRPCRouter({\n /** List all explicit grants on a folder. Caller must have WRITE. */\n list: protectedProcedure\n .input(z.object({ folderId: z.string() }))\n .query(({ ctx, input }) =>\n listPermissions(ctx.user!.id, input.folderId)\n ),\n\n /** Create a new explicit grant on a folder. */\n grant: protectedProcedure\n .input(\n z.object({\n folderId: z.string(),\n principal: principalSchema,\n level: levelSchema,\n })\n )\n .mutation(({ ctx, input }) =>\n grantPermission(ctx.user!.id, {\n folderId: input.folderId,\n principal: input.principal,\n level: input.level,\n })\n ),\n\n /** Remove an explicit grant. Allowed for the granter or anyone with WRITE on the folder. */\n revoke: protectedProcedure\n .input(z.object({ permissionId: z.string() }))\n .mutation(({ ctx, input }) =>\n revokePermission(ctx.user!.id, input.permissionId)\n ),\n\n /** Drive-style \"Shared with me\" — top-most folders explicitly granted to the caller. */\n listSharedWithMe: protectedProcedure.query(({ ctx }) =>\n listSharedWithMe(ctx.user!.id)\n ),\n});\n"],"names":[],"mappings":"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","debug_id":"dccc1159-4761-5abc-bf19-947124f66887"}