Skip to content

Commit

Permalink
[BE#209] 친구 조회 추가 삭제 (#223)
Browse files Browse the repository at this point in the history
* feat: 소셜 기능 추가

- 친구 추가 기능
- 내 친구 목록 불러오기 기능
- 친구 삭제 기능

* docs: 컨트롤러 api 문서 수정

* fix: 친구 추가 함수 수정

* chore: 컨트롤러 파라미터 변경

- 유저 객체를 바로 받아오도록 변경
- dto에 ondelete 추가
  • Loading branch information
victolee0 authored Nov 27, 2023
1 parent 2f2c31a commit 3758c42
Show file tree
Hide file tree
Showing 9 changed files with 240 additions and 11 deletions.
3 changes: 2 additions & 1 deletion BE/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { PassportModule } from '@nestjs/passport';
import { AuthModule } from './auth/auth.module';
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';
import { Mates } from './mates/mates.entity';

@Module({
imports: [
Expand All @@ -33,7 +34,7 @@ import { join } from 'path';
username: config.get<string>('DATABASE_USERNAME'),
password: config.get<string>('DATABASE_PASSWORD'),
database: config.get<string>('DATABASE_NAME'),
entities: [StudyLogs, Categories, UsersModel],
entities: [StudyLogs, Categories, UsersModel, Mates],
synchronize: true,
}),
inject: [ConfigService],
Expand Down
24 changes: 24 additions & 0 deletions BE/src/mates/dto/response/mates.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ApiProperty } from '@nestjs/swagger';

export class MatesDto {
@ApiProperty({
type: 'number',
example: '1',
description: '친구 관계 id',
})
id: number;

@ApiProperty({
type: 'number',
example: 1,
description: '구독의 주체 id (1이 2를 구독중)',
})
follower_id: number;

@ApiProperty({
type: 'number',
example: 2,
description: '구독 중인 친구 id',
})
following_id: number;
}
17 changes: 17 additions & 0 deletions BE/src/mates/dto/response/status-message.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ApiProperty } from '@nestjs/swagger';

export class StatusMessageDto {
@ApiProperty({
type: 'number',
example: 200,
description: '상태 코드',
})
statusCode: number;

@ApiProperty({
type: 'string',
example: '성공적으로 삭제되었습니다.',
description: '메시지',
})
message: string;
}
63 changes: 53 additions & 10 deletions BE/src/mates/mates.controller.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,72 @@
import { Controller, Delete, Get, Param, Post } from '@nestjs/common';
import { ApiCreatedResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
import {
Controller,
Delete,
Get,
Param,
Post,
Body,
UseGuards,
} from '@nestjs/common';
import {
ApiBearerAuth,
ApiCreatedResponse,
ApiOperation,
ApiTags,
} from '@nestjs/swagger';
import { User } from 'src/users/decorator/user.decorator';
import { MatesService } from './mates.service';
import { MatesDto } from './dto/response/mates.dto';
import { StatusMessageDto } from './dto/response/status-message.dto';
import { AccessTokenGuard } from 'src/auth/guard/bearer-token.guard';
import { UsersModel } from 'src/users/entity/users.entity';

@Controller('mates')
@ApiTags('소셜 페이지')
export class MatesController {
constructor(private readonly matesService: MatesService) {}
@Get()
@ApiOperation({ summary: '모든 친구들 조회하기' })
getMates() {}
@UseGuards(AccessTokenGuard)
@ApiBearerAuth()
@ApiOperation({ summary: '모든 친구들 조회하기 (완)' })
getMates(@User('id') user_id: number): Promise<MatesDto[]> {
return this.matesService.getMates(user_id);
}

@Get('/:mate_id/stats')
@UseGuards(AccessTokenGuard)
@ApiBearerAuth()
@ApiOperation({ summary: '특정 친구의 통계 조회하기' })
getMateStats(@Param('mate_id') id: string) {
id;
}

@Post()
@UseGuards(AccessTokenGuard)
@ApiBearerAuth()
@ApiCreatedResponse({
description: '친구가 성공적으로 구독되었습니다.',
})
@ApiOperation({ summary: '친구 구독하기' })
crateMate() {}
@ApiOperation({ summary: '친구 구독하기 (완)' })
createMate(
@User() user: UsersModel,
@Body('following_nickname') following_nickname: string,
): Promise<MatesDto> {
return this.matesService.addMate(user, following_nickname);
}

@Delete('/:mate_id')
@ApiOperation({ summary: '구독한 친구 구독 취소하기' })
deleteMate(@Param('mate_id') id: string) {
id;
@Delete('')
@UseGuards(AccessTokenGuard)
@ApiBearerAuth()
@ApiOperation({ summary: '구독한 친구 구독 취소하기 (완)' })
async deleteMate(
@User() user: UsersModel,
@Body('following_id') following_id: number,
): Promise<StatusMessageDto> {
await this.matesService.deleteMate(user, following_id);

return {
statusCode: 200,
message: '성공적으로 삭제되었습니다.',
};
}
}
28 changes: 28 additions & 0 deletions BE/src/mates/mates.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToOne,
JoinColumn,
} from 'typeorm';
import { UsersModel } from 'src/users/entity/users.entity';

@Entity()
export class Mates {
@PrimaryGeneratedColumn()
id: number;

@ManyToOne(() => UsersModel, (user) => user.follower, {
eager: true,
onDelete: 'CASCADE',
})
@JoinColumn({ name: 'follower_id' })
follower_id: UsersModel;

@ManyToOne(() => UsersModel, (user) => user.following, {
eager: true,
onDelete: 'CASCADE',
})
@JoinColumn({ name: 'following_id' })
following_id: UsersModel;
}
7 changes: 7 additions & 0 deletions BE/src/mates/mates.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { Module } from '@nestjs/common';
import { MatesController } from './mates.controller';
import { MatesService } from './mates.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Mates } from './mates.entity';
import { AuthModule } from 'src/auth/auth.module';
import { UsersModule } from 'src/users/users.module';

@Module({
imports: [TypeOrmModule.forFeature([Mates]), AuthModule, UsersModule],
controllers: [MatesController],
providers: [MatesService],
})
export class MatesModule {}
18 changes: 18 additions & 0 deletions BE/src/mates/mates.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { MatesService } from './mates.service';

describe('MatesService', () => {
let service: MatesService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [MatesService],
}).compile();

service = module.get<MatesService>(MatesService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
84 changes: 84 additions & 0 deletions BE/src/mates/mates.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import {
Injectable,
NotFoundException,
BadRequestException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Mates } from './mates.entity';
import { Repository } from 'typeorm';
import { MatesDto } from './dto/response/mates.dto';
import { UsersModel } from 'src/users/entity/users.entity';

@Injectable()
export class MatesService {
constructor(
@InjectRepository(Mates)
private matesRepository: Repository<Mates>,
@InjectRepository(UsersModel)
private userRepository: Repository<UsersModel>,
) {}

async getMates(user_id: number): Promise<MatesDto[]> {
const result = await this.matesRepository.find({
where: { follower_id: { id: user_id } },
});
return result.map((mate) => this.entityToDto(mate));
}

async addMate(
user: UsersModel,
following_nickname: string,
): Promise<MatesDto> {
const following = await this.userRepository.findOne({
where: { nickname: following_nickname },
});

if (user.id === following.id) {
throw new BadRequestException('자신을 친구 추가 할 수 없습니다.');
}

if (!user || !following) {
throw new NotFoundException('해당 유저는 존재하지 않습니다.');
}

const isExist = await this.matesRepository.findOne({
where: { follower_id: user, following_id: following },
});

if (isExist) {
throw new BadRequestException('이미 친구 관계입니다.');
}

const mate = this.matesRepository.create({
follower_id: user,
following_id: following,
});

const result = await this.matesRepository.save(mate);
return this.entityToDto(result);
}

async deleteMate(user: UsersModel, following_id: number): Promise<void> {
const following = await this.userRepository.findOne({
where: { id: following_id },
});
const result = await this.matesRepository.delete({
follower_id: user,
following_id: following,
});

if (result.affected === 0) {
throw new NotFoundException('해당 친구 관계는 존재하지 않습니다.');
}
}

entityToDto(mate: Mates): MatesDto {
const { id, follower_id, following_id } = mate;
const mateDto = {
id: id,
follower_id: follower_id.id,
following_id: following_id.id,
};
return mateDto;
}
}
7 changes: 7 additions & 0 deletions BE/src/users/entity/users.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ApiProperty } from '@nestjs/swagger';
import { StudyLogs } from 'src/study-logs/study-logs.entity';
import { Categories } from 'src/categories/categories.entity';
import { AuthTypeEnum } from '../const/auth-type.const';
import { Mates } from 'src/mates/mates.entity';

@Entity()
export class UsersModel {
Expand Down Expand Up @@ -57,4 +58,10 @@ export class UsersModel {

@OneToMany(() => Categories, (category) => category.user_id)
categories: Categories[];

@OneToMany(() => Mates, (mate) => mate.follower_id)
follower: Mates[];

@OneToMany(() => Mates, (mate) => mate.following_id)
following: Mates[];
}

0 comments on commit 3758c42

Please sign in to comment.