@studious-lms/server 1.4.7 → 1.5.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/.github/workflows/npm.yml +28 -0
- package/dist/lib/config/cors.d.ts.map +1 -1
- package/dist/lib/config/cors.js +2 -4
- package/dist/lib/config/cors.js.map +1 -1
- package/dist/lib/fileUpload.d.ts.map +1 -1
- package/dist/lib/fileUpload.js +4 -5
- package/dist/lib/fileUpload.js.map +1 -1
- package/dist/models/assignment.d.ts +32 -0
- package/dist/models/assignment.d.ts.map +1 -1
- package/dist/models/assignment.js +111 -2
- package/dist/models/assignment.js.map +1 -1
- package/dist/models/auth.d.ts +1 -0
- package/dist/models/auth.d.ts.map +1 -1
- package/dist/models/auth.js +3 -2
- package/dist/models/auth.js.map +1 -1
- package/dist/models/comment.d.ts +0 -5
- package/dist/models/comment.d.ts.map +1 -1
- package/dist/models/conversation.d.ts +2 -1
- package/dist/models/conversation.d.ts.map +1 -1
- package/dist/models/labChat.d.ts +2 -1
- package/dist/models/labChat.d.ts.map +1 -1
- package/dist/models/message.d.ts +6 -3
- package/dist/models/message.d.ts.map +1 -1
- package/dist/models/school.d.ts +0 -22
- package/dist/models/school.d.ts.map +1 -1
- package/dist/models/school.js +2 -14
- package/dist/models/school.js.map +1 -1
- package/dist/models/worksheet.d.ts +174 -95
- package/dist/models/worksheet.d.ts.map +1 -1
- package/dist/models/worksheet.js +38 -5
- package/dist/models/worksheet.js.map +1 -1
- package/dist/pipelines/aiLabChat.js +6 -6
- package/dist/pipelines/aiLabChat.js.map +1 -1
- package/dist/pipelines/gradeWorksheet.d.ts +5 -3
- package/dist/pipelines/gradeWorksheet.d.ts.map +1 -1
- package/dist/pipelines/gradeWorksheet.js +60 -24
- package/dist/pipelines/gradeWorksheet.js.map +1 -1
- package/dist/pipelines/pdfToWorksheet.d.ts +3 -0
- package/dist/pipelines/pdfToWorksheet.d.ts.map +1 -1
- package/dist/pipelines/pdfToWorksheet.js +65 -24
- package/dist/pipelines/pdfToWorksheet.js.map +1 -1
- package/dist/routers/_app.d.ts +232 -48
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/announcement.d.ts +0 -4
- package/dist/routers/announcement.d.ts.map +1 -1
- package/dist/routers/assignment.d.ts +35 -8
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/assignment.js +10 -3
- package/dist/routers/assignment.js.map +1 -1
- package/dist/routers/auth.d.ts +1 -0
- package/dist/routers/auth.d.ts.map +1 -1
- package/dist/routers/class.d.ts +19 -0
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/comment.d.ts +0 -3
- package/dist/routers/comment.d.ts.map +1 -1
- package/dist/routers/conversation.d.ts +2 -1
- package/dist/routers/conversation.d.ts.map +1 -1
- package/dist/routers/labChat.d.ts +2 -1
- package/dist/routers/labChat.d.ts.map +1 -1
- package/dist/routers/school.d.ts +6 -0
- package/dist/routers/school.d.ts.map +1 -1
- package/dist/routers/school.js +7 -2
- package/dist/routers/school.js.map +1 -1
- package/dist/routers/worksheet.d.ts +51 -7
- package/dist/routers/worksheet.d.ts.map +1 -1
- package/dist/routers/worksheet.js +10 -3
- package/dist/routers/worksheet.js.map +1 -1
- package/dist/services/assignment.d.ts +30 -0
- package/dist/services/assignment.d.ts.map +1 -1
- package/dist/services/assignment.js +37 -3
- package/dist/services/assignment.js.map +1 -1
- package/dist/services/auth.d.ts +1 -0
- package/dist/services/auth.d.ts.map +1 -1
- package/dist/services/class.d.ts +19 -0
- package/dist/services/class.d.ts.map +1 -1
- package/dist/services/class.js +37 -19
- package/dist/services/class.js.map +1 -1
- package/dist/services/comment.d.ts +0 -3
- package/dist/services/comment.d.ts.map +1 -1
- package/dist/services/conversation.d.ts +2 -1
- package/dist/services/conversation.d.ts.map +1 -1
- package/dist/services/labChat.d.ts +2 -1
- package/dist/services/labChat.d.ts.map +1 -1
- package/dist/services/labChat.js +6 -6
- package/dist/services/labChat.js.map +1 -1
- package/dist/services/message.d.ts.map +1 -1
- package/dist/services/message.js +14 -2
- package/dist/services/message.js.map +1 -1
- package/dist/services/school.d.ts +6 -0
- package/dist/services/school.d.ts.map +1 -1
- package/dist/services/school.js +71 -6
- package/dist/services/school.js.map +1 -1
- package/dist/services/worksheet.d.ts +46 -7
- package/dist/services/worksheet.d.ts.map +1 -1
- package/dist/services/worksheet.js +52 -20
- package/dist/services/worksheet.js.map +1 -1
- package/dist/utils/generateUsername.d.ts +8 -0
- package/dist/utils/generateUsername.d.ts.map +1 -0
- package/dist/utils/generateUsername.js +103 -0
- package/dist/utils/generateUsername.js.map +1 -0
- package/dist/workers/connection.d.ts +3 -0
- package/dist/workers/connection.d.ts.map +1 -0
- package/dist/workers/connection.js +33 -0
- package/dist/workers/connection.js.map +1 -0
- package/dist/workers/index.d.ts +10 -0
- package/dist/workers/index.d.ts.map +1 -0
- package/dist/workers/index.js +53 -0
- package/dist/workers/index.js.map +1 -0
- package/dist/workers/processors/pdfToWorksheet.d.ts +9 -0
- package/dist/workers/processors/pdfToWorksheet.d.ts.map +1 -0
- package/dist/workers/processors/pdfToWorksheet.js +100 -0
- package/dist/workers/processors/pdfToWorksheet.js.map +1 -0
- package/dist/workers/queues.d.ts +69 -0
- package/dist/workers/queues.d.ts.map +1 -0
- package/dist/workers/queues.js +119 -0
- package/dist/workers/queues.js.map +1 -0
- package/package.json +4 -1
- package/prisma/migrations/20260504071500_school_memberships/migration.sql +1 -1
- package/prisma/migrations/20260506162500_consolidate_run_job_and_unify_job_status/migration.sql +166 -0
- package/prisma/schema.prisma +465 -387
- package/src/lib/config/cors.ts +0 -2
- package/src/lib/fileUpload.ts +2 -4
- package/src/models/assignment.ts +132 -0
- package/src/models/auth.ts +1 -0
- package/src/models/school.ts +0 -14
- package/src/models/worksheet.ts +56 -2
- package/src/pipelines/aiLabChat.ts +4 -4
- package/src/pipelines/gradeWorksheet.ts +63 -25
- package/src/pipelines/pdfToWorksheet.ts +68 -22
- package/src/routers/assignment.ts +19 -0
- package/src/routers/school.ts +5 -0
- package/src/routers/worksheet.ts +18 -0
- package/src/services/assignment.ts +47 -1
- package/src/services/class.ts +41 -17
- package/src/services/labChat.ts +4 -4
- package/src/services/message.ts +13 -0
- package/src/services/school.ts +89 -6
- package/src/services/worksheet.ts +62 -18
- package/src/utils/generateUsername.ts +108 -0
- package/src/workers/connection.ts +37 -0
- package/src/workers/index.ts +61 -0
- package/src/workers/processors/pdfToWorksheet.ts +119 -0
- package/src/workers/queues.ts +159 -0
- package/tests/{globalSetup.ts → integration/globalSetup.ts} +4 -4
- package/tests/{helpers.ts → integration/helpers.ts} +2 -2
- package/tests/{pipelines → integration/pipelines}/pdfToWorksheet.test.ts +55 -43
- package/tests/{routers → integration/routers}/attendance.test.ts +1 -1
- package/tests/{routers → integration/routers}/auth.test.ts +3 -3
- package/tests/{routers → integration/routers}/class.test.ts +3 -17
- package/tests/{routers → integration/routers}/conversation.test.ts +1 -1
- package/tests/{routers → integration/routers}/event.test.ts +1 -1
- package/tests/{routers → integration/routers}/message.test.ts +1 -1
- package/tests/{routers → integration/routers}/newtonChat.test.ts +1 -1
- package/tests/{routers → integration/routers}/studentProgress.test.ts +1 -1
- package/tests/{user.test.ts → integration/routers/user.test.ts} +2 -2
- package/tests/integration/routers/worksheet.test.ts +448 -0
- package/tests/{setup.ts → integration/setup.ts} +4 -4
- package/tests/{lib → unit/lib}/cors.test.ts +1 -1
- package/tests/{middleware → unit/middleware}/security.test.ts +1 -1
- package/tests/{pipelines → unit/pipelines}/aiLabChat.test.ts +1 -1
- package/tests/{lib → unit/pipelines}/aiLabChatContract.test.ts +1 -1
- package/tests/{utils/aiLabChatPrompt.test.ts → unit/pipelines/labChatPrompt.test.ts} +2 -2
- package/tests/{utils → unit/services}/studentProgress.test.ts +5 -5
- package/tests/{utils → unit/utils}/aiUser.test.ts +1 -1
- package/tests/{utils → unit/utils}/generateInviteCode.test.ts +1 -1
- package/tests/{utils → unit/utils}/inference.test.ts +6 -6
- package/tests/{utils → unit/utils}/logger.test.ts +1 -1
- package/tests/{utils → unit/utils}/prismaErrorHandler.test.ts +1 -1
- package/tests/{utils → unit/utils}/prismaWrapper.test.ts +1 -1
- package/vitest.config.ts +11 -3
- package/vitest.unit.config.ts +10 -10
- package/dist/lib/notificationHandler.d.ts +0 -25
- package/dist/lib/notificationHandler.d.ts.map +0 -1
- package/dist/lib/notificationHandler.js +0 -32
- package/dist/lib/notificationHandler.js.map +0 -1
- package/dist/server/pipelines/aiLabChat.d.ts +0 -21
- package/dist/server/pipelines/aiLabChat.d.ts.map +0 -1
- package/dist/server/pipelines/aiLabChat.js +0 -456
- package/dist/server/pipelines/aiLabChat.js.map +0 -1
- package/dist/server/pipelines/aiNewtonChat.d.ts +0 -30
- package/dist/server/pipelines/aiNewtonChat.d.ts.map +0 -1
- package/dist/server/pipelines/aiNewtonChat.js +0 -285
- package/dist/server/pipelines/aiNewtonChat.js.map +0 -1
- package/dist/server/pipelines/gradeWorksheet.d.ts +0 -30
- package/dist/server/pipelines/gradeWorksheet.d.ts.map +0 -1
- package/dist/server/pipelines/gradeWorksheet.js +0 -248
- package/dist/server/pipelines/gradeWorksheet.js.map +0 -1
- package/tests/routers/worksheet.test.ts +0 -194
- package/tests/startup.test.ts +0 -5
- package/tests/worksheet.test.ts +0 -181
- /package/tests/{routers → integration/routers}/agenda.test.ts +0 -0
- /package/tests/{routers → integration/routers}/announcement.test.ts +0 -0
- /package/tests/{routers → integration/routers}/assignment.test.ts +0 -0
- /package/tests/{routers → integration/routers}/comment.test.ts +0 -0
- /package/tests/{routers → integration/routers}/folder.test.ts +0 -0
- /package/tests/{routers → integration/routers}/labChat.test.ts +0 -0
- /package/tests/{routers → integration/routers}/marketing.test.ts +0 -0
- /package/tests/{routers → integration/routers}/notification.test.ts +0 -0
- /package/tests/{routers → integration/routers}/search.test.ts +0 -0
- /package/tests/{routers → integration/routers}/section.test.ts +0 -0
- /package/tests/{server → unit/middleware}/rateLimit.test.ts +0 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Publish Package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
id-token: write # Required for OIDC / npm provenance
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
publish:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
env:
|
|
16
|
+
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v6
|
|
19
|
+
|
|
20
|
+
- uses: actions/setup-node@v6
|
|
21
|
+
with:
|
|
22
|
+
node-version: '24'
|
|
23
|
+
registry-url: 'https://registry.npmjs.org'
|
|
24
|
+
package-manager-cache: false # never use caching in release builds
|
|
25
|
+
|
|
26
|
+
- run: npm ci
|
|
27
|
+
- run: npm run build --if-present
|
|
28
|
+
- run: npm publish --access public
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cors.d.ts","sourceRoot":"/","sources":["lib/config/cors.ts"],"names":[],"mappings":"AAAA,KAAK,OAAO,GAAG;IACb,QAAQ,CAAC,EAAE,aAAa,GAAG,YAAY,GAAG,MAAM,CAAC;IACjD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,4BAA4B,CAAC,EAAE,MAAM,CAAC;CACvC,CAAC;
|
|
1
|
+
{"version":3,"file":"cors.d.ts","sourceRoot":"/","sources":["lib/config/cors.ts"],"names":[],"mappings":"AAAA,KAAK,OAAO,GAAG;IACb,QAAQ,CAAC,EAAE,aAAa,GAAG,YAAY,GAAG,MAAM,CAAC;IACjD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,4BAA4B,CAAC,EAAE,MAAM,CAAC;CACvC,CAAC;AAuCF,eAAO,MAAM,gBAAgB,GAAI,UAAU,MAAM,aACX,CAAC;AAiBvC,eAAO,MAAM,uBAAuB,GAAI,WAAW,MAAM,aAC6B,CAAC;AAEvF,eAAO,MAAM,4BAA4B,GAAI,WAAW,MAAM,YAO7D,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,KAAK,OAAO;;;+BAYhB,MAAM;CAczC,CAAC"}
|
package/dist/lib/config/cors.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
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]="672f131c-9cfe-50db-bd9a-c2a57fa5ceef")}catch(e){}}();
|
|
3
3
|
const productionOrigins = [
|
|
4
4
|
'https://www.studious.sh',
|
|
5
5
|
'https://studious.sh',
|
|
6
|
-
'https://dev.studious.sh',
|
|
7
|
-
'https://www.dev.studious.sh',
|
|
8
6
|
];
|
|
9
7
|
const nonProductionOrigins = [
|
|
10
8
|
'http://localhost:3000',
|
|
@@ -77,4 +75,4 @@ export const createCorsOriginMatcher = (env) => {
|
|
|
77
75
|
};
|
|
78
76
|
};
|
|
79
77
|
//# sourceMappingURL=cors.js.map
|
|
80
|
-
//# debugId=
|
|
78
|
+
//# debugId=672f131c-9cfe-50db-bd9a-c2a57fa5ceef
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cors.js","sources":["lib/config/cors.ts"],"sourceRoot":"/","sourcesContent":["type CorsEnv = {\n NODE_ENV?: 'development' | 'production' | 'test';\n NEXT_PUBLIC_APP_URL?: string;\n CORS_ALLOWED_ORIGINS?: string;\n CORS_ALLOWED_ORIGIN_PATTERNS?: string;\n};\n\nconst productionOrigins = [\n 'https://www.studious.sh',\n 'https://studious.sh',\n
|
|
1
|
+
{"version":3,"file":"cors.js","sources":["lib/config/cors.ts"],"sourceRoot":"/","sourcesContent":["type CorsEnv = {\n NODE_ENV?: 'development' | 'production' | 'test';\n NEXT_PUBLIC_APP_URL?: string;\n CORS_ALLOWED_ORIGINS?: string;\n CORS_ALLOWED_ORIGIN_PATTERNS?: string;\n};\n\nconst productionOrigins = [\n 'https://www.studious.sh',\n 'https://studious.sh',\n];\n\nconst nonProductionOrigins = [\n 'http://localhost:3000',\n 'http://localhost:3001',\n 'http://127.0.0.1:3000',\n 'http://127.0.0.1:3001',\n];\n\n/** Any preview / prod deployment on *.vercel.app (HTTPS only). */\nconst vercelAppOriginPattern = /^https:\\/\\/[a-z0-9][a-z0-9.-]*\\.vercel\\.app$/i;\n\nconst MAX_PATTERN_LENGTH = 200;\n// This heuristic only targets common nested-quantifier cases like `(a+)+`.\n// It does not catch every risky construct (for example `.*.*` or deep alternation nesting),\n// so `parseCorsOriginPatterns` should still be limited to operator-controlled, anchored patterns.\nconst SUSPICIOUS_QUANTIFIER_PATTERN = /(\\([^)]*[+*{][^)]*\\)|\\[[^\\]]+[+*{][^\\]]*\\])[+*{]/;\n\nconst parseList = (value?: string) =>\n value\n ?.split(',')\n .map((item) => item.trim())\n .filter(Boolean) ?? [];\n\nconst isDefined = <T>(value: T | undefined | null): value is T => Boolean(value);\n\nconst toCorsOrigin = (value: string) => {\n try {\n return new URL(value).origin;\n } catch {\n return value.replace(/\\/+$/, '');\n }\n};\n\nexport const parseCorsOrigins = (origins?: string) =>\n parseList(origins).map(toCorsOrigin);\n\nconst validateCorsOriginPattern = (pattern: string) => {\n if (pattern.length > MAX_PATTERN_LENGTH) {\n throw new Error(`CORS pattern exceeds maximum length of ${MAX_PATTERN_LENGTH}`);\n }\n\n // Prefer short, anchored patterns and avoid other complex regex features even if they pass this check.\n if (SUSPICIOUS_QUANTIFIER_PATTERN.test(pattern)) {\n throw new Error(\"CORS pattern contains nested or ambiguous quantifiers\");\n }\n\n return pattern;\n};\n\n// Patterns are operator-controlled and matched against bounded URL origins, so ReDoS risk is low.\n// Syntax validation does not guarantee safety; prefer anchored patterns and avoid nested quantifiers.\nexport const parseCorsOriginPatterns = (patterns?: string) =>\n parseList(patterns).map((pattern) => new RegExp(validateCorsOriginPattern(pattern)));\n\nexport const isValidCorsOriginPatternList = (patterns?: string) => {\n try {\n parseCorsOriginPatterns(patterns);\n return true;\n } catch {\n return false;\n }\n};\n\nexport const createCorsOriginMatcher = (env: CorsEnv) => {\n const allowedOrigins = Array.from(new Set([\n ...(env.NODE_ENV === 'production' ? productionOrigins : nonProductionOrigins),\n env.NEXT_PUBLIC_APP_URL ? toCorsOrigin(env.NEXT_PUBLIC_APP_URL) : undefined,\n ...parseCorsOrigins(env.CORS_ALLOWED_ORIGINS),\n ].filter(isDefined)));\n\n const allowedOriginPatterns = [\n vercelAppOriginPattern,\n ...parseCorsOriginPatterns(env.CORS_ALLOWED_ORIGIN_PATTERNS),\n ];\n\n const isAllowedOrigin = (origin?: string) => {\n const corsOrigin = origin ? toCorsOrigin(origin) : undefined;\n\n return Boolean(corsOrigin && (\n allowedOrigins.includes(corsOrigin) ||\n allowedOriginPatterns.some((pattern) => pattern.test(corsOrigin))\n ));\n };\n\n return {\n allowedOrigins,\n allowedOriginPatterns,\n isAllowedOrigin,\n };\n};\n"],"names":[],"mappings":"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","debug_id":"672f131c-9cfe-50db-bd9a-c2a57fa5ceef"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileUpload.d.ts","sourceRoot":"/","sources":["lib/fileUpload.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAEd;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAEd;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,IAAI,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,wBAAsB,0BAA0B,CAAC,KAAK,EAAE;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB;;;GA+BA;AAKD;;GAEG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,YAAY,CAAC,CAKvB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,QAAQ,EAAE,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CAKzB;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUlE;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,MAAM,EACrB,cAAc,CAAC,EAAE,MAAM,EACvB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,gBAAgB,CAAC,
|
|
1
|
+
{"version":3,"file":"fileUpload.d.ts","sourceRoot":"/","sources":["lib/fileUpload.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAEd;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAEd;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,IAAI,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,wBAAsB,0BAA0B,CAAC,KAAK,EAAE;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB;;;GA+BA;AAKD;;GAEG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,YAAY,CAAC,CAKvB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,QAAQ,EAAE,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CAKzB;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAUlE;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,MAAM,EACrB,cAAc,CAAC,EAAE,MAAM,EACvB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,gBAAgB,CAAC,CAkG3B;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,OAAO,EACtB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CA4Df;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CA8Bf;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,cAAc,EAAE,EACvB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,YAAY,CAAC,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,MAAM,EACrB,cAAc,CAAC,EAAE,MAAM,EACvB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAyB7B"}
|
package/dist/lib/fileUpload.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
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]="c2b8462a-2a3e-5192-85cc-5f8cc649bfec")}catch(e){}}();
|
|
3
3
|
import { TRPCError } from "@trpc/server";
|
|
4
4
|
import { v4 as uuidv4 } from "uuid";
|
|
5
5
|
import { getSignedUrl, objectExists } from "./googleCloudStorage.js";
|
|
@@ -121,6 +121,7 @@ export async function createDirectUploadFile(file, userId, directory, assignment
|
|
|
121
121
|
uploadUrl,
|
|
122
122
|
uploadExpiresAt,
|
|
123
123
|
uploadSessionId,
|
|
124
|
+
uploadedAt: null,
|
|
124
125
|
user: {
|
|
125
126
|
connect: { id: userId }
|
|
126
127
|
},
|
|
@@ -216,14 +217,12 @@ export async function confirmDirectUpload(fileId, uploadSuccess, errorMessage) {
|
|
|
216
217
|
const updateData = {
|
|
217
218
|
uploadStatus: actualUploadSuccess ? 'COMPLETED' : 'FAILED',
|
|
218
219
|
uploadProgress: actualUploadSuccess ? 100 : 0,
|
|
220
|
+
uploadedAt: actualUploadSuccess ? new Date() : null,
|
|
219
221
|
};
|
|
220
222
|
if (!actualUploadSuccess && actualErrorMessage) {
|
|
221
223
|
updateData.uploadError = actualErrorMessage;
|
|
222
224
|
updateData.uploadRetryCount = { increment: 1 };
|
|
223
225
|
}
|
|
224
|
-
if (actualUploadSuccess) {
|
|
225
|
-
updateData.uploadedAt = new Date();
|
|
226
|
-
}
|
|
227
226
|
await prisma.file.update({
|
|
228
227
|
where: { id: fileId },
|
|
229
228
|
data: updateData
|
|
@@ -302,4 +301,4 @@ export async function createDirectUploadFiles(files, userId, directory, assignme
|
|
|
302
301
|
}
|
|
303
302
|
}
|
|
304
303
|
//# sourceMappingURL=fileUpload.js.map
|
|
305
|
-
//# debugId=
|
|
304
|
+
//# debugId=c2b8462a-2a3e-5192-85cc-5f8cc649bfec
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileUpload.js","sources":["lib/fileUpload.ts"],"sourceRoot":"/","sourcesContent":["import { TRPCError } from \"@trpc/server\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { getSignedUrl, objectExists } from \"./googleCloudStorage.js\";\nimport { prisma } from \"./prisma.js\";\nimport { logger } from \"../utils/logger.js\";\nimport { env } from \"./config/env.js\";\n\nexport interface FileData {\n name: string;\n type: string;\n size: number;\n // No data field - for direct file uploads\n}\n\nexport interface DirectFileData {\n name: string;\n type: string;\n size: number;\n // No data field - for direct file uploads\n}\n\nexport interface UploadedFile {\n id: string;\n name: string;\n type: string;\n size: number;\n path: string;\n thumbnailId?: string;\n}\n\nexport interface DirectUploadFile {\n id: string;\n name: string;\n type: string;\n size: number;\n path: string;\n uploadUrl: string;\n uploadExpiresAt: Date;\n uploadSessionId: string;\n}\n\nexport async function validateDirectUploadIntent(input: {\n filePath: string;\n uploadSessionId: string;\n userId: string;\n}) {\n const fileRecord = await prisma.file.findFirst({\n where: {\n path: input.filePath,\n uploadSessionId: input.uploadSessionId,\n userId: input.userId,\n uploadExpiresAt: { gt: new Date() },\n isOrphaned: false,\n messageId: null,\n },\n select: {\n id: true,\n uploadStatus: true,\n },\n });\n\n if (!fileRecord) {\n throw new TRPCError({\n code: 'FORBIDDEN',\n message: 'Invalid or expired upload intent',\n });\n }\n\n if (!['PENDING', 'UPLOADING'].includes(fileRecord.uploadStatus)) {\n throw new TRPCError({\n code: 'BAD_REQUEST',\n message: 'Upload is no longer accepting data',\n });\n }\n\n return fileRecord;\n}\n\n// DEPRECATED: These functions are no longer used - files are uploaded directly to GCS\n// Use createDirectUploadFile() and createDirectUploadFiles() instead\n\n/**\n * @deprecated Use createDirectUploadFile instead\n */\nexport async function uploadFile(\n file: FileData,\n userId: string,\n directory?: string,\n assignmentId?: string\n): Promise<UploadedFile> {\n throw new TRPCError({\n code: 'NOT_IMPLEMENTED',\n message: 'uploadFile is deprecated. Use createDirectUploadFile instead.',\n });\n}\n\n/**\n * @deprecated Use createDirectUploadFiles instead\n */\nexport async function uploadFiles(\n files: FileData[], \n userId: string,\n directory?: string\n): Promise<UploadedFile[]> {\n throw new TRPCError({\n code: 'NOT_IMPLEMENTED',\n message: 'uploadFiles is deprecated. Use createDirectUploadFiles instead.',\n });\n}\n\n/**\n * Gets a signed URL for a file\n * @param filePath The path of the file in Google Cloud Storage\n * @returns The signed URL\n */\nexport async function getFileUrl(filePath: string): Promise<string> {\n try {\n return await getSignedUrl(filePath);\n } catch (error) {\n console.error('Error getting signed URL:', error);\n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message: 'Failed to get file URL',\n });\n }\n}\n\n/**\n * Creates a file record for direct upload and generates signed URL\n * @param file The file metadata (no base64 data)\n * @param userId The ID of the user uploading the file\n * @param directory Optional directory to store the file in\n * @param assignmentId Optional assignment ID to associate the file with\n * @param submissionId Optional submission ID to associate the file with\n * @returns The direct upload file information with signed URL\n */\nexport async function createDirectUploadFile(\n file: DirectFileData,\n userId: string,\n directory?: string,\n assignmentId?: string,\n submissionId?: string,\n announcementId?: string,\n conversationId?: string\n): Promise<DirectUploadFile> {\n try {\n // Validate file extension matches MIME type\n const fileExtension = file.name.split('.').pop()?.toLowerCase();\n const mimeType = file.type.toLowerCase();\n \n const extensionMimeMap: Record<string, string[]> = {\n 'jpg': ['image/jpeg'],\n 'jpeg': ['image/jpeg'],\n 'png': ['image/png'],\n 'gif': ['image/gif'],\n 'webp': ['image/webp']\n };\n \n if (fileExtension && extensionMimeMap[fileExtension]) {\n if (!extensionMimeMap[fileExtension].includes(mimeType)) {\n throw new Error(`File extension .${fileExtension} does not match MIME type ${mimeType}`);\n }\n }\n \n // Create a unique filename\n const uniqueFilename = `${uuidv4()}.${fileExtension}`;\n \n // Construct the full path\n const filePath = directory \n ? `${directory}/${uniqueFilename}`\n : uniqueFilename;\n \n // Generate upload session ID\n const uploadSessionId = uuidv4();\n \n // Generate backend proxy upload URL (not direct GCS)\n const baseUrl = env.BACKEND_URL || 'http://localhost:3001';\n const uploadUrl = `${baseUrl}/api/upload/${encodeURIComponent(filePath)}?uploadSessionId=${encodeURIComponent(uploadSessionId)}`;\n const uploadExpiresAt = new Date(Date.now() + 15 * 60 * 1000); // 15 minutes from now\n \n // Create file record in database with PENDING status\n const fileRecord = await prisma.file.create({\n data: {\n name: file.name,\n type: file.type,\n size: file.size,\n path: filePath,\n uploadStatus: 'PENDING',\n uploadUrl,\n uploadExpiresAt,\n uploadSessionId,\n user: {\n connect: { id: userId }\n },\n ...(directory && {\n folder: {\n connect: {id: directory},\n },\n }),\n ...(assignmentId && {\n assignment: {\n connect: { id: assignmentId }\n }\n }),\n ...(submissionId && {\n submission: {\n connect: { id: submissionId }\n }\n }),\n ...(announcementId && {\n announcement: {\n connect: { id: announcementId }\n }\n }),\n ...(conversationId && {\n conversationId,\n })\n },\n });\n \n return {\n id: fileRecord.id,\n name: file.name,\n type: file.type,\n size: file.size,\n path: filePath,\n uploadUrl,\n uploadExpiresAt,\n uploadSessionId\n };\n } catch (error) {\n logger.error('Error creating direct upload file:', {error: error instanceof Error ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n } : error});\n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message: 'Failed to create direct upload file',\n });\n }\n}\n\n/**\n * Confirms a direct upload was successful\n * @param fileId The ID of the file record\n * @param uploadSuccess Whether the upload was successful\n * @param errorMessage Optional error message if upload failed\n */\nexport async function confirmDirectUpload(\n fileId: string,\n uploadSuccess: boolean,\n errorMessage?: string\n): Promise<void> {\n try {\n // First fetch the file record to get the object path\n const fileRecord = await prisma.file.findUnique({\n where: { id: fileId },\n select: { path: true }\n });\n\n if (!fileRecord) {\n throw new TRPCError({\n code: 'NOT_FOUND',\n message: 'File record not found',\n });\n }\n\n let actualUploadSuccess = uploadSuccess;\n let actualErrorMessage = errorMessage;\n\n // If uploadSuccess is true, verify the object actually exists in GCS\n if (uploadSuccess) {\n try {\n const exists = await objectExists(env.GOOGLE_CLOUD_BUCKET_NAME!, fileRecord.path);\n if (!exists) {\n actualUploadSuccess = false;\n actualErrorMessage = 'File upload reported as successful but object not found in Google Cloud Storage';\n logger.error(`File upload verification failed for ${fileId}: object ${fileRecord.path} not found in GCS`);\n }\n } catch (error) {\n logger.error(`Error verifying file existence in GCS for ${fileId}:`, {error: error instanceof Error ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n } : error});\n actualUploadSuccess = false;\n actualErrorMessage = 'Failed to verify file existence in Google Cloud Storage';\n }\n }\n\n const updateData: any = {\n uploadStatus: actualUploadSuccess ? 'COMPLETED' : 'FAILED',\n uploadProgress: actualUploadSuccess ? 100 : 0,\n };\n \n if (!actualUploadSuccess && actualErrorMessage) {\n updateData.uploadError = actualErrorMessage;\n updateData.uploadRetryCount = { increment: 1 };\n }\n \n if (actualUploadSuccess) {\n updateData.uploadedAt = new Date();\n }\n \n await prisma.file.update({\n where: { id: fileId },\n data: updateData\n });\n } catch (error) {\n logger.error('Error confirming direct upload:', {error});\n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message: 'Failed to confirm upload',\n });\n }\n}\n\n/**\n * Updates upload progress for a direct upload\n * @param fileId The ID of the file record\n * @param progress Progress percentage (0-100)\n */\nexport async function updateUploadProgress(\n fileId: string,\n progress: number\n): Promise<void> {\n try {\n // await prisma.file.update({\n // where: { id: fileId },\n // data: {\n // uploadStatus: 'UPLOADING',\n // uploadProgress: Math.min(100, Math.max(0, progress))\n // }\n // });\n const current = await prisma.file.findUnique({ where: { id: fileId }, select: { uploadStatus: true } });\n if (!current || ['COMPLETED','FAILED','CANCELLED'].includes(current.uploadStatus as string)) return;\n const clamped = Math.min(100, Math.max(0, progress));\n await prisma.file.update({\n where: { id: fileId },\n data: {\n uploadStatus: 'UPLOADING',\n uploadProgress: clamped\n }\n });\n } catch (error) {\n logger.error('Error updating upload progress:', {error: error instanceof Error ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n } : error}); \n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message: 'Failed to update upload progress',\n });\n }\n}\n\n/**\n * Creates multiple direct upload files\n * @param files Array of file metadata\n * @param userId The ID of the user uploading the files\n * @param directory Optional subdirectory to store the files in\n * @param assignmentId Optional assignment ID to associate files with\n * @param submissionId Optional submission ID to associate files with\n * @returns Array of direct upload file information\n */\nexport async function createDirectUploadFiles(\n files: DirectFileData[], \n userId: string,\n directory?: string,\n assignmentId?: string,\n submissionId?: string,\n announcementId?: string,\n conversationId?: string\n): Promise<DirectUploadFile[]> {\n try {\n const uploadPromises = files.map(file => \n createDirectUploadFile(\n file,\n userId,\n directory,\n assignmentId,\n submissionId,\n announcementId,\n conversationId\n )\n );\n return await Promise.all(uploadPromises);\n } catch (error) {\n logger.error('Error creating direct upload files:', {error: error instanceof Error ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n } : error});\n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message: 'Failed to create direct upload files',\n });\n }\n}\n"],"names":[],"mappings":"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","debug_id":"01a3ee28-2d14-5542-9301-e6f24e5c7a0d"}
|
|
1
|
+
{"version":3,"file":"fileUpload.js","sources":["lib/fileUpload.ts"],"sourceRoot":"/","sourcesContent":["import { TRPCError } from \"@trpc/server\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { getSignedUrl, objectExists } from \"./googleCloudStorage.js\";\nimport { prisma } from \"./prisma.js\";\nimport { logger } from \"../utils/logger.js\";\nimport { env } from \"./config/env.js\";\n\nexport interface FileData {\n name: string;\n type: string;\n size: number;\n // No data field - for direct file uploads\n}\n\nexport interface DirectFileData {\n name: string;\n type: string;\n size: number;\n // No data field - for direct file uploads\n}\n\nexport interface UploadedFile {\n id: string;\n name: string;\n type: string;\n size: number;\n path: string;\n thumbnailId?: string;\n}\n\nexport interface DirectUploadFile {\n id: string;\n name: string;\n type: string;\n size: number;\n path: string;\n uploadUrl: string;\n uploadExpiresAt: Date;\n uploadSessionId: string;\n}\n\nexport async function validateDirectUploadIntent(input: {\n filePath: string;\n uploadSessionId: string;\n userId: string;\n}) {\n const fileRecord = await prisma.file.findFirst({\n where: {\n path: input.filePath,\n uploadSessionId: input.uploadSessionId,\n userId: input.userId,\n uploadExpiresAt: { gt: new Date() },\n isOrphaned: false,\n messageId: null,\n },\n select: {\n id: true,\n uploadStatus: true,\n },\n });\n\n if (!fileRecord) {\n throw new TRPCError({\n code: 'FORBIDDEN',\n message: 'Invalid or expired upload intent',\n });\n }\n\n if (!['PENDING', 'UPLOADING'].includes(fileRecord.uploadStatus)) {\n throw new TRPCError({\n code: 'BAD_REQUEST',\n message: 'Upload is no longer accepting data',\n });\n }\n\n return fileRecord;\n}\n\n// DEPRECATED: These functions are no longer used - files are uploaded directly to GCS\n// Use createDirectUploadFile() and createDirectUploadFiles() instead\n\n/**\n * @deprecated Use createDirectUploadFile instead\n */\nexport async function uploadFile(\n file: FileData,\n userId: string,\n directory?: string,\n assignmentId?: string\n): Promise<UploadedFile> {\n throw new TRPCError({\n code: 'NOT_IMPLEMENTED',\n message: 'uploadFile is deprecated. Use createDirectUploadFile instead.',\n });\n}\n\n/**\n * @deprecated Use createDirectUploadFiles instead\n */\nexport async function uploadFiles(\n files: FileData[], \n userId: string,\n directory?: string\n): Promise<UploadedFile[]> {\n throw new TRPCError({\n code: 'NOT_IMPLEMENTED',\n message: 'uploadFiles is deprecated. Use createDirectUploadFiles instead.',\n });\n}\n\n/**\n * Gets a signed URL for a file\n * @param filePath The path of the file in Google Cloud Storage\n * @returns The signed URL\n */\nexport async function getFileUrl(filePath: string): Promise<string> {\n try {\n return await getSignedUrl(filePath);\n } catch (error) {\n console.error('Error getting signed URL:', error);\n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message: 'Failed to get file URL',\n });\n }\n}\n\n/**\n * Creates a file record for direct upload and generates signed URL\n * @param file The file metadata (no base64 data)\n * @param userId The ID of the user uploading the file\n * @param directory Optional directory to store the file in\n * @param assignmentId Optional assignment ID to associate the file with\n * @param submissionId Optional submission ID to associate the file with\n * @returns The direct upload file information with signed URL\n */\nexport async function createDirectUploadFile(\n file: DirectFileData,\n userId: string,\n directory?: string,\n assignmentId?: string,\n submissionId?: string,\n announcementId?: string,\n conversationId?: string\n): Promise<DirectUploadFile> {\n try {\n // Validate file extension matches MIME type\n const fileExtension = file.name.split('.').pop()?.toLowerCase();\n const mimeType = file.type.toLowerCase();\n \n const extensionMimeMap: Record<string, string[]> = {\n 'jpg': ['image/jpeg'],\n 'jpeg': ['image/jpeg'],\n 'png': ['image/png'],\n 'gif': ['image/gif'],\n 'webp': ['image/webp']\n };\n \n if (fileExtension && extensionMimeMap[fileExtension]) {\n if (!extensionMimeMap[fileExtension].includes(mimeType)) {\n throw new Error(`File extension .${fileExtension} does not match MIME type ${mimeType}`);\n }\n }\n \n // Create a unique filename\n const uniqueFilename = `${uuidv4()}.${fileExtension}`;\n \n // Construct the full path\n const filePath = directory \n ? `${directory}/${uniqueFilename}`\n : uniqueFilename;\n \n // Generate upload session ID\n const uploadSessionId = uuidv4();\n \n // Generate backend proxy upload URL (not direct GCS)\n const baseUrl = env.BACKEND_URL || 'http://localhost:3001';\n const uploadUrl = `${baseUrl}/api/upload/${encodeURIComponent(filePath)}?uploadSessionId=${encodeURIComponent(uploadSessionId)}`;\n const uploadExpiresAt = new Date(Date.now() + 15 * 60 * 1000); // 15 minutes from now\n \n // Create file record in database with PENDING status\n const fileRecord = await prisma.file.create({\n data: {\n name: file.name,\n type: file.type,\n size: file.size,\n path: filePath,\n uploadStatus: 'PENDING',\n uploadUrl,\n uploadExpiresAt,\n uploadSessionId,\n uploadedAt: null,\n user: {\n connect: { id: userId }\n },\n ...(directory && {\n folder: {\n connect: {id: directory},\n },\n }),\n ...(assignmentId && {\n assignment: {\n connect: { id: assignmentId }\n }\n }),\n ...(submissionId && {\n submission: {\n connect: { id: submissionId }\n }\n }),\n ...(announcementId && {\n announcement: {\n connect: { id: announcementId }\n }\n }),\n ...(conversationId && {\n conversationId,\n })\n },\n });\n \n return {\n id: fileRecord.id,\n name: file.name,\n type: file.type,\n size: file.size,\n path: filePath,\n uploadUrl,\n uploadExpiresAt,\n uploadSessionId\n };\n } catch (error) {\n logger.error('Error creating direct upload file:', {error: error instanceof Error ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n } : error});\n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message: 'Failed to create direct upload file',\n });\n }\n}\n\n/**\n * Confirms a direct upload was successful\n * @param fileId The ID of the file record\n * @param uploadSuccess Whether the upload was successful\n * @param errorMessage Optional error message if upload failed\n */\nexport async function confirmDirectUpload(\n fileId: string,\n uploadSuccess: boolean,\n errorMessage?: string\n): Promise<void> {\n try {\n // First fetch the file record to get the object path\n const fileRecord = await prisma.file.findUnique({\n where: { id: fileId },\n select: { path: true }\n });\n\n if (!fileRecord) {\n throw new TRPCError({\n code: 'NOT_FOUND',\n message: 'File record not found',\n });\n }\n\n let actualUploadSuccess = uploadSuccess;\n let actualErrorMessage = errorMessage;\n\n // If uploadSuccess is true, verify the object actually exists in GCS\n if (uploadSuccess) {\n try {\n const exists = await objectExists(env.GOOGLE_CLOUD_BUCKET_NAME!, fileRecord.path);\n if (!exists) {\n actualUploadSuccess = false;\n actualErrorMessage = 'File upload reported as successful but object not found in Google Cloud Storage';\n logger.error(`File upload verification failed for ${fileId}: object ${fileRecord.path} not found in GCS`);\n }\n } catch (error) {\n logger.error(`Error verifying file existence in GCS for ${fileId}:`, {error: error instanceof Error ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n } : error});\n actualUploadSuccess = false;\n actualErrorMessage = 'Failed to verify file existence in Google Cloud Storage';\n }\n }\n\n const updateData: any = {\n uploadStatus: actualUploadSuccess ? 'COMPLETED' : 'FAILED',\n uploadProgress: actualUploadSuccess ? 100 : 0,\n uploadedAt: actualUploadSuccess ? new Date() : null,\n };\n \n if (!actualUploadSuccess && actualErrorMessage) {\n updateData.uploadError = actualErrorMessage;\n updateData.uploadRetryCount = { increment: 1 };\n }\n \n await prisma.file.update({\n where: { id: fileId },\n data: updateData\n });\n } catch (error) {\n logger.error('Error confirming direct upload:', {error});\n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message: 'Failed to confirm upload',\n });\n }\n}\n\n/**\n * Updates upload progress for a direct upload\n * @param fileId The ID of the file record\n * @param progress Progress percentage (0-100)\n */\nexport async function updateUploadProgress(\n fileId: string,\n progress: number\n): Promise<void> {\n try {\n // await prisma.file.update({\n // where: { id: fileId },\n // data: {\n // uploadStatus: 'UPLOADING',\n // uploadProgress: Math.min(100, Math.max(0, progress))\n // }\n // });\n const current = await prisma.file.findUnique({ where: { id: fileId }, select: { uploadStatus: true } });\n if (!current || ['COMPLETED','FAILED','CANCELLED'].includes(current.uploadStatus as string)) return;\n const clamped = Math.min(100, Math.max(0, progress));\n await prisma.file.update({\n where: { id: fileId },\n data: {\n uploadStatus: 'UPLOADING',\n uploadProgress: clamped\n }\n });\n } catch (error) {\n logger.error('Error updating upload progress:', {error: error instanceof Error ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n } : error}); \n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message: 'Failed to update upload progress',\n });\n }\n}\n\n/**\n * Creates multiple direct upload files\n * @param files Array of file metadata\n * @param userId The ID of the user uploading the files\n * @param directory Optional subdirectory to store the files in\n * @param assignmentId Optional assignment ID to associate files with\n * @param submissionId Optional submission ID to associate files with\n * @returns Array of direct upload file information\n */\nexport async function createDirectUploadFiles(\n files: DirectFileData[], \n userId: string,\n directory?: string,\n assignmentId?: string,\n submissionId?: string,\n announcementId?: string,\n conversationId?: string\n): Promise<DirectUploadFile[]> {\n try {\n const uploadPromises = files.map(file => \n createDirectUploadFile(\n file,\n userId,\n directory,\n assignmentId,\n submissionId,\n announcementId,\n conversationId\n )\n );\n return await Promise.all(uploadPromises);\n } catch (error) {\n logger.error('Error creating direct upload files:', {error: error instanceof Error ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n } : error});\n throw new TRPCError({\n code: 'INTERNAL_SERVER_ERROR',\n message: 'Failed to create direct upload files',\n });\n }\n}\n"],"names":[],"mappings":"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","debug_id":"c2b8462a-2a3e-5192-85cc-5f8cc649bfec"}
|
|
@@ -946,6 +946,38 @@ export declare function findAssignmentWithClassForTeacher(assignmentId: string,
|
|
|
946
946
|
};
|
|
947
947
|
};
|
|
948
948
|
}>;
|
|
949
|
+
/**
|
|
950
|
+
* Clone an assignment into another class with a new title: copies settings, duplicates linked
|
|
951
|
+
* worksheets into the target class, clones attachment file records (same storage path),
|
|
952
|
+
* creates empty submissions for all students in the target class, and does not copy the
|
|
953
|
+
* calendar event link or per-student “assigned to” overrides.
|
|
954
|
+
*/
|
|
955
|
+
export declare function duplicateAssignment(sourceAssignmentId: string, targetClassId: string, title: string, duplicatingUserId: string): Promise<{
|
|
956
|
+
type: import(".prisma/client").$Enums.AssignmentType;
|
|
957
|
+
id: string;
|
|
958
|
+
createdAt: Date | null;
|
|
959
|
+
modifiedAt: Date | null;
|
|
960
|
+
classId: string;
|
|
961
|
+
title: string;
|
|
962
|
+
instructions: string;
|
|
963
|
+
dueDate: Date;
|
|
964
|
+
teacherId: string;
|
|
965
|
+
acceptFiles: boolean;
|
|
966
|
+
acceptExtendedResponse: boolean;
|
|
967
|
+
acceptWorksheet: boolean;
|
|
968
|
+
gradeWithAI: boolean;
|
|
969
|
+
aiPolicyLevel: number;
|
|
970
|
+
sectionId: string | null;
|
|
971
|
+
graded: boolean;
|
|
972
|
+
maxGrade: number | null;
|
|
973
|
+
weight: number;
|
|
974
|
+
inProgress: boolean;
|
|
975
|
+
template: boolean;
|
|
976
|
+
eventId: string | null;
|
|
977
|
+
markSchemeId: string | null;
|
|
978
|
+
order: number | null;
|
|
979
|
+
gradingBoundaryId: string | null;
|
|
980
|
+
} | null>;
|
|
949
981
|
/** @returns Submissions for assignment (teacher view). */
|
|
950
982
|
export declare function findSubmissionsByAssignmentForTeacher(assignmentId: string, teacherId: string): import(".prisma/client").Prisma.PrismaPromise<({
|
|
951
983
|
assignment: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assignment.d.ts","sourceRoot":"/","sources":["models/assignment.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"assignment.d.ts","sourceRoot":"/","sources":["models/assignment.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Assignment model – assignments, submissions, attachments.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
5
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="d97b0aba-efb0-533e-b942-06f6eb24b6d0")}catch(e){}}();
|
|
6
6
|
import { prisma } from "../lib/prisma.js";
|
|
7
|
+
import { duplicateWorksheetWithClient } from "./worksheet.js";
|
|
7
8
|
import { classMemberOrSchoolAdminWhere, classTeacherOrSchoolAdminWhere, schoolAdminForClassWhere, } from "./access.js";
|
|
8
9
|
const assignmentGetInclude = {
|
|
9
10
|
submissions: {
|
|
@@ -200,6 +201,114 @@ export function findAssignmentWithClassForTeacher(assignmentId, teacherId) {
|
|
|
200
201
|
include: { class: true },
|
|
201
202
|
});
|
|
202
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* Clone an assignment into another class with a new title: copies settings, duplicates linked
|
|
206
|
+
* worksheets into the target class, clones attachment file records (same storage path),
|
|
207
|
+
* creates empty submissions for all students in the target class, and does not copy the
|
|
208
|
+
* calendar event link or per-student “assigned to” overrides.
|
|
209
|
+
*/
|
|
210
|
+
export async function duplicateAssignment(sourceAssignmentId, targetClassId, title, duplicatingUserId) {
|
|
211
|
+
return prisma.$transaction(async (tx) => {
|
|
212
|
+
const source = await tx.assignment.findUnique({
|
|
213
|
+
where: { id: sourceAssignmentId },
|
|
214
|
+
include: {
|
|
215
|
+
worksheets: { select: { id: true, name: true } },
|
|
216
|
+
attachments: {
|
|
217
|
+
select: { name: true, type: true, size: true, path: true },
|
|
218
|
+
},
|
|
219
|
+
section: { select: { id: true, name: true } },
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
if (!source) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
let targetSectionId;
|
|
226
|
+
if (source.sectionId && source.section) {
|
|
227
|
+
const match = await tx.section.findFirst({
|
|
228
|
+
where: { classId: targetClassId, name: source.section.name },
|
|
229
|
+
select: { id: true },
|
|
230
|
+
});
|
|
231
|
+
targetSectionId = match?.id;
|
|
232
|
+
}
|
|
233
|
+
const newWorksheetIds = [];
|
|
234
|
+
for (const ws of source.worksheets) {
|
|
235
|
+
const dup = await duplicateWorksheetWithClient(tx, ws.id, targetClassId, ws.name);
|
|
236
|
+
if (dup) {
|
|
237
|
+
newWorksheetIds.push(dup.id);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const classData = await tx.class.findUnique({
|
|
241
|
+
where: { id: targetClassId },
|
|
242
|
+
include: { students: { select: { id: true } } },
|
|
243
|
+
});
|
|
244
|
+
if (!classData) {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
const submissionData = classData.students.map((s) => ({
|
|
248
|
+
student: { connect: { id: s.id } },
|
|
249
|
+
}));
|
|
250
|
+
const created = await tx.assignment.create({
|
|
251
|
+
data: {
|
|
252
|
+
title,
|
|
253
|
+
instructions: source.instructions,
|
|
254
|
+
dueDate: source.dueDate,
|
|
255
|
+
teacher: { connect: { id: duplicatingUserId } },
|
|
256
|
+
class: { connect: { id: targetClassId } },
|
|
257
|
+
acceptFiles: source.acceptFiles,
|
|
258
|
+
acceptExtendedResponse: source.acceptExtendedResponse,
|
|
259
|
+
acceptWorksheet: source.acceptWorksheet,
|
|
260
|
+
gradeWithAI: source.gradeWithAI,
|
|
261
|
+
aiPolicyLevel: source.aiPolicyLevel,
|
|
262
|
+
graded: source.graded,
|
|
263
|
+
maxGrade: source.maxGrade,
|
|
264
|
+
weight: source.weight,
|
|
265
|
+
type: source.type,
|
|
266
|
+
inProgress: source.inProgress,
|
|
267
|
+
template: source.template,
|
|
268
|
+
...(source.markSchemeId && {
|
|
269
|
+
markScheme: { connect: { id: source.markSchemeId } },
|
|
270
|
+
}),
|
|
271
|
+
...(source.gradingBoundaryId && {
|
|
272
|
+
gradingBoundary: { connect: { id: source.gradingBoundaryId } },
|
|
273
|
+
}),
|
|
274
|
+
...(targetSectionId && {
|
|
275
|
+
section: { connect: { id: targetSectionId } },
|
|
276
|
+
}),
|
|
277
|
+
...(newWorksheetIds.length > 0 && {
|
|
278
|
+
worksheets: { connect: newWorksheetIds.map((id) => ({ id })) },
|
|
279
|
+
}),
|
|
280
|
+
submissions: { create: submissionData },
|
|
281
|
+
order: 0,
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
await tx.assignment.updateMany({
|
|
285
|
+
where: { classId: targetClassId, id: { not: created.id } },
|
|
286
|
+
data: { order: { increment: 1 } },
|
|
287
|
+
});
|
|
288
|
+
await tx.section.updateMany({
|
|
289
|
+
where: { classId: targetClassId },
|
|
290
|
+
data: { order: { increment: 1 } },
|
|
291
|
+
});
|
|
292
|
+
await tx.assignment.update({
|
|
293
|
+
where: { id: created.id },
|
|
294
|
+
data: { order: 1 },
|
|
295
|
+
});
|
|
296
|
+
for (const file of source.attachments) {
|
|
297
|
+
await tx.file.create({
|
|
298
|
+
data: {
|
|
299
|
+
name: file.name,
|
|
300
|
+
type: file.type,
|
|
301
|
+
size: file.size ?? 0,
|
|
302
|
+
path: file.path,
|
|
303
|
+
uploadStatus: "COMPLETED",
|
|
304
|
+
user: { connect: { id: duplicatingUserId } },
|
|
305
|
+
assignment: { connect: { id: created.id } },
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
return created;
|
|
310
|
+
}, { maxWait: 10000, timeout: 60000 });
|
|
311
|
+
}
|
|
203
312
|
/** @returns Submissions for assignment (teacher view). */
|
|
204
313
|
export function findSubmissionsByAssignmentForTeacher(assignmentId, teacherId) {
|
|
205
314
|
return prisma.submission.findMany({
|
|
@@ -306,4 +415,4 @@ export function detachAssignmentFromEvent(assignmentId) {
|
|
|
306
415
|
});
|
|
307
416
|
}
|
|
308
417
|
//# sourceMappingURL=assignment.js.map
|
|
309
|
-
//# debugId=
|
|
418
|
+
//# debugId=d97b0aba-efb0-533e-b942-06f6eb24b6d0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assignment.js","sources":["models/assignment.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Assignment model – assignments, submissions, attachments.\n */\nimport { prisma } from \"../lib/prisma.js\";\nimport {\n classMemberOrSchoolAdminWhere,\n classTeacherOrSchoolAdminWhere,\n schoolAdminForClassWhere,\n} from \"./access.js\";\n\nconst assignmentGetInclude = {\n submissions: {\n select: {\n student: { select: { id: true, username: true } },\n },\n },\n attachments: {\n select: {\n id: true,\n name: true,\n type: true,\n size: true,\n path: true,\n uploadedAt: true,\n thumbnailId: true,\n },\n },\n section: { select: { id: true, name: true } },\n teacher: { select: { id: true, username: true } },\n worksheets: { select: { id: true, name: true } },\n class: { select: { id: true, name: true } },\n eventAttached: {\n select: {\n id: true,\n name: true,\n startTime: true,\n endTime: true,\n location: true,\n remarks: true,\n color: true,\n },\n },\n markScheme: { select: { id: true, structured: true } },\n gradingBoundary: { select: { id: true, structured: true } },\n} as const;\n\n/** @returns Assignment by ID. */\nexport function findAssignmentById(id: string) {\n return prisma.assignment.findUnique({\n where: { id },\n });\n}\n\n/** @returns Assignment with full details for get. */\nexport function findAssignmentWithDetails(id: string) {\n return prisma.assignment.findUnique({\n where: { id },\n include: assignmentGetInclude,\n });\n}\n\n/** @returns Assignment with attachments for delete. */\nexport function findAssignmentForDelete(id: string, teacherId: string) {\n return prisma.assignment.findFirst({\n where: {\n id,\n OR: [\n { teacherId },\n { class: schoolAdminForClassWhere(teacherId) },\n ],\n },\n include: {\n attachments: { include: { thumbnail: true } },\n submissions: {\n include: {\n attachments: { include: { thumbnail: true } },\n annotations: { include: { thumbnail: true } },\n },\n },\n },\n });\n}\n\n/** @returns Assignments due today. */\nexport function findAssignmentsDueToday() {\n return prisma.assignment.findMany({\n where: {\n dueDate: { equals: new Date() },\n },\n select: {\n id: true,\n title: true,\n dueDate: true,\n type: true,\n graded: true,\n maxGrade: true,\n class: { select: { id: true, name: true } },\n },\n });\n}\n\n/** @returns Submission by assignment and student. */\nexport function findSubmissionByAssignmentAndStudent(assignmentId: string, studentId: string) {\n return prisma.submission.findFirst({\n where: { assignmentId, studentId },\n include: {\n attachments: true,\n student: { select: { id: true, username: true, profile: true } },\n assignment: {\n include: {\n class: true,\n markScheme: { select: { id: true, structured: true } },\n worksheets: { select: { id: true, name: true } },\n gradingBoundary: { select: { id: true, structured: true } },\n },\n },\n annotations: true,\n },\n });\n}\n\n/** @returns Submission by ID for class member. */\nexport function findSubmissionByIdForClassMember(submissionId: string, classId: string, userId: string) {\n return prisma.submission.findFirst({\n where: {\n id: submissionId,\n assignment: {\n classId,\n class: classMemberOrSchoolAdminWhere(userId),\n },\n },\n include: {\n attachments: true,\n annotations: true,\n student: { select: { id: true, username: true, profile: true } },\n assignment: {\n include: {\n class: true,\n markScheme: { select: { id: true, structured: true } },\n worksheets: { select: { id: true, name: true } },\n gradingBoundary: { select: { id: true, structured: true } },\n },\n },\n },\n });\n}\n\n/** @returns Submission by ID for update (student or teacher). */\nexport function findSubmissionForUpdate(submissionId: string, userId: string) {\n return prisma.submission.findFirst({\n where: {\n id: submissionId,\n OR: [\n { studentId: userId },\n {\n assignment: {\n class: classTeacherOrSchoolAdminWhere(userId),\n },\n },\n ],\n },\n include: {\n attachments: { include: { thumbnail: true } },\n assignment: {\n include: {\n class: true,\n markScheme: { select: { id: true, structured: true } },\n gradingBoundary: { select: { id: true, structured: true } },\n },\n },\n },\n });\n}\n\n/** Create a submission. */\nexport function createSubmission(assignmentId: string, studentId: string) {\n return prisma.submission.create({\n data: {\n assignment: { connect: { id: assignmentId } },\n student: { connect: { id: studentId } },\n },\n include: {\n attachments: true,\n annotations: true,\n student: { select: { id: true, username: true } },\n assignment: {\n include: {\n class: true,\n markScheme: { select: { id: true, structured: true } },\n worksheets: { select: { id: true, name: true } },\n gradingBoundary: { select: { id: true, structured: true } },\n },\n },\n },\n });\n}\n\n/** @returns Sections for a class. */\nexport function findSectionsByClassId(classId: string) {\n return prisma.section.findMany({\n where: { classId },\n select: { id: true, name: true },\n });\n}\n\n/** @returns Assignment with class for teacher (auth check). */\nexport function findAssignmentWithClassForTeacher(assignmentId: string, teacherId: string) {\n return prisma.assignment.findFirst({\n where: {\n id: assignmentId,\n class: classTeacherOrSchoolAdminWhere(teacherId),\n },\n include: { class: true },\n });\n}\n\n/** @returns Submissions for assignment (teacher view). */\nexport function findSubmissionsByAssignmentForTeacher(assignmentId: string, teacherId: string) {\n return prisma.submission.findMany({\n where: {\n assignment: {\n id: assignmentId,\n class: classTeacherOrSchoolAdminWhere(teacherId),\n },\n },\n include: {\n attachments: { include: { thumbnail: true } },\n student: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n profilePictureThumbnail: true,\n },\n },\n },\n },\n assignment: {\n include: {\n class: true,\n markScheme: { select: { id: true, structured: true } },\n gradingBoundary: { select: { id: true, structured: true } },\n },\n },\n },\n });\n}\n\n/** @returns Submission by ID for teacher update. */\nexport function findSubmissionForTeacherUpdate(submissionId: string, teacherId: string) {\n return prisma.submission.findFirst({\n where: {\n id: submissionId,\n assignment: {\n class: classTeacherOrSchoolAdminWhere(teacherId),\n },\n },\n include: {\n attachments: { include: { thumbnail: true } },\n annotations: { include: { thumbnail: true } },\n assignment: {\n include: {\n class: true,\n markScheme: { select: { id: true, structured: true } },\n gradingBoundary: { select: { id: true, structured: true } },\n },\n },\n },\n });\n}\n\n/** @returns Events in class that don't have this assignment attached. */\nexport function findAvailableEventsForAssignment(classId: string, assignmentId: string) {\n return prisma.event.findMany({\n where: {\n classId,\n assignmentsAttached: { none: { id: assignmentId } },\n },\n select: {\n id: true,\n name: true,\n startTime: true,\n endTime: true,\n location: true,\n remarks: true,\n color: true,\n },\n orderBy: { startTime: \"asc\" },\n });\n}\n\nconst assignmentAttachEventInclude = {\n attachments: { select: { id: true, name: true, type: true } },\n section: { select: { id: true, name: true } },\n teacher: { select: { id: true, username: true } },\n eventAttached: {\n select: {\n id: true,\n name: true,\n startTime: true,\n endTime: true,\n color: true,\n },\n },\n};\n\n/** Attach assignment to event. */\nexport function attachAssignmentToEvent(assignmentId: string, eventId: string) {\n return prisma.assignment.update({\n where: { id: assignmentId },\n data: { eventAttached: { connect: { id: eventId } } },\n include: assignmentAttachEventInclude,\n });\n}\n\n/** Detach assignment from event. */\nexport function detachAssignmentFromEvent(assignmentId: string) {\n return prisma.assignment.update({\n where: { id: assignmentId },\n data: { eventAttached: { disconnect: true } },\n include: assignmentAttachEventInclude,\n });\n}\n"],"names":[],"mappings":"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","debug_id":"42061a1a-7f8e-55c4-a836-0e727f41fe0d"}
|
|
1
|
+
{"version":3,"file":"assignment.js","sources":["models/assignment.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Assignment model – assignments, submissions, attachments.\n */\nimport { prisma } from \"../lib/prisma.js\";\nimport { duplicateWorksheetWithClient } from \"./worksheet.js\";\nimport {\n classMemberOrSchoolAdminWhere,\n classTeacherOrSchoolAdminWhere,\n schoolAdminForClassWhere,\n} from \"./access.js\";\n\nconst assignmentGetInclude = {\n submissions: {\n select: {\n student: { select: { id: true, username: true } },\n },\n },\n attachments: {\n select: {\n id: true,\n name: true,\n type: true,\n size: true,\n path: true,\n uploadedAt: true,\n thumbnailId: true,\n },\n },\n section: { select: { id: true, name: true } },\n teacher: { select: { id: true, username: true } },\n worksheets: { select: { id: true, name: true } },\n class: { select: { id: true, name: true } },\n eventAttached: {\n select: {\n id: true,\n name: true,\n startTime: true,\n endTime: true,\n location: true,\n remarks: true,\n color: true,\n },\n },\n markScheme: { select: { id: true, structured: true } },\n gradingBoundary: { select: { id: true, structured: true } },\n} as const;\n\n/** @returns Assignment by ID. */\nexport function findAssignmentById(id: string) {\n return prisma.assignment.findUnique({\n where: { id },\n });\n}\n\n/** @returns Assignment with full details for get. */\nexport function findAssignmentWithDetails(id: string) {\n return prisma.assignment.findUnique({\n where: { id },\n include: assignmentGetInclude,\n });\n}\n\n/** @returns Assignment with attachments for delete. */\nexport function findAssignmentForDelete(id: string, teacherId: string) {\n return prisma.assignment.findFirst({\n where: {\n id,\n OR: [\n { teacherId },\n { class: schoolAdminForClassWhere(teacherId) },\n ],\n },\n include: {\n attachments: { include: { thumbnail: true } },\n submissions: {\n include: {\n attachments: { include: { thumbnail: true } },\n annotations: { include: { thumbnail: true } },\n },\n },\n },\n });\n}\n\n/** @returns Assignments due today. */\nexport function findAssignmentsDueToday() {\n return prisma.assignment.findMany({\n where: {\n dueDate: { equals: new Date() },\n },\n select: {\n id: true,\n title: true,\n dueDate: true,\n type: true,\n graded: true,\n maxGrade: true,\n class: { select: { id: true, name: true } },\n },\n });\n}\n\n/** @returns Submission by assignment and student. */\nexport function findSubmissionByAssignmentAndStudent(assignmentId: string, studentId: string) {\n return prisma.submission.findFirst({\n where: { assignmentId, studentId },\n include: {\n attachments: true,\n student: { select: { id: true, username: true, profile: true } },\n assignment: {\n include: {\n class: true,\n markScheme: { select: { id: true, structured: true } },\n worksheets: { select: { id: true, name: true } },\n gradingBoundary: { select: { id: true, structured: true } },\n },\n },\n annotations: true,\n },\n });\n}\n\n/** @returns Submission by ID for class member. */\nexport function findSubmissionByIdForClassMember(submissionId: string, classId: string, userId: string) {\n return prisma.submission.findFirst({\n where: {\n id: submissionId,\n assignment: {\n classId,\n class: classMemberOrSchoolAdminWhere(userId),\n },\n },\n include: {\n attachments: true,\n annotations: true,\n student: { select: { id: true, username: true, profile: true } },\n assignment: {\n include: {\n class: true,\n markScheme: { select: { id: true, structured: true } },\n worksheets: { select: { id: true, name: true } },\n gradingBoundary: { select: { id: true, structured: true } },\n },\n },\n },\n });\n}\n\n/** @returns Submission by ID for update (student or teacher). */\nexport function findSubmissionForUpdate(submissionId: string, userId: string) {\n return prisma.submission.findFirst({\n where: {\n id: submissionId,\n OR: [\n { studentId: userId },\n {\n assignment: {\n class: classTeacherOrSchoolAdminWhere(userId),\n },\n },\n ],\n },\n include: {\n attachments: { include: { thumbnail: true } },\n assignment: {\n include: {\n class: true,\n markScheme: { select: { id: true, structured: true } },\n gradingBoundary: { select: { id: true, structured: true } },\n },\n },\n },\n });\n}\n\n/** Create a submission. */\nexport function createSubmission(assignmentId: string, studentId: string) {\n return prisma.submission.create({\n data: {\n assignment: { connect: { id: assignmentId } },\n student: { connect: { id: studentId } },\n },\n include: {\n attachments: true,\n annotations: true,\n student: { select: { id: true, username: true } },\n assignment: {\n include: {\n class: true,\n markScheme: { select: { id: true, structured: true } },\n worksheets: { select: { id: true, name: true } },\n gradingBoundary: { select: { id: true, structured: true } },\n },\n },\n },\n });\n}\n\n/** @returns Sections for a class. */\nexport function findSectionsByClassId(classId: string) {\n return prisma.section.findMany({\n where: { classId },\n select: { id: true, name: true },\n });\n}\n\n/** @returns Assignment with class for teacher (auth check). */\nexport function findAssignmentWithClassForTeacher(assignmentId: string, teacherId: string) {\n return prisma.assignment.findFirst({\n where: {\n id: assignmentId,\n class: classTeacherOrSchoolAdminWhere(teacherId),\n },\n include: { class: true },\n });\n}\n\n/**\n * Clone an assignment into another class with a new title: copies settings, duplicates linked\n * worksheets into the target class, clones attachment file records (same storage path),\n * creates empty submissions for all students in the target class, and does not copy the\n * calendar event link or per-student “assigned to” overrides.\n */\nexport async function duplicateAssignment(\n sourceAssignmentId: string,\n targetClassId: string,\n title: string,\n duplicatingUserId: string\n) {\n return prisma.$transaction(\n async (tx) => {\n const source = await tx.assignment.findUnique({\n where: { id: sourceAssignmentId },\n include: {\n worksheets: { select: { id: true, name: true } },\n attachments: {\n select: { name: true, type: true, size: true, path: true },\n },\n section: { select: { id: true, name: true } },\n },\n });\n\n if (!source) {\n return null;\n }\n\n let targetSectionId: string | undefined;\n if (source.sectionId && source.section) {\n const match = await tx.section.findFirst({\n where: { classId: targetClassId, name: source.section.name },\n select: { id: true },\n });\n targetSectionId = match?.id;\n }\n\n const newWorksheetIds: string[] = [];\n for (const ws of source.worksheets) {\n const dup = await duplicateWorksheetWithClient(\n tx,\n ws.id,\n targetClassId,\n ws.name\n );\n if (dup) {\n newWorksheetIds.push(dup.id);\n }\n }\n\n const classData = await tx.class.findUnique({\n where: { id: targetClassId },\n include: { students: { select: { id: true } } },\n });\n if (!classData) {\n return null;\n }\n\n const submissionData = classData.students.map((s) => ({\n student: { connect: { id: s.id } },\n }));\n\n const created = await tx.assignment.create({\n data: {\n title,\n instructions: source.instructions,\n dueDate: source.dueDate,\n teacher: { connect: { id: duplicatingUserId } },\n class: { connect: { id: targetClassId } },\n acceptFiles: source.acceptFiles,\n acceptExtendedResponse: source.acceptExtendedResponse,\n acceptWorksheet: source.acceptWorksheet,\n gradeWithAI: source.gradeWithAI,\n aiPolicyLevel: source.aiPolicyLevel,\n graded: source.graded,\n maxGrade: source.maxGrade,\n weight: source.weight,\n type: source.type,\n inProgress: source.inProgress,\n template: source.template,\n ...(source.markSchemeId && {\n markScheme: { connect: { id: source.markSchemeId } },\n }),\n ...(source.gradingBoundaryId && {\n gradingBoundary: { connect: { id: source.gradingBoundaryId } },\n }),\n ...(targetSectionId && {\n section: { connect: { id: targetSectionId } },\n }),\n ...(newWorksheetIds.length > 0 && {\n worksheets: { connect: newWorksheetIds.map((id) => ({ id })) },\n }),\n submissions: { create: submissionData },\n order: 0,\n },\n });\n\n await tx.assignment.updateMany({\n where: { classId: targetClassId, id: { not: created.id } },\n data: { order: { increment: 1 } },\n });\n await tx.section.updateMany({\n where: { classId: targetClassId },\n data: { order: { increment: 1 } },\n });\n await tx.assignment.update({\n where: { id: created.id },\n data: { order: 1 },\n });\n\n for (const file of source.attachments) {\n await tx.file.create({\n data: {\n name: file.name,\n type: file.type,\n size: file.size ?? 0,\n path: file.path,\n uploadStatus: \"COMPLETED\",\n user: { connect: { id: duplicatingUserId } },\n assignment: { connect: { id: created.id } },\n },\n });\n }\n\n return created;\n },\n { maxWait: 10000, timeout: 60000 }\n );\n}\n\n/** @returns Submissions for assignment (teacher view). */\nexport function findSubmissionsByAssignmentForTeacher(assignmentId: string, teacherId: string) {\n return prisma.submission.findMany({\n where: {\n assignment: {\n id: assignmentId,\n class: classTeacherOrSchoolAdminWhere(teacherId),\n },\n },\n include: {\n attachments: { include: { thumbnail: true } },\n student: {\n select: {\n id: true,\n username: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n profilePictureThumbnail: true,\n },\n },\n },\n },\n assignment: {\n include: {\n class: true,\n markScheme: { select: { id: true, structured: true } },\n gradingBoundary: { select: { id: true, structured: true } },\n },\n },\n },\n });\n}\n\n/** @returns Submission by ID for teacher update. */\nexport function findSubmissionForTeacherUpdate(submissionId: string, teacherId: string) {\n return prisma.submission.findFirst({\n where: {\n id: submissionId,\n assignment: {\n class: classTeacherOrSchoolAdminWhere(teacherId),\n },\n },\n include: {\n attachments: { include: { thumbnail: true } },\n annotations: { include: { thumbnail: true } },\n assignment: {\n include: {\n class: true,\n markScheme: { select: { id: true, structured: true } },\n gradingBoundary: { select: { id: true, structured: true } },\n },\n },\n },\n });\n}\n\n/** @returns Events in class that don't have this assignment attached. */\nexport function findAvailableEventsForAssignment(classId: string, assignmentId: string) {\n return prisma.event.findMany({\n where: {\n classId,\n assignmentsAttached: { none: { id: assignmentId } },\n },\n select: {\n id: true,\n name: true,\n startTime: true,\n endTime: true,\n location: true,\n remarks: true,\n color: true,\n },\n orderBy: { startTime: \"asc\" },\n });\n}\n\nconst assignmentAttachEventInclude = {\n attachments: { select: { id: true, name: true, type: true } },\n section: { select: { id: true, name: true } },\n teacher: { select: { id: true, username: true } },\n eventAttached: {\n select: {\n id: true,\n name: true,\n startTime: true,\n endTime: true,\n color: true,\n },\n },\n};\n\n/** Attach assignment to event. */\nexport function attachAssignmentToEvent(assignmentId: string, eventId: string) {\n return prisma.assignment.update({\n where: { id: assignmentId },\n data: { eventAttached: { connect: { id: eventId } } },\n include: assignmentAttachEventInclude,\n });\n}\n\n/** Detach assignment from event. */\nexport function detachAssignmentFromEvent(assignmentId: string) {\n return prisma.assignment.update({\n where: { id: assignmentId },\n data: { eventAttached: { disconnect: true } },\n include: assignmentAttachEventInclude,\n });\n}\n"],"names":[],"mappings":"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","debug_id":"d97b0aba-efb0-533e-b942-06f6eb24b6d0"}
|
package/dist/models/auth.d.ts
CHANGED
|
@@ -53,6 +53,7 @@ export declare function findUserByEmail(email: string): import(".prisma/client")
|
|
|
53
53
|
export declare function findUserById(id: string): import(".prisma/client").Prisma.Prisma__UserClient<{
|
|
54
54
|
id: string;
|
|
55
55
|
username: string;
|
|
56
|
+
email: string;
|
|
56
57
|
profile: {
|
|
57
58
|
location: string | null;
|
|
58
59
|
displayName: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"/","sources":["models/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAuB7C,+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
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"/","sources":["models/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAuB7C,+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;;;;;;;;;;;;;;;;;;GAmBtC;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;;KAKxD;AAED,oDAAoD;AACpD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;;;;;;;;;;GAOlE;AAED,2DAA2D;AAC3D,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;;;;;;;;;;;;GAOtE"}
|
package/dist/models/auth.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
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]="e3101e01-922b-52d7-b98a-a20d1623f1be")}catch(e){}}();
|
|
7
7
|
import { SessionType } from "@prisma/client";
|
|
8
8
|
import { getRedis } from "../lib/redis.js";
|
|
9
9
|
import { prisma } from "../lib/prisma.js";
|
|
@@ -73,6 +73,7 @@ export function findUserById(id) {
|
|
|
73
73
|
select: {
|
|
74
74
|
id: true,
|
|
75
75
|
username: true,
|
|
76
|
+
email: true,
|
|
76
77
|
profile: {
|
|
77
78
|
select: {
|
|
78
79
|
displayName: true,
|
|
@@ -233,4 +234,4 @@ export function findClassWithTeacher(classId, teacherId) {
|
|
|
233
234
|
});
|
|
234
235
|
}
|
|
235
236
|
//# sourceMappingURL=auth.js.map
|
|
236
|
-
//# debugId=
|
|
237
|
+
//# debugId=e3101e01-922b-52d7-b98a-a20d1623f1be
|