Skip to content

Commit

Permalink
Merge pull request #44 from No-Country-simulation/backend
Browse files Browse the repository at this point in the history
Backend
  • Loading branch information
MarcossIC authored Nov 24, 2024
2 parents 06a97e4 + e16eac5 commit 5dc49e2
Show file tree
Hide file tree
Showing 15 changed files with 284 additions and 159 deletions.
2 changes: 1 addition & 1 deletion server/apps/courses/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ dotenv.config();
@Module({
imports: [
MongooseModule.forRoot(process.env.MONGO_URI),
CoursesModule
CoursesModule,
],
})
export class AppModule {}
54 changes: 35 additions & 19 deletions server/apps/courses/src/courses/courses.controller.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Controller } from '@nestjs/common';
import { CoursesService } from './courses.service';
import { MessagePattern, RpcException } from '@nestjs/microservices';
import { CreateCourseSchema } from './dto/create-course.dto';
import { CreateCourseDto, CreateCourseSchema } from './dto/create-course.dto';

@Controller('courses')
export class CoursesController {
constructor(private readonly coursesService: CoursesService) {}

courseModel: any;
constructor(private readonly coursesService: CoursesService) { }

@MessagePattern({ cmd: 'createCourse' })
async createCourse(courseData: any) {
async createCourse(courseData: CreateCourseDto) {
// Validar los datos con Zod
const validationResult = CreateCourseSchema.safeParse(courseData);
if (!validationResult.success) {
Expand All @@ -19,24 +20,39 @@ export class CoursesController {
});
}

// Llamar al servicio para guardar el curso
return this.coursesService.createCourse(validationResult.data);
// Pasamos el userId al objeto de datos
const courseDataWithUserId = {
...validationResult.data
};

try {
// Delegamos la creación del curso al servicio
const newCourse = await this.coursesService.createCourse(courseDataWithUserId);

// Devolver el resultado
return newCourse;
} catch (error) {
throw new RpcException({
statusCode: 500,
message: error.message || 'Error al crear el curso',
});
}
}
}

// @Get('/')
// async getCourse(){
// return await this.coursesService.getCourse();
// }
// @Get('/')
// async getCourse(){
// return await this.coursesService.getCourse();
// }

// @Get('/:id')
// async getCourseId(@Param('id') id:string) {
// return await this.coursesService.getCourseId(id);
// }
// @Get('/:id')
// async getCourseId(@Param('id') id:string) {
// return await this.coursesService.getCourseId(id);
// }

// @Post()
// async create(@Body() createCourseDto: CreateCourseDto){
// return await this.coursesService.create(createCourseDto);
// }
// @Post()
// async create(@Body() createCourseDto: CreateCourseDto){
// return await this.coursesService.create(createCourseDto);
// }

// Otros métodos del controlador (por ejemplo, para obtener cursos, eliminar, etc.)
}
81 changes: 54 additions & 27 deletions server/apps/courses/src/courses/courses.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,63 @@ import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Course } from './schemas/course.schema';
import { CreateCourseDto } from './dto/create-course.dto';

@Injectable()
export class CoursesService {
constructor(@InjectModel(Course.name) private courseModel: Model<Course>) {}
constructor(
@InjectModel(Course.name) private ModelCourse: Model<Course>, // Asegúrate de que 'Course.name' esté correctamente referenciado
) {}

async createCourse(data: any) {
const newCourse = new this.courseModel(data);
return newCourse.save();
async createCourse(data: CreateCourseDto) {
console.log('Datos recibidos para crear curso:', data);

try {
// Creamos un objeto de curso de manera explícita para evitar errores con datos no proporcionados
const courseData: any = {
userId: data.userId, // Asegúrate de que siempre esté presente el ID del usuario
title: data.title, // Asegúrate de que el título esté presente
contentType: data.contentType || 'premium', // Default 'premium' si no se proporciona
courseType: data.courseType || 'appsheet', // Default 'appsheet' si no se proporciona
kind: data.kind || 'course', // Default 'course' si no se proporciona
basicDescription: data.basicDescription, // Si no se proporciona, no se agrega
prerequisites: data.prerequisites || [], // Default vacío si no se proporciona
detailedContent: data.detailedContent, // Si no se proporciona, no se agrega
imageUrl: data.imageUrl, // Si no se proporciona, no se agrega
modules: data.modules || [], // Default vacío si no se proporciona
status: 'in-progress', // Estado inicial del curso
createdAt: new Date(), // Fecha de creación
updatedAt: new Date(), // Fecha de actualización
};

// Crear el curso con los datos validados y asignados explícitamente
const newCourse = new this.ModelCourse(courseData);
return await newCourse.save(); // Guardamos el curso en la base de datos
} catch (error) {
throw new Error(`Error al crear el curso: ${error.message}`);
}
}
}
//constructor(@InjectModel(Course.name) private courseModel: Model<Course>) { }

// async createCourse(data: { title: string; description?: string }) {
// const newCourse = new this.courseModel(data);
// return newCourse.save();
// }

// async getAllCourses() {
// return this.courseModel.find().exec();
// }

// async getCourse(){
// return this.courseModel.find();
// }
// async getCourseId(id){
// return await this.courseModel.findById(id);
// }

// // Método para crear un curso
// async create(createCourseDto: CreateCourseDto): Promise<Course> {
// const course = new this.courseModel(createCourseDto); // Usa el DTO para crear el curso
// return course.save(); // Guarda el curso en la base de datos
// }
//constructor(@InjectModel(Course.name) private courseModel: Model<Course>) { }

// async createCourse(data: { title: string; description?: string }) {
// const newCourse = new this.courseModel(data);
// return newCourse.save();
// }

// async getAllCourses() {
// return this.courseModel.find().exec();
// }

// async getCourse(){
// return this.courseModel.find();
// }
// async getCourseId(id){
// return await this.courseModel.findById(id);
// }

// // Método para crear un curso
// async create(createCourseDto: CreateCourseDto): Promise<Course> {
// const course = new this.courseModel(createCourseDto); // Usa el DTO para crear el curso
// return course.save(); // Guarda el curso en la base de datos
// }
61 changes: 36 additions & 25 deletions server/apps/courses/src/courses/dto/create-course.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { z } from 'zod';

// Paso 1: Información básica del curso
export const StepOneSchema = z.object({
title: z.string().min(3, { message: 'Title must be at least 3 characters long' }),
title: z
.string()
.min(3, { message: 'Title must be at least 3 characters long' })
.max(100, { message: 'Title cannot exceed 100 characters' }), // Limitar la longitud
contentType: z.enum(['free', 'premium']),
courseType: z.enum(['appsheet', 'powerapps']),
kind: z.enum(['course', 'lesson']),
Expand All @@ -17,32 +20,40 @@ export const StepTwoSchema = z.object({
});

// Paso 3: Módulos y lecciones
export const LessonSchema = z.object({
lessonTitle: z
.string()
.min(3, { message: 'Lesson title must be at least 3 characters long' }),
lessonDescription: z.string().optional(),
materialUrl: z.string().url().optional(),
uploadedMaterial: z.string().optional(),
videoUrl: z.string().url().optional(),
});

export const ModuleSchema = z.object({
moduleTitle: z
.string()
.min(3, { message: 'Module title must be at least 3 characters long' }),
moduleDescription: z.string().optional(),
lessons: z.array(LessonSchema).optional(),
});

export const StepThreeSchema = z.object({
modules: z
.array(
z.object({
moduleTitle: z.string().min(3, { message: 'Module title must be at least 3 characters long' }),
moduleDescription: z.string().optional(),
lessons: z
.array(
z.object({
lessonTitle: z.string().min(3, { message: 'Lesson title must be at least 3 characters long' }),
lessonDescription: z.string().optional(),
materialUrl: z.string().url().optional(),
uploadedMaterial: z.string().optional(),
videoUrl: z.string().url().optional(),
}),
)
.optional(),
}),
)
.optional(),
modules: z.array(ModuleSchema).optional(),
});

// Paso 4: Información de fusiones
export const MergeInfoSchema = z.object({
discountPercentage: z.number().min(0).max(100).optional(),
relatedCourses: z.array(z.string()).optional(),
});

// Combinar los tres pasos en un esquema general
export const CreateCourseSchema = StepOneSchema.merge(StepTwoSchema).merge(StepThreeSchema);
// Combinar todos los pasos en un esquema general
export const CreateCourseSchema = StepOneSchema.merge(StepTwoSchema)
.merge(StepThreeSchema)
.extend({
mergeInfo: MergeInfoSchema.optional(),
userId: z.string(), // Se debe incluir desde el token
});

export type StepOneDto = z.infer<typeof StepOneSchema>;
export type StepTwoDto = z.infer<typeof StepTwoSchema>;
export type StepThreeDto = z.infer<typeof StepThreeSchema>;
export type CreateCourseDto = z.infer<typeof CreateCourseSchema>;
22 changes: 11 additions & 11 deletions server/apps/courses/src/courses/schemas/course.schema.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
import { Module } from './lesson.module.schema'; // Importamos el subesquema de módulos
import { MergeInfo, MergeInfoSchema } from './merge-info.schema'; // Importamos el subesquema de mergeInfo
import { Module, ModuleSchema } from './module.schema';
import { MergeInfo, MergeInfoSchema } from './merge-info.schema';

@Schema()
export class Course extends Document {
Expand All @@ -17,21 +17,21 @@ export class Course extends Document {
default: 'premium',
required: true,
})
contentType: string; // Tipo de contenido: gratuito o premium
contentType: string; // Tipo de contenido

@Prop({
type: String,
enum: ['appsheet', 'powerapps'],
required: true,
})
courseType: string; // Tipo de curso: appsheet o powerapps
courseType: string; // Tipo de curso

@Prop({
type: String,
enum: ['course', 'lesson'],
required: true,
})
kind: string; // Indica si es un curso o lección
kind: string; // Curso o lección

@Prop()
basicDescription?: string; // Descripción básica del curso
Expand All @@ -40,16 +40,16 @@ export class Course extends Document {
prerequisites?: string[]; // Requisitos previos del curso

@Prop()
detailedContent?: string; // Descripción detallada del contenido
detailedContent?: string; // Descripción detallada

@Prop()
imageUrl?: string; // URL de la imagen del curso

@Prop({ type: [Module], default: [] })
modules?: Module[]; // Lista de módulos del curso
@Prop({ type: [ModuleSchema], default: [] })
modules?: Module[]; // Lista de módulos

@Prop({ type: MergeInfoSchema })
mergeInfo?: MergeInfo; // Información sobre fusiones con otras apps o cursos
mergeInfo?: MergeInfo; // Información de fusiones

@Prop({ default: 'in-progress' })
status: string; // Estado del curso
Expand All @@ -58,7 +58,7 @@ export class Course extends Document {
createdAt: Date; // Fecha de creación

@Prop({ default: Date.now })
updatedAt: Date; // Fecha de última actualización
updatedAt: Date; // Fecha de actualización
}

export const CourseSchema = SchemaFactory.createForClass(Course);
export const CourseSchema = SchemaFactory.createForClass(Course);
5 changes: 3 additions & 2 deletions server/apps/courses/src/courses/schemas/merge-info.schema.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// merge-info.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

@Schema()
export class MergeInfo extends Document {
@Prop({ type: Number, required: false })
@Prop()
discountPercentage?: number; // Porcentaje de descuento

@Prop({ type: [String], required: false })
@Prop({ type: [String], default: [] })
relatedCourses?: string[]; // IDs de cursos relacionados
}

Expand Down
36 changes: 36 additions & 0 deletions server/apps/courses/src/courses/schemas/module.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// module.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';

@Schema()
export class Lesson {
@Prop({ required: true })
lessonTitle: string;

@Prop()
lessonDescription?: string;

@Prop()
materialUrl?: string;

@Prop()
uploadedMaterial?: string;

@Prop()
videoUrl?: string;
}

export const LessonSchema = SchemaFactory.createForClass(Lesson);

@Schema()
export class Module {
@Prop({ required: true })
moduleTitle: string;

@Prop()
moduleDescription?: string;

@Prop({ type: [LessonSchema], default: [] })
lessons?: Lesson[];
}

export const ModuleSchema = SchemaFactory.createForClass(Module);
Loading

0 comments on commit 5dc49e2

Please sign in to comment.