feat: Add token-based authorization to category deletion and enhance user registration with error handling and audit logging.
This commit is contained in:
parent
45941fbe6c
commit
af14610442
16 changed files with 1003 additions and 236 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue