Skip to content

Commit

Permalink
feat: update lesson progress module
Browse files Browse the repository at this point in the history
  • Loading branch information
wielopolski committed Dec 23, 2024
1 parent 386f762 commit 12fc5ed
Show file tree
Hide file tree
Showing 17 changed files with 2,247 additions and 177 deletions.
71 changes: 19 additions & 52 deletions apps/api/src/lesson/lesson.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,23 @@ import { CurrentUser } from "src/common/decorators/user.decorator";
import { RolesGuard } from "src/common/guards/roles.guard";
import { USER_ROLES } from "src/user/schemas/userRoles";

import { AdminLessonService } from "./services/adminLesson.service";
import {
CreateLessonBody,
createLessonSchema,
CreateQuizLessonBody,
createQuizLessonSchema,
LessonShow,
lessonShowSchema,
UpdateLessonBody,
updateLessonSchema,
UpdateQuizLessonBody,
updateQuizLessonSchema,
} from "./lesson.schema";
import { AdminLessonService } from "./services/adminLesson.service";
import { LessonService } from "./services/lesson.service";

import type {
LessonShow} from "./lesson.schema";

@Controller("lesson")
@UseGuards(RolesGuard)
export class LessonController {
Expand Down Expand Up @@ -157,56 +159,21 @@ export class LessonController {
});
}

// @Patch("course-lesson")
// @Roles(USER_ROLES.TEACHER, USER_ROLES.ADMIN)
// @Validate({
// request: [
// {
// type: "body",
// schema: Type.Object({
// courseId: UUIDSchema,
// lessonId: UUIDSchema,
// isFree: Type.Boolean(),
// }),
// },
// ],
// response: baseResponse(Type.Object({ isFree: Type.Boolean(), message: Type.String() })),
// })
// async toggleLessonAsFree(
// @Body() body: { courseId: string; lessonId: string; isFree: boolean },
// ): Promise<BaseResponse<{ isFree: boolean; message: string }>> {
// const [toggledLesson] = await this.adminLessonsService.toggleLessonAsFree(
// body.courseId,
// body.lessonId,
// body.isFree,
// );
// return new BaseResponse({
// isFree: toggledLesson.isFree,
// message: body.isFree
// ? "Lesson toggled as free successfully"
// : "Lesson toggled as not free successfully",
// });
// }

// @Post("evaluation-quiz")
// @Roles(USER_ROLES.STUDENT)
// @Validate({
// request: [
// { type: "query", name: "courseId", schema: UUIDSchema },
// { type: "query", name: "lessonId", schema: UUIDSchema },
// ],
// response: baseResponse(Type.Object({ message: Type.String() })),
// })
// async evaluationQuiz(
// @Query("courseId") courseId: string,
// @Query("lessonId") lessonId: string,
// @CurrentUser("userId") currentUserId: UUIDType,
// ): Promise<BaseResponse<{ message: string }>> {
// await this.lessonsService.evaluationQuiz(courseId, lessonId, currentUserId);
// return new BaseResponse({
// message: "Evaluation quiz successfully",
// });
// }
// @Post("evaluation-quiz")
// @Roles(USER_ROLES.STUDENT)
// @Validate({
// request: [{ type: "query", name: "lessonId", schema: UUIDSchema, required: true }],
// response: baseResponse(Type.Object({ message: Type.String() })),
// })
// async evaluationQuiz(
// @Query("lessonId") lessonId: string,
// @CurrentUser("userId") currentUserId: UUIDType,
// ): Promise<BaseResponse<{ message: string }>> {
// await this.lessonService.evaluationQuiz(lessonId, currentUserId);
// return new BaseResponse({
// message: "Evaluation quiz successfully",
// });
// }

// @Delete("clear-quiz-progress")
// @Roles(USER_ROLES.STUDENT)
Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/lesson/lesson.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { Module } from "@nestjs/common";

import { FileModule } from "src/file/files.module";

import { AdminLessonRepository } from "./repositories/adminLesson.repository";
import { AdminLessonService } from "./services/adminLesson.service";
import { LessonController } from "./lesson.controller";
import { AdminLessonRepository } from "./repositories/adminLesson.repository";
import { LessonRepository } from "./repositories/lesson.repository";
import { AdminLessonService } from "./services/adminLesson.service";
import { LessonService } from "./services/lesson.service";

@Module({
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/lesson/lesson.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Type } from "@sinclair/typebox";

import { UUIDSchema } from "src/common";

import { LESSON_TYPES, PhotoQuestionType, QuestionType } from "./lesson.type";
import { PhotoQuestionType, QuestionType } from "./lesson.type";

import type { Static } from "@sinclair/typebox";

Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/lesson/lesson.type.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const LESSON_TYPES = {
TEXT_BLOCK: "text_block",
TEXT: "text",
FILE: "file",
PRESENTATION: "presentation",
VIDEO: "video",
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/lesson/services/adminLesson.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { eq, gte, inArray, lte, sql } from "drizzle-orm";
import { DatabasePg } from "src/common";
import { lessons, questionAnswerOptions, questions } from "src/storage/schema";

import { LESSON_TYPES } from "../lesson.type";
import { AdminLessonRepository } from "../repositories/adminLesson.repository";
import { LessonRepository } from "../repositories/lesson.repository";
import { LESSON_TYPES } from "../lesson.type";

import type {
CreateLessonBody,
Expand Down
49 changes: 33 additions & 16 deletions apps/api/src/lesson/services/lesson.service.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
import { Inject, Injectable, NotFoundException } from "@nestjs/common";
import { EventBus } from "@nestjs/cqrs";
import { eq, sql } from "drizzle-orm";
import { and, eq, sql } from "drizzle-orm";

import { DatabasePg } from "src/common";
import { FileService } from "src/file/file.service";
import {
chapters,
lessons,
questionAnswerOptions,
questions,
studentCourses,
} from "src/storage/schema";

import { LESSON_TYPES } from "../lesson.type";


import type { LessonShow, OptionBody, QuestionBody } from "../lesson.schema";
import type { PhotoQuestionType, QuestionType } from "../lesson.type";
import type { UUIDType } from "src/common";
import { lessons, questionAnswerOptions, questions } from "src/storage/schema";
import { LESSON_TYPES, PhotoQuestionType, QuestionType } from "../lesson.type";
import { FileService } from "src/file/file.service";
import { LessonShow, OptionBody, QuestionBody } from "../lesson.schema";
import { QuestionTypes } from "src/questions/schema/questions.types";

@Injectable()
export class LessonService {
constructor(
@Inject("DB") private readonly db: DatabasePg,
private readonly fileService: FileService, // TODO: add event bus
) // private readonly eventBus: EventBus,
{}
// private readonly eventBus: EventBus,
) {}

async getLessonById(id: UUIDType): Promise<LessonShow> {
const [lesson] = await this.db
Expand All @@ -34,7 +41,7 @@ export class LessonService {

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

if (lesson.type === LESSON_TYPES.TEXT_BLOCK && !lesson.fileUrl) return lesson;
if (lesson.type === LESSON_TYPES.TEXT && !lesson.fileUrl) return lesson;

if (lesson.type !== LESSON_TYPES.QUIZ) {
if (!lesson.fileUrl) throw new NotFoundException("Lesson file not found");
Expand Down Expand Up @@ -97,12 +104,8 @@ export class LessonService {
return { ...lesson, quizDetails };
}

// async evaluationQuiz(courseId: UUIDType, lessonId: UUIDType, userId: UUIDType) {
// const [accessCourseLessons] = await this.chapterRepository.checkLessonAssignment(
// courseId,
// lessonId,
// userId,
// );
// async evaluationQuiz(lessonId: UUIDType, userId: UUIDType) {
// const [accessCourseLessons] = await this.checkLessonAssignment(lessonId, userId);

// if (!accessCourseLessons.isAssigned && !accessCourseLessons.isFree)
// throw new UnauthorizedException("You don't have assignment to this lesson");
Expand Down Expand Up @@ -140,6 +143,20 @@ export class LessonService {
// return true;
// }

async checkLessonAssignment(id: UUIDType, userId: UUIDType) {
return this.db
.select({
isAssigned: sql<boolean>`CASE WHEN ${studentCourses.id} IS NOT NULL THEN TRUE ELSE FALSE END`,
})
.from(lessons)
.leftJoin(chapters, eq(lessons.chapterId, chapters.id))
.leftJoin(
studentCourses,
and(eq(studentCourses.courseId, chapters.courseId), eq(studentCourses.studentId, userId)),
)
.where(and(eq(chapters.isPublished, true), eq(lessons.id, id)));
}

// private async evaluationsQuestions(courseId: UUIDType, lessonId: UUIDType, userId: UUIDType) {
// const lesson = await this.chapterRepository.getLessonForUser(courseId, lessonId, userId);
// const questionLessonItems = await this.getLessonQuestionsToEvaluation(
Expand Down
10 changes: 5 additions & 5 deletions apps/api/src/scorm/services/scorm.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import xml2js from "xml2js";
import { AdminChapterService } from "src/chapter/adminChapter.service";
import { DatabasePg } from "src/common";
import { FileService } from "src/file/file.service";
import { AdminLessonService } from "src/lesson/adminLesson.service";
import { LESSON_TYPES } from "src/lesson/lesson.type";
import { S3Service } from "src/s3/s3.service";

import { SCORM } from "../constants/scorm.consts";
import { ScormRepository } from "../repositories/scorm.repository";

import type { UUIDType } from "src/common";

Check failure on line 19 in apps/api/src/scorm/services/scorm.service.ts

View workflow job for this annotation

GitHub Actions / Lint

There should be at least one empty line between import groups
import { AdminLessonService } from "src/lesson/services/adminLesson.service";

Check failure on line 20 in apps/api/src/scorm/services/scorm.service.ts

View workflow job for this annotation

GitHub Actions / Lint

`src/lesson/services/adminLesson.service` import should occur before import of `src/s3/s3.service`

type ScormChapter = {
title: string;
Expand Down Expand Up @@ -478,10 +478,10 @@ export class ScormService {
const extension = path.extname(href).toLowerCase();

return match(extension)
.with(".mp4", ".webm", () => LESSON_TYPES.video)
.with(".pptx", ".ppt", () => LESSON_TYPES.presentation)
.with(".html", () => LESSON_TYPES.textBlock)
.otherwise(() => LESSON_TYPES.file);
.with(".mp4", ".webm", () => LESSON_TYPES.VIDEO)
.with(".pptx", ".ppt", () => LESSON_TYPES.PRESENTATION)
.with(".html", () => LESSON_TYPES.TEXT)
.otherwise(() => LESSON_TYPES.FILE);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/seed/e2e-data-seeds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const e2eCourses: NiceCourseData[] = [
displayOrder: 1,
lessons: [
{
type: LESSON_TYPES.TEXT_BLOCK,
type: LESSON_TYPES.TEXT,
title: "E2E Testing Text Block",
description: "E2E Testing Text Block Body",
displayOrder: 1,
Expand Down
Loading

0 comments on commit 12fc5ed

Please sign in to comment.