Skip to content

Commit

Permalink
Merge pull request #38 from PBTP/feature/pet
Browse files Browse the repository at this point in the history
feature: pet �관련 API
  • Loading branch information
emibgo2 authored Oct 6, 2024
2 parents 42db0bf + 44a695f commit 1033355
Show file tree
Hide file tree
Showing 15 changed files with 614 additions and 75 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"aws-sdk": "^2.1623.0",
"axios": "^1.7.2",
"bcrypt": "^5.1.1",
"builder-pattern": "^2.2.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"ioredis": "^5.4.1",
Expand Down
20 changes: 10 additions & 10 deletions src/auth/decorator/auth.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ import {
ForbiddenException,
HttpCode,
HttpStatus,
UseGuards
} from "@nestjs/common";
import { Customer } from "../../schemas/customer.entity";
import { ApiBearerAuth, ApiUnauthorizedResponse } from "@nestjs/swagger";
import { AuthGuard } from "@nestjs/passport";
import { Business } from "../../schemas/business.entity";
import { Driver } from "../../schemas/drivers.entity";
UseGuards,
} from '@nestjs/common';
import { Customer } from '../../schemas/customer.entity';
import { ApiBearerAuth, ApiUnauthorizedResponse } from '@nestjs/swagger';
import { AuthGuard } from '@nestjs/passport';
import { Business } from '../../schemas/business.entity';
import { Driver } from '../../schemas/drivers.entity';

export const CurrentCustomer = createParamDecorator(
(data: unknown, context: ExecutionContext) => {
const req: { user?: Customer } = context.switchToHttp().getRequest();

if (!req.user.customerId) {
if (!req.user?.customerId) {
throw new ForbiddenException('해당 계정은 고객 계정이 아닙니다.');
}
return req.user;
Expand All @@ -28,7 +28,7 @@ export const CurrentBusiness = createParamDecorator(
(data: unknown, context: ExecutionContext) => {
const req: { user?: Business } = context.switchToHttp().getRequest();

if (!req.user.businessId) {
if (!req.user?.businessId) {
throw new ForbiddenException('해당 계정은 업체 계정이 아닙니다.');
}
return req.user;
Expand All @@ -39,7 +39,7 @@ export const CurrentDriver = createParamDecorator(
(data: unknown, context: ExecutionContext) => {
const req: { user?: Driver } = context.switchToHttp().getRequest();

if (!req.user.driverId) {
if (!req.user?.driverId) {
throw new ForbiddenException('해당 계정은 기사 계정이 아닙니다.');
}
return req.user;
Expand Down
24 changes: 24 additions & 0 deletions src/pet/application/pet.checklist.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Test, TestingModule } from '@nestjs/testing';
import { PetService } from './pet.service';

describe('PetChecklistService', () => {
let service: PetService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [PetService],
}).compile();

service = module.get<PetService>(PetService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});

it('should find checklist', () => {
service.findCheckList(null, null).then((checklist) => {
expect(checklist).toBeDefined();
});
});
});
185 changes: 170 additions & 15 deletions src/pet/application/pet.service.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,43 @@
import { ForbiddenException, Injectable, NotFoundException } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { Pet } from "../../schemas/pets.entity";
import { Breed } from "../../schemas/breed.entity";
import { Customer } from "../../schemas/customer.entity";
import { PetDto } from "../presentation/pet.dto";
import {
ForbiddenException,
Injectable,
NotFoundException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Repository } from 'typeorm';
import { Pet } from '../../schemas/pets.entity';
import { Breed } from '../../schemas/breed.entity';
import { Customer } from '../../schemas/customer.entity';
import {
PetChecklistAnswerDto,
PetChecklistChoiceDto,
PetChecklistDto,
PetDto,
} from '../presentation/pet.dto';
import {
ChecklistType,
PetChecklist,
PetChecklistCategory,
} from '../../schemas/pet-checklist.entity';
import { PetChecklistChoice } from '../../schemas/pet-checklist-chocie.entity';
import { PetChecklistAnswer } from '../../schemas/pet-checklist-answer.entity';
import { PetChecklistChoiceAnswer } from '../../schemas/pet-checklist-chocie-answer.entity';
import { Builder } from 'builder-pattern';
import { CustomerService } from '../../customer/application/customer.service';
import { BadRequestException } from '@nestjs/common/exceptions';

@Injectable()
export class PetService {
constructor(
private customerService: CustomerService,
@InjectRepository(Pet)
private petRepository: Repository<Pet>,

@InjectRepository(PetChecklist)
private petChecklistRepository: Repository<PetChecklist>,
@InjectRepository(PetChecklistAnswer)
private petChecklistAnswerRepository: Repository<PetChecklistAnswer>,
@InjectRepository(PetChecklistChoiceAnswer)
private petChecklistChoiceAnswerRepository: Repository<PetChecklistChoiceAnswer>,
@InjectRepository(Breed)
private breedRepository: Repository<Breed>,
) {}
Expand All @@ -34,6 +60,12 @@ export class PetService {
return await this.petRepository.save(newPet);
}

async findAll(customer: Customer): Promise<Pet[]> {
return await this.petRepository.find({
where: { customer: { customerId: customer.customerId } },
relations: ['breed'],
});
}
async findOne(id: number, customer: Customer): Promise<Pet> {
const pet = await this.petRepository.findOneOrFail({
where: { petId: id },
Expand All @@ -55,20 +87,18 @@ export class PetService {
const pet = await this.findOne(id, customer);

if (dto.breedId && dto.breedId !== pet.breed.breedId) {
const breed = await this.breedRepository.findOneOrFail({
pet.breed = await this.breedRepository.findOneOrFail({
where: { breedId: dto.breedId },
});

pet.breed = breed;
}

pet.name = dto.name ?? pet.name;
pet.birthdate = dto.birthdate ?? pet.birthdate;
pet.weight = dto.weight ?? pet.weight;
pet.petName = dto.petName ?? pet.petName;
pet.petBirthdate = dto.petBirthdate ?? pet.petBirthdate;
pet.petWeight = dto.petWeight ?? pet.petWeight;
pet.neuteredYn = dto.neuteredYn ?? pet.neuteredYn;
pet.personality = dto.personality ?? pet.personality;
pet.vaccinationStatus = dto.vaccinationStatus ?? pet.vaccinationStatus;
pet.gender = dto.gender ?? pet.gender;
pet.petGender = dto.petGender ?? pet.petGender;

return await this.petRepository.save(pet);
}
Expand All @@ -78,4 +108,129 @@ export class PetService {

await this.petRepository.softDelete(pet.petId);
}

async findCheckList(
category: PetChecklistCategory,
type: ChecklistType,
petId: number,
customer: Customer,
): Promise<PetChecklistDto[]> {
let query = this.petChecklistRepository
.createQueryBuilder('PC')
.leftJoinAndMapMany(
'PC.petChecklistChoices',
PetChecklistChoice,
'PCC',
'PC.pet_checklist_id = PCC.pet_checklist_id',
);

if (petId) {
await this.findOne(petId, customer);

query = query
.leftJoinAndMapOne(
'PCC.petChecklistChoiceAnswers',
PetChecklistChoiceAnswer,
'PCCA',
`PCC.pet_checklist_id = PCCA.pet_checklist_id
AND PCC.pet_checklist_choice_id = PCCA.pet_checklist_choice_id
AND PCCA.pet_id = :petId`,
{ petId },
)
.leftJoinAndMapMany(
'PC.petChecklistAnswers',
PetChecklistAnswer,
'PCA',
'PC.pet_checklist_id = PCA.pet_checklist_id AND PCA.pet_id = :petId',
{ petId },
);
}

type && query.andWhere('PC.pet_checklist_type = :type', { type });
category &&
query.andWhere('PC.pet_checklist_category = :category', { category });

query.orderBy('PC.pet_checklist_id');

const data = await query.getMany();
return data.map((checklist) => {
const dto = Builder<PetChecklistDto>()
.petChecklistId(checklist.petChecklistId)
.petChecklistType(checklist.petChecklistType)
.petChecklistCategory(checklist.petChecklistCategory)
.petChecklistContent(checklist.petChecklistContent)
.petChecklistChoices(
checklist?.petChecklistChoices?.map((choice) => {
return Builder<PetChecklistChoiceDto>()
.petChecklistChoiceId(choice.petChecklistChoiceId)
.petChecklistChoiceContent(choice.petChecklistChoiceContent)
.checked(!!choice?.petChecklistChoiceAnswers)
.build();
}),
)
.petChecklistAnswer(
checklist.petChecklistAnswers
? checklist?.petChecklistAnswers[0]?.petChecklistAnswer
: null,
)
.build();

if (dto.petChecklistType === ChecklistType.ANSWER) {
dto.petChecklistChoices = null;
} else {
dto.petChecklistAnswer = null;
}

return dto;
});
}

async answerChecklist(
petId: number,
dto: PetChecklistAnswerDto[],
customer: Customer,
) {
const pet = await this.findOne(petId, customer);

const checklist = await this.petChecklistRepository.find({
where: {
petChecklistId: In(dto.map((v) => v.petChecklistId)),
},
});

for (const v of checklist) {
const answer = dto.find((d) => d.petChecklistId === v.petChecklistId);

if (v.petChecklistType === ChecklistType.ANSWER) {
if (!answer.petChecklistAnswer) {
throw new BadRequestException('답변을 적어주세요');
}

await this.petChecklistAnswerRepository.save({
pet,
petChecklistId: v.petChecklistId,
petChecklistAnswer: answer.petChecklistAnswer,
});
} else {
if (!answer.petChecklistChoiceId || answer.checked == undefined) {
throw new BadRequestException('선택지를 선택해주세요');
}

if (answer.checked) {
await this.petChecklistChoiceAnswerRepository.save({
petId,
petChecklistId: v.petChecklistId,
petChecklistChoiceId: answer.petChecklistChoiceId,
});
return;
}

await this.petChecklistChoiceAnswerRepository.delete({
petId,
petChecklistId: v.petChecklistId,
petChecklistChoiceId: answer.petChecklistChoiceId,
});
}
}
}
}
15 changes: 14 additions & 1 deletion src/pet/pet.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,22 @@ import { PetService } from './application/pet.service';
import { PetController } from './presentation/pet.controller';
import { Pet } from 'src/schemas/pets.entity';
import { Breed } from 'src/schemas/breed.entity';
import { PetChecklist } from '../schemas/pet-checklist.entity';
import { CustomerModule } from '../customer/customer.module';
import { PetChecklistChoiceAnswer } from '../schemas/pet-checklist-chocie-answer.entity';
import { PetChecklistAnswer } from '../schemas/pet-checklist-answer.entity';

@Module({
imports: [TypeOrmModule.forFeature([Pet, Breed])],
imports: [
TypeOrmModule.forFeature([
Pet,
Breed,
PetChecklist,
PetChecklistAnswer,
PetChecklistChoiceAnswer,
]),
CustomerModule,
],
controllers: [PetController],
providers: [PetService],
exports: [PetService],
Expand Down
Loading

0 comments on commit 1033355

Please sign in to comment.