Skip to content

Commit

Permalink
Merge branch 'feature/#33-SNP-64' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
raymondanythings committed Dec 17, 2023
2 parents 73be55e + 2462390 commit 5a7cb7f
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class AuthService {

async refreshToken(refresh: string): Promise<JWT> {
this.verify(refresh, {
secret: process.env.RES_SALT,
secret: process.env.SALT,
});

const queryRunner = this.dataSource.createQueryRunner();
Expand Down
5 changes: 3 additions & 2 deletions src/auth/dtos/jwt.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';

export class JWT {
@ApiProperty()
@ApiProperty({ description: '엑세스 토큰' })
@IsString()
access: string;

@ApiProperty()
@ApiProperty({ description: '리프레시 토큰' })
@IsString()
refresh: string;

Expand All @@ -17,6 +17,7 @@ export class JWT {
}

export class Payload {
@ApiProperty({ description: 'Guard를 통과한 후 사용자 아이디' })
@IsString()
id: number;
}
11 changes: 7 additions & 4 deletions src/oauth/dtos/google.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,29 @@ import { UserResponse } from 'src/users/dtos/user.dto';
import { User } from 'src/users/entities/user.entity';

export class GoogleUserInfo {
@ApiProperty()
@ApiProperty({ description: '아이디' })
@IsString()
id: string;

@ApiProperty()
@ApiProperty({ description: '이메일' })
@IsEmail()
email: string;

@ApiProperty()
@ApiProperty({ description: '이메일 검증 여부' })
@IsBoolean()
verified_email: boolean;

@ApiProperty()
@ApiProperty({ description: '프로필 사진 주소' })
@IsOptional()
@IsString()
picture: string;
}

export class GoogleAuthResponse {
@ApiProperty({ type: () => JWT })
token: JWT;

@ApiProperty({ type: () => UserResponse })
user: UserResponse;

constructor(token: JWT, user: User) {
Expand Down
5 changes: 4 additions & 1 deletion src/oauth/oauth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ export class OauthService {

const googleUesr = userResponse.data as GoogleUserInfo;

const user = await this.userService.findByUserEmail(googleUesr.email);
let user = await this.userService.findByUserEmail(googleUesr.email);
if (!user) {
user = await this.userService.create({ email: googleUesr.email });
}
const token = this.authService.sign(user.id);
user.refresh = token.refresh;
await this.dataSource.getRepository(User).save(user);
Expand Down
8 changes: 8 additions & 0 deletions src/users/dtos/set-nickname.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';

export class ChangeNicknameDTO {
@ApiProperty({ description: '번경할 닉네임', default: '츄츄' })
@IsString()
nickname: string;
}
23 changes: 22 additions & 1 deletion src/users/user.controller.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { Controller, Get, UseGuards } from '@nestjs/common';
import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common';
import { UserService } from './user.service';
import { AccessGuard } from 'src/auth/guards/acess.guard';
import { AuthUser } from 'src/auth/decorators/auth-user.decorator';
import { Payload } from 'src/auth/dtos/jwt.dto';
import {
ApiBearerAuth,
ApiExtraModels,
ApiOkResponse,
ApiOperation,
ApiTags,
getSchemaPath,
} from '@nestjs/swagger';
import { UserResponse } from './dtos/user.dto';
import { ChangeNicknameDTO } from './dtos/set-nickname.dto';

@Controller('user')
@ApiBearerAuth()
@ApiExtraModels(UserResponse)
@ApiTags('User API')
export class UserController {
Expand All @@ -33,4 +36,22 @@ export class UserController {
async getMe(@AuthUser() { id }: Payload) {
return await this.userService.getMe(id);
}

@ApiOperation({
summary: '닉네임 변경',
description: '나의 닉네임을 설정/변경한다.',
})
@ApiOkResponse({
description: '성공 여부',
type: Boolean,
})
@ApiBearerAuth()
@UseGuards(AccessGuard)
@Post('nickname')
async changeNickname(
@AuthUser() { id }: Payload,
@Body() changeNicknameDTO: ChangeNicknameDTO,
) {
return await this.userService.changeNickname(id, changeNicknameDTO);
}
}
3 changes: 2 additions & 1 deletion src/users/user.module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { UserRepository } from './user.repository';

@Module({
imports: [],
controllers: [UserController],
providers: [UserService],
providers: [UserService, UserRepository],
exports: [UserService],
})
export class UserModule {}
13 changes: 13 additions & 0 deletions src/users/user.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { DataSource, DeepPartial, Repository } from 'typeorm';
import { User } from './entities/user.entity';
import { InjectDataSource } from '@nestjs/typeorm';

export class UserRepository extends Repository<User> {
constructor(@InjectDataSource() private readonly dataSource: DataSource) {
super(User, dataSource.manager);
}

async updateAndReturning(userId: number, userLike: DeepPartial<User>) {
return await this.update(userId, userLike);
}
}
55 changes: 53 additions & 2 deletions src/users/user.service.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { UserRepository } from './user.repository';
import { UserResponse } from './dtos/user.dto';
import { Injectable } from '@nestjs/common';
import { InjectDataSource } from '@nestjs/typeorm';
Expand All @@ -8,10 +9,14 @@ import {
PostUserResponseDto,
} from './dtos/create-users.dto';
import { createResponse } from 'src/utils/response.utils';
import { ChangeNicknameDTO } from './dtos/set-nickname.dto';

@Injectable()
export class UserService {
constructor(@InjectDataSource() private readonly connection: DataSource) {}
constructor(
@InjectDataSource() private readonly connection: DataSource,
private readonly userRepository: UserRepository,
) {}

async createUser(postUserRequestDto: PostUserRequestDto) {
const { email } = postUserRequestDto;
Expand All @@ -26,6 +31,22 @@ export class UserService {
return createResponse(new PostUserResponseDto(result.generatedMaps[0].id));
}

/**
* 사용자를 생성하고 반환한다
*
* @issue SNP-64
* @author raymondanything
* @param {PostUserRequestDto} postUserRequestDto
* @returns {Promise<User>} user
*/
async create(postUserRequestDto: PostUserRequestDto): Promise<User> {
const { email } = postUserRequestDto;
const repository = this.connection.getRepository(User);
const result = await repository.save(repository.create({ email }));

return result;
}

async findByUserEmail(email: string) {
const result = await this.connection
.createQueryBuilder(User, 'users')
Expand All @@ -35,10 +56,40 @@ export class UserService {
return result;
}

async getMe(id: number) {
/**
* 내정보를 조회한다
*
* @issue SNP-64
* @author raymondanything
* @param {number} id
* @returns {Promise<UserResponse>} UserResponse
*/
async getMe(id: number): Promise<UserResponse> {
const user = await this.connection
.getRepository(User)
.findOne({ where: { id } });
return new UserResponse(user);
}

/**
* 닉네임을 설정 / 변경한다.
*
* @issue SNP-64
* @link https://www.notion.so/raymondanything/SNP-64-Google-b3c69d93313d47fba51201412b70c635?pvs=4
* @author raymondanything
* @param userId
* @param changeNicknameDTO
* @returns {Promise<boolean>}
*/
async changeNickname(
userId: number,
changeNicknameDTO: ChangeNicknameDTO,
): Promise<boolean> {
try {
await this.userRepository.updateAndReturning(userId, changeNicknameDTO);
return true;
} catch (error) {
return false;
}
}
}

0 comments on commit 5a7cb7f

Please sign in to comment.