Skip to content

Commit

Permalink
Merge pull request #73 from boostcampwm-2024/be/feature/edit_nickname
Browse files Browse the repository at this point in the history
[BE/feature] 닉네임 수정 api 구현
  • Loading branch information
DongKey777 authored Nov 21, 2024
2 parents 185a299 + f12026b commit f1bdfe6
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 31 deletions.
34 changes: 25 additions & 9 deletions apps/backend/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import { Body, Controller, Get, Patch, Post, Req, UseGuards } from '@nestjs/common';
import { Request } from 'express';
import { ApiOperation } from '@nestjs/swagger';
import { AuthGuard } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { SignUpDto } from './dto/signUp.dto';
import { User } from 'src/global/utils/memberData';
import { successhandler, successMessage } from 'src/global/successhandler';
import { ApiOperation } from '@nestjs/swagger';
import { JwtAuthGuard } from 'src/global/utils/jwtAuthGuard';
import { SignUpDto } from './dto/signUp.dto';
import { LoginDto } from './dto/login.dto';
import { signUpResponseDecorator } from './decorator/signUp.decorator';
import { loginResponseDecorator } from './decorator/login.decorator';
import { AuthGuard } from '@nestjs/passport';
import { GoogleLoginDto } from './dto/googleLogin.dto';
import { KakaoLoginDto } from './dto/kakaoLogin.dto';
import { UpdateIntroduceDto } from './dto/updateIntroduce.dto';
import { UpdateNicknameDto } from './dto/updateNickname.dto';
import { signUpResponseDecorator } from './decorator/signUp.decorator';
import { loginResponseDecorator } from './decorator/login.decorator';
import { oauthResponseDecorator } from './decorator/oauth.decorator';
import { JwtAuthGuard } from 'src/global/utils/jwtAuthGuard';
import { Request } from 'express';
import { logoutResponseDecorator } from './decorator/logout.decorator';
import { UpdateIntroduceDto } from './dto/updateIntroduce.dto';
import { updateIntroduceResponseDecorator } from './decorator/updateIntroduce.decorator';
import { User } from 'src/global/utils/memberData';
import { updateNicknameResponseDecorator } from './decorator/updateNickname.decorator';

@Controller('api/auth')
export class AuthController {
Expand Down Expand Up @@ -88,4 +90,18 @@ export class AuthController {
await this.authService.updateIntroduce(memberId, introduce);
return successhandler(successMessage.INTRODUCE_UPDATE_SUCCESS);
}

@Patch('nickname')
@UseGuards(JwtAuthGuard)
@ApiOperation({ summary: '유저 닉네임 변경 API' })
@updateNicknameResponseDecorator()
async updateNickname(
@User() user: { memberId: number },
@Body() updateNicknameDto: UpdateNicknameDto
) {
const { memberId } = user;
const { nickname } = updateNicknameDto;
await this.authService.updateNickname(memberId, nickname);
return successhandler(successMessage.NICKNAME_UPDATE_SUCCESS);
}
}
3 changes: 2 additions & 1 deletion apps/backend/src/auth/auth.queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export const authQueries = {
signUpQuery: 'INSERT INTO members (email, password, nickname) VALUES ($1, $2, $3) RETURNING *',
findByEmailQuery:
'SELECT member_id, email, password, nickname FROM members WHERE email = $1 LIMIT 1',
updateMemberQuery: 'UPDATE members SET introduce = $1 WHERE member_id = $2'
updateInroduceQuery: 'UPDATE members SET introduce = $1 WHERE member_id = $2',
updateNicknameQuery: 'UPDATE members SET nickname = $1 WHERE member_id = $2'
};
21 changes: 15 additions & 6 deletions apps/backend/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,24 +62,27 @@ export class AuthService {
if (!isPasswordValid)
throw new HttpException('이메일 또는 비밀번호가 올바르지 않습니다.', HttpStatus.UNAUTHORIZED);

return this.generateTokens(member.rows[0].member_id);
const nickname = member.rows[0].nickname;
const { accessToken, refreshToken } = await this.generateTokens(member.rows[0].member_id);
return { nickname, accessToken, refreshToken };
}

private async verifyUser(email: string, nickname: string) {
const existingUser = await this.databaseService.query(authQueries.findByEmailQuery, [email]);
if (existingUser?.rows?.length) return existingUser.rows[0].memberId;
if (existingUser?.rows?.length) return existingUser.rows[0];
const hashedPassword = await bcrypt.hash('default', 10);
const newMember = await this.databaseService.query(authQueries.signUpQuery, [
email,
hashedPassword,
nickname
]);
return newMember.rows[0].memberId;
return newMember.rows[0];
}

async SocialLogin(email: string, nickname: string) {
const memberId = await this.verifyUser(email, nickname);
return this.generateTokens(memberId);
const member = await this.verifyUser(email, nickname);
const { accessToken, refreshToken } = await this.generateTokens(member.rows[0].member_id);
return { nickname, accessToken, refreshToken };
}

private async generateTokens(memberId: number) {
Expand Down Expand Up @@ -112,6 +115,12 @@ export class AuthService {
}

async updateIntroduce(memberId: number, introduce: Nullable<string>) {
await this.databaseService.query(authQueries.updateMemberQuery, [introduce, memberId]);
await this.databaseService.query(authQueries.updateInroduceQuery, [introduce, memberId]);
}

async updateNickname(memberId: number, nickname: Nullable<string>) {
if (!nickname || nickname.length < 2 || nickname.length > 10)
throw new HttpException('닉네임은 2자에서 10자 사이로 입력해주세요.', HttpStatus.BAD_REQUEST);
await this.databaseService.query(authQueries.updateNicknameQuery, [nickname, memberId]);
}
}
7 changes: 3 additions & 4 deletions apps/backend/src/auth/decorator/logout.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { applyDecorators } from '@nestjs/common';
import { ApiBearerAuth, ApiResponse } from '@nestjs/swagger';
import { ApiResponse } from '@nestjs/swagger';
import { LogoutSuccessResponseDto } from '../dto/logout.dto';
import { TokenDecorator } from 'src/global/utils/tokenSwagger';

export function logoutResponseDecorator() {
return applyDecorators(
ApiBearerAuth(),
TokenDecorator(),
ApiResponse({
status: 200,
description: '로그아웃 성공',
type: LogoutSuccessResponseDto
}),
TokenDecorator()
})
);
}
11 changes: 5 additions & 6 deletions apps/backend/src/auth/decorator/updateIntroduce.decorator.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { applyDecorators } from '@nestjs/common';
import { ApiBearerAuth, ApiResponse } from '@nestjs/swagger';
import { ApiResponse } from '@nestjs/swagger';
import { TokenDecorator } from 'src/global/utils/tokenSwagger';
import { updateIntroduceSuccessResponseDto } from '../dto/updateIntroduce.dto';
import { UpdateIntroduceSuccessResponseDto } from '../dto/updateIntroduce.dto';

export function updateIntroduceResponseDecorator() {
return applyDecorators(
ApiBearerAuth(),
TokenDecorator(),
ApiResponse({
status: 200,
description: '소개글 수정 성공',
type: updateIntroduceSuccessResponseDto
}),
TokenDecorator()
type: UpdateIntroduceSuccessResponseDto
})
);
}
32 changes: 32 additions & 0 deletions apps/backend/src/auth/decorator/updateNickname.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { applyDecorators } from '@nestjs/common';
import { ApiResponse } from '@nestjs/swagger';
import { TokenDecorator } from 'src/global/utils/tokenSwagger';
import { UpdateNicknameSuccessResponseDto } from '../dto/updateNickname.dto';

export function updateNicknameResponseDecorator() {
return applyDecorators(
TokenDecorator(),
ApiResponse({
status: 200,
description: '닉네임 수정 성공',
type: UpdateNicknameSuccessResponseDto
}),
ApiResponse({
status: 400,
description: '유효하지 않은 입력값 에러',
content: {
'application/json': {
examples: {
invalidNickname: {
summary: '닉네임이 2~10자 범위를 벗어남',
value: {
code: 400,
message: '닉네임은 2자에서 10자 사이로 입력해주세요.'
}
}
}
}
}
})
);
}
6 changes: 6 additions & 0 deletions apps/backend/src/auth/dto/login.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ export class LoginDto {
}

export class LoginDataDto {
@ApiProperty({
description: '닉네임',
example: '홍길동'
})
nickname: string;

@ApiProperty({
description: 'Access Token',
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
Expand Down
4 changes: 2 additions & 2 deletions apps/backend/src/auth/dto/updateIntroduce.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class UpdateIntroduceDto {
introduce: string;
}

export class updateIntroduceSuccessResponseDto {
export class UpdateIntroduceSuccessResponseDto {
@ApiProperty({
description: '응답 코드',
example: 200
Expand All @@ -17,7 +17,7 @@ export class updateIntroduceSuccessResponseDto {

@ApiProperty({
description: '응답 메세지',
example: '로그인 되었습니다.'
example: '소개글이 변경되었습니다.'
})
message: string;
}
23 changes: 23 additions & 0 deletions apps/backend/src/auth/dto/updateNickname.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ApiProperty } from '@nestjs/swagger';

export class UpdateNicknameDto {
@ApiProperty({
description: '닉네임',
example: '홍길동'
})
nickname: string;
}

export class UpdateNicknameSuccessResponseDto {
@ApiProperty({
description: '응답 코드',
example: 200
})
code: number;

@ApiProperty({
description: '응답 메세지',
example: '닉네임이 변경되었습니다.'
})
message: string;
}
1 change: 1 addition & 0 deletions apps/backend/src/global/successhandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const successMessage = {
LOGOUT_SUCCESS: { code: 200, message: '로그아웃 되었습니다.' },
GET_MEMBER_SUCCESS: { code: 201, message: '회원 가입되었습니다.' },
INTRODUCE_UPDATE_SUCCESS: { code: 200, message: '소개글이 변경되었습니다.' },
NICKNAME_UPDATE_SUCCESS: { code: 200, message: '닉네임이 변경되었습니다.' },
GET_MAIL_SUCCESS: { code: 200, message: '메일 조회를 완료했습니다.' },
DELETE_MAIL_SUCCESS: { code: 200, message: '메일 삭제를 완료했습니다.' },
GET_MAIL_ALARM_SUCCESS: { code: 200, message: 'Catch alarm!.' },
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/src/global/utils/jwtAuthGuard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class JwtAuthGuard {
}

const { memberId } = decoded;
request.member = { memberId };
request.user = { memberId };
return true;
} catch {
throw new HttpException('잘못된 토큰입니다.', HttpStatus.UNAUTHORIZED);
Expand Down
3 changes: 2 additions & 1 deletion apps/backend/src/global/utils/memberData.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { Optional } from './dataCustomType';

export const User = createParamDecorator((data: string | undefined, ctx: ExecutionContext) => {
export const User = createParamDecorator((data: Optional<string>, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
const user = request.user;

Expand Down
3 changes: 2 additions & 1 deletion apps/backend/src/global/utils/tokenSwagger.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { applyDecorators } from '@nestjs/common';
import { ApiHeader, ApiResponse } from '@nestjs/swagger';
import { ApiBearerAuth, ApiHeader, ApiResponse } from '@nestjs/swagger';

export function TokenDecorator() {
return applyDecorators(
ApiBearerAuth(),
ApiHeader({
name: 'Authorization',
description: 'Bearer <token>',
Expand Down

0 comments on commit f1bdfe6

Please sign in to comment.