@studious-lms/server 1.8.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.
- package/dist/middleware/security.d.ts.map +1 -1
- package/dist/middleware/security.js +3 -3
- package/dist/middleware/security.js.map +1 -1
- package/dist/models/agenda.d.ts +2 -2
- package/dist/models/announcement.d.ts +2 -2
- package/dist/models/assignment.d.ts +33 -33
- package/dist/models/class.d.ts +2 -2
- package/dist/models/cloudStorage.d.ts +14 -1
- package/dist/models/cloudStorage.d.ts.map +1 -1
- package/dist/models/cloudStorage.js +123 -3
- package/dist/models/cloudStorage.js.map +1 -1
- package/dist/models/event.d.ts +3 -3
- package/dist/models/file.d.ts +27 -26
- package/dist/models/file.d.ts.map +1 -1
- package/dist/models/file.js +4 -39
- package/dist/models/file.js.map +1 -1
- package/dist/models/labChat.d.ts +6 -6
- package/dist/models/section.d.ts +1 -1
- package/dist/routers/_app.d.ts +354 -100
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +4 -2
- package/dist/routers/_app.js.map +1 -1
- package/dist/routers/agenda.d.ts +2 -2
- package/dist/routers/assignment.d.ts +31 -31
- package/dist/routers/class.d.ts +5 -5
- package/dist/routers/event.d.ts +2 -2
- package/dist/routers/file.d.ts +2 -2
- package/dist/routers/folder.d.ts +24 -0
- package/dist/routers/folder.d.ts.map +1 -1
- package/dist/routers/folder.js +27 -5
- package/dist/routers/folder.js.map +1 -1
- package/dist/routers/labChat.d.ts +2 -2
- package/dist/routers/newtonChat.d.ts +1 -1
- package/dist/routers/permissions.d.ts +120 -0
- package/dist/routers/permissions.d.ts.map +1 -0
- package/dist/routers/permissions.js +50 -0
- package/dist/routers/permissions.js.map +1 -0
- package/dist/routers/tag.d.ts +5 -5
- package/dist/services/agenda.d.ts +2 -2
- package/dist/services/assignment.d.ts +31 -31
- package/dist/services/class.d.ts +5 -5
- package/dist/services/class.js +3 -3
- package/dist/services/class.js.map +1 -1
- package/dist/services/event.d.ts +2 -2
- package/dist/services/file.d.ts +22 -5
- package/dist/services/file.d.ts.map +1 -1
- package/dist/services/file.js +81 -45
- package/dist/services/file.js.map +1 -1
- package/dist/services/folder.d.ts +97 -2
- package/dist/services/folder.d.ts.map +1 -1
- package/dist/services/folder.js +158 -87
- package/dist/services/folder.js.map +1 -1
- package/dist/services/labChat.d.ts +2 -2
- package/dist/services/permissions.d.ts +188 -0
- package/dist/services/permissions.d.ts.map +1 -0
- package/dist/services/permissions.js +661 -0
- package/dist/services/permissions.js.map +1 -0
- package/package.json +1 -1
- package/prisma/migrations/20260510170000_add_folder_permissions/migration.sql +93 -0
- package/prisma/schema.prisma +74 -0
- package/src/middleware/security.ts +1 -1
- package/src/models/cloudStorage.ts +134 -1
- package/src/models/file.ts +2 -37
- package/src/routers/_app.ts +2 -0
- package/src/routers/folder.ts +32 -2
- package/src/routers/permissions.ts +71 -0
- package/src/services/class.ts +1 -1
- package/src/services/file.ts +76 -47
- package/src/services/folder.ts +180 -91
- package/src/services/permissions.ts +778 -0
- package/tests/unit/services/permissions.test.ts +463 -0
package/dist/routers/folder.d.ts
CHANGED
|
@@ -30,6 +30,8 @@ export declare const folderRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
30
30
|
} | {
|
|
31
31
|
userId: string;
|
|
32
32
|
kind: "PERSONAL";
|
|
33
|
+
} | {
|
|
34
|
+
kind: "SHARED_WITH_ME";
|
|
33
35
|
};
|
|
34
36
|
};
|
|
35
37
|
output: {
|
|
@@ -75,6 +77,23 @@ export declare const folderRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
75
77
|
}[];
|
|
76
78
|
canWrite: boolean;
|
|
77
79
|
scope: import("../models/cloudStorage.js").CloudScope;
|
|
80
|
+
displayRoot: {
|
|
81
|
+
kind: "SHARED_WITH_ME";
|
|
82
|
+
name: string;
|
|
83
|
+
} | null;
|
|
84
|
+
};
|
|
85
|
+
meta: object;
|
|
86
|
+
}>;
|
|
87
|
+
/** Top-most folders/files explicitly shared with the caller (Drive-style). */
|
|
88
|
+
listSharedWithMe: import("@trpc/server").TRPCQueryProcedure<{
|
|
89
|
+
input: void;
|
|
90
|
+
output: {
|
|
91
|
+
folders: {
|
|
92
|
+
id: string;
|
|
93
|
+
name: string;
|
|
94
|
+
color: string | null;
|
|
95
|
+
}[];
|
|
96
|
+
files: never[];
|
|
78
97
|
};
|
|
79
98
|
meta: object;
|
|
80
99
|
}>;
|
|
@@ -100,6 +119,11 @@ export declare const folderRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
100
119
|
color: string | null;
|
|
101
120
|
section: string;
|
|
102
121
|
}[];
|
|
122
|
+
sharedWithMe: {
|
|
123
|
+
kind: "SHARED_WITH_ME";
|
|
124
|
+
folderCount: number;
|
|
125
|
+
fileCount: number;
|
|
126
|
+
};
|
|
103
127
|
};
|
|
104
128
|
meta: object;
|
|
105
129
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"folder.d.ts","sourceRoot":"/","sources":["routers/folder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"folder.d.ts","sourceRoot":"/","sources":["routers/folder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAyDxB,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;IACvB,wEAAwE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAoBxE,8EAA8E;;;;;;;;;;;;;IAK9E,mEAAmE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAKnE,+CAA+C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAiE/C,uDAAuD;;;;;;;;;;;;;IAevD,yDAAyD;;;;;;;;;;;;GAgBzD,CAAC"}
|
package/dist/routers/folder.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="f76c8e6f-19ba-5dd6-9a07-530a455a8b5f")}catch(e){}}();
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { createTRPCRouter, protectedProcedure, } from "../trpc.js";
|
|
5
|
-
import { browseFolder, confirmFolderUpload, createFolderRecord, deleteFolder, getFolder, getFolderParents, getFolderUploadUrls, getRootFolder, listUserScopes, moveFolder, updateFolderRecord, } from "../services/folder.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";
|
|
6
7
|
const directFileSchema = z.object({
|
|
7
8
|
name: z.string(),
|
|
8
9
|
type: z.string(),
|
|
@@ -24,14 +25,35 @@ const cloudScopeSchema = z.discriminatedUnion("kind", [
|
|
|
24
25
|
z.object({ kind: z.literal("SCHOOL_STORAGE"), schoolId: z.string() }),
|
|
25
26
|
z.object({ kind: z.literal("PERSONAL"), userId: z.string() }),
|
|
26
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
|
+
]);
|
|
27
40
|
export const folderRouter = createTRPCRouter({
|
|
28
41
|
/** Browse a folder (or scope root) with breadcrumbs and access flag. */
|
|
29
42
|
browse: protectedProcedure
|
|
30
43
|
.input(z.union([
|
|
31
44
|
z.object({ folderId: z.string() }),
|
|
32
|
-
z.object({ scope:
|
|
45
|
+
z.object({ scope: browseScopeSchema }),
|
|
33
46
|
]))
|
|
34
|
-
.query(({ ctx, input }) =>
|
|
47
|
+
.query(({ ctx, input }) => {
|
|
48
|
+
if ("scope" in input && input.scope.kind === "SHARED_WITH_ME") {
|
|
49
|
+
return browseSharedWithMe(ctx.user.id);
|
|
50
|
+
}
|
|
51
|
+
return browseFolder(ctx.user.id, "scope" in input
|
|
52
|
+
? { scope: input.scope }
|
|
53
|
+
: input);
|
|
54
|
+
}),
|
|
55
|
+
/** Top-most folders/files explicitly shared with the caller (Drive-style). */
|
|
56
|
+
listSharedWithMe: protectedProcedure.query(({ ctx }) => listSharedWithMe(ctx.user.id)),
|
|
35
57
|
/** What scopes can this user pick from in the cloud-storage UI? */
|
|
36
58
|
listScopes: protectedProcedure.query(({ ctx }) => listUserScopes(ctx.user.id)),
|
|
37
59
|
/** Root folder for any scope (no folderId). */
|
|
@@ -104,4 +126,4 @@ export const folderRouter = createTRPCRouter({
|
|
|
104
126
|
})),
|
|
105
127
|
});
|
|
106
128
|
//# sourceMappingURL=folder.js.map
|
|
107
|
-
//# debugId=
|
|
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} from \"../trpc.js\";\nimport {\n browseFolder,\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\";\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\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: cloudScopeSchema }),\n ])\n )\n .query(({ ctx, input }) => browseFolder(ctx.user!.id, input)),\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":"9f777a4d-302d-516f-8d82-00a1ba3392ab"}
|
|
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"}
|
|
@@ -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
|
};
|
|
@@ -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
|
};
|
|
@@ -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;
|
|
@@ -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"}
|
package/dist/routers/tag.d.ts
CHANGED
|
@@ -79,9 +79,9 @@ export declare const tagRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
79
79
|
}>;
|
|
80
80
|
attach: import("@trpc/server").TRPCMutationProcedure<{
|
|
81
81
|
input: {
|
|
82
|
-
target: "CLASS" | "USER" | "RUBRIC" | "BOUNDARY";
|
|
83
|
-
targetId: string;
|
|
84
82
|
tagId: string;
|
|
83
|
+
target: "USER" | "CLASS" | "RUBRIC" | "BOUNDARY";
|
|
84
|
+
targetId: string;
|
|
85
85
|
};
|
|
86
86
|
output: {
|
|
87
87
|
id: string;
|
|
@@ -90,9 +90,9 @@ export declare const tagRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
90
90
|
}>;
|
|
91
91
|
detach: import("@trpc/server").TRPCMutationProcedure<{
|
|
92
92
|
input: {
|
|
93
|
-
target: "CLASS" | "USER" | "RUBRIC" | "BOUNDARY";
|
|
94
|
-
targetId: string;
|
|
95
93
|
tagId: string;
|
|
94
|
+
target: "USER" | "CLASS" | "RUBRIC" | "BOUNDARY";
|
|
95
|
+
targetId: string;
|
|
96
96
|
};
|
|
97
97
|
output: {
|
|
98
98
|
id: string;
|
|
@@ -101,7 +101,7 @@ export declare const tagRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
101
101
|
}>;
|
|
102
102
|
getAttached: import("@trpc/server").TRPCQueryProcedure<{
|
|
103
103
|
input: {
|
|
104
|
-
target: "
|
|
104
|
+
target: "USER" | "CLASS" | "RUBRIC" | "BOUNDARY";
|
|
105
105
|
targetId: string;
|
|
106
106
|
};
|
|
107
107
|
output: {
|
|
@@ -16,8 +16,8 @@ export declare function getAgenda(userId: string, weekStart: string): Promise<{
|
|
|
16
16
|
type: import(".prisma/client").$Enums.AssignmentType;
|
|
17
17
|
id: string;
|
|
18
18
|
createdAt: Date | null;
|
|
19
|
-
modifiedAt: Date | null;
|
|
20
19
|
classId: string;
|
|
20
|
+
modifiedAt: Date | null;
|
|
21
21
|
title: string;
|
|
22
22
|
instructions: string;
|
|
23
23
|
dueDate: Date;
|
|
@@ -64,8 +64,8 @@ export declare function getAgenda(userId: string, weekStart: string): Promise<{
|
|
|
64
64
|
type: import(".prisma/client").$Enums.AssignmentType;
|
|
65
65
|
id: string;
|
|
66
66
|
createdAt: Date | null;
|
|
67
|
-
modifiedAt: Date | null;
|
|
68
67
|
classId: string;
|
|
68
|
+
modifiedAt: Date | null;
|
|
69
69
|
title: string;
|
|
70
70
|
instructions: string;
|
|
71
71
|
dueDate: Date;
|