Skip to content

Commit 97c29dc

Browse files
committed
plan updates
1 parent 4cd5b35 commit 97c29dc

14 files changed

Lines changed: 506 additions & 11 deletions

File tree

apps/chat/src/app/api/chatbots/[chatbotId]/credits/route.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
getChatModelRegistry,
44
} from '@/src/lib/server/chatModelRegistry'
55
import { CreditsService } from '@/src/services/credits'
6+
import { prisma } from '@klicker-uzh/prisma'
67
import { JWTPayload, jwtVerify } from 'jose'
78
import { NextRequest, NextResponse } from 'next/server'
89

@@ -49,6 +50,37 @@ export async function GET(
4950
)
5051
}
5152

53+
// check participation
54+
try {
55+
const participation = await prisma.participation.findUnique({
56+
where: {
57+
courseId_participantId: {
58+
courseId:
59+
(
60+
await prisma.chatbot.findUnique({
61+
where: { id: chatbotId },
62+
select: { courseId: true },
63+
})
64+
)?.courseId ?? '',
65+
participantId: participantId,
66+
},
67+
},
68+
})
69+
70+
if (!participation) {
71+
return NextResponse.json(
72+
{ error: 'No valid participation found for this chatbot' },
73+
{ status: 403 }
74+
)
75+
}
76+
} catch (error) {
77+
console.error('Error checking participation:', error)
78+
return NextResponse.json(
79+
{ error: 'Error checking participation' },
80+
{ status: 500 }
81+
)
82+
}
83+
5284
try {
5385
const credits = await CreditsService.getUserCredits(
5486
participantId as string,

apps/chat/src/app/api/chatbots/[chatbotId]/disclaimer/route.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { DisclaimersService } from '@/src/services/disclaimers'
2+
import { prisma } from '@klicker-uzh/prisma'
23
import { jwtVerify, type JWTPayload } from 'jose'
34
import { NextRequest, NextResponse } from 'next/server'
45

@@ -47,6 +48,37 @@ export async function GET(
4748
)
4849
}
4950

51+
// check participation
52+
try {
53+
const participation = await prisma.participation.findUnique({
54+
where: {
55+
courseId_participantId: {
56+
courseId:
57+
(
58+
await prisma.chatbot.findUnique({
59+
where: { id: chatbotId },
60+
select: { courseId: true },
61+
})
62+
)?.courseId ?? '',
63+
participantId: participantId,
64+
},
65+
},
66+
})
67+
68+
if (!participation) {
69+
return NextResponse.json(
70+
{ error: 'No valid participation found for this chatbot' },
71+
{ status: 403 }
72+
)
73+
}
74+
} catch (error) {
75+
console.error('Error checking participation:', error)
76+
return NextResponse.json(
77+
{ error: 'Error checking participation' },
78+
{ status: 500 }
79+
)
80+
}
81+
5082
try {
5183
// Get disclaimer for chatbot
5284
const disclaimer =
@@ -114,6 +146,37 @@ export async function POST(
114146
)
115147
}
116148

149+
// check participation
150+
try {
151+
const participation = await prisma.participation.findUnique({
152+
where: {
153+
courseId_participantId: {
154+
courseId:
155+
(
156+
await prisma.chatbot.findUnique({
157+
where: { id: chatbotId },
158+
select: { courseId: true },
159+
})
160+
)?.courseId ?? '',
161+
participantId: participantId,
162+
},
163+
},
164+
})
165+
166+
if (!participation) {
167+
return NextResponse.json(
168+
{ error: 'No valid participation found for this chatbot' },
169+
{ status: 403 }
170+
)
171+
}
172+
} catch (error) {
173+
console.error('Error checking participation:', error)
174+
return NextResponse.json(
175+
{ error: 'Error checking participation' },
176+
{ status: 500 }
177+
)
178+
}
179+
117180
try {
118181
const body = await req.json()
119182
const { action, disclaimerId } = body

apps/frontend-control/next.config.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ let nextConfig = {
4242
},
4343
}
4444

45+
nextConfig.transpilePackages = Array.from(
46+
new Set([...(nextConfig.transpilePackages ?? []), 'formik'])
47+
)
48+
4549
if (process.env.NODE_ENV !== 'test') {
4650
const withPWA = withPWAInit(
4751
getNextPWAConfig({ NODE_ENV: process.env.NODE_ENV })

apps/frontend-manage/next.config.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ let nextConfig = {
2222
},
2323
}
2424

25+
nextConfig.transpilePackages = Array.from(
26+
new Set([...(nextConfig.transpilePackages ?? []), 'formik'])
27+
)
28+
2529
if (process.env.NODE_ENV !== 'test') {
2630
const withPWA = withPWAInit(
2731
getNextPWAConfig({ NODE_ENV: process.env.NODE_ENV })

apps/frontend-pwa/next.config.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ let nextConfig = {
1212
}),
1313
}
1414

15+
nextConfig.transpilePackages = Array.from(
16+
new Set([...(nextConfig.transpilePackages ?? []), 'formik'])
17+
)
18+
1519
if (process.env.NODE_ENV !== 'test') {
1620
const withPWA = withPWAInit(
1721
getNextPWAConfig({ NODE_ENV: process.env.NODE_ENV })

packages/graphql/src/services/courses.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -157,28 +157,24 @@ export async function ensureParticipation(
157157
try {
158158
const course = await ctx.prisma.course.findUnique({
159159
where: { id: courseId },
160-
select: { id: true, isAssessmentEnabled: true },
160+
select: { id: true },
161161
})
162162

163-
if (!course || course.isAssessmentEnabled) {
163+
if (!course) {
164164
return false
165165
}
166166

167-
await ctx.prisma.participation.upsert({
167+
const participation = await ctx.prisma.participation.findUnique({
168168
where: {
169169
courseId_participantId: {
170170
courseId,
171171
participantId: ctx.user.sub,
172172
},
173173
},
174-
create: {
175-
course: { connect: { id: courseId } },
176-
participant: { connect: { id: ctx.user.sub } },
177-
},
178-
update: {},
174+
select: { id: true },
179175
})
180176

181-
return true
177+
return participation !== null
182178
} catch (error) {
183179
console.error('ensureParticipation failed', {
184180
courseId,

project/plans_archive/PLAN-chat-credits.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
**Done on this branch**
88
- Persisted and displayed per-message `creditsUsed` (computed from token usage), enabling cost auditing per assistant response.
99
- Credits initialization/reset exists server-side via scalar chatbot fields + fixed-period logic (this differs from the JSON sketch in this doc).
10+
- Credits endpoint now enforces course membership (403 for non-members).
1011

1112
**Remaining**
1213
- Reconcile this plan with the current implementation so it matches reality.

project/plans_archive/PLAN-chatbot-disclaimer.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This plan outlines the implementation of a comprehensive disclaimer system for K
99
**Done on this branch**
1010
- Implemented disclaimer read + accept/decline endpoints (`/api/chatbots/[chatbotId]/disclaimer`) with acceptance tracked in `ChatUsageCredits`.
1111
- Enforced disclaimer acceptance in the main chat send endpoint (blocks usage when required + not accepted).
12+
- Disclaimer GET/POST now enforce course membership.
1213

1314
**Remaining**
1415
- Enforce disclaimer guard consistently across other endpoints (threads/messages/credits) and return `428 Precondition Required` with remediation info as per this plan.

0 commit comments

Comments
 (0)