@studious-lms/server 1.0.4 → 1.0.7
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/API_SPECIFICATION.md +1117 -0
- package/dist/exportType.js +1 -2
- package/dist/index.js +25 -30
- package/dist/lib/fileUpload.d.ts.map +1 -1
- package/dist/lib/fileUpload.js +31 -29
- package/dist/lib/googleCloudStorage.js +9 -14
- package/dist/lib/prisma.js +4 -7
- package/dist/lib/thumbnailGenerator.js +12 -20
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +17 -22
- package/dist/middleware/logging.js +5 -9
- package/dist/routers/_app.d.ts +3483 -1801
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +28 -27
- package/dist/routers/agenda.d.ts +13 -8
- package/dist/routers/agenda.d.ts.map +1 -1
- package/dist/routers/agenda.js +14 -17
- package/dist/routers/announcement.d.ts +4 -3
- package/dist/routers/announcement.d.ts.map +1 -1
- package/dist/routers/announcement.js +28 -31
- package/dist/routers/assignment.d.ts +282 -196
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/assignment.js +256 -202
- package/dist/routers/attendance.d.ts +5 -4
- package/dist/routers/attendance.d.ts.map +1 -1
- package/dist/routers/attendance.js +31 -34
- package/dist/routers/auth.d.ts +1 -0
- package/dist/routers/auth.d.ts.map +1 -1
- package/dist/routers/auth.js +80 -75
- package/dist/routers/class.d.ts +284 -14
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/class.js +435 -164
- package/dist/routers/event.d.ts +47 -38
- package/dist/routers/event.d.ts.map +1 -1
- package/dist/routers/event.js +76 -79
- package/dist/routers/file.d.ts +71 -1
- package/dist/routers/file.d.ts.map +1 -1
- package/dist/routers/file.js +267 -32
- package/dist/routers/folder.d.ts +296 -0
- package/dist/routers/folder.d.ts.map +1 -0
- package/dist/routers/folder.js +693 -0
- package/dist/routers/notifications.d.ts +103 -0
- package/dist/routers/notifications.d.ts.map +1 -0
- package/dist/routers/notifications.js +91 -0
- package/dist/routers/school.d.ts +208 -0
- package/dist/routers/school.d.ts.map +1 -0
- package/dist/routers/school.js +481 -0
- package/dist/routers/section.d.ts +1 -0
- package/dist/routers/section.d.ts.map +1 -1
- package/dist/routers/section.js +30 -33
- package/dist/routers/user.d.ts +2 -1
- package/dist/routers/user.d.ts.map +1 -1
- package/dist/routers/user.js +21 -24
- package/dist/seedDatabase.d.ts +22 -0
- package/dist/seedDatabase.d.ts.map +1 -0
- package/dist/seedDatabase.js +57 -0
- package/dist/socket/handlers.js +26 -30
- package/dist/trpc.d.ts +5 -0
- package/dist/trpc.d.ts.map +1 -1
- package/dist/trpc.js +35 -26
- package/dist/types/trpc.js +1 -2
- package/dist/utils/email.js +2 -8
- package/dist/utils/generateInviteCode.js +1 -5
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +13 -9
- package/dist/utils/prismaErrorHandler.d.ts +9 -0
- package/dist/utils/prismaErrorHandler.d.ts.map +1 -0
- package/dist/utils/prismaErrorHandler.js +234 -0
- package/dist/utils/prismaWrapper.d.ts +14 -0
- package/dist/utils/prismaWrapper.d.ts.map +1 -0
- package/dist/utils/prismaWrapper.js +64 -0
- package/package.json +17 -4
- package/prisma/migrations/20250807062924_init/migration.sql +436 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +67 -0
- package/src/index.ts +2 -2
- package/src/lib/fileUpload.ts +16 -7
- package/src/middleware/auth.ts +0 -2
- package/src/routers/_app.ts +5 -1
- package/src/routers/assignment.ts +82 -22
- package/src/routers/auth.ts +80 -54
- package/src/routers/class.ts +330 -36
- package/src/routers/file.ts +283 -20
- package/src/routers/folder.ts +755 -0
- package/src/routers/notifications.ts +93 -0
- package/src/seedDatabase.ts +66 -0
- package/src/socket/handlers.ts +4 -4
- package/src/trpc.ts +13 -0
- package/src/utils/logger.ts +14 -4
- package/src/utils/prismaErrorHandler.ts +275 -0
- package/src/utils/prismaWrapper.ts +91 -0
- package/tests/auth.test.ts +25 -0
- package/tests/class.test.ts +281 -0
- package/tests/setup.ts +98 -0
- package/tests/startup.test.ts +5 -0
- package/tsconfig.json +2 -1
- package/vitest.config.ts +11 -0
- package/dist/logger.d.ts +0 -26
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -135
- package/src/logger.ts +0 -163
|
@@ -5,6 +5,7 @@ export declare const attendanceRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
5
5
|
errorShape: {
|
|
6
6
|
data: {
|
|
7
7
|
zodError: z.typeToFlattenedError<any, string> | null;
|
|
8
|
+
prismaError: import("../utils/prismaErrorHandler").PrismaErrorInfo | null;
|
|
8
9
|
code: import("@trpc/server").TRPC_ERROR_CODE_KEY;
|
|
9
10
|
httpStatus: number;
|
|
10
11
|
path?: string;
|
|
@@ -25,9 +26,9 @@ export declare const attendanceRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
25
26
|
id: string;
|
|
26
27
|
name: string | null;
|
|
27
28
|
color: string | null;
|
|
29
|
+
location: string | null;
|
|
28
30
|
startTime: Date;
|
|
29
31
|
endTime: Date;
|
|
30
|
-
location: string | null;
|
|
31
32
|
} | null;
|
|
32
33
|
late: {
|
|
33
34
|
id: string;
|
|
@@ -44,8 +45,8 @@ export declare const attendanceRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
44
45
|
} & {
|
|
45
46
|
id: string;
|
|
46
47
|
classId: string;
|
|
47
|
-
date: Date;
|
|
48
48
|
eventId: string | null;
|
|
49
|
+
date: Date;
|
|
49
50
|
})[];
|
|
50
51
|
meta: object;
|
|
51
52
|
}>;
|
|
@@ -73,9 +74,9 @@ export declare const attendanceRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
73
74
|
event: {
|
|
74
75
|
id: string;
|
|
75
76
|
name: string | null;
|
|
77
|
+
location: string | null;
|
|
76
78
|
startTime: Date;
|
|
77
79
|
endTime: Date;
|
|
78
|
-
location: string | null;
|
|
79
80
|
} | null;
|
|
80
81
|
late: {
|
|
81
82
|
id: string;
|
|
@@ -92,8 +93,8 @@ export declare const attendanceRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
92
93
|
} & {
|
|
93
94
|
id: string;
|
|
94
95
|
classId: string;
|
|
95
|
-
date: Date;
|
|
96
96
|
eventId: string | null;
|
|
97
|
+
date: Date;
|
|
97
98
|
};
|
|
98
99
|
meta: object;
|
|
99
100
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attendance.d.ts","sourceRoot":"","sources":["../../src/routers/attendance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB,eAAO,MAAM,gBAAgB
|
|
1
|
+
{"version":3,"file":"attendance.d.ts","sourceRoot":"","sources":["../../src/routers/attendance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+Q3B,CAAC"}
|
|
@@ -1,31 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
present: zod_1.z.array(zod_1.z.object({ id: zod_1.z.string(), username: zod_1.z.string() })),
|
|
11
|
-
late: zod_1.z.array(zod_1.z.object({ id: zod_1.z.string(), username: zod_1.z.string() })),
|
|
12
|
-
absent: zod_1.z.array(zod_1.z.object({ id: zod_1.z.string(), username: zod_1.z.string() })),
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
|
3
|
+
import { TRPCError } from "@trpc/server";
|
|
4
|
+
import { prisma } from "../lib/prisma";
|
|
5
|
+
const attendanceSchema = z.object({
|
|
6
|
+
eventId: z.string().optional(),
|
|
7
|
+
present: z.array(z.object({ id: z.string(), username: z.string() })),
|
|
8
|
+
late: z.array(z.object({ id: z.string(), username: z.string() })),
|
|
9
|
+
absent: z.array(z.object({ id: z.string(), username: z.string() })),
|
|
13
10
|
});
|
|
14
|
-
|
|
15
|
-
get:
|
|
16
|
-
.input(
|
|
17
|
-
classId:
|
|
18
|
-
eventId:
|
|
11
|
+
export const attendanceRouter = createTRPCRouter({
|
|
12
|
+
get: protectedProcedure
|
|
13
|
+
.input(z.object({
|
|
14
|
+
classId: z.string(),
|
|
15
|
+
eventId: z.string().optional(),
|
|
19
16
|
}))
|
|
20
17
|
.query(async ({ ctx, input }) => {
|
|
21
18
|
if (!ctx.user) {
|
|
22
|
-
throw new
|
|
19
|
+
throw new TRPCError({
|
|
23
20
|
code: "UNAUTHORIZED",
|
|
24
21
|
message: "You must be logged in to view attendance",
|
|
25
22
|
});
|
|
26
23
|
}
|
|
27
24
|
// Check if user is a teacher or student of the class
|
|
28
|
-
const classData = await
|
|
25
|
+
const classData = await prisma.class.findUnique({
|
|
29
26
|
where: {
|
|
30
27
|
id: input.classId,
|
|
31
28
|
OR: [
|
|
@@ -54,25 +51,25 @@ exports.attendanceRouter = (0, trpc_1.createTRPCRouter)({
|
|
|
54
51
|
},
|
|
55
52
|
});
|
|
56
53
|
if (!classData) {
|
|
57
|
-
throw new
|
|
54
|
+
throw new TRPCError({
|
|
58
55
|
code: "UNAUTHORIZED",
|
|
59
56
|
message: "You are not authorized to view this class's attendance",
|
|
60
57
|
});
|
|
61
58
|
}
|
|
62
59
|
// check each event has an attendance, if not create one
|
|
63
|
-
const events = await
|
|
60
|
+
const events = await prisma.event.findMany({
|
|
64
61
|
where: {
|
|
65
62
|
classId: input.classId,
|
|
66
63
|
},
|
|
67
64
|
});
|
|
68
65
|
for (const event of events) {
|
|
69
|
-
const attendance = await
|
|
66
|
+
const attendance = await prisma.attendance.findFirst({
|
|
70
67
|
where: {
|
|
71
68
|
eventId: event.id,
|
|
72
69
|
},
|
|
73
70
|
});
|
|
74
71
|
if (!attendance) {
|
|
75
|
-
await
|
|
72
|
+
await prisma.attendance.create({
|
|
76
73
|
data: {
|
|
77
74
|
event: {
|
|
78
75
|
connect: {
|
|
@@ -91,7 +88,7 @@ exports.attendanceRouter = (0, trpc_1.createTRPCRouter)({
|
|
|
91
88
|
});
|
|
92
89
|
}
|
|
93
90
|
}
|
|
94
|
-
const attendance = await
|
|
91
|
+
const attendance = await prisma.attendance.findMany({
|
|
95
92
|
where: {
|
|
96
93
|
classId: input.classId,
|
|
97
94
|
...(input.eventId ? { eventId: input.eventId } : {}),
|
|
@@ -132,21 +129,21 @@ exports.attendanceRouter = (0, trpc_1.createTRPCRouter)({
|
|
|
132
129
|
});
|
|
133
130
|
return attendance;
|
|
134
131
|
}),
|
|
135
|
-
update:
|
|
136
|
-
.input(
|
|
137
|
-
classId:
|
|
138
|
-
eventId:
|
|
132
|
+
update: protectedProcedure
|
|
133
|
+
.input(z.object({
|
|
134
|
+
classId: z.string(),
|
|
135
|
+
eventId: z.string().optional(),
|
|
139
136
|
attendance: attendanceSchema,
|
|
140
137
|
}))
|
|
141
138
|
.mutation(async ({ ctx, input }) => {
|
|
142
139
|
if (!ctx.user) {
|
|
143
|
-
throw new
|
|
140
|
+
throw new TRPCError({
|
|
144
141
|
code: "UNAUTHORIZED",
|
|
145
142
|
message: "You must be logged in to update attendance",
|
|
146
143
|
});
|
|
147
144
|
}
|
|
148
145
|
// Check if user is a teacher of the class
|
|
149
|
-
const classData = await
|
|
146
|
+
const classData = await prisma.class.findUnique({
|
|
150
147
|
where: {
|
|
151
148
|
id: input.classId,
|
|
152
149
|
teachers: {
|
|
@@ -157,13 +154,13 @@ exports.attendanceRouter = (0, trpc_1.createTRPCRouter)({
|
|
|
157
154
|
},
|
|
158
155
|
});
|
|
159
156
|
if (!classData) {
|
|
160
|
-
throw new
|
|
157
|
+
throw new TRPCError({
|
|
161
158
|
code: "UNAUTHORIZED",
|
|
162
159
|
message: "You are not authorized to update this class's attendance",
|
|
163
160
|
});
|
|
164
161
|
}
|
|
165
162
|
// Check if attendance record exists
|
|
166
|
-
const existingAttendance = await
|
|
163
|
+
const existingAttendance = await prisma.attendance.findFirst({
|
|
167
164
|
where: {
|
|
168
165
|
classId: input.classId,
|
|
169
166
|
eventId: input.eventId,
|
|
@@ -171,7 +168,7 @@ exports.attendanceRouter = (0, trpc_1.createTRPCRouter)({
|
|
|
171
168
|
});
|
|
172
169
|
if (!existingAttendance) {
|
|
173
170
|
// Create new attendance record
|
|
174
|
-
const attendance = await
|
|
171
|
+
const attendance = await prisma.attendance.create({
|
|
175
172
|
data: {
|
|
176
173
|
classId: input.classId,
|
|
177
174
|
eventId: input.eventId,
|
|
@@ -219,7 +216,7 @@ exports.attendanceRouter = (0, trpc_1.createTRPCRouter)({
|
|
|
219
216
|
return attendance;
|
|
220
217
|
}
|
|
221
218
|
// Update existing attendance record
|
|
222
|
-
const attendance = await
|
|
219
|
+
const attendance = await prisma.attendance.update({
|
|
223
220
|
where: {
|
|
224
221
|
id: existingAttendance.id,
|
|
225
222
|
},
|
package/dist/routers/auth.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export declare const authRouter: import("@trpc/server").TRPCBuiltRouter<{
|
|
|
5
5
|
errorShape: {
|
|
6
6
|
data: {
|
|
7
7
|
zodError: z.typeToFlattenedError<any, string> | null;
|
|
8
|
+
prismaError: import("../utils/prismaErrorHandler").PrismaErrorInfo | null;
|
|
8
9
|
code: import("@trpc/server").TRPC_ERROR_CODE_KEY;
|
|
9
10
|
httpStatus: number;
|
|
10
11
|
path?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/routers/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/routers/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAwBxB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+RrB,CAAC"}
|
package/dist/routers/auth.js
CHANGED
|
@@ -1,33 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const loginSchema = zod_1.z.object({
|
|
12
|
-
username: zod_1.z.string(),
|
|
13
|
-
password: zod_1.z.string(),
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
|
3
|
+
import { TRPCError } from "@trpc/server";
|
|
4
|
+
import { prisma } from "../lib/prisma";
|
|
5
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
6
|
+
import { compare, hash } from "bcryptjs";
|
|
7
|
+
import { prismaWrapper } from "../utils/prismaWrapper";
|
|
8
|
+
const loginSchema = z.object({
|
|
9
|
+
username: z.string(),
|
|
10
|
+
password: z.string(),
|
|
14
11
|
});
|
|
15
|
-
const registerSchema =
|
|
16
|
-
username:
|
|
17
|
-
email:
|
|
18
|
-
password:
|
|
19
|
-
confirmPassword:
|
|
12
|
+
const registerSchema = z.object({
|
|
13
|
+
username: z.string().min(3, "Username must be at least 3 characters"),
|
|
14
|
+
email: z.string().email("Invalid email address"),
|
|
15
|
+
password: z.string().min(6, "Password must be at least 6 characters"),
|
|
16
|
+
confirmPassword: z.string(),
|
|
20
17
|
}).refine((data) => data.password === data.confirmPassword, {
|
|
21
18
|
message: "Passwords don't match",
|
|
22
19
|
path: ["confirmPassword"],
|
|
23
20
|
});
|
|
24
|
-
|
|
25
|
-
register:
|
|
21
|
+
export const authRouter = createTRPCRouter({
|
|
22
|
+
register: publicProcedure
|
|
26
23
|
.input(registerSchema)
|
|
27
24
|
.mutation(async ({ input }) => {
|
|
28
25
|
const { username, email, password } = input;
|
|
29
26
|
// Check if username already exists
|
|
30
|
-
const existingUser = await
|
|
27
|
+
const existingUser = await prismaWrapper.findFirst(() => prisma.user.findFirst({
|
|
31
28
|
where: {
|
|
32
29
|
OR: [
|
|
33
30
|
{ username },
|
|
@@ -40,56 +37,58 @@ exports.authRouter = (0, trpc_1.createTRPCRouter)({
|
|
|
40
37
|
email: true,
|
|
41
38
|
verified: true,
|
|
42
39
|
}
|
|
43
|
-
});
|
|
40
|
+
}), 'checking for existing user during registration');
|
|
44
41
|
if (existingUser && existingUser.verified) {
|
|
45
42
|
if (existingUser.username === username) {
|
|
46
|
-
throw new
|
|
43
|
+
throw new TRPCError({
|
|
47
44
|
code: "CONFLICT",
|
|
48
45
|
message: "Username already exists",
|
|
49
46
|
});
|
|
50
47
|
}
|
|
51
48
|
if (existingUser.email === email) {
|
|
52
|
-
throw new
|
|
49
|
+
throw new TRPCError({
|
|
53
50
|
code: "CONFLICT",
|
|
54
51
|
message: "Email already exists",
|
|
55
52
|
});
|
|
56
53
|
}
|
|
57
54
|
}
|
|
58
55
|
else if (existingUser && !existingUser.verified) {
|
|
59
|
-
await
|
|
56
|
+
await prismaWrapper.deleteMany(() => prisma.session.deleteMany({
|
|
60
57
|
where: { userId: existingUser.id },
|
|
61
|
-
});
|
|
62
|
-
await
|
|
58
|
+
}), 'deleting existing sessions for unverified user');
|
|
59
|
+
await prismaWrapper.delete(() => prisma.user.delete({
|
|
63
60
|
where: { id: existingUser.id },
|
|
64
|
-
});
|
|
61
|
+
}), 'deleting unverified user');
|
|
65
62
|
}
|
|
66
63
|
// Create new user
|
|
67
|
-
const user = await
|
|
64
|
+
const user = await prismaWrapper.create(async () => await prisma.user.create({
|
|
68
65
|
data: {
|
|
69
66
|
username,
|
|
70
67
|
email,
|
|
71
|
-
password: await
|
|
68
|
+
password: await hash(password, 10),
|
|
72
69
|
profile: {},
|
|
70
|
+
verified: true, // temporary
|
|
73
71
|
},
|
|
74
72
|
select: {
|
|
75
73
|
id: true,
|
|
76
74
|
username: true,
|
|
77
75
|
email: true,
|
|
78
76
|
}
|
|
79
|
-
});
|
|
80
|
-
const verificationToken = await
|
|
77
|
+
}), 'creating new user during registration');
|
|
78
|
+
const verificationToken = await prismaWrapper.create(() => prisma.session.create({
|
|
81
79
|
data: {
|
|
82
|
-
id: (
|
|
80
|
+
id: uuidv4(),
|
|
83
81
|
userId: user.id,
|
|
84
82
|
expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30),
|
|
85
83
|
},
|
|
86
|
-
});
|
|
87
|
-
await
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
});
|
|
84
|
+
}), 'creating verification token');
|
|
85
|
+
// await transport.sendMail({
|
|
86
|
+
// from: 'noreply@studious.sh',
|
|
87
|
+
// to: user.email,
|
|
88
|
+
// subject: 'Verify your email',
|
|
89
|
+
// text: `Click the link to verify your email: ${process.env.NEXT_PUBLIC_APP_URL}/verify/${verificationToken.id}`,
|
|
90
|
+
// });
|
|
91
|
+
console.log(`${process.env.NEXT_PUBLIC_APP_URL}/verify/${verificationToken.id}`);
|
|
93
92
|
return {
|
|
94
93
|
user: {
|
|
95
94
|
id: user.id,
|
|
@@ -97,11 +96,11 @@ exports.authRouter = (0, trpc_1.createTRPCRouter)({
|
|
|
97
96
|
},
|
|
98
97
|
};
|
|
99
98
|
}),
|
|
100
|
-
login:
|
|
99
|
+
login: publicProcedure
|
|
101
100
|
.input(loginSchema)
|
|
102
101
|
.mutation(async ({ input }) => {
|
|
103
102
|
const { username, password } = input;
|
|
104
|
-
const user = await
|
|
103
|
+
const user = await prisma.user.findFirst({
|
|
105
104
|
where: { username },
|
|
106
105
|
select: {
|
|
107
106
|
id: true,
|
|
@@ -112,13 +111,13 @@ exports.authRouter = (0, trpc_1.createTRPCRouter)({
|
|
|
112
111
|
}
|
|
113
112
|
});
|
|
114
113
|
if (!user) {
|
|
115
|
-
throw new
|
|
114
|
+
throw new TRPCError({
|
|
116
115
|
code: "UNAUTHORIZED",
|
|
117
116
|
message: "Invalid username or password",
|
|
118
117
|
});
|
|
119
118
|
}
|
|
120
|
-
if (await
|
|
121
|
-
throw new
|
|
119
|
+
if (!(await compare(password, user.password))) {
|
|
120
|
+
throw new TRPCError({
|
|
122
121
|
code: "UNAUTHORIZED",
|
|
123
122
|
message: "Invalid username or password",
|
|
124
123
|
});
|
|
@@ -132,9 +131,9 @@ exports.authRouter = (0, trpc_1.createTRPCRouter)({
|
|
|
132
131
|
};
|
|
133
132
|
}
|
|
134
133
|
// Create a new session
|
|
135
|
-
const session = await
|
|
134
|
+
const session = await prisma.session.create({
|
|
136
135
|
data: {
|
|
137
|
-
id: (
|
|
136
|
+
id: uuidv4(),
|
|
138
137
|
userId: user.id,
|
|
139
138
|
expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30),
|
|
140
139
|
},
|
|
@@ -147,29 +146,29 @@ exports.authRouter = (0, trpc_1.createTRPCRouter)({
|
|
|
147
146
|
},
|
|
148
147
|
};
|
|
149
148
|
}),
|
|
150
|
-
logout:
|
|
149
|
+
logout: publicProcedure
|
|
151
150
|
.mutation(async ({ ctx }) => {
|
|
152
151
|
if (!ctx.user) {
|
|
153
|
-
throw new
|
|
152
|
+
throw new TRPCError({
|
|
154
153
|
code: "UNAUTHORIZED",
|
|
155
154
|
message: "Not authenticated",
|
|
156
155
|
});
|
|
157
156
|
}
|
|
158
157
|
// Delete the current session
|
|
159
|
-
await
|
|
158
|
+
await prisma.session.deleteMany({
|
|
160
159
|
where: { userId: ctx.user.id },
|
|
161
160
|
});
|
|
162
161
|
return { success: true };
|
|
163
162
|
}),
|
|
164
|
-
check:
|
|
163
|
+
check: protectedProcedure
|
|
165
164
|
.query(async ({ ctx }) => {
|
|
166
165
|
if (!ctx.user) {
|
|
167
|
-
throw new
|
|
166
|
+
throw new TRPCError({
|
|
168
167
|
code: "UNAUTHORIZED",
|
|
169
168
|
message: "Not authenticated",
|
|
170
169
|
});
|
|
171
170
|
}
|
|
172
|
-
const user = await
|
|
171
|
+
const user = await prisma.user.findUnique({
|
|
173
172
|
where: { id: ctx.user.id },
|
|
174
173
|
select: {
|
|
175
174
|
id: true,
|
|
@@ -177,79 +176,85 @@ exports.authRouter = (0, trpc_1.createTRPCRouter)({
|
|
|
177
176
|
}
|
|
178
177
|
});
|
|
179
178
|
if (!user) {
|
|
180
|
-
throw new
|
|
179
|
+
throw new TRPCError({
|
|
181
180
|
code: "NOT_FOUND",
|
|
182
181
|
message: "User not found",
|
|
183
182
|
});
|
|
184
183
|
}
|
|
185
184
|
return { user };
|
|
186
185
|
}),
|
|
187
|
-
resendVerificationEmail:
|
|
188
|
-
.input(
|
|
189
|
-
email:
|
|
186
|
+
resendVerificationEmail: publicProcedure
|
|
187
|
+
.input(z.object({
|
|
188
|
+
email: z.string().email(),
|
|
190
189
|
}))
|
|
191
190
|
.mutation(async ({ input }) => {
|
|
192
191
|
const { email } = input;
|
|
193
|
-
const user = await
|
|
192
|
+
const user = await prisma.user.findFirst({
|
|
194
193
|
where: {
|
|
195
194
|
email,
|
|
196
195
|
},
|
|
197
196
|
select: {
|
|
198
197
|
id: true,
|
|
199
198
|
email: true,
|
|
199
|
+
role: true,
|
|
200
|
+
schoolId: true,
|
|
200
201
|
},
|
|
201
202
|
});
|
|
202
203
|
if (!user) {
|
|
203
|
-
throw new
|
|
204
|
+
throw new TRPCError({
|
|
204
205
|
code: "NOT_FOUND",
|
|
205
206
|
message: "User not found",
|
|
206
207
|
});
|
|
207
208
|
}
|
|
208
|
-
await
|
|
209
|
+
await prisma.session.deleteMany({
|
|
209
210
|
where: { userId: user?.id },
|
|
210
211
|
});
|
|
211
|
-
const verificationToken = await
|
|
212
|
+
const verificationToken = await prisma.session.create({
|
|
212
213
|
data: {
|
|
213
|
-
id: (
|
|
214
|
+
id: uuidv4(),
|
|
214
215
|
userId: user.id,
|
|
215
216
|
expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30),
|
|
216
217
|
},
|
|
217
218
|
});
|
|
218
|
-
await
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
});
|
|
219
|
+
// await transport.sendMail({
|
|
220
|
+
// from: 'noreply@studious.sh',
|
|
221
|
+
// to: user.email,
|
|
222
|
+
// subject: 'Verify your email',
|
|
223
|
+
// text: `Click the link to verify your email: ${process.env.NEXT_PUBLIC_APP_URL}/verify/${verificationToken.id}`,
|
|
224
|
+
// });
|
|
224
225
|
return { success: true };
|
|
225
226
|
}),
|
|
226
|
-
verify:
|
|
227
|
-
.input(
|
|
228
|
-
token:
|
|
227
|
+
verify: publicProcedure
|
|
228
|
+
.input(z.object({
|
|
229
|
+
token: z.string(),
|
|
229
230
|
}))
|
|
230
231
|
.mutation(async ({ input }) => {
|
|
231
232
|
const { token } = input;
|
|
232
|
-
const session = await
|
|
233
|
+
const session = await prisma.session.findUnique({
|
|
233
234
|
where: { id: token },
|
|
234
235
|
});
|
|
235
236
|
if (!session) {
|
|
236
|
-
throw new
|
|
237
|
+
throw new TRPCError({
|
|
237
238
|
code: "NOT_FOUND",
|
|
238
239
|
message: "Session not found",
|
|
239
240
|
});
|
|
240
241
|
}
|
|
241
242
|
if (session.expiresAt && session.expiresAt < new Date()) {
|
|
242
|
-
throw new
|
|
243
|
+
throw new TRPCError({
|
|
243
244
|
code: "UNAUTHORIZED",
|
|
244
245
|
message: "Session expired",
|
|
245
246
|
});
|
|
246
247
|
}
|
|
247
|
-
await
|
|
248
|
+
await prisma.user.update({
|
|
248
249
|
where: { id: session.userId },
|
|
249
250
|
data: {
|
|
250
251
|
verified: true,
|
|
251
252
|
},
|
|
252
253
|
});
|
|
254
|
+
// Clean up the verification token
|
|
255
|
+
await prisma.session.delete({
|
|
256
|
+
where: { id: token },
|
|
257
|
+
});
|
|
253
258
|
return { success: true };
|
|
254
259
|
}),
|
|
255
260
|
});
|