Files
classroomio/apps/api/src/services/v1/course.ts
T

136 lines
4.0 KiB
TypeScript

import type {
TPublicApiCourseParam,
TPublicApiCoursesQuery,
TPublicApiCreateCourse,
TPublicApiUpdateCourse,
TPublicApiUpdateCourseStructure
} from '@cio/utils/validation/public-api';
import { ROLE } from '@cio/utils/constants';
import {
createCourse as createCourseService,
deleteCourse as deleteCourseService,
getCourse,
updateCourse as updateCourseService
} from '@api/services/course/course';
import {
createCourseImportDraftService,
getCourseImportStructureService,
publishCourseImportDraftToExistingCourseService
} from '@api/services/course-import/course-import';
import { getCourseOrganizationId } from '@cio/db/queries/tag';
import { getOrganizationCourses } from '@api/services/organization';
import { listCourseMembers } from '@api/services/course/people';
import { AppError, ErrorCodes } from '@api/utils/errors';
async function assertCourseBelongsToOrganization(orgId: string, courseId: string): Promise<void> {
const courseOrganizationId = await getCourseOrganizationId(courseId);
if (!courseOrganizationId || courseOrganizationId !== orgId) {
throw new AppError('Course not found', ErrorCodes.COURSE_NOT_FOUND, 404);
}
}
export async function listCoursesService(orgId: string, query: TPublicApiCoursesQuery) {
const result = await getOrganizationCourses(orgId, '', ROLE.ADMIN, {
page: 1,
limit: 100,
search: undefined,
tags: query.tags
});
return result.items;
}
export async function getCourseService(orgId: string, params: TPublicApiCourseParam) {
await assertCourseBelongsToOrganization(orgId, params.courseId);
return getCourse(params.courseId);
}
export async function listCourseStudentsService(orgId: string, params: TPublicApiCourseParam) {
await assertCourseBelongsToOrganization(orgId, params.courseId);
const members = await listCourseMembers(params.courseId);
return members.filter((member) => member.roleId === ROLE.STUDENT);
}
export async function exportCourseService(orgId: string, params: TPublicApiCourseParam) {
await assertCourseBelongsToOrganization(orgId, params.courseId);
return getCourseImportStructureService(orgId, params.courseId);
}
export async function createPublicApiCourseService(
orgId: string,
actorId: string | null,
payload: TPublicApiCreateCourse
) {
if (!actorId) {
throw new AppError('Automation actor is required', ErrorCodes.UNAUTHORIZED, 401);
}
return createCourseService(actorId, {
...payload,
organizationId: orgId
});
}
export async function updatePublicApiCourseService(
orgId: string,
params: TPublicApiCourseParam,
payload: TPublicApiUpdateCourse
) {
await assertCourseBelongsToOrganization(orgId, params.courseId);
return updateCourseService(params.courseId, payload);
}
export async function deletePublicApiCourseService(orgId: string, params: TPublicApiCourseParam) {
await assertCourseBelongsToOrganization(orgId, params.courseId);
return deleteCourseService(params.courseId);
}
export async function updatePublicApiCourseStructureService(
orgId: string,
actorId: string | null,
params: TPublicApiCourseParam,
payload: TPublicApiUpdateCourseStructure
) {
if (!actorId) {
throw new AppError('Automation actor is required', ErrorCodes.UNAUTHORIZED, 401);
}
await assertCourseBelongsToOrganization(orgId, params.courseId);
const draft = await createCourseImportDraftService(orgId, actorId, {
sourceType: 'course',
idempotencyKey: payload.idempotencyKey,
summary: {
sourceCourseId: params.courseId,
syncMode: payload.mode,
...(payload.summary ?? {})
},
sourceArtifacts: [
{
type: 'course',
courseId: params.courseId,
label: payload.draft.course.title
},
...(payload.sourceArtifacts ?? [])
],
draft: payload.draft
});
const result = await publishCourseImportDraftToExistingCourseService(orgId, draft.id, {
courseId: params.courseId,
syncMode: payload.mode
});
return {
draftId: draft.id,
syncMode: payload.mode,
...result
};
}