Skip to content

Commit

Permalink
Merge pull request #317 from tmddus2/feature/240306-test-code
Browse files Browse the repository at this point in the history
Refactor(#318): UserService ํ…Œ์ŠคํŠธ์ฝ”๋“œ ์ถ”๊ฐ€
  • Loading branch information
platinouss authored Mar 19, 2024
2 parents 4a5363a + 5f0edd7 commit ccbf311
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 66 deletions.
14 changes: 7 additions & 7 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"devDependencies": {
"@nestjs/cli": "^10.0.0",
"@nestjs/schematics": "^10.0.0",
"@nestjs/testing": "^10.0.0",
"@nestjs/testing": "^10.3.3",
"@types/cookie-parser": "^1.4.6",
"@types/express": "^4.17.17",
"@types/jest": "^29.5.2",
Expand Down Expand Up @@ -74,6 +74,9 @@
"ts"
],
"rootDir": "src",
"modulePaths": [
"<rootDir>/.."
],
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
Expand Down
11 changes: 4 additions & 7 deletions backend/src/lecture/lecture.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
} from '@nestjs/common';
import { ApiBody, ApiHeader, ApiOperation, ApiParam, ApiQuery, ApiResponse, ApiTags } from '@nestjs/swagger';
import { Response } from 'express';
import { UserService } from 'src/user/user.service';
import { CreateLectureDto } from './dto/create-lecture.dto';
import { LectureInfoDto } from './dto/response/response-lecture-info.dto';
import { UpdateLectureDto } from './dto/update-lecture.dto';
Expand All @@ -28,8 +27,7 @@ import { Types } from 'mongoose';
@Controller('lecture')
export class LectureController {
constructor(
private readonly lectureService: LectureService,
private readonly userService: UserService
private readonly lectureService: LectureService
) {}

@UseGuards(CustomAuthGuard)
Expand All @@ -43,8 +41,7 @@ export class LectureController {
if (!req.user) {
throw new HttpException('๋กœ๊ทธ์ธ ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ž…๋‹ˆ๋‹ค.', HttpStatus.UNAUTHORIZED);
}
const user = await this.userService.findOneByEmail(req.user.email);
const code = await this.lectureService.createLecture(createLecture, user._id);
const code = await this.lectureService.createLecture(createLecture, req.user.email);
res.status(HttpStatus.CREATED).send({ code: code });
}

Expand Down Expand Up @@ -73,7 +70,7 @@ export class LectureController {
throw new HttpException('์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฐ•์˜ ์ฐธ์—ฌ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.', HttpStatus.NOT_FOUND);
}

await this.userService.updateLecture(req.user.email, enterCodeDocument);
await this.lectureService.updateLecture(req.user.email, enterCodeDocument);
res.status(HttpStatus.OK).send();
}

Expand Down Expand Up @@ -140,7 +137,7 @@ export class LectureController {
throw new HttpException('๋กœ๊ทธ์ธ ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ž…๋‹ˆ๋‹ค.', HttpStatus.UNAUTHORIZED);
}

const result = await this.userService.findLectureList(req.user.email);
const result = await this.lectureService.findLectureList(req.user.email);
return res.status(HttpStatus.OK).send(result);
}
}
5 changes: 2 additions & 3 deletions backend/src/lecture/lecture.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ import { JwtModule } from '@nestjs/jwt';
{ name: WhiteboardLog.name, schema: WhiteboardLogSchema },
{ name: LectureSubtitle.name, schema: LectureSubtitleSchema }
]),
JwtModule
JwtModule,
],
controllers: [LectureController],
providers: [LectureService, UserService],
exports: [LectureService, MongooseModule]
providers: [LectureService, UserService]
})
export class LectureModule {}
18 changes: 15 additions & 3 deletions backend/src/lecture/lecture.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Lecture } from './schema/lecture.schema';
import { EnterCode } from './schema/lecture-code.schema';
import { generateRandomNumber } from 'src/utils/GenerateUtils';
import { LectureRecordDto } from './dto/response/response-lecture-record.dto';
import { UserService } from 'src/user/user.service';

@Injectable()
export class LectureService {
Expand All @@ -21,14 +22,16 @@ export class LectureService {
@InjectModel(WhiteboardLog.name)
private whiteboardLogModel: Model<WhiteboardLog>,
@InjectModel(LectureSubtitle.name)
private lectureSubtitleModel: Model<LectureSubtitle>
private lectureSubtitleModel: Model<LectureSubtitle>,
private readonly userService: UserService
) {}

async createLecture(createLectureDto: CreateLectureDto, id: Types.ObjectId) {
async createLecture(createLectureDto: CreateLectureDto, email: string) {
const user = await this.userService.findOneByEmail(email);
const lecture = new this.lectureModel({
title: createLectureDto.title,
description: createLectureDto.description,
presenter_id: id
presenter_id: user._id
});
const lectureCode = new this.enterCodeModel({
code: await this.generateRoomCode(),
Expand Down Expand Up @@ -103,4 +106,13 @@ export class LectureService {
const audioFile = lecture.audio_file;
return new LectureRecordDto(logs, subtitles, audioFile);
}

async updateLecture(email: string, enterCode: EnterCode) {
const lecture = await this.findLectureInfo(enterCode);
return await this.userService.updateLectureList(email, lecture.id);
}

async findLectureList(email: string) {
return await this.userService.findLectureList(email);
}
}
8 changes: 0 additions & 8 deletions backend/src/user/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ export class UserController {
throw new HttpException('๋กœ๊ทธ์ธ ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ž…๋‹ˆ๋‹ค.', HttpStatus.UNAUTHORIZED);
}
const userInfo = await this.userService.findOneByEmail(req.user.email);

if (!userInfo) {
throw new HttpException('์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.', HttpStatus.NOT_FOUND);
}
res.status(HttpStatus.OK).send(new UserInfoDto(userInfo));
}

Expand All @@ -39,10 +35,6 @@ export class UserController {
throw new HttpException('๋กœ๊ทธ์ธ ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ž…๋‹ˆ๋‹ค.', HttpStatus.UNAUTHORIZED);
}
const result = await this.userService.updateUsername(req.user.email, userUpdateDto.username);
if (!result) {
res.status(HttpStatus.NOT_FOUND).send();
throw new HttpException('์—…๋ฐ์ดํŠธ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.', HttpStatus.NOT_FOUND);
}
res.status(HttpStatus.OK).send(new UserInfoDto(result));
}
}
16 changes: 5 additions & 11 deletions backend/src/user/user.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,18 @@ import { User, UserSchema } from './user.schema';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { JwtModule } from '@nestjs/jwt';
import { LectureService } from 'src/lecture/lecture.service';
import { Lecture, LectureSchema } from 'src/lecture/schema/lecture.schema';
import { EnterCode, EnterCodeSchema } from 'src/lecture/schema/lecture-code.schema';
import { WhiteboardLog, WhiteboardLogSchema } from 'src/lecture/schema/whiteboard-log.schema';
import { LectureSubtitle, LectureSubtitleSchema } from 'src/lecture/lecture-subtitle.schema';
import { LectureModule } from 'src/lecture/lecture.module';

@Module({
imports: [
MongooseModule.forFeature([
{ name: User.name, schema: UserSchema },
{ name: Lecture.name, schema: LectureSchema },
{ name: EnterCode.name, schema: EnterCodeSchema },
{ name: WhiteboardLog.name, schema: WhiteboardLogSchema },
{ name: LectureSubtitle.name, schema: LectureSubtitleSchema }
]),
JwtModule
JwtModule,
LectureModule
],
controllers: [UserController],
providers: [UserService, LectureService]
providers: [UserService],
exports: [UserModule]
})
export class UserModule {}
102 changes: 102 additions & 0 deletions backend/src/user/user.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { Test } from '@nestjs/testing';
import { UserService } from './user.service';
import { getModelToken } from '@nestjs/mongoose';
import { User } from './user.schema';
import { Model, Types } from 'mongoose';
import { NotFoundException } from '@nestjs/common';


describe('UserModule', () => {
let service: UserService;
let model: Model<User>;
beforeAll(async () => {
const module = await Test.createTestingModule({
providers: [UserService,
{
provide: getModelToken(User.name),
useValue: Model
}
]
}).compile();

service = module.get<UserService>(UserService);
model = module.get<Model<User>>(getModelToken(User.name));
});

it('should have UserService', () => {
expect(service).toBeDefined();
});

describe('findOneByEmail', () => {
const id = new Types.ObjectId();
const email = "[email protected]";

it('should throw NotFoundException', async () => {
jest.spyOn(model, 'findOne').mockResolvedValue(null);
await expect(service.findOneByEmail(email)).rejects.toThrow(NotFoundException);
})

it('should find user', async () => {
jest.spyOn(model, 'findOne').mockResolvedValue({
_id: id,
email: email
});
const user = await service.findOneByEmail(email);
expect(user._id).toEqual(id);
expect(user.email).toEqual(email);
})
});

describe('updateUsername', () => {
const id = new Types.ObjectId();
const email = "[email protected]";
const username = "testname";

it('should throw NotFoundException', async () => {
jest.spyOn(model, 'findOneAndUpdate').mockResolvedValue(null);
await expect(service.updateUsername(email, username)).rejects.toThrow(NotFoundException);
})

it('should update username', async () => {
jest.spyOn(model, 'findOneAndUpdate').mockResolvedValue({
_id: id,
email: email,
username: username
});

const user = await service.updateUsername(email, username);
expect(user.username).toEqual(username);
})
});


describe('findLectureList', () => {
const email = "[email protected]";

it('should throw NotFoundException', async () => {
jest.spyOn(model, 'findOne').mockResolvedValue(null);
await expect(service.findLectureList(email)).rejects.toThrow(NotFoundException);
})
});

describe('updateLectureList', () => {
const email = '[email protected]';
const id = new Types.ObjectId();

it('should throw NotFoundException', async () => {
jest.spyOn(model, 'findOneAndUpdate').mockResolvedValue(null);
await expect(service.updateLectureList(email, id)).rejects.toThrow(NotFoundException);
})

it('should call with', async () => {
const findOneAndUpdateMock = jest.spyOn(model, 'findOneAndUpdate').mockResolvedValue({});

await service.updateLectureList(email, id);
expect(findOneAndUpdateMock).toHaveBeenCalledWith(
{ email: email },
{ $push: { lecture_id: id } },
{ new: true }
);
})
});
});
58 changes: 32 additions & 26 deletions backend/src/user/user.service.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,50 @@
import { Injectable } from '@nestjs/common';
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { User, UserDocument } from './user.schema';
import { Model } from 'mongoose';
import { LectureService } from 'src/lecture/lecture.service';
import { EnterCode } from 'src/lecture/schema/lecture-code.schema';
import { Model, Types } from 'mongoose';

@Injectable()
export class UserService {
constructor(
@InjectModel(User.name) private userModel: Model<User>,
private lectureService: LectureService
@InjectModel(User.name) private userModel: Model<User>
) {}

async findOneByEmail(email: string): Promise<UserDocument> {
return await this.userModel.findOne({ email: email });
const user = await this.userModel.findOne({ email: email });
if (!user) {
throw new NotFoundException('user not found');
}
return user;
}

async updateUsername(email: string, username: string) {
return await this.userModel.findOneAndUpdate({ email: email }, { username: username }, { new: true });
const user = await this.userModel.findOneAndUpdate({ email: email }, { username: username }, { new: true });
if (!user) {
throw new NotFoundException('user not found');
}
return user;
}

async updateLecture(email: string, enterCode: EnterCode) {
const lecture = await this.lectureService.findLectureInfo(enterCode);
return await this.userModel.findOneAndUpdate(
{ email: email },
{ $push: { lecture_id: lecture.id } },
{ new: true }
);
async findLectureList(email: string) {
let user = await this.findOneByEmail(email);
user = await user.populate({
path: 'lecture_id',
select: '-__v',
match: { is_end: true },
populate: { path: 'presenter_id', select: '-_id username' }
});
return user.lecture_id;
}

async findLectureList(email: string) {
return (
await (
await this.findOneByEmail(email)
).populate({
path: 'lecture_id',
select: '-__v',
match: { is_end: true },
populate: { path: 'presenter_id', select: '-_id username' }
})
).lecture_id;
async updateLectureList(email: string, id: Types.ObjectId) {
const user = await this.userModel.findOneAndUpdate(
{ email: email },
{ $push: { lecture_id: id } },
{ new: true }
);
if (!user) {
throw new NotFoundException('user not found');
}
return user;
}
}

0 comments on commit ccbf311

Please sign in to comment.