Files
Vault/app/api/videos/latest/route.ts
T
twotalesanimation 9a73058eb4
Deploy Vault CMS / deploy (push) Failing after 4m1s
Upgrade Next.js to 16.4.6 and show locks on latest videos
- Upgrade next and eslint-config-next from 16.3.5 to 16.4.6. The older
  version has critical advisories, which made the Docker build's
  `pnpm audit --audit-level critical` step fail and blocked deploys.
- /api/videos/latest now reports whether the viewer can open each video;
  the dashboard shows a lock and the reason instead of opening the player.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-11 17:56:19 +02:00

98 lines
2.7 KiB
TypeScript

// app/api/videos/latest/route.ts
import { NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth-options';
import { prisma } from '@/lib/prisma';
import { checkVideoAccess } from '@/lib/video-access';
export async function GET() {
try {
const session = await getServerSession(authOptions);
if (!session?.user?.email) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const user = await prisma.user.findUnique({
where: { email: session.user.email },
});
if (!user) {
return NextResponse.json({ error: 'User not found' }, { status: 404 });
}
// Get all courses the user is enrolled in
const enrolledCourses = await prisma.enrollment.findMany({
where: { userId: user.id },
select: { courseId: true },
});
const enrolledCourseIds = enrolledCourses.map((e) => e.courseId);
if (enrolledCourseIds.length === 0) {
return NextResponse.json({ videos: [] });
}
// Get the latest 10 videos from those courses
// Videos can be in playlists that belong to enrolled courses
const videos = await prisma.video.findMany({
where: {
playlist: {
OR: [
{ courseId: { in: enrolledCourseIds } },
{
courses: {
some: { courseId: { in: enrolledCourseIds } },
},
},
],
},
},
select: {
id: true,
title: true,
durationSec: true,
thumbnail: true,
createdAt: true,
uploader: {
select: {
id: true,
name: true,
image: true,
},
},
playlist: {
select: {
id: true,
title: true,
},
},
},
orderBy: { createdAt: 'desc' },
take: 10,
});
// Tell the dashboard which of these the user can actually open, so locked
// ones show a lock instead of leading to a refusal.
const role = (session.user as any).role;
const viewer = { id: user.id, isAdmin: role === 'admin' || role === 'superadmin' };
const withAccess = await Promise.all(
videos.map(async (video) => {
const access = await checkVideoAccess(viewer, video.id, { peek: true });
return {
...video,
accessible: access.ok,
lockReason: access.ok ? null : access.error,
};
})
);
return NextResponse.json({ videos: withAccess });
} catch (err: any) {
console.error('GET /api/videos/latest error', err);
return NextResponse.json(
{ error: err?.message ?? 'Server error' },
{ status: 500 }
);
}
}