@studious-lms/server 1.4.6 → 1.4.7
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/models/access.d.ts +112 -0
- package/dist/models/access.d.ts.map +1 -0
- package/dist/models/access.js +49 -0
- package/dist/models/access.js.map +1 -0
- package/dist/models/announcement.d.ts +17 -2
- package/dist/models/announcement.d.ts.map +1 -1
- package/dist/models/announcement.js +21 -4
- package/dist/models/announcement.js.map +1 -1
- package/dist/models/assignment.d.ts +37 -37
- package/dist/models/assignment.d.ts.map +1 -1
- package/dist/models/assignment.js +15 -15
- package/dist/models/assignment.js.map +1 -1
- package/dist/models/attendance.d.ts +1 -1
- package/dist/models/attendance.d.ts.map +1 -1
- package/dist/models/attendance.js +6 -5
- package/dist/models/attendance.js.map +1 -1
- package/dist/models/auth.d.ts +5 -5
- package/dist/models/auth.d.ts.map +1 -1
- package/dist/models/auth.js +7 -11
- package/dist/models/auth.js.map +1 -1
- package/dist/models/class.d.ts +26 -26
- package/dist/models/class.d.ts.map +1 -1
- package/dist/models/class.js +7 -11
- package/dist/models/class.js.map +1 -1
- package/dist/models/comment.d.ts +134 -70
- package/dist/models/comment.d.ts.map +1 -1
- package/dist/models/comment.js +30 -42
- package/dist/models/comment.js.map +1 -1
- package/dist/models/conversation.d.ts +7 -7
- package/dist/models/event.d.ts +52 -3
- package/dist/models/event.d.ts.map +1 -1
- package/dist/models/event.js +56 -6
- package/dist/models/event.js.map +1 -1
- package/dist/models/file.d.ts +178 -103
- package/dist/models/file.d.ts.map +1 -1
- package/dist/models/file.js +54 -14
- package/dist/models/file.js.map +1 -1
- package/dist/models/folder.d.ts +22 -22
- package/dist/models/folder.d.ts.map +1 -1
- package/dist/models/folder.js +5 -4
- package/dist/models/folder.js.map +1 -1
- package/dist/models/labChat.d.ts +20 -20
- package/dist/models/labChat.d.ts.map +1 -1
- package/dist/models/labChat.js +8 -10
- package/dist/models/labChat.js.map +1 -1
- package/dist/models/marketing.d.ts +1 -1
- package/dist/models/message.d.ts +6 -6
- package/dist/models/newtonChat.d.ts +5 -5
- package/dist/models/school.d.ts +361 -0
- package/dist/models/school.d.ts.map +1 -0
- package/dist/models/school.js +314 -0
- package/dist/models/school.js.map +1 -0
- package/dist/models/section.d.ts +1 -1
- package/dist/models/section.d.ts.map +1 -1
- package/dist/models/section.js +5 -4
- package/dist/models/section.js.map +1 -1
- package/dist/models/user.d.ts +4 -4
- package/dist/models/worksheet.d.ts +65 -65
- package/dist/models/worksheet.d.ts.map +1 -1
- package/dist/models/worksheet.js +6 -14
- package/dist/models/worksheet.js.map +1 -1
- package/dist/pipelines/gradeWorksheet.d.ts +2 -2
- package/dist/pipelines/pdfToWorksheet.d.ts +1 -1
- package/dist/routers/_app.d.ts +2855 -2051
- 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/announcement.d.ts +5 -5
- package/dist/routers/announcement.d.ts.map +1 -1
- package/dist/routers/announcement.js +25 -5
- package/dist/routers/announcement.js.map +1 -1
- package/dist/routers/assignment.d.ts +44 -44
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/assignment.js +24 -11
- package/dist/routers/assignment.js.map +1 -1
- package/dist/routers/class.d.ts +21 -20
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/class.js +3 -2
- package/dist/routers/class.js.map +1 -1
- package/dist/routers/comment.d.ts +5 -5
- package/dist/routers/conversation.d.ts +6 -6
- package/dist/routers/event.d.ts +21 -2
- package/dist/routers/event.d.ts.map +1 -1
- package/dist/routers/file.d.ts +2 -2
- package/dist/routers/folder.d.ts +24 -24
- package/dist/routers/labChat.d.ts +7 -7
- package/dist/routers/school.d.ts +384 -0
- package/dist/routers/school.d.ts.map +1 -0
- package/dist/routers/school.js +79 -0
- package/dist/routers/school.js.map +1 -0
- package/dist/routers/search.d.ts +1 -1
- package/dist/routers/worksheet.d.ts +21 -21
- package/dist/services/announcement.d.ts.map +1 -1
- package/dist/services/announcement.js +10 -6
- package/dist/services/announcement.js.map +1 -1
- package/dist/services/assignment.d.ts +36 -36
- package/dist/services/class.d.ts +20 -19
- package/dist/services/class.d.ts.map +1 -1
- package/dist/services/class.js +22 -3
- package/dist/services/class.js.map +1 -1
- package/dist/services/comment.d.ts +5 -5
- package/dist/services/comment.d.ts.map +1 -1
- package/dist/services/comment.js +8 -3
- package/dist/services/comment.js.map +1 -1
- package/dist/services/conversation.d.ts +6 -6
- package/dist/services/event.d.ts +21 -2
- package/dist/services/event.d.ts.map +1 -1
- package/dist/services/event.js +11 -7
- package/dist/services/event.js.map +1 -1
- package/dist/services/file.d.ts +2 -2
- package/dist/services/file.d.ts.map +1 -1
- package/dist/services/file.js +17 -8
- package/dist/services/file.js.map +1 -1
- package/dist/services/folder.d.ts +24 -24
- package/dist/services/labChat.d.ts +7 -7
- package/dist/services/school.d.ts +299 -0
- package/dist/services/school.d.ts.map +1 -0
- package/dist/services/school.js +225 -0
- package/dist/services/school.js.map +1 -0
- package/dist/services/worksheet.d.ts +21 -21
- package/package.json +1 -1
- package/prisma/migrations/20260504071500_school_memberships/migration.sql +81 -0
- package/prisma/schema.prisma +66 -2
- package/src/models/access.ts +48 -0
- package/src/models/announcement.ts +19 -2
- package/src/models/assignment.ts +17 -13
- package/src/models/attendance.ts +4 -3
- package/src/models/auth.ts +8 -9
- package/src/models/class.ts +8 -9
- package/src/models/comment.ts +29 -40
- package/src/models/event.ts +54 -4
- package/src/models/file.ts +53 -12
- package/src/models/folder.ts +3 -2
- package/src/models/labChat.ts +9 -8
- package/src/models/school.ts +361 -0
- package/src/models/section.ts +3 -2
- package/src/models/worksheet.ts +7 -12
- package/src/routers/_app.ts +2 -0
- package/src/routers/announcement.ts +30 -4
- package/src/routers/assignment.ts +27 -9
- package/src/routers/class.ts +1 -0
- package/src/routers/school.ts +122 -0
- package/src/services/announcement.ts +12 -4
- package/src/services/class.ts +25 -2
- package/src/services/comment.ts +10 -1
- package/src/services/event.ts +23 -6
- package/src/services/file.ts +20 -6
- package/src/services/school.ts +308 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event.d.ts","sourceRoot":"/","sources":["services/event.ts"],"names":[],"mappings":"AAmBA,6DAA6D;AAC7D,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM
|
|
1
|
+
{"version":3,"file":"event.d.ts","sourceRoot":"/","sources":["services/event.ts"],"names":[],"mappings":"AAmBA,6DAA6D;AAC7D,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAexD;AAED,wCAAwC;AACxC,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;;;;;;;;;;;;;;;;GAwBF;AAED,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;;;;;;;;;;;;GA2BF;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;;GAiBjE;AAuBD,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CrB;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkBrB;AAED,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;GAkBhB"}
|
package/dist/services/event.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Handles assignment attachment/detachment.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
!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]="
|
|
6
|
+
!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]="b9df3493-e672-5d24-b6f8-26b10b12a289")}catch(e){}}();
|
|
7
7
|
import { TRPCError } from "@trpc/server";
|
|
8
8
|
import { parseISO } from "date-fns";
|
|
9
9
|
import { findEventById, findClassWithTeachers, createEvent, updateEvent, deleteEventById, findEventWithClass, findAssignmentWithClass, attachAssignmentToEvent, detachAssignmentFromEvent, findAvailableAssignmentsForClass, } from "../models/event.js";
|
|
@@ -16,7 +16,7 @@ export async function getEvent(userId, id) {
|
|
|
16
16
|
message: "Event not found",
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
|
-
if (event
|
|
19
|
+
if (!canModifyEvent(event, userId)) {
|
|
20
20
|
throw new TRPCError({
|
|
21
21
|
code: "UNAUTHORIZED",
|
|
22
22
|
message: "You are not authorized to view this event",
|
|
@@ -55,7 +55,7 @@ export async function updateEventRecord(userId, id, data) {
|
|
|
55
55
|
message: "Event not found",
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
|
-
if (event
|
|
58
|
+
if (!canModifyEvent(event, userId)) {
|
|
59
59
|
throw new TRPCError({
|
|
60
60
|
code: "UNAUTHORIZED",
|
|
61
61
|
message: "You are not authorized to update this event",
|
|
@@ -80,7 +80,7 @@ export async function deleteEventRecord(userId, id) {
|
|
|
80
80
|
message: "Event not found",
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
|
-
if (event
|
|
83
|
+
if (!canModifyEvent(event, userId)) {
|
|
84
84
|
throw new TRPCError({
|
|
85
85
|
code: "UNAUTHORIZED",
|
|
86
86
|
message: "You are not authorized to delete this event",
|
|
@@ -92,7 +92,9 @@ export async function deleteEventRecord(userId, id) {
|
|
|
92
92
|
function canModifyEvent(event, userId) {
|
|
93
93
|
if (event.userId === userId)
|
|
94
94
|
return true;
|
|
95
|
-
return event.class?.teachers.some((t) => t.id === userId)
|
|
95
|
+
return Boolean(event.class?.teachers.some((t) => t.id === userId) ||
|
|
96
|
+
event.class?.school?.memberships?.some((admin) => admin.userId === userId) ||
|
|
97
|
+
event.class?.school?.users.some((admin) => admin.id === userId));
|
|
96
98
|
}
|
|
97
99
|
export async function attachAssignment(userId, eventId, assignmentId) {
|
|
98
100
|
const event = await findEventWithClass(eventId);
|
|
@@ -115,7 +117,9 @@ export async function attachAssignment(userId, eventId, assignmentId) {
|
|
|
115
117
|
message: "Assignment not found",
|
|
116
118
|
});
|
|
117
119
|
}
|
|
118
|
-
if (!assignment.class.teachers.some((t) => t.id === userId)
|
|
120
|
+
if (!assignment.class.teachers.some((t) => t.id === userId) &&
|
|
121
|
+
!assignment.class.school?.memberships?.some((admin) => admin.userId === userId) &&
|
|
122
|
+
!assignment.class.school?.users.some((admin) => admin.id === userId)) {
|
|
119
123
|
throw new TRPCError({
|
|
120
124
|
code: "UNAUTHORIZED",
|
|
121
125
|
message: "You are not authorized to modify this assignment",
|
|
@@ -165,4 +169,4 @@ export async function getAvailableAssignments(userId, eventId) {
|
|
|
165
169
|
return { assignments };
|
|
166
170
|
}
|
|
167
171
|
//# sourceMappingURL=event.js.map
|
|
168
|
-
//# debugId=
|
|
172
|
+
//# debugId=b9df3493-e672-5d24-b6f8-26b10b12a289
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event.js","sources":["services/event.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Event service – CRUD for calendar events. Supports personal and class events.\n * Handles assignment attachment/detachment.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { parseISO } from \"date-fns\";\nimport {\n findEventById,\n findClassWithTeachers,\n createEvent,\n updateEvent,\n deleteEventById,\n findEventWithClass,\n findAssignmentWithClass,\n attachAssignmentToEvent,\n detachAssignmentFromEvent,\n findAvailableAssignmentsForClass,\n} from \"../models/event.js\";\n\n/** Get a single event. Personal events require ownership. */\nexport async function getEvent(userId: string, id: string) {\n const event = await findEventById(id);\n if (!event) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Event not found\",\n });\n }\n if (event.userId !== userId) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to view this event\",\n });\n }\n return { event };\n}\n\n/** Create a personal or class event. */\nexport async function createEventRecord(\n userId: string,\n input: {\n name?: string;\n location?: string;\n remarks?: string;\n startTime: string;\n endTime: string;\n classId?: string;\n color?: string;\n }\n) {\n if (input.classId) {\n const classData = await findClassWithTeachers(input.classId, userId);\n if (!classData) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to create events for this class\",\n });\n }\n }\n\n const event = await createEvent({\n name: input.name,\n location: input.location,\n remarks: input.remarks,\n startTime: parseISO(input.startTime),\n endTime: parseISO(input.endTime),\n userId,\n color: input.color,\n classId: input.classId,\n });\n\n return { event };\n}\n\nexport async function updateEventRecord(\n userId: string,\n id: string,\n data: {\n name?: string;\n location?: string;\n remarks?: string;\n startTime?: string;\n endTime?: string;\n color?: string;\n classId?: string;\n }\n) {\n const event = await findEventById(id);\n if (!event) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Event not found\",\n });\n }\n if (event.userId !== userId) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to update this event\",\n });\n }\n\n const updatedEvent = await updateEvent(id, {\n name: data.name,\n location: data.location,\n remarks: data.remarks,\n startTime: data.startTime ? parseISO(data.startTime) : undefined,\n endTime: data.endTime ? parseISO(data.endTime) : undefined,\n color: data.color,\n classId: data.classId,\n });\n\n return { event: updatedEvent };\n}\n\nexport async function deleteEventRecord(userId: string, id: string) {\n const event = await findEventById(id);\n if (!event) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Event not found\",\n });\n }\n if (event.userId !== userId) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to delete this event\",\n });\n }\n\n await deleteEventById(id);\n return { success: true };\n}\n\nfunction canModifyEvent(\n event: { userId: string | null; class?: { teachers: { id: string }[] } | null },\n userId: string\n) {\n if (event.userId === userId) return true;\n return event.class?.teachers.some((t) => t.id === userId) ?? false;\n}\n\nexport async function attachAssignment(\n userId: string,\n eventId: string,\n assignmentId: string\n) {\n const event = await findEventWithClass(eventId);\n if (!event) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Event not found\",\n });\n }\n if (!canModifyEvent(event, userId)) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to modify this event\",\n });\n }\n\n const assignment = await findAssignmentWithClass(assignmentId);\n if (!assignment) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Assignment not found\",\n });\n }\n if (!assignment.class.teachers.some((t) => t.id === userId)) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to modify this assignment\",\n });\n }\n if (event.classId !== assignment.classId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Event and assignment must belong to the same class\",\n });\n }\n\n const updatedAssignment = await attachAssignmentToEvent(\n assignmentId,\n eventId\n );\n return { assignment: updatedAssignment };\n}\n\nexport async function detachAssignment(\n userId: string,\n eventId: string,\n assignmentId: string\n) {\n const event = await findEventWithClass(eventId);\n if (!event) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Event not found\",\n });\n }\n if (!canModifyEvent(event, userId)) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to modify this event\",\n });\n }\n\n const updatedAssignment = await detachAssignmentFromEvent(assignmentId);\n return { assignment: updatedAssignment };\n}\n\nexport async function getAvailableAssignments(\n userId: string,\n eventId: string\n) {\n const event = await findEventWithClass(eventId);\n if (!event || !event.classId) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Event not found\",\n });\n }\n if (!canModifyEvent(event, userId)) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to access this event\",\n });\n }\n\n const assignments = await findAvailableAssignmentsForClass(event.classId);\n return { assignments };\n}\n"],"names":[],"mappings":"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","debug_id":"04996008-f63b-58af-ad46-976c9d537646"}
|
|
1
|
+
{"version":3,"file":"event.js","sources":["services/event.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Event service – CRUD for calendar events. Supports personal and class events.\n * Handles assignment attachment/detachment.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { parseISO } from \"date-fns\";\nimport {\n findEventById,\n findClassWithTeachers,\n createEvent,\n updateEvent,\n deleteEventById,\n findEventWithClass,\n findAssignmentWithClass,\n attachAssignmentToEvent,\n detachAssignmentFromEvent,\n findAvailableAssignmentsForClass,\n} from \"../models/event.js\";\n\n/** Get a single event. Personal events require ownership. */\nexport async function getEvent(userId: string, id: string) {\n const event = await findEventById(id);\n if (!event) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Event not found\",\n });\n }\n if (!canModifyEvent(event, userId)) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to view this event\",\n });\n }\n return { event };\n}\n\n/** Create a personal or class event. */\nexport async function createEventRecord(\n userId: string,\n input: {\n name?: string;\n location?: string;\n remarks?: string;\n startTime: string;\n endTime: string;\n classId?: string;\n color?: string;\n }\n) {\n if (input.classId) {\n const classData = await findClassWithTeachers(input.classId, userId);\n if (!classData) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to create events for this class\",\n });\n }\n }\n\n const event = await createEvent({\n name: input.name,\n location: input.location,\n remarks: input.remarks,\n startTime: parseISO(input.startTime),\n endTime: parseISO(input.endTime),\n userId,\n color: input.color,\n classId: input.classId,\n });\n\n return { event };\n}\n\nexport async function updateEventRecord(\n userId: string,\n id: string,\n data: {\n name?: string;\n location?: string;\n remarks?: string;\n startTime?: string;\n endTime?: string;\n color?: string;\n classId?: string;\n }\n) {\n const event = await findEventById(id);\n if (!event) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Event not found\",\n });\n }\n if (!canModifyEvent(event, userId)) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to update this event\",\n });\n }\n\n const updatedEvent = await updateEvent(id, {\n name: data.name,\n location: data.location,\n remarks: data.remarks,\n startTime: data.startTime ? parseISO(data.startTime) : undefined,\n endTime: data.endTime ? parseISO(data.endTime) : undefined,\n color: data.color,\n classId: data.classId,\n });\n\n return { event: updatedEvent };\n}\n\nexport async function deleteEventRecord(userId: string, id: string) {\n const event = await findEventById(id);\n if (!event) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Event not found\",\n });\n }\n if (!canModifyEvent(event, userId)) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to delete this event\",\n });\n }\n\n await deleteEventById(id);\n return { success: true };\n}\n\nfunction canModifyEvent(\n event: {\n userId: string | null;\n class?: {\n teachers: { id: string }[];\n school?: {\n users: { id: string }[];\n memberships?: { userId: string }[];\n } | null;\n } | null;\n },\n userId: string\n) {\n if (event.userId === userId) return true;\n return Boolean(\n event.class?.teachers.some((t) => t.id === userId) ||\n event.class?.school?.memberships?.some((admin) => admin.userId === userId) ||\n event.class?.school?.users.some((admin) => admin.id === userId)\n );\n}\n\nexport async function attachAssignment(\n userId: string,\n eventId: string,\n assignmentId: string\n) {\n const event = await findEventWithClass(eventId);\n if (!event) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Event not found\",\n });\n }\n if (!canModifyEvent(event, userId)) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to modify this event\",\n });\n }\n\n const assignment = await findAssignmentWithClass(assignmentId);\n if (!assignment) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Assignment not found\",\n });\n }\n if (\n !assignment.class.teachers.some((t) => t.id === userId) &&\n !assignment.class.school?.memberships?.some((admin) => admin.userId === userId) &&\n !assignment.class.school?.users.some((admin) => admin.id === userId)\n ) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to modify this assignment\",\n });\n }\n if (event.classId !== assignment.classId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Event and assignment must belong to the same class\",\n });\n }\n\n const updatedAssignment = await attachAssignmentToEvent(\n assignmentId,\n eventId\n );\n return { assignment: updatedAssignment };\n}\n\nexport async function detachAssignment(\n userId: string,\n eventId: string,\n assignmentId: string\n) {\n const event = await findEventWithClass(eventId);\n if (!event) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Event not found\",\n });\n }\n if (!canModifyEvent(event, userId)) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to modify this event\",\n });\n }\n\n const updatedAssignment = await detachAssignmentFromEvent(assignmentId);\n return { assignment: updatedAssignment };\n}\n\nexport async function getAvailableAssignments(\n userId: string,\n eventId: string\n) {\n const event = await findEventWithClass(eventId);\n if (!event || !event.classId) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Event not found\",\n });\n }\n if (!canModifyEvent(event, userId)) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"You are not authorized to access this event\",\n });\n }\n\n const assignments = await findAvailableAssignmentsForClass(event.classId);\n return { assignments };\n}\n"],"names":[],"mappings":"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","debug_id":"b9df3493-e672-5d24-b6f8-26b10b12a289"}
|
package/dist/services/file.d.ts
CHANGED
|
@@ -12,8 +12,8 @@ export declare function moveFile(fileId: string, targetFolderId: string): Promis
|
|
|
12
12
|
type: string;
|
|
13
13
|
name: string;
|
|
14
14
|
id: string;
|
|
15
|
-
size: number | null;
|
|
16
15
|
userId: string | null;
|
|
16
|
+
size: number | null;
|
|
17
17
|
uploadedAt: Date | null;
|
|
18
18
|
uploadStatus: import(".prisma/client").$Enums.UploadStatus;
|
|
19
19
|
uploadUrl: string | null;
|
|
@@ -45,8 +45,8 @@ export declare function renameFile(fileId: string, newName: string): Promise<{
|
|
|
45
45
|
type: string;
|
|
46
46
|
name: string;
|
|
47
47
|
id: string;
|
|
48
|
-
size: number | null;
|
|
49
48
|
userId: string | null;
|
|
49
|
+
size: number | null;
|
|
50
50
|
uploadedAt: Date | null;
|
|
51
51
|
uploadStatus: import(".prisma/client").$Enums.UploadStatus;
|
|
52
52
|
uploadUrl: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.d.ts","sourceRoot":"/","sources":["services/file.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"/","sources":["services/file.ts"],"names":[],"mappings":"AA2BA,0EAA0E;AAC1E,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;GAkFpE;AAED,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmBvB;AAED,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkBhB;AAED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;GA6BrE"}
|
package/dist/services/file.js
CHANGED
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
* for assignment, submission, announcement, folder, and user-owned files.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
!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]="
|
|
6
|
+
!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]="4ce26498-ba77-5a67-910b-428e64d7047b")}catch(e){}}();
|
|
7
7
|
import { TRPCError } from "@trpc/server";
|
|
8
8
|
import { getSignedUrl, deleteFile } from "../lib/googleCloudStorage.js";
|
|
9
9
|
import { logger } from "../utils/logger.js";
|
|
10
10
|
import { findFileById, findFileWithFolder, findFileWithFolderAndThumbnail, findFolderById, updateFileFolder, updateFileName, deleteFileById, } from "../models/file.js";
|
|
11
11
|
import { findConversationMembership } from "../models/message.js";
|
|
12
|
+
function isSchoolAdminForClass(classData, userId) {
|
|
13
|
+
return Boolean(classData?.school?.memberships?.some((membership) => membership.userId === userId) ||
|
|
14
|
+
classData?.school?.users?.some((admin) => admin.id === userId));
|
|
15
|
+
}
|
|
12
16
|
/** Generate a signed URL for file download. Validates user has access. */
|
|
13
17
|
export async function getFileSignedUrl(userId, fileId) {
|
|
14
18
|
const file = await findFileById(fileId);
|
|
@@ -22,26 +26,30 @@ export async function getFileSignedUrl(userId, fileId) {
|
|
|
22
26
|
if (file.assignment?.class) {
|
|
23
27
|
const isTeacher = file.assignment.class.teachers.some((t) => t.id === userId);
|
|
24
28
|
const isStudent = file.assignment.class.students.some((s) => s.id === userId);
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
const isSchoolAdmin = isSchoolAdminForClass(file.assignment.class, userId);
|
|
30
|
+
logger.info(`Assignment file access check - userId: ${userId}, isTeacher: ${isTeacher}, isStudent: ${isStudent}, isSchoolAdmin: ${isSchoolAdmin}`);
|
|
31
|
+
hasAccess = isTeacher || isStudent || isSchoolAdmin;
|
|
27
32
|
}
|
|
28
33
|
if (file.announcement?.class) {
|
|
29
34
|
const ann = file.announcement;
|
|
30
35
|
const isTeacher = ann.class.teachers.some((t) => t.id === userId);
|
|
31
36
|
const isStudent = ann.class.students.some((s) => s.id === userId);
|
|
32
|
-
|
|
37
|
+
const isSchoolAdmin = isSchoolAdminForClass(ann.class, userId);
|
|
38
|
+
hasAccess = hasAccess || isTeacher || isStudent || isSchoolAdmin;
|
|
33
39
|
}
|
|
34
40
|
if (file.submission?.assignment?.classId) {
|
|
35
41
|
hasAccess =
|
|
36
42
|
hasAccess ||
|
|
37
43
|
file.submission.studentId === userId ||
|
|
38
|
-
file.submission.assignment.class.teachers.some((t) => t.id === userId)
|
|
44
|
+
file.submission.assignment.class.teachers.some((t) => t.id === userId) ||
|
|
45
|
+
isSchoolAdminForClass(file.submission.assignment.class, userId);
|
|
39
46
|
}
|
|
40
47
|
if (file.annotations?.assignment?.classId) {
|
|
41
48
|
hasAccess =
|
|
42
49
|
hasAccess ||
|
|
43
50
|
file.annotations.studentId === userId ||
|
|
44
|
-
file.annotations.assignment.class.teachers.some((t) => t.id === userId)
|
|
51
|
+
file.annotations.assignment.class.teachers.some((t) => t.id === userId) ||
|
|
52
|
+
isSchoolAdminForClass(file.annotations.assignment.class, userId);
|
|
45
53
|
}
|
|
46
54
|
if (file.userId === userId) {
|
|
47
55
|
hasAccess = true;
|
|
@@ -53,7 +61,8 @@ export async function getFileSignedUrl(userId, fileId) {
|
|
|
53
61
|
if (file.folder?.class) {
|
|
54
62
|
const isTeacher = file.folder.class.teachers.some((t) => t.id === userId);
|
|
55
63
|
const isStudent = file.folder.class.students.some((s) => s.id === userId);
|
|
56
|
-
|
|
64
|
+
const isSchoolAdmin = isSchoolAdminForClass(file.folder.class, userId);
|
|
65
|
+
hasAccess = hasAccess || isTeacher || isStudent || isSchoolAdmin;
|
|
57
66
|
}
|
|
58
67
|
if (!hasAccess) {
|
|
59
68
|
throw new TRPCError({
|
|
@@ -135,4 +144,4 @@ export async function deleteFileRecord(fileId, classId) {
|
|
|
135
144
|
return { success: true };
|
|
136
145
|
}
|
|
137
146
|
//# sourceMappingURL=file.js.map
|
|
138
|
-
//# debugId=
|
|
147
|
+
//# debugId=4ce26498-ba77-5a67-910b-428e64d7047b
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.js","sources":["services/file.ts"],"sourceRoot":"/","sourcesContent":["/**\n * File service – signed URLs, move, rename, delete. Handles permission checks\n * for assignment, submission, announcement, folder, and user-owned files.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { getSignedUrl, deleteFile } from \"../lib/googleCloudStorage.js\";\nimport { logger } from \"../utils/logger.js\";\nimport {\n findFileById,\n findFileWithFolder,\n findFileWithFolderAndThumbnail,\n findFolderById,\n updateFileFolder,\n updateFileName,\n deleteFileById,\n} from \"../models/file.js\";\nimport { findConversationMembership } from \"../models/message.js\";\n\n/** Generate a signed URL for file download. Validates user has access. */\nexport async function getFileSignedUrl(userId: string, fileId: string) {\n const file = await findFileById(fileId);\n if (!file) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"File does not exist\",\n });\n }\n\n let hasAccess = false;\n\n if (file.assignment?.class) {\n const isTeacher = file.assignment.class.teachers.some(\n (t) => t.id === userId\n );\n const isStudent = file.assignment.class.students.some(\n (s) => s.id === userId\n );\n logger.info(\n `Assignment file access check - userId: ${userId}, isTeacher: ${isTeacher}, isStudent: ${isStudent}`\n );\n hasAccess = isTeacher || isStudent;\n }\n\n if ((file as any).announcement?.class) {\n const ann = (file as any).announcement;\n const isTeacher = ann.class.teachers.some((t: any) => t.id === userId);\n const isStudent = ann.class.students.some((s: any) => s.id === userId);\n hasAccess = hasAccess || isTeacher || isStudent;\n }\n\n if (file.submission?.assignment?.classId) {\n hasAccess =\n hasAccess ||\n file.submission.studentId === userId ||\n file.submission.assignment.class.teachers.some((t) => t.id === userId);\n }\n\n if (file.annotations?.assignment?.classId) {\n hasAccess =\n hasAccess ||\n file.annotations.studentId === userId ||\n file.annotations.assignment.class.teachers.some((t) => t.id === userId);\n }\n\n if (file.userId === userId) {\n hasAccess = true;\n }\n\n if (file.conversationId) {\n const membership = await findConversationMembership(file.conversationId, userId);\n hasAccess = hasAccess || Boolean(membership);\n }\n\n if (file.folder?.class) {\n const isTeacher = file.folder.class.teachers.some((t) => t.id === userId);\n const isStudent = file.folder.class.students.some((s) => s.id === userId);\n hasAccess = hasAccess || isTeacher || isStudent;\n }\n\n if (!hasAccess) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You do not have access to this file\",\n });\n }\n\n try {\n const signedUrl = await getSignedUrl(file.path);\n return { url: signedUrl };\n } catch (error) {\n logger.error(\"Error generating signed URL:\", error as Record<string, unknown>);\n throw new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: \"Failed to generate download URL\",\n });\n }\n}\n\nexport async function moveFile(\n fileId: string,\n targetFolderId: string\n) {\n const file = await findFileWithFolder(fileId);\n if (!file) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"File not found\",\n });\n }\n\n const targetFolder = await findFolderById(targetFolderId);\n if (!targetFolder) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Target folder not found\",\n });\n }\n\n return updateFileFolder(fileId, targetFolderId);\n}\n\nexport async function renameFile(\n fileId: string,\n newName: string\n) {\n const file = await findFileWithFolder(fileId);\n if (!file) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"File not found\",\n });\n }\n\n if (!newName.trim()) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"File name cannot be empty\",\n });\n }\n\n return updateFileName(fileId, newName.trim());\n}\n\nexport async function deleteFileRecord(fileId: string, classId: string) {\n const file = await findFileWithFolderAndThumbnail(fileId);\n if (!file) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"File not found\",\n });\n }\n\n if (file.folder?.classId !== classId) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"File does not belong to this class\",\n });\n }\n\n try {\n if (file.uploadStatus === \"COMPLETED\") {\n await deleteFile(file.path);\n if (file.thumbnail) {\n await deleteFile(file.thumbnail.path);\n }\n }\n } catch (error) {\n logger.warn(`Failed to delete file ${file.path}:`, error as Record<string, unknown>);\n }\n\n await deleteFileById(fileId);\n return { success: true };\n}\n"],"names":[],"mappings":"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","debug_id":"c9a35639-e642-5ed5-b260-9bacbf8cb7e9"}
|
|
1
|
+
{"version":3,"file":"file.js","sources":["services/file.ts"],"sourceRoot":"/","sourcesContent":["/**\n * File service – signed URLs, move, rename, delete. Handles permission checks\n * for assignment, submission, announcement, folder, and user-owned files.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { getSignedUrl, deleteFile } from \"../lib/googleCloudStorage.js\";\nimport { logger } from \"../utils/logger.js\";\nimport {\n findFileById,\n findFileWithFolder,\n findFileWithFolderAndThumbnail,\n findFolderById,\n updateFileFolder,\n updateFileName,\n deleteFileById,\n} from \"../models/file.js\";\nimport { findConversationMembership } from \"../models/message.js\";\n\nfunction isSchoolAdminForClass(classData: any, userId: string) {\n return Boolean(\n classData?.school?.memberships?.some(\n (membership: { userId: string }) => membership.userId === userId\n ) ||\n classData?.school?.users?.some((admin: { id: string }) => admin.id === userId)\n );\n}\n\n/** Generate a signed URL for file download. Validates user has access. */\nexport async function getFileSignedUrl(userId: string, fileId: string) {\n const file = await findFileById(fileId);\n if (!file) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"File does not exist\",\n });\n }\n\n let hasAccess = false;\n\n if (file.assignment?.class) {\n const isTeacher = file.assignment.class.teachers.some(\n (t) => t.id === userId\n );\n const isStudent = file.assignment.class.students.some(\n (s) => s.id === userId\n );\n const isSchoolAdmin = isSchoolAdminForClass(file.assignment.class, userId);\n logger.info(\n `Assignment file access check - userId: ${userId}, isTeacher: ${isTeacher}, isStudent: ${isStudent}, isSchoolAdmin: ${isSchoolAdmin}`\n );\n hasAccess = isTeacher || isStudent || isSchoolAdmin;\n }\n\n if ((file as any).announcement?.class) {\n const ann = (file as any).announcement;\n const isTeacher = ann.class.teachers.some((t: any) => t.id === userId);\n const isStudent = ann.class.students.some((s: any) => s.id === userId);\n const isSchoolAdmin = isSchoolAdminForClass(ann.class, userId);\n hasAccess = hasAccess || isTeacher || isStudent || isSchoolAdmin;\n }\n\n if (file.submission?.assignment?.classId) {\n hasAccess =\n hasAccess ||\n file.submission.studentId === userId ||\n file.submission.assignment.class.teachers.some((t) => t.id === userId) ||\n isSchoolAdminForClass(file.submission.assignment.class, userId);\n }\n\n if (file.annotations?.assignment?.classId) {\n hasAccess =\n hasAccess ||\n file.annotations.studentId === userId ||\n file.annotations.assignment.class.teachers.some((t) => t.id === userId) ||\n isSchoolAdminForClass(file.annotations.assignment.class, userId);\n }\n\n if (file.userId === userId) {\n hasAccess = true;\n }\n\n if (file.conversationId) {\n const membership = await findConversationMembership(file.conversationId, userId);\n hasAccess = hasAccess || Boolean(membership);\n }\n\n if (file.folder?.class) {\n const isTeacher = file.folder.class.teachers.some((t) => t.id === userId);\n const isStudent = file.folder.class.students.some((s) => s.id === userId);\n const isSchoolAdmin = isSchoolAdminForClass(file.folder.class, userId);\n hasAccess = hasAccess || isTeacher || isStudent || isSchoolAdmin;\n }\n\n if (!hasAccess) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You do not have access to this file\",\n });\n }\n\n try {\n const signedUrl = await getSignedUrl(file.path);\n return { url: signedUrl };\n } catch (error) {\n logger.error(\"Error generating signed URL:\", error as Record<string, unknown>);\n throw new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: \"Failed to generate download URL\",\n });\n }\n}\n\nexport async function moveFile(\n fileId: string,\n targetFolderId: string\n) {\n const file = await findFileWithFolder(fileId);\n if (!file) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"File not found\",\n });\n }\n\n const targetFolder = await findFolderById(targetFolderId);\n if (!targetFolder) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"Target folder not found\",\n });\n }\n\n return updateFileFolder(fileId, targetFolderId);\n}\n\nexport async function renameFile(\n fileId: string,\n newName: string\n) {\n const file = await findFileWithFolder(fileId);\n if (!file) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"File not found\",\n });\n }\n\n if (!newName.trim()) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"File name cannot be empty\",\n });\n }\n\n return updateFileName(fileId, newName.trim());\n}\n\nexport async function deleteFileRecord(fileId: string, classId: string) {\n const file = await findFileWithFolderAndThumbnail(fileId);\n if (!file) {\n throw new TRPCError({\n code: \"NOT_FOUND\",\n message: \"File not found\",\n });\n }\n\n if (file.folder?.classId !== classId) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"File does not belong to this class\",\n });\n }\n\n try {\n if (file.uploadStatus === \"COMPLETED\") {\n await deleteFile(file.path);\n if (file.thumbnail) {\n await deleteFile(file.thumbnail.path);\n }\n }\n } catch (error) {\n logger.warn(`Failed to delete file ${file.path}:`, error as Record<string, unknown>);\n }\n\n await deleteFileById(fileId);\n return { success: true };\n}\n"],"names":[],"mappings":"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","debug_id":"4ce26498-ba77-5a67-910b-428e64d7047b"}
|
|
@@ -9,21 +9,21 @@ export declare function createFolderRecord(userId: string, input: {
|
|
|
9
9
|
type: string;
|
|
10
10
|
name: string;
|
|
11
11
|
id: string;
|
|
12
|
-
size: number | null;
|
|
13
|
-
uploadedAt: Date | null;
|
|
14
12
|
user: {
|
|
15
13
|
id: string;
|
|
16
14
|
username: string;
|
|
17
15
|
} | null;
|
|
16
|
+
size: number | null;
|
|
17
|
+
uploadedAt: Date | null;
|
|
18
18
|
}[];
|
|
19
19
|
childFolders: {
|
|
20
20
|
name: string;
|
|
21
21
|
id: string;
|
|
22
|
+
color: string | null;
|
|
22
23
|
_count: {
|
|
23
24
|
files: number;
|
|
24
25
|
childFolders: number;
|
|
25
26
|
};
|
|
26
|
-
color: string | null;
|
|
27
27
|
}[];
|
|
28
28
|
} & {
|
|
29
29
|
name: string;
|
|
@@ -38,21 +38,21 @@ export declare function getFolder(folderId: string): Promise<{
|
|
|
38
38
|
type: string;
|
|
39
39
|
name: string;
|
|
40
40
|
id: string;
|
|
41
|
-
size: number | null;
|
|
42
|
-
uploadedAt: Date | null;
|
|
43
41
|
user: {
|
|
44
42
|
id: string;
|
|
45
43
|
username: string;
|
|
46
44
|
} | null;
|
|
45
|
+
size: number | null;
|
|
46
|
+
uploadedAt: Date | null;
|
|
47
47
|
}[];
|
|
48
48
|
childFolders: {
|
|
49
49
|
name: string;
|
|
50
50
|
id: string;
|
|
51
|
+
color: string | null;
|
|
51
52
|
_count: {
|
|
52
53
|
files: number;
|
|
53
54
|
childFolders: number;
|
|
54
55
|
};
|
|
55
|
-
color: string | null;
|
|
56
56
|
}[];
|
|
57
57
|
parentFolder: {
|
|
58
58
|
name: string;
|
|
@@ -70,21 +70,21 @@ export declare function getChildFolders(classId: string): Promise<({
|
|
|
70
70
|
type: string;
|
|
71
71
|
name: string;
|
|
72
72
|
id: string;
|
|
73
|
-
size: number | null;
|
|
74
|
-
uploadedAt: Date | null;
|
|
75
73
|
user: {
|
|
76
74
|
id: string;
|
|
77
75
|
username: string;
|
|
78
76
|
} | null;
|
|
77
|
+
size: number | null;
|
|
78
|
+
uploadedAt: Date | null;
|
|
79
79
|
}[];
|
|
80
80
|
childFolders: {
|
|
81
81
|
name: string;
|
|
82
82
|
id: string;
|
|
83
|
+
color: string | null;
|
|
83
84
|
_count: {
|
|
84
85
|
files: number;
|
|
85
86
|
childFolders: number;
|
|
86
87
|
};
|
|
87
|
-
color: string | null;
|
|
88
88
|
}[];
|
|
89
89
|
} & {
|
|
90
90
|
name: string;
|
|
@@ -98,21 +98,21 @@ export declare function getFolderChildren(folderId: string, classId: string): Pr
|
|
|
98
98
|
type: string;
|
|
99
99
|
name: string;
|
|
100
100
|
id: string;
|
|
101
|
-
size: number | null;
|
|
102
|
-
uploadedAt: Date | null;
|
|
103
101
|
user: {
|
|
104
102
|
id: string;
|
|
105
103
|
username: string;
|
|
106
104
|
} | null;
|
|
105
|
+
size: number | null;
|
|
106
|
+
uploadedAt: Date | null;
|
|
107
107
|
}[];
|
|
108
108
|
childFolders: {
|
|
109
109
|
name: string;
|
|
110
110
|
id: string;
|
|
111
|
+
color: string | null;
|
|
111
112
|
_count: {
|
|
112
113
|
files: number;
|
|
113
114
|
childFolders: number;
|
|
114
115
|
};
|
|
115
|
-
color: string | null;
|
|
116
116
|
}[];
|
|
117
117
|
} & {
|
|
118
118
|
name: string;
|
|
@@ -126,24 +126,24 @@ export declare function getRootFolder(classId: string): Promise<{
|
|
|
126
126
|
type: string;
|
|
127
127
|
name: string;
|
|
128
128
|
id: string;
|
|
129
|
-
size: number | null;
|
|
130
|
-
uploadedAt: Date | null;
|
|
131
129
|
user: {
|
|
132
130
|
id: string;
|
|
133
131
|
username: string;
|
|
134
132
|
} | null;
|
|
133
|
+
size: number | null;
|
|
134
|
+
uploadedAt: Date | null;
|
|
135
135
|
}[];
|
|
136
136
|
childFolders: {
|
|
137
137
|
name: string;
|
|
138
138
|
id: string;
|
|
139
|
-
|
|
140
|
-
id: string;
|
|
141
|
-
}[];
|
|
139
|
+
color: string | null;
|
|
142
140
|
_count: {
|
|
143
141
|
files: number;
|
|
144
142
|
childFolders: number;
|
|
145
143
|
};
|
|
146
|
-
|
|
144
|
+
files: {
|
|
145
|
+
id: string;
|
|
146
|
+
}[];
|
|
147
147
|
childFolders: {
|
|
148
148
|
id: string;
|
|
149
149
|
}[];
|
|
@@ -173,21 +173,21 @@ export declare function moveFolder(userId: string, folderId: string, targetParen
|
|
|
173
173
|
type: string;
|
|
174
174
|
name: string;
|
|
175
175
|
id: string;
|
|
176
|
-
size: number | null;
|
|
177
|
-
uploadedAt: Date | null;
|
|
178
176
|
user: {
|
|
179
177
|
id: string;
|
|
180
178
|
username: string;
|
|
181
179
|
} | null;
|
|
180
|
+
size: number | null;
|
|
181
|
+
uploadedAt: Date | null;
|
|
182
182
|
}[];
|
|
183
183
|
childFolders: {
|
|
184
184
|
name: string;
|
|
185
185
|
id: string;
|
|
186
|
+
color: string | null;
|
|
186
187
|
_count: {
|
|
187
188
|
files: number;
|
|
188
189
|
childFolders: number;
|
|
189
190
|
};
|
|
190
|
-
color: string | null;
|
|
191
191
|
}[];
|
|
192
192
|
} & {
|
|
193
193
|
name: string;
|
|
@@ -201,21 +201,21 @@ export declare function updateFolderRecord(folderId: string, name: string, color
|
|
|
201
201
|
type: string;
|
|
202
202
|
name: string;
|
|
203
203
|
id: string;
|
|
204
|
-
size: number | null;
|
|
205
|
-
uploadedAt: Date | null;
|
|
206
204
|
user: {
|
|
207
205
|
id: string;
|
|
208
206
|
username: string;
|
|
209
207
|
} | null;
|
|
208
|
+
size: number | null;
|
|
209
|
+
uploadedAt: Date | null;
|
|
210
210
|
}[];
|
|
211
211
|
childFolders: {
|
|
212
212
|
name: string;
|
|
213
213
|
id: string;
|
|
214
|
+
color: string | null;
|
|
214
215
|
_count: {
|
|
215
216
|
files: number;
|
|
216
217
|
childFolders: number;
|
|
217
218
|
};
|
|
218
|
-
color: string | null;
|
|
219
219
|
}[];
|
|
220
220
|
} & {
|
|
221
221
|
name: string;
|
|
@@ -22,9 +22,9 @@ export declare function createLabChat(userId: string, input: {
|
|
|
22
22
|
};
|
|
23
23
|
} & {
|
|
24
24
|
id: string;
|
|
25
|
+
role: import(".prisma/client").$Enums.ConversationRole;
|
|
25
26
|
userId: string;
|
|
26
27
|
conversationId: string;
|
|
27
|
-
role: import(".prisma/client").$Enums.ConversationRole;
|
|
28
28
|
joinedAt: Date;
|
|
29
29
|
hiddenAt: Date | null;
|
|
30
30
|
lastViewedAt: Date | null;
|
|
@@ -48,11 +48,11 @@ export declare function createLabChat(userId: string, input: {
|
|
|
48
48
|
} & {
|
|
49
49
|
context: string;
|
|
50
50
|
id: string;
|
|
51
|
-
conversationId: string;
|
|
52
51
|
createdAt: Date;
|
|
52
|
+
updatedAt: Date;
|
|
53
|
+
conversationId: string;
|
|
53
54
|
classId: string;
|
|
54
55
|
title: string;
|
|
55
|
-
updatedAt: Date;
|
|
56
56
|
createdById: string;
|
|
57
57
|
}>;
|
|
58
58
|
export declare function getLabChat(userId: string, labChatId: string): Promise<{
|
|
@@ -75,9 +75,9 @@ export declare function getLabChat(userId: string, labChatId: string): Promise<{
|
|
|
75
75
|
};
|
|
76
76
|
} & {
|
|
77
77
|
id: string;
|
|
78
|
+
role: import(".prisma/client").$Enums.ConversationRole;
|
|
78
79
|
userId: string;
|
|
79
80
|
conversationId: string;
|
|
80
|
-
role: import(".prisma/client").$Enums.ConversationRole;
|
|
81
81
|
joinedAt: Date;
|
|
82
82
|
hiddenAt: Date | null;
|
|
83
83
|
lastViewedAt: Date | null;
|
|
@@ -101,11 +101,11 @@ export declare function getLabChat(userId: string, labChatId: string): Promise<{
|
|
|
101
101
|
};
|
|
102
102
|
context: string;
|
|
103
103
|
id: string;
|
|
104
|
-
conversationId: string;
|
|
105
104
|
createdAt: Date;
|
|
105
|
+
updatedAt: Date;
|
|
106
|
+
conversationId: string;
|
|
106
107
|
classId: string;
|
|
107
108
|
title: string;
|
|
108
|
-
updatedAt: Date;
|
|
109
109
|
createdById: string;
|
|
110
110
|
}>;
|
|
111
111
|
export declare function listLabChats(userId: string, classId: string): Promise<{
|
|
@@ -134,8 +134,8 @@ export declare function listLabChats(userId: string, classId: string): Promise<{
|
|
|
134
134
|
status: import(".prisma/client").$Enums.GenerationStatus | null;
|
|
135
135
|
meta: import("@prisma/client/runtime/library.js").JsonValue | null;
|
|
136
136
|
id: string;
|
|
137
|
-
conversationId: string;
|
|
138
137
|
createdAt: Date;
|
|
138
|
+
conversationId: string;
|
|
139
139
|
content: string;
|
|
140
140
|
senderId: string;
|
|
141
141
|
};
|