Skip to content

Commit

Permalink
feat: add delete option for chapter and lesson (#286)
Browse files Browse the repository at this point in the history
  • Loading branch information
wielopolski authored Dec 12, 2024
1 parent dbb0f8a commit eefad3a
Show file tree
Hide file tree
Showing 10 changed files with 264 additions and 104 deletions.
20 changes: 8 additions & 12 deletions apps/api/src/chapter/adminChapter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,20 +234,16 @@ export class AdminChapterService {
// await this.adminChapterRepository.updateDisplayOrderLessonsInCourse(courseId, lessonId);
// }

// async removeChapter(courseId: string, chapterId: string) {
// const lessonItemsList = await this.adminChapterRepository.getBetaLessons(chapterId);
async removeChapter(chapterId: UUIDType) {
const [chapter] = await this.adminChapterRepository.getChapterById(chapterId);

// const result = await this.adminChapterRepository.removeChapterAndReferences(
// chapterId,
// lessonItemsList as LessonItemWithContentSchema[],
// );

// if (result.length === 0) {
// throw new NotFoundException("Lesson not found in this course");
// }
if (!chapter) throw new NotFoundException("Chapter not found");

// await this.adminChapterRepository.updateChapterDisplayOrder(courseId, chapterId);
// }
await this.db.transaction(async (trx) => {
await this.adminChapterRepository.removeChapter(chapterId, trx);
await this.adminChapterRepository.updateChapterDisplayOrder(chapter.courseId, trx);
});
}

// private getFiltersConditions(filters: LessonsFilterSchema) {
// const conditions = [];
Expand Down
34 changes: 15 additions & 19 deletions apps/api/src/chapter/chapter.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Body, Controller, Patch, Post, Query, UseGuards } from "@nestjs/common";
import { Body, Controller, Delete, Patch, Post, Query, UseGuards } from "@nestjs/common";
import { Type } from "@sinclair/typebox";
import { Validate } from "nestjs-typebox";

Expand Down Expand Up @@ -179,24 +179,20 @@ export class ChapterController {
// });
// }

// @Delete("chapter/:courseId/:chapterId")
// @Roles(USER_ROLES.teacher, USER_ROLES.admin)
// @Validate({
// request: [
// { type: "param", name: "courseId", schema: UUIDSchema },
// { type: "param", name: "chapterId", schema: UUIDSchema },
// ],
// response: baseResponse(Type.Object({ message: Type.String() })),
// })
// async removeChapter(
// @Query("courseId") courseId: UUIDType,
// @Query("chapterId") chapterId: UUIDType,
// ): Promise<BaseResponse<{ message: string }>> {
// await this.adminLessonsService.removeChapter(courseId, chapterId);
// return new BaseResponse({
// message: "Lesson removed from course successfully",
// });
// }
@Delete()
@Roles(USER_ROLES.teacher, USER_ROLES.admin)
@Validate({
request: [{ type: "query", name: "chapterId", schema: UUIDSchema, required: true }],
response: baseResponse(Type.Object({ message: Type.String() })),
})
async removeChapter(
@Query("chapterId") chapterId: UUIDType,
): Promise<BaseResponse<{ message: string }>> {
await this.adminChapterService.removeChapter(chapterId);
return new BaseResponse({
message: "Lesson removed from course successfully",
});
}

// @Delete("lesson/:chapterId/:lessonId")
// @Roles(USER_ROLES.teacher, USER_ROLES.admin)
Expand Down
90 changes: 27 additions & 63 deletions apps/api/src/chapter/repositories/adminChapter.repository.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import { Inject, Injectable } from "@nestjs/common";
import { eq, and, sql } from "drizzle-orm";


import { DatabasePg, type UUIDType } from "src/common";
import { chapters, lessons } from "src/storage/schema";

import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
import type * as schema from "src/storage/schema";

@Injectable()
export class AdminChapterRepository {
constructor(@Inject("DB") private readonly db: DatabasePg) {}

async getChapterById(chapterId: UUIDType) {
return await this.db.select().from(chapters).where(eq(chapters.id, chapterId));
}

// async getLessons(conditions: any[], sortOrder: any) {
// return await this.db
// .select({
Expand Down Expand Up @@ -88,34 +96,22 @@ export class AdminChapterRepository {
// `);
// }

// async updateChapterDisplayOrder(courseId: UUIDType, lessonId: UUIDType) {
// await this.db.transaction(async (trx) => {
// await trx.execute(sql`
// UPDATE ${courseLessons}
// SET display_order = display_order - 1
// WHERE course_id = ${courseId}
// AND display_order > (
// SELECT display_order
// FROM ${courseLessons}
// WHERE course_id = ${courseId}
// AND lesson_id = ${lessonId}
// )
// `);
async updateChapterDisplayOrder(courseId: UUIDType, trx?: PostgresJsDatabase<typeof schema>) {
const dbInstance = trx ?? this.db;

// await trx.execute(sql`
// WITH ranked_lessons AS (
// SELECT lesson_id, row_number() OVER (ORDER BY display_order) AS new_display_order
// FROM ${courseLessons}
// WHERE course_id = ${courseId}
// )
// UPDATE ${courseLessons} cl
// SET display_order = rl.new_display_order
// FROM ranked_lessons rl
// WHERE cl.lesson_id = rl.lesson_id
// AND cl.course_id = ${courseId}
// `);
// });
// }
return await dbInstance.execute(sql`
WITH ranked_chapters AS (
SELECT id, row_number() OVER (ORDER BY display_order) AS new_display_order
FROM ${chapters}
WHERE course_id = ${courseId}
)
UPDATE ${chapters} cc
SET display_order = rc.new_display_order
FROM ranked_chapters rc
WHERE cc.id = rc.id
AND cc.course_id = ${courseId}
`);
}

// async removeCourseLesson(courseId: string, lessonId: string) {
// return await this.db
Expand All @@ -124,43 +120,11 @@ export class AdminChapterRepository {
// .returning();
// }

// async removeChapterAndReferences(
// chapterId: string,
// lessonItemsList: LessonItemWithContentSchema[],
// ) {
// return await this.db.transaction(async (trx) => {
// for (const lessonItem of lessonItemsList) {
// const { lessonItemType } = lessonItem;
// switch (lessonItemType) {
// case LESSON_ITEM_TYPE.text_block.key:
// if (lessonItem.textBlockData?.id) {
// await trx.delete(textBlocks).where(eq(textBlocks.id, lessonItem.textBlockData.id));
// }
// break;

// case LESSON_ITEM_TYPE.question.key:
// if (lessonItem.questionData?.id) {
// await trx.delete(questions).where(eq(questions.id, lessonItem.questionData.id));
// }
// break;

// case LESSON_ITEM_TYPE.file.key:
// if (lessonItem.fileData?.id) {
// await trx.delete(files).where(eq(files.id, lessonItem.fileData.id));
// }
// break;

// default:
// throw new Error(`Unsupported lesson item type: ${lessonItemType}`);
// }
// }
// await trx.delete(lessonItems).where(eq(lessonItems.lessonId, chapterId));
async removeChapter(chapterId: UUIDType, trx?: PostgresJsDatabase<typeof schema>) {
const dbInstance = trx ?? this.db;

// await trx.delete(courseLessons).where(eq(courseLessons.lessonId, chapterId));

// return await trx.delete(lessons).where(eq(lessons.id, chapterId)).returning();
// });
// }
return await dbInstance.delete(chapters).where(eq(chapters.id, chapterId)).returning();
}

// async getMaxOrderLessonsInCourse(courseId: UUIDType) {
// const [maxOrderResult] = await this.db
Expand Down
27 changes: 27 additions & 0 deletions apps/api/src/lesson/adminLesson.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import type * as schema from "src/storage/schema";
export class AdminLessonRepository {
constructor(@Inject("DB") private readonly db: DatabasePg) {}

async getLesson(id: UUIDType) {
return await this.db.select().from(lessons).where(eq(lessons.id, id));
}

async createLessonForChapter(data: CreateLessonBody, authorId: UUIDType) {
const [lesson] = await this.db.insert(lessons).values(data).returning();
return lesson;
Expand Down Expand Up @@ -110,6 +114,29 @@ export class AdminLessonRepository {
.where(eq(studentQuestionAnswers.questionId, questionId));
}

async removeLesson(lessonId: UUIDType, trx?: PostgresJsDatabase<typeof schema>) {
const dbInstance = trx ?? this.db;

return await dbInstance.delete(lessons).where(eq(lessons.id, lessonId)).returning();
}

async updateLessonDisplayOrder(chapterId: UUIDType, trx?: PostgresJsDatabase<typeof schema>) {
const dbInstance = trx ?? this.db;

return await dbInstance.execute(sql`
WITH ranked_chapters AS (
SELECT id, row_number() OVER (ORDER BY display_order) AS new_display_order
FROM ${lessons}
WHERE chapter_id = ${chapterId}
)
UPDATE ${lessons} cc
SET display_order = rc.new_display_order
FROM ranked_chapters rc
WHERE cc.id = rc.id
AND cc.chapter_id = ${chapterId}
`);
}

// async getLessonStudentAnswers(lessonId: UUIDType) {
// return await this.db
// .select()
Expand Down
13 changes: 13 additions & 0 deletions apps/api/src/lesson/adminLesson.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,19 @@ export class AdminLessonService {
return updatedLesson.id;
}

async removeLesson(lessonId: UUIDType) {
const [lesson] = await this.adminLessonRepository.getLesson(lessonId);

if (!lesson) {
throw new NotFoundException("Lesson not found");
}

await this.db.transaction(async (trx) => {
await this.adminLessonRepository.removeLesson(lessonId, trx);
await this.adminLessonRepository.updateLessonDisplayOrder(lesson.chapterId, trx);
});
}

// async getAllLessonItems(query: GetLessonItemsQuery = {}) {
// const {
// type,
Expand Down
18 changes: 17 additions & 1 deletion apps/api/src/lesson/lesson.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Body, Controller, Patch, Post, Query, UseGuards } from "@nestjs/common";
import { Body, Controller, Delete, Patch, Post, Query, UseGuards } from "@nestjs/common";
import { Type } from "@sinclair/typebox";
import { Validate } from "nestjs-typebox";

Expand Down Expand Up @@ -189,6 +189,22 @@ export class LessonController {
return new BaseResponse({ message: "Text block updated successfully" });
}

@Delete()
@Roles(USER_ROLES.teacher, USER_ROLES.admin)
@Validate({
request: [{ type: "query", name: "lessonId", schema: UUIDSchema, required: true }],
response: baseResponse(Type.Object({ message: Type.String() })),
})
async removeLesson(
@Query("lessonId") lessonId: UUIDType,
): Promise<BaseResponse<{ message: string }>> {
await this.adminLessonsService.removeLesson(lessonId);

return new BaseResponse({
message: "Lesson removed from course successfully",
});
}

// @Patch("lesson")
// @Roles(USER_ROLES.teacher, USER_ROLES.admin)
// @Validate({
Expand Down
Loading

0 comments on commit eefad3a

Please sign in to comment.