@studious-lms/server 1.6.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/models/access.d.ts +21 -66
- package/dist/models/access.d.ts.map +1 -1
- package/dist/models/access.js +10 -26
- package/dist/models/access.js.map +1 -1
- package/dist/models/agenda.d.ts +2 -0
- package/dist/models/agenda.d.ts.map +1 -1
- package/dist/models/announcement.d.ts +2 -1
- package/dist/models/announcement.d.ts.map +1 -1
- package/dist/models/announcement.js +2 -3
- package/dist/models/announcement.js.map +1 -1
- package/dist/models/assignment.d.ts +7 -0
- package/dist/models/assignment.d.ts.map +1 -1
- package/dist/models/auth.d.ts +2 -4
- package/dist/models/auth.d.ts.map +1 -1
- package/dist/models/auth.js +2 -3
- package/dist/models/auth.js.map +1 -1
- package/dist/models/class.d.ts +32 -4
- package/dist/models/class.d.ts.map +1 -1
- package/dist/models/class.js +15 -2
- package/dist/models/class.js.map +1 -1
- package/dist/models/cloudStorage.d.ts +140 -0
- package/dist/models/cloudStorage.d.ts.map +1 -0
- package/dist/models/cloudStorage.js +175 -0
- package/dist/models/cloudStorage.js.map +1 -0
- package/dist/models/comment.d.ts +0 -24
- package/dist/models/comment.d.ts.map +1 -1
- package/dist/models/comment.js +2 -6
- package/dist/models/comment.js.map +1 -1
- package/dist/models/conversation.d.ts +38 -22
- package/dist/models/conversation.d.ts.map +1 -1
- package/dist/models/conversation.js +50 -2
- package/dist/models/conversation.js.map +1 -1
- package/dist/models/department.d.ts +154 -0
- package/dist/models/department.d.ts.map +1 -0
- package/dist/models/department.js +135 -0
- package/dist/models/department.js.map +1 -0
- package/dist/models/event.d.ts +7 -1
- package/dist/models/event.d.ts.map +1 -1
- package/dist/models/event.js +2 -5
- package/dist/models/event.js.map +1 -1
- package/dist/models/file.d.ts +25 -10
- package/dist/models/file.d.ts.map +1 -1
- package/dist/models/file.js +2 -5
- package/dist/models/file.js.map +1 -1
- package/dist/models/folder.d.ts +47 -0
- package/dist/models/folder.d.ts.map +1 -1
- package/dist/models/labChat.d.ts +5 -3
- package/dist/models/labChat.d.ts.map +1 -1
- package/dist/models/message.d.ts +46 -12
- package/dist/models/message.d.ts.map +1 -1
- package/dist/models/message.js +19 -10
- package/dist/models/message.js.map +1 -1
- package/dist/models/newtonChat.d.ts +2 -1
- package/dist/models/newtonChat.d.ts.map +1 -1
- package/dist/models/school.d.ts +45 -12
- package/dist/models/school.d.ts.map +1 -1
- package/dist/models/school.js +19 -2
- package/dist/models/school.js.map +1 -1
- package/dist/models/section.d.ts +1 -0
- package/dist/models/section.d.ts.map +1 -1
- package/dist/models/tag.d.ts +117 -0
- package/dist/models/tag.d.ts.map +1 -0
- package/dist/models/tag.js +113 -0
- package/dist/models/tag.js.map +1 -0
- package/dist/models/worksheet.d.ts +3 -0
- package/dist/models/worksheet.d.ts.map +1 -1
- package/dist/pipelines/aiLabChatContract.d.ts +8 -8
- package/dist/routers/_app.d.ts +3556 -2298
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +6 -2
- package/dist/routers/_app.js.map +1 -1
- package/dist/routers/agenda.d.ts +2 -0
- package/dist/routers/agenda.d.ts.map +1 -1
- package/dist/routers/announcement.d.ts.map +1 -1
- package/dist/routers/announcement.js +3 -5
- package/dist/routers/announcement.js.map +1 -1
- package/dist/routers/assignment.d.ts +18 -9
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/assignment.js +2 -3
- package/dist/routers/assignment.js.map +1 -1
- package/dist/routers/class.d.ts +87 -14
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/class.js +5 -2
- package/dist/routers/class.js.map +1 -1
- package/dist/routers/conversation.d.ts +20 -5
- package/dist/routers/conversation.d.ts.map +1 -1
- package/dist/routers/conversation.js +6 -3
- package/dist/routers/conversation.js.map +1 -1
- package/dist/routers/department.d.ts +293 -0
- package/dist/routers/department.d.ts.map +1 -0
- package/dist/routers/department.js +93 -0
- package/dist/routers/department.js.map +1 -0
- package/dist/routers/event.d.ts +2 -1
- package/dist/routers/event.d.ts.map +1 -1
- package/dist/routers/file.d.ts +8 -6
- package/dist/routers/file.d.ts.map +1 -1
- package/dist/routers/file.js +26 -17
- package/dist/routers/file.js.map +1 -1
- package/dist/routers/folder.d.ts +139 -186
- package/dist/routers/folder.d.ts.map +1 -1
- package/dist/routers/folder.js +82 -90
- package/dist/routers/folder.js.map +1 -1
- package/dist/routers/labChat.d.ts +11 -2
- package/dist/routers/labChat.d.ts.map +1 -1
- package/dist/routers/message.d.ts +20 -2
- package/dist/routers/message.d.ts.map +1 -1
- package/dist/routers/newtonChat.d.ts +9 -0
- package/dist/routers/newtonChat.d.ts.map +1 -1
- package/dist/routers/school.d.ts +160 -17
- package/dist/routers/school.d.ts.map +1 -1
- package/dist/routers/school.js +46 -3
- package/dist/routers/school.js.map +1 -1
- package/dist/routers/tag.d.ts +119 -0
- package/dist/routers/tag.d.ts.map +1 -0
- package/dist/routers/tag.js +52 -0
- package/dist/routers/tag.js.map +1 -0
- package/dist/routers/worksheet.d.ts +1 -0
- package/dist/routers/worksheet.d.ts.map +1 -1
- package/dist/seedDatabase.d.ts +0 -1
- package/dist/seedDatabase.d.ts.map +1 -1
- package/dist/services/agenda.d.ts +2 -0
- package/dist/services/agenda.d.ts.map +1 -1
- package/dist/services/assignment.d.ts +18 -9
- package/dist/services/assignment.d.ts.map +1 -1
- package/dist/services/assignment.js +4 -4
- package/dist/services/assignment.js.map +1 -1
- package/dist/services/class.d.ts +87 -14
- package/dist/services/class.d.ts.map +1 -1
- package/dist/services/class.js +91 -4
- package/dist/services/class.js.map +1 -1
- package/dist/services/conversation.d.ts +21 -5
- package/dist/services/conversation.d.ts.map +1 -1
- package/dist/services/conversation.js +22 -3
- package/dist/services/conversation.js.map +1 -1
- package/dist/services/department.d.ts +200 -0
- package/dist/services/department.d.ts.map +1 -0
- package/dist/services/department.js +368 -0
- package/dist/services/department.js.map +1 -0
- package/dist/services/event.d.ts +2 -1
- package/dist/services/event.d.ts.map +1 -1
- package/dist/services/file.d.ts +85 -0
- package/dist/services/file.d.ts.map +1 -1
- package/dist/services/file.js +92 -2
- package/dist/services/file.js.map +1 -1
- package/dist/services/folder.d.ts +125 -149
- package/dist/services/folder.d.ts.map +1 -1
- package/dist/services/folder.js +258 -199
- package/dist/services/folder.js.map +1 -1
- package/dist/services/labChat.d.ts +11 -2
- package/dist/services/labChat.d.ts.map +1 -1
- package/dist/services/labChat.js +8 -7
- package/dist/services/labChat.js.map +1 -1
- package/dist/services/message.d.ts +20 -2
- package/dist/services/message.d.ts.map +1 -1
- package/dist/services/message.js +7 -23
- package/dist/services/message.js.map +1 -1
- package/dist/services/newtonChat.d.ts +9 -0
- package/dist/services/newtonChat.d.ts.map +1 -1
- package/dist/services/newtonChat.js +7 -6
- package/dist/services/newtonChat.js.map +1 -1
- package/dist/services/school.d.ts +142 -15
- package/dist/services/school.d.ts.map +1 -1
- package/dist/services/school.js +308 -54
- package/dist/services/school.js.map +1 -1
- package/dist/services/tag.d.ts +71 -0
- package/dist/services/tag.d.ts.map +1 -0
- package/dist/services/tag.js +178 -0
- package/dist/services/tag.js.map +1 -0
- package/dist/services/worksheet.d.ts +1 -0
- package/dist/services/worksheet.d.ts.map +1 -1
- package/dist/utils/aiUser.d.ts.map +1 -1
- package/dist/utils/aiUser.js +2 -3
- package/dist/utils/aiUser.js.map +1 -1
- package/package.json +1 -1
- package/prisma/migrations/20260509220000_institution_overhaul/migration.sql +184 -0
- package/prisma/schema.prisma +119 -35
- package/src/models/access.ts +8 -24
- package/src/models/announcement.ts +0 -1
- package/src/models/auth.ts +0 -1
- package/src/models/class.ts +13 -0
- package/src/models/cloudStorage.ts +194 -0
- package/src/models/comment.ts +0 -4
- package/src/models/conversation.ts +54 -0
- package/src/models/department.ts +159 -0
- package/src/models/event.ts +0 -3
- package/src/models/file.ts +0 -3
- package/src/models/message.ts +19 -5
- package/src/models/school.ts +26 -0
- package/src/models/tag.ts +140 -0
- package/src/routers/_app.ts +4 -0
- package/src/routers/announcement.ts +1 -3
- package/src/routers/assignment.ts +0 -1
- package/src/routers/class.ts +3 -0
- package/src/routers/conversation.ts +7 -0
- package/src/routers/department.ts +174 -0
- package/src/routers/file.ts +29 -26
- package/src/routers/folder.ts +100 -121
- package/src/routers/school.ts +83 -0
- package/src/routers/tag.ts +78 -0
- package/src/services/assignment.ts +2 -3
- package/src/services/class.ts +108 -3
- package/src/services/conversation.ts +30 -0
- package/src/services/department.ts +478 -0
- package/src/services/file.ts +100 -0
- package/src/services/folder.ts +313 -240
- package/src/services/labChat.ts +7 -6
- package/src/services/message.ts +5 -21
- package/src/services/newtonChat.ts +5 -5
- package/src/services/school.ts +369 -57
- package/src/services/tag.ts +229 -0
- package/src/utils/aiUser.ts +0 -1
- package/tests/integration/routers/conversation.test.ts +121 -2
package/src/services/file.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* File service – signed URLs, move, rename, delete. Handles permission checks
|
|
3
3
|
* for assignment, submission, announcement, folder, and user-owned files.
|
|
4
|
+
*
|
|
5
|
+
* The class files page calls the legacy class-scoped helpers; the unified
|
|
6
|
+
* cloud-storage page calls the `*Scoped` / `*Generic` helpers below, which
|
|
7
|
+
* derive permissions from the parent folder's CloudScope so the same endpoint
|
|
8
|
+
* can serve class, school, and personal storage.
|
|
4
9
|
*/
|
|
5
10
|
import { TRPCError } from "@trpc/server";
|
|
6
11
|
import { getSignedUrl, deleteFile } from "../lib/googleCloudStorage.js";
|
|
@@ -15,6 +20,9 @@ import {
|
|
|
15
20
|
deleteFileById,
|
|
16
21
|
} from "../models/file.js";
|
|
17
22
|
import { findConversationMembership } from "../models/message.js";
|
|
23
|
+
import { prisma } from "../lib/prisma.js";
|
|
24
|
+
import { resolveFolderScope } from "../models/cloudStorage.js";
|
|
25
|
+
import { requireFolderAccess } from "./folder.js";
|
|
18
26
|
|
|
19
27
|
function isSchoolAdminForClass(classData: any, userId: string) {
|
|
20
28
|
return Boolean(
|
|
@@ -185,3 +193,95 @@ export async function deleteFileRecord(fileId: string, classId: string) {
|
|
|
185
193
|
await deleteFileById(fileId);
|
|
186
194
|
return { success: true };
|
|
187
195
|
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Scope-aware move: works for class, school, and personal storage. Source
|
|
199
|
+
* and target must live in the same scope (no cross-scope moves).
|
|
200
|
+
*/
|
|
201
|
+
export async function moveFileScoped(
|
|
202
|
+
userId: string,
|
|
203
|
+
input: { fileId: string; targetFolderId: string }
|
|
204
|
+
) {
|
|
205
|
+
const file = await findFileWithFolder(input.fileId);
|
|
206
|
+
if (!file?.folderId) {
|
|
207
|
+
throw new TRPCError({ code: "NOT_FOUND", message: "File not found" });
|
|
208
|
+
}
|
|
209
|
+
const [sourceScope, targetScope] = await Promise.all([
|
|
210
|
+
resolveFolderScope(file.folderId),
|
|
211
|
+
resolveFolderScope(input.targetFolderId),
|
|
212
|
+
]);
|
|
213
|
+
if (!sourceScope || !targetScope) {
|
|
214
|
+
throw new TRPCError({ code: "NOT_FOUND", message: "Folder not found" });
|
|
215
|
+
}
|
|
216
|
+
if (JSON.stringify(sourceScope) !== JSON.stringify(targetScope)) {
|
|
217
|
+
throw new TRPCError({
|
|
218
|
+
code: "BAD_REQUEST",
|
|
219
|
+
message: "Cannot move files between scopes",
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
await requireFolderAccess(userId, file.folderId, "WRITE");
|
|
223
|
+
await requireFolderAccess(userId, input.targetFolderId, "WRITE");
|
|
224
|
+
return updateFileFolder(input.fileId, input.targetFolderId);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Scope-aware rename. */
|
|
228
|
+
export async function renameFileScoped(
|
|
229
|
+
userId: string,
|
|
230
|
+
input: { fileId: string; newName: string }
|
|
231
|
+
) {
|
|
232
|
+
const trimmed = input.newName.trim();
|
|
233
|
+
if (!trimmed) {
|
|
234
|
+
throw new TRPCError({
|
|
235
|
+
code: "BAD_REQUEST",
|
|
236
|
+
message: "File name cannot be empty",
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
const file = await findFileWithFolder(input.fileId);
|
|
240
|
+
if (!file) {
|
|
241
|
+
throw new TRPCError({ code: "NOT_FOUND", message: "File not found" });
|
|
242
|
+
}
|
|
243
|
+
if (file.folderId) {
|
|
244
|
+
await requireFolderAccess(userId, file.folderId, "WRITE");
|
|
245
|
+
} else if (file.userId !== userId) {
|
|
246
|
+
throw new TRPCError({
|
|
247
|
+
code: "FORBIDDEN",
|
|
248
|
+
message: "You don't own this file",
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
return updateFileName(input.fileId, trimmed);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Generic delete that works across class / school / personal storage by
|
|
256
|
+
* deriving permissions from the parent folder's CloudScope (or owning user
|
|
257
|
+
* for unfiled files).
|
|
258
|
+
*/
|
|
259
|
+
export async function deleteFileGeneric(userId: string, fileId: string) {
|
|
260
|
+
const file = await findFileWithFolderAndThumbnail(fileId);
|
|
261
|
+
if (!file) {
|
|
262
|
+
throw new TRPCError({ code: "NOT_FOUND", message: "File not found" });
|
|
263
|
+
}
|
|
264
|
+
if (file.folderId) {
|
|
265
|
+
await requireFolderAccess(userId, file.folderId, "WRITE");
|
|
266
|
+
} else if (file.userId !== userId) {
|
|
267
|
+
throw new TRPCError({
|
|
268
|
+
code: "FORBIDDEN",
|
|
269
|
+
message: "You don't own this file",
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
try {
|
|
273
|
+
if (file.uploadStatus === "COMPLETED") {
|
|
274
|
+
await deleteFile(file.path);
|
|
275
|
+
if (file.thumbnail) {
|
|
276
|
+
await deleteFile(file.thumbnail.path);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
} catch (error) {
|
|
280
|
+
logger.warn(
|
|
281
|
+
`Failed to delete file ${file.path}:`,
|
|
282
|
+
error as Record<string, unknown>
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
await deleteFileById(fileId);
|
|
286
|
+
return { success: true };
|
|
287
|
+
}
|