feat: Add token-based authorization to category deletion and enhance user registration with error handling and audit logging.

This commit is contained in:
JakkrapartXD 2026-02-12 17:55:45 +07:00
parent 45941fbe6c
commit af14610442
16 changed files with 1003 additions and 236 deletions

View file

@ -18,7 +18,7 @@ export class AdminCourseApprovalService {
/**
* Get all pending courses for admin review
*/
static async listPendingCourses(): Promise<ListPendingCoursesResponse> {
static async listPendingCourses(token: string): Promise<ListPendingCoursesResponse> {
try {
const courses = await prisma.course.findMany({
where: { status: 'PENDING' },
@ -68,18 +68,18 @@ export class AdminCourseApprovalService {
description: course.description as { th: string; en: string },
thumbnail_url: thumbnail_presigned_url,
status: course.status,
created_at: course.created_at,
updated_at: course.updated_at,
created_by: course.created_by,
creator: course.creator,
instructors: course.instructors.map(i => ({
user_id: i.user_id,
is_primary: i.is_primary,
user: i.user
})),
chapters_count: course.chapters.length,
lessons_count: course.chapters.reduce((sum, ch) => sum + ch.lessons.length, 0),
latest_submission: course.courseApprovals[0] ? {
created_at: course.created_at,
updated_at: course.updated_at,
created_by: course.created_by,
creator: course.creator,
instructors: course.instructors.map(i => ({
user_id: i.user_id,
is_primary: i.is_primary,
user: i.user
})),
chapters_count: course.chapters.length,
lessons_count: course.chapters.reduce((sum, ch) => sum + ch.lessons.length, 0),
latest_submission: course.courseApprovals[0] ? {
id: course.courseApprovals[0].id,
submitted_by: course.courseApprovals[0].submitted_by,
created_at: course.courseApprovals[0].created_at,
@ -96,6 +96,16 @@ export class AdminCourseApprovalService {
};
} catch (error) {
logger.error('Failed to list pending courses', { error });
const decoded = jwt.decode(token) as { id: number } | null;
await auditService.logSync({
userId: decoded?.id || 0,
action: AuditAction.ERROR,
entityType: 'Course',
entityId: 0,
metadata: {
error: error instanceof Error ? error.message : String(error)
}
});
throw error;
}
}
@ -103,7 +113,7 @@ export class AdminCourseApprovalService {
/**
* Get course details for admin review
*/
static async getCourseDetail(courseId: number): Promise<GetCourseDetailForAdminResponse> {
static async getCourseDetail(token: string,courseId: number): Promise<GetCourseDetailForAdminResponse> {
try {
const course = await prisma.course.findUnique({
where: { id: courseId },
@ -214,6 +224,16 @@ export class AdminCourseApprovalService {
};
} catch (error) {
logger.error('Failed to get course detail', { error });
const decoded = jwt.decode(token) as { id: number } | null;
await auditService.logSync({
userId: decoded?.id || 0,
action: AuditAction.ERROR,
entityType: 'Course',
entityId: courseId,
metadata: {
error: error instanceof Error ? error.message : String(error)
}
});
throw error;
}
}
@ -238,7 +258,7 @@ export class AdminCourseApprovalService {
// Update course status
prisma.course.update({
where: { id: courseId },
data: {
data: {
status: 'APPROVED',
approved_by: decoded.id,
approved_at: new Date()
@ -275,6 +295,17 @@ export class AdminCourseApprovalService {
};
} catch (error) {
logger.error('Failed to approve course', { error });
const decoded = jwt.decode(token) as { id: number } | null;
await auditService.logSync({
userId: decoded?.id || 0,
action: AuditAction.ERROR,
entityType: 'Course',
entityId: courseId,
metadata: {
operation: 'approve_course',
error: error instanceof Error ? error.message : String(error)
}
});
throw error;
}
}
@ -303,12 +334,12 @@ export class AdminCourseApprovalService {
// Update course status back to REJECTED
prisma.course.update({
where: { id: courseId },
data: {
data: {
status: 'REJECTED',
rejection_reason: comment,
approved_by: null,
approved_at: null
}
}
}),
// Create rejection record
prisma.courseApproval.create({
@ -341,6 +372,17 @@ export class AdminCourseApprovalService {
};
} catch (error) {
logger.error('Failed to reject course', { error });
const decoded = jwt.decode(token) as { id: number } | null;
await auditService.logSync({
userId: decoded?.id || 0,
action: AuditAction.ERROR,
entityType: 'Course',
entityId: courseId,
metadata: {
operation: 'reject_course',
error: error instanceof Error ? error.message : String(error)
}
});
throw error;
}
}