diff --git a/src/expert-initiated/dtos/login.dto.ts b/src/expert-initiated/dtos/login.dto.ts new file mode 100644 index 0000000..68b650b --- /dev/null +++ b/src/expert-initiated/dtos/login.dto.ts @@ -0,0 +1,32 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { IsEmail, IsNotEmpty, IsString } from "class-validator"; + +export class FieldExpertLoginDto { + @ApiProperty() + @IsEmail({ allow_underscores: true }) + @IsString({ + message: "email is not string", + context: { + errorCode: 4000, + note: "The validated email type must be string", + }, + }) + readonly email: string; + + @ApiProperty() + @IsNotEmpty({ + message: "password is empty", + context: { + errorCode: 4001, + note: "The validated password must not be empty", + }, + }) + @IsString({ + message: "password is not string", + context: { + errorCode: 4002, + note: "The validated password type must be string", + }, + }) + readonly password: string; +} diff --git a/src/expert-initiated/expert-initiated.controller.ts b/src/expert-initiated/expert-initiated.controller.ts new file mode 100644 index 0000000..8f2a1e8 --- /dev/null +++ b/src/expert-initiated/expert-initiated.controller.ts @@ -0,0 +1,16 @@ +import { Body, Controller, Post } from "@nestjs/common"; +import { ApiBearerAuth, ApiTags } from "@nestjs/swagger"; +import { FieldExpertLoginDto } from "./dtos/login.dto"; +import { FieldExpertService } from "./expert-initiated.service"; + +@Controller("expert-initiated") +@ApiTags("Expert Initiated Flow (Field Expert)") +@ApiBearerAuth() +export class FieldExpertController { + constructor(private readonly fieldExpertService: FieldExpertService) {} + + @Post("login") + async login(@Body() fieldExpertLoginDto: FieldExpertLoginDto) { + return await this.fieldExpertService.login(fieldExpertLoginDto); + } +} diff --git a/src/expert-initiated/expert-initiated.module.ts b/src/expert-initiated/expert-initiated.module.ts new file mode 100644 index 0000000..2050ef1 --- /dev/null +++ b/src/expert-initiated/expert-initiated.module.ts @@ -0,0 +1,25 @@ +import { Module } from "@nestjs/common"; +import { MongooseModule } from "@nestjs/mongoose"; +import { FieldExpert, FieldExpertSchema } from "./schemas/field-expert.schema"; +import { FieldExpertController } from "./expert-initiated.controller"; +import { FieldExpertService } from "./expert-initiated.service"; +import { FieldExpertRepository } from "./repositories/field-expert.repository"; +import { AuthModule } from "src/auth/auth.module"; +import { JwtModule } from "@nestjs/jwt"; + +@Module({ + imports: [ + MongooseModule.forFeature([ + { + name: FieldExpert.name, + schema: FieldExpertSchema, + }, + ]), + AuthModule, + JwtModule, + ], + controllers: [FieldExpertController], + providers: [FieldExpertRepository, FieldExpertService], + exports: [], +}) +export class ExpertInitiatedModule {} diff --git a/src/expert-initiated/expert-initiated.service.ts b/src/expert-initiated/expert-initiated.service.ts new file mode 100644 index 0000000..2a88ce7 --- /dev/null +++ b/src/expert-initiated/expert-initiated.service.ts @@ -0,0 +1,32 @@ +import { + BadRequestException, + Injectable, + NotFoundException, +} from "@nestjs/common"; +import { FieldExpertRepository } from "./repositories/field-expert.repository"; +import { FieldExpertLoginDto } from "./dtos/login.dto"; +import { UserAuthService } from "src/auth/auth-services/user.auth.service"; + +@Injectable() +export class FieldExpertService { + constructor( + private readonly fieldExpertRepository: FieldExpertRepository, + private readonly authService: UserAuthService, + ) {} + + async login(fieldExpertLoginDto: FieldExpertLoginDto) { + const user = await this.fieldExpertRepository.retrieveByEmail( + fieldExpertLoginDto.email, + ); + + if (!user) throw new NotFoundException("User not found"); + + const validate = await this.authService.validateUser( + user.email, + user.password, + ); + + if (!validate) + throw new BadRequestException("Username/Password does not match"); + } +} diff --git a/src/expert-initiated/repositories/field-expert.repository.ts b/src/expert-initiated/repositories/field-expert.repository.ts new file mode 100644 index 0000000..2e4784d --- /dev/null +++ b/src/expert-initiated/repositories/field-expert.repository.ts @@ -0,0 +1,22 @@ +import { Injectable } from "@nestjs/common"; +import { InjectModel } from "@nestjs/mongoose"; +import { Model } from "mongoose"; +import { FieldExpert } from "../schemas/field-expert.schema"; + +@Injectable() +export class FieldExpertRepository { + constructor( + @InjectModel(FieldExpert.name) + private readonly fieldExpertModel: Model, + ) {} + + async retrieveById(id: string): Promise { + return await this.fieldExpertModel.findById(id).exec(); + } + + async retrieveByEmail(email: string): Promise { + return await this.fieldExpertModel.findOne({ + email, + }); + } +} diff --git a/src/expert-initiated/schemas/field-expert.schema.ts b/src/expert-initiated/schemas/field-expert.schema.ts new file mode 100644 index 0000000..cde1c7d --- /dev/null +++ b/src/expert-initiated/schemas/field-expert.schema.ts @@ -0,0 +1,27 @@ +import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; +import { HydratedDocument, Types } from "mongoose"; + +export type FieldExpertDocument = HydratedDocument; + +@Schema({ + id: true, + timestamps: true, +}) +export class FieldExpert { + @Prop({ unique: true }) + email: string; + + @Prop({ required: true }) + password: string; + + @Prop({ required: true }) + firstName: string; + + @Prop({ required: true }) + lastName: string; + + @Prop({ required: true }) + cellphone: string; +} + +export const FieldExpertSchema = SchemaFactory.createForClass(FieldExpert);