55 lines
2.1 KiB
TypeScript
55 lines
2.1 KiB
TypeScript
// Large-course mode API — cancel a course generation run.
|
|
//
|
|
// POST /api/courses/:courseId/cancel
|
|
//
|
|
// Aborts the full pipeline (and any module-regeneration cascade) and cooperatively
|
|
// cancels the in-flight classroom job of the current module. Succeeded modules
|
|
// are kept; the course status flips to `cancelled` once the run settles.
|
|
|
|
import { type NextRequest } from 'next/server';
|
|
import { apiError, apiSuccess, API_ERROR_CODES } from '@/lib/server/api-response';
|
|
import { createLogger } from '@/lib/logger';
|
|
import { isValidCourseId, readCourseRecordReconciled } from '@/lib/course-framework/store';
|
|
import {
|
|
cancelCourseGenerationJob,
|
|
isCourseGenerationRunning,
|
|
} from '@/lib/course-framework/runner';
|
|
import { requireOpsAccess } from '@/lib/server/ops-access';
|
|
import { proxyLargeCourseControlToEngine } from '@/lib/makelore-runtime/ops-engine-control';
|
|
|
|
const log = createLogger('Course Cancel API');
|
|
|
|
export async function POST(
|
|
request: NextRequest,
|
|
{ params }: { params: Promise<{ courseId: string }> },
|
|
) {
|
|
const denied = await requireOpsAccess(request);
|
|
if (denied) return denied;
|
|
|
|
try {
|
|
const { courseId } = await params;
|
|
if (!isValidCourseId(courseId)) {
|
|
return apiError(API_ERROR_CODES.INVALID_REQUEST, 400, `Invalid course id: ${courseId}`);
|
|
}
|
|
const record = await readCourseRecordReconciled(courseId);
|
|
if (!record) {
|
|
return apiError(API_ERROR_CODES.INVALID_REQUEST, 404, `Course not found: ${courseId}`);
|
|
}
|
|
const proxied = await proxyLargeCourseControlToEngine({
|
|
request,
|
|
course: record,
|
|
action: 'cancel',
|
|
});
|
|
if (proxied) return proxied;
|
|
if (!isCourseGenerationRunning(courseId)) {
|
|
return apiError(API_ERROR_CODES.INVALID_REQUEST, 409, 'Course generation is not running');
|
|
}
|
|
cancelCourseGenerationJob(courseId);
|
|
log.info(`Course cancellation requested: ${courseId}`);
|
|
return apiSuccess({ courseId, message: 'Cancellation requested' });
|
|
} catch (error) {
|
|
log.error('Course cancel failed:', error);
|
|
return apiError(API_ERROR_CODES.INTERNAL_ERROR, 500, 'Failed to cancel course');
|
|
}
|
|
}
|