diff --git a/BE/src/question/controller/question.controller.spec.ts b/BE/src/question/controller/question.controller.spec.ts deleted file mode 100644 index 7b1d377..0000000 --- a/BE/src/question/controller/question.controller.spec.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { QuestionController } from './question.controller'; -import { QuestionService } from '../service/question.service'; -import { TokenService } from '../../token/service/token.service'; -import { CustomQuestionRequest } from '../dto/customQuestionRequest'; -import { - memberFixture, - mockReqWithMemberFixture, - oauthRequestFixture, -} from '../../member/fixture/member.fixture'; -import { ContentEmptyException } from '../exception/question.exception'; -import { INestApplication, UnauthorizedException } from '@nestjs/common'; -import { QuestionRepository } from '../repository/question.repository'; -import { Member } from '../../member/entity/member'; -import { Question } from '../entity/question'; -import { - customQuestionRequestFixture, - questionFixture, -} from '../fixture/question.fixture'; -import * as request from 'supertest'; -import { MemberModule } from '../../member/member.module'; -import { TokenModule } from '../../token/token.module'; -import { QuestionModule } from '../question.module'; -import { AuthModule } from '../../auth/auth.module'; -import { AuthService } from '../../auth/service/auth.service'; -import { MemberRepository } from '../../member/repository/member.repository'; -import { Token } from '../../token/entity/token'; -import { createIntegrationTestModule } from '../../util/test.util'; - -describe('QuestionController 단위테스트', () => { - let controller: QuestionController; - - const mockQuestionService = { - createCustomQuestion: jest.fn(), - findCategories: jest.fn(), - deleteById: jest.fn(), - }; - - const mockTokenService = {}; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [QuestionService, TokenService], - controllers: [QuestionController], - }) - .overrideProvider(QuestionService) - .useValue(mockQuestionService) - .overrideProvider(TokenService) - .useValue(mockTokenService) - .compile(); - - controller = module.get(QuestionController); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); - - it('커스텀 질문을 생성할 때 토큰이 있고, body의 content가 문자열로 존재한다면 성공적으로 저장된다.', async () => { - mockQuestionService.createCustomQuestion.mockResolvedValue(undefined); - - const body = { content: 'test content' } as CustomQuestionRequest; - const result = await controller.createCustomQuestion( - mockReqWithMemberFixture, - body, - ); - expect(result).toEqual(undefined); - }); - - it('커스텀 질문 생성 실패 => body === undefined | "" | null', async () => { - const arr = [undefined, '', null]; - for (const value of arr) { - const body = { content: value } as CustomQuestionRequest; - - mockQuestionService.createCustomQuestion.mockRejectedValue( - new ContentEmptyException(), - ); - - await expect( - controller.createCustomQuestion(mockReqWithMemberFixture, body), - ).rejects.toThrow(ContentEmptyException); - } - }); - - /* - TODO: 카테고리별 질문 조회는 후에 Answer API를 생성 후에, Default Answer까지 붙여서 한번에 테스트하기 위해 보류 - */ - - it('나만의 질문을 삭제한다', async () => { - mockQuestionService.deleteById.mockResolvedValue(undefined); - const result = await controller.deleteQuestion(1, mockReqWithMemberFixture); - expect(result).toEqual(undefined); - }); - - it('나만의 질문을 삭제 실패 => Unauthorized', async () => { - mockQuestionService.deleteById.mockRejectedValue( - new UnauthorizedException(), - ); - await expect( - controller.deleteQuestion(1, mockReqWithMemberFixture), - ).rejects.toThrow(UnauthorizedException); - }); -}); - -describe('Question Controller 통합 테스트', () => { - let app: INestApplication; - let questionRepository: QuestionRepository; - let authService: AuthService; - let memberRepository: MemberRepository; - - beforeAll(async () => { - const modules = [MemberModule, TokenModule, QuestionModule, AuthModule]; - - const entities = [Member, Question, Token]; - const moduleFixture: TestingModule = await createIntegrationTestModule( - modules, - entities, - ); - - app = moduleFixture.createNestApplication(); - await app.init(); - - questionRepository = - moduleFixture.get(QuestionRepository); - authService = moduleFixture.get(AuthService); - memberRepository = moduleFixture.get(MemberRepository); - }); - - it('해당 게시물을 저장한다.', (done) => { - memberRepository - .save(memberFixture) - .then(() => { - return authService.login(oauthRequestFixture); - }) - .then((token) => { - request - .agent(app.getHttpServer()) - .post('/api/question') - .set('Cookie', [`accessToken=${token}`]) - .send(customQuestionRequestFixture) - .expect(201); - }) - .then(done); - }); - - it('해당 게시물을 삭제한다.', (done) => { - memberRepository - .save(memberFixture) - .then(() => questionRepository.save(questionFixture)) - .then(() => { - return authService.login(oauthRequestFixture); - }) - .then((token) => { - request - .agent(app.getHttpServer()) - .delete(`/api/question?id=${questionFixture.id}`) - .set('Cookie', [`accessToken=${token}`]) - .expect(204); - }) - .then((response) => { - expect(response).toBeUndefined(); - done(); - }); - }); - - afterEach(async () => { - // 테스트용 데이터베이스의 테이블 데이터를 지우는 로직 추가 - await questionRepository.query('delete from token'); - await questionRepository.query('delete from Question'); - await questionRepository.query('delete from Member'); - }); - - afterAll(async () => { - await app.close(); - }); -}); diff --git a/BE/src/question/controller/question.controller.ts b/BE/src/question/controller/question.controller.ts deleted file mode 100644 index 24bec05..0000000 --- a/BE/src/question/controller/question.controller.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { - Body, - Controller, - Delete, - Get, - Param, - Post, - Query, - Req, - UseGuards, -} from '@nestjs/common'; -import { - ApiBearerAuth, - ApiOperation, - ApiResponse, - ApiTags, -} from '@nestjs/swagger'; -import { QuestionService } from '../service/question.service'; -import { Request } from 'express'; -import { TokenService } from 'src/token/service/token.service'; -import { QuestionListResponse } from '../dto/questionListResponse'; -import { createApiResponseOption } from '../../util/swagger.util'; -import { AuthGuard } from '@nestjs/passport'; -import { Member } from '../../member/entity/member'; -import { CustomQuestionRequest } from '../dto/customQuestionRequest'; -import { CategoriesResponse } from '../dto/categoriesResponse'; - -@Controller('/api/question') -@ApiTags('question') -export class QuestionController { - constructor( - private questionService: QuestionService, - private tokenService: TokenService, - ) {} - - @Post('') - @UseGuards(AuthGuard('jwt')) - @ApiBearerAuth() - @ApiOperation({ summary: '커스텀 질문 생성' }) - @ApiResponse(createApiResponseOption(201, '커스텀 질문 생성', null)) - async createCustomQuestion( - @Req() req: Request, - @Body() customQuestionRequest: CustomQuestionRequest, - ) { - await this.questionService.createCustomQuestion( - customQuestionRequest, - req.user as Member, - ); - } - - @Get('') - @ApiResponse( - createApiResponseOption( - 200, - '카테고리별 게시물 조회 api', - QuestionListResponse, - ), - ) - @ApiOperation({ summary: '카테고리별 질문 조회' }) - @UseGuards(AuthGuard('jwt-soft')) - async findAllByCategory( - @Query('category') category: string, - @Req() request: Request, - ): Promise { - const member = request.user; - return await this.questionService.findByCategory( - category, - member ? (request.user as Member).id : undefined, - ); - } - - @Get('/category') - @ApiResponse( - createApiResponseOption(200, '전체 카테고리 조회', CategoriesResponse), - ) - @ApiOperation({ summary: '전체 카테고리 조회' }) - async findAllCategories(): Promise { - return new CategoriesResponse(await this.questionService.findCategories()); - } - - @ApiOperation({ summary: '게시글 삭제 api' }) - @UseGuards(AuthGuard('jwt')) - @ApiBearerAuth() - @Delete(':questionId') - @ApiResponse(createApiResponseOption(204, '게시글 삭제', null)) - async deleteQuestion( - @Param('questionId') questionId: number, - @Req() req: Request, - ) { - await this.questionService.deleteById(questionId, req.user as Member); - } -} diff --git a/BE/src/question/dto/categoriesResponse.ts b/BE/src/question/dto/categoriesResponse.ts deleted file mode 100644 index 295bc19..0000000 --- a/BE/src/question/dto/categoriesResponse.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { createPropertyOption } from '../../util/swagger.util'; - -const CATEGORIES_EXAMPLE = ['CS', 'BE', 'FE', '나만의 질문']; - -export class CategoriesResponse { - @ApiProperty( - createPropertyOption(CATEGORIES_EXAMPLE, '질문 dto의 리스트', [String]), - ) - categories: string[]; - - constructor(categories: string[]) { - this.categories = categories; - } -} diff --git a/BE/src/question/dto/createQuestionRequest.ts b/BE/src/question/dto/createQuestionRequest.ts deleted file mode 100644 index f3680d9..0000000 --- a/BE/src/question/dto/createQuestionRequest.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { IsNotEmpty, IsString } from '@nestjs/class-validator'; - -export class CreateQuestionRequest { - @IsString() - @IsNotEmpty() - category: string; - - @IsString() - @IsNotEmpty() - content: string; -} diff --git a/BE/src/question/dto/customQuestionRequest.ts b/BE/src/question/dto/customQuestionRequest.ts deleted file mode 100644 index b040d06..0000000 --- a/BE/src/question/dto/customQuestionRequest.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { IsNotEmpty, IsString } from '@nestjs/class-validator'; -import { ApiProperty } from '@nestjs/swagger'; - -export class CustomQuestionRequest { - @ApiProperty({ - example: '개발자가 되기 좋은 역량은 무엇일까요?', - description: 'content', - required: true, - }) - @IsString() - @IsNotEmpty() - readonly content: string; -} diff --git a/BE/src/question/dto/questionListResponse.ts b/BE/src/question/dto/questionListResponse.ts deleted file mode 100644 index 912a0f6..0000000 --- a/BE/src/question/dto/questionListResponse.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { Question } from '../entity/question'; -import { SingleQuestionResponse } from './singleQuestionResponse'; -import { questionListExample } from '../util/question.util'; -import { createPropertyOption } from '../../util/swagger.util'; - -export class QuestionListResponse { - @ApiProperty( - createPropertyOption(questionListExample, '질문 dto의 리스트', [ - SingleQuestionResponse, - ]), - ) - readonly questionsList: SingleQuestionResponse[]; - - constructor(questionDtoList: SingleQuestionResponse[]) { - this.questionsList = questionDtoList; - } - - static from(question: Question[]): QuestionListResponse { - return new QuestionListResponse(question.map(SingleQuestionResponse.from)); - } -} diff --git a/BE/src/question/dto/singleQuestionResponse.ts b/BE/src/question/dto/singleQuestionResponse.ts deleted file mode 100644 index 78d0101..0000000 --- a/BE/src/question/dto/singleQuestionResponse.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { Question } from '../entity/question'; -import { createPropertyOption } from '../../util/swagger.util'; - -export class SingleQuestionResponse { - @ApiProperty(createPropertyOption('1', '게시물 ID', Number)) - readonly id: number; - - @ApiProperty( - createPropertyOption('CS/BE/FE/CUSTOM', '질문에 대한 카테고리', String), - ) - readonly category: string; - - @ApiProperty( - createPropertyOption('CS는 무슨 단어의 약자일까요?', '질문 내용', String), - ) - readonly content: string; - - constructor(id: number, category: string, content: string) { - this.id = id; - this.category = category; - this.content = content; - } - - static from(question: Question): SingleQuestionResponse { - return new SingleQuestionResponse( - question.id, - question.category, - question.content, - ); - } -} diff --git a/BE/src/question/entity/question.ts b/BE/src/question/entity/question.ts index e5f5972..f1dff10 100644 --- a/BE/src/question/entity/question.ts +++ b/BE/src/question/entity/question.ts @@ -1,35 +1,38 @@ import { DefaultEntity } from '../../app.entity'; -import { Column, Entity, ManyToMany, JoinTable } from 'typeorm'; -import { Member } from '../../member/entity/member'; -import { CreateQuestionRequest } from '../dto/createQuestionRequest'; +import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm'; +import { Category } from '../../category/entity/category'; @Entity({ name: 'Question' }) export class Question extends DefaultEntity { - @Column() - readonly category: string; - @Column({ type: 'text' }) readonly content: string; - @ManyToMany(() => Member) - @JoinTable({ name: 'MemberQuestion' }) - readonly members: Member[]; + @ManyToOne(() => Category, { onDelete: 'CASCADE', eager: true }) + @JoinColumn({ name: 'category' }) + readonly category: Category; - constructor(category: string, content: string, members: Member[]) { - super(undefined, new Date()); - this.category = category; + @ManyToOne(() => Question, { nullable: true, onDelete: 'CASCADE' }) + @JoinColumn({ name: 'origin' }) + readonly origin: Question; + + constructor( + id: number, + content: string, + category: Category, + origin: Question, + createdAt: Date, + ) { + super(id, createdAt); this.content = content; - this.members = members; + this.category = category; + this.origin = origin; + } + + static of(category: Category, origin: Question, content: string) { + return new Question(null, content, category, origin, new Date()); } - static from( - createQuestionRequest: CreateQuestionRequest, - member: Member, - ): Question { - return new Question( - createQuestionRequest.category, - createQuestionRequest.content, - [member], - ); + static copyOf(question: Question, category: Category) { + return new Question(null, question.content, category, question, new Date()); } } diff --git a/BE/src/question/exception/question.exception.ts b/BE/src/question/exception/question.exception.ts deleted file mode 100644 index d5972b2..0000000 --- a/BE/src/question/exception/question.exception.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { HttpException } from '@nestjs/common'; - -class QuestionNotFoundException extends HttpException { - constructor() { - super('해당 커스텀 질문이 존재하지 않습니다.', 404); - } -} - -class ContentEmptyException extends HttpException { - constructor() { - super('나만의 질문의 내용을 입력해야 합니다.', 400); - } -} - -export { QuestionNotFoundException, ContentEmptyException }; diff --git a/BE/src/question/fixture/question.fixture.ts b/BE/src/question/fixture/question.fixture.ts deleted file mode 100644 index 2c7715a..0000000 --- a/BE/src/question/fixture/question.fixture.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Question } from '../entity/question'; -import { memberFixture } from '../../member/fixture/member.fixture'; -import { CustomQuestionRequest } from '../dto/customQuestionRequest'; - -export const questionFixture: Question = new Question( - 'CUSTOM', - 'test content', - [memberFixture], -); - -export const customQuestionRequestFixture = { - content: 'test content', -} as CustomQuestionRequest; - -export const BEQuestionFixture = new Question( - 'BE', - '관계형 데이터베이스와 NoSQL의 차이는?', - null, -); -export const FEQuestionFixture = new Question( - 'FE', - '상태관리를 보통 어떻게 해오시나요?', - null, -); -export const CSQuestionFixture = new Question( - 'CS', - '깃의 저장방식에 대해서 설명해보세요', - null, -); -export const CustomQuestionFixture = new Question( - 'CUSTOM', - '깃의 저장방식에 대해서 설명해보세요', - null, -); -export const multiQuestionFixture = [ - BEQuestionFixture, - FEQuestionFixture, - CSQuestionFixture, - CustomQuestionFixture, -]; diff --git a/BE/src/question/question.module.ts b/BE/src/question/question.module.ts index 8326f05..764c924 100644 --- a/BE/src/question/question.module.ts +++ b/BE/src/question/question.module.ts @@ -1,16 +1,10 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { Member } from '../member/entity/member'; import { Question } from './entity/question'; -import { QuestionService } from './service/question.service'; -import { QuestionRepository } from './repository/question.repository'; -import { QuestionController } from './controller/question.controller'; import { TokenModule } from 'src/token/token.module'; -import { MemberRepository } from '../member/repository/member.repository'; +import { Category } from '../category/entity/category'; @Module({ - imports: [TypeOrmModule.forFeature([Question, Member]), TokenModule], - providers: [QuestionRepository, QuestionService, MemberRepository], - controllers: [QuestionController], + imports: [TypeOrmModule.forFeature([Question, Category]), TokenModule], }) export class QuestionModule {} diff --git a/BE/src/question/repository/question.repository.ts b/BE/src/question/repository/question.repository.ts index 43c894a..6a3728f 100644 --- a/BE/src/question/repository/question.repository.ts +++ b/BE/src/question/repository/question.repository.ts @@ -1,67 +1,27 @@ +import { Repository } from 'typeorm'; +import { Question } from '../entity/question'; import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { Question } from '../entity/question'; -import { Repository } from 'typeorm'; @Injectable() export class QuestionRepository { constructor( - @InjectRepository(Question) - private questionRepository: Repository, + @InjectRepository(Question) private repository: Repository, ) {} async save(question: Question) { - await this.questionRepository.save(question); + return await this.repository.save(question); } - async findAllByCategoryOrderByCreatedAtDesc( - category: string, - memberId: number, - ): Promise { - return (await this.constructQueryBuilder(category, memberId)) - .orderBy('Question.createdAt', 'DESC') - .getMany(); + async findByCategoryId(categoryId: number) { + return await this.repository.findBy({ category: { id: categoryId } }); } - async findById(id: number) { - return await this.questionRepository.findOneBy({ id: id }); - } - - async findCategories(): Promise { - const distinctCategories = (await this.questionRepository - .createQueryBuilder() - .select('DISTINCT category', 'category') - .getRawMany()) as Question[]; - - return distinctCategories.map((result) => result.category); - } - - async findQuestionByIdAndMember_Id(questionId: number, memberId: number) { - return this.questionRepository.findOneBy({ - members: { id: memberId }, - id: questionId, - }); + async findById(questionId: number) { + return await this.repository.findOneBy({ id: questionId }); } async remove(question: Question) { - await this.questionRepository.remove(question); - } - - async query(query: string) { - await this.questionRepository.query(query); - } - - private async constructQueryBuilder(category: string, memberId: number) { - const queryBuilder = this.questionRepository.createQueryBuilder('Question'); - - if (category === 'CUSTOM') { - return queryBuilder - .leftJoin('Question.id', 'QuestionMember') - .leftJoin('QuestionMember.memberId', 'Member') - .where('Question.category = :category', { category }) - .andWhere('member.id = :memberId', { memberId }); - } - - return queryBuilder.where('Question.category = :category', { category }); + await this.repository.remove(question); } } diff --git a/BE/src/question/service/question.service.spec.ts b/BE/src/question/service/question.service.spec.ts deleted file mode 100644 index bc4eed1..0000000 --- a/BE/src/question/service/question.service.spec.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { QuestionService } from './question.service'; -import { QuestionRepository } from '../repository/question.repository'; -import { MemberRepository } from '../../member/repository/member.repository'; -import { CustomQuestionRequest } from '../dto/customQuestionRequest'; -import { ContentEmptyException } from '../exception/question.exception'; -import { UnauthorizedException } from '@nestjs/common'; -import { memberFixture } from '../../member/fixture/member.fixture'; -import { - customQuestionRequestFixture, - questionFixture, -} from '../fixture/question.fixture'; -import { AppModule } from '../../app.module'; -import { MemberModule } from '../../member/member.module'; - -describe('QuestionService 단위 테스트', () => { - let service: QuestionService; - const mockQuestionRepository = { - save: jest.fn(), - findCategories: jest.fn(), - findQuestionByIdAndMember_Id: jest.fn(), - remove: jest.fn(), - }; - - const mockMemberRepository = {}; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [QuestionService, QuestionRepository, MemberRepository], - }) - .overrideProvider(QuestionRepository) - .useValue(mockQuestionRepository) - .overrideProvider(MemberRepository) - .useValue(mockMemberRepository) - .compile(); - - service = module.get(QuestionService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); - - it('나만의 질문을 저장한다.', async () => { - mockQuestionRepository.save.mockResolvedValue(undefined); - const result = await service.createCustomQuestion( - customQuestionRequestFixture, - memberFixture, - ); - expect(result).toEqual(undefined); - }); - - it('나만의 질문 저장 실패 => content가 없을 때', async () => { - const customQuestionRequest = { - content: undefined, - } as CustomQuestionRequest; - mockQuestionRepository.save.mockResolvedValue(undefined); - await expect( - service.createCustomQuestion(customQuestionRequest, memberFixture), - ).rejects.toThrow(ContentEmptyException); - }); - - /* - TODO : 카테고리별 질문 조회는 Answer까지 만든 후에, 이를 Question에 합쳐야 하는 문제가 있다. 이로 인해 Answer API생성 후, 해당 API 단위테스트시에 추가할 예정이다. - */ - - it('나만의 질문을 삭제를 실패 => 회원의 id와 Question.id로 조회하지 못할 때', async () => { - mockQuestionRepository.findQuestionByIdAndMember_Id.mockResolvedValue( - undefined, - ); - await expect(service.deleteById(1, memberFixture)).rejects.toThrow( - UnauthorizedException, - ); - }); - - it('나만의 질문을 삭제한다', async () => { - mockQuestionRepository.findQuestionByIdAndMember_Id.mockResolvedValue( - questionFixture, - ); - mockQuestionRepository.remove.mockResolvedValue(undefined); - const result = await service.deleteById(1, memberFixture); - expect(result).toEqual(undefined); - }); -}); - -describe('Question Service 통합 테스트', () => { - let service: QuestionService; - let questionRepository: QuestionRepository; - let memberRepository: MemberRepository; - - beforeAll(async () => { - const module: TestingModule = await Test.createTestingModule({ - imports: [AppModule, MemberModule], - }).compile(); - - service = module.get(QuestionService); - questionRepository = module.get(QuestionRepository); - memberRepository = module.get(MemberRepository); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); - - it('나만의 커스텀 질문을 저장한다.', (done) => { - memberRepository - .save(memberFixture) - .then(() => - service.createCustomQuestion( - customQuestionRequestFixture, - memberFixture, - ), - ) - .then(() => { - // 비동기 작업이 완료되면 done()을 호출하여 테스트 종료 - done(); - }) - .catch((error) => { - done(error); // 에러가 발생한 경우 done.fail()을 호출하여 테스트를 실패로 표시 - }); - }); - - it('id를 통해 질문 삭제', (done) => { - const question = questionFixture; - questionRepository - .save(question) - .then(() => service.deleteById(question.id, memberFixture)) - .then(() => questionRepository.findById(question.id)) - .then((question) => { - expect(question).toBeNull(); - done(); - }); - }); -}); diff --git a/BE/src/question/service/question.service.ts b/BE/src/question/service/question.service.ts deleted file mode 100644 index 3985abf..0000000 --- a/BE/src/question/service/question.service.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { Injectable, UnauthorizedException } from '@nestjs/common'; -import { QuestionRepository } from '../repository/question.repository'; -import { CreateQuestionRequest } from '../dto/createQuestionRequest'; -import { Member } from 'src/member/entity/member'; -import { Question } from '../entity/question'; -import { isEmpty } from 'class-validator'; -import { isCategoryCustom, OUTPUT_FORM } from '../util/question.util'; -import { MemberRepository } from '../../member/repository/member.repository'; -import { QuestionListResponse } from '../dto/questionListResponse'; -import { CustomQuestionRequest } from '../dto/customQuestionRequest'; -import { ContentEmptyException } from '../exception/question.exception'; - -@Injectable() -export class QuestionService { - constructor( - private questionRepository: QuestionRepository, - private memberRepository: MemberRepository, - ) {} - - // async createQuestion( - // createQuestionRequest: CreateQuestionRequest, - // member: Member, - // ) { - // const question = Question.from(createQuestionRequest, member); - // await this.questionRepository.save(question); - // } - - async createCustomQuestion( - customQuestionRequest: CustomQuestionRequest, - member: Member, - ) { - if (isEmpty(customQuestionRequest.content)) { - throw new ContentEmptyException(); - } - - const questionRequest = { - category: 'CUSTOM', - content: customQuestionRequest.content, - } as CreateQuestionRequest; - const question = Question.from(questionRequest, member); - await this.questionRepository.save(question); - } - - async findCategories() { - const categories = (await this.questionRepository.findCategories()).map( - (categoryOnDB) => OUTPUT_FORM[categoryOnDB], - ); - categories.sort(); - return categories; - } - - async findByCategory(category: string, memberId?: number) { - if (isEmpty(memberId) && isCategoryCustom(category)) { - throw new UnauthorizedException(); - } - - const member = await this.memberRepository.findById(memberId); - const questionList = - await this.questionRepository.findAllByCategoryOrderByCreatedAtDesc( - category, - isEmpty(member) ? undefined : memberId, - ); - - return QuestionListResponse.from(questionList); - } - - async deleteById(id: number, member: Member) { - const question = await this.questionRepository.findQuestionByIdAndMember_Id( - id, - member.id, - ); - - if (isEmpty(question)) { - throw new UnauthorizedException(); - } - - await this.questionRepository.remove(question); - } -}