feat: productionize learning engine and classroom
This commit is contained in:
1 parent
2d04197f3f
commit
ba35adfbfa
124 files changed
+9071
-796
No files matched your search
@@ -0,0 +1,69 @@
|
||||
import type { NextRequest } from 'next/server';
|
||||
import { readCourseRecordReconciled } from '@/lib/course-framework/store';
|
||||
import { authorizeLearningRuntime, runtimeUnauthorized } from '@/lib/makelore-runtime/auth';
|
||||
import { isValidClassroomJobId, readClassroomGenerationJob } from '@/lib/server/classroom-job-store';
|
||||
import { buildRequestOrigin, readClassroom } from '@/lib/server/classroom-storage';
|
||||
import {
|
||||
finalizeLargeLearningCourse,
|
||||
finalizeSingleLearningCourse,
|
||||
frozenLearningFinalizeResponse,
|
||||
} from '@/lib/makelore-course/finalize';
|
||||
import { FrozenLearningCourseMutationError } from '@/lib/makelore-course/immutability';
|
||||
|
||||
export async function POST(request: NextRequest, context: { params: Promise<{ jobId: string }> }) {
|
||||
if (!authorizeLearningRuntime(request)) return runtimeUnauthorized();
|
||||
const { jobId } = await context.params;
|
||||
const owner = request.headers.get('x-owner-user-id')?.trim();
|
||||
if (!owner || !isValidClassroomJobId(jobId)) return Response.json({ error: 'invalid_request' }, { status: 400 });
|
||||
const job = await readClassroomGenerationJob(jobId);
|
||||
try {
|
||||
if (job) {
|
||||
if (job.ownerPrincipalId !== owner) {
|
||||
return Response.json({ error: 'job_not_found' }, { status: 404 });
|
||||
}
|
||||
if (job.status !== 'succeeded' || !job.result?.classroomId) {
|
||||
return Response.json({ error: 'job_not_ready' }, { status: 409 });
|
||||
}
|
||||
const classroom = await readClassroom(job.result.classroomId);
|
||||
if (!classroom) return Response.json({ error: 'classroom_not_found' }, { status: 404 });
|
||||
const record = await finalizeSingleLearningCourse({
|
||||
jobId,
|
||||
classroom,
|
||||
baseUrl: buildRequestOrigin(request),
|
||||
requireInteractiveHtml: job.input.interactiveMode === true,
|
||||
requireNarrationAudio: job.input.enableTTS === true,
|
||||
});
|
||||
return Response.json(frozenLearningFinalizeResponse(record));
|
||||
}
|
||||
|
||||
const course = await readCourseRecordReconciled(jobId);
|
||||
if (!course || course.ownerPrincipalId !== owner) {
|
||||
return Response.json({ error: 'job_not_found' }, { status: 404 });
|
||||
}
|
||||
if (course.status !== 'completed') {
|
||||
return Response.json(
|
||||
{
|
||||
error: course.status === 'framework_ready' ? 'review_required' : 'job_not_ready',
|
||||
...(course.status === 'framework_ready'
|
||||
? { reviewUrl: `/learning-ops/courses/${course.id}` }
|
||||
: {}),
|
||||
},
|
||||
{ status: 409 },
|
||||
);
|
||||
}
|
||||
const record = await finalizeLargeLearningCourse({
|
||||
jobId,
|
||||
course,
|
||||
baseUrl: buildRequestOrigin(request),
|
||||
});
|
||||
return Response.json(frozenLearningFinalizeResponse(record));
|
||||
} catch (error) {
|
||||
if (error instanceof FrozenLearningCourseMutationError) {
|
||||
return Response.json({ error: 'course_frozen', message: error.message }, { status: 409 });
|
||||
}
|
||||
return Response.json({
|
||||
error: 'course_not_offline_complete',
|
||||
message: error instanceof Error ? error.message : 'Course finalization failed',
|
||||
}, { status: 422 });
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user