Snai3i-MarketPlace / backend / src / services / course / chapter.service.ts
chapter.service.ts
Raw
import { HttpCodes } from '../../config/Errors';
import { db } from '../../settings';
import { ResultSetHeader } from 'mysql2';
import { ErrorResponseC, SuccessResponseC } from '../services.response';
import courseLogs, { ICourseLogs, courseLogger } from './course.logs';
import { formatString } from '../../utils/Strings';
import { VideoServices } from './video.service';
import { DocumentServices } from './document.service';

export class ChapterServices {
  static createChapter = async (
    course_id: number,
    chapter: ChapterI
  ): Promise<ResponseT> => {
    try {
      const sqlInsertQuery =
        'INSERT INTO chapters (course_id, title, position) VALUES (?, ?, ?)';
      const [result]: any = await db.query<ResultSetHeader[]>(sqlInsertQuery, [
        course_id,
        chapter.title,
        chapter.position,
      ]);
      const chapterId = result.insertId;
      const resp: ICode<ICourseLogs> = courseLogs.CREATE_CHAPTER_SUCCESS;
      const msg = formatString(resp.message, {
        chapterId,
      });
      courseLogger.info(msg, { type: resp.type });
      return new SuccessResponseC(resp.type, {}, msg, HttpCodes.Created.code);
    } catch (err) {
      const msg = formatString(courseLogs.CHAPTER_ERROR_GENERIC.message, {
        error: (err as Error)?.message || '',
      });
      courseLogger.error(msg, err as Error);
      return new ErrorResponseC(
        courseLogs.CHAPTER_ERROR_GENERIC.type,
        HttpCodes.InternalServerError.code,
        msg
      );
    }
  };

  static createChapters = async (
    course_id: number,
    chapters: ChapterI[]
  ): Promise<ResponseT> => {
    try {
      const sqlInsertQuery =
        'INSERT INTO chapters (course_id, title, position) VALUES (?, ?, ?)';

      for (const chapter of chapters) {
        const { title, position, data } = chapter;
        // if data item has video_id then it is a video
        const videos = data?.filter(
          (item) => (item as VideoI).videoLength
        ) as VideoI[];

        // documents = rest of the data items
        const documents = data?.filter(
          (item) => !(item as VideoI).videoLength
        ) as DocumentI[];

        const [result]: any = await db.query<ResultSetHeader[]>(
          sqlInsertQuery,
          [course_id, title, position]
        );

        const chapterId = result.insertId;
        chapter.chapter_id = chapterId;
        if (videos.length > 0) {
          videos.forEach((video) => (video.chapter_id = chapterId));

          const videosResponse = await VideoServices.insertVideos(videos);

          if (videosResponse instanceof ErrorResponseC) {
            return videosResponse;
          }
        }
        if (documents.length > 0) {
          documents.forEach((document) => (document.chapter_id = chapterId));

          const documentsResponse = await DocumentServices.insertDocuments(
            documents
          );

          if (documentsResponse instanceof ErrorResponseC) {
            return documentsResponse;
          }
        }
      }
      const resp: ICode<ICourseLogs> = courseLogs.CREATE_CHAPTERS_SUCCESS;
      const msg = formatString(resp.message, {
        chapterIds: chapters.map((chapter) => chapter.chapter_id).join(', '),
      });
      courseLogger.info(msg, { type: resp.type });
      return new SuccessResponseC(
        resp.type,
        chapters,
        msg,
        HttpCodes.Created.code
      );
    } catch (err) {
      const msg = formatString(courseLogs.CHAPTER_ERROR_GENERIC.message, {
        error: (err as Error)?.message || '',
      });
      courseLogger.error(msg, err as Error);
      return new ErrorResponseC(
        courseLogs.CHAPTER_ERROR_GENERIC.type,
        HttpCodes.InternalServerError.code,
        msg
      );
    }
  };

  static updateChapters = async (chapters: ChapterI[]): Promise<ResponseT> => {
    try {
      const sqlUpdateQuery =
        'UPDATE chapters SET title = ?, position = ? WHERE chapter_id = ?';
      const values: any = chapters.map((chapter) => [
        chapter.title,
        chapter.position,
        chapter.chapter_id,
      ]);
      for (const value of values) {
        // const [result]: any =
        await db.query<ResultSetHeader>(sqlUpdateQuery, [
          value.title,
          value.position,
          value.chapter_id,
        ]);
        // if (result.affectedRows === 0) {
        //   const msg = formatString(courseLogs.CHAPTER_ERROR_NOT_FOUND.message, {
        //     chapterId: chapters.map((chapter) => chapter.chapter_id).join(', '),
        //   });
        //   courseLogger.error(msg);
        //   return new ErrorResponseC(
        //     courseLogs.CHAPTER_ERROR_NOT_FOUND.type,
        //     HttpCodes.NotFound.code,
        //     msg
        //   );
        // }
      }
      const resp: ICode<ICourseLogs> = courseLogs.UPDATE_CHAPTER_SUCCESS;
      const msg = formatString(resp.message, {
        chapterIds: chapters.map((chapter) => chapter.chapter_id).join(', '),
      });
      courseLogger.info(msg, { type: resp.type });
      return new SuccessResponseC(resp.type, {}, msg, HttpCodes.Accepted.code);
    } catch (err) {
      const msg = formatString(courseLogs.CHAPTER_ERROR_GENERIC.message, {
        error: (err as Error)?.message || '',
      });
      courseLogger.error(msg, err as Error);
      return new ErrorResponseC(
        courseLogs.CHAPTER_ERROR_GENERIC.type,
        HttpCodes.InternalServerError.code,
        msg
      );
    }
  };

  static deleteChapters = async (chapter_ids: number[]): Promise<ResponseT> => {
    try {
      const sqlDeleteQuery = 'DELETE FROM chapters WHERE chapter_id IN (?)';
      const [result]: any = await db.query<ResultSetHeader[]>(sqlDeleteQuery, [
        chapter_ids,
      ]);
      if (result.affectedRows === 0) {
        const msg = formatString(courseLogs.CHAPTER_ERROR_NOT_FOUND.message, {
          chapterId: chapter_ids.join(', '),
        });
        courseLogger.error(msg);
        return new ErrorResponseC(
          courseLogs.CHAPTER_ERROR_NOT_FOUND.type,
          HttpCodes.NotFound.code,
          msg
        );
      }
      const resp: ICode<ICourseLogs> = courseLogs.DELETE_CHAPTERS_SUCCESS;
      const msg = formatString(resp.message, {
        chapterIds: chapter_ids.join(', '),
      });
      courseLogger.info(msg, { type: resp.type });
      return new SuccessResponseC(resp.type, {}, msg, HttpCodes.Accepted.code);
    } catch (err) {
      const msg = formatString(courseLogs.CHAPTER_ERROR_GENERIC.message, {
        error: (err as Error)?.message || '',
      });
      courseLogger.error(msg, err as Error);
      return new ErrorResponseC(
        courseLogs.CHAPTER_ERROR_GENERIC.type,
        HttpCodes.InternalServerError.code,
        msg
      );
    }
  };
  static identifyAddedChapters = (
    oldChapters: ChapterI[],
    newChapters: ChapterI[]
  ) => {
    const addedChapters = newChapters.filter(
      (newChapter) =>
        !oldChapters.some(
          (oldChapter) => oldChapter.chapter_id === newChapter.chapter_id
        )
    );
    return addedChapters;
  };
  static identifyDeletedChapters = (
    oldChapters: ChapterI[],
    newChapters: ChapterI[]
  ) => {
    const deletedChapters = oldChapters.filter(
      (oldChapter) =>
        !newChapters.some(
          (newChapter) => newChapter.chapter_id === oldChapter.chapter_id
        )
    );
    return deletedChapters;
  };
  static identifyUpdatedChapters = (
    oldChapters: ChapterI[],
    newChapters: ChapterI[]
  ) => {
    const updatedChapters = newChapters.filter((newChapter) =>
      oldChapters.some(
        (oldChapter) =>
          oldChapter.chapter_id === newChapter.chapter_id &&
          (oldChapter.title !== newChapter.title ||
            oldChapter.position !== newChapter.position)
      )
    );
    return updatedChapters;
  };
  static filterChapters = (
    chapters: ChapterI[],
    deletedChapters: ChapterI[]
  ) => {
    const filteredChapters = chapters.filter(
      (chapter) =>
        !deletedChapters.some(
          (deletedChapter) => deletedChapter.chapter_id === chapter.chapter_id
        )
    );
    return filteredChapters;
  };
}