Skip to content

Commit

Permalink
refactor: 전체적인 코드 리뷰 (#69)
Browse files Browse the repository at this point in the history
* refactor: remove unused import

* refactor(eslint): 문법 수정

* refactor(auth): 중복 코드 삭제

* refactor(study): 사용하지 않는 메소드 삭제

* refactor(member): repository 메소드 네이밍 통일

* fix(activity/study): author 시그니처 변경

* fix(activity/study): controller에서 member 그만 받기

* fix(activity/study): 중복된 study가 생성되지 않도록 수정
  • Loading branch information
son-daehyeon committed Sep 13, 2024
1 parent e978007 commit ecc9320
Show file tree
Hide file tree
Showing 23 changed files with 131 additions and 176 deletions.
20 changes: 7 additions & 13 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,11 @@ import tseslint from 'typescript-eslint';
import prettierConfig from 'eslint-config-prettier';
import prettierRecommended from 'eslint-plugin-prettier/recommended';

export default tseslint.config(
{
files: ['**/*.js', '**/*.mjs', '**/*.ts'],
extends: [eslint.configs.recommended, ...tseslint.configs.recommended],
rules: {
'no-console': 'warn',
},
export default tseslint.config({
files: ['**/*.js', '**/*.mjs', '**/*.ts'],
extends: [eslint.configs.recommended, ...tseslint.configs.recommended, prettierRecommended],
rules: {
...prettierConfig.rules,
'no-console': 'warn',
},
{
files: ['**/*.js', '**/*.mjs', '**/*.ts'],
extends: [prettierRecommended],
rules: prettierConfig.rules,
},
);
});
20 changes: 10 additions & 10 deletions src/domain/activity/study/controller/study.admin.controller.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { Body, Controller, Delete, Patch, Put } from '@nestjs/common';
import { ApiOperation, ApiProperty, ApiTags } from '@nestjs/swagger';

import { AuthAdminAccount, AuthAdminAccountException, ReqMember } from '@wink/auth/guard';

import { Member } from '@wink/member/schema';
import { AuthAdminAccount, AuthAdminAccountException } from '@wink/auth/guard';

import {
CreateCategoryRequestDto,
Expand All @@ -16,6 +14,7 @@ import {
} from '@wink/activity/dto';
import {
AlreadyExistsCategoryException,
AlreadyExistsStudyException,
CategoryNotFoundException,
StudyNotFoundException,
} from '@wink/activity/exception';
Expand Down Expand Up @@ -50,7 +49,7 @@ export class StudyAdminController {
return this.studyAdminService.updateCategory(request);
}

@Put('/category')
@Delete('/category')
@AuthAdminAccount()
@ApiOperation({ summary: '카테고리 삭제' })
@ApiProperty({ type: CreateStudyRequestDto })
Expand All @@ -65,12 +64,13 @@ export class StudyAdminController {
@ApiOperation({ summary: '스터디 생성' })
@ApiProperty({ type: CreateStudyRequestDto })
@ApiCustomResponse(CreateStudyResponseDto)
@ApiCustomErrorResponse([...AuthAdminAccountException, CategoryNotFoundException])
async createStudy(
@ReqMember() member: Member,
@Body() request: CreateStudyRequestDto,
): Promise<CreateStudyResponseDto> {
return this.studyAdminService.createStudy(member, request);
@ApiCustomErrorResponse([
...AuthAdminAccountException,
CategoryNotFoundException,
AlreadyExistsStudyException,
])
async createStudy(@Body() request: CreateStudyRequestDto): Promise<CreateStudyResponseDto> {
return this.studyAdminService.createStudy(request);
}

@Delete()
Expand Down
2 changes: 1 addition & 1 deletion src/domain/activity/study/controller/study.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ApiCustomResponse } from '@wink/swagger';
export class StudyController {
constructor(private readonly studyService: StudyService) {}

@Get()
@Get('/category')
@ApiOperation({ summary: '스터디 카테고리 목록' })
@ApiCustomResponse(GetCategoriesResponseDto)
async getCategories(): Promise<GetCategoriesResponseDto> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import { Category } from '@wink/activity/schema';
export class CreateCategoryResponseDto {
@ApiProperty({
description: '카테고리',
type: Category,
example: {
_id: '1a2b3c4d5e6f7a8b9c0d1e2f',
name: 'React.js 스터디',
},
})
category!: Category;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ import { Study } from '@wink/activity/schema';
export class CreateStudyResponseDto {
@ApiProperty({
description: '스터디',
example: {
_id: '1a2b3c4d5e6f7a8b9c0d1e2f',
createdAt: '2024-08-01T00:00:00.000Z',
updatedAt: '2024-08-01T00:00:00.000Z',
title: '[React.js] 1주차 스터디',
content: 'React.js는 뭐 어쩌고 기반이고... Virtual Dom을 사용 어쩌고...',
author: '홍길동',
image: 'https://blog.kakaocdn.net/dn/.../img.png',
link: 'https://cs-kookmin-club.tistory.com/0',
uploadedAt: '2023-01-01T00:00:00.000Z',
category: {
_id: '1a2b3c4d5e6f7a8b9c0d1e2f',
name: 'React.js',
},
},
})
study!: Study;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ export class GetCategoriesResponseDto {
@ApiProperty({
description: '카테고리 목록',
type: [Category],
example: [
{
_id: '1a2b3c4d5e6f7a8b9c0d1e2f',
name: 'React.js 스터디',
},
],
})
categories!: Category[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ApiProperty } from '@nestjs/swagger';
export class GetStudiesPageResponse {
@ApiProperty({
description: '최대 페이지',
type: Number,
example: 1,
})
page!: number;
}
17 changes: 17 additions & 0 deletions src/domain/activity/study/dto/response/get-studies.response.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@ export class GetStudiesResponse {
@ApiProperty({
description: '스터디 목록',
type: [Study],
example: [
{
_id: '1a2b3c4d5e6f7a8b9c0d1e2f',
createdAt: '2024-08-01T00:00:00.000Z',
updatedAt: '2024-08-01T00:00:00.000Z',
title: '[React.js] 1주차 스터디',
content: 'React.js는 뭐 어쩌고 기반이고... Virtual Dom을 사용 어쩌고...',
author: '홍길동',
image: 'https://blog.kakaocdn.net/dn/.../img.png',
link: 'https://cs-kookmin-club.tistory.com/0',
uploadedAt: '2023-01-01T00:00:00.000Z',
category: {
_id: '1a2b3c4d5e6f7a8b9c0d1e2f',
name: 'React.js',
},
},
],
})
studies!: Study[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { HttpStatus } from '@nestjs/common';

import { ApiException } from '@wink/swagger';

export class AlreadyExistsStudyException extends ApiException {
constructor() {
super({
swagger: '스터디가 이미 존재하는 경우',
message: '스터디가 이미 존재합니다.',
code: HttpStatus.CONFLICT,
});
}
}
2 changes: 1 addition & 1 deletion src/domain/activity/study/exception/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './already-exists-category.exception';
export * from './already-exists-study.exception';
export * from './category-not-found.exception';

export * from './study-not-found.exception';
4 changes: 0 additions & 4 deletions src/domain/activity/study/repository/category.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ export class CategoryRepository {
return this.categoryModel.find().exec();
}

async findById(id: string): Promise<Category | null> {
return this.categoryModel.findById(id).exec();
}

async findByName(name: string): Promise<Category | null> {
return this.categoryModel.findOne({ name }).exec();
}
Expand Down
8 changes: 4 additions & 4 deletions src/domain/activity/study/repository/study.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ export class StudyRepository {
.exec();
}

async findById(id: string): Promise<Study | null> {
return this.studyModel.findById(id).exec();
}

// Delete
async deleteById(id: string): Promise<void> {
await this.studyModel.deleteOne({ _id: id }).exec();
Expand All @@ -41,4 +37,8 @@ export class StudyRepository {
async existsById(id: string): Promise<boolean> {
return !!(await this.studyModel.exists({ _id: id }).exec());
}

async existsByLink(link: string): Promise<boolean> {
return !!(await this.studyModel.exists({ link }).exec());
}
}
21 changes: 11 additions & 10 deletions src/domain/activity/study/service/study.admin.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { Injectable } from '@nestjs/common';

import { Member } from '@wink/member/schema';

import {
CreateCategoryRequestDto,
CreateCategoryResponseDto,
Expand All @@ -13,6 +11,7 @@ import {
} from '@wink/activity/dto';
import {
AlreadyExistsCategoryException,
AlreadyExistsStudyException,
CategoryNotFoundException,
StudyNotFoundException,
} from '@wink/activity/exception';
Expand Down Expand Up @@ -59,34 +58,36 @@ export class StudyAdminService {
await this.categoryRepository.deleteById(categoryId);
}

async createStudy(
member: Member,
{ link }: CreateStudyRequestDto,
): Promise<CreateStudyResponseDto> {
async createStudy({ link }: CreateStudyRequestDto): Promise<CreateStudyResponseDto> {
if (await this.studyRepository.existsByLink(link)) {
throw new AlreadyExistsStudyException();
}

const { data: html } = await axios.get(link);
const $ = cheerio.load(html);

const title = $('meta[property="og:title"]').attr('content')!;
const content = $('meta[property="og:description"]').attr('content')!;
const author = $('meta[property="og.article.author"]').attr('content')!;
const image = $('meta[property="og:image"]').attr('content')!;
const uploadedAt = $('meta[property="article:published_time"]').attr('content')!;
const rawUploadedAt = $('meta[property="article:published_time"]').attr('content')!;
const uploadedAt = new Date(new Date(rawUploadedAt).getTime() + 9 * 60 * 60 * 1000);

const entryInfoMatch = html.match(/window\.T\.entryInfo\s*=\s*({[^}]*});/);
const entryInfo = entryInfoMatch ? JSON.parse(entryInfoMatch[1]) : null;
const categoryLabel = entryInfo['categoryLabel'];

const category = await this.categoryRepository.findByName(categoryLabel);

if (!category) {
throw new CategoryNotFoundException();
}

const study: Partial<Study> = {
author: member,
title,
content,
author,
image,
uploadedAt: new Date(uploadedAt),
uploadedAt,
link,
category,
};
Expand Down
88 changes: 19 additions & 69 deletions src/domain/auth/dto/response/my-info.response.dto.ts
Original file line number Diff line number Diff line change
@@ -1,78 +1,28 @@
import { ApiProperty } from '@nestjs/swagger';

import { Role, MyInfoLinks } from '@wink/member/schema';
import { Member } from '@wink/member/schema';

export class MyInfoResponseDto {
@ApiProperty({
description: '멤버 아이디',
example: '1a2b3c4d5e6f7a8b9c0d1e2f',
})
memberId!: string;

@ApiProperty({
description: '계정 생성일',
example: '2024-01-01T00:00:00.000Z',
})
createdAt!: Date;

@ApiProperty({
description: '계정 수정일',
example: '2024-01-01T00:00:00.000Z',
})
updatedAt!: Date;

@ApiProperty({
description: '이름',
example: '홍길동',
})
name!: string;

@ApiProperty({
description: '학번',
example: '20240001',
})
studentId!: string;

@ApiProperty({
description: '이메일',
example: '[email protected]',
})
email!: string;

@ApiProperty({
description: '아이콘 URL',
example:
'https://kmu-wink.s3.ap-northeast-2.amazonaws.com/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee.jpeg',
})
avatar!: string | null;

@ApiProperty({
description: '자기소개',
example: '안녕하세요',
})
description!: string | null;

@ApiProperty({
description: '링크',
type: Object,
description: '사용자',
example: {
github: 'https://github.com/hongildong',
instagram: 'https://www.instagram.com/hongildong/',
blog: 'https://hongildong.tistory.com/',
_id: '60f6b5c3f5d0e7b2c2a3c2b0',
createdAt: '2021-07-20T07:47:07.000Z',
updatedAt: '2021-07-20T07:47:07.000Z',
name: '홍길동',
studentId: '20240001',
email: '[email protected]',
avatar:
'https://kmu-wink.s3.ap-northeast-2.amazonaws.com/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee.jpeg',
description: '안녕하세요',
link: {
github: 'https://github.com/hongildong',
instagram: 'https://www.instagram.com/hongildong/',
blog: 'https://hongildong.tistory.com/',
},
role: 'MEMBER',
fee: true,
},
})
link!: MyInfoLinks;

@ApiProperty({
description: '역할',
enum: Role,
example: Role.MEMBER,
})
role!: Role | null;

@ApiProperty({
description: '회비 납부 여부',
example: true,
})
fee!: boolean;
member!: Member;
}
Loading

0 comments on commit ecc9320

Please sign in to comment.