50 lines
2.1 KiB
TypeScript
50 lines
2.1 KiB
TypeScript
// Courseware detail — GET /api/coursewares/[id]
|
|
//
|
|
// Returns the latest published record for one courseware (or a specific
|
|
// version via `?version=N`). Public read path for the learner player.
|
|
|
|
import { type NextRequest } from 'next/server';
|
|
import { apiError, apiSuccess, API_ERROR_CODES } from '@/lib/server/api-response';
|
|
import { COURSEWARES_DIR, createFileCoursewareRepo } from '@/lib/courseware-repo/store';
|
|
import { toSummary } from '@/lib/courseware-repo';
|
|
import {
|
|
filterLearnerVisibleCoursewares,
|
|
isCoursewareLearnerVisible,
|
|
} from '@/lib/courseware-repo/learner-visibility';
|
|
import { createLogger } from '@/lib/logger';
|
|
|
|
const log = createLogger('Courseware Detail API');
|
|
|
|
export async function GET(request: NextRequest, context: { params: Promise<{ id: string }> }) {
|
|
try {
|
|
const { id } = await context.params;
|
|
if (!/^[a-zA-Z0-9_-]+$/.test(id)) {
|
|
return apiError(API_ERROR_CODES.INVALID_REQUEST, 400, 'Invalid courseware id');
|
|
}
|
|
const repo = createFileCoursewareRepo(COURSEWARES_DIR);
|
|
const versionParam = new URL(request.url).searchParams.get('version');
|
|
let record;
|
|
if (versionParam) {
|
|
const version = Number(versionParam);
|
|
if (!Number.isInteger(version) || version < 1) {
|
|
return apiError(API_ERROR_CODES.INVALID_REQUEST, 400, 'Invalid version');
|
|
}
|
|
record = await repo.getRecord(id, version);
|
|
if (record && !(await isCoursewareLearnerVisible(record))) record = null;
|
|
} else {
|
|
const candidates = (await repo.listRecords({ status: 'published' })).filter(
|
|
(candidate) => candidate.coursewareId === id,
|
|
);
|
|
const visible = await filterLearnerVisibleCoursewares(candidates);
|
|
record = visible.sort((a, b) => b.version - a.version)[0] ?? null;
|
|
}
|
|
if (!record || record.status !== 'published') {
|
|
return apiError(API_ERROR_CODES.INVALID_REQUEST, 404, 'Courseware not found');
|
|
}
|
|
return apiSuccess({ courseware: toSummary(record) });
|
|
} catch (error) {
|
|
log.error('Courseware detail failed:', error);
|
|
return apiError(API_ERROR_CODES.INTERNAL_ERROR, 500, 'Courseware detail failed');
|
|
}
|
|
}
|