diff --git a/public/.DS_Store b/public/.DS_Store deleted file mode 100644 index 59fa5ad..0000000 Binary files a/public/.DS_Store and /dev/null differ diff --git a/public/css/styles.css b/public/css/styles.css deleted file mode 100644 index 51e9c96..0000000 --- a/public/css/styles.css +++ /dev/null @@ -1,7 +0,0 @@ -body { - background-color: black; -} - -.bg_nest_color { - background-color: rgb(217, 19, 70); -} diff --git a/public/js/scripts.js b/public/js/scripts.js deleted file mode 100644 index 9511601..0000000 --- a/public/js/scripts.js +++ /dev/null @@ -1,64 +0,0 @@ -const socket = io('/chat'); -const getElementById = (id) => document.getElementById(id) || null; - -const helloUserElement = getElementById('hello_user'); -const chattingBoxElement = getElementById('chatting_box'); -const formElement = getElementById('chat_form'); - -socket.on('user_connected', (nickname) => { - drawNewChat(`${nickname} connected`); -}); - -socket.on('new_chat', (data) => { - const { chat, nickname } = data; - drawNewChat(`${nickname}:${chat}`); -}); - -socket.on('disconnect_user', (nickname) => drawNewChat(`${nickname}:bye..`)); - -const handlesSubmit = (event) => { - event.preventDefault(); - const inputValue = event.target.elements[0].value; - if (inputValue !== '') { - socket.emit('submit_chat', inputValue); - drawNewChat(`me: ${inputValue}`, true); - event.target.elements[0].value = ''; - } -}; - -const drawHelloStranger = (nickname) => { - helloUserElement.innerText = `Hello ${nickname} :)`; -}; - -const drawNewChat = (message, isMe = false) => { - const wrapperChatBox = document.createElement('div'); - let chatBox; - if (!isMe) - chatBox = ` -
- ${message} -
- `; - else - chatBox = ` -
- ${message} -
- `; - wrapperChatBox.innerHTML = chatBox; - chattingBoxElement.append(wrapperChatBox); -}; - -function helloUser() { - const phoneNumber = prompt(`What is your nickname`); - socket.emit('find_user', nickname, (data) => { - drawHelloStranger(data); - }); -} - -function init() { - helloUser(); - formElement.addEventListener('submit', handlesSubmit); -} - -init(); diff --git a/src/apis/letter/letter.controller.ts b/src/apis/letter/letter.controller.ts index 4899b0b..75ff90f 100644 --- a/src/apis/letter/letter.controller.ts +++ b/src/apis/letter/letter.controller.ts @@ -42,10 +42,9 @@ import { SuccessInterceptor } from 'src/common/interceptors/sucess.interceptor'; @Controller('letters') @ApiBearerAuth('accessToken') @UseGuards(JwtAuthGuard) -@UseInterceptors(SuccessInterceptor) export class LetterController { constructor(private readonly letterService: LetterService) {} - @UseInterceptors(ClassSerializerInterceptor) + @ApiOperation({ summary: '편지를 상대방에게 보낼 수 있음' }) @ApiResponse({ status: 201, @@ -65,6 +64,7 @@ export class LetterController { ); } + // 시리얼라이징 적용 필요 @ApiOperation({ summary: '상대방과 편지를 한걸 모아볼수있음' }) @ApiResponse({ status: 200, @@ -82,7 +82,6 @@ export class LetterController { ); } - @UseInterceptors(ClassSerializerInterceptor) @ApiOperation({ summary: '쪽지탭용' }) @ApiResponse({ status: 200, @@ -97,7 +96,7 @@ export class LetterController { console.log(instanceToPlain(list[0])); return list; } - @UseInterceptors(ClassSerializerInterceptor) + @ApiOperation({ summary: '쪽지룸을 떠남' }) @ApiResponse({ status: 200, diff --git a/src/apis/questions/dto/QuestionList.res.dto.ts b/src/apis/questions/dto/QuestionList.res.dto.ts new file mode 100644 index 0000000..904f85b --- /dev/null +++ b/src/apis/questions/dto/QuestionList.res.dto.ts @@ -0,0 +1,51 @@ +import { ApiProperty, PickType } from '@nestjs/swagger'; +import { Comment, Question } from 'src/models/question.model'; +import { Types } from 'mongoose'; +import { Exclude, Expose } from 'class-transformer'; +export class QuestionListShowDto extends PickType(Question, [ + '_id', + 'user', + 'content', + 'commentList', + 'likes', + 'createdAt', + 'myUserId', +] as const) { + @Expose({ toClassOnly: true }) + @Exclude({ toPlainOnly: true }) + commentList: Comment[]; + + @ApiProperty({ + description: '좋아요 갯수', + type: Number, + }) + @Expose() + get likesCount(): number { + return this.likes.length; + } + + @ApiProperty({ + description: '댓글갯수', + type: Number, + }) + @Expose() + get commentsCount(): number { + return this.commentList.length; + } + + @ApiProperty({ + description: '내가 좋아요 눌렀는지', + type: Boolean, + }) + @Expose({ name: 'ilike' }) + get ilike(): boolean { + if ( + this.likes.find((user) => { + return user._id.equals(this.myUserId); + }) + ) + return true; + + return false; + } +} diff --git a/src/apis/questions/questions.controller.ts b/src/apis/questions/questions.controller.ts index bc6a6d7..f91f53a 100644 --- a/src/apis/questions/questions.controller.ts +++ b/src/apis/questions/questions.controller.ts @@ -31,14 +31,13 @@ import { User } from 'src/models/user.model'; import { CommentStringDto } from './dto/CommentString.dto'; import { IlikeResDto } from './dto/Ilike.res.dto'; import { QuestionShowDto } from './dto/Question.res.dto'; +import { QuestionListShowDto } from './dto/QuestionList.res.dto'; import { QuestionFindRequestDto } from './dto/QuestionsList.req.dto'; import { QuestionsService } from './questions.service'; @ApiTags('questions') @Controller('questions') @ApiBearerAuth('accessToken') -@UseInterceptors(ClassSerializerInterceptor) -@UseInterceptors(SuccessInterceptor) @UseGuards(JwtAuthGuard) export class QuestionsController { constructor(private readonly questionService: QuestionsService) {} @@ -48,8 +47,9 @@ export class QuestionsController { }) @ApiResponse({ status: 200, - description: '요청 성공시', - type: [QuestionShowDto], + description: + '요청 성공시 , 코멘트 갯수만 반환합니다 밑에 QuestionShow는 디테일 인포 용입니당!', + type: [QuestionListShowDto], }) @Get() findQuestions( diff --git a/src/apis/questions/questions.service.ts b/src/apis/questions/questions.service.ts index bf3de2b..2152282 100644 --- a/src/apis/questions/questions.service.ts +++ b/src/apis/questions/questions.service.ts @@ -12,6 +12,7 @@ import { UserRepository } from 'src/repositories/user.repository'; import { CommentStringDto } from './dto/CommentString.dto'; import { IlikeResDto } from './dto/Ilike.res.dto'; import { QuestionShowDto } from './dto/Question.res.dto'; +import { QuestionListShowDto } from './dto/QuestionList.res.dto'; import { QuestionFindRequestDto } from './dto/QuestionsList.req.dto'; @Injectable() @@ -30,11 +31,11 @@ export class QuestionsService { return new RoomIdDto(user.myRoom._id); } - @returnValueToDto(QuestionShowDto) + @returnValueToDto(QuestionListShowDto) async findQuestions( userIdDto: UserIdDto, questionFindRequestDto: QuestionFindRequestDto, - ): Promise { + ): Promise { // 내 아이디 정보를 넣어서 비교로직 추가가 필요함. const myRoomIdDto = await this.checkMyRoom(userIdDto); let result = []; diff --git a/src/apis/rooms/dto/find-room.res.dto copy.ts b/src/apis/rooms/dto/find-room.res.dto copy.ts index 7ed38ac..a6befa2 100644 --- a/src/apis/rooms/dto/find-room.res.dto copy.ts +++ b/src/apis/rooms/dto/find-room.res.dto copy.ts @@ -1,50 +1,40 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { Types } from 'mongoose'; -import { CATEGORY_TYPE } from 'src/common/consts/enum'; +import { ApiProperty, PickType } from '@nestjs/swagger'; +import { Exclude, Expose } from 'class-transformer'; +import { UserProfileDto } from 'src/common/dtos/UserProfile.dto'; import { Room } from 'src/models/room.model'; -export class ResFindRoomDto { - constructor(room: Room, iFavorite: boolean, iJoin: boolean) { - this._id = room._id; - this.category = room.category; - this.name = room.name; - this.radius = room.radius; - this.lat = room.geometry.coordinates[0]; - this.lng = room.geometry.coordinates[1]; - this.userCount = room.userCount; - this.distance = room.distance; - this.iFavorite = iFavorite; - this.iJoin = iJoin; - } - @ApiProperty() - _id: string; - - @ApiProperty({ description: '채팅방 이름' }) - name: string; - - @ApiProperty({ description: '반경정보' }) - radius: number; - - @ApiProperty({ enum: CATEGORY_TYPE, description: '카테고리정보' }) - category: CATEGORY_TYPE; - - @ApiProperty() - lat: number; - - @ApiProperty() - lng: number; - - @ApiProperty({ description: '채팅방내 유저숫자' }) - userCount: number; - - @ApiProperty({ description: '거리정보' }) - distance: number; - - @ApiProperty({ description: '내가 즐겨찾기 했는지' }) +export class ResFindRoomDto extends PickType(Room, [ + '_id', + 'name', + 'category', + 'radius', + 'userList', + 'geometry', + 'userCount', +] as const) { + @Expose({ toClassOnly: true }) + @Exclude({ toPlainOnly: true }) + userList: UserProfileDto[]; + + @ApiProperty({ description: '내가 즐겨찾기 했는지', type: Boolean }) + @Expose() iFavorite: boolean; - @ApiProperty({ description: '내가 들어가 있는지' }) + @ApiProperty({ description: '내가 들어가 있는지', type: Boolean }) + @Expose() iJoin: boolean; + + @ApiProperty({ description: '위도 가로선', type: Number }) + @Expose() + get lat(): number { + return this.geometry.coordinates[0]; + } + + @ApiProperty({ description: '경도 세로선', type: Number }) + @Expose() + get lng(): number { + return this.geometry.coordinates[1]; + } } // console.log(plainToClass(User, fromPlainUser, { excludeExtraneousValues: true })); // '_id', diff --git a/src/apis/rooms/dto/findOne-room.res.dto.ts b/src/apis/rooms/dto/findOne-room.res.dto.ts index e3d91fe..57c4a74 100644 --- a/src/apis/rooms/dto/findOne-room.res.dto.ts +++ b/src/apis/rooms/dto/findOne-room.res.dto.ts @@ -1,98 +1,91 @@ +import { Room } from 'src/models/room.model'; import { ApiProperty, PickType } from '@nestjs/swagger'; -import { Expose, plainToClass, plainToInstance } from 'class-transformer'; -import { Types } from 'mongoose'; -import { CATEGORY_TYPE } from 'src/common/consts/enum'; +import { Expose, Transform } from 'class-transformer'; + +export class ResFindOneRoomDto extends PickType(Room, [ + '_id', + 'name', + 'category', + 'radius', + 'userList', + 'geometry', + 'userCount', +] as const) { + @ApiProperty({ description: '내가 즐겨찾기 했는지', type: Boolean }) + @Expose() + iFavorite: boolean; + + @ApiProperty({ description: '내가 들어가 있는지', type: Boolean }) + @Expose() + iJoin: boolean; -import { UserProfileDto } from 'src/common/dtos/UserProfile.dto'; -import { Room } from 'src/models/room.model'; + @ApiProperty({ description: '위도 가로선', type: Number }) + @Expose() + get lat(): number { + return this.geometry.coordinates[0]; + } -export class ResFindOneRoomDto { - constructor(room: Room, iFavoriteRoom: boolean, iAlarm: boolean) { - this._id = room._id; - this.category = room.category; - this.name = room.name; - this.radius = room.radius; - this.lat = room.geometry.coordinates[0]; - this.lng = room.geometry.coordinates[1]; - this.iFavoriteRoom = iFavoriteRoom; - this.iAlarm = iAlarm; - this.userCount = room.userList.length; - this.userList = room.userList; + @ApiProperty({ description: '경도 세로선', type: Number }) + @Expose() + get lng(): number { + return this.geometry.coordinates[1]; } - @ApiProperty() - _id: string; - @ApiProperty() - name: string; + @ApiProperty({ description: '내가 채팅방 알림 켰는지여부' }) + @Expose() + iAlarm: boolean; + + @ApiProperty({ description: '유저명수' }) + @Transform((value) => value.obj.userList.length, { toPlainOnly: true }) + @Expose() + userCount: number; + // get userCount(): number { + // return 0; + // } +} +// export class ResFindOneRoomDto { +// constructor(room: Room, iFavoriteRoom: boolean, iAlarm: boolean) { +// this._id = room._id; +// this.category = room.category; +// this.name = room.name; +// this.radius = room.radius; +// this.lat = room.geometry.coordinates[0]; +// this.lng = room.geometry.coordinates[1]; +// this.iFavoriteRoom = iFavoriteRoom; +// this.iAlarm = iAlarm; +// this.userCount = room.userList.length; +// this.userList = room.userList; +// } +// @ApiProperty() +// _id: string; - @ApiProperty() - radius: number; +// @ApiProperty() +// name: string; - @ApiProperty({ enum: CATEGORY_TYPE }) - category: CATEGORY_TYPE; +// @ApiProperty() +// radius: number; - @ApiProperty() - lat: number; +// @ApiProperty({ enum: CATEGORY_TYPE }) +// category: CATEGORY_TYPE; - @ApiProperty() - lng: number; +// @ApiProperty() +// lat: number; - @ApiProperty({ type: [UserProfileDto], required: false }) - userList: UserProfileDto[]; +// @ApiProperty() +// lng: number; - @ApiProperty({ description: '유저 숫자' }) - userCount: number; +// @ApiProperty({ type: [UserProfileDto], required: false }) +// userList: UserProfileDto[]; - @ApiProperty({ description: '내가 즐겨찾기 했는지' }) - iFavoriteRoom: boolean; +// @ApiProperty({ description: '유저 숫자' }) +// userCount: number; - @ApiProperty({ description: '내가 들어가 있는지' }) - iJoin: boolean; +// @ApiProperty({ description: '내가 즐겨찾기 했는지' }) +// iFavoriteRoom: boolean; - @ApiProperty({ description: '내가 채팅방 알림 켰는지여부' }) - iAlarm: boolean; -} +// @ApiProperty({ description: '내가 들어가 있는지' }) +// iJoin: boolean; -// '_id', -// 'name', -// 'radius', -// 'category', - -// export class UserShowDto { -// // (1) -// @Exclude() private readonly _id: number; -// @Exclude() private readonly _firstName: string; -// @Exclude() private readonly _lastName: string; -// @Exclude() private readonly _orderDateTime: LocalDateTime; - -// constructor(user: User) { -// this._id = user.id; -// this._firstName = user.firstName; -// this._lastName = user.lastName; -// this._orderDateTime = user.orderDateTime.plusDays(1); // (2) -// } - -// @ApiProperty() -// @Expose() // (3) -// get id(): number { -// return this._id; -// } - -// @ApiProperty() -// @Expose() -// get firstName(): string { -// return this._firstName; -// } - -// @ApiProperty() -// @Expose() -// get lastName(): string { -// return this._lastName; -// } - -// @ApiProperty() -// @Expose() -// get orderDateTime(): string { -// return DateTimeUtil.toString(this._orderDateTime); // (4) -// } -// } +// @ApiProperty({ description: '내가 채팅방 알림 켰는지여부' }) +// iAlarm: boolean; +// } diff --git a/src/apis/rooms/dto/leftRoomResult.res.dto.ts b/src/apis/rooms/dto/leftRoomResult.res.dto.ts new file mode 100644 index 0000000..2674ee7 --- /dev/null +++ b/src/apis/rooms/dto/leftRoomResult.res.dto.ts @@ -0,0 +1,11 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Expose } from 'class-transformer'; + +export class LeftRoomResultResDto { + @ApiProperty({ + example: true, + description: '방떠난거 성공여부', + }) + @Expose() + leftSuccess: boolean; +} diff --git a/src/apis/rooms/rooms.controller.ts b/src/apis/rooms/rooms.controller.ts index 68fbe04..bfbf0e2 100644 --- a/src/apis/rooms/rooms.controller.ts +++ b/src/apis/rooms/rooms.controller.ts @@ -11,6 +11,7 @@ import { SerializeOptions, UseGuards, UseInterceptors, + ClassSerializerInterceptor, } from '@nestjs/common'; import { RoomsService } from './rooms.service'; import { CreateRoomDto } from './dto/create-room.dto'; @@ -40,13 +41,12 @@ import { SuccessInterceptor } from 'src/common/interceptors/sucess.interceptor'; import { ResChatAlarmToggleDto } from './dto/chatAlarmToggle.res.dto'; import { ResFavoriteToggleDto } from './dto/FavoriteToggle.res.dto'; import { Room } from 'src/models/room.model'; -import { ResShortCutRoomDto } from '../../common/dtos/shortCutRoomInfo.res.dto'; +import { ResShortCutRoomDto } from 'src/common/dtos/shortCutRoomInfo.res.dto'; @ApiTags('rooms') @Controller('rooms') @ApiBearerAuth('accessToken') @UseGuards(JwtAuthGuard) -@UseInterceptors(SuccessInterceptor) export class RoomsController { constructor(private readonly roomsService: RoomsService) {} diff --git a/src/apis/rooms/rooms.service.ts b/src/apis/rooms/rooms.service.ts index 5a38c99..694459b 100644 --- a/src/apis/rooms/rooms.service.ts +++ b/src/apis/rooms/rooms.service.ts @@ -2,8 +2,10 @@ import { BadRequestException, Injectable, Type } from '@nestjs/common'; import { plainToInstance } from 'class-transformer'; import { ObjectId, Types } from 'mongoose'; import { CATEGORY_TYPE, FIND_ROOM_FILTER_TYPE } from 'src/common/consts/enum'; +import { returnValueToDto } from 'src/common/decorators/returnValueToDto.decorator'; import { MongoId } from 'src/common/dtos/MongoId.dto'; import { RoomIdDto } from 'src/common/dtos/RoomId.dto'; +import { ResShortCutRoomDto } from 'src/common/dtos/shortCutRoomInfo.res.dto'; import { UserIdDto } from 'src/common/dtos/UserId.dto'; import { Room } from 'src/models/room.model'; import { User } from 'src/models/user.model'; @@ -15,6 +17,7 @@ import { ResFavoriteToggleDto } from './dto/FavoriteToggle.res.dto'; import { FindRoomDto } from './dto/find-room.dto'; import { ResFindRoomDto } from './dto/find-room.res.dto copy'; import { ResFindOneRoomDto } from './dto/findOne-room.res.dto'; +import { LeftRoomResultResDto } from './dto/leftRoomResult.res.dto'; import { UpdateRoomDto } from './dto/update-room.dto'; @Injectable() @@ -29,6 +32,7 @@ export class RoomsService { * @param createRoomDto * @returns room */ + @returnValueToDto(Room) async createRoom(createRoomDto: CreateRoomDto): Promise { return await this.roomRepository.createRoom(createRoomDto); } @@ -38,6 +42,7 @@ export class RoomsService { * @param createRoomDto * @returns room */ + // @returnValueToDto(ResFindRoomDto) async findRoom( findRoomDto: FindRoomDto, userId: UserIdDto, @@ -64,13 +69,24 @@ export class RoomsService { ); } + const result = rooms.map((element: Room) => { + const iFavorite = user.favoriteRoomList.find((room) => + room._id.equals(element._id), + ) + ? true + : false; + const iJoin = element._id.equals(user.myRoom._id); + return { ...element, iFavorite, iJoin }; + }); //필터링 룸 - const filteredRooms = rooms.map((room: Room) => { - const iFavorite = user.favoriteRoomList.includes(room._id); - const iJoin = room._id.equals(user.myRoom); - return new ResFindRoomDto(room, iFavorite, iJoin); + // const filteredRooms = rooms.map((room: Room) => { + // const iFavorite = user.favoriteRoomList.includes(room._id); + // const iJoin = room._id.equals(user.myRoom); + // return new ResFindRoomDto(room, iFavorite, iJoin); + // }); + return plainToInstance(ResFindRoomDto, result, { + excludeExtraneousValues: true, }); - return filteredRooms; } /** @@ -94,9 +110,18 @@ export class RoomsService { // 유저가 들어간 채팅방이 있을경우 if (roomIdDto.roomId.equals(user.myRoom._id)) { // 룸이 같을경우 룸의 정보를 리턴 - const isFavoritRoom = user.favoriteRoomList.includes(user.myRoom._id); + const iFavorite = user.favoriteRoomList.find((room) => + room._id.equals(user.myRoom._id), + ) + ? true + : false; + // const isFavoritRoom = user.favoriteRoomList.includes(user.myRoom._id); const room = await this.roomRepository.findOneByRoomId(roomIdDto); - return new ResFindOneRoomDto(room, isFavoritRoom, user.chatAlarm); + const result = { ...room, iFavorite, iAlarm: user.chatAlarm }; + + return plainToInstance(ResFindOneRoomDto, result, { + excludeExtraneousValues: true, + }); } else { // 다른 룸일 경우 다른룸에서 해당 유저를 빼줌 await this.roomRepository.pullUserFromRoom( @@ -110,18 +135,30 @@ export class RoomsService { await this.userRepository.turnOnChatAlarm(userIdDto); const room = await this.roomRepository.addUserToRoom(roomIdDto, userIdDto); //check - const isFavoritRoom = user.favoriteRoomList.includes(room._id); - console.log('new room', isFavoritRoom); + const iFavorite = user.favoriteRoomList.find((room) => + room._id.equals(roomIdDto.roomId), + ) + ? true + : false; - return new ResFindOneRoomDto(room, isFavoritRoom, true); + const result = { ...room, iFavorite, iAlarm: true }; + // console.log(result); + return plainToInstance(ResFindOneRoomDto, result, { + excludeExtraneousValues: true, + }); } + @returnValueToDto(LeftRoomResultResDto) async pullUserFromRoom( roomIdDto: RoomIdDto, userIdDto: UserIdDto, - ): Promise { + ): Promise { await this.userRepository.setMyRoom(userIdDto, null); - return await this.roomRepository.pullUserFromRoom(roomIdDto, userIdDto); + const result = await this.roomRepository.pullUserFromRoom( + roomIdDto, + userIdDto, + ); + return { leftSuccess: result ? true : false }; } // async pushRoomToUserFavoriteList(roomIdDto: RoomIdDto, userIdDto: UserIdDto) { @@ -176,6 +213,7 @@ export class RoomsService { // return send; // } + @returnValueToDto(ResShortCutRoomDto) async getMyRoomShortCutInfo(userId: UserIdDto) { const roomInfo = await this.userRepository.getMyRoom(userId); console.log(roomInfo); @@ -184,9 +222,11 @@ export class RoomsService { // } return roomInfo; } + @returnValueToDto(ResShortCutRoomDto) async getMyFavorite(userId: UserIdDto) { return await this.userRepository.findMyFavoriteRooms(userId); } + async toggleChatAlarm(userId: UserIdDto): Promise { const isChatAlarmOn = await this.userRepository.toggleChatAlarm(userId); @@ -195,6 +235,7 @@ export class RoomsService { }); } + @returnValueToDto(ResShortCutRoomDto) async getPopularRooms() { console.log('asdfasdfa'); return await this.roomRepository.getPopularRooms(); diff --git a/src/apis/users/user.controller.ts b/src/apis/users/user.controller.ts index a7c3528..a452507 100644 --- a/src/apis/users/user.controller.ts +++ b/src/apis/users/user.controller.ts @@ -7,7 +7,6 @@ import { Controller, Post, Param, - Put, UseGuards, Get, Patch, @@ -19,20 +18,14 @@ import { ApiBody, ApiOperation, ApiTags, - ApiParam, ApiBearerAuth, - ApiUnauthorizedResponse, ApiResponse, - ApiBasicAuth, } from '@nestjs/swagger'; -import { AuthService } from 'src/auth/auth.service'; import { UserService } from './user.service'; -import { NicknameDto, UpdateProfileDto } from './dto/user.dto'; +import { NicknameDto } from './dto/user.dto'; import { UserIdDto } from 'src/common/dtos/UserId.dto'; import { UpdateProfileReqDto } from './dto/updateUserDto.req.dto'; import { SuccessInterceptor } from 'src/common/interceptors/sucess.interceptor'; -import { MongooseClassSerializerInterceptor } from 'src/common/interceptors/mongooseClassSerializer.interceptor'; -import { LoggingInterceptor } from 'src/common/interceptors/test.interceptors'; import { UserProfileDto } from 'src/common/dtos/UserProfile.dto'; import { ReportResultDtoResDto } from './dto/reportResultDto.res.dto'; import { CanChangeNicknameResDto } from './dto/canChangeNickname.res.dto'; @@ -41,8 +34,6 @@ import { NewAlarmStateResDto } from './dto/newAlarmState.res.dto'; @ApiTags('user') @Controller('user') @ApiBearerAuth('accessToken') -@UseInterceptors(SuccessInterceptor) -// @UseInterceptors(ClassSerializerInterceptor) @UseGuards(JwtAuthGuard) export class UserController { constructor(private readonly userService: UserService) {} @@ -53,7 +44,6 @@ export class UserController { description: '요청 성공시', type: User, }) - @MongooseClassSerializerInterceptor(User) @Get('') async getMyUserInfo(@ReqUser() user: User) { // findOneByUserId @@ -67,14 +57,11 @@ export class UserController { description: '요청 성공시', type: User, }) - @MongooseClassSerializerInterceptor(User) @Patch('') async updateProfile( @Body() updateProfileReqDto: UpdateProfileReqDto, @ReqUser() user: User, ): Promise { - console.log(user); - return await this.userService.updateProfile( user.userIdDto, updateProfileReqDto, @@ -87,16 +74,14 @@ export class UserController { description: '요청 성공시', type: UserProfileDto, }) - @MongooseClassSerializerInterceptor(UserProfileDto) @Get(':userId') - async getUserInfo(@Param() UserIdDto: UserIdDto) { + async getOtherUserInfo(@Param() UserIdDto: UserIdDto) { // findOneByUserId - return await this.userService.getUserInfo(UserIdDto); + return await this.userService.getOtherUserInfo(UserIdDto); } @ApiOperation({ summary: '상대방 유저를 차단한다' }) @Post(':userId/block') - @MongooseClassSerializerInterceptor(User) @ApiResponse({ status: 201, description: '요청 성공시', @@ -112,7 +97,6 @@ export class UserController { description: '요청 성공시', type: User, }) - @MongooseClassSerializerInterceptor(User) @Delete(':userId/block') unblockUser(@Param() otherUSerIdDto: UserIdDto, @ReqUser() user: User) { return this.userService.upBlockUser(user.userIdDto, otherUSerIdDto); @@ -122,23 +106,19 @@ export class UserController { @ApiOperation({ summary: '상대방 유저를 신고한다.' }) @Post(':userId/report') - @MongooseClassSerializerInterceptor(ReportResultDtoResDto) @ApiResponse({ status: 200, description: '요청 성공시', type: ReportResultDtoResDto, }) reportUser(@Param() reportedIdDto: UserIdDto, @ReqUser() user: User) { - const result = this.userService.reportUser(user.userIdDto, reportedIdDto); - console.log(typeof result); - return result; + return this.userService.reportUser(user.userIdDto, reportedIdDto); } @ApiOperation({ summary: '닉네임이 유효한지 , 내가 들어가있는 방정보가 있는지 확인한다.', }) @Get('canChange/:nickname') - @MongooseClassSerializerInterceptor(CanChangeNicknameResDto) @ApiResponse({ status: 200, description: '요청 성공시', @@ -157,7 +137,6 @@ export class UserController { @ApiOperation({ summary: '알림 토글 ( 최신 상태를 리턴 )', }) - @MongooseClassSerializerInterceptor(NewAlarmStateResDto) @Patch('alarm') @ApiResponse({ status: 200, diff --git a/src/apis/users/user.service.ts b/src/apis/users/user.service.ts index 19ad0a2..0412b50 100644 --- a/src/apis/users/user.service.ts +++ b/src/apis/users/user.service.ts @@ -10,6 +10,7 @@ import { ReportResultDtoResDto } from './dto/reportResultDto.res.dto'; import { returnValueToDto } from 'src/common/decorators/returnValueToDto.decorator'; import { CanChangeNicknameResDto } from './dto/canChangeNickname.res.dto'; import { NewAlarmStateResDto } from './dto/newAlarmState.res.dto'; +import { UserProfileDto } from 'src/common/dtos/UserProfile.dto'; @Injectable() export class UserService { @@ -18,11 +19,19 @@ export class UserService { private reportRepository: ReportRepository, ) {} + @returnValueToDto(User) async getUserInfo(userIdDto: UserIdDto): Promise { // auto 시리얼 라이징 return await this.userRepository.findOneByUserId(userIdDto); } + @returnValueToDto(UserProfileDto) + async getOtherUserInfo(userIdDto: UserIdDto): Promise { + // auto 시리얼 라이징 + return await this.userRepository.findOneByUserId(userIdDto); + } + + @returnValueToDto(User) async updateProfile( userIdDto: UserIdDto, updateProfileReqDto: UpdateProfileReqDto, @@ -34,6 +43,7 @@ export class UserService { ); } + @returnValueToDto(User) async blockUser( myUserIdDto: UserIdDto, otherUserIdDto: UserIdDto, @@ -60,7 +70,7 @@ export class UserService { // auto 시리얼 라이징 return returnUser; } - + @returnValueToDto(User) async upBlockUser( myUserIdDto: UserIdDto, otherUserIdDto: UserIdDto, diff --git a/src/common/dtos/ReportId.dto.ts b/src/common/dtos/ReportId.dto.ts index 873af56..e1a708e 100644 --- a/src/common/dtos/ReportId.dto.ts +++ b/src/common/dtos/ReportId.dto.ts @@ -8,7 +8,11 @@ import { Transform } from 'class-transformer'; */ export class ReportIdDto { constructor(reportId: string | Types.ObjectId) { - this.reportId = new Types.ObjectId(reportId); + if (reportId instanceof Types.ObjectId) { + this.reportId = reportId; + } else { + this.reportId = new Types.ObjectId(reportId); + } } @ApiProperty({ diff --git a/src/common/dtos/RoomId.dto.ts b/src/common/dtos/RoomId.dto.ts index b3a756e..1c805a8 100644 --- a/src/common/dtos/RoomId.dto.ts +++ b/src/common/dtos/RoomId.dto.ts @@ -7,8 +7,12 @@ import { Types } from 'mongoose'; * mongoId 용 DTO */ export class RoomIdDto { - constructor(roomId: string) { - this.roomId = new Types.ObjectId(roomId); + constructor(roomId: string | Types.ObjectId) { + if (roomId instanceof Types.ObjectId) { + this.roomId = roomId; + } else { + this.roomId = new Types.ObjectId(roomId); + } } @ApiProperty({ type: String, diff --git a/src/common/dtos/UserId.dto.ts b/src/common/dtos/UserId.dto.ts index 842bb40..01181bc 100644 --- a/src/common/dtos/UserId.dto.ts +++ b/src/common/dtos/UserId.dto.ts @@ -8,7 +8,11 @@ import { Transform } from 'class-transformer'; */ export class UserIdDto { constructor(userId: string | Types.ObjectId) { - this.userId = new Types.ObjectId(userId); + if (userId instanceof Types.ObjectId) { + this.userId = userId; + } else { + this.userId = new Types.ObjectId(userId); + } } @ApiProperty({ diff --git a/src/common/dtos/UserProfile.dto.ts b/src/common/dtos/UserProfile.dto.ts index f2ccc41..988c8f8 100644 --- a/src/common/dtos/UserProfile.dto.ts +++ b/src/common/dtos/UserProfile.dto.ts @@ -14,6 +14,7 @@ export class UserProfileDto { } @ApiProperty({ type: String, example: '626cf238b51596721c21289b' }) @Expose() + @Transform((value) => value.obj._id, { toClassOnly: true }) @TransformObjectIdToString({ toPlainOnly: true }) _id: Types.ObjectId; diff --git a/src/common/dtos/shortCutRoomInfo.res.dto.ts b/src/common/dtos/shortCutRoomInfo.res.dto.ts index 5f34fae..38ba775 100644 --- a/src/common/dtos/shortCutRoomInfo.res.dto.ts +++ b/src/common/dtos/shortCutRoomInfo.res.dto.ts @@ -1,5 +1,5 @@ import { ApiProperty } from '@nestjs/swagger'; -import { Expose } from 'class-transformer'; +import { Expose, Transform } from 'class-transformer'; import { Types } from 'mongoose'; import { CATEGORY_TYPE } from 'src/common/consts/enum'; import { Room } from 'src/models/room.model'; @@ -10,6 +10,7 @@ export class ResShortCutRoomDto { description: '방의 고유 아이디', type: String, }) + @Transform((value) => value.obj._id, { toClassOnly: true }) @TransformObjectIdToString({ toClassOnly: true }) @Expose() _id: string; diff --git a/src/main.ts b/src/main.ts index 686a6d2..781366b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,9 @@ -import { ValidationPipe } from '@nestjs/common'; -import { NestFactory } from '@nestjs/core'; +import { ClassSerializerInterceptor, ValidationPipe } from '@nestjs/common'; +import { NestFactory, Reflector } from '@nestjs/core'; import { NestExpressApplication } from '@nestjs/platform-express'; import { join } from 'path'; import { AppModule } from './app.module'; +import { SuccessInterceptor } from './common/interceptors/sucess.interceptor'; import { setupSwagger } from './utils/swagger'; async function bootstrap() { @@ -25,6 +26,8 @@ async function bootstrap() { //앱서버용 app.getHttpAdapter().getInstance().set('etag', false); app.enableCors({ origin: true, credentials: true }); + app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector))); + app.useGlobalInterceptors(new SuccessInterceptor()); const PORT = process.env.PORT; diff --git a/src/models/room.model.ts b/src/models/room.model.ts index 79a2e29..d13da23 100644 --- a/src/models/room.model.ts +++ b/src/models/room.model.ts @@ -10,7 +10,10 @@ import { import { Prop, Schema, SchemaFactory, SchemaOptions } from '@nestjs/mongoose'; import { CATEGORY_TYPE } from 'src/common/consts/enum'; import { User } from './user.model'; -import { Document, Schema as MongooseSchema } from 'mongoose'; +import { Types, Schema as MongooseSchema } from 'mongoose'; +import { Exclude, Expose, Transform, Type } from 'class-transformer'; +import { TransformObjectIdToString } from 'src/common/decorators/Expose.decorator'; +import { UserProfileDto } from 'src/common/dtos/UserProfile.dto'; const options: SchemaOptions = { // rooms default 로 s 붙여지는데 디폴트로가는게 좋을것 같아요! (이찬진) @@ -22,16 +25,33 @@ const options: SchemaOptions = { export class Geometry { @IsArray() @Prop({ type: Array, required: true }) + @Expose({ toClassOnly: true }) + @Exclude({ toPlainOnly: true }) + @Type(() => Number) coordinates: number[]; @IsString() @Prop({ type: String }) + @Expose({ toClassOnly: true }) + @Exclude({ toPlainOnly: true }) type: string; } @Schema(options) -export class Room extends Document { +export class Room { + @ApiProperty({ + description: '유저의 고유아이디', + type: String, + }) + // 시리얼 라이제이션 할때 사용 + @TransformObjectIdToString({ toPlainOnly: true }) + @Transform((value) => value.obj._id, { toClassOnly: true }) + @Type(() => Types.ObjectId) + @Expose() + _id: Types.ObjectId; + @Prop({ required: true, + type: String, }) @ApiProperty({ type: String, @@ -41,10 +61,12 @@ export class Room extends Document { }) @IsNotEmpty() @IsString() + @Expose() name: string; @Prop({ required: true, + enum: CATEGORY_TYPE, }) @ApiProperty({ enum: CATEGORY_TYPE, @@ -55,9 +77,10 @@ export class Room extends Document { }) @IsNotEmpty() @IsEnum(CATEGORY_TYPE) + @Expose() category: CATEGORY_TYPE; - @Prop({ required: true }) + @Prop({ required: true, type: Number }) @ApiProperty({ type: Number, title: '반경정보', @@ -66,42 +89,44 @@ export class Room extends Document { }) @IsNotEmpty() @IsNumber() + @Expose() radius: number; @Prop({ required: true, - type: [{ type: MongooseSchema.Types.ObjectId, ref: 'User' }], + type: [{ type: Types.ObjectId, ref: 'User' }], }) @IsNotEmpty() @IsArray() - userList: User[]; + @Transform((value) => value.obj.userList, { toClassOnly: true }) + @Type(() => UserProfileDto) + @Expose() + userList: UserProfileDto[]; - @ApiProperty({ - type: Geometry, - title: 'current_location', - example: '{"type":"Point","coordinates":[36.612849, 126.229883]}', - }) + // @ApiProperty({ + // type: Geometry, + // title: 'current_location', + // example: '{"type":"Point","coordinates":[36.612849, 126.229883]}', + // }) @IsObject() @Prop({ type: Geometry, index: '2dsphere', }) + @Type(() => Geometry) + @Expose({ toClassOnly: true }) + @Exclude({ toPlainOnly: true }) geometry: Geometry; // 거리정보 반환시에 타입 선언 + @ApiProperty({ description: '거리정보' }) + @Expose() distance: number; // 유저숫자 타입 선언 + @ApiProperty({ description: '유저 숫자' }) + @Expose() userCount: number; } const _RoomSchema = SchemaFactory.createForClass(Room); -// Duplicate the ID field. -_RoomSchema.virtual('id').get(function () { - return this._id.toHexString(); -}); - -// Ensure virtual fields are serialised. -_RoomSchema.set('toJSON', { - virtuals: true, -}); export const RoomSchema = _RoomSchema; diff --git a/src/models/user.model.ts b/src/models/user.model.ts index a3d0872..6c50b1b 100644 --- a/src/models/user.model.ts +++ b/src/models/user.model.ts @@ -3,15 +3,13 @@ import { IsEnum, IsNotEmpty, IsNumber, - IsObject, IsPhoneNumber, IsString, } from 'class-validator'; import { Prop, Schema, SchemaFactory, SchemaOptions } from '@nestjs/mongoose'; import { Document } from 'mongoose'; -import { getEnumToArray, STATUS_TYPE } from 'src/common/consts/enum'; +import { STATUS_TYPE } from 'src/common/consts/enum'; import { Room } from './room.model'; -import * as mongoose from 'mongoose'; import { IsObjectId } from 'class-validator-mongo-object-id'; import { ApiProperty } from '@nestjs/swagger'; import { Exclude, Expose, Transform, Type } from 'class-transformer'; @@ -101,7 +99,7 @@ export class User { FCMToken: string; // 룸리스트 아이디 형태만 저장 - @Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Room' }] }) + @Prop({ type: [{ type: Types.ObjectId, ref: 'Room' }] }) favoriteRoomList: Room[]; @ApiProperty({ @@ -111,7 +109,7 @@ export class User { description: '유저의 앱알림 설정 ( 앱 모든 알림 전체 )', }) @Type(() => ResShortCutRoomDto) - @Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'Room' }) + @Prop({ type: Types.ObjectId, ref: 'Room' }) @IsObjectId() @Expose() myRoom: Room; @@ -138,7 +136,7 @@ export class User { @Expose() chatAlarm: boolean; - @Prop({ type: [{ type: mongoose.Schema.Types.ObjectId, ref: User.name }] }) + @Prop({ type: [{ type: Types.ObjectId, ref: User.name }] }) @IsObjectId() @Type(() => UserProfileDto) @Exclude() @@ -149,7 +147,7 @@ export class User { description: '내가 차단한 유저들. 정보탭에서 보여지는 부분들', }) @Prop({ - type: [{ type: mongoose.Schema.Types.ObjectId, ref: User.name }], + type: [{ type: Types.ObjectId, ref: User.name }], }) @IsObjectId() @Type(() => UserProfileDto) @@ -166,7 +164,7 @@ export class User { type: String, description: '한국시간으로 보정된 시간값', }) - @Transform(({ value }) => toKRTimeZone(value)) + @Transform(({ value }) => toKRTimeZone(value), { toClassOnly: true }) @Expose() createdAt: Date; } diff --git a/src/repositories/room.repository.ts b/src/repositories/room.repository.ts index f618249..76f8ed4 100644 --- a/src/repositories/room.repository.ts +++ b/src/repositories/room.repository.ts @@ -168,7 +168,8 @@ export class RoomRepository { .populate({ path: 'userList', select: UserProfileSelect, - }); + }) + .lean({ defaults: true }); if (!room) { throw new BadRequestException('Room does not exist'); } @@ -181,17 +182,20 @@ export class RoomRepository { userIdDto: UserIdDto, ): Promise { console.log(roomIdDto); - const room = await this.roomModel.findOneAndUpdate( - { - _id: roomIdDto.roomId, - }, - { - $pull: { - userList: userIdDto.userId, + const room = await this.roomModel + .findOneAndUpdate( + { + _id: roomIdDto.roomId, }, - }, - { new: true }, - ); + { + $pull: { + userList: userIdDto.userId, + }, + }, + { new: true }, + ) + .lean({ defaults: true }); + if (!room) { throw new BadRequestException('Room does not exist'); } @@ -207,7 +211,9 @@ export class RoomRepository { .populate({ path: 'userList', select: UserProfileSelect, - }); + }) + .lean({ defaults: true }); + if (!room) { throw new BadRequestException('Room does not exist'); } diff --git a/src/repositories/user.repository.ts b/src/repositories/user.repository.ts index 486a622..9f7f99e 100644 --- a/src/repositories/user.repository.ts +++ b/src/repositories/user.repository.ts @@ -22,7 +22,6 @@ export class UserRepository { @InjectModel(User.name) private readonly userModel: Model, ) {} - // @TestDecorator(User) async findOneByUserId(userIdDto: UserIdDto): Promise { const user = await this.userModel .findOne({ _id: userIdDto.userId }) @@ -71,6 +70,15 @@ export class UserRepository { path: 'iBlockUsers', select: UserProfileSelect, }) + .populate({ + path: 'myRoom', + select: { + _id: 1, + name: 1, + category: 1, + userCount: { $size: '$userList' }, + }, + }) .lean({ defaults: true }); } @@ -104,6 +112,15 @@ export class UserRepository { path: 'iBlockUsers', select: UserProfileSelect, }) + .populate({ + path: 'myRoom', + select: { + _id: 1, + name: 1, + category: 1, + userCount: { $size: '$userList' }, + }, + }) .lean({ defaults: true }); } @@ -135,6 +152,15 @@ export class UserRepository { path: 'iBlockUsers', select: UserProfileSelect, }) + .populate({ + path: 'myRoom', + select: { + _id: 1, + name: 1, + category: 1, + userCount: { $size: '$userList' }, + }, + }) .lean({ defaults: true }); } @@ -247,7 +273,9 @@ export class UserRepository { return user; } - async findMyFavoriteRooms(userIdDto: UserIdDto): Promise { + async findMyFavoriteRooms( + userIdDto: UserIdDto, + ): Promise { const myFavoriteRoomList = await this.userModel.aggregate([ { $match: { diff --git a/views/index.hbs b/views/index.hbs deleted file mode 100644 index 13894e0..0000000 --- a/views/index.hbs +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - {{data.title}} - - - - -
-
- -
-
-
- -
-
- -
- - -
- - - - - - - \ No newline at end of file