@studious-lms/server 1.0.8 → 1.1.1

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.
@@ -5,11 +5,13 @@ import { prisma } from "../lib/prisma.js";
5
5
  const createSectionSchema = z.object({
6
6
  classId: z.string(),
7
7
  name: z.string(),
8
+ color: z.string().optional(),
8
9
  });
9
10
  const updateSectionSchema = z.object({
10
11
  id: z.string(),
11
12
  classId: z.string(),
12
13
  name: z.string(),
14
+ color: z.string().optional(),
13
15
  });
14
16
  const deleteSectionSchema = z.object({
15
17
  id: z.string(),
@@ -48,6 +50,9 @@ export const sectionRouter = createTRPCRouter({
48
50
  class: {
49
51
  connect: { id: input.classId },
50
52
  },
53
+ ...(input.color && {
54
+ color: input.color,
55
+ }),
51
56
  },
52
57
  });
53
58
  return section;
@@ -82,10 +87,51 @@ export const sectionRouter = createTRPCRouter({
82
87
  where: { id: input.id },
83
88
  data: {
84
89
  name: input.name,
90
+ ...(input.color && {
91
+ color: input.color,
92
+ }),
85
93
  },
86
94
  });
87
95
  return section;
88
96
  }),
97
+ reOrder: protectedProcedure
98
+ .input(z.object({
99
+ id: z.string(),
100
+ classId: z.string(),
101
+ order: z.number(),
102
+ }))
103
+ .mutation(async ({ ctx, input }) => {
104
+ if (!ctx.user) {
105
+ throw new TRPCError({
106
+ code: "UNAUTHORIZED",
107
+ message: "User must be authenticated",
108
+ });
109
+ }
110
+ // Verify user is a teacher of the class
111
+ const classData = await prisma.class.findFirst({
112
+ where: {
113
+ id: input.classId,
114
+ teachers: {
115
+ some: {
116
+ id: ctx.user.id,
117
+ },
118
+ },
119
+ },
120
+ });
121
+ if (!classData) {
122
+ throw new TRPCError({
123
+ code: "NOT_FOUND",
124
+ message: "Class not found or you are not a teacher",
125
+ });
126
+ }
127
+ await prisma.section.update({
128
+ where: { id: input.id },
129
+ data: {
130
+ order: input.order,
131
+ },
132
+ });
133
+ return { id: input.id };
134
+ }),
89
135
  delete: protectedProcedure
90
136
  .input(deleteSectionSchema)
91
137
  .mutation(async ({ ctx, input }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@studious-lms/server",
3
- "version": "1.0.8",
3
+ "version": "1.1.1",
4
4
  "description": "Backend server for Studious application",
5
5
  "main": "dist/exportType.js",
6
6
  "types": "dist/exportType.d.ts",
@@ -132,6 +132,7 @@ model Folder {
132
132
  childFolders Folder[] @relation("ParentChildFolders")
133
133
  parentFolder Folder? @relation("ParentChildFolders", fields: [parentFolderId], references: [id])
134
134
  parentFolderId String?
135
+ color String? @default("#3B82F6")
135
136
  class Class? @relation("ClassFiles", fields: [classId], references: [id])
136
137
  classId String? @unique
137
138
  }
@@ -194,6 +195,7 @@ model Assignment {
194
195
  eventId String?
195
196
  markScheme MarkScheme? @relation(fields: [markSchemeId], references: [id], onDelete: Cascade)
196
197
  markSchemeId String?
198
+ order Int?
197
199
  gradingBoundary GradingBoundary? @relation(fields: [gradingBoundaryId], references: [id], onDelete: Cascade)
198
200
  gradingBoundaryId String?
199
201
  }
@@ -227,6 +229,7 @@ model Submission {
227
229
  gradeReceived Int?
228
230
 
229
231
  rubricState String?
232
+ teacherComments String?
230
233
 
231
234
  submittedAt DateTime?
232
235
  submitted Boolean? @default(false)
@@ -239,6 +242,8 @@ model Section {
239
242
  classId String
240
243
  class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
241
244
  assignments Assignment[]
245
+ color String? @default("#3B82F6")
246
+ order Int?
242
247
  }
243
248
 
244
249
  model Session {
@@ -84,6 +84,23 @@ const updateSubmissionSchema = z.object({
84
84
  });
85
85
 
86
86
  export const assignmentRouter = createTRPCRouter({
87
+ order: protectedTeacherProcedure
88
+ .input(z.object({
89
+ id: z.string(),
90
+ classId: z.string(),
91
+ order: z.number(),
92
+ }))
93
+ .mutation(async ({ ctx, input }) => {
94
+ const { id, order } = input;
95
+
96
+ const assignment = await prisma.assignment.update({
97
+ where: { id },
98
+ data: { order },
99
+ });
100
+
101
+ return assignment;
102
+ }),
103
+
87
104
  create: protectedProcedure
88
105
  .input(createAssignmentSchema)
89
106
  .mutation(async ({ ctx, input }) => {
@@ -168,25 +168,30 @@ export const classRouter = createTRPCRouter({
168
168
  },
169
169
  });
170
170
 
171
+
172
+ if (!classData) {
173
+ throw new Error('Class not found');
174
+ }
175
+
176
+ const formattedClassData = {
177
+ ...classData,
178
+ assignments: classData.assignments.map(assignment => ({
179
+ ...assignment,
180
+ late: assignment.dueDate < new Date(),
181
+ submitted: assignment.submissions.some(submission => submission.studentId === ctx.user?.id),
182
+ returned: assignment.submissions.some(submission => submission.studentId === ctx.user?.id && submission.returned),
183
+ })),
184
+ }
185
+
171
186
  const sections = await prisma.section.findMany({
172
187
  where: {
173
188
  classId: classId,
174
189
  },
175
190
  });
176
191
 
177
- if (!classData) {
178
- throw new Error('Class not found');
179
- }
180
-
181
192
  return {
182
193
  class: {
183
- ...classData,
184
- assignments: classData.assignments.map(assignment => ({
185
- ...assignment,
186
- late: assignment.dueDate < new Date(),
187
- submitted: assignment.submissions.some(submission => submission.studentId === ctx.user?.id),
188
- returned: assignment.submissions.some(submission => submission.studentId === ctx.user?.id && submission.returned),
189
- })),
194
+ ...formattedClassData,
190
195
  sections,
191
196
  },
192
197
  };
@@ -14,6 +14,7 @@ const fileSchema = z.object({
14
14
  const createFolderSchema = z.object({
15
15
  name: z.string(),
16
16
  parentFolderId: z.string().optional(),
17
+ color: z.string().optional(),
17
18
  });
18
19
 
19
20
  const uploadFilesToFolderSchema = z.object({
@@ -29,7 +30,7 @@ export const folderRouter = createTRPCRouter({
29
30
  create: protectedTeacherProcedure
30
31
  .input(createFolderSchema)
31
32
  .mutation(async ({ ctx, input }) => {
32
- const { classId, name } = input;
33
+ const { classId, name, color } = input;
33
34
  let parentFolderId = input.parentFolderId || null;
34
35
 
35
36
  if (!ctx.user) {
@@ -75,6 +76,9 @@ export const folderRouter = createTRPCRouter({
75
76
  class: {
76
77
  connect: { id: classId },
77
78
  },
79
+ ...(color && {
80
+ color: color,
81
+ }),
78
82
  },
79
83
  });
80
84
  }
@@ -104,6 +108,9 @@ export const folderRouter = createTRPCRouter({
104
108
  connect: { id: parentFolderId },
105
109
  },
106
110
  }),
111
+ ...(color && {
112
+ color: color,
113
+ }),
107
114
  },
108
115
  include: {
109
116
  files: {
@@ -682,14 +689,15 @@ export const folderRouter = createTRPCRouter({
682
689
  return updatedFolder;
683
690
  }),
684
691
 
685
- rename: protectedTeacherProcedure
692
+ update: protectedTeacherProcedure
686
693
  .input(z.object({
687
694
  folderId: z.string(),
688
- newName: z.string(),
695
+ name: z.string(),
696
+ color: z.string().optional(),
689
697
  classId: z.string(),
690
698
  }))
691
699
  .mutation(async ({ ctx, input }) => {
692
- const { folderId, newName, classId } = input;
700
+ const { folderId, name, color, classId } = input;
693
701
 
694
702
  // Get the folder
695
703
  const folder = await prisma.folder.findFirst({
@@ -706,7 +714,7 @@ export const folderRouter = createTRPCRouter({
706
714
  }
707
715
 
708
716
  // Validate new name
709
- if (!newName.trim()) {
717
+ if (!name.trim()) {
710
718
  throw new TRPCError({
711
719
  code: "BAD_REQUEST",
712
720
  message: "Folder name cannot be empty",
@@ -717,7 +725,10 @@ export const folderRouter = createTRPCRouter({
717
725
  const updatedFolder = await prisma.folder.update({
718
726
  where: { id: folderId },
719
727
  data: {
720
- name: newName.trim(),
728
+ name: name.trim(),
729
+ ...(color && {
730
+ color: color,
731
+ }),
721
732
  },
722
733
  include: {
723
734
  files: {
@@ -6,12 +6,14 @@ import { prisma } from "../lib/prisma.js";
6
6
  const createSectionSchema = z.object({
7
7
  classId: z.string(),
8
8
  name: z.string(),
9
+ color: z.string().optional(),
9
10
  });
10
11
 
11
12
  const updateSectionSchema = z.object({
12
13
  id: z.string(),
13
14
  classId: z.string(),
14
15
  name: z.string(),
16
+ color: z.string().optional(),
15
17
  });
16
18
 
17
19
  const deleteSectionSchema = z.object({
@@ -55,6 +57,9 @@ export const sectionRouter = createTRPCRouter({
55
57
  class: {
56
58
  connect: { id: input.classId },
57
59
  },
60
+ ...(input.color && {
61
+ color: input.color,
62
+ }),
58
63
  },
59
64
  });
60
65
 
@@ -94,12 +99,58 @@ export const sectionRouter = createTRPCRouter({
94
99
  where: { id: input.id },
95
100
  data: {
96
101
  name: input.name,
102
+ ...(input.color && {
103
+ color: input.color,
104
+ }),
97
105
  },
98
106
  });
99
107
 
100
108
  return section;
101
109
  }),
102
110
 
111
+ reOrder: protectedProcedure
112
+ .input(z.object({
113
+ id: z.string(),
114
+ classId: z.string(),
115
+ order: z.number(),
116
+ }))
117
+ .mutation(async ({ ctx, input }) => {
118
+ if (!ctx.user) {
119
+ throw new TRPCError({
120
+ code: "UNAUTHORIZED",
121
+ message: "User must be authenticated",
122
+ });
123
+ }
124
+
125
+ // Verify user is a teacher of the class
126
+ const classData = await prisma.class.findFirst({
127
+ where: {
128
+ id: input.classId,
129
+ teachers: {
130
+ some: {
131
+ id: ctx.user.id,
132
+ },
133
+ },
134
+ },
135
+ });
136
+
137
+ if (!classData) {
138
+ throw new TRPCError({
139
+ code: "NOT_FOUND",
140
+ message: "Class not found or you are not a teacher",
141
+ });
142
+ }
143
+
144
+ await prisma.section.update({
145
+ where: { id: input.id },
146
+ data: {
147
+ order: input.order,
148
+ },
149
+ });
150
+
151
+ return { id: input.id };
152
+ }),
153
+
103
154
  delete: protectedProcedure
104
155
  .input(deleteSectionSchema)
105
156
  .mutation(async ({ ctx, input }) => {