From 79b17937ce97e92aa5573a3eddfe0329114b9ad9 Mon Sep 17 00:00:00 2001 From: NaayoungKwon Date: Tue, 15 Nov 2022 11:55:11 +0900 Subject: [PATCH 1/3] =?UTF-8?q?refactor:=20user=20repo=20create=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20#9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/apps/api/src/main.ts | 2 -- server/dao/repository/user.repository.ts | 4 +--- server/dao/schemas/channel.schema.ts | 4 ++-- server/dao/schemas/chat.schema.ts | 2 +- server/dao/schemas/user.schema.ts | 4 ++-- server/tsconfig.json | 1 + server/{dao/schemas/type.ts => utils/def.ts} | 2 +- 7 files changed, 8 insertions(+), 11 deletions(-) rename server/{dao/schemas/type.ts => utils/def.ts} (65%) diff --git a/server/apps/api/src/main.ts b/server/apps/api/src/main.ts index 2801d0e3..4736c81f 100644 --- a/server/apps/api/src/main.ts +++ b/server/apps/api/src/main.ts @@ -1,10 +1,8 @@ import { NestFactory } from '@nestjs/core'; import { ApiModule } from './api.module'; -import * as dotenv from 'dotenv'; async function bootstrap() { const app = await NestFactory.create(ApiModule); await app.listen(3000); - console.log(dotenv); } bootstrap(); diff --git a/server/dao/repository/user.repository.ts b/server/dao/repository/user.repository.ts index 7b0bfff4..983d1984 100644 --- a/server/dao/repository/user.repository.ts +++ b/server/dao/repository/user.repository.ts @@ -9,9 +9,7 @@ export class UsersRepository { constructor(@InjectModel(User.name) private userModel: Model) {} async create(createUserDto: CreateUserDto) { - const createdUser = new this.userModel(createUserDto); - await createdUser.save(); - console.log(this.userModel.find()); + await this.userModel.create(createUserDto); return null; } } diff --git a/server/dao/schemas/channel.schema.ts b/server/dao/schemas/channel.schema.ts index c8be6c1d..605b3d0d 100644 --- a/server/dao/schemas/channel.schema.ts +++ b/server/dao/schemas/channel.schema.ts @@ -1,7 +1,7 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Document } from 'mongoose'; -import { CHANNEL_TYPE } from './type'; -import { IsBoolean, IsIn, IsNotEmpty, IsString} from 'class-validator'; +import { CHANNEL_TYPE } from '@utils/def'; +import { IsBoolean, IsIn, IsNotEmpty, IsString } from 'class-validator'; export type ChannelDocument = Channel & Document; diff --git a/server/dao/schemas/chat.schema.ts b/server/dao/schemas/chat.schema.ts index 8f61fc74..9af4d828 100644 --- a/server/dao/schemas/chat.schema.ts +++ b/server/dao/schemas/chat.schema.ts @@ -1,6 +1,6 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import mongoose, { Document } from 'mongoose'; -import { CHAT_TYPE } from './type'; +import { CHAT_TYPE } from '@utils/def'; import { IsIn, IsString } from 'class-validator'; export type UserDocument = Chat & Document; diff --git a/server/dao/schemas/user.schema.ts b/server/dao/schemas/user.schema.ts index 2d8d2f66..1ef981cb 100644 --- a/server/dao/schemas/user.schema.ts +++ b/server/dao/schemas/user.schema.ts @@ -1,7 +1,7 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { IsIn, IsString } from 'class-validator'; import mongoose, { Document } from 'mongoose'; -import { STATUS } from './type'; +import { STATUS } from '@utils/def'; export type UserDocument = User & Document; @@ -43,7 +43,7 @@ export class User { @Prop({ default: 'ONLINE' }) @IsString() - @IsIn(Object.keys(STATUS)) + @IsIn(STATUS) status: string; @Prop({ default: new Date(), type: mongoose.Schema.Types.Date }) diff --git a/server/tsconfig.json b/server/tsconfig.json index 5b2659e3..658f902d 100644 --- a/server/tsconfig.json +++ b/server/tsconfig.json @@ -20,6 +20,7 @@ "paths": { "@schemas/*": ["dao/schemas/*"], "@repository/*": ["dao/repository/*"], + "@utils/*": ["utils/*"], "@user/*": ["apps/api/src/user/*"], } } diff --git a/server/dao/schemas/type.ts b/server/utils/def.ts similarity index 65% rename from server/dao/schemas/type.ts rename to server/utils/def.ts index cb515c80..5b0f48d1 100644 --- a/server/dao/schemas/type.ts +++ b/server/utils/def.ts @@ -1,4 +1,4 @@ -export const STATUS = { ONLINE : 0, OFFLINE : 1, CUSTOM_OFFLINE : 2}; +export const STATUS = ['ONLINE', 'OFFLINE', 'CUSTOM_OFFLINE']; export const PROVIDER = ['LOCAL', 'GITHUB']; export const CHANNEL_TYPE = ['CHANNEL', 'DM']; export const CHAT_TYPE = ['TEXT', 'IMAGE']; \ No newline at end of file From c39586db48bb2c5f1aadee88ddedf8709c2b65a2 Mon Sep 17 00:00:00 2001 From: NaayoungKwon Date: Tue, 15 Nov 2022 14:03:38 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=ED=8C=94=EB=A1=9C=EC=9A=B0=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EC=B2=98=EB=A6=AC=20#20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/apps/api/src/api.controller.ts | 2 +- .../api/src/user/dto/add-following.dto.ts | 9 ++++++ server/apps/api/src/user/user.controller.ts | 20 +++++++----- server/apps/api/src/user/user.service.ts | 6 ++++ server/dao/repository/user.repository.ts | 31 ++++++++++++++++++- server/utils/def.ts | 13 +++++++- 6 files changed, 71 insertions(+), 10 deletions(-) create mode 100644 server/apps/api/src/user/dto/add-following.dto.ts diff --git a/server/apps/api/src/api.controller.ts b/server/apps/api/src/api.controller.ts index a2231cbb..5957b397 100644 --- a/server/apps/api/src/api.controller.ts +++ b/server/apps/api/src/api.controller.ts @@ -1,7 +1,7 @@ import { Controller, Get } from '@nestjs/common'; import { ApiService } from './api.service'; -@Controller() +@Controller('api') export class ApiController { constructor(private readonly apiService: ApiService) {} diff --git a/server/apps/api/src/user/dto/add-following.dto.ts b/server/apps/api/src/user/dto/add-following.dto.ts new file mode 100644 index 00000000..69e0cc8b --- /dev/null +++ b/server/apps/api/src/user/dto/add-following.dto.ts @@ -0,0 +1,9 @@ +import { IsString } from 'class-validator'; + +export class AddFollowingDto { + @IsString() + myId: string; + + @IsString() + followId: string; +} diff --git a/server/apps/api/src/user/user.controller.ts b/server/apps/api/src/user/user.controller.ts index d1f28077..6f26f003 100644 --- a/server/apps/api/src/user/user.controller.ts +++ b/server/apps/api/src/user/user.controller.ts @@ -1,22 +1,28 @@ import { Body, Controller, Get, Param, Post } from '@nestjs/common'; -import { User } from '../../../../dao/schemas/user.schema'; +import { User } from '@schemas/user.schema'; import { UserService } from './user.service'; import { CreateUserDto } from './dto/create-user.dto'; +import { AddFollowingDto } from '@user/dto/add-following.dto'; +import { SucessRes } from '@utils/def'; -@Controller('user') +@Controller('api/user') export class UserController { constructor(private usersService: UserService) {} @Get() getUsers() { - const createUserDto: CreateUserDto = { id: 'ny', pw: 'nypw' }; + const createUserDto: CreateUserDto = { id: 'mj', pw: 'mjpw' }; this.usersService.createUser(createUserDto); return 'hello user'; } - // @Get('followers/:id') - // getFollowers(@Param('id') id: string): User[] { - // return this.usersService.getAllFollowers(); - // } + + @Post('following/:id') + getFollower(@Param('id') id: string) { + const myId = '6372fcf4cf6f605428fe45df'; + const addFollowingDto: AddFollowingDto = { myId, followId: id }; + this.usersService.addFollowing(addFollowingDto); + return SucessRes; + } // @Post() // createUser(@Body() createUserDto: CreateUserDto) { diff --git a/server/apps/api/src/user/user.service.ts b/server/apps/api/src/user/user.service.ts index 3ee0521f..835ef062 100644 --- a/server/apps/api/src/user/user.service.ts +++ b/server/apps/api/src/user/user.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; import { UsersRepository } from '@repository/user.repository'; +import {AddFollowingDto} from "@user/dto/add-following.dto"; @Injectable() export class UserService { @@ -11,4 +12,9 @@ export class UserService { createUser(createUserDto: CreateUserDto) { this.userRepository.create(createUserDto); } + + addFollowing(addFollowingDto: AddFollowingDto) { + this.userRepository.appendFollowing(addFollowingDto); + this.userRepository.appendFollwer(addFollowingDto); + } } diff --git a/server/dao/repository/user.repository.ts b/server/dao/repository/user.repository.ts index 983d1984..417322bc 100644 --- a/server/dao/repository/user.repository.ts +++ b/server/dao/repository/user.repository.ts @@ -1,8 +1,9 @@ import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { User, UserDocument } from '@schemas/user.schema'; -import { Model } from 'mongoose'; +import mongoose, { Model, Schema } from 'mongoose'; import { CreateUserDto } from '@user/dto/create-user.dto'; +import { AddFollowingDto } from '@user/dto/add-following.dto'; @Injectable() export class UsersRepository { @@ -12,4 +13,32 @@ export class UsersRepository { await this.userModel.create(createUserDto); return null; } + + async findById(id: string) { + return await this.userModel.findById(id); + } + + appendFollowing(addFollowingDto: AddFollowingDto) { + this.userModel.updateOne( + { _id: addFollowingDto.myId }, + { + $push: { followings: addFollowingDto.followId }, + }, + (err, res) => { + if (err) throw err; + }, + ); + } + + appendFollwer(addFollowingDto: AddFollowingDto) { + this.userModel.updateOne( + { _id: addFollowingDto.followId }, + { + $push: { followers: addFollowingDto.myId }, + }, + (err, res) => { + if (err) throw err; + }, + ); + } } diff --git a/server/utils/def.ts b/server/utils/def.ts index 5b0f48d1..564ee975 100644 --- a/server/utils/def.ts +++ b/server/utils/def.ts @@ -1,4 +1,15 @@ export const STATUS = ['ONLINE', 'OFFLINE', 'CUSTOM_OFFLINE']; export const PROVIDER = ['LOCAL', 'GITHUB']; export const CHANNEL_TYPE = ['CHANNEL', 'DM']; -export const CHAT_TYPE = ['TEXT', 'IMAGE']; \ No newline at end of file +export const CHAT_TYPE = ['TEXT', 'IMAGE']; + +export const SucessRes = { + statusCode: 200, + result: {}, +}; + +export const FailRes = { + statusCode: 200, + error: '', + messages: [], +}; From 4d56aa464680cb92ad6084478c172d31320a1e5e Mon Sep 17 00:00:00 2001 From: NaayoungKwon Date: Tue, 15 Nov 2022 18:04:17 +0900 Subject: [PATCH 3/3] =?UTF-8?q?refactor:=20=ED=8C=94=EB=A1=9C=EC=9A=B0=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20error=20handling=20#20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/.prettierrc | 6 ++++- server/apps/api/src/api.module.ts | 15 ++++++++++++ server/apps/api/src/main.ts | 2 ++ server/apps/api/src/user/user.controller.ts | 27 ++++++++++++++------- server/apps/api/src/user/user.module.ts | 10 +++----- server/apps/api/src/user/user.service.ts | 19 +++++++++++---- server/dao/repository/user.repository.ts | 6 ++--- server/package.json | 6 +++-- 8 files changed, 64 insertions(+), 27 deletions(-) diff --git a/server/.prettierrc b/server/.prettierrc index dcb72794..a75ce2da 100644 --- a/server/.prettierrc +++ b/server/.prettierrc @@ -1,4 +1,8 @@ { + "endOfLine": "lf", + "tabWidth": 2, + "semi": true, "singleQuote": true, - "trailingComma": "all" + "trailingComma": "all", + "printWidth": 100 } \ No newline at end of file diff --git a/server/apps/api/src/api.module.ts b/server/apps/api/src/api.module.ts index ca7e8fa4..b14c4e3e 100644 --- a/server/apps/api/src/api.module.ts +++ b/server/apps/api/src/api.module.ts @@ -6,6 +6,8 @@ import { ConfigModule } from '@nestjs/config'; import { ChannelModule } from './channel/channel.module'; import { CommunityModule } from './community/community.module'; import { UserModule } from './user/user.module'; +import * as winston from 'winston'; +import { utilities as nestWinstonModuleUtilities, WinstonModule } from 'nest-winston'; @Module({ imports: [ @@ -14,6 +16,19 @@ import { UserModule } from './user/user.module'; envFilePath: `config/${process.env.NODE_ENV}.env`, }), MongooseModule.forRoot(process.env.MONGODB_URL), + WinstonModule.forRoot({ + transports: [ + new winston.transports.Console({ + level: process.env.NODE_ENV === 'production' ? 'info' : 'silly', + format: winston.format.combine( + winston.format.colorize({ all: true }), + winston.format.simple(), + winston.format.timestamp(), + nestWinstonModuleUtilities.format.nestLike('Asnity', { prettyPrint: true }), + ), + }), + ], + }), UserModule, ChannelModule, CommunityModule, diff --git a/server/apps/api/src/main.ts b/server/apps/api/src/main.ts index 4736c81f..b985730d 100644 --- a/server/apps/api/src/main.ts +++ b/server/apps/api/src/main.ts @@ -1,8 +1,10 @@ import { NestFactory } from '@nestjs/core'; +import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston'; import { ApiModule } from './api.module'; async function bootstrap() { const app = await NestFactory.create(ApiModule); + app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER)); await app.listen(3000); } bootstrap(); diff --git a/server/apps/api/src/user/user.controller.ts b/server/apps/api/src/user/user.controller.ts index 6f26f003..d2d1668e 100644 --- a/server/apps/api/src/user/user.controller.ts +++ b/server/apps/api/src/user/user.controller.ts @@ -1,27 +1,36 @@ -import { Body, Controller, Get, Param, Post } from '@nestjs/common'; -import { User } from '@schemas/user.schema'; +import { Body, Controller, Get, Inject, LoggerService, Param, Post } from '@nestjs/common'; import { UserService } from './user.service'; import { CreateUserDto } from './dto/create-user.dto'; import { AddFollowingDto } from '@user/dto/add-following.dto'; import { SucessRes } from '@utils/def'; +import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston'; @Controller('api/user') export class UserController { - constructor(private usersService: UserService) {} + constructor( + @Inject(WINSTON_MODULE_NEST_PROVIDER) private readonly logger: LoggerService, + private userService: UserService, + ) {} @Get() getUsers() { const createUserDto: CreateUserDto = { id: 'mj', pw: 'mjpw' }; - this.usersService.createUser(createUserDto); + this.userService.createUser(createUserDto); return 'hello user'; } @Post('following/:id') - getFollower(@Param('id') id: string) { - const myId = '6372fcf4cf6f605428fe45df'; - const addFollowingDto: AddFollowingDto = { myId, followId: id }; - this.usersService.addFollowing(addFollowingDto); - return SucessRes; + async addFollowing(@Param('id') id: string) { + try { + const myId = '63734e98384f478a32c3a1cc'; + // TODO: Request Header에서 access token으로 현재 사용자 알아내기 + const addFollowingDto: AddFollowingDto = { myId, followId: id }; + await this.userService.addFollowing(addFollowingDto); + return SucessRes; + } catch (error) { + this.logger.error(JSON.stringify(error.response)); + return error.response; + } } // @Post() diff --git a/server/apps/api/src/user/user.module.ts b/server/apps/api/src/user/user.module.ts index 78f2b2f0..b1dd8c72 100644 --- a/server/apps/api/src/user/user.module.ts +++ b/server/apps/api/src/user/user.module.ts @@ -4,14 +4,12 @@ import { UserService } from './user.service'; import { MongooseModule } from '@nestjs/mongoose'; import { User, UserSchema } from '../../../../dao/schemas/user.schema'; import { AuthModule } from './auth/auth.module'; -import { UsersRepository } from '@repository/user.repository'; +import { UserRepository } from '@repository/user.repository'; +import { WinstonModule } from 'nest-winston'; @Module({ - imports: [ - MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]), - AuthModule, - ], + imports: [MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]), AuthModule], controllers: [UserController], - providers: [UserService, UsersRepository], + providers: [UserService, UserRepository], }) export class UserModule {} diff --git a/server/apps/api/src/user/user.service.ts b/server/apps/api/src/user/user.service.ts index 835ef062..d8101da8 100644 --- a/server/apps/api/src/user/user.service.ts +++ b/server/apps/api/src/user/user.service.ts @@ -1,11 +1,11 @@ -import { Injectable } from '@nestjs/common'; +import { BadRequestException, ConflictException, Injectable } from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; -import { UsersRepository } from '@repository/user.repository'; -import {AddFollowingDto} from "@user/dto/add-following.dto"; +import { UserRepository } from '@repository/user.repository'; +import { AddFollowingDto } from '@user/dto/add-following.dto'; @Injectable() export class UserService { - constructor(private readonly userRepository: UsersRepository) {} + constructor(private readonly userRepository: UserRepository) {} // getAllFollowers() {} @@ -13,7 +13,16 @@ export class UserService { this.userRepository.create(createUserDto); } - addFollowing(addFollowingDto: AddFollowingDto) { + async addFollowing(addFollowingDto: AddFollowingDto) { + const user = await this.userRepository.findById(addFollowingDto.myId); + const otherUser = await this.userRepository.findById(addFollowingDto.followId); + if (!user || !otherUser) { + throw new BadRequestException('해당하는 사용자의 _id가 올바르지 않습니다.'); + } else if (user.followings.includes(addFollowingDto.followId)) { + throw new BadRequestException('팔로우 요청한 사용자는 이미 팔로우되어있습니다.'); + } else if (otherUser.followers.includes(addFollowingDto.myId)) { + throw new ConflictException('상대방의 팔로워 목록에 이미 있습니다.'); + } this.userRepository.appendFollowing(addFollowingDto); this.userRepository.appendFollwer(addFollowingDto); } diff --git a/server/dao/repository/user.repository.ts b/server/dao/repository/user.repository.ts index 417322bc..4bba441f 100644 --- a/server/dao/repository/user.repository.ts +++ b/server/dao/repository/user.repository.ts @@ -6,7 +6,7 @@ import { CreateUserDto } from '@user/dto/create-user.dto'; import { AddFollowingDto } from '@user/dto/add-following.dto'; @Injectable() -export class UsersRepository { +export class UserRepository { constructor(@InjectModel(User.name) private userModel: Model) {} async create(createUserDto: CreateUserDto) { @@ -21,9 +21,7 @@ export class UsersRepository { appendFollowing(addFollowingDto: AddFollowingDto) { this.userModel.updateOne( { _id: addFollowingDto.myId }, - { - $push: { followings: addFollowingDto.followId }, - }, + { $push: { followings: addFollowingDto.followId } }, (err, res) => { if (err) throw err; }, diff --git a/server/package.json b/server/package.json index 9cd1ff1c..c64b8785 100644 --- a/server/package.json +++ b/server/package.json @@ -50,6 +50,7 @@ "eslint-plugin-prettier": "^4.0.0", "jest": "28.1.3", "mongoose": "^6.7.2", + "nest-winston": "^1.8.0", "prettier": "^2.3.2", "source-map-support": "^0.5.20", "supertest": "^6.1.3", @@ -57,7 +58,8 @@ "ts-loader": "^9.2.3", "ts-node": "^10.0.0", "tsconfig-paths": "4.1.0", - "typescript": "^4.7.4" + "typescript": "^4.7.4", + "winston": "^3.8.2" }, "jest": { "moduleFileExtensions": [ @@ -79,4 +81,4 @@ "/apps/" ] } -} \ No newline at end of file +}