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

Put notice like button #119

Merged
merged 12 commits into from
Aug 11, 2024
79 changes: 79 additions & 0 deletions src/popo/noticeLike/noticeLike.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { Test, TestingModule } from '@nestjs/testing';
import { NoticeLikeController } from './noticeLike.controller';
import { NoticeLikeService } from './noticeLike.service';
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { NoticeLike } from './noticeLike.entity';

describe('NoticeLikeController', () => {
let controller: NoticeLikeController;
let noticeLikeService: DeepMocked<NoticeLikeService>;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [NoticeLikeController],
providers: [
{
provide: NoticeLikeService,
useValue: createMock<NoticeLikeService>(),
},
],
}).compile();

controller = module.get<NoticeLikeController>(NoticeLikeController);
noticeLikeService = module.get(NoticeLikeService);
});

it('should be defined', () => {
expect(controller).toBeDefined();
expect(noticeLikeService).toBeDefined();
});

it('should count likes', async () => {
const result = 1;
const noticeId = '1';
noticeLikeService.countLikes.mockResolvedValue(result);

expect(await controller.countLikes(noticeId)).toBe(result);
});

// TODO: noticeLike.service.spec.ts로 테스트 옮기기
// 테스트 DB를 만들어 실제로 데이터를 DB에 넣고 findByUserIdAndNoticeId를 테스트하기
// it('should get status', async () => {
// const result = true;
// const like: Promise<NoticeLike> = {
// id: 1,
// user_id: '1',
// notice_id: '1',
// created_at: new Date(),
// };
// const userId = '1';
// const noticeId = '1';
// noticeLikeService.findByUserIdAndNoticeId.mockResolvedValue(like);

// await expect(controller.getStatus(userId, noticeId)).toBe(result);
// });

it('should throw error when delete if it is not liked', async () => {
const userId = '1';
const noticeId = '1';
noticeLikeService.findByUserIdAndNoticeId.mockResolvedValue(null);

await expect(controller.delete(userId, noticeId)).rejects.toThrow();
});

it('should delete like', async () => {
const userId = '1';
const noticeId = '1';
const like: NoticeLike = {
id: 1,
user_id: '1',
notice_id: '1',
created_at: new Date(),
};
const mockedDeletedResult = { affected: 1, raw: null };
noticeLikeService.findByUserIdAndNoticeId.mockResolvedValue(like);
noticeLikeService.delete.mockResolvedValue(mockedDeletedResult);

expect(await controller.delete(userId, noticeId)).toBe(mockedDeletedResult);
});
});
87 changes: 87 additions & 0 deletions src/popo/noticeLike/noticeLike.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import {
BadRequestException,
Body,
Controller,
Delete,
Get,
HttpException,
HttpStatus,
Post,
Query,
UseGuards,
} from '@nestjs/common';
import { ApiBody, ApiTags } from '@nestjs/swagger';

import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard';
import { NoticeLikeDto } from './noticeLike.dto';
import { NoticeLikeService } from './noticeLike.service';
import { QueryFailedError } from 'typeorm';
import { NoticeLike } from './noticeLike.entity';

const Message = {
FAIL_LIKE_DELETION_NEVER_LIKED: 'There is no record of liking the post.',
FAIL_DUPLICATE_ENTRY: 'Duplicate entry detected',
FAIL_INTERNAL_SERVER: 'Internal server error',
};

@ApiTags('Notice Like')
@Controller('noticeLike')
export class NoticeLikeController {
constructor(private readonly noticeLikeService: NoticeLikeService) {}

@Post()
@UseGuards(JwtAuthGuard)
@ApiBody({ type: NoticeLikeDto })
async create(@Body() dto: NoticeLikeDto): Promise<NoticeLike> {
try {
return await this.noticeLikeService.save(dto);
} catch (e) {
if (e instanceof QueryFailedError) {
throw new HttpException(
Message.FAIL_DUPLICATE_ENTRY,
HttpStatus.CONFLICT,
);
} else {
throw new HttpException(
Message.FAIL_INTERNAL_SERVER,
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
}

@Get('count')
countLikes(@Query('notice_id') notice_id: string): Promise<number> {
return this.noticeLikeService.countLikes(notice_id);
}

@Get('status')
async getStatus(
@Query('user_id') user_id: string,
@Query('notice_id') notice_id: string,
): Promise<boolean> {
return (await this.noticeLikeService.findByUserIdAndNoticeId(
user_id,
notice_id,
))
? true
: false;
}

@Delete()
@UseGuards(JwtAuthGuard)
async delete(
@Query('user_id') user_id: string,
@Query('notice_id') notice_id: string,
) {
const target = await this.noticeLikeService.findByUserIdAndNoticeId(
user_id,
notice_id,
);

if (!target) {
throw new BadRequestException(Message.FAIL_LIKE_DELETION_NEVER_LIKED);
}
return this.noticeLikeService.delete(user_id, notice_id);
}
}
4 changes: 4 additions & 0 deletions src/popo/noticeLike/noticeLike.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export class NoticeLikeDto {
readonly user_id: string;
readonly notice_id: string;
}
23 changes: 23 additions & 0 deletions src/popo/noticeLike/noticeLike.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
Index,
} from 'typeorm';

@Entity()
@Index(['user_id', 'notice_id'], { unique: true })
export class NoticeLike {
@PrimaryGeneratedColumn('increment')
id: number;

@Column({ nullable: false })
user_id: string;

@Column({ nullable: false })
notice_id: string;

@CreateDateColumn()
created_at: Date;
}
14 changes: 14 additions & 0 deletions src/popo/noticeLike/noticeLike.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

import { NoticeLike } from './noticeLike.entity';
import { NoticeLikeController } from './noticeLike.controller';
import { NoticeLikeService } from './noticeLike.service';

@Module({
imports: [TypeOrmModule.forFeature([NoticeLike])],
controllers: [NoticeLikeController],
providers: [NoticeLikeService],
exports: [NoticeLikeService],
})
export class NoticeLikeModule {}
41 changes: 41 additions & 0 deletions src/popo/noticeLike/noticeLike.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

import { NoticeLike } from './noticeLike.entity';
import { NoticeLikeDto } from './noticeLike.dto';

@Injectable()
export class NoticeLikeService {
constructor(
@InjectRepository(NoticeLike)
private readonly noticeLikeRepo: Repository<NoticeLike>,
) {}

save(dto: NoticeLikeDto) {
return this.noticeLikeRepo.save(dto);
}

findByUserIdAndNoticeId(user_id: string, notice_id: string) {
return this.noticeLikeRepo.findOne({
where: { user_id: user_id, notice_id: notice_id },
});
}

findAllByNoticeId(notice_id: string) {
return this.noticeLikeRepo.find({
where: { notice_id: notice_id },
});
}

countLikes(notice_id: string) {
return this.noticeLikeRepo.count({ where: { notice_id: notice_id } });
}

delete(user_id: string, notice_id: string) {
return this.noticeLikeRepo.delete({
user_id: user_id,
notice_id: notice_id,
});
}
}
2 changes: 2 additions & 0 deletions src/popo/popo.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ReservationModule } from './reservation/reservation.module';
import { SettingModule } from './setting/setting.module';
import { UserModule } from './user/user.module';
import { WhitebookModule } from './whitebook/whitebook.module';
import { NoticeLikeModule } from './noticeLike/noticeLike.module';
import { FavoritePlaceModule } from './favorite/place/place.favorite.module';

@Module({
Expand All @@ -24,6 +25,7 @@ import { FavoritePlaceModule } from './favorite/place/place.favorite.module';
SettingModule,
UserModule,
WhitebookModule,
NoticeLikeModule,
FavoritePlaceModule,
],
controllers: [],
Expand Down
Loading