@studious-lms/server 1.0.1 → 1.0.3
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/index.js +4 -4
- package/dist/middleware/auth.js +1 -1
- package/dist/middleware/logging.js +1 -1
- package/dist/routers/_app.js +1 -1
- package/dist/routers/agenda.js +1 -1
- package/dist/routers/announcement.js +1 -1
- package/dist/routers/assignment.js +3 -3
- package/dist/routers/attendance.js +1 -1
- package/dist/routers/auth.js +2 -2
- package/dist/routers/class.js +2 -2
- package/dist/routers/event.js +1 -1
- package/dist/routers/file.js +2 -2
- package/dist/routers/section.js +1 -1
- package/dist/routers/user.js +2 -2
- package/dist/trpc.js +2 -2
- package/package.json +1 -6
- package/prisma/schema.prisma +228 -0
- package/src/exportType.ts +9 -0
- package/src/index.ts +94 -0
- package/src/lib/fileUpload.ts +163 -0
- package/src/lib/googleCloudStorage.ts +94 -0
- package/src/lib/prisma.ts +16 -0
- package/src/lib/thumbnailGenerator.ts +185 -0
- package/src/logger.ts +163 -0
- package/src/middleware/auth.ts +191 -0
- package/src/middleware/logging.ts +54 -0
- package/src/routers/_app.ts +34 -0
- package/src/routers/agenda.ts +79 -0
- package/src/routers/announcement.ts +134 -0
- package/src/routers/assignment.ts +1614 -0
- package/src/routers/attendance.ts +284 -0
- package/src/routers/auth.ts +286 -0
- package/src/routers/class.ts +753 -0
- package/src/routers/event.ts +509 -0
- package/src/routers/file.ts +96 -0
- package/src/routers/section.ts +138 -0
- package/src/routers/user.ts +82 -0
- package/src/socket/handlers.ts +143 -0
- package/src/trpc.ts +90 -0
- package/src/types/trpc.ts +15 -0
- package/src/utils/email.ts +11 -0
- package/src/utils/generateInviteCode.ts +8 -0
- package/src/utils/logger.ts +156 -0
- package/tsconfig.json +17 -0
- package/generated/prisma/client.d.ts +0 -1
- package/generated/prisma/client.js +0 -4
- package/generated/prisma/default.d.ts +0 -1
- package/generated/prisma/default.js +0 -4
- package/generated/prisma/edge.d.ts +0 -1
- package/generated/prisma/edge.js +0 -389
- package/generated/prisma/index-browser.js +0 -375
- package/generated/prisma/index.d.ts +0 -34865
- package/generated/prisma/index.js +0 -410
- package/generated/prisma/libquery_engine-darwin-arm64.dylib.node +0 -0
- package/generated/prisma/package.json +0 -140
- package/generated/prisma/runtime/edge-esm.js +0 -34
- package/generated/prisma/runtime/edge.js +0 -34
- package/generated/prisma/runtime/index-browser.d.ts +0 -370
- package/generated/prisma/runtime/index-browser.js +0 -16
- package/generated/prisma/runtime/library.d.ts +0 -3647
- package/generated/prisma/runtime/library.js +0 -146
- package/generated/prisma/runtime/react-native.js +0 -83
- package/generated/prisma/runtime/wasm.js +0 -35
- package/generated/prisma/schema.prisma +0 -304
- package/generated/prisma/wasm.d.ts +0 -1
- package/generated/prisma/wasm.js +0 -375
package/dist/index.js
CHANGED
|
@@ -9,10 +9,10 @@ const socket_io_1 = require("socket.io");
|
|
|
9
9
|
const cors_1 = __importDefault(require("cors"));
|
|
10
10
|
const dotenv_1 = __importDefault(require("dotenv"));
|
|
11
11
|
const express_2 = require("@trpc/server/adapters/express");
|
|
12
|
-
const _app_1 = require("
|
|
13
|
-
const trpc_1 = require("
|
|
14
|
-
const logger_1 = require("
|
|
15
|
-
const handlers_1 = require("
|
|
12
|
+
const _app_1 = require("./routers/_app");
|
|
13
|
+
const trpc_1 = require("./trpc");
|
|
14
|
+
const logger_1 = require("./utils/logger");
|
|
15
|
+
const handlers_1 = require("./socket/handlers");
|
|
16
16
|
dotenv_1.default.config();
|
|
17
17
|
const app = (0, express_1.default)();
|
|
18
18
|
// CORS middleware
|
package/dist/middleware/auth.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createAuthMiddleware = void 0;
|
|
4
4
|
const server_1 = require("@trpc/server");
|
|
5
|
-
const prisma_1 = require("
|
|
5
|
+
const prisma_1 = require("../lib/prisma");
|
|
6
6
|
const createAuthMiddleware = (t) => {
|
|
7
7
|
// Auth middleware
|
|
8
8
|
const isAuthed = t.middleware(async ({ next, ctx }) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createLoggingMiddleware = void 0;
|
|
4
|
-
const logger_1 = require("
|
|
4
|
+
const logger_1 = require("../utils/logger");
|
|
5
5
|
const createLoggingMiddleware = (t) => {
|
|
6
6
|
return t.middleware(async ({ path, type, next, ctx }) => {
|
|
7
7
|
const start = Date.now();
|
package/dist/routers/_app.js
CHANGED
|
@@ -6,7 +6,7 @@ const class_1 = require("./class");
|
|
|
6
6
|
const announcement_1 = require("./announcement");
|
|
7
7
|
const assignment_1 = require("./assignment");
|
|
8
8
|
const user_1 = require("./user");
|
|
9
|
-
const trpc_2 = require("
|
|
9
|
+
const trpc_2 = require("../trpc");
|
|
10
10
|
const section_1 = require("./section");
|
|
11
11
|
const attendance_1 = require("./attendance");
|
|
12
12
|
const event_1 = require("./event");
|
package/dist/routers/agenda.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.agendaRouter = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const trpc_1 = require("../trpc");
|
|
6
|
-
const prisma_1 = require("
|
|
6
|
+
const prisma_1 = require("../lib/prisma");
|
|
7
7
|
const server_1 = require("@trpc/server");
|
|
8
8
|
const date_fns_1 = require("date-fns");
|
|
9
9
|
exports.agendaRouter = (0, trpc_1.createTRPCRouter)({
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.announcementRouter = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const trpc_1 = require("../trpc");
|
|
6
|
-
const prisma_1 = require("
|
|
6
|
+
const prisma_1 = require("../lib/prisma");
|
|
7
7
|
const server_1 = require("@trpc/server");
|
|
8
8
|
const AnnouncementSelect = {
|
|
9
9
|
id: true,
|
|
@@ -4,9 +4,9 @@ exports.assignmentRouter = void 0;
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const trpc_1 = require("../trpc");
|
|
6
6
|
const server_1 = require("@trpc/server");
|
|
7
|
-
const prisma_1 = require("
|
|
8
|
-
const fileUpload_1 = require("
|
|
9
|
-
const googleCloudStorage_1 = require("
|
|
7
|
+
const prisma_1 = require("../lib/prisma");
|
|
8
|
+
const fileUpload_1 = require("../lib/fileUpload");
|
|
9
|
+
const googleCloudStorage_1 = require("../lib/googleCloudStorage");
|
|
10
10
|
const fileSchema = zod_1.z.object({
|
|
11
11
|
name: zod_1.z.string(),
|
|
12
12
|
type: zod_1.z.string(),
|
|
@@ -4,7 +4,7 @@ exports.attendanceRouter = void 0;
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const trpc_1 = require("../trpc");
|
|
6
6
|
const server_1 = require("@trpc/server");
|
|
7
|
-
const prisma_1 = require("
|
|
7
|
+
const prisma_1 = require("../lib/prisma");
|
|
8
8
|
const attendanceSchema = zod_1.z.object({
|
|
9
9
|
eventId: zod_1.z.string().optional(),
|
|
10
10
|
present: zod_1.z.array(zod_1.z.object({ id: zod_1.z.string(), username: zod_1.z.string() })),
|
package/dist/routers/auth.js
CHANGED
|
@@ -4,10 +4,10 @@ exports.authRouter = void 0;
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const trpc_1 = require("../trpc");
|
|
6
6
|
const server_1 = require("@trpc/server");
|
|
7
|
-
const prisma_1 = require("
|
|
7
|
+
const prisma_1 = require("../lib/prisma");
|
|
8
8
|
const uuid_1 = require("uuid");
|
|
9
9
|
const bcryptjs_1 = require("bcryptjs");
|
|
10
|
-
const email_1 = require("
|
|
10
|
+
const email_1 = require("../utils/email");
|
|
11
11
|
const loginSchema = zod_1.z.object({
|
|
12
12
|
username: zod_1.z.string(),
|
|
13
13
|
password: zod_1.z.string(),
|
package/dist/routers/class.js
CHANGED
|
@@ -3,9 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.classRouter = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const trpc_1 = require("../trpc");
|
|
6
|
-
const prisma_1 = require("
|
|
6
|
+
const prisma_1 = require("../lib/prisma");
|
|
7
7
|
const server_1 = require("@trpc/server");
|
|
8
|
-
const generateInviteCode_1 = require("
|
|
8
|
+
const generateInviteCode_1 = require("../utils/generateInviteCode");
|
|
9
9
|
exports.classRouter = (0, trpc_1.createTRPCRouter)({
|
|
10
10
|
getAll: trpc_1.protectedProcedure
|
|
11
11
|
.query(async ({ ctx }) => {
|
package/dist/routers/event.js
CHANGED
|
@@ -4,7 +4,7 @@ exports.eventRouter = void 0;
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const trpc_1 = require("../trpc");
|
|
6
6
|
const server_1 = require("@trpc/server");
|
|
7
|
-
const prisma_1 = require("
|
|
7
|
+
const prisma_1 = require("../lib/prisma");
|
|
8
8
|
const date_fns_1 = require("date-fns");
|
|
9
9
|
const eventSchema = zod_1.z.object({
|
|
10
10
|
name: zod_1.z.string().optional(),
|
package/dist/routers/file.js
CHANGED
|
@@ -4,8 +4,8 @@ exports.fileRouter = void 0;
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const trpc_1 = require("../trpc");
|
|
6
6
|
const server_1 = require("@trpc/server");
|
|
7
|
-
const googleCloudStorage_1 = require("
|
|
8
|
-
const prisma_1 = require("
|
|
7
|
+
const googleCloudStorage_1 = require("../lib/googleCloudStorage");
|
|
8
|
+
const prisma_1 = require("../lib/prisma");
|
|
9
9
|
exports.fileRouter = (0, trpc_1.createTRPCRouter)({
|
|
10
10
|
getSignedUrl: trpc_1.protectedProcedure
|
|
11
11
|
.input(zod_1.z.object({
|
package/dist/routers/section.js
CHANGED
|
@@ -4,7 +4,7 @@ exports.sectionRouter = void 0;
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const trpc_1 = require("../trpc");
|
|
6
6
|
const server_1 = require("@trpc/server");
|
|
7
|
-
const prisma_1 = require("
|
|
7
|
+
const prisma_1 = require("../lib/prisma");
|
|
8
8
|
const createSectionSchema = zod_1.z.object({
|
|
9
9
|
classId: zod_1.z.string(),
|
|
10
10
|
name: zod_1.z.string(),
|
package/dist/routers/user.js
CHANGED
|
@@ -4,8 +4,8 @@ exports.userRouter = void 0;
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const trpc_1 = require("../trpc");
|
|
6
6
|
const server_1 = require("@trpc/server");
|
|
7
|
-
const prisma_1 = require("
|
|
8
|
-
const fileUpload_1 = require("
|
|
7
|
+
const prisma_1 = require("../lib/prisma");
|
|
8
|
+
const fileUpload_1 = require("../lib/fileUpload");
|
|
9
9
|
const fileSchema = zod_1.z.object({
|
|
10
10
|
name: zod_1.z.string(),
|
|
11
11
|
type: zod_1.z.string(),
|
package/dist/trpc.js
CHANGED
|
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createCallerFactory = exports.protectedTeacherProcedure = exports.protectedClassMemberProcedure = exports.protectedProcedure = exports.publicProcedure = exports.createTRPCRouter = exports.t = exports.createTRPCContext = void 0;
|
|
4
4
|
const server_1 = require("@trpc/server");
|
|
5
5
|
const zod_1 = require("zod");
|
|
6
|
-
const logger_1 = require("
|
|
7
|
-
const prisma_1 = require("
|
|
6
|
+
const logger_1 = require("./utils/logger");
|
|
7
|
+
const prisma_1 = require("./lib/prisma");
|
|
8
8
|
const logging_1 = require("./middleware/logging");
|
|
9
9
|
const auth_1 = require("./middleware/auth");
|
|
10
10
|
const zod_2 = require("zod");
|
package/package.json
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@studious-lms/server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Backend server for Studious application",
|
|
5
5
|
"main": "dist/exportType.js",
|
|
6
6
|
"types": "dist/exportType.d.ts",
|
|
7
|
-
"files": [
|
|
8
|
-
"dist/**/*",
|
|
9
|
-
"generated/**/*",
|
|
10
|
-
"README.md"
|
|
11
|
-
],
|
|
12
7
|
"scripts": {
|
|
13
8
|
"dev": "ts-node-dev -r tsconfig-paths/register --respawn --transpile-only src/index.ts",
|
|
14
9
|
"build": "tsc",
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// This is your Prisma schema file,
|
|
2
|
+
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
3
|
+
|
|
4
|
+
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
|
5
|
+
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
|
6
|
+
|
|
7
|
+
generator client {
|
|
8
|
+
provider = "prisma-client-js"
|
|
9
|
+
// output = "../generated/prisma"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
datasource db {
|
|
13
|
+
provider = "postgresql"
|
|
14
|
+
url = env("DATABASE_URL")
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
enum AssignmentType {
|
|
18
|
+
HOMEWORK
|
|
19
|
+
QUIZ
|
|
20
|
+
TEST
|
|
21
|
+
PROJECT
|
|
22
|
+
ESSAY
|
|
23
|
+
DISCUSSION
|
|
24
|
+
PRESENTATION
|
|
25
|
+
LAB
|
|
26
|
+
OTHER
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
model User {
|
|
31
|
+
id String @id @default(uuid())
|
|
32
|
+
username String
|
|
33
|
+
email String
|
|
34
|
+
password String
|
|
35
|
+
profile UserProfile?
|
|
36
|
+
verified Boolean @default(false)
|
|
37
|
+
|
|
38
|
+
profileId String? @unique
|
|
39
|
+
|
|
40
|
+
teacherIn Class[] @relation("UserTeacherToClass")
|
|
41
|
+
studentIn Class[] @relation("UserStudentToClass")
|
|
42
|
+
|
|
43
|
+
submissions Submission[]
|
|
44
|
+
sessions Session[]
|
|
45
|
+
files File[]
|
|
46
|
+
assignments Assignment[]
|
|
47
|
+
events Event[]
|
|
48
|
+
announcements Announcement[]
|
|
49
|
+
|
|
50
|
+
presentAttendance Attendance[] @relation("PresentAttendance")
|
|
51
|
+
lateAttendance Attendance[] @relation("LateAttendance")
|
|
52
|
+
absentAttendance Attendance[] @relation("AbsentAttendance")
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
model UserProfile {
|
|
56
|
+
id String @id @default(uuid())
|
|
57
|
+
userId String @unique
|
|
58
|
+
user User? @relation(fields: [userId], references: [id])
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
model Class {
|
|
63
|
+
id String @id @default(uuid())
|
|
64
|
+
name String
|
|
65
|
+
subject String
|
|
66
|
+
color String? @default("#3B82F6")
|
|
67
|
+
section String
|
|
68
|
+
announcements Announcement[]
|
|
69
|
+
assignments Assignment[]
|
|
70
|
+
attendance Attendance[]
|
|
71
|
+
events Event[]
|
|
72
|
+
sections Section[]
|
|
73
|
+
sessions Session[]
|
|
74
|
+
students User[] @relation("UserStudentToClass")
|
|
75
|
+
teachers User[] @relation("UserTeacherToClass")
|
|
76
|
+
markSchemes MarkScheme[] @relation("ClassToMarkScheme")
|
|
77
|
+
gradingBoundaries GradingBoundary[] @relation("ClassToGradingBoundary")
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
model MarkScheme {
|
|
81
|
+
id String @id @default(uuid())
|
|
82
|
+
classId String
|
|
83
|
+
class Class[] @relation("ClassToMarkScheme")
|
|
84
|
+
structured String
|
|
85
|
+
assignments Assignment[]
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
model GradingBoundary {
|
|
89
|
+
id String @id @default(uuid())
|
|
90
|
+
classId String
|
|
91
|
+
class Class[] @relation("ClassToGradingBoundary")
|
|
92
|
+
structured String
|
|
93
|
+
assignments Assignment[]
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
model File {
|
|
97
|
+
id String @id @default(uuid())
|
|
98
|
+
name String
|
|
99
|
+
path String
|
|
100
|
+
size Int?
|
|
101
|
+
type String
|
|
102
|
+
user User? @relation(fields: [userId], references: [id])
|
|
103
|
+
userId String?
|
|
104
|
+
uploadedAt DateTime? @default(now())
|
|
105
|
+
|
|
106
|
+
// Thumbnail relationship
|
|
107
|
+
thumbnail File? @relation("Thumbnail", fields: [thumbnailId], references: [id])
|
|
108
|
+
thumbnailId String? @unique
|
|
109
|
+
originalFile File? @relation("Thumbnail")
|
|
110
|
+
|
|
111
|
+
assignment Assignment? @relation(fields: [assignmentId], references: [id], onDelete: Cascade)
|
|
112
|
+
assignmentId String?
|
|
113
|
+
|
|
114
|
+
submission Submission? @relation("SubmissionFile", fields: [submissionId], references: [id], onDelete: Cascade)
|
|
115
|
+
submissionId String?
|
|
116
|
+
|
|
117
|
+
annotations Submission? @relation("SubmissionAnnotations", fields: [annotationId], references: [id], onDelete: Cascade)
|
|
118
|
+
annotationId String?
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
model Assignment {
|
|
122
|
+
id String @id @default(uuid())
|
|
123
|
+
title String
|
|
124
|
+
instructions String
|
|
125
|
+
dueDate DateTime
|
|
126
|
+
createdAt DateTime? @default(now())
|
|
127
|
+
modifiedAt DateTime? @updatedAt
|
|
128
|
+
teacher User @relation(fields: [teacherId], references: [id], onDelete: NoAction)
|
|
129
|
+
teacherId String
|
|
130
|
+
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
131
|
+
classId String
|
|
132
|
+
attachments File[]
|
|
133
|
+
submissions Submission[]
|
|
134
|
+
section Section? @relation(fields: [sectionId], references: [id], onDelete: Cascade)
|
|
135
|
+
sectionId String?
|
|
136
|
+
graded Boolean @default(false)
|
|
137
|
+
maxGrade Int? @default(0)
|
|
138
|
+
weight Float @default(1)
|
|
139
|
+
type AssignmentType @default(HOMEWORK)
|
|
140
|
+
eventAttached Event? @relation(fields: [eventId], references: [id], onDelete: NoAction)
|
|
141
|
+
eventId String?
|
|
142
|
+
markScheme MarkScheme? @relation(fields: [markSchemeId], references: [id], onDelete: Cascade)
|
|
143
|
+
markSchemeId String?
|
|
144
|
+
gradingBoundary GradingBoundary? @relation(fields: [gradingBoundaryId], references: [id], onDelete: Cascade)
|
|
145
|
+
gradingBoundaryId String?
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
model Announcement {
|
|
149
|
+
id String @id @default(uuid())
|
|
150
|
+
remarks String
|
|
151
|
+
teacher User @relation(fields: [teacherId], references: [id])
|
|
152
|
+
teacherId String
|
|
153
|
+
createdAt DateTime @default(now())
|
|
154
|
+
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
155
|
+
classId String
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
model Submission {
|
|
159
|
+
id String @id @default(uuid())
|
|
160
|
+
createdAt DateTime @default(now())
|
|
161
|
+
modifiedAt DateTime @default(now())
|
|
162
|
+
|
|
163
|
+
assignment Assignment @relation(fields: [assignmentId], references: [id], onDelete: Cascade)
|
|
164
|
+
assignmentId String
|
|
165
|
+
|
|
166
|
+
student User @relation(fields: [studentId], references: [id])
|
|
167
|
+
studentId String
|
|
168
|
+
|
|
169
|
+
attachments File[] @relation("SubmissionFile")
|
|
170
|
+
annotations File[] @relation("SubmissionAnnotations")
|
|
171
|
+
|
|
172
|
+
gradeReceived Int?
|
|
173
|
+
|
|
174
|
+
rubricState String?
|
|
175
|
+
|
|
176
|
+
submittedAt DateTime?
|
|
177
|
+
submitted Boolean? @default(false)
|
|
178
|
+
returned Boolean? @default(false)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
model Section {
|
|
182
|
+
id String @id @default(uuid())
|
|
183
|
+
name String
|
|
184
|
+
classId String
|
|
185
|
+
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
186
|
+
assignments Assignment[]
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
model Session {
|
|
190
|
+
id String @id @default(uuid())
|
|
191
|
+
createdAt DateTime? @default(now())
|
|
192
|
+
expiresAt DateTime?
|
|
193
|
+
userId String?
|
|
194
|
+
user User? @relation(fields: [userId], references: [id], onDelete: NoAction)
|
|
195
|
+
classId String?
|
|
196
|
+
class Class? @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
model Event {
|
|
200
|
+
id String @id @default(uuid())
|
|
201
|
+
name String?
|
|
202
|
+
startTime DateTime
|
|
203
|
+
endTime DateTime
|
|
204
|
+
location String?
|
|
205
|
+
remarks String?
|
|
206
|
+
userId String?
|
|
207
|
+
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
208
|
+
classId String?
|
|
209
|
+
class Class? @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
210
|
+
color String? @default("#3B82F6")
|
|
211
|
+
assignmentsAttached Assignment[]
|
|
212
|
+
attendance Attendance[]
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
model Attendance {
|
|
216
|
+
id String @id @default(uuid())
|
|
217
|
+
date DateTime @default(now())
|
|
218
|
+
|
|
219
|
+
class Class @relation(fields: [classId], references: [id], onDelete: Cascade)
|
|
220
|
+
classId String
|
|
221
|
+
|
|
222
|
+
event Event? @relation(fields: [eventId], references: [id], onDelete: Cascade)
|
|
223
|
+
eventId String?
|
|
224
|
+
|
|
225
|
+
present User[] @relation("PresentAttendance")
|
|
226
|
+
late User[] @relation("LateAttendance")
|
|
227
|
+
absent User[] @relation("AbsentAttendance")
|
|
228
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export types for the server
|
|
3
|
+
* This is used to export the types for the server
|
|
4
|
+
* to the client via npmjs
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type { AppRouter } from "./routers/_app";
|
|
8
|
+
export type { RouterInputs } from "./routers/_app";
|
|
9
|
+
export type { RouterOutputs } from "./routers/_app";
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import type { Request, Response } from 'express';
|
|
3
|
+
import { createServer } from 'http';
|
|
4
|
+
import { Server } from 'socket.io';
|
|
5
|
+
import cors from 'cors';
|
|
6
|
+
import dotenv from 'dotenv';
|
|
7
|
+
import { createExpressMiddleware } from '@trpc/server/adapters/express';
|
|
8
|
+
import { appRouter } from './routers/_app';
|
|
9
|
+
import { createTRPCContext, createCallerFactory } from './trpc';
|
|
10
|
+
import { logger } from './utils/logger';
|
|
11
|
+
import { setupSocketHandlers } from './socket/handlers';
|
|
12
|
+
|
|
13
|
+
dotenv.config();
|
|
14
|
+
|
|
15
|
+
const app = express();
|
|
16
|
+
|
|
17
|
+
// CORS middleware
|
|
18
|
+
app.use(cors({
|
|
19
|
+
origin: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000',
|
|
20
|
+
credentials: true,
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
// Response time logging middleware
|
|
24
|
+
app.use((req, res, next) => {
|
|
25
|
+
const start = Date.now();
|
|
26
|
+
res.on('finish', () => {
|
|
27
|
+
const duration = Date.now() - start;
|
|
28
|
+
logger.info('Request completed', {
|
|
29
|
+
method: req.method,
|
|
30
|
+
path: req.path,
|
|
31
|
+
statusCode: res.statusCode,
|
|
32
|
+
duration: `${duration}ms`
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
next();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Create HTTP server
|
|
39
|
+
const httpServer = createServer(app);
|
|
40
|
+
|
|
41
|
+
// Setup Socket.IO
|
|
42
|
+
const io = new Server(httpServer, {
|
|
43
|
+
cors: {
|
|
44
|
+
origin: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000',
|
|
45
|
+
methods: ['GET', 'POST'],
|
|
46
|
+
credentials: true,
|
|
47
|
+
allowedHeaders: ['Access-Control-Allow-Origin']
|
|
48
|
+
},
|
|
49
|
+
transports: ['websocket', 'polling'],
|
|
50
|
+
pingTimeout: 60000,
|
|
51
|
+
pingInterval: 25000,
|
|
52
|
+
connectTimeout: 45000,
|
|
53
|
+
path: '/socket.io/',
|
|
54
|
+
allowEIO3: true
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Add server-level logging
|
|
58
|
+
io.engine.on('connection_error', (err) => {
|
|
59
|
+
logger.error('Socket connection error', { error: err.message });
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Setup socket handlers
|
|
63
|
+
setupSocketHandlers(io);
|
|
64
|
+
|
|
65
|
+
// Create caller
|
|
66
|
+
const createCaller = createCallerFactory(appRouter);
|
|
67
|
+
|
|
68
|
+
// Setup tRPC middleware
|
|
69
|
+
app.use(
|
|
70
|
+
'/trpc',
|
|
71
|
+
createExpressMiddleware({
|
|
72
|
+
router: appRouter,
|
|
73
|
+
createContext: async ({ req, res }: { req: Request; res: Response }) => {
|
|
74
|
+
return createTRPCContext({ req, res });
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const PORT = process.env.PORT || 3001;
|
|
80
|
+
|
|
81
|
+
httpServer.listen(PORT, () => {
|
|
82
|
+
logger.info(`Server running on port ${PORT}`, {
|
|
83
|
+
port: PORT,
|
|
84
|
+
services: ['tRPC', 'Socket.IO']
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// log all env variables
|
|
89
|
+
logger.info('Configurations', {
|
|
90
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
91
|
+
PORT: process.env.PORT,
|
|
92
|
+
NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
|
|
93
|
+
LOG_MODE: process.env.LOG_MODE,
|
|
94
|
+
});
|