@studious-lms/server 1.4.2 → 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.coderabbit.yaml +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +67 -28
- package/dist/index.js.map +1 -1
- package/dist/lib/fileUpload.d.ts +10 -2
- package/dist/lib/fileUpload.d.ts.map +1 -1
- package/dist/lib/fileUpload.js +38 -6
- package/dist/lib/fileUpload.js.map +1 -1
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +18 -5
- package/dist/middleware/auth.js.map +1 -1
- package/dist/models/auth.d.ts +19 -14
- package/dist/models/auth.d.ts.map +1 -1
- package/dist/models/auth.js +53 -30
- package/dist/models/auth.js.map +1 -1
- package/dist/models/class.d.ts +3 -1
- package/dist/models/class.d.ts.map +1 -1
- package/dist/models/class.js +16 -4
- package/dist/models/class.js.map +1 -1
- package/dist/models/notification.d.ts +11 -10
- package/dist/models/notification.d.ts.map +1 -1
- package/dist/models/notification.js +13 -9
- package/dist/models/notification.js.map +1 -1
- package/dist/models/worksheet.d.ts +378 -7
- package/dist/models/worksheet.d.ts.map +1 -1
- package/dist/models/worksheet.js +168 -2
- package/dist/models/worksheet.js.map +1 -1
- package/dist/pipelines/aiLabChat.d.ts.map +1 -1
- package/dist/pipelines/aiLabChat.js +11 -3
- package/dist/pipelines/aiLabChat.js.map +1 -1
- package/dist/pipelines/aiLabChatContract.d.ts +3 -3
- package/dist/pipelines/aiNewtonChat.d.ts.map +1 -1
- package/dist/pipelines/aiNewtonChat.js +25 -14
- package/dist/pipelines/aiNewtonChat.js.map +1 -1
- package/dist/pipelines/gradeWorksheet.d.ts.map +1 -1
- package/dist/pipelines/gradeWorksheet.js +10 -3
- package/dist/pipelines/gradeWorksheet.js.map +1 -1
- package/dist/routers/_app.d.ts +124 -18
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/class.d.ts +2 -1
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/class.js +3 -3
- package/dist/routers/class.js.map +1 -1
- package/dist/routers/labChat.d.ts +6 -0
- package/dist/routers/labChat.d.ts.map +1 -1
- package/dist/routers/labChat.js +5 -3
- package/dist/routers/labChat.js.map +1 -1
- package/dist/routers/message.d.ts +31 -0
- package/dist/routers/message.d.ts.map +1 -1
- package/dist/routers/message.js +27 -4
- package/dist/routers/message.js.map +1 -1
- package/dist/routers/newtonChat.d.ts +6 -0
- package/dist/routers/newtonChat.d.ts.map +1 -1
- package/dist/routers/newtonChat.js +5 -4
- package/dist/routers/newtonChat.js.map +1 -1
- package/dist/routers/notifications.d.ts +9 -2
- package/dist/routers/notifications.d.ts.map +1 -1
- package/dist/routers/notifications.js +4 -4
- package/dist/routers/notifications.js.map +1 -1
- package/dist/routers/worksheet.d.ts +8 -6
- package/dist/routers/worksheet.d.ts.map +1 -1
- package/dist/routers/worksheet.js +18 -16
- package/dist/routers/worksheet.js.map +1 -1
- package/dist/services/auth.d.ts +1 -1
- package/dist/services/auth.d.ts.map +1 -1
- package/dist/services/auth.js +19 -12
- package/dist/services/auth.js.map +1 -1
- package/dist/services/class.d.ts +1 -1
- package/dist/services/class.d.ts.map +1 -1
- package/dist/services/class.js +6 -3
- package/dist/services/class.js.map +1 -1
- package/dist/services/file.d.ts.map +1 -1
- package/dist/services/file.js +7 -2
- package/dist/services/file.js.map +1 -1
- package/dist/services/labChat.d.ts +6 -0
- package/dist/services/labChat.d.ts.map +1 -1
- package/dist/services/labChat.js +30 -18
- package/dist/services/labChat.js.map +1 -1
- package/dist/services/message.d.ts +30 -0
- package/dist/services/message.d.ts.map +1 -1
- package/dist/services/message.js +97 -21
- package/dist/services/message.js.map +1 -1
- package/dist/services/newtonChat.d.ts +6 -1
- package/dist/services/newtonChat.d.ts.map +1 -1
- package/dist/services/newtonChat.js +36 -18
- package/dist/services/newtonChat.js.map +1 -1
- package/dist/services/notification.d.ts +12 -5
- package/dist/services/notification.d.ts.map +1 -1
- package/dist/services/notification.js +24 -9
- package/dist/services/notification.js.map +1 -1
- package/dist/services/studentProgress.d.ts.map +1 -1
- package/dist/services/studentProgress.js +6 -3
- package/dist/services/studentProgress.js.map +1 -1
- package/dist/services/worksheet.d.ts +15 -15
- package/dist/services/worksheet.d.ts.map +1 -1
- package/dist/services/worksheet.js +138 -54
- package/dist/services/worksheet.js.map +1 -1
- package/dist/trpc.d.ts.map +1 -1
- package/dist/trpc.js +11 -17
- package/dist/trpc.js.map +1 -1
- package/dist/utils/inference.d.ts +9 -1
- package/dist/utils/inference.d.ts.map +1 -1
- package/dist/utils/inference.js +138 -50
- package/dist/utils/inference.js.map +1 -1
- package/package.json +1 -1
- package/prisma/migrations/20260415103500_add_session_type/migration.sql +33 -0
- package/prisma/migrations/20260415133000_add_ai_usage_logs/migration.sql +19 -0
- package/prisma/schema.prisma +27 -1
- package/scripts/test-pre-push.ts +6 -2
- package/src/index.ts +80 -28
- package/src/lib/fileUpload.ts +55 -5
- package/src/middleware/auth.ts +19 -4
- package/src/models/auth.ts +59 -29
- package/src/models/class.ts +15 -4
- package/src/models/notification.ts +13 -7
- package/src/models/worksheet.ts +202 -0
- package/src/pipelines/aiLabChat.ts +9 -1
- package/src/pipelines/aiNewtonChat.ts +24 -14
- package/src/pipelines/gradeWorksheet.ts +8 -0
- package/src/routers/class.ts +2 -2
- package/src/routers/labChat.ts +3 -1
- package/src/routers/message.ts +38 -1
- package/src/routers/newtonChat.ts +4 -2
- package/src/routers/notifications.ts +2 -2
- package/src/routers/worksheet.ts +31 -19
- package/src/services/auth.ts +26 -12
- package/src/services/class.ts +4 -1
- package/src/services/file.ts +6 -0
- package/src/services/labChat.ts +42 -18
- package/src/services/message.ts +163 -18
- package/src/services/newtonChat.ts +49 -18
- package/src/services/notification.ts +27 -8
- package/src/services/studentProgress.ts +4 -1
- package/src/services/worksheet.ts +191 -51
- package/src/trpc.ts +12 -18
- package/src/utils/inference.ts +209 -55
- package/tests/globalSetup.ts +13 -4
- package/tests/routers/auth.test.ts +120 -17
- package/tests/routers/class.test.ts +7 -1
- package/tests/routers/message.test.ts +236 -9
- package/tests/routers/newtonChat.test.ts +81 -0
- package/tests/routers/notification.test.ts +12 -0
- package/tests/routers/worksheet.test.ts +194 -0
- package/tests/setup.ts +22 -5
- package/tests/utils/inference.test.ts +218 -0
package/dist/middleware/auth.js
CHANGED
|
@@ -1,19 +1,32 @@
|
|
|
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]="ef261406-0c03-5992-af7a-26665f456c05")}catch(e){}}();
|
|
3
3
|
import { TRPCError } from "@trpc/server";
|
|
4
4
|
import * as Sentry from "@sentry/node";
|
|
5
5
|
import { findUserBySessionToken, findTeacherClassesByUserId, findClassWithMember, findClassWithTeacher, } from "../models/auth.js";
|
|
6
|
+
function getRequestToken(headers) {
|
|
7
|
+
const userHeader = headers["x-user"];
|
|
8
|
+
if (typeof userHeader === "string") {
|
|
9
|
+
return userHeader;
|
|
10
|
+
}
|
|
11
|
+
if (Array.isArray(userHeader) && userHeader.length > 0) {
|
|
12
|
+
return userHeader[0];
|
|
13
|
+
}
|
|
14
|
+
const authorizationHeader = headers.authorization;
|
|
15
|
+
if (typeof authorizationHeader === "string" && authorizationHeader.startsWith("Bearer ")) {
|
|
16
|
+
return authorizationHeader.slice(7);
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
6
20
|
export const createAuthMiddleware = (t) => {
|
|
7
21
|
const isAuthed = t.middleware(async ({ next, ctx }) => {
|
|
8
|
-
const
|
|
9
|
-
if (!
|
|
22
|
+
const token = getRequestToken(ctx.req.headers);
|
|
23
|
+
if (!token) {
|
|
10
24
|
throw new TRPCError({
|
|
11
25
|
code: "UNAUTHORIZED",
|
|
12
26
|
message: "Not authenticated - no token found",
|
|
13
27
|
});
|
|
14
28
|
}
|
|
15
29
|
try {
|
|
16
|
-
const token = typeof userHeader === "string" ? userHeader : userHeader[0];
|
|
17
30
|
const user = await findUserBySessionToken(token);
|
|
18
31
|
if (!user) {
|
|
19
32
|
throw new TRPCError({
|
|
@@ -110,4 +123,4 @@ export const createAuthMiddleware = (t) => {
|
|
|
110
123
|
};
|
|
111
124
|
};
|
|
112
125
|
//# sourceMappingURL=auth.js.map
|
|
113
|
-
//# debugId=
|
|
126
|
+
//# debugId=ef261406-0c03-5992-af7a-26665f456c05
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sources":["middleware/auth.ts"],"sourceRoot":"/","sourcesContent":["import { TRPCError } from \"@trpc/server\";\nimport * as Sentry from \"@sentry/node\";\nimport type { MiddlewareContext } from \"../types/trpc.js\";\nimport {\n findUserBySessionToken,\n findTeacherClassesByUserId,\n findClassWithMember,\n findClassWithTeacher,\n} from \"../models/auth.js\";\n\nexport const createAuthMiddleware = (t: any) => {\n const isAuthed = t.middleware(async ({ next, ctx }: MiddlewareContext) => {\n const
|
|
1
|
+
{"version":3,"file":"auth.js","sources":["middleware/auth.ts"],"sourceRoot":"/","sourcesContent":["import { TRPCError } from \"@trpc/server\";\nimport * as Sentry from \"@sentry/node\";\nimport type { MiddlewareContext } from \"../types/trpc.js\";\nimport {\n findUserBySessionToken,\n findTeacherClassesByUserId,\n findClassWithMember,\n findClassWithTeacher,\n} from \"../models/auth.js\";\n\nfunction getRequestToken(headers: MiddlewareContext[\"ctx\"][\"req\"][\"headers\"]) {\n const userHeader = headers[\"x-user\"];\n if (typeof userHeader === \"string\") {\n return userHeader;\n }\n if (Array.isArray(userHeader) && userHeader.length > 0) {\n return userHeader[0];\n }\n\n const authorizationHeader = headers.authorization;\n if (typeof authorizationHeader === \"string\" && authorizationHeader.startsWith(\"Bearer \")) {\n return authorizationHeader.slice(7);\n }\n\n return null;\n}\n\nexport const createAuthMiddleware = (t: any) => {\n const isAuthed = t.middleware(async ({ next, ctx }: MiddlewareContext) => {\n const token = getRequestToken(ctx.req.headers);\n\n if (!token) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"Not authenticated - no token found\",\n });\n }\n\n try {\n const user = await findUserBySessionToken(token);\n\n if (!user) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"Invalid or expired session\",\n });\n }\n\n return next({\n ctx: {\n ...ctx,\n user,\n },\n });\n } catch (error) {\n if (error instanceof TRPCError) {\n throw error;\n }\n Sentry.captureException(error);\n console.error(error);\n throw new TRPCError({\n code: \"INTERNAL_SERVER_ERROR\",\n message: \"Internal server error\",\n });\n }\n });\n\n const addComputedFlags = t.middleware(\n async ({ next, ctx }: MiddlewareContext) => {\n if (!ctx.user) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"Not authenticated\",\n });\n }\n\n const teacherClasses = await findTeacherClassesByUserId(ctx.user.id);\n\n return next({\n ctx: {\n ...ctx,\n isTeacher: teacherClasses.length > 0,\n teacherClassIds: teacherClasses.map((c) => c.id),\n },\n });\n }\n );\n\n const isMemberInClass = t.middleware(\n async ({ next, ctx, input }: MiddlewareContext) => {\n if (!ctx.user) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"Not authenticated\",\n });\n }\n\n const classId = (input as { classId: string })?.classId;\n if (!classId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"classId is required\",\n });\n }\n\n const isMember = await findClassWithMember(classId, ctx.user.id);\n if (!isMember) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Not a member in this class\",\n });\n }\n\n return next();\n }\n );\n\n const isTeacherInClass = t.middleware(\n async ({ next, ctx, input }: MiddlewareContext) => {\n if (!ctx.user) {\n throw new TRPCError({\n code: \"UNAUTHORIZED\",\n message: \"Not authenticated\",\n });\n }\n\n const classId = (input as { classId: string })?.classId;\n if (!classId) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"classId is required\",\n });\n }\n\n const isTeacher = await findClassWithTeacher(classId, ctx.user.id);\n if (!isTeacher) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Not a teacher in this class\",\n });\n }\n\n return next();\n }\n );\n\n return {\n isAuthed,\n addComputedFlags,\n isMemberInClass,\n isTeacherInClass,\n };\n};\n"],"names":[],"mappings":"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","debug_id":"ef261406-0c03-5992-af7a-26665f456c05"}
|
package/dist/models/auth.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth model – user lookup, session CRUD, Redis session cache.
|
|
3
|
+
* findUserBySessionToken checks Redis first, then DB.
|
|
4
|
+
*/
|
|
5
|
+
import { SessionType } from "@prisma/client";
|
|
1
6
|
/** @returns User by username (includes password for login). */
|
|
2
7
|
export declare function findUserByUsername(username: string): import(".prisma/client").Prisma.Prisma__UserClient<{
|
|
3
8
|
id: string;
|
|
@@ -83,9 +88,12 @@ export declare function createUser(data: {
|
|
|
83
88
|
/** Create a session. */
|
|
84
89
|
export declare function createSession(data: {
|
|
85
90
|
id: string;
|
|
86
|
-
|
|
91
|
+
type: SessionType;
|
|
87
92
|
expiresAt: Date;
|
|
93
|
+
userId?: string;
|
|
94
|
+
classId?: string;
|
|
88
95
|
}): import(".prisma/client").Prisma.Prisma__SessionClient<{
|
|
96
|
+
type: import(".prisma/client").$Enums.SessionType;
|
|
89
97
|
id: string;
|
|
90
98
|
userId: string | null;
|
|
91
99
|
createdAt: Date | null;
|
|
@@ -100,7 +108,7 @@ export declare function createSession(data: {
|
|
|
100
108
|
}>;
|
|
101
109
|
/** Delete all sessions for user. Invalidates Redis cache. */
|
|
102
110
|
export declare function deleteSessionsByUserId(userId: string): Promise<import(".prisma/client").Prisma.BatchPayload>;
|
|
103
|
-
/** Delete
|
|
111
|
+
/** Delete password reset sessions expiring before date. */
|
|
104
112
|
export declare function deleteShortLivedSessionsByUserId(userId: string, expiresBefore: Date): import(".prisma/client").Prisma.PrismaPromise<import(".prisma/client").Prisma.BatchPayload>;
|
|
105
113
|
/** Delete a user. */
|
|
106
114
|
export declare function deleteUserById(id: string): import(".prisma/client").Prisma.Prisma__UserClient<{
|
|
@@ -118,8 +126,9 @@ export declare function deleteUserById(id: string): import(".prisma/client").Pri
|
|
|
118
126
|
};
|
|
119
127
|
};
|
|
120
128
|
}>;
|
|
121
|
-
/** @returns Session by ID. */
|
|
122
|
-
export declare function
|
|
129
|
+
/** @returns Session by ID and type. */
|
|
130
|
+
export declare function findSessionByIdAndType(id: string, type: SessionType): import(".prisma/client").Prisma.Prisma__SessionClient<{
|
|
131
|
+
type: import(".prisma/client").$Enums.SessionType;
|
|
123
132
|
id: string;
|
|
124
133
|
userId: string | null;
|
|
125
134
|
createdAt: Date | null;
|
|
@@ -132,12 +141,13 @@ export declare function findSessionById(id: string): import(".prisma/client").Pr
|
|
|
132
141
|
};
|
|
133
142
|
};
|
|
134
143
|
}>;
|
|
135
|
-
/** @returns Session with user. */
|
|
136
|
-
export declare function
|
|
144
|
+
/** @returns Session with user by ID and type. */
|
|
145
|
+
export declare function findSessionByIdWithUserAndType(id: string, type: SessionType): import(".prisma/client").Prisma.Prisma__SessionClient<({
|
|
137
146
|
user: {
|
|
138
147
|
id: string;
|
|
139
148
|
} | null;
|
|
140
149
|
} & {
|
|
150
|
+
type: import(".prisma/client").$Enums.SessionType;
|
|
141
151
|
id: string;
|
|
142
152
|
userId: string | null;
|
|
143
153
|
createdAt: Date | null;
|
|
@@ -183,20 +193,15 @@ export declare function updateUserPassword(userId: string, password: string): im
|
|
|
183
193
|
};
|
|
184
194
|
}>;
|
|
185
195
|
/** Delete a session. */
|
|
186
|
-
export declare function deleteSessionById(id: string):
|
|
196
|
+
export declare function deleteSessionById(id: string): Promise<{
|
|
197
|
+
type: import(".prisma/client").$Enums.SessionType;
|
|
187
198
|
id: string;
|
|
188
199
|
userId: string | null;
|
|
189
200
|
createdAt: Date | null;
|
|
190
201
|
expiresAt: Date | null;
|
|
191
202
|
classId: string | null;
|
|
192
|
-
}, never, import("@prisma/client/runtime/library.js").DefaultArgs, {
|
|
193
|
-
datasources: {
|
|
194
|
-
db: {
|
|
195
|
-
url: string;
|
|
196
|
-
};
|
|
197
|
-
};
|
|
198
203
|
}>;
|
|
199
|
-
/** @returns User from session token. Checks Redis first, then DB. Caches in Redis. */
|
|
204
|
+
/** @returns User from valid auth session token. Checks Redis first, then DB. Caches in Redis. */
|
|
200
205
|
export declare function findUserBySessionToken(token: string): Promise<any>;
|
|
201
206
|
/** @returns Class IDs where user is a teacher. */
|
|
202
207
|
export declare function findTeacherClassesByUserId(userId: string): import(".prisma/client").Prisma.PrismaPromise<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"/","sources":["models/auth.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"/","sources":["models/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAmB7C,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM;;;;;;;;;;;;GAWlD;AAED,0CAA0C;AAC1C,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;;;;;;;;;;;GAYxE;AAED,2CAA2C;AAC3C,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM;;;;;;;;;;;;;;;;;GAkB5C;AAED,wCAAwC;AACxC,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;GAkBtC;AAED,wCAAwC;AACxC,wBAAgB,UAAU,CAAC,IAAI,EAAE;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;;;;;;;;;;GAeA;AAED,wBAAwB;AACxB,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;;;;;;;;;;;;;GAIA;AAED,6DAA6D;AAC7D,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,MAAM,yDAU1D;AAED,2DAA2D;AAC3D,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,IAAI,+FASpB;AAED,qBAAqB;AACrB,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;GAIxC;AAED,uCAAuC;AACvC,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW;;;;;;;;;;;;;GAInE;AAED,iDAAiD;AACjD,wBAAgB,8BAA8B,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW;;;;;;;;;;;;;;;;;GAO3E;AAED,gCAAgC;AAChC,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO;;;;;;;;;;;;;;GAKnE;AAED,4BAA4B;AAC5B,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;GAKlE;AAED,wBAAwB;AACxB,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,MAAM;;;;;;;GAKjD;AAED,iGAAiG;AACjG,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,MAAM,gBAqCzD;AAED,kDAAkD;AAClD,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM;;KAOxD;AAED,oDAAoD;AACpD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;;;;;;;;;GAUlE;AAED,2CAA2C;AAC3C,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;;;;;;;;;;;;GAOtE"}
|
package/dist/models/auth.js
CHANGED
|
@@ -3,9 +3,21 @@
|
|
|
3
3
|
* findUserBySessionToken checks Redis first, then DB.
|
|
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]="caa0301d-42ed-55b1-a0ef-383918fe715a")}catch(e){}}();
|
|
7
|
+
import { SessionType } from "@prisma/client";
|
|
7
8
|
import { getRedis } from "../lib/redis.js";
|
|
8
9
|
import { prisma } from "../lib/prisma.js";
|
|
10
|
+
const AUTH_SESSION_CACHE_PREFIX = "auth-session:";
|
|
11
|
+
function getAuthSessionCacheKey(token) {
|
|
12
|
+
return `${AUTH_SESSION_CACHE_PREFIX}${token}`;
|
|
13
|
+
}
|
|
14
|
+
function getSessionTtlSeconds(expiresAt) {
|
|
15
|
+
if (!expiresAt) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const ttlSeconds = Math.floor((expiresAt.getTime() - Date.now()) / 1000);
|
|
19
|
+
return ttlSeconds > 0 ? ttlSeconds : null;
|
|
20
|
+
}
|
|
9
21
|
/** @returns User by username (includes password for login). */
|
|
10
22
|
export function findUserByUsername(username) {
|
|
11
23
|
return prisma.user.findFirst({
|
|
@@ -102,18 +114,18 @@ export async function deleteSessionsByUserId(userId) {
|
|
|
102
114
|
where: { userId },
|
|
103
115
|
});
|
|
104
116
|
for (const session of sessions) {
|
|
105
|
-
await getRedis()?.del(
|
|
117
|
+
await getRedis()?.del(getAuthSessionCacheKey(session.id));
|
|
106
118
|
}
|
|
107
119
|
return prisma.session.deleteMany({
|
|
108
120
|
where: { userId },
|
|
109
121
|
});
|
|
110
122
|
}
|
|
111
|
-
/** Delete
|
|
123
|
+
/** Delete password reset sessions expiring before date. */
|
|
112
124
|
export function deleteShortLivedSessionsByUserId(userId, expiresBefore) {
|
|
113
125
|
return prisma.session.deleteMany({
|
|
114
126
|
where: {
|
|
115
127
|
userId,
|
|
116
|
-
|
|
128
|
+
type: SessionType.PASSWORD_RESET,
|
|
117
129
|
expiresAt: { lte: expiresBefore },
|
|
118
130
|
},
|
|
119
131
|
});
|
|
@@ -124,16 +136,16 @@ export function deleteUserById(id) {
|
|
|
124
136
|
where: { id },
|
|
125
137
|
});
|
|
126
138
|
}
|
|
127
|
-
/** @returns Session by ID. */
|
|
128
|
-
export function
|
|
129
|
-
return prisma.session.
|
|
130
|
-
where: { id },
|
|
139
|
+
/** @returns Session by ID and type. */
|
|
140
|
+
export function findSessionByIdAndType(id, type) {
|
|
141
|
+
return prisma.session.findFirst({
|
|
142
|
+
where: { id, type },
|
|
131
143
|
});
|
|
132
144
|
}
|
|
133
|
-
/** @returns Session with user. */
|
|
134
|
-
export function
|
|
135
|
-
return prisma.session.
|
|
136
|
-
where: { id },
|
|
145
|
+
/** @returns Session with user by ID and type. */
|
|
146
|
+
export function findSessionByIdWithUserAndType(id, type) {
|
|
147
|
+
return prisma.session.findFirst({
|
|
148
|
+
where: { id, type },
|
|
137
149
|
include: {
|
|
138
150
|
user: { select: { id: true } },
|
|
139
151
|
},
|
|
@@ -154,34 +166,45 @@ export function updateUserPassword(userId, password) {
|
|
|
154
166
|
});
|
|
155
167
|
}
|
|
156
168
|
/** Delete a session. */
|
|
157
|
-
export function deleteSessionById(id) {
|
|
169
|
+
export async function deleteSessionById(id) {
|
|
170
|
+
await getRedis()?.del(getAuthSessionCacheKey(id));
|
|
158
171
|
return prisma.session.delete({
|
|
159
172
|
where: { id },
|
|
160
173
|
});
|
|
161
174
|
}
|
|
162
|
-
/** @returns User from session token. Checks Redis first, then DB. Caches in Redis. */
|
|
175
|
+
/** @returns User from valid auth session token. Checks Redis first, then DB. Caches in Redis. */
|
|
163
176
|
export async function findUserBySessionToken(token) {
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
177
|
+
const cacheKey = getAuthSessionCacheKey(token);
|
|
178
|
+
const cachedUser = await getRedis()?.get(cacheKey);
|
|
179
|
+
if (cachedUser) {
|
|
180
|
+
return JSON.parse(cachedUser);
|
|
181
|
+
}
|
|
182
|
+
const session = await prisma.session.findFirst({
|
|
168
183
|
where: {
|
|
169
|
-
|
|
184
|
+
id: token,
|
|
185
|
+
type: SessionType.AUTH,
|
|
186
|
+
userId: { not: null },
|
|
187
|
+
expiresAt: { gt: new Date() },
|
|
170
188
|
},
|
|
171
189
|
select: {
|
|
172
|
-
|
|
173
|
-
|
|
190
|
+
expiresAt: true,
|
|
191
|
+
user: {
|
|
192
|
+
select: {
|
|
193
|
+
id: true,
|
|
194
|
+
username: true,
|
|
195
|
+
},
|
|
196
|
+
},
|
|
174
197
|
},
|
|
175
198
|
});
|
|
176
|
-
if (user) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
199
|
+
if (!session?.user) {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
const ttlSeconds = getSessionTtlSeconds(session.expiresAt);
|
|
203
|
+
const r = getRedis();
|
|
204
|
+
if (r && ttlSeconds) {
|
|
205
|
+
await r.setex(cacheKey, ttlSeconds, JSON.stringify(session.user));
|
|
183
206
|
}
|
|
184
|
-
return
|
|
207
|
+
return session.user;
|
|
185
208
|
}
|
|
186
209
|
/** @returns Class IDs where user is a teacher. */
|
|
187
210
|
export function findTeacherClassesByUserId(userId) {
|
|
@@ -214,4 +237,4 @@ export function findClassWithTeacher(classId, teacherId) {
|
|
|
214
237
|
});
|
|
215
238
|
}
|
|
216
239
|
//# sourceMappingURL=auth.js.map
|
|
217
|
-
//# debugId=
|
|
240
|
+
//# debugId=caa0301d-42ed-55b1-a0ef-383918fe715a
|
package/dist/models/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sources":["models/auth.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Auth model – user lookup, session CRUD, Redis session cache.\n * findUserBySessionToken checks Redis first, then DB.\n */\nimport { getRedis } from \"../lib/redis.js\";\nimport { prisma } from \"../lib/prisma.js\";\n\n/** @returns User by username (includes password for login). */\nexport function findUserByUsername(username: string) {\n return prisma.user.findFirst({\n where: { username },\n select: {\n id: true,\n username: true,\n password: true,\n email: true,\n verified: true,\n },\n });\n}\n\n/** @returns User by username or email. */\nexport function findUserByUsernameOrEmail(username: string, email: string) {\n return prisma.user.findFirst({\n where: {\n OR: [{ username }, { email }],\n },\n select: {\n id: true,\n username: true,\n email: true,\n verified: true,\n },\n });\n}\n\n/** @returns User by email with profile. */\nexport function findUserByEmail(email: string) {\n return prisma.user.findFirst({\n where: { email },\n select: {\n id: true,\n email: true,\n role: true,\n profile: {\n select: {\n displayName: true,\n bio: true,\n location: true,\n website: true,\n profilePicture: true,\n },\n },\n },\n });\n}\n\n/** @returns User by ID with profile. */\nexport function findUserById(id: string) {\n return prisma.user.findUnique({\n where: { id },\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n bio: true,\n location: true,\n website: true,\n profilePicture: true,\n profilePictureThumbnail: true,\n },\n },\n },\n });\n}\n\n/** Create a user with empty profile. */\nexport function createUser(data: {\n username: string;\n email: string;\n password: string;\n verified?: boolean;\n}) {\n return prisma.user.create({\n data: {\n username: data.username,\n email: data.email,\n password: data.password,\n verified: data.verified ?? false,\n profile: { create: {} },\n },\n select: {\n id: true,\n username: true,\n email: true,\n },\n });\n}\n\n/** Create a session. */\nexport function createSession(data: {\n id: string;\n userId: string;\n expiresAt: Date;\n}) {\n return prisma.session.create({\n data,\n });\n}\n\n/** Delete all sessions for user. Invalidates Redis cache. */\nexport async function deleteSessionsByUserId(userId: string) {\n const sessions = await prisma.session.findMany({\n where: { userId },\n });\n for (const session of sessions) {\n await getRedis()?.del(`session:${session.id}`);\n }\n return prisma.session.deleteMany({\n where: { userId },\n });\n}\n\n/** Delete short-lived sessions (no classId) expiring before date. */\nexport function deleteShortLivedSessionsByUserId(\n userId: string,\n expiresBefore: Date\n) {\n return prisma.session.deleteMany({\n where: {\n userId,\n classId: null,\n expiresAt: { lte: expiresBefore },\n },\n });\n}\n\n/** Delete a user. */\nexport function deleteUserById(id: string) {\n return prisma.user.delete({\n where: { id },\n });\n}\n\n/** @returns Session by ID. */\nexport function findSessionById(id: string) {\n return prisma.session.findUnique({\n where: { id },\n });\n}\n\n/** @returns Session with user. */\nexport function findSessionByIdWithUser(id: string) {\n return prisma.session.findUnique({\n where: { id },\n include: {\n user: { select: { id: true } },\n },\n });\n}\n\n/** Set user verified status. */\nexport function updateUserVerified(userId: string, verified: boolean) {\n return prisma.user.update({\n where: { id: userId },\n data: { verified },\n });\n}\n\n/** Update user password. */\nexport function updateUserPassword(userId: string, password: string) {\n return prisma.user.update({\n where: { id: userId },\n data: { password },\n });\n}\n\n/** Delete a session. */\nexport function deleteSessionById(id: string) {\n return prisma.session.delete({\n where: { id },\n });\n}\n\n/** @returns User from session token. Checks Redis first, then DB. Caches in Redis. */\nexport async function findUserBySessionToken(token: string) {\n const session = await getRedis()?.get(`session:${token}`);\n\n if (session)\n return JSON.parse(session);\n\n const user = await prisma.user.findFirst({\n where: {\n sessions: { some: { id: token } },\n },\n select: {\n id: true,\n username: true,\n },\n });\n\n if (user) {\n const r = getRedis();\n if (r) {\n const ttlSeconds = 30 * 24 * 60 * 60; // 30 days, match session expiry\n await r.setex(`session:${token}`, ttlSeconds, JSON.stringify(user));\n }\n return user;\n }\n\n return null;\n}\n\n/** @returns Class IDs where user is a teacher. */\nexport function findTeacherClassesByUserId(userId: string) {\n return prisma.class.findMany({\n where: {\n teachers: { some: { id: userId } },\n },\n select: { id: true },\n });\n}\n\n/** @returns Class if user is student or teacher. */\nexport function findClassWithMember(classId: string, userId: string) {\n return prisma.class.findFirst({\n where: {\n id: classId,\n OR: [\n { students: { some: { id: userId } } },\n { teachers: { some: { id: userId } } },\n ],\n },\n });\n}\n\n/** @returns Class if user is a teacher. */\nexport function findClassWithTeacher(classId: string, teacherId: string) {\n return prisma.class.findFirst({\n where: {\n id: classId,\n teachers: { some: { id: teacherId } },\n },\n });\n}\n"],"names":[],"mappings":"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","debug_id":"807b5838-7465-59d7-9c89-4d5177b75a3c"}
|
|
1
|
+
{"version":3,"file":"auth.js","sources":["models/auth.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Auth model – user lookup, session CRUD, Redis session cache.\n * findUserBySessionToken checks Redis first, then DB.\n */\nimport { SessionType } from \"@prisma/client\";\nimport { getRedis } from \"../lib/redis.js\";\nimport { prisma } from \"../lib/prisma.js\";\n\nconst AUTH_SESSION_CACHE_PREFIX = \"auth-session:\";\n\nfunction getAuthSessionCacheKey(token: string) {\n return `${AUTH_SESSION_CACHE_PREFIX}${token}`;\n}\n\nfunction getSessionTtlSeconds(expiresAt?: Date | null) {\n if (!expiresAt) {\n return null;\n }\n\n const ttlSeconds = Math.floor((expiresAt.getTime() - Date.now()) / 1000);\n return ttlSeconds > 0 ? ttlSeconds : null;\n}\n\n/** @returns User by username (includes password for login). */\nexport function findUserByUsername(username: string) {\n return prisma.user.findFirst({\n where: { username },\n select: {\n id: true,\n username: true,\n password: true,\n email: true,\n verified: true,\n },\n });\n}\n\n/** @returns User by username or email. */\nexport function findUserByUsernameOrEmail(username: string, email: string) {\n return prisma.user.findFirst({\n where: {\n OR: [{ username }, { email }],\n },\n select: {\n id: true,\n username: true,\n email: true,\n verified: true,\n },\n });\n}\n\n/** @returns User by email with profile. */\nexport function findUserByEmail(email: string) {\n return prisma.user.findFirst({\n where: { email },\n select: {\n id: true,\n email: true,\n role: true,\n profile: {\n select: {\n displayName: true,\n bio: true,\n location: true,\n website: true,\n profilePicture: true,\n },\n },\n },\n });\n}\n\n/** @returns User by ID with profile. */\nexport function findUserById(id: string) {\n return prisma.user.findUnique({\n where: { id },\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n bio: true,\n location: true,\n website: true,\n profilePicture: true,\n profilePictureThumbnail: true,\n },\n },\n },\n });\n}\n\n/** Create a user with empty profile. */\nexport function createUser(data: {\n username: string;\n email: string;\n password: string;\n verified?: boolean;\n}) {\n return prisma.user.create({\n data: {\n username: data.username,\n email: data.email,\n password: data.password,\n verified: data.verified ?? false,\n profile: { create: {} },\n },\n select: {\n id: true,\n username: true,\n email: true,\n },\n });\n}\n\n/** Create a session. */\nexport function createSession(data: {\n id: string;\n type: SessionType;\n expiresAt: Date;\n userId?: string;\n classId?: string;\n}) {\n return prisma.session.create({\n data,\n });\n}\n\n/** Delete all sessions for user. Invalidates Redis cache. */\nexport async function deleteSessionsByUserId(userId: string) {\n const sessions = await prisma.session.findMany({\n where: { userId },\n });\n for (const session of sessions) {\n await getRedis()?.del(getAuthSessionCacheKey(session.id));\n }\n return prisma.session.deleteMany({\n where: { userId },\n });\n}\n\n/** Delete password reset sessions expiring before date. */\nexport function deleteShortLivedSessionsByUserId(\n userId: string,\n expiresBefore: Date\n) {\n return prisma.session.deleteMany({\n where: {\n userId,\n type: SessionType.PASSWORD_RESET,\n expiresAt: { lte: expiresBefore },\n },\n });\n}\n\n/** Delete a user. */\nexport function deleteUserById(id: string) {\n return prisma.user.delete({\n where: { id },\n });\n}\n\n/** @returns Session by ID and type. */\nexport function findSessionByIdAndType(id: string, type: SessionType) {\n return prisma.session.findFirst({\n where: { id, type },\n });\n}\n\n/** @returns Session with user by ID and type. */\nexport function findSessionByIdWithUserAndType(id: string, type: SessionType) {\n return prisma.session.findFirst({\n where: { id, type },\n include: {\n user: { select: { id: true } },\n },\n });\n}\n\n/** Set user verified status. */\nexport function updateUserVerified(userId: string, verified: boolean) {\n return prisma.user.update({\n where: { id: userId },\n data: { verified },\n });\n}\n\n/** Update user password. */\nexport function updateUserPassword(userId: string, password: string) {\n return prisma.user.update({\n where: { id: userId },\n data: { password },\n });\n}\n\n/** Delete a session. */\nexport async function deleteSessionById(id: string) {\n await getRedis()?.del(getAuthSessionCacheKey(id));\n return prisma.session.delete({\n where: { id },\n });\n}\n\n/** @returns User from valid auth session token. Checks Redis first, then DB. Caches in Redis. */\nexport async function findUserBySessionToken(token: string) {\n const cacheKey = getAuthSessionCacheKey(token);\n const cachedUser = await getRedis()?.get(cacheKey);\n\n if (cachedUser) {\n return JSON.parse(cachedUser);\n }\n\n const session = await prisma.session.findFirst({\n where: {\n id: token,\n type: SessionType.AUTH,\n userId: { not: null },\n expiresAt: { gt: new Date() },\n },\n select: {\n expiresAt: true,\n user: {\n select: {\n id: true,\n username: true,\n },\n },\n },\n });\n\n if (!session?.user) {\n return null;\n }\n\n const ttlSeconds = getSessionTtlSeconds(session.expiresAt);\n const r = getRedis();\n if (r && ttlSeconds) {\n await r.setex(cacheKey, ttlSeconds, JSON.stringify(session.user));\n }\n\n return session.user;\n}\n\n/** @returns Class IDs where user is a teacher. */\nexport function findTeacherClassesByUserId(userId: string) {\n return prisma.class.findMany({\n where: {\n teachers: { some: { id: userId } },\n },\n select: { id: true },\n });\n}\n\n/** @returns Class if user is student or teacher. */\nexport function findClassWithMember(classId: string, userId: string) {\n return prisma.class.findFirst({\n where: {\n id: classId,\n OR: [\n { students: { some: { id: userId } } },\n { teachers: { some: { id: userId } } },\n ],\n },\n });\n}\n\n/** @returns Class if user is a teacher. */\nexport function findClassWithTeacher(classId: string, teacherId: string) {\n return prisma.class.findFirst({\n where: {\n id: classId,\n teachers: { some: { id: teacherId } },\n },\n });\n}\n"],"names":[],"mappings":"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","debug_id":"caa0301d-42ed-55b1-a0ef-383918fe715a"}
|
package/dist/models/class.d.ts
CHANGED
|
@@ -214,6 +214,7 @@ export declare function findUserById(userId: string): import(".prisma/client").P
|
|
|
214
214
|
}>;
|
|
215
215
|
/** @returns Session by class invite code. */
|
|
216
216
|
export declare function findSessionByClassCode(classCode: string): import(".prisma/client").Prisma.Prisma__SessionClient<{
|
|
217
|
+
type: import(".prisma/client").$Enums.SessionType;
|
|
217
218
|
id: string;
|
|
218
219
|
userId: string | null;
|
|
219
220
|
createdAt: Date | null;
|
|
@@ -228,6 +229,7 @@ export declare function findSessionByClassCode(classCode: string): import(".pris
|
|
|
228
229
|
}>;
|
|
229
230
|
/** @returns Session for a class. */
|
|
230
231
|
export declare function findSessionByClassId(classId: string): import(".prisma/client").Prisma.Prisma__SessionClient<{
|
|
232
|
+
type: import(".prisma/client").$Enums.SessionType;
|
|
231
233
|
id: string;
|
|
232
234
|
userId: string | null;
|
|
233
235
|
createdAt: Date | null;
|
|
@@ -475,8 +477,8 @@ export declare function findFullExportableClass(classId: string): Promise<{
|
|
|
475
477
|
id: string;
|
|
476
478
|
classId: string;
|
|
477
479
|
questions: {
|
|
478
|
-
options: import("@prisma/client/runtime/library.js").JsonValue;
|
|
479
480
|
type: import(".prisma/client").$Enums.WorksheetQuestionType;
|
|
481
|
+
options: import("@prisma/client/runtime/library.js").JsonValue;
|
|
480
482
|
order: number | null;
|
|
481
483
|
points: number;
|
|
482
484
|
worksheetId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"class.d.ts","sourceRoot":"/","sources":["models/class.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH,OAAO,EAAc,KAAK,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"class.d.ts","sourceRoot":"/","sources":["models/class.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH,OAAO,EAAc,KAAK,EAAE,MAAM,EAAgE,MAAM,gBAAgB,CAAC;AAgDzH,gDAAgD;AAChD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAKhD;AAED,gDAAgD;AAChD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAKhD;AAED,2CAA2C;AAC3C,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;;;;;;;;;GAO/D;AAsHD,qFAAqF;AACrF,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CjD;AAED,sCAAsC;AACtC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM;;;;;;;;;;;;;;GAIjD;AAED,qCAAqC;AACrC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM;;;;;;KAIpD;AAED,+CAA+C;AAC/C,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM;;;;;;;;;GAK1C;AAED,6CAA6C;AAC7C,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM;;;;;;;;;;;;;GAOvD;AAED,oCAAoC;AACpC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM;;;;;;;;;;;;;GAInD;AAED,gEAAgE;AAChE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAsBvE;AAED,mCAAmC;AACnC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM;;;;KAKlD;AAED,yCAAyC;AACzC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM;;;;KAIvD;AAED,+CAA+C;AAC/C,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,MAAM;;;;KAI7D;AAED,+BAA+B;AAC/B,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM;;;;;;;;GAKhD;AAED,qDAAqD;AACrD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;KAStE;AAED,6DAA6D;AAC7D,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAiDvD;AAoGD,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAoF5D;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,GAAG;IAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA6HjK"}
|
package/dist/models/class.js
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* grading boundaries, syllabus, lab drafts, invite codes.
|
|
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]="f92cda2a-2ce2-5da3-914b-24deba15bc61")}catch(e){}}();
|
|
7
|
+
import { SessionType } from "@prisma/client";
|
|
7
8
|
import { prisma } from "../lib/prisma.js";
|
|
8
9
|
import { v4 as uuidv4 } from 'uuid';
|
|
9
10
|
import { copyFile } from "../lib/googleCloudStorage.js";
|
|
@@ -198,8 +199,18 @@ export function findClassWithAssignments(classId, options) {
|
|
|
198
199
|
const submissionWhere = !options.isTeacher && options.userId
|
|
199
200
|
? { studentId: options.userId }
|
|
200
201
|
: undefined;
|
|
201
|
-
return prisma.class.
|
|
202
|
-
where: {
|
|
202
|
+
return prisma.class.findFirst({
|
|
203
|
+
where: {
|
|
204
|
+
id: classId,
|
|
205
|
+
...(options.userId
|
|
206
|
+
? {
|
|
207
|
+
OR: [
|
|
208
|
+
{ students: { some: { id: options.userId } } },
|
|
209
|
+
{ teachers: { some: { id: options.userId } } },
|
|
210
|
+
],
|
|
211
|
+
}
|
|
212
|
+
: {}),
|
|
213
|
+
},
|
|
203
214
|
include: {
|
|
204
215
|
teachers: classIncludeForGet.teachers,
|
|
205
216
|
students: classIncludeForGet.students,
|
|
@@ -241,6 +252,7 @@ export function findSessionByClassCode(classCode) {
|
|
|
241
252
|
return prisma.session.findFirst({
|
|
242
253
|
where: {
|
|
243
254
|
id: { equals: classCode, mode: "insensitive" },
|
|
255
|
+
type: SessionType.CLASS_INVITE,
|
|
244
256
|
},
|
|
245
257
|
});
|
|
246
258
|
}
|
|
@@ -642,4 +654,4 @@ export async function createClassByImport(classId, userId, year, classData) {
|
|
|
642
654
|
return newClassId;
|
|
643
655
|
}
|
|
644
656
|
//# sourceMappingURL=class.js.map
|
|
645
|
-
//# debugId=
|
|
657
|
+
//# debugId=f92cda2a-2ce2-5da3-914b-24deba15bc61
|