feat: normalize chapter sort_order to prevent gaps and duplicates in course chapters
Add normalizeChapterSortOrder method to ensure sequential 1-based sort_order values. Update reorderChapter to normalize before reordering and validate new position against chapter count. Call normalization after chapter deletion to fill gaps in remaining chapters.
This commit is contained in:
parent
2b248cad10
commit
ec67c7c6b6
1 changed files with 50 additions and 6 deletions
|
|
@ -167,6 +167,10 @@ export class ChaptersLessonService {
|
|||
throw new ForbiddenError('You are not permitted to delete chapter');
|
||||
}
|
||||
await prisma.chapter.delete({ where: { id: chapter_id } });
|
||||
|
||||
// Normalize sort_order for remaining chapters (fill gaps)
|
||||
await this.normalizeChapterSortOrder(course_id);
|
||||
|
||||
return { code: 200, message: 'Chapter deleted successfully' };
|
||||
} catch (error) {
|
||||
logger.error(`Error deleting chapter: ${error}`);
|
||||
|
|
@ -197,10 +201,22 @@ export class ChaptersLessonService {
|
|||
if (currentChapter.course_id !== course_id) {
|
||||
throw new NotFoundError('Chapter not found in this course');
|
||||
}
|
||||
const oldSortOrder = currentChapter.sort_order;
|
||||
|
||||
// First, normalize sort_order to fix any gaps or duplicates
|
||||
await this.normalizeChapterSortOrder(course_id);
|
||||
|
||||
// Re-fetch the chapter to get updated sort_order after normalization
|
||||
const normalizedChapter = await prisma.chapter.findUnique({ where: { id: chapter_id } });
|
||||
if (!normalizedChapter) throw new NotFoundError('Chapter not found');
|
||||
|
||||
const oldSortOrder = normalizedChapter.sort_order;
|
||||
|
||||
// Get total chapter count to validate sort_order (1-based)
|
||||
const chapterCount = await prisma.chapter.count({ where: { course_id } });
|
||||
const validNewSortOrder = Math.max(1, Math.min(newSortOrder, chapterCount));
|
||||
|
||||
// If same position, no need to reorder
|
||||
if (oldSortOrder === newSortOrder) {
|
||||
if (oldSortOrder === validNewSortOrder) {
|
||||
const chapters = await prisma.chapter.findMany({
|
||||
where: { course_id },
|
||||
orderBy: { sort_order: 'asc' }
|
||||
|
|
@ -209,12 +225,12 @@ export class ChaptersLessonService {
|
|||
}
|
||||
|
||||
// Shift other chapters to make room for the insert
|
||||
if (oldSortOrder > newSortOrder) {
|
||||
if (oldSortOrder > validNewSortOrder) {
|
||||
// Moving up: shift chapters between newSortOrder and oldSortOrder-1 down by 1
|
||||
await prisma.chapter.updateMany({
|
||||
where: {
|
||||
course_id,
|
||||
sort_order: { gte: newSortOrder, lt: oldSortOrder }
|
||||
sort_order: { gte: validNewSortOrder, lt: oldSortOrder }
|
||||
},
|
||||
data: { sort_order: { increment: 1 } }
|
||||
});
|
||||
|
|
@ -223,14 +239,14 @@ export class ChaptersLessonService {
|
|||
await prisma.chapter.updateMany({
|
||||
where: {
|
||||
course_id,
|
||||
sort_order: { gt: oldSortOrder, lte: newSortOrder }
|
||||
sort_order: { gt: oldSortOrder, lte: validNewSortOrder }
|
||||
},
|
||||
data: { sort_order: { decrement: 1 } }
|
||||
});
|
||||
}
|
||||
|
||||
// Update the target chapter to the new position
|
||||
await prisma.chapter.update({ where: { id: chapter_id }, data: { sort_order: newSortOrder } });
|
||||
await prisma.chapter.update({ where: { id: chapter_id }, data: { sort_order: validNewSortOrder } });
|
||||
|
||||
// Fetch all chapters with updated order
|
||||
const chapters = await prisma.chapter.findMany({
|
||||
|
|
@ -1265,6 +1281,34 @@ export class ChaptersLessonService {
|
|||
logger.info(`Normalized sort_order for chapter ${chapterId}: ${lessons.length} lessons`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize sort_order for all chapters in a course
|
||||
* Ensures sort_order is sequential starting from 1 with no gaps or duplicates
|
||||
*
|
||||
* @param courseId Course ID to normalize
|
||||
*/
|
||||
private async normalizeChapterSortOrder(courseId: number): Promise<void> {
|
||||
// Get all chapters ordered by current sort_order
|
||||
const chapters = await prisma.chapter.findMany({
|
||||
where: { course_id: courseId },
|
||||
orderBy: { sort_order: 'asc' },
|
||||
select: { id: true, sort_order: true }
|
||||
});
|
||||
|
||||
if (chapters.length === 0) return;
|
||||
|
||||
// Update each chapter with sequential sort_order starting from 1
|
||||
const updates = chapters.map((chapter, index) =>
|
||||
prisma.chapter.update({
|
||||
where: { id: chapter.id },
|
||||
data: { sort_order: index + 1 }
|
||||
})
|
||||
);
|
||||
|
||||
await prisma.$transaction(updates);
|
||||
logger.info(`Normalized sort_order for course ${courseId}: ${chapters.length} chapters`);
|
||||
}
|
||||
|
||||
/**
|
||||
* อัพเดตการตั้งค่า Quiz
|
||||
* Update quiz settings (title, passing_score, time_limit, etc.)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue