Skip to content

Commit c8425dc

Browse files
fix(courses): use admin client for all teacher course sub-pages to fix RLS
Same root cause as the course detail page: RLS get_tenant_id() reads JWT claims which don't match the subdomain tenant. All 15 teacher course sub-pages (lessons, exams, exercises, certificates, settings, preview, community) now use createAdminClient() with manual tenant_id filtering. Auth validation via getCurrentUserId() and tenant isolation via getCurrentTenantId() (from middleware header) remain in place. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 01f8164 commit c8425dc

15 files changed

Lines changed: 30 additions & 32 deletions

File tree

app/[locale]/dashboard/teacher/courses/[courseId]/certificates/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createClient } from '@/lib/supabase/server'
1+
import { createAdminClient } from '@/lib/supabase/admin'
22
import { redirect, notFound } from 'next/navigation'
33
import Link from 'next/link'
44
import { getTranslations } from 'next-intl/server'
@@ -17,7 +17,7 @@ interface PageProps {
1717

1818
export default async function CertificatesPage({ params }: PageProps) {
1919
const { courseId } = await params
20-
const supabase = await createClient()
20+
const supabase = createAdminClient()
2121
const t = await getTranslations('dashboard.teacher.manageCourse')
2222
const tenantId = await getCurrentTenantId()
2323

app/[locale]/dashboard/teacher/courses/[courseId]/certificates/settings/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createClient } from '@/lib/supabase/server'
1+
import { createAdminClient } from '@/lib/supabase/admin'
22
import { redirect, notFound } from 'next/navigation'
33
import Link from 'next/link'
44
import { getTranslations } from 'next-intl/server'
@@ -31,7 +31,7 @@ interface PageProps {
3131

3232
export default async function CertificateSettingsPage({ params }: PageProps) {
3333
const { courseId } = await params
34-
const supabase = await createClient()
34+
const supabase = createAdminClient()
3535
const t = await getTranslations('dashboard.teacher.manageCourse')
3636
const tenantId = await getCurrentTenantId()
3737

app/[locale]/dashboard/teacher/courses/[courseId]/community/page.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { createClient } from '@/lib/supabase/server'
21
import { createAdminClient } from '@/lib/supabase/admin'
32
import {getCurrentTenantId, getCurrentUserId } from '@/lib/supabase/tenant'
43
import { getUserRole } from '@/lib/supabase/get-user-role'
@@ -16,7 +15,6 @@ interface PageProps {
1615
export default async function TeacherCourseCommunityPage({ params }: PageProps) {
1716
const { courseId } = await params
1817
const t = await getTranslations('community')
19-
const supabase = await createClient()
2018
const tenantId = await getCurrentTenantId()
2119
const role = await getUserRole()
2220
const numericCourseId = parseInt(courseId)
@@ -50,7 +48,7 @@ export default async function TeacherCourseCommunityPage({ params }: PageProps)
5048
}
5149

5250
// Check plan features for community access
53-
const { data: planFeatures } = await supabase.rpc('get_plan_features', { _tenant_id: tenantId })
51+
const { data: planFeatures } = await adminClient.rpc('get_plan_features', { _tenant_id: tenantId })
5452

5553
if (!planFeatures?.features?.community) {
5654
return (

app/[locale]/dashboard/teacher/courses/[courseId]/exams/[examId]/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createClient } from '@/lib/supabase/server'
1+
import { createAdminClient } from '@/lib/supabase/admin'
22
import { getTranslations } from 'next-intl/server'
33
import { redirect, notFound } from 'next/navigation'
44
import dynamic from 'next/dynamic'
@@ -28,7 +28,7 @@ interface PageProps {
2828

2929
export default async function EditExamPage({ params }: PageProps) {
3030
const { courseId, examId } = await params
31-
const supabase = await createClient()
31+
const supabase = createAdminClient()
3232
const t = await getTranslations('dashboard.teacher.manageCourse')
3333
const tenantId = await getCurrentTenantId()
3434

app/[locale]/dashboard/teacher/courses/[courseId]/exams/[examId]/submissions/[submissionId]/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createClient } from '@/lib/supabase/server'
1+
import { createAdminClient } from '@/lib/supabase/admin'
22
import { notFound, redirect } from 'next/navigation'
33
import { getTranslations } from 'next-intl/server'
44
import { SubmissionReview } from '@/components/teacher/submission-review'
@@ -9,7 +9,7 @@ import { revalidatePath } from 'next/cache'
99
import {getCurrentTenantId, getCurrentUserId } from '@/lib/supabase/tenant'
1010

1111
export default async function SubmissionDetailPage({ params }: { params: Promise<{ courseId: string; examId: string; submissionId: string }> }) {
12-
const supabase = await createClient()
12+
const supabase = createAdminClient()
1313
const tenantId = await getCurrentTenantId()
1414
const t = await getTranslations('dashboard.teacher')
1515
const userId = await getCurrentUserId()
@@ -124,7 +124,7 @@ export default async function SubmissionDetailPage({ params }: { params: Promise
124124
}[]
125125
}) => {
126126
'use server'
127-
const supabase = await createClient()
127+
const supabase = createAdminClient()
128128
const userId = await getCurrentUserId()
129129
if (!userId) return
130130

app/[locale]/dashboard/teacher/courses/[courseId]/exams/[examId]/submissions/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createClient } from '@/lib/supabase/server'
1+
import { createAdminClient } from '@/lib/supabase/admin'
22
import { notFound } from 'next/navigation'
33
import Link from 'next/link'
44
import { getTranslations } from 'next-intl/server'
@@ -8,7 +8,7 @@ import { ExamSubmissionsReview } from '@/components/teacher/exam-submissions-rev
88
import {getCurrentTenantId, getCurrentUserId } from '@/lib/supabase/tenant'
99

1010
export default async function SubmissionsPage({ params }: { params: Promise<{ courseId: string; examId: string }> }) {
11-
const supabase = await createClient()
11+
const supabase = createAdminClient()
1212
const tenantId = await getCurrentTenantId()
1313
const t = await getTranslations('dashboard.teacher')
1414
const userId = await getCurrentUserId()

app/[locale]/dashboard/teacher/courses/[courseId]/exams/new/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createClient } from '@/lib/supabase/server'
1+
import { createAdminClient } from '@/lib/supabase/admin'
22
import { notFound } from 'next/navigation'
33
import dynamic from 'next/dynamic'
44
import { Skeleton } from '@/components/ui/skeleton'
@@ -27,7 +27,7 @@ interface PageProps {
2727

2828
export default async function NewExamPage({ params }: PageProps) {
2929
const { courseId } = await params
30-
const supabase = await createClient()
30+
const supabase = createAdminClient()
3131
const tenantId = await getCurrentTenantId()
3232

3333
const userId = await getCurrentUserId()

app/[locale]/dashboard/teacher/courses/[courseId]/exercises/[exerciseId]/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createClient } from '@/lib/supabase/server'
1+
import { createAdminClient } from '@/lib/supabase/admin'
22
import { notFound, redirect } from 'next/navigation'
33
import { getTranslations } from 'next-intl/server'
44
import dynamic from 'next/dynamic'
@@ -29,7 +29,7 @@ interface PageProps {
2929

3030
export default async function EditExercisePage({ params }: PageProps) {
3131
const { courseId, exerciseId } = await params
32-
const supabase = await createClient()
32+
const supabase = createAdminClient()
3333
const t = await getTranslations('dashboard.teacher.manageCourse')
3434
const tEx = await getTranslations('dashboard.teacher.exerciseBuilder')
3535
const tenantId = await getCurrentTenantId()

app/[locale]/dashboard/teacher/courses/[courseId]/exercises/new/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createClient } from '@/lib/supabase/server'
1+
import { createAdminClient } from '@/lib/supabase/admin'
22
import { notFound } from 'next/navigation'
33
import { getTranslations } from 'next-intl/server'
44
import dynamic from 'next/dynamic'
@@ -28,7 +28,7 @@ interface PageProps {
2828

2929
export default async function NewExercisePage({ params }: PageProps) {
3030
const { courseId } = await params
31-
const supabase = await createClient()
31+
const supabase = createAdminClient()
3232
const t = await getTranslations('dashboard.teacher.manageCourse')
3333
const tEx = await getTranslations('dashboard.teacher.exerciseBuilder')
3434
const tenantId = await getCurrentTenantId()

app/[locale]/dashboard/teacher/courses/[courseId]/exercises/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createClient } from '@/lib/supabase/server'
1+
import { createAdminClient } from '@/lib/supabase/admin'
22
import { notFound } from 'next/navigation'
33
import Link from 'next/link'
44
import { getTranslations } from 'next-intl/server'
@@ -21,7 +21,7 @@ import * as motion from 'motion/react-client'
2121
import {getCurrentTenantId, getCurrentUserId } from '@/lib/supabase/tenant'
2222

2323
export default async function ExercisesPage({ params }: { params: Promise<{ courseId: string }> }) {
24-
const supabase = await createClient()
24+
const supabase = createAdminClient()
2525
const t = await getTranslations('dashboard.teacher.manageCourse')
2626
const tenantId = await getCurrentTenantId()
2727
const userId = await getCurrentUserId()

0 commit comments

Comments
 (0)