diff --git a/drizzle/0001_add_gamification.sql b/drizzle/0001_add_gamification.sql deleted file mode 100644 index 56362d1..0000000 --- a/drizzle/0001_add_gamification.sql +++ /dev/null @@ -1,41 +0,0 @@ -CREATE TABLE "user_stats" ( - "user_id" text PRIMARY KEY REFERENCES "user"("id") ON DELETE CASCADE, - "total_points" integer NOT NULL DEFAULT 0, - "current_streak" integer NOT NULL DEFAULT 0, - "longest_streak" integer NOT NULL DEFAULT 0, - "last_study_date" date, - "today_active_minutes" integer NOT NULL DEFAULT 0, - "today_chat_count" integer NOT NULL DEFAULT 0, - "updated_at" timestamp NOT NULL DEFAULT now() -); - -CREATE TABLE "study_sessions" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(), - "user_id" text NOT NULL REFERENCES "user"("id") ON DELETE CASCADE, - "note_id" uuid NOT NULL REFERENCES "note"("id") ON DELETE CASCADE, - "day_date" date NOT NULL, - "active_seconds" integer NOT NULL DEFAULT 0, - "points_awarded" integer NOT NULL DEFAULT 0, - "last_activity_at" timestamp, - "created_at" timestamp NOT NULL DEFAULT now(), - "updated_at" timestamp NOT NULL DEFAULT now() -); - -CREATE UNIQUE INDEX "study_sessions_user_note_day_idx" - ON "study_sessions" ("user_id", "note_id", "day_date"); - -CREATE INDEX "study_sessions_user_day_idx" - ON "study_sessions" ("user_id", "day_date"); - -CREATE TABLE "note_completion" ( - "user_id" text NOT NULL REFERENCES "user"("id") ON DELETE CASCADE, - "note_id" uuid NOT NULL REFERENCES "note"("id") ON DELETE CASCADE, - "completed_at" timestamp NOT NULL DEFAULT now(), - PRIMARY KEY ("user_id", "note_id") -); - -CREATE INDEX "note_completion_user_idx" - ON "note_completion" ("user_id"); - -CREATE INDEX "note_completion_completed_at_idx" - ON "note_completion" ("completed_at"); diff --git a/drizzle/0002_add_teacher_verification.sql b/drizzle/0002_add_teacher_verification.sql deleted file mode 100644 index c4e8068..0000000 --- a/drizzle/0002_add_teacher_verification.sql +++ /dev/null @@ -1,6 +0,0 @@ -ALTER TABLE "user" - ADD COLUMN "teacher_verified" boolean NOT NULL DEFAULT false; - -UPDATE "user" -SET "teacher_verified" = true -WHERE "role" = 'teacher'; diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json deleted file mode 100644 index 1d6f15a..0000000 --- a/drizzle/meta/_journal.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": 1, - "dialect": "postgresql", - "entries": [] -} diff --git a/src/app/api/chat/route.ts b/src/app/api/chat/route.ts index bec0957..8d05a1c 100644 --- a/src/app/api/chat/route.ts +++ b/src/app/api/chat/route.ts @@ -28,27 +28,15 @@ export async function POST(req: Request) { return new Response("Note ID is required", { status: 400 }); } - // Save user message + award points for meaningful chat - // Save user message + award points for meaningful chat const lastMessage = messages[messages.length - 1]; - if (lastMessage?.role === "user") { - const lastMessageContent = lastMessage.parts - .filter((p) => p.type === "text") - .map((p) => p.text) - .join(""); - - // Fire and forget, or we could await if needed. - // For now, just calling them to resolve unused variable lint error. - void caller.chat.onStudentMessage({ - noteId, - content: lastMessageContent, - }); - - void caller.activity.ping({ - noteId, - eventType: "chat", - }); - } + const shouldTrack = + lastMessage?.role === "user" && lastMessage.parts?.length; + const lastMessageContent = shouldTrack + ? lastMessage.parts + .filter((p) => p.type === "text") + .map((p) => p.text) + .join("") + : ""; const modelMessages = await convertToModelMessages(messages); @@ -76,6 +64,18 @@ ${textContent ?? "No text content available."} noteId: noteId, }); } + + if (shouldTrack && lastMessageContent) { + void caller.chat.onStudentMessage({ + noteId, + content: lastMessageContent, + }); + + void caller.activity.ping({ + noteId, + eventType: "chat", + }); + } }, }); diff --git a/src/app/api/uploadthing/core.ts b/src/app/api/uploadthing/core.ts index 32098eb..10e2ce4 100644 --- a/src/app/api/uploadthing/core.ts +++ b/src/app/api/uploadthing/core.ts @@ -43,7 +43,15 @@ export const ourFileRouter = { }); } - if (existingCourse.teacherId !== context.session?.user.id) { + const requester = await caller.user.getById({ + id: context.session?.user.id ?? "", + }); + + const isOwner = + existingCourse.teacherId === context.session?.user.id; + const isAdmin = requester?.role === "admin"; + + if (!isOwner && !isAdmin) { // eslint-disable-next-line @typescript-eslint/only-throw-error throw new UploadThingError({ code: "FORBIDDEN", diff --git a/src/components/layout/main-layout.tsx b/src/components/layout/main-layout.tsx index bfd821c..c3040b3 100644 --- a/src/components/layout/main-layout.tsx +++ b/src/components/layout/main-layout.tsx @@ -9,7 +9,7 @@ export default function MainLayout({
+ Ranked by total reward points +
++ {student.name ?? "Student"} +
++ {student.totalPoints ?? 0} pts +
+