@studious-lms/server 1.7.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 +22 -22
- 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 +3200 -1972
- 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 +5 -5
- 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/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 +5 -5
- 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 +4 -3
- 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 +4 -3
- 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/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/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/class.ts +108 -3
- 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 +2 -1
- package/src/services/message.ts +5 -21
- package/src/services/newtonChat.ts +2 -1
- package/src/services/school.ts +369 -57
- package/src/services/tag.ts +229 -0
- package/src/utils/aiUser.ts +0 -1
package/src/models/message.ts
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Message model – messages, attachments, mentions, unread counts.
|
|
3
3
|
*/
|
|
4
|
+
import type { Prisma } from "@prisma/client";
|
|
4
5
|
import { prisma } from "../lib/prisma.js";
|
|
5
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Canonical shape for File rows surfaced as message attachments.
|
|
9
|
+
* Use this everywhere a message (list, send, update, suggestion broadcast)
|
|
10
|
+
* exposes attached files so the wire shape stays in sync.
|
|
11
|
+
*/
|
|
12
|
+
export const messageFileSelect = {
|
|
13
|
+
id: true,
|
|
14
|
+
name: true,
|
|
15
|
+
type: true,
|
|
16
|
+
size: true,
|
|
17
|
+
path: true,
|
|
18
|
+
uploadedAt: true,
|
|
19
|
+
uploadStatus: true,
|
|
20
|
+
thumbnailId: true,
|
|
21
|
+
thumbnail: { select: { id: true, path: true } },
|
|
22
|
+
} as const satisfies Prisma.FileSelect;
|
|
23
|
+
|
|
6
24
|
const messageInclude = {
|
|
7
25
|
attachments: {
|
|
8
|
-
select:
|
|
9
|
-
id: true,
|
|
10
|
-
name: true,
|
|
11
|
-
type: true,
|
|
12
|
-
},
|
|
26
|
+
select: messageFileSelect,
|
|
13
27
|
},
|
|
14
28
|
sender: {
|
|
15
29
|
select: {
|
package/src/models/school.ts
CHANGED
|
@@ -52,8 +52,10 @@ export function listUserSchoolMemberships(userId: string) {
|
|
|
52
52
|
select: {
|
|
53
53
|
id: true,
|
|
54
54
|
name: true,
|
|
55
|
+
description: true,
|
|
55
56
|
subdomain: true,
|
|
56
57
|
logoId: true,
|
|
58
|
+
logo: { select: { id: true, path: true, type: true } },
|
|
57
59
|
createdAt: true,
|
|
58
60
|
updatedAt: true,
|
|
59
61
|
},
|
|
@@ -96,14 +98,38 @@ export function getSchoolById(schoolId: string) {
|
|
|
96
98
|
select: {
|
|
97
99
|
id: true,
|
|
98
100
|
name: true,
|
|
101
|
+
description: true,
|
|
99
102
|
subdomain: true,
|
|
100
103
|
logoId: true,
|
|
104
|
+
logo: { select: { id: true, name: true, type: true, path: true } },
|
|
101
105
|
createdAt: true,
|
|
102
106
|
updatedAt: true,
|
|
103
107
|
},
|
|
104
108
|
});
|
|
105
109
|
}
|
|
106
110
|
|
|
111
|
+
export function updateSchoolRecord(
|
|
112
|
+
schoolId: string,
|
|
113
|
+
data: {
|
|
114
|
+
name?: string;
|
|
115
|
+
description?: string | null;
|
|
116
|
+
subdomain?: string | null;
|
|
117
|
+
logoId?: string | null;
|
|
118
|
+
}
|
|
119
|
+
) {
|
|
120
|
+
return prisma.school.update({
|
|
121
|
+
where: { id: schoolId },
|
|
122
|
+
data,
|
|
123
|
+
select: {
|
|
124
|
+
id: true,
|
|
125
|
+
name: true,
|
|
126
|
+
description: true,
|
|
127
|
+
subdomain: true,
|
|
128
|
+
logoId: true,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
107
133
|
export function getSchoolOverview(schoolId: string) {
|
|
108
134
|
return prisma.school.findUnique({
|
|
109
135
|
where: { id: schoolId },
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tag model — institution-scoped tags applicable to users, classes, rubrics,
|
|
3
|
+
* and grading boundaries. Optionally associated with a department.
|
|
4
|
+
*/
|
|
5
|
+
import { prisma } from "../lib/prisma.js";
|
|
6
|
+
|
|
7
|
+
const tagSelect = {
|
|
8
|
+
id: true,
|
|
9
|
+
schoolId: true,
|
|
10
|
+
departmentId: true,
|
|
11
|
+
name: true,
|
|
12
|
+
color: true,
|
|
13
|
+
createdAt: true,
|
|
14
|
+
updatedAt: true,
|
|
15
|
+
} as const;
|
|
16
|
+
|
|
17
|
+
export type TagTarget = "USER" | "CLASS" | "RUBRIC" | "BOUNDARY";
|
|
18
|
+
|
|
19
|
+
export function listTagsForSchool(
|
|
20
|
+
schoolId: string,
|
|
21
|
+
options?: { departmentId?: string | null }
|
|
22
|
+
) {
|
|
23
|
+
return prisma.tag.findMany({
|
|
24
|
+
where: {
|
|
25
|
+
schoolId,
|
|
26
|
+
...(options?.departmentId === null
|
|
27
|
+
? { departmentId: null }
|
|
28
|
+
: options?.departmentId
|
|
29
|
+
? { departmentId: options.departmentId }
|
|
30
|
+
: {}),
|
|
31
|
+
},
|
|
32
|
+
orderBy: [{ name: "asc" }],
|
|
33
|
+
select: tagSelect,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getTag(tagId: string) {
|
|
38
|
+
return prisma.tag.findUnique({
|
|
39
|
+
where: { id: tagId },
|
|
40
|
+
select: tagSelect,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function createTag(data: {
|
|
45
|
+
schoolId: string;
|
|
46
|
+
departmentId?: string | null;
|
|
47
|
+
name: string;
|
|
48
|
+
color?: string;
|
|
49
|
+
}) {
|
|
50
|
+
return prisma.tag.create({
|
|
51
|
+
data: {
|
|
52
|
+
schoolId: data.schoolId,
|
|
53
|
+
departmentId: data.departmentId ?? null,
|
|
54
|
+
name: data.name,
|
|
55
|
+
color: data.color ?? "#3B82F6",
|
|
56
|
+
},
|
|
57
|
+
select: tagSelect,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function updateTag(
|
|
62
|
+
tagId: string,
|
|
63
|
+
data: { name?: string; color?: string; departmentId?: string | null }
|
|
64
|
+
) {
|
|
65
|
+
return prisma.tag.update({
|
|
66
|
+
where: { id: tagId },
|
|
67
|
+
data,
|
|
68
|
+
select: tagSelect,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function deleteTag(tagId: string) {
|
|
73
|
+
return prisma.tag.delete({ where: { id: tagId } });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const targetRelation: Record<TagTarget, "users" | "classes" | "rubrics" | "boundaries"> = {
|
|
77
|
+
USER: "users",
|
|
78
|
+
CLASS: "classes",
|
|
79
|
+
RUBRIC: "rubrics",
|
|
80
|
+
BOUNDARY: "boundaries",
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export function attachTagToTarget(params: {
|
|
84
|
+
tagId: string;
|
|
85
|
+
target: TagTarget;
|
|
86
|
+
targetId: string;
|
|
87
|
+
}) {
|
|
88
|
+
const relation = targetRelation[params.target];
|
|
89
|
+
return prisma.tag.update({
|
|
90
|
+
where: { id: params.tagId },
|
|
91
|
+
data: {
|
|
92
|
+
[relation]: { connect: { id: params.targetId } },
|
|
93
|
+
},
|
|
94
|
+
select: { id: true },
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function detachTagFromTarget(params: {
|
|
99
|
+
tagId: string;
|
|
100
|
+
target: TagTarget;
|
|
101
|
+
targetId: string;
|
|
102
|
+
}) {
|
|
103
|
+
const relation = targetRelation[params.target];
|
|
104
|
+
return prisma.tag.update({
|
|
105
|
+
where: { id: params.tagId },
|
|
106
|
+
data: {
|
|
107
|
+
[relation]: { disconnect: { id: params.targetId } },
|
|
108
|
+
},
|
|
109
|
+
select: { id: true },
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function listTagsAttachedTo(target: TagTarget, targetId: string) {
|
|
114
|
+
switch (target) {
|
|
115
|
+
case "USER":
|
|
116
|
+
return prisma.tag.findMany({
|
|
117
|
+
where: { users: { some: { id: targetId } } },
|
|
118
|
+
select: tagSelect,
|
|
119
|
+
orderBy: { name: "asc" },
|
|
120
|
+
});
|
|
121
|
+
case "CLASS":
|
|
122
|
+
return prisma.tag.findMany({
|
|
123
|
+
where: { classes: { some: { id: targetId } } },
|
|
124
|
+
select: tagSelect,
|
|
125
|
+
orderBy: { name: "asc" },
|
|
126
|
+
});
|
|
127
|
+
case "RUBRIC":
|
|
128
|
+
return prisma.tag.findMany({
|
|
129
|
+
where: { rubrics: { some: { id: targetId } } },
|
|
130
|
+
select: tagSelect,
|
|
131
|
+
orderBy: { name: "asc" },
|
|
132
|
+
});
|
|
133
|
+
case "BOUNDARY":
|
|
134
|
+
return prisma.tag.findMany({
|
|
135
|
+
where: { boundaries: { some: { id: targetId } } },
|
|
136
|
+
select: tagSelect,
|
|
137
|
+
orderBy: { name: "asc" },
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
package/src/routers/_app.ts
CHANGED
|
@@ -23,6 +23,8 @@ import { commentRouter } from "./comment.js";
|
|
|
23
23
|
import { studentProgressRouter } from "./studentProgress.js";
|
|
24
24
|
import { searchRouter } from "./search.js";
|
|
25
25
|
import { schoolRouter } from "./school.js";
|
|
26
|
+
import { departmentRouter } from "./department.js";
|
|
27
|
+
import { tagRouter } from "./tag.js";
|
|
26
28
|
|
|
27
29
|
export const appRouter = createTRPCRouter({
|
|
28
30
|
class: classRouter,
|
|
@@ -47,6 +49,8 @@ export const appRouter = createTRPCRouter({
|
|
|
47
49
|
studentProgress: studentProgressRouter,
|
|
48
50
|
search: searchRouter,
|
|
49
51
|
school: schoolRouter,
|
|
52
|
+
department: departmentRouter,
|
|
53
|
+
tag: tagRouter,
|
|
50
54
|
});
|
|
51
55
|
|
|
52
56
|
// Export type router type definition
|
package/src/routers/class.ts
CHANGED
|
@@ -58,6 +58,8 @@ export const classRouter = createTRPCRouter({
|
|
|
58
58
|
name: z.string().optional(),
|
|
59
59
|
section: z.string().optional(),
|
|
60
60
|
subject: z.string().optional(),
|
|
61
|
+
color: z.string().optional(),
|
|
62
|
+
departmentId: z.string().nullable().optional(),
|
|
61
63
|
})
|
|
62
64
|
)
|
|
63
65
|
.mutation(({ input }) => {
|
|
@@ -75,6 +77,7 @@ export const classRouter = createTRPCRouter({
|
|
|
75
77
|
subject: z.string(),
|
|
76
78
|
color: z.string().optional(),
|
|
77
79
|
schoolId: z.string().optional(),
|
|
80
|
+
departmentId: z.string().optional(),
|
|
78
81
|
})
|
|
79
82
|
)
|
|
80
83
|
.mutation(({ ctx, input }) =>
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createTRPCRouter, protectedProcedure } from "../trpc.js";
|
|
3
|
+
import {
|
|
4
|
+
addMembersToDepartment,
|
|
5
|
+
applyBoundaryTemplate,
|
|
6
|
+
applyRubricTemplate,
|
|
7
|
+
createBoundaryTemplate,
|
|
8
|
+
createDepartmentRecord,
|
|
9
|
+
createRubricTemplate,
|
|
10
|
+
deleteBoundaryTemplate,
|
|
11
|
+
deleteDepartmentRecord,
|
|
12
|
+
deleteRubricTemplate,
|
|
13
|
+
getDepartmentDetails,
|
|
14
|
+
listDepartments,
|
|
15
|
+
listMyDepartments,
|
|
16
|
+
removeMemberFromDepartment,
|
|
17
|
+
setClassDepartment,
|
|
18
|
+
updateBoundaryTemplate,
|
|
19
|
+
updateDepartmentRecord,
|
|
20
|
+
updateRubricTemplate,
|
|
21
|
+
} from "../services/department.js";
|
|
22
|
+
|
|
23
|
+
export const departmentRouter = createTRPCRouter({
|
|
24
|
+
list: protectedProcedure
|
|
25
|
+
.input(z.object({ schoolId: z.string() }))
|
|
26
|
+
.query(({ ctx, input }) => listDepartments(ctx.user!.id, input.schoolId)),
|
|
27
|
+
|
|
28
|
+
listMine: protectedProcedure
|
|
29
|
+
.input(z.object({ schoolId: z.string() }))
|
|
30
|
+
.query(({ ctx, input }) =>
|
|
31
|
+
listMyDepartments(ctx.user!.id, input.schoolId)
|
|
32
|
+
),
|
|
33
|
+
|
|
34
|
+
get: protectedProcedure
|
|
35
|
+
.input(z.object({ departmentId: z.string() }))
|
|
36
|
+
.query(({ ctx, input }) =>
|
|
37
|
+
getDepartmentDetails(ctx.user!.id, input.departmentId)
|
|
38
|
+
),
|
|
39
|
+
|
|
40
|
+
create: protectedProcedure
|
|
41
|
+
.input(
|
|
42
|
+
z.object({
|
|
43
|
+
schoolId: z.string(),
|
|
44
|
+
name: z.string().min(1),
|
|
45
|
+
description: z.string().optional(),
|
|
46
|
+
color: z.string().optional(),
|
|
47
|
+
})
|
|
48
|
+
)
|
|
49
|
+
.mutation(({ ctx, input }) =>
|
|
50
|
+
createDepartmentRecord(ctx.user!.id, input)
|
|
51
|
+
),
|
|
52
|
+
|
|
53
|
+
update: protectedProcedure
|
|
54
|
+
.input(
|
|
55
|
+
z.object({
|
|
56
|
+
departmentId: z.string(),
|
|
57
|
+
name: z.string().min(1).optional(),
|
|
58
|
+
description: z.string().nullable().optional(),
|
|
59
|
+
color: z.string().optional(),
|
|
60
|
+
})
|
|
61
|
+
)
|
|
62
|
+
.mutation(({ ctx, input }) =>
|
|
63
|
+
updateDepartmentRecord(ctx.user!.id, input)
|
|
64
|
+
),
|
|
65
|
+
|
|
66
|
+
delete: protectedProcedure
|
|
67
|
+
.input(z.object({ departmentId: z.string() }))
|
|
68
|
+
.mutation(({ ctx, input }) =>
|
|
69
|
+
deleteDepartmentRecord(ctx.user!.id, input.departmentId)
|
|
70
|
+
),
|
|
71
|
+
|
|
72
|
+
addMembers: protectedProcedure
|
|
73
|
+
.input(
|
|
74
|
+
z.object({
|
|
75
|
+
departmentId: z.string(),
|
|
76
|
+
userIds: z.array(z.string()),
|
|
77
|
+
})
|
|
78
|
+
)
|
|
79
|
+
.mutation(({ ctx, input }) =>
|
|
80
|
+
addMembersToDepartment(ctx.user!.id, input)
|
|
81
|
+
),
|
|
82
|
+
|
|
83
|
+
removeMember: protectedProcedure
|
|
84
|
+
.input(z.object({ departmentId: z.string(), memberId: z.string() }))
|
|
85
|
+
.mutation(({ ctx, input }) =>
|
|
86
|
+
removeMemberFromDepartment(ctx.user!.id, input)
|
|
87
|
+
),
|
|
88
|
+
|
|
89
|
+
setClassDepartment: protectedProcedure
|
|
90
|
+
.input(
|
|
91
|
+
z.object({
|
|
92
|
+
classId: z.string(),
|
|
93
|
+
departmentId: z.string().nullable(),
|
|
94
|
+
})
|
|
95
|
+
)
|
|
96
|
+
.mutation(({ ctx, input }) => setClassDepartment(ctx.user!.id, input)),
|
|
97
|
+
|
|
98
|
+
/** Template authoring. */
|
|
99
|
+
createRubricTemplate: protectedProcedure
|
|
100
|
+
.input(
|
|
101
|
+
z.object({
|
|
102
|
+
departmentId: z.string(),
|
|
103
|
+
name: z.string(),
|
|
104
|
+
structured: z.string(),
|
|
105
|
+
})
|
|
106
|
+
)
|
|
107
|
+
.mutation(({ ctx, input }) =>
|
|
108
|
+
createRubricTemplate(ctx.user!.id, input)
|
|
109
|
+
),
|
|
110
|
+
|
|
111
|
+
updateRubricTemplate: protectedProcedure
|
|
112
|
+
.input(
|
|
113
|
+
z.object({
|
|
114
|
+
templateId: z.string(),
|
|
115
|
+
name: z.string().optional(),
|
|
116
|
+
structured: z.string().optional(),
|
|
117
|
+
})
|
|
118
|
+
)
|
|
119
|
+
.mutation(({ ctx, input }) =>
|
|
120
|
+
updateRubricTemplate(ctx.user!.id, input)
|
|
121
|
+
),
|
|
122
|
+
|
|
123
|
+
deleteRubricTemplate: protectedProcedure
|
|
124
|
+
.input(z.object({ templateId: z.string() }))
|
|
125
|
+
.mutation(({ ctx, input }) =>
|
|
126
|
+
deleteRubricTemplate(ctx.user!.id, input.templateId)
|
|
127
|
+
),
|
|
128
|
+
|
|
129
|
+
createBoundaryTemplate: protectedProcedure
|
|
130
|
+
.input(
|
|
131
|
+
z.object({
|
|
132
|
+
departmentId: z.string(),
|
|
133
|
+
name: z.string(),
|
|
134
|
+
structured: z.string(),
|
|
135
|
+
})
|
|
136
|
+
)
|
|
137
|
+
.mutation(({ ctx, input }) =>
|
|
138
|
+
createBoundaryTemplate(ctx.user!.id, input)
|
|
139
|
+
),
|
|
140
|
+
|
|
141
|
+
updateBoundaryTemplate: protectedProcedure
|
|
142
|
+
.input(
|
|
143
|
+
z.object({
|
|
144
|
+
templateId: z.string(),
|
|
145
|
+
name: z.string().optional(),
|
|
146
|
+
structured: z.string().optional(),
|
|
147
|
+
})
|
|
148
|
+
)
|
|
149
|
+
.mutation(({ ctx, input }) =>
|
|
150
|
+
updateBoundaryTemplate(ctx.user!.id, input)
|
|
151
|
+
),
|
|
152
|
+
|
|
153
|
+
deleteBoundaryTemplate: protectedProcedure
|
|
154
|
+
.input(z.object({ templateId: z.string() }))
|
|
155
|
+
.mutation(({ ctx, input }) =>
|
|
156
|
+
deleteBoundaryTemplate(ctx.user!.id, input.templateId)
|
|
157
|
+
),
|
|
158
|
+
|
|
159
|
+
applyRubricTemplate: protectedProcedure
|
|
160
|
+
.input(
|
|
161
|
+
z.object({ classId: z.string(), templateId: z.string() })
|
|
162
|
+
)
|
|
163
|
+
.mutation(({ ctx, input }) =>
|
|
164
|
+
applyRubricTemplate(ctx.user!.id, input)
|
|
165
|
+
),
|
|
166
|
+
|
|
167
|
+
applyBoundaryTemplate: protectedProcedure
|
|
168
|
+
.input(
|
|
169
|
+
z.object({ classId: z.string(), templateId: z.string() })
|
|
170
|
+
)
|
|
171
|
+
.mutation(({ ctx, input }) =>
|
|
172
|
+
applyBoundaryTemplate(ctx.user!.id, input)
|
|
173
|
+
),
|
|
174
|
+
});
|
package/src/routers/file.ts
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { createTRPCRouter, protectedProcedure } from "../trpc.js";
|
|
2
3
|
import {
|
|
3
|
-
|
|
4
|
-
protectedProcedure,
|
|
5
|
-
protectedTeacherProcedure,
|
|
6
|
-
} from "../trpc.js";
|
|
7
|
-
import {
|
|
4
|
+
deleteFileGeneric,
|
|
8
5
|
getFileSignedUrl,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
deleteFileRecord,
|
|
6
|
+
moveFileScoped,
|
|
7
|
+
renameFileScoped,
|
|
12
8
|
} from "../services/file.js";
|
|
13
9
|
|
|
10
|
+
/**
|
|
11
|
+
* File router. Backed by the same unified scope-aware permission model as the
|
|
12
|
+
* folder router. The class files page and the cloud-storage page (personal /
|
|
13
|
+
* institution) both run through the same endpoints.
|
|
14
|
+
*
|
|
15
|
+
* Permissions are derived from the file's parent folder scope, so callers
|
|
16
|
+
* never need to send `classId` / `scope` — just the file id.
|
|
17
|
+
*/
|
|
14
18
|
export const fileRouter = createTRPCRouter({
|
|
15
19
|
getSignedUrl: protectedProcedure
|
|
16
20
|
.input(z.object({ fileId: z.string() }))
|
|
@@ -18,38 +22,37 @@ export const fileRouter = createTRPCRouter({
|
|
|
18
22
|
getFileSignedUrl(ctx.user!.id, input.fileId)
|
|
19
23
|
),
|
|
20
24
|
|
|
21
|
-
move:
|
|
25
|
+
move: protectedProcedure
|
|
22
26
|
.input(
|
|
23
27
|
z.object({
|
|
24
28
|
fileId: z.string(),
|
|
25
29
|
targetFolderId: z.string(),
|
|
26
|
-
classId: z.string(),
|
|
27
30
|
})
|
|
28
31
|
)
|
|
29
|
-
.mutation(({ input }) =>
|
|
30
|
-
|
|
32
|
+
.mutation(({ ctx, input }) =>
|
|
33
|
+
moveFileScoped(ctx.user!.id, {
|
|
34
|
+
fileId: input.fileId,
|
|
35
|
+
targetFolderId: input.targetFolderId,
|
|
36
|
+
})
|
|
31
37
|
),
|
|
32
38
|
|
|
33
|
-
rename:
|
|
39
|
+
rename: protectedProcedure
|
|
34
40
|
.input(
|
|
35
41
|
z.object({
|
|
36
42
|
fileId: z.string(),
|
|
37
|
-
newName: z.string(),
|
|
38
|
-
classId: z.string(),
|
|
43
|
+
newName: z.string().min(1),
|
|
39
44
|
})
|
|
40
45
|
)
|
|
41
|
-
.mutation(({ input }) =>
|
|
42
|
-
|
|
46
|
+
.mutation(({ ctx, input }) =>
|
|
47
|
+
renameFileScoped(ctx.user!.id, {
|
|
48
|
+
fileId: input.fileId,
|
|
49
|
+
newName: input.newName,
|
|
50
|
+
})
|
|
43
51
|
),
|
|
44
52
|
|
|
45
|
-
delete:
|
|
46
|
-
.input(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
classId: z.string(),
|
|
50
|
-
})
|
|
51
|
-
)
|
|
52
|
-
.mutation(({ input }) =>
|
|
53
|
-
deleteFileRecord(input.fileId, input.classId)
|
|
53
|
+
delete: protectedProcedure
|
|
54
|
+
.input(z.object({ fileId: z.string() }))
|
|
55
|
+
.mutation(({ ctx, input }) =>
|
|
56
|
+
deleteFileGeneric(ctx.user!.id, input.fileId)
|
|
54
57
|
),
|
|
55
58
|
});
|