@studious-lms/server 1.24.0 → 1.26.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/data/curriculum/nepal-cdc-g4-g5/subjects/english.json +4 -4
- package/data/curriculum/nepal-cdc-g4-g5/subjects/mathematics.json +1 -1
- package/data/curriculum/nepal-cdc-g4-g5/subjects/science-technology.json +4 -4
- package/data/curriculum/nepal-cdc-g4-g5/subjects/social-studies.json +4 -4
- package/dist/models/attendance.d.ts.map +1 -1
- package/dist/models/attendance.js +17 -14
- package/dist/models/attendance.js.map +1 -1
- package/dist/models/marketplace.d.ts +37 -0
- package/dist/models/marketplace.d.ts.map +1 -1
- package/dist/models/marketplace.js +10 -2
- package/dist/models/marketplace.js.map +1 -1
- package/dist/models/module.d.ts +228 -0
- package/dist/models/module.d.ts.map +1 -0
- package/dist/models/module.js +69 -0
- package/dist/models/module.js.map +1 -0
- package/dist/models/moduleItem.d.ts +5 -1
- package/dist/models/moduleItem.d.ts.map +1 -1
- package/dist/models/moduleItem.js +19 -4
- package/dist/models/moduleItem.js.map +1 -1
- package/dist/pipelines/gradeWorksheet.d.ts.map +1 -1
- package/dist/pipelines/gradeWorksheet.js +4 -2
- package/dist/pipelines/gradeWorksheet.js.map +1 -1
- package/dist/routers/_app.d.ts +768 -6
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +4 -2
- package/dist/routers/_app.js.map +1 -1
- package/dist/routers/fees.d.ts +1 -1
- package/dist/routers/marketplace.d.ts +41 -0
- package/dist/routers/marketplace.d.ts.map +1 -1
- package/dist/routers/marketplace.js +13 -3
- package/dist/routers/marketplace.js.map +1 -1
- package/dist/routers/module.d.ts +345 -0
- package/dist/routers/module.d.ts.map +1 -0
- package/dist/routers/module.js +82 -0
- package/dist/routers/module.js.map +1 -0
- package/dist/routers/moduleItem.d.ts.map +1 -1
- package/dist/routers/moduleItem.js +7 -6
- package/dist/routers/moduleItem.js.map +1 -1
- package/dist/routers/parent.d.ts +2 -1
- package/dist/routers/parent.d.ts.map +1 -1
- package/dist/routers/school.d.ts +1 -1
- package/dist/routers/school.d.ts.map +1 -1
- package/dist/routers/school.js +14 -4
- package/dist/routers/school.js.map +1 -1
- package/dist/services/academicCalendar.d.ts.map +1 -1
- package/dist/services/academicCalendar.js +30 -2
- package/dist/services/academicCalendar.js.map +1 -1
- package/dist/services/assignment.d.ts.map +1 -1
- package/dist/services/assignment.js +8 -3
- package/dist/services/assignment.js.map +1 -1
- package/dist/services/attendance.d.ts +6 -2
- package/dist/services/attendance.d.ts.map +1 -1
- package/dist/services/attendance.js +8 -4
- package/dist/services/attendance.js.map +1 -1
- package/dist/services/class.d.ts +14 -9
- package/dist/services/class.d.ts.map +1 -1
- package/dist/services/class.js +4 -4
- package/dist/services/class.js.map +1 -1
- package/dist/services/fees.d.ts.map +1 -1
- package/dist/services/fees.js +24 -4
- package/dist/services/fees.js.map +1 -1
- package/dist/services/feesAuthz.d.ts +2 -5
- package/dist/services/feesAuthz.d.ts.map +1 -1
- package/dist/services/feesAuthz.js +5 -8
- package/dist/services/feesAuthz.js.map +1 -1
- package/dist/services/marketplace.d.ts +36 -0
- package/dist/services/marketplace.d.ts.map +1 -1
- package/dist/services/marketplace.js +36 -6
- package/dist/services/marketplace.js.map +1 -1
- package/dist/services/module.d.ts +288 -0
- package/dist/services/module.d.ts.map +1 -0
- package/dist/services/module.js +518 -0
- package/dist/services/module.js.map +1 -0
- package/dist/services/moduleItem.d.ts.map +1 -1
- package/dist/services/moduleItem.js +23 -7
- package/dist/services/moduleItem.js.map +1 -1
- package/dist/services/parentPortal.d.ts +3 -5
- package/dist/services/parentPortal.d.ts.map +1 -1
- package/dist/services/parentPortal.js +29 -43
- package/dist/services/parentPortal.js.map +1 -1
- package/dist/services/school.d.ts.map +1 -1
- package/dist/services/school.js +52 -16
- package/dist/services/school.js.map +1 -1
- package/dist/services/studentImport.d.ts.map +1 -1
- package/dist/services/studentImport.js +38 -25
- package/dist/services/studentImport.js.map +1 -1
- package/dist/services/transcript.d.ts +2 -3
- package/dist/services/transcript.d.ts.map +1 -1
- package/dist/services/transcript.js +13 -25
- package/dist/services/transcript.js.map +1 -1
- package/package.json +1 -1
- package/prisma/migrations/20260708013000_add_modules/migration.sql +100 -0
- package/prisma/schema.prisma +93 -0
- package/scripts/import-nepal-cdc-curriculum.ts +29 -6
- package/src/models/attendance.ts +10 -12
- package/src/models/marketplace.ts +19 -0
- package/src/models/module.ts +77 -0
- package/src/models/moduleItem.ts +20 -2
- package/src/pipelines/gradeWorksheet.ts +6 -0
- package/src/routers/_app.ts +2 -0
- package/src/routers/marketplace.ts +16 -0
- package/src/routers/module.ts +118 -0
- package/src/routers/moduleItem.ts +6 -4
- package/src/routers/school.ts +16 -6
- package/src/services/academicCalendar.ts +28 -0
- package/src/services/assignment.ts +12 -1
- package/src/services/attendance.ts +7 -3
- package/src/services/class.ts +2 -2
- package/src/services/fees.ts +25 -2
- package/src/services/feesAuthz.ts +3 -7
- package/src/services/marketplace.ts +47 -3
- package/src/services/module.ts +683 -0
- package/src/services/moduleItem.ts +28 -4
- package/src/services/parentPortal.ts +26 -39
- package/src/services/school.ts +52 -15
- package/src/services/studentImport.ts +37 -25
- package/src/services/transcript.ts +11 -23
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* ModuleItem service – Canvas-style class content (pages, file packs, videos).
|
|
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]="12a2a128-6cfd-5abf-8cc1-da7dcbaf76f8")}catch(e){}}();
|
|
6
6
|
import { TRPCError } from "@trpc/server";
|
|
7
7
|
import { prisma } from "../lib/prisma.js";
|
|
8
|
-
import { attachFilesToModuleItem, createModuleItem, deleteModuleItem, findModuleItemByIdForMember, findModuleItemByIdForTeacher, findModuleItemsByClassId, findModuleItemsBySectionId, updateModuleItem, } from "../models/moduleItem.js";
|
|
8
|
+
import { attachFilesToModuleItem, createModuleItem, findAccessibleFilesByIds, deleteModuleItem, findModuleItemByIdForMember, findModuleItemByIdForTeacher, findModuleItemsByClassId, findModuleItemsBySectionId, updateModuleItem, } from "../models/moduleItem.js";
|
|
9
9
|
import { classTeacherOrSchoolAdminWhere } from "../models/access.js";
|
|
10
10
|
import { createDirectUploadFiles } from "../lib/fileUpload.js";
|
|
11
11
|
const VIDEO_MIME_PREFIX = "video/";
|
|
@@ -20,6 +20,16 @@ function assertVideoFiles(type, files) {
|
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
async function resolveExistingFiles(type, existingFileIds, userId) {
|
|
24
|
+
const accessible = await findAccessibleFilesByIds(existingFileIds, userId);
|
|
25
|
+
if (accessible.length !== new Set(existingFileIds).size) {
|
|
26
|
+
throw new TRPCError({
|
|
27
|
+
code: "FORBIDDEN",
|
|
28
|
+
message: "One or more files are not accessible",
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
assertVideoFiles(type, accessible);
|
|
32
|
+
}
|
|
23
33
|
async function assertTeacherOwnsSection(sectionId, userId) {
|
|
24
34
|
const section = await prisma.section.findFirst({
|
|
25
35
|
where: {
|
|
@@ -109,6 +119,9 @@ export async function createModuleItemRecord(userId, input) {
|
|
|
109
119
|
// Allow empty collection; files attach later via upload URLs.
|
|
110
120
|
}
|
|
111
121
|
assertVideoFiles(input.type, input.files);
|
|
122
|
+
if (input.existingFileIds?.length) {
|
|
123
|
+
await resolveExistingFiles(input.type, input.existingFileIds, userId);
|
|
124
|
+
}
|
|
112
125
|
const maxOrder = await prisma.moduleItem.aggregate({
|
|
113
126
|
where: { sectionId: input.sectionId },
|
|
114
127
|
_max: { order: true },
|
|
@@ -123,12 +136,12 @@ export async function createModuleItemRecord(userId, input) {
|
|
|
123
136
|
published: input.published ?? true,
|
|
124
137
|
});
|
|
125
138
|
if (input.existingFileIds?.length) {
|
|
126
|
-
await attachFilesToModuleItem(created.id, input.existingFileIds);
|
|
139
|
+
await attachFilesToModuleItem(created.id, input.existingFileIds, userId);
|
|
127
140
|
}
|
|
128
141
|
let uploadFiles = [];
|
|
129
142
|
if (input.files?.length) {
|
|
130
143
|
uploadFiles = await createDirectUploadFiles(input.files, userId, undefined, undefined, undefined);
|
|
131
|
-
await attachFilesToModuleItem(created.id, uploadFiles.map((f) => f.id));
|
|
144
|
+
await attachFilesToModuleItem(created.id, uploadFiles.map((f) => f.id), userId);
|
|
132
145
|
}
|
|
133
146
|
const refreshed = await findModuleItemByIdForTeacher(created.id, userId);
|
|
134
147
|
return { item: refreshed ?? created, uploadFiles };
|
|
@@ -143,6 +156,9 @@ export async function updateModuleItemRecord(userId, input) {
|
|
|
143
156
|
}
|
|
144
157
|
const nextType = input.type ?? existing.type;
|
|
145
158
|
assertVideoFiles(nextType, input.files);
|
|
159
|
+
if (input.existingFileIds?.length) {
|
|
160
|
+
await resolveExistingFiles(nextType, input.existingFileIds, userId);
|
|
161
|
+
}
|
|
146
162
|
if (input.sectionId && input.sectionId !== existing.sectionId) {
|
|
147
163
|
await assertTeacherOwnsSection(input.sectionId, userId);
|
|
148
164
|
}
|
|
@@ -155,12 +171,12 @@ export async function updateModuleItemRecord(userId, input) {
|
|
|
155
171
|
order: input.order,
|
|
156
172
|
});
|
|
157
173
|
if (input.existingFileIds?.length) {
|
|
158
|
-
await attachFilesToModuleItem(input.id, input.existingFileIds);
|
|
174
|
+
await attachFilesToModuleItem(input.id, input.existingFileIds, userId);
|
|
159
175
|
}
|
|
160
176
|
let uploadFiles = [];
|
|
161
177
|
if (input.files?.length) {
|
|
162
178
|
uploadFiles = await createDirectUploadFiles(input.files, userId, undefined, undefined, undefined);
|
|
163
|
-
await attachFilesToModuleItem(input.id, uploadFiles.map((f) => f.id));
|
|
179
|
+
await attachFilesToModuleItem(input.id, uploadFiles.map((f) => f.id), userId);
|
|
164
180
|
}
|
|
165
181
|
const refreshed = await findModuleItemByIdForTeacher(input.id, userId);
|
|
166
182
|
return { item: refreshed ?? updated, uploadFiles };
|
|
@@ -185,4 +201,4 @@ export async function reorderModuleItems(userId, input) {
|
|
|
185
201
|
return findModuleItemsBySectionId(input.sectionId);
|
|
186
202
|
}
|
|
187
203
|
//# sourceMappingURL=moduleItem.js.map
|
|
188
|
-
//# debugId=
|
|
204
|
+
//# debugId=12a2a128-6cfd-5abf-8cc1-da7dcbaf76f8
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"moduleItem.js","sources":["services/moduleItem.ts"],"sourceRoot":"/","sourcesContent":["/**\n * ModuleItem service – Canvas-style class content (pages, file packs, videos).\n */\nimport { TRPCError } from \"@trpc/server\";\nimport type { ModuleItemType } from \"@prisma/client\";\nimport { prisma } from \"../lib/prisma.js\";\nimport {\n attachFilesToModuleItem,\n createModuleItem,\n deleteModuleItem,\n findModuleItemByIdForMember,\n findModuleItemByIdForTeacher,\n findModuleItemsByClassId,\n findModuleItemsBySectionId,\n updateModuleItem,\n} from \"../models/moduleItem.js\";\nimport { classTeacherOrSchoolAdminWhere } from \"../models/access.js\";\nimport { createDirectUploadFiles } from \"../lib/fileUpload.js\";\n\nconst VIDEO_MIME_PREFIX = \"video/\";\n\nfunction assertVideoFiles(\n type: ModuleItemType,\n files?: { type: string }[]\n) {\n if (type !== \"VIDEO\" || !files?.length) return;\n const invalid = files.filter((f) => !f.type.startsWith(VIDEO_MIME_PREFIX));\n if (invalid.length > 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"VIDEO module items only accept video MIME types\",\n });\n }\n}\n\nasync function assertTeacherOwnsSection(sectionId: string, userId: string) {\n const section = await prisma.section.findFirst({\n where: {\n id: sectionId,\n class: classTeacherOrSchoolAdminWhere(userId),\n },\n select: { id: true, classId: true },\n });\n if (!section) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can manage module items\",\n });\n }\n return section;\n}\n\nexport async function listModuleItemsForClass(classId: string, userId: string) {\n const membership = await prisma.class.findFirst({\n where: {\n id: classId,\n OR: [\n { teachers: { some: { id: userId } } },\n { students: { some: { id: userId } } },\n ],\n },\n select: { id: true },\n });\n if (!membership) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Not a class member\" });\n }\n const items = await findModuleItemsByClassId(classId);\n const isTeacher = await prisma.class.findFirst({\n where: { id: classId, ...classTeacherOrSchoolAdminWhere(userId) },\n select: { id: true },\n });\n if (isTeacher) return items;\n return items.filter((item) => item.published);\n}\n\nexport async function listModuleItemsForSection(\n sectionId: string,\n userId: string\n) {\n const section = await prisma.section.findFirst({\n where: {\n id: sectionId,\n class: {\n OR: [\n { teachers: { some: { id: userId } } },\n { students: { some: { id: userId } } },\n ],\n },\n },\n select: { id: true, classId: true },\n });\n if (!section) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Not a class member\" });\n }\n const items = await findModuleItemsBySectionId(sectionId);\n const isTeacher = await prisma.class.findFirst({\n where: {\n id: section.classId,\n ...classTeacherOrSchoolAdminWhere(userId),\n },\n select: { id: true },\n });\n if (isTeacher) return items;\n return items.filter((item) => item.published);\n}\n\nexport async function getModuleItem(id: string, userId: string) {\n const item = await findModuleItemByIdForMember(id, userId);\n if (!item) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module item not found\" });\n }\n const isTeacher = await findModuleItemByIdForTeacher(id, userId);\n if (!item.published && !isTeacher) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module item not found\" });\n }\n return item;\n}\n\nexport async function createModuleItemRecord(\n userId: string,\n input: {\n sectionId: string;\n title: string;\n type: ModuleItemType;\n body?: string | null;\n published?: boolean;\n files?: { name: string; type: string; size: number }[];\n existingFileIds?: string[];\n }\n) {\n await assertTeacherOwnsSection(input.sectionId, userId);\n\n if (input.type === \"PAGE\" && !input.body && !input.files?.length) {\n // Allow empty page draft; body can be filled later.\n }\n if (\n (input.type === \"FILES\" || input.type === \"VIDEO\") &&\n !input.files?.length &&\n !input.existingFileIds?.length\n ) {\n // Allow empty collection; files attach later via upload URLs.\n }\n\n assertVideoFiles(input.type, input.files);\n\n const maxOrder = await prisma.moduleItem.aggregate({\n where: { sectionId: input.sectionId },\n _max: { order: true },\n });\n const order = (maxOrder._max.order ?? 0) + 1;\n\n const created = await createModuleItem({\n sectionId: input.sectionId,\n title: input.title,\n type: input.type,\n body: input.type === \"PAGE\" ? input.body ?? \"\" : input.body,\n order,\n published: input.published ?? true,\n });\n\n if (input.existingFileIds?.length) {\n await attachFilesToModuleItem(created.id, input.existingFileIds);\n }\n\n let uploadFiles: Awaited<ReturnType<typeof createDirectUploadFiles>> = [];\n if (input.files?.length) {\n uploadFiles = await createDirectUploadFiles(\n input.files,\n userId,\n undefined,\n undefined,\n undefined\n );\n await attachFilesToModuleItem(\n created.id,\n uploadFiles.map((f) => f.id)\n );\n }\n\n const refreshed = await findModuleItemByIdForTeacher(created.id, userId);\n return { item: refreshed ?? created, uploadFiles };\n}\n\nexport async function updateModuleItemRecord(\n userId: string,\n input: {\n id: string;\n title?: string;\n body?: string | null;\n published?: boolean;\n type?: ModuleItemType;\n sectionId?: string;\n order?: number | null;\n existingFileIds?: string[];\n files?: { name: string; type: string; size: number }[];\n }\n) {\n const existing = await findModuleItemByIdForTeacher(input.id, userId);\n if (!existing) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can update module items\",\n });\n }\n\n const nextType = input.type ?? existing.type;\n assertVideoFiles(nextType, input.files);\n\n if (input.sectionId && input.sectionId !== existing.sectionId) {\n await assertTeacherOwnsSection(input.sectionId, userId);\n }\n\n const updated = await updateModuleItem(input.id, {\n title: input.title,\n body: input.body,\n published: input.published,\n type: input.type,\n sectionId: input.sectionId,\n order: input.order,\n });\n\n if (input.existingFileIds?.length) {\n await attachFilesToModuleItem(input.id, input.existingFileIds);\n }\n\n let uploadFiles: Awaited<ReturnType<typeof createDirectUploadFiles>> = [];\n if (input.files?.length) {\n uploadFiles = await createDirectUploadFiles(\n input.files,\n userId,\n undefined,\n undefined,\n undefined\n );\n await attachFilesToModuleItem(\n input.id,\n uploadFiles.map((f) => f.id)\n );\n }\n\n const refreshed = await findModuleItemByIdForTeacher(input.id, userId);\n return { item: refreshed ?? updated, uploadFiles };\n}\n\nexport async function deleteModuleItemRecord(userId: string, id: string) {\n const existing = await findModuleItemByIdForTeacher(id, userId);\n if (!existing) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can delete module items\",\n });\n }\n await deleteModuleItem(id);\n return { success: true };\n}\n\nexport async function reorderModuleItems(\n userId: string,\n input: {\n sectionId: string;\n orderedIds: string[];\n }\n) {\n await assertTeacherOwnsSection(input.sectionId, userId);\n await prisma.$transaction(\n input.orderedIds.map((id, index) =>\n prisma.moduleItem.updateMany({\n where: { id, sectionId: input.sectionId },\n data: { order: index + 1 },\n })\n )\n );\n return findModuleItemsBySectionId(input.sectionId);\n}\n"],"names":[],"mappings":"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","debug_id":"59adfd77-e2d9-5f75-9467-06605b2ddc77"}
|
|
1
|
+
{"version":3,"file":"moduleItem.js","sources":["services/moduleItem.ts"],"sourceRoot":"/","sourcesContent":["/**\n * ModuleItem service – Canvas-style class content (pages, file packs, videos).\n */\nimport { TRPCError } from \"@trpc/server\";\nimport type { ModuleItemType } from \"@prisma/client\";\nimport { prisma } from \"../lib/prisma.js\";\nimport {\n attachFilesToModuleItem,\n createModuleItem,\n findAccessibleFilesByIds,\n deleteModuleItem,\n findModuleItemByIdForMember,\n findModuleItemByIdForTeacher,\n findModuleItemsByClassId,\n findModuleItemsBySectionId,\n updateModuleItem,\n} from \"../models/moduleItem.js\";\nimport { classTeacherOrSchoolAdminWhere } from \"../models/access.js\";\nimport { createDirectUploadFiles } from \"../lib/fileUpload.js\";\n\nconst VIDEO_MIME_PREFIX = \"video/\";\n\nfunction assertVideoFiles(\n type: ModuleItemType,\n files?: { type: string }[]\n) {\n if (type !== \"VIDEO\" || !files?.length) return;\n const invalid = files.filter((f) => !f.type.startsWith(VIDEO_MIME_PREFIX));\n if (invalid.length > 0) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"VIDEO module items only accept video MIME types\",\n });\n }\n}\n\nasync function resolveExistingFiles(\n type: ModuleItemType,\n existingFileIds: string[],\n userId: string\n) {\n const accessible = await findAccessibleFilesByIds(existingFileIds, userId);\n if (accessible.length !== new Set(existingFileIds).size) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"One or more files are not accessible\",\n });\n }\n assertVideoFiles(type, accessible);\n}\n\nasync function assertTeacherOwnsSection(sectionId: string, userId: string) {\n const section = await prisma.section.findFirst({\n where: {\n id: sectionId,\n class: classTeacherOrSchoolAdminWhere(userId),\n },\n select: { id: true, classId: true },\n });\n if (!section) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can manage module items\",\n });\n }\n return section;\n}\n\nexport async function listModuleItemsForClass(classId: string, userId: string) {\n const membership = await prisma.class.findFirst({\n where: {\n id: classId,\n OR: [\n { teachers: { some: { id: userId } } },\n { students: { some: { id: userId } } },\n ],\n },\n select: { id: true },\n });\n if (!membership) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Not a class member\" });\n }\n const items = await findModuleItemsByClassId(classId);\n const isTeacher = await prisma.class.findFirst({\n where: { id: classId, ...classTeacherOrSchoolAdminWhere(userId) },\n select: { id: true },\n });\n if (isTeacher) return items;\n return items.filter((item) => item.published);\n}\n\nexport async function listModuleItemsForSection(\n sectionId: string,\n userId: string\n) {\n const section = await prisma.section.findFirst({\n where: {\n id: sectionId,\n class: {\n OR: [\n { teachers: { some: { id: userId } } },\n { students: { some: { id: userId } } },\n ],\n },\n },\n select: { id: true, classId: true },\n });\n if (!section) {\n throw new TRPCError({ code: \"FORBIDDEN\", message: \"Not a class member\" });\n }\n const items = await findModuleItemsBySectionId(sectionId);\n const isTeacher = await prisma.class.findFirst({\n where: {\n id: section.classId,\n ...classTeacherOrSchoolAdminWhere(userId),\n },\n select: { id: true },\n });\n if (isTeacher) return items;\n return items.filter((item) => item.published);\n}\n\nexport async function getModuleItem(id: string, userId: string) {\n const item = await findModuleItemByIdForMember(id, userId);\n if (!item) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module item not found\" });\n }\n const isTeacher = await findModuleItemByIdForTeacher(id, userId);\n if (!item.published && !isTeacher) {\n throw new TRPCError({ code: \"NOT_FOUND\", message: \"Module item not found\" });\n }\n return item;\n}\n\nexport async function createModuleItemRecord(\n userId: string,\n input: {\n sectionId: string;\n title: string;\n type: ModuleItemType;\n body?: string | null;\n published?: boolean;\n files?: { name: string; type: string; size: number }[];\n existingFileIds?: string[];\n }\n) {\n await assertTeacherOwnsSection(input.sectionId, userId);\n\n if (input.type === \"PAGE\" && !input.body && !input.files?.length) {\n // Allow empty page draft; body can be filled later.\n }\n if (\n (input.type === \"FILES\" || input.type === \"VIDEO\") &&\n !input.files?.length &&\n !input.existingFileIds?.length\n ) {\n // Allow empty collection; files attach later via upload URLs.\n }\n\n assertVideoFiles(input.type, input.files);\n if (input.existingFileIds?.length) {\n await resolveExistingFiles(input.type, input.existingFileIds, userId);\n }\n\n const maxOrder = await prisma.moduleItem.aggregate({\n where: { sectionId: input.sectionId },\n _max: { order: true },\n });\n const order = (maxOrder._max.order ?? 0) + 1;\n\n const created = await createModuleItem({\n sectionId: input.sectionId,\n title: input.title,\n type: input.type,\n body: input.type === \"PAGE\" ? input.body ?? \"\" : input.body,\n order,\n published: input.published ?? true,\n });\n\n if (input.existingFileIds?.length) {\n await attachFilesToModuleItem(created.id, input.existingFileIds, userId);\n }\n\n let uploadFiles: Awaited<ReturnType<typeof createDirectUploadFiles>> = [];\n if (input.files?.length) {\n uploadFiles = await createDirectUploadFiles(\n input.files,\n userId,\n undefined,\n undefined,\n undefined\n );\n await attachFilesToModuleItem(\n created.id,\n uploadFiles.map((f) => f.id),\n userId\n );\n }\n\n const refreshed = await findModuleItemByIdForTeacher(created.id, userId);\n return { item: refreshed ?? created, uploadFiles };\n}\n\nexport async function updateModuleItemRecord(\n userId: string,\n input: {\n id: string;\n title?: string;\n body?: string | null;\n published?: boolean;\n type?: ModuleItemType;\n sectionId?: string;\n order?: number | null;\n existingFileIds?: string[];\n files?: { name: string; type: string; size: number }[];\n }\n) {\n const existing = await findModuleItemByIdForTeacher(input.id, userId);\n if (!existing) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can update module items\",\n });\n }\n\n const nextType = input.type ?? existing.type;\n assertVideoFiles(nextType, input.files);\n if (input.existingFileIds?.length) {\n await resolveExistingFiles(nextType, input.existingFileIds, userId);\n }\n\n if (input.sectionId && input.sectionId !== existing.sectionId) {\n await assertTeacherOwnsSection(input.sectionId, userId);\n }\n\n const updated = await updateModuleItem(input.id, {\n title: input.title,\n body: input.body,\n published: input.published,\n type: input.type,\n sectionId: input.sectionId,\n order: input.order,\n });\n\n if (input.existingFileIds?.length) {\n await attachFilesToModuleItem(input.id, input.existingFileIds, userId);\n }\n\n let uploadFiles: Awaited<ReturnType<typeof createDirectUploadFiles>> = [];\n if (input.files?.length) {\n uploadFiles = await createDirectUploadFiles(\n input.files,\n userId,\n undefined,\n undefined,\n undefined\n );\n await attachFilesToModuleItem(\n input.id,\n uploadFiles.map((f) => f.id),\n userId\n );\n }\n\n const refreshed = await findModuleItemByIdForTeacher(input.id, userId);\n return { item: refreshed ?? updated, uploadFiles };\n}\n\nexport async function deleteModuleItemRecord(userId: string, id: string) {\n const existing = await findModuleItemByIdForTeacher(id, userId);\n if (!existing) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only class teachers can delete module items\",\n });\n }\n await deleteModuleItem(id);\n return { success: true };\n}\n\nexport async function reorderModuleItems(\n userId: string,\n input: {\n sectionId: string;\n orderedIds: string[];\n }\n) {\n await assertTeacherOwnsSection(input.sectionId, userId);\n await prisma.$transaction(\n input.orderedIds.map((id, index) =>\n prisma.moduleItem.updateMany({\n where: { id, sectionId: input.sectionId },\n data: { order: index + 1 },\n })\n )\n );\n return findModuleItemsBySectionId(input.sectionId);\n}\n"],"names":[],"mappings":"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","debug_id":"12a2a128-6cfd-5abf-8cc1-da7dcbaf76f8"}
|
|
@@ -70,10 +70,7 @@ export declare function listMyChildren(userId: string, schoolId: string): Promis
|
|
|
70
70
|
};
|
|
71
71
|
}[];
|
|
72
72
|
}>;
|
|
73
|
-
/**
|
|
74
|
-
* Read-only attendance stub for a linked child (aggregates class attendance M2M).
|
|
75
|
-
* Does not touch A1 AttendanceRecord refactor.
|
|
76
|
-
*/
|
|
73
|
+
/** Read-only attendance view for a linked child (reads AttendanceRecord). */
|
|
77
74
|
export declare function getChildAttendance(userId: string, input: {
|
|
78
75
|
schoolId: string;
|
|
79
76
|
studentUserId: string;
|
|
@@ -85,6 +82,7 @@ export declare function getChildAttendance(userId: string, input: {
|
|
|
85
82
|
present: number;
|
|
86
83
|
late: number;
|
|
87
84
|
absent: number;
|
|
85
|
+
excused: number;
|
|
88
86
|
total: number;
|
|
89
87
|
};
|
|
90
88
|
records: {
|
|
@@ -97,7 +95,7 @@ export declare function getChildAttendance(userId: string, input: {
|
|
|
97
95
|
name: string;
|
|
98
96
|
subject: string;
|
|
99
97
|
} | null;
|
|
100
|
-
status: "
|
|
98
|
+
status: import(".prisma/client").$Enums.AttendanceStatus;
|
|
101
99
|
}[];
|
|
102
100
|
}>;
|
|
103
101
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parentPortal.d.ts","sourceRoot":"/","sources":["services/parentPortal.ts"],"names":[],"mappings":"AAkCA,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE;;;;;;;;;GAiDzE;AAED,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE;;GAWzE;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;GA8B3E;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;;;;;;GAgDpE;AA0BD
|
|
1
|
+
{"version":3,"file":"parentPortal.d.ts","sourceRoot":"/","sources":["services/parentPortal.ts"],"names":[],"mappings":"AAkCA,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE;;;;;;;;;GAiDzE;AAED,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE;;GAWzE;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;GA8B3E;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;;;;;;GAgDpE;AA0BD,6EAA6E;AAC7E,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,EAAE,CAAC,EAAE,IAAI,CAAC;CACX;;;;;;;;;;;;;;;;;;;;GA2DF;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;GA8DrE;AAED,uEAAuE;AACvE,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,oBAatB"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* read-only attendance / grades stubs for linked children.
|
|
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]="e0a84844-f117-5700-89b0-1d460b45e236")}catch(e){}}();
|
|
7
7
|
import { TRPCError } from "@trpc/server";
|
|
8
8
|
import { prisma } from "../lib/prisma.js";
|
|
9
9
|
import { findActiveSchoolAdminMembership, findActiveSchoolMembership, findSchoolMembership, } from "../models/school.js";
|
|
@@ -177,10 +177,7 @@ async function assertParentOfStudent(schoolId, parentUserId, studentUserId) {
|
|
|
177
177
|
}
|
|
178
178
|
return link;
|
|
179
179
|
}
|
|
180
|
-
/**
|
|
181
|
-
* Read-only attendance stub for a linked child (aggregates class attendance M2M).
|
|
182
|
-
* Does not touch A1 AttendanceRecord refactor.
|
|
183
|
-
*/
|
|
180
|
+
/** Read-only attendance view for a linked child (reads AttendanceRecord). */
|
|
184
181
|
export async function getChildAttendance(userId, input) {
|
|
185
182
|
await assertParentOfStudent(input.schoolId, userId, input.studentUserId);
|
|
186
183
|
const classes = await prisma.class.findMany({
|
|
@@ -192,59 +189,48 @@ export async function getChildAttendance(userId, input) {
|
|
|
192
189
|
select: { id: true, name: true, subject: true, section: true },
|
|
193
190
|
});
|
|
194
191
|
const classIds = classes.map((c) => c.id);
|
|
195
|
-
const
|
|
192
|
+
const attendanceRecords = await prisma.attendanceRecord.findMany({
|
|
196
193
|
where: {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
{ absent: { some: { id: input.studentUserId } } },
|
|
210
|
-
],
|
|
194
|
+
studentId: input.studentUserId,
|
|
195
|
+
attendance: {
|
|
196
|
+
classId: { in: classIds },
|
|
197
|
+
...(input.from || input.to
|
|
198
|
+
? {
|
|
199
|
+
date: {
|
|
200
|
+
...(input.from ? { gte: input.from } : {}),
|
|
201
|
+
...(input.to ? { lte: input.to } : {}),
|
|
202
|
+
},
|
|
203
|
+
}
|
|
204
|
+
: {}),
|
|
205
|
+
},
|
|
211
206
|
},
|
|
212
207
|
select: {
|
|
213
|
-
|
|
214
|
-
date: true,
|
|
215
|
-
classId: true,
|
|
216
|
-
present: { where: { id: input.studentUserId }, select: { id: true } },
|
|
217
|
-
late: { where: { id: input.studentUserId }, select: { id: true } },
|
|
218
|
-
absent: { where: { id: input.studentUserId }, select: { id: true } },
|
|
208
|
+
status: true,
|
|
209
|
+
attendance: { select: { id: true, date: true, classId: true } },
|
|
219
210
|
},
|
|
220
|
-
orderBy: { date: "desc" },
|
|
211
|
+
orderBy: { attendance: { date: "desc" } },
|
|
221
212
|
take: 200,
|
|
222
213
|
});
|
|
223
214
|
const classMap = new Map(classes.map((c) => [c.id, c]));
|
|
224
|
-
const records =
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
attendanceId: row.id,
|
|
232
|
-
date: row.date,
|
|
233
|
-
classId: row.classId,
|
|
234
|
-
class: classMap.get(row.classId) ?? null,
|
|
235
|
-
status,
|
|
236
|
-
};
|
|
237
|
-
});
|
|
215
|
+
const records = attendanceRecords.map((row) => ({
|
|
216
|
+
attendanceId: row.attendance.id,
|
|
217
|
+
date: row.attendance.date,
|
|
218
|
+
classId: row.attendance.classId,
|
|
219
|
+
class: classMap.get(row.attendance.classId) ?? null,
|
|
220
|
+
status: row.status,
|
|
221
|
+
}));
|
|
238
222
|
const summary = records.reduce((acc, r) => {
|
|
239
223
|
acc.total += 1;
|
|
240
224
|
if (r.status === "PRESENT")
|
|
241
225
|
acc.present += 1;
|
|
242
226
|
else if (r.status === "LATE")
|
|
243
227
|
acc.late += 1;
|
|
228
|
+
else if (r.status === "EXCUSED")
|
|
229
|
+
acc.excused += 1;
|
|
244
230
|
else
|
|
245
231
|
acc.absent += 1;
|
|
246
232
|
return acc;
|
|
247
|
-
}, { present: 0, late: 0, absent: 0, total: 0 });
|
|
233
|
+
}, { present: 0, late: 0, absent: 0, excused: 0, total: 0 });
|
|
248
234
|
return { summary, records };
|
|
249
235
|
}
|
|
250
236
|
/**
|
|
@@ -325,4 +311,4 @@ export async function isParentOfStudent(schoolId, parentUserId, studentUserId) {
|
|
|
325
311
|
return Boolean(link);
|
|
326
312
|
}
|
|
327
313
|
//# sourceMappingURL=parentPortal.js.map
|
|
328
|
-
//# debugId=
|
|
314
|
+
//# debugId=e0a84844-f117-5700-89b0-1d460b45e236
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parentPortal.js","sources":["services/parentPortal.ts"],"sourceRoot":"/","sourcesContent":["/**\n * C4: Minimal parent portal — link parents to students and expose\n * read-only attendance / grades stubs for linked children.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { prisma } from \"../lib/prisma.js\";\nimport {\n findActiveSchoolAdminMembership,\n findActiveSchoolMembership,\n findSchoolMembership,\n} from \"../models/school.js\";\n\nasync function requireSchoolAdmin(schoolId: string, userId: string) {\n const membership = await findActiveSchoolAdminMembership(schoolId, userId);\n if (!membership) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only school admins can perform this action\",\n });\n }\n return membership;\n}\n\nasync function requireParentMembership(schoolId: string, userId: string) {\n const membership = await findActiveSchoolMembership(schoolId, userId);\n if (!membership || membership.role !== \"PARENT\") {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only parents can access this resource\",\n });\n }\n return membership;\n}\n\nexport async function linkParentToStudent(\n userId: string,\n input: { schoolId: string; parentUserId: string; studentUserId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n const [parentMembership, studentMembership] = await Promise.all([\n findSchoolMembership(input.schoolId, input.parentUserId),\n findSchoolMembership(input.schoolId, input.studentUserId),\n ]);\n\n if (!parentMembership || parentMembership.status !== \"ACTIVE\") {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Parent must be an active school member\",\n });\n }\n if (parentMembership.role !== \"PARENT\") {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"parentUserId must have the PARENT role\",\n });\n }\n if (\n !studentMembership ||\n studentMembership.status !== \"ACTIVE\" ||\n studentMembership.role !== \"STUDENT\"\n ) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"studentUserId must be an active STUDENT member\",\n });\n }\n\n const link = await prisma.parentStudentLink.upsert({\n where: {\n schoolId_parentUserId_studentUserId: {\n schoolId: input.schoolId,\n parentUserId: input.parentUserId,\n studentUserId: input.studentUserId,\n },\n },\n update: {},\n create: {\n schoolId: input.schoolId,\n parentUserId: input.parentUserId,\n studentUserId: input.studentUserId,\n },\n });\n\n return { link };\n}\n\nexport async function unlinkParentFromStudent(\n userId: string,\n input: { schoolId: string; parentUserId: string; studentUserId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n await prisma.parentStudentLink.deleteMany({\n where: {\n schoolId: input.schoolId,\n parentUserId: input.parentUserId,\n studentUserId: input.studentUserId,\n },\n });\n return { ok: true as const };\n}\n\nexport async function listParentLinks(\n userId: string,\n input: { schoolId: string; parentUserId?: string; studentUserId?: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const links = await prisma.parentStudentLink.findMany({\n where: {\n schoolId: input.schoolId,\n ...(input.parentUserId ? { parentUserId: input.parentUserId } : {}),\n ...(input.studentUserId ? { studentUserId: input.studentUserId } : {}),\n },\n include: {\n parent: {\n select: {\n id: true,\n username: true,\n email: true,\n profile: { select: { displayName: true } },\n },\n },\n student: {\n select: {\n id: true,\n username: true,\n email: true,\n profile: { select: { displayName: true } },\n },\n },\n },\n orderBy: { createdAt: \"desc\" },\n });\n return { links };\n}\n\nexport async function listMyChildren(userId: string, schoolId: string) {\n await requireParentMembership(schoolId, userId);\n const links = await prisma.parentStudentLink.findMany({\n where: { schoolId, parentUserId: userId },\n include: {\n student: {\n select: {\n id: true,\n username: true,\n email: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n profilePictureThumbnail: true,\n },\n },\n studentIn: {\n where: { schoolId },\n select: {\n id: true,\n name: true,\n subject: true,\n section: true,\n color: true,\n },\n },\n },\n },\n },\n orderBy: { createdAt: \"asc\" },\n });\n\n return {\n children: links.map((link) => ({\n linkId: link.id,\n student: {\n id: link.student.id,\n username: link.student.username,\n email: link.student.email,\n displayName: link.student.profile?.displayName ?? null,\n profilePicture: link.student.profile?.profilePicture ?? null,\n profilePictureThumbnail:\n link.student.profile?.profilePictureThumbnail ?? null,\n classes: link.student.studentIn,\n },\n })),\n };\n}\n\nasync function assertParentOfStudent(\n schoolId: string,\n parentUserId: string,\n studentUserId: string\n) {\n await requireParentMembership(schoolId, parentUserId);\n const link = await prisma.parentStudentLink.findUnique({\n where: {\n schoolId_parentUserId_studentUserId: {\n schoolId,\n parentUserId,\n studentUserId,\n },\n },\n });\n if (!link) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You are not linked to this student\",\n });\n }\n return link;\n}\n\n/**\n * Read-only attendance stub for a linked child (aggregates class attendance M2M).\n * Does not touch A1 AttendanceRecord refactor.\n */\nexport async function getChildAttendance(\n userId: string,\n input: {\n schoolId: string;\n studentUserId: string;\n classId?: string;\n from?: Date;\n to?: Date;\n }\n) {\n await assertParentOfStudent(input.schoolId, userId, input.studentUserId);\n\n const classes = await prisma.class.findMany({\n where: {\n schoolId: input.schoolId,\n students: { some: { id: input.studentUserId } },\n ...(input.classId ? { id: input.classId } : {}),\n },\n select: { id: true, name: true, subject: true, section: true },\n });\n const classIds = classes.map((c) => c.id);\n\n const attendance = await prisma.attendance.findMany({\n where: {\n classId: { in: classIds },\n ...(input.from || input.to\n ? {\n date: {\n ...(input.from ? { gte: input.from } : {}),\n ...(input.to ? { lte: input.to } : {}),\n },\n }\n : {}),\n OR: [\n { present: { some: { id: input.studentUserId } } },\n { late: { some: { id: input.studentUserId } } },\n { absent: { some: { id: input.studentUserId } } },\n ],\n },\n select: {\n id: true,\n date: true,\n classId: true,\n present: { where: { id: input.studentUserId }, select: { id: true } },\n late: { where: { id: input.studentUserId }, select: { id: true } },\n absent: { where: { id: input.studentUserId }, select: { id: true } },\n },\n orderBy: { date: \"desc\" },\n take: 200,\n });\n\n const classMap = new Map(classes.map((c) => [c.id, c]));\n const records = attendance.map((row) => {\n let status: \"PRESENT\" | \"LATE\" | \"ABSENT\" = \"PRESENT\";\n if (row.absent.length > 0) status = \"ABSENT\";\n else if (row.late.length > 0) status = \"LATE\";\n return {\n attendanceId: row.id,\n date: row.date,\n classId: row.classId,\n class: classMap.get(row.classId) ?? null,\n status,\n };\n });\n\n const summary = records.reduce(\n (acc, r) => {\n acc.total += 1;\n if (r.status === \"PRESENT\") acc.present += 1;\n else if (r.status === \"LATE\") acc.late += 1;\n else acc.absent += 1;\n return acc;\n },\n { present: 0, late: 0, absent: 0, total: 0 }\n );\n\n return { summary, records };\n}\n\n/**\n * Read-only grades stub — returns assignment score rows for the linked child.\n */\nexport async function getChildGrades(\n userId: string,\n input: { schoolId: string; studentUserId: string; classId?: string }\n) {\n await assertParentOfStudent(input.schoolId, userId, input.studentUserId);\n\n const classes = await prisma.class.findMany({\n where: {\n schoolId: input.schoolId,\n students: { some: { id: input.studentUserId } },\n ...(input.classId ? { id: input.classId } : {}),\n },\n select: {\n id: true,\n name: true,\n subject: true,\n section: true,\n assignments: {\n select: {\n id: true,\n title: true,\n type: true,\n dueDate: true,\n maxGrade: true,\n submissions: {\n where: { studentId: input.studentUserId },\n select: {\n id: true,\n gradeReceived: true,\n returned: true,\n submittedAt: true,\n },\n take: 1,\n },\n },\n orderBy: { dueDate: \"desc\" },\n take: 100,\n },\n },\n });\n\n return {\n classes: classes.map((cls) => ({\n id: cls.id,\n name: cls.name,\n subject: cls.subject,\n section: cls.section,\n assignments: cls.assignments.map((a) => ({\n id: a.id,\n title: a.title,\n type: a.type,\n dueDate: a.dueDate,\n maxGrade: a.maxGrade,\n submission: a.submissions[0]\n ? {\n id: a.submissions[0].id,\n gradeReceived: a.submissions[0].gradeReceived,\n returned: a.submissions[0].returned,\n submittedAt: a.submissions[0].submittedAt,\n }\n : null,\n })),\n })),\n };\n}\n\n/** Helper for other services: is this user a parent of the student? */\nexport async function isParentOfStudent(\n schoolId: string,\n parentUserId: string,\n studentUserId: string\n) {\n const link = await prisma.parentStudentLink.findUnique({\n where: {\n schoolId_parentUserId_studentUserId: {\n schoolId,\n parentUserId,\n studentUserId,\n },\n },\n select: { id: true },\n });\n return Boolean(link);\n}\n"],"names":[],"mappings":"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","debug_id":"3d43f9df-fb4b-55f0-948a-80ffd38d00d9"}
|
|
1
|
+
{"version":3,"file":"parentPortal.js","sources":["services/parentPortal.ts"],"sourceRoot":"/","sourcesContent":["/**\n * C4: Minimal parent portal — link parents to students and expose\n * read-only attendance / grades stubs for linked children.\n */\nimport { TRPCError } from \"@trpc/server\";\nimport { prisma } from \"../lib/prisma.js\";\nimport {\n findActiveSchoolAdminMembership,\n findActiveSchoolMembership,\n findSchoolMembership,\n} from \"../models/school.js\";\n\nasync function requireSchoolAdmin(schoolId: string, userId: string) {\n const membership = await findActiveSchoolAdminMembership(schoolId, userId);\n if (!membership) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only school admins can perform this action\",\n });\n }\n return membership;\n}\n\nasync function requireParentMembership(schoolId: string, userId: string) {\n const membership = await findActiveSchoolMembership(schoolId, userId);\n if (!membership || membership.role !== \"PARENT\") {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"Only parents can access this resource\",\n });\n }\n return membership;\n}\n\nexport async function linkParentToStudent(\n userId: string,\n input: { schoolId: string; parentUserId: string; studentUserId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n\n const [parentMembership, studentMembership] = await Promise.all([\n findSchoolMembership(input.schoolId, input.parentUserId),\n findSchoolMembership(input.schoolId, input.studentUserId),\n ]);\n\n if (!parentMembership || parentMembership.status !== \"ACTIVE\") {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"Parent must be an active school member\",\n });\n }\n if (parentMembership.role !== \"PARENT\") {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"parentUserId must have the PARENT role\",\n });\n }\n if (\n !studentMembership ||\n studentMembership.status !== \"ACTIVE\" ||\n studentMembership.role !== \"STUDENT\"\n ) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"studentUserId must be an active STUDENT member\",\n });\n }\n\n const link = await prisma.parentStudentLink.upsert({\n where: {\n schoolId_parentUserId_studentUserId: {\n schoolId: input.schoolId,\n parentUserId: input.parentUserId,\n studentUserId: input.studentUserId,\n },\n },\n update: {},\n create: {\n schoolId: input.schoolId,\n parentUserId: input.parentUserId,\n studentUserId: input.studentUserId,\n },\n });\n\n return { link };\n}\n\nexport async function unlinkParentFromStudent(\n userId: string,\n input: { schoolId: string; parentUserId: string; studentUserId: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n await prisma.parentStudentLink.deleteMany({\n where: {\n schoolId: input.schoolId,\n parentUserId: input.parentUserId,\n studentUserId: input.studentUserId,\n },\n });\n return { ok: true as const };\n}\n\nexport async function listParentLinks(\n userId: string,\n input: { schoolId: string; parentUserId?: string; studentUserId?: string }\n) {\n await requireSchoolAdmin(input.schoolId, userId);\n const links = await prisma.parentStudentLink.findMany({\n where: {\n schoolId: input.schoolId,\n ...(input.parentUserId ? { parentUserId: input.parentUserId } : {}),\n ...(input.studentUserId ? { studentUserId: input.studentUserId } : {}),\n },\n include: {\n parent: {\n select: {\n id: true,\n username: true,\n email: true,\n profile: { select: { displayName: true } },\n },\n },\n student: {\n select: {\n id: true,\n username: true,\n email: true,\n profile: { select: { displayName: true } },\n },\n },\n },\n orderBy: { createdAt: \"desc\" },\n });\n return { links };\n}\n\nexport async function listMyChildren(userId: string, schoolId: string) {\n await requireParentMembership(schoolId, userId);\n const links = await prisma.parentStudentLink.findMany({\n where: { schoolId, parentUserId: userId },\n include: {\n student: {\n select: {\n id: true,\n username: true,\n email: true,\n profile: {\n select: {\n displayName: true,\n profilePicture: true,\n profilePictureThumbnail: true,\n },\n },\n studentIn: {\n where: { schoolId },\n select: {\n id: true,\n name: true,\n subject: true,\n section: true,\n color: true,\n },\n },\n },\n },\n },\n orderBy: { createdAt: \"asc\" },\n });\n\n return {\n children: links.map((link) => ({\n linkId: link.id,\n student: {\n id: link.student.id,\n username: link.student.username,\n email: link.student.email,\n displayName: link.student.profile?.displayName ?? null,\n profilePicture: link.student.profile?.profilePicture ?? null,\n profilePictureThumbnail:\n link.student.profile?.profilePictureThumbnail ?? null,\n classes: link.student.studentIn,\n },\n })),\n };\n}\n\nasync function assertParentOfStudent(\n schoolId: string,\n parentUserId: string,\n studentUserId: string\n) {\n await requireParentMembership(schoolId, parentUserId);\n const link = await prisma.parentStudentLink.findUnique({\n where: {\n schoolId_parentUserId_studentUserId: {\n schoolId,\n parentUserId,\n studentUserId,\n },\n },\n });\n if (!link) {\n throw new TRPCError({\n code: \"FORBIDDEN\",\n message: \"You are not linked to this student\",\n });\n }\n return link;\n}\n\n/** Read-only attendance view for a linked child (reads AttendanceRecord). */\nexport async function getChildAttendance(\n userId: string,\n input: {\n schoolId: string;\n studentUserId: string;\n classId?: string;\n from?: Date;\n to?: Date;\n }\n) {\n await assertParentOfStudent(input.schoolId, userId, input.studentUserId);\n\n const classes = await prisma.class.findMany({\n where: {\n schoolId: input.schoolId,\n students: { some: { id: input.studentUserId } },\n ...(input.classId ? { id: input.classId } : {}),\n },\n select: { id: true, name: true, subject: true, section: true },\n });\n const classIds = classes.map((c) => c.id);\n\n const attendanceRecords = await prisma.attendanceRecord.findMany({\n where: {\n studentId: input.studentUserId,\n attendance: {\n classId: { in: classIds },\n ...(input.from || input.to\n ? {\n date: {\n ...(input.from ? { gte: input.from } : {}),\n ...(input.to ? { lte: input.to } : {}),\n },\n }\n : {}),\n },\n },\n select: {\n status: true,\n attendance: { select: { id: true, date: true, classId: true } },\n },\n orderBy: { attendance: { date: \"desc\" } },\n take: 200,\n });\n\n const classMap = new Map(classes.map((c) => [c.id, c]));\n const records = attendanceRecords.map((row) => ({\n attendanceId: row.attendance.id,\n date: row.attendance.date,\n classId: row.attendance.classId,\n class: classMap.get(row.attendance.classId) ?? null,\n status: row.status,\n }));\n\n const summary = records.reduce(\n (acc, r) => {\n acc.total += 1;\n if (r.status === \"PRESENT\") acc.present += 1;\n else if (r.status === \"LATE\") acc.late += 1;\n else if (r.status === \"EXCUSED\") acc.excused += 1;\n else acc.absent += 1;\n return acc;\n },\n { present: 0, late: 0, absent: 0, excused: 0, total: 0 }\n );\n\n return { summary, records };\n}\n\n/**\n * Read-only grades stub — returns assignment score rows for the linked child.\n */\nexport async function getChildGrades(\n userId: string,\n input: { schoolId: string; studentUserId: string; classId?: string }\n) {\n await assertParentOfStudent(input.schoolId, userId, input.studentUserId);\n\n const classes = await prisma.class.findMany({\n where: {\n schoolId: input.schoolId,\n students: { some: { id: input.studentUserId } },\n ...(input.classId ? { id: input.classId } : {}),\n },\n select: {\n id: true,\n name: true,\n subject: true,\n section: true,\n assignments: {\n select: {\n id: true,\n title: true,\n type: true,\n dueDate: true,\n maxGrade: true,\n submissions: {\n where: { studentId: input.studentUserId },\n select: {\n id: true,\n gradeReceived: true,\n returned: true,\n submittedAt: true,\n },\n take: 1,\n },\n },\n orderBy: { dueDate: \"desc\" },\n take: 100,\n },\n },\n });\n\n return {\n classes: classes.map((cls) => ({\n id: cls.id,\n name: cls.name,\n subject: cls.subject,\n section: cls.section,\n assignments: cls.assignments.map((a) => ({\n id: a.id,\n title: a.title,\n type: a.type,\n dueDate: a.dueDate,\n maxGrade: a.maxGrade,\n submission: a.submissions[0]\n ? {\n id: a.submissions[0].id,\n gradeReceived: a.submissions[0].gradeReceived,\n returned: a.submissions[0].returned,\n submittedAt: a.submissions[0].submittedAt,\n }\n : null,\n })),\n })),\n };\n}\n\n/** Helper for other services: is this user a parent of the student? */\nexport async function isParentOfStudent(\n schoolId: string,\n parentUserId: string,\n studentUserId: string\n) {\n const link = await prisma.parentStudentLink.findUnique({\n where: {\n schoolId_parentUserId_studentUserId: {\n schoolId,\n parentUserId,\n studentUserId,\n },\n },\n select: { id: true },\n });\n return Boolean(link);\n}\n"],"names":[],"mappings":"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","debug_id":"e0a84844-f117-5700-89b0-1d460b45e236"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"school.d.ts","sourceRoot":"/","sources":["services/school.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,oBAAoB,EAAe,MAAM,gBAAgB,CAAC;AAmEnE,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BvE;AAED,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;;;;;;;;;;;;;;;;;;;;;GAcF;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IACL,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"school.d.ts","sourceRoot":"/","sources":["services/school.ts"],"names":[],"mappings":"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"}
|
package/dist/services/school.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* School service - school admin workflow, memberships, and invites.
|
|
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]="c3d38743-6297-594a-9bde-bf049584e6b4")}catch(e){}}();
|
|
6
6
|
import { SessionType } from "@prisma/client";
|
|
7
7
|
import { TRPCError } from "@trpc/server";
|
|
8
8
|
import { hash } from "bcryptjs";
|
|
@@ -76,6 +76,26 @@ export async function createSchoolRecord(userId, input) {
|
|
|
76
76
|
}
|
|
77
77
|
export async function updateSchoolDetails(userId, input) {
|
|
78
78
|
await requireSchoolAdmin(input.schoolId, userId);
|
|
79
|
+
const brandingFileIds = [input.logoId, input.letterheadFileId].filter((id) => typeof id === "string");
|
|
80
|
+
if (brandingFileIds.length) {
|
|
81
|
+
const accessible = await prisma.file.findMany({
|
|
82
|
+
where: {
|
|
83
|
+
id: { in: brandingFileIds },
|
|
84
|
+
OR: [
|
|
85
|
+
{ userId },
|
|
86
|
+
{ folder: { schoolStorageId: input.schoolId } },
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
select: { id: true },
|
|
90
|
+
});
|
|
91
|
+
const accessibleIds = new Set(accessible.map((f) => f.id));
|
|
92
|
+
if (brandingFileIds.some((id) => !accessibleIds.has(id))) {
|
|
93
|
+
throw new TRPCError({
|
|
94
|
+
code: "FORBIDDEN",
|
|
95
|
+
message: "File does not belong to this school",
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
79
99
|
const updated = await updateSchoolRecord(input.schoolId, {
|
|
80
100
|
name: input.name,
|
|
81
101
|
description: input.description,
|
|
@@ -433,16 +453,19 @@ export async function getStudentTimeline(userId, input) {
|
|
|
433
453
|
message: "Student is not in this institution",
|
|
434
454
|
});
|
|
435
455
|
}
|
|
456
|
+
// Default to the last 12 months when no range is given, to bound reads.
|
|
457
|
+
const defaultFrom = new Date();
|
|
458
|
+
defaultFrom.setFullYear(defaultFrom.getFullYear() - 1);
|
|
436
459
|
const range = {
|
|
437
|
-
|
|
460
|
+
gte: input.from ?? defaultFrom,
|
|
438
461
|
...(input.to ? { lte: input.to } : {}),
|
|
439
462
|
};
|
|
440
|
-
const hasRange = Object.keys(range).length > 0;
|
|
441
463
|
const [events, assignments, attendance] = await Promise.all([
|
|
442
464
|
prisma.event.findMany({
|
|
443
465
|
where: {
|
|
444
466
|
userId: input.studentId,
|
|
445
|
-
|
|
467
|
+
startTime: range,
|
|
468
|
+
OR: [{ classId: null }, { class: { schoolId: input.schoolId } }],
|
|
446
469
|
},
|
|
447
470
|
select: {
|
|
448
471
|
id: true,
|
|
@@ -459,10 +482,11 @@ export async function getStudentTimeline(userId, input) {
|
|
|
459
482
|
prisma.assignment.findMany({
|
|
460
483
|
where: {
|
|
461
484
|
class: {
|
|
485
|
+
schoolId: input.schoolId,
|
|
462
486
|
students: { some: { id: input.studentId } },
|
|
463
487
|
},
|
|
464
488
|
template: false,
|
|
465
|
-
|
|
489
|
+
dueDate: range,
|
|
466
490
|
},
|
|
467
491
|
select: {
|
|
468
492
|
id: true,
|
|
@@ -499,7 +523,7 @@ export async function getStudentTimeline(userId, input) {
|
|
|
499
523
|
studentId: input.studentId,
|
|
500
524
|
attendance: {
|
|
501
525
|
class: { schoolId: input.schoolId },
|
|
502
|
-
|
|
526
|
+
date: range,
|
|
503
527
|
},
|
|
504
528
|
},
|
|
505
529
|
select: {
|
|
@@ -575,11 +599,13 @@ export async function getMemberTimeline(userId, input) {
|
|
|
575
599
|
message: "This person is not in this institution",
|
|
576
600
|
});
|
|
577
601
|
}
|
|
602
|
+
// Default to the last 12 months when no range is given, to bound reads.
|
|
603
|
+
const defaultFrom = new Date();
|
|
604
|
+
defaultFrom.setFullYear(defaultFrom.getFullYear() - 1);
|
|
578
605
|
const range = {
|
|
579
|
-
|
|
606
|
+
gte: input.from ?? defaultFrom,
|
|
580
607
|
...(input.to ? { lte: input.to } : {}),
|
|
581
608
|
};
|
|
582
|
-
const hasRange = Object.keys(range).length > 0;
|
|
583
609
|
if (membership.role === "STUDENT") {
|
|
584
610
|
if (!callerIsAdmin) {
|
|
585
611
|
const sharedClass = await prisma.class.findFirst({
|
|
@@ -601,7 +627,8 @@ export async function getMemberTimeline(userId, input) {
|
|
|
601
627
|
prisma.event.findMany({
|
|
602
628
|
where: {
|
|
603
629
|
userId: input.memberId,
|
|
604
|
-
|
|
630
|
+
startTime: range,
|
|
631
|
+
OR: [{ classId: null }, { class: { schoolId: input.schoolId } }],
|
|
605
632
|
},
|
|
606
633
|
select: {
|
|
607
634
|
id: true,
|
|
@@ -617,9 +644,12 @@ export async function getMemberTimeline(userId, input) {
|
|
|
617
644
|
}),
|
|
618
645
|
prisma.assignment.findMany({
|
|
619
646
|
where: {
|
|
620
|
-
class: {
|
|
647
|
+
class: {
|
|
648
|
+
schoolId: input.schoolId,
|
|
649
|
+
students: { some: { id: input.memberId } },
|
|
650
|
+
},
|
|
621
651
|
template: false,
|
|
622
|
-
|
|
652
|
+
dueDate: range,
|
|
623
653
|
},
|
|
624
654
|
select: {
|
|
625
655
|
id: true,
|
|
@@ -656,7 +686,7 @@ export async function getMemberTimeline(userId, input) {
|
|
|
656
686
|
studentId: input.memberId,
|
|
657
687
|
attendance: {
|
|
658
688
|
class: { schoolId: input.schoolId },
|
|
659
|
-
|
|
689
|
+
date: range,
|
|
660
690
|
},
|
|
661
691
|
},
|
|
662
692
|
select: {
|
|
@@ -705,10 +735,16 @@ export async function getMemberTimeline(userId, input) {
|
|
|
705
735
|
prisma.event.findMany({
|
|
706
736
|
where: {
|
|
707
737
|
OR: [
|
|
708
|
-
{ userId: input.memberId },
|
|
709
|
-
{
|
|
738
|
+
{ userId: input.memberId, classId: null },
|
|
739
|
+
{ userId: input.memberId, class: { schoolId: input.schoolId } },
|
|
740
|
+
{
|
|
741
|
+
class: {
|
|
742
|
+
schoolId: input.schoolId,
|
|
743
|
+
teachers: { some: { id: input.memberId } },
|
|
744
|
+
},
|
|
745
|
+
},
|
|
710
746
|
],
|
|
711
|
-
|
|
747
|
+
startTime: range,
|
|
712
748
|
},
|
|
713
749
|
select: {
|
|
714
750
|
id: true,
|
|
@@ -885,4 +921,4 @@ export async function acceptInvite(userId, token) {
|
|
|
885
921
|
return { membership };
|
|
886
922
|
}
|
|
887
923
|
//# sourceMappingURL=school.js.map
|
|
888
|
-
//# debugId=
|
|
924
|
+
//# debugId=c3d38743-6297-594a-9bde-bf049584e6b4
|