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
@@ -17,7 +17,10 @@ import {
|
||||
import { COURSEWARE_PUBLISH_TOKEN_ENV, isPublishTokenConfigured } from '@/lib/courseware-repo';
|
||||
import type { CourseManifestRecord } from '@/lib/course-manifest-repo/types';
|
||||
import type { CoursePublicationReceipt } from '@/lib/course-framework/types';
|
||||
import { requireOpsAccess } from '@/lib/server/ops-access';
|
||||
import {
|
||||
configuredWorksSquareApiOrigin,
|
||||
requireOpsAccess,
|
||||
} from '@/lib/server/ops-access';
|
||||
import { buildRequestOrigin } from '@/lib/server/classroom-storage';
|
||||
import { isCourseGenerationRunning } from '@/lib/course-framework/runner';
|
||||
import {
|
||||
@@ -49,6 +52,7 @@ import { publishCourseToServer } from '@/lib/server/course-publish-transport';
|
||||
import { commitRemoteCoursePublish } from '@/lib/server/course-publish-transaction';
|
||||
|
||||
const log = createLogger('Course Publish API');
|
||||
export const maxDuration = 900;
|
||||
|
||||
function buildPublicationReceipt(
|
||||
snapshot: CoursePublishSnapshot,
|
||||
@@ -112,7 +116,7 @@ export async function POST(
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ courseId: string }> },
|
||||
) {
|
||||
const denied = requireOpsAccess(request);
|
||||
const denied = await requireOpsAccess(request);
|
||||
if (denied) return denied;
|
||||
|
||||
try {
|
||||
@@ -120,6 +124,64 @@ export async function POST(
|
||||
if (!isValidCourseId(courseId)) {
|
||||
return apiError(API_ERROR_CODES.INVALID_REQUEST, 400, `Invalid course id: ${courseId}`);
|
||||
}
|
||||
const worksOrigin = configuredWorksSquareApiOrigin();
|
||||
if (worksOrigin) {
|
||||
const authorization = request.headers.get('authorization') ?? '';
|
||||
const finalizeResponse = await fetch(
|
||||
`${worksOrigin}/api/admin/learning/generations/${encodeURIComponent(courseId)}/finalize`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { Authorization: authorization, Accept: 'application/json' },
|
||||
redirect: 'error',
|
||||
cache: 'no-store',
|
||||
signal: AbortSignal.timeout(10 * 60_000),
|
||||
},
|
||||
);
|
||||
const finalized = (await finalizeResponse.json().catch(() => null)) as {
|
||||
id?: unknown;
|
||||
status?: unknown;
|
||||
} | null;
|
||||
if (!finalizeResponse.ok || typeof finalized?.id !== 'string') {
|
||||
return apiError(
|
||||
API_ERROR_CODES.UPSTREAM_ERROR,
|
||||
finalizeResponse.status >= 400 && finalizeResponse.status < 500
|
||||
? finalizeResponse.status
|
||||
: 502,
|
||||
'Works could not finalize the aggregate learning course',
|
||||
);
|
||||
}
|
||||
const publishResponse = await fetch(
|
||||
`${worksOrigin}/api/admin/learning/courses/${encodeURIComponent(finalized.id)}/publish`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { Authorization: authorization, Accept: 'application/json' },
|
||||
redirect: 'error',
|
||||
cache: 'no-store',
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
},
|
||||
);
|
||||
const published = (await publishResponse.json().catch(() => null)) as {
|
||||
id?: unknown;
|
||||
status?: unknown;
|
||||
} | null;
|
||||
if (!publishResponse.ok || typeof published?.id !== 'string') {
|
||||
return apiError(
|
||||
API_ERROR_CODES.UPSTREAM_ERROR,
|
||||
publishResponse.status >= 400 && publishResponse.status < 500
|
||||
? publishResponse.status
|
||||
: 502,
|
||||
'Works registered the course package but could not publish it',
|
||||
);
|
||||
}
|
||||
await updateCourseRecord(courseId, {
|
||||
externalPublication: {
|
||||
courseId: published.id,
|
||||
status: published.status === 'published' ? 'published' : 'ready',
|
||||
publishedAt: new Date().toISOString(),
|
||||
},
|
||||
});
|
||||
return apiSuccess({ record: published, aggregate: true });
|
||||
}
|
||||
if (!isPublishTokenConfigured()) {
|
||||
return apiError(
|
||||
API_ERROR_CODES.INTERNAL_ERROR,
|
||||
|
||||
Reference in new issue
Block a user