Files
classroomio/apps/api/src/routes/course/course.ts
T
Rotimi Best 4b52906445 feat: enhance API route naming conventions and structure
- Added comprehensive guidelines for API route naming and structure in `ROUTE_NAMING_BEST_PRACTICES.md`.
- Updated `ARCHITECHTURE.md` to reference the new best practices document.
- Refactored course-related routes to follow new naming conventions, including changes to endpoint paths and validation schemas.
- Removed the deprecated course clone route and integrated cloning functionality directly into the course routes.
- Adjusted various API methods to ensure consistent usage of HTTP methods and parameter structures across the application.
2025-12-05 17:24:16 +01:00

95 lines
2.7 KiB
TypeScript

import {
ZCertificateDownload,
ZCourseClone,
ZCourseCloneParam,
ZCourseDownloadContent,
ZCourseDownloadParam
} from '@cio/utils/validation/course';
import { Hono } from '@api/utils/hono';
import { authMiddleware } from '@api/middlewares/auth';
import { cloneCourse } from '@api/services/course/clone';
import { generateCertificate } from '@api/utils/certificate';
import { generateCoursePdf } from '@api/utils/course';
import { handleError } from '@api/utils/errors';
import { katexRouter } from '@api/routes/course/katex';
import { lessonRouter } from '@api/routes/course/lesson';
import { presignRouter } from '@api/routes/course/presign';
import { zValidator } from '@hono/zod-validator';
export const courseRouter = new Hono()
.post(
'/:courseId/download/certificate',
zValidator('param', ZCourseDownloadParam),
zValidator('json', ZCertificateDownload),
async (c) => {
const validatedData = c.req.valid('json');
const result = await generateCertificate(validatedData);
c.header('Content-Type', 'application/pdf');
c.header('Content-Disposition', `attachment; filename="certificate-${validatedData.courseName}.pdf"`);
return c.body(
new ReadableStream({
start(controller) {
controller.enqueue(result);
controller.close();
}
})
);
}
)
.post(
'/:courseId/download/content',
zValidator('param', ZCourseDownloadParam),
zValidator('json', ZCourseDownloadContent),
async (c) => {
const validatedData = c.req.valid('json');
const pdfBuffer = await generateCoursePdf(validatedData);
c.header('Content-Type', 'application/pdf');
return c.body(
new ReadableStream({
start(controller) {
controller.enqueue(pdfBuffer);
controller.close();
}
})
);
}
)
.post(
'/:courseId/clone',
authMiddleware,
zValidator('param', ZCourseCloneParam),
zValidator('json', ZCourseClone),
async (c) => {
try {
const { courseId } = c.req.valid('param');
const validatedData = c.req.valid('json');
const { title, description, slug, organizationId } = validatedData;
const user = c.get('user');
// Clone the course
const newCourse = await cloneCourse(courseId, title, user.id, description, slug, organizationId);
return c.json(
{
success: true,
course: newCourse
},
200
);
} catch (error) {
return handleError(c, error, 'Failed to clone course');
}
}
)
.route('/katex', katexRouter)
.route('/lesson', lessonRouter)
.route('/presign', presignRouter);