Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auth, Music, Playlist 에 트랜잭션 추가 #365

Merged
merged 7 commits into from
Jan 9, 2024
7 changes: 6 additions & 1 deletion server/src/auth/auth.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { getRepositoryToken } from '@nestjs/typeorm';
import { User } from 'src/entity/user.entity';
import { Repository } from 'typeorm';
import { Repository, DataSource } from 'typeorm';
import { JwtModule, JwtService } from '@nestjs/jwt';
import { Playlist } from 'src/entity/playlist.entity';
import { Music } from 'src/entity/music.entity';
Expand All @@ -16,6 +16,7 @@ describe('AuthController', () => {
let service: AuthService;
let jwtModule: JwtModule;
let userRepository: Repository<User>;
let mockDataSource: jest.Mocked<DataSource>;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
Expand All @@ -40,6 +41,10 @@ describe('AuthController', () => {
provide: getRepositoryToken(Music_Playlist),
useClass: Repository,
},
{
provide: DataSource,
useValue: mockDataSource,
},
],
}).compile();

Expand Down
7 changes: 6 additions & 1 deletion server/src/auth/auth.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AuthService } from './auth.service';
import { Repository } from 'typeorm';
import { Repository, DataSource } from 'typeorm';
import { getRepositoryToken } from '@nestjs/typeorm';
import { User } from 'src/entity/user.entity';
import { JwtModule, JwtService } from '@nestjs/jwt';
Expand All @@ -15,6 +15,7 @@ describe('AuthService', () => {
let jwtModule: JwtModule;
let userRepository: Repository<User>;
let playlistService: PlaylistService;
let mockDataSource: jest.Mocked<DataSource>;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
Expand All @@ -38,6 +39,10 @@ describe('AuthService', () => {
useClass: Repository,
},
PlaylistService,
{
provide: DataSource,
useValue: mockDataSource,
},
],
}).compile();

Expand Down
97 changes: 64 additions & 33 deletions server/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ERROR_CODE } from 'src/config/errorCode.enum';
import { UserCreateDto } from 'src/dto/userCreate.dto';
import { User } from 'src/entity/user.entity';
import { HTTP_STATUS_CODE } from 'src/httpStatusCode.enum';
import { Repository } from 'typeorm';
import { Repository, DataSource } from 'typeorm';
import { v4 as uuid } from 'uuid';

@Injectable()
Expand All @@ -15,26 +15,29 @@ export class AuthService {
constructor(
@InjectRepository(User) private userRepository: Repository<User>,
private jwtService: JwtService,
private readonly dataSource: DataSource,
) {}

async login(email: string): Promise<{ accessToken: string }> {
const user: User = await this.userRepository.findOneBy({
user_email: email,
});
const user: User = await this.dataSource
.getRepository(User)
.createQueryBuilder('user')
.where('user.user_email = :email', { email })
.getOne();

if (user) {
const payload = { user_id: user['user_id'] };
const accessToken = this.jwtService.sign(payload);

return { accessToken };
} else {
this.logger.error(`auth.service - login : NOT_EXIST_USER`);
throw new CatchyException(
'NOT_EXIST_USER',
HTTP_STATUS_CODE['WRONG_TOKEN'],
ERROR_CODE.NOT_EXIST_USER,
);
}

this.logger.error(`auth.service - login : NOT_EXIST_USER`);
throw new CatchyException(
'NOT_EXIST_USER',
HTTP_STATUS_CODE['WRONG_TOKEN'],
ERROR_CODE.NOT_EXIST_USER,
);
}

async signup(userCreateDto: UserCreateDto): Promise<{ accessToken: string }> {
Expand All @@ -49,24 +52,38 @@ export class AuthService {
ERROR_CODE.ALREADY_EXIST_EMAIL,
);
}
if (email) {
const newUser: User = this.userRepository.create({
user_id: uuid(),
nickname,
photo: null,
user_email: email,
created_at: new Date(),
});
await this.userRepository.save(newUser);

return this.login(email);

const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.startTransaction();

try {
if (email) {
const newUser: User = this.userRepository.create({
user_id: uuid(),
nickname,
photo: null,
user_email: email,
created_at: new Date(),
});

await queryRunner.manager.save(newUser);

await queryRunner.commitTransaction();

return await this.login(email);
}

this.logger.error(`auth.service - signup : WRONG_TOKEN`);
throw new CatchyException(
'WRONG_TOKEN',
HTTP_STATUS_CODE.WRONG_TOKEN,
ERROR_CODE.WRONG_TOKEN,
);
} catch {
await queryRunner.rollbackTransaction();
} finally {
await queryRunner.release();
}
this.logger.error(`auth.service - signup : WRONG_TOKEN`);
throw new CatchyException(
'WRONG_TOKEN',
HTTP_STATUS_CODE.WRONG_TOKEN,
ERROR_CODE.WRONG_TOKEN,
);
}

async getGoogleEmail(googleIdToken: string): Promise<string> {
Expand All @@ -84,13 +101,16 @@ export class AuthService {
ERROR_CODE.EXPIRED_TOKEN,
);
}

return userInfo.email;
}

async isExistEmail(email: string): Promise<boolean> {
const user: User = await this.userRepository.findOneBy({
user_email: email,
});
const user: User = await this.dataSource
.getRepository(User)
.createQueryBuilder('user')
.where('user.user_email = :email', { email })
.getOne();

if (!user) {
return false;
Expand All @@ -100,7 +120,18 @@ export class AuthService {
}

async deleteUser(user: User): Promise<{ userId: string }> {
await this.userRepository.delete(user.user_id);
return { userId: user.user_id };
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.startTransaction();

try {
await queryRunner.manager.remove(user);
await queryRunner.commitTransaction();

return { userId: user.user_id };
} catch {
await queryRunner.rollbackTransaction();
} finally {
await queryRunner.release();
}
}
}
10 changes: 9 additions & 1 deletion server/src/music/music.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { UploadService } from 'src/upload/upload.service';
import { NcloudConfigService } from 'src/config/ncloud.config';
import { ConfigService } from '@nestjs/config';
import { getRepositoryToken } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { DataSource, Repository } from 'typeorm';
import { Music } from 'src/entity/music.entity';
import { musicCreateInfo, user } from 'test/constants/music.mockData';
import { MusicController } from './music.controller';
Expand All @@ -27,6 +27,7 @@ describe('UploadController', () => {
let authService: AuthService;
let musicRepository: Repository<Music>;
let mockJwtStrategy = { validate: () => user };
let mockDataSource: jest.Mocked<DataSource>;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
Expand All @@ -49,6 +50,10 @@ describe('UploadController', () => {
provide: getRepositoryToken(User),
useClass: Repository,
},
{
provide: DataSource,
useValue: mockDataSource,
},
],
})
.overrideProvider(JwtStrategy)
Expand All @@ -62,6 +67,9 @@ describe('UploadController', () => {
musicController = module.get<MusicController>(MusicController);
musicService = module.get<MusicService>(MusicService);
musicRepository = module.get(getRepositoryToken(Music));
mockDataSource = {
createQueryRunner: jest.fn(),
} as unknown as jest.Mocked<DataSource>;

app = module.createNestApplication();
await app.init();
Expand Down
16 changes: 15 additions & 1 deletion server/src/music/music.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { UploadService } from 'src/upload/upload.service';
import { NcloudConfigService } from 'src/config/ncloud.config';
import { ConfigService } from '@nestjs/config';
import { getRepositoryToken } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { DataSource, Repository } from 'typeorm';
import { Music } from 'src/entity/music.entity';
import { MusicCreateDto } from 'src/dto/musicCreate.dto';
import { CatchyException } from 'src/config/catchyException';
Expand All @@ -24,6 +24,7 @@ describe('UploadController', () => {
let cloudService: NcloudConfigService;
let configService: ConfigService;
let mockRepository: jest.Mocked<Repository<Music>>;
let mockDataSource: jest.Mocked<DataSource>;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
Expand All @@ -43,12 +44,24 @@ describe('UploadController', () => {
provide: getRepositoryToken(Recent_Played),
useClass: Repository,
},
{
provide: DataSource,
useValue: mockDataSource,
},
],
}).compile();

configService = module.get<ConfigService>(ConfigService);
cloudService = module.get<NcloudConfigService>(NcloudConfigService);
uploadService = module.get<UploadService>(UploadService);
mockDataSource = {
createQueryRunner: jest.fn().mockResolvedValue({
startTransaction: jest.fn(),
commitTransaction: jest.fn(),
rollbackTransaction: jest.fn(),
release: jest.fn(),
}),
} as unknown as jest.Mocked<DataSource>;
mockRepository = {
create: jest.fn(),
save: jest.fn(),
Expand All @@ -57,6 +70,7 @@ describe('UploadController', () => {
mockRepository,
uploadService,
cloudService,
mockDataSource,
);
});

Expand Down
42 changes: 23 additions & 19 deletions server/src/music/music.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable, Logger } from '@nestjs/common';
import { HTTP_STATUS_CODE } from 'src/httpStatusCode.enum';
import { Repository } from 'typeorm';
import { Repository, DataSource } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { MusicCreateDto } from 'src/dto/musicCreate.dto';
import { Music } from 'src/entity/music.entity';
Expand All @@ -19,6 +19,7 @@ export class MusicService {
@InjectRepository(Music) private musicRepository: Repository<Music>,
private uploadService: UploadService,
private readonly ncloudConfigService: NcloudConfigService,
private readonly dataSource: DataSource,
) {
this.objectStorage = ncloudConfigService.createObjectStorageOption();
}
Expand All @@ -35,24 +36,21 @@ export class MusicService {
musicCreateDto: MusicCreateDto,
user_id: string,
): Promise<string> {
try {
const {
music_id,
title,
cover,
file: music_file,
genre,
} = musicCreateDto;
const { music_id, title, cover, file: music_file, genre } = musicCreateDto;

if (!this.isValidGenre(genre)) {
this.logger.error(`music.service - createMusic : NOT_EXIST_GENRE`);
throw new CatchyException(
'NOT_EXIST_GENRE',
HTTP_STATUS_CODE.BAD_REQUEST,
ERROR_CODE.NOT_EXIST_GENRE,
);
}
if (!this.isValidGenre(genre)) {
this.logger.error(`music.service - createMusic : NOT_EXIST_GENRE`);
throw new CatchyException(
'NOT_EXIST_GENRE',
HTTP_STATUS_CODE.BAD_REQUEST,
ERROR_CODE.NOT_EXIST_GENRE,
);
}

const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.startTransaction();

try {
const newMusic: Music = this.musicRepository.create({
music_id,
title,
Expand All @@ -63,10 +61,14 @@ export class MusicService {
user: { user_id },
});

const savedMusic: Music = await this.musicRepository.save(newMusic);
await queryRunner.manager.save(newMusic);

return savedMusic.music_id;
await queryRunner.commitTransaction();

return music_id;
} catch (err) {
await queryRunner.rollbackTransaction();

if (err instanceof CatchyException) {
throw err;
}
Expand All @@ -77,6 +79,8 @@ export class MusicService {
HTTP_STATUS_CODE.SERVER_ERROR,
ERROR_CODE.SERVICE_ERROR,
);
} finally {
await queryRunner.release();
}
}

Expand Down
Loading
Loading