-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from tscenping/yubin
- closed #4
- Loading branch information
Showing
14 changed files
with
288 additions
and
12 deletions.
There are no files selected for viewing
Submodule BE-config
updated
from 14eea8 to b50bdd
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { User } from 'src/users/entities/user.entity'; | ||
|
||
export type UserFindReturnDto = { | ||
user: User; | ||
mfaCode?: string; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// pagenation에서 한 페이지에 보여줄 데이터 개수 | ||
export const DATA_PER_PAGE = 10; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export enum UserStatus { | ||
ONLINE = 'ONLINE', | ||
OFFLINE = 'OFFLINE', | ||
IN_GAME = 'IN_GAME', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export type FriendInfoDto = { | ||
id: number; | ||
nickname: string; | ||
avatar: string; | ||
status: string; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { FriendInfoDto } from './friend-info.dto'; | ||
|
||
export type FriendResponseDto = { | ||
friends: FriendInfoDto[]; | ||
|
||
totalItemCount: number; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export type PageInfoDto = { | ||
total: number; | ||
page: number; | ||
lastPage: number; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { IsNumber, IsPositive } from 'class-validator'; | ||
import { BaseEntity } from 'src/common/base-entity'; | ||
import { Column, Entity } from 'typeorm'; | ||
@Entity() | ||
export class Friend extends BaseEntity { | ||
@Column() | ||
@IsNumber() | ||
@IsPositive() | ||
fromUserId: number; | ||
|
||
@Column() | ||
@IsNumber() | ||
@IsPositive() | ||
toUserId: number; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { InjectRepository } from '@nestjs/typeorm'; | ||
import { Friend } from './entities/friend.entity'; | ||
import { Repository, DataSource } from 'typeorm'; | ||
import { FriendInfoDto } from './dto/friend-info.dto'; | ||
import { DATA_PER_PAGE } from 'src/common/constants'; | ||
|
||
export class FriendRepository extends Repository<Friend> { | ||
constructor(@InjectRepository(Friend) private dataSource: DataSource) { | ||
super(Friend, dataSource.manager); | ||
} | ||
|
||
async findFriend(fromUserId: number, toUserId: number) { | ||
return await this.findOne({ | ||
where: { | ||
fromUserId, | ||
toUserId, | ||
}, | ||
}); | ||
} | ||
|
||
async findFriendInfos( | ||
userId: number, | ||
page: number, | ||
): Promise<FriendInfoDto[]> { | ||
// raw query | ||
const friends = await this.dataSource.query( | ||
` | ||
SELECT u.id, u.nickname, u.avatar, u.status | ||
FROM friend f | ||
JOIN "user" u | ||
ON u.id = f."toUserId" | ||
WHERE f."fromUserId" = $1 | ||
LIMIT $2 OFFSET $3 | ||
`, | ||
[userId, DATA_PER_PAGE, (page - 1) * DATA_PER_PAGE], | ||
); | ||
return friends; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import { BadRequestException, Injectable, Logger } from '@nestjs/common'; | ||
import { FriendRepository } from './friends.repository'; | ||
import { UserRepository } from './users.repository'; | ||
import { FriendResponseDto } from './dto/friend-response.dto'; | ||
|
||
@Injectable() | ||
export class FriendsService { | ||
private readonly logger = new Logger(FriendsService.name); | ||
|
||
constructor( | ||
private readonly friendRepository: FriendRepository, | ||
private readonly userRepository: UserRepository, | ||
) {} | ||
|
||
/** | ||
* 친구 추가 | ||
* @param fromUserId 친구요청을 보낸 유저의 id | ||
* @param toUserId 친구요청을 받은 유저의 id | ||
* @returns | ||
*/ | ||
async createFriend(fromUserId: number, toUserId: number) { | ||
// 본인에게 친구요청을 보내는지 확인 | ||
this.checkSelfFriendship(fromUserId, toUserId); | ||
|
||
// 친구요청을 받은 유저가 존재하는지 확인 | ||
await this.validateUserExists(toUserId); | ||
|
||
// 이미 친구인지 확인 | ||
await this.checkAlreadyFriends(fromUserId, toUserId); | ||
|
||
// 친구 추가 | ||
const friend = this.friendRepository.create({ | ||
fromUserId, | ||
toUserId, | ||
}); | ||
this.logger.log('friend: ', friend); | ||
await this.friendRepository.save(friend); | ||
} | ||
|
||
/** | ||
* 친구 삭제 | ||
* @param fromUserId 친구 삭제 요청을 보낸 유저의 id | ||
* @param toUserId 친구 삭제 요청을 받은 유저의 id | ||
*/ | ||
async deleteFriend(fromUserId: number, toUserId: number) { | ||
// 본인에게 친구 삭제 요청을 보내는지 확인 | ||
this.checkSelfFriendship(fromUserId, toUserId); | ||
|
||
// 친구 삭제 요청을 받은 유저가 존재하는지 확인 | ||
await this.validateUserExists(toUserId); | ||
|
||
// 친구인지 확인 | ||
const friend = await this.friendRepository.findFriend(fromUserId, toUserId); | ||
if (!friend) { | ||
throw new BadRequestException(`Not friend with ${toUserId}`); | ||
} | ||
|
||
// 친구 삭제 | ||
const result = await this.friendRepository.softDelete(friend.id); | ||
if (result.affected !== 1) { | ||
throw new BadRequestException(`Failed to delete friend with ${toUserId}`); | ||
} | ||
this.logger.log('result: ', result); | ||
} | ||
|
||
/** | ||
* 친구 목록 조회 | ||
* @param userId 친구 목록을 조회할 유저의 id | ||
* @param page 페이지 번호 | ||
* @returns 친구 목록 | ||
*/ | ||
async findFriendsWithPage( | ||
userId: number, | ||
page: number, | ||
): Promise<FriendResponseDto> { | ||
// 친구 목록 조회 | ||
const friends = await this.friendRepository.findFriendInfos(userId, page); | ||
|
||
// 페이지 정보 조회 | ||
const totalItemCount = await this.friendRepository.count({ | ||
where: { | ||
fromUserId: userId, | ||
}, | ||
}); | ||
|
||
this.logger.log('friends: ', friends); | ||
this.logger.log('pageInfo: ', totalItemCount); | ||
|
||
return { friends, totalItemCount }; | ||
} | ||
|
||
/** | ||
* 유저가 존재하는지 확인 | ||
*/ | ||
async validateUserExists(userId: number) { | ||
const user = await this.userRepository.findOne({ | ||
where: { | ||
id: userId, | ||
}, | ||
}); | ||
|
||
if (!user) { | ||
throw new BadRequestException(`User with id ${userId} doesn't exist`); | ||
} | ||
} | ||
|
||
/** | ||
* 본인에게 친구/친구삭제 요청을 보내는지 확인 | ||
*/ | ||
private checkSelfFriendship(fromUserId: number, toUserId: number) { | ||
if (fromUserId === toUserId) { | ||
throw new BadRequestException(`Can't be friend with yourself`); | ||
} | ||
} | ||
|
||
/** | ||
* 이미 친구인지 확인 | ||
*/ | ||
private async checkAlreadyFriends(fromUserId: number, toUserId: number) { | ||
const isExistFriend = await this.friendRepository.findFriend( | ||
fromUserId, | ||
toUserId, | ||
); | ||
if (isExistFriend) { | ||
throw new BadRequestException(`Already friends`); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,57 @@ | ||
import { Controller } from '@nestjs/common'; | ||
import { | ||
Body, | ||
Controller, | ||
Delete, | ||
Get, | ||
Param, | ||
ParseIntPipe, | ||
Post, | ||
UseGuards, | ||
} from '@nestjs/common'; | ||
import { GetUser } from 'src/auth/get-user.decorator'; | ||
import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard'; | ||
import { PositiveIntPipe } from 'src/common/pipes/positiveInt.pipe'; | ||
import { User } from './entities/user.entity'; | ||
import { FriendsService } from './friends.service'; | ||
import { UsersService } from './users.service'; | ||
|
||
@Controller('users') | ||
export class UsersController { | ||
constructor(private readonly usersService: UsersService) {} | ||
constructor( | ||
private readonly usersService: UsersService, | ||
private readonly friendsService: FriendsService, | ||
) {} | ||
|
||
@Post('/friends') | ||
@UseGuards(JwtAuthGuard) | ||
async createFriend( | ||
@GetUser() user: User, | ||
@Body('friendId', ParseIntPipe, PositiveIntPipe) toUserId: number, | ||
) { | ||
await this.friendsService.createFriend(user.id, toUserId); | ||
// TODO: 친구요청을 받은 유저에게 알림 보내기 | ||
} | ||
|
||
@Delete('/friends') | ||
@UseGuards(JwtAuthGuard) | ||
async deleteFriend( | ||
@GetUser() user: User, | ||
@Body('friendId', ParseIntPipe, PositiveIntPipe) toUserId: number, | ||
) { | ||
await this.friendsService.deleteFriend(user.id, toUserId); | ||
} | ||
|
||
@Get('/friends/:page') | ||
@UseGuards(JwtAuthGuard) | ||
async findFriendsWithPage( | ||
@GetUser() user: User, | ||
@Param('page', ParseIntPipe, PositiveIntPipe) page: number, | ||
) { | ||
const friendResponseDto = await this.friendsService.findFriendsWithPage( | ||
user.id, | ||
page, | ||
); | ||
|
||
return friendResponseDto; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters