Skip to content

Commit

Permalink
merge #455 from kmi0817/be-feature/#454-block-user
Browse files Browse the repository at this point in the history
[feat] νšŒμ› 차단 κΈ°λŠ₯ μΆ”κ°€
  • Loading branch information
yaongmeow authored May 23, 2024
2 parents e9d9163 + 8fece0d commit 1fde35d
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 7 deletions.
5 changes: 3 additions & 2 deletions BE/src/postings/postings.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@ export class PostingsController {
description: '검색어와 선택 νƒœκ·Έμ˜ ꡐ집합에 ν•΄λ‹Ήν•˜λŠ” κ²Œμ‹œκΈ€μ„ λ°˜ν™˜ν•©λ‹ˆλ‹€.',
})
@ApiOkResponse({ schema: { example: search_OK } })
async search(@Query() searchPostingDto: SearchPostingDto) {
return this.postingsService.findAll(searchPostingDto);
async search(@Req() request, @Query() searchPostingDto: SearchPostingDto) {
const userId = request['user'].id;
return this.postingsService.findAll(userId, searchPostingDto);
}

@Get('titles')
Expand Down
11 changes: 10 additions & 1 deletion BE/src/postings/postings.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ import { Report } from './entities/report.entity';
import { Period, Season } from './postings.types';
import { BLOCKING_LIMIT } from './postings.constants';
import { StorageService } from 'src/storage/storage.service';
import { BlockRepository } from 'src/users/block.repository';

@Injectable()
export class PostingsService {
constructor(
private readonly userRepository: UserRepository,
private readonly blockRepository: BlockRepository,
private readonly postingsRepository: PostingsRepository,
private readonly likedsRepository: LikedsRepository,
private readonly reportsRepository: ReportsRepository,
Expand All @@ -44,8 +46,10 @@ export class PostingsService {
return this.postingsRepository.save(posting);
}

async findAll(dto: SearchPostingDto) {
async findAll(userId: string, dto: SearchPostingDto) {
const blockedIds = await this.findBlockedIds(userId);
const postings = await this.postingsRepository.findAll(
blockedIds,
dto.keyword,
dto.sorting,
dto.offset,
Expand Down Expand Up @@ -226,4 +230,9 @@ export class PostingsService {
reports: posting.reports,
};
}

private async findBlockedIds(blocker: string) {
const blocks = await this.blockRepository.findByBlocker(blocker);
return blocks.map((block) => block.blocked.id);
}
}
10 changes: 9 additions & 1 deletion BE/src/postings/repositories/postings.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export class PostingsRepository {
}

async findAll(
blockedIds: string[],
keyword: string,
sorting: Sorting,
offset: number,
Expand All @@ -50,7 +51,14 @@ export class PostingsRepository {
withWhos: WithWho[]
) {
const conditions = ['p.title LIKE :keyword'];
let params: { [key: string]: string } = { keyword: `%${keyword}%` };
let params: { [key: string]: string | string[] } = {
keyword: `%${keyword}%`,
};

if (blockedIds.length > 0) {
conditions.push('p.writer NOT IN (:...blockedIds)');
params = { ...params, blockedIds };
}

if (budget) {
conditions.push('p.budget = :budget');
Expand Down
38 changes: 38 additions & 0 deletions BE/src/users/block.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Inject, Injectable } from '@nestjs/common';
import { Block } from './entities/block.entity';
import { BLOCK_REPOSITORY } from './users.constants';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';

@Injectable()
export class BlockRepository {
constructor(
@Inject(BLOCK_REPOSITORY)
private blockRepository: Repository<Block>
) {}

save(blocker: User, blocked: User) {
return this.blockRepository.save({ blocker, blocked });
}

findByBlocker(blocker: string) {
return this.blockRepository
.createQueryBuilder('b')
.leftJoinAndSelect('b.blocker', 'x')
.leftJoinAndSelect('b.blocked', 'y')
.where('b.blocker = :blocker', { blocker })
.getMany();
}

findByBlockerAndBlocked(blocker: string, blocked: string) {
return this.blockRepository
.createQueryBuilder('b')
.leftJoinAndSelect('b.blocker', 'x')
.leftJoinAndSelect('b.blocked', 'y')
.where('b.blocker = :blocker AND b.blocked = :blocked', {
blocker,
blocked,
})
.getOne();
}
}
16 changes: 16 additions & 0 deletions BE/src/users/entities/block.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Entity, PrimaryGeneratedColumn, ManyToOne, JoinColumn } from 'typeorm';
import { User } from './user.entity';

@Entity()
export class Block {
@PrimaryGeneratedColumn('uuid')
id: string;

@ManyToOne(() => User, (user) => user.blockers, { nullable: false })
@JoinColumn({ name: 'blocker', referencedColumnName: 'id' })
blocker: User;

@ManyToOne(() => User, (user) => user.blockeds, { nullable: false })
@JoinColumn({ name: 'blocked', referencedColumnName: 'id' })
blocked: User;
}
7 changes: 7 additions & 0 deletions BE/src/users/entities/user.entity.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Liked } from 'src/postings/entities/liked.entity';
import { Posting } from 'src/postings/entities/posting.entity';
import { Report } from 'src/postings/entities/report.entity';
import { Block } from './block.entity';
import {
Entity,
Column,
Expand Down Expand Up @@ -49,4 +50,10 @@ export class User {
@ManyToOne(() => SocialLogin, (socialLogin) => socialLogin.users)
@JoinColumn({ name: 'social_type', referencedColumnName: 'id' })
socials: SocialLogin;

@OneToMany(() => Block, (block) => block.blocker)
blockers: Block[];

@OneToMany(() => Block, (block) => block.blocked)
blockeds: Block[];
}
1 change: 1 addition & 0 deletions BE/src/users/users.constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export const DATA_SOURCE = 'DATA_SOURCE';
export const USERS_REPOSITORY = 'USERS_REPOSITORY';
export const BLOCK_REPOSITORY = 'BLOCK_REPOSITORY';
13 changes: 13 additions & 0 deletions BE/src/users/users.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import {
UploadedFile,
UseGuards,
Req,
Post,
Param,
ParseUUIDPipe,
} from '@nestjs/common';
import { UsersService } from './users.service';
import {
Expand Down Expand Up @@ -110,4 +113,14 @@ export class UsersController {
checkDuplicatedName(@Query('name') name: string) {
return this.usersService.checkDuplicatedName(name);
}

@Post(':id/block')
@ApiOperation({
summary: 'νŠΉμ • νšŒμ› 차단',
description: 'ν˜„μž¬ μœ μ €κ°€ id에 ν•΄λ‹Ήν•˜λŠ” νšŒμ›μ„ μ°¨λ‹¨ν•©λ‹ˆλ‹€.',
})
blockUser(@Req() request, @Param('id', ParseUUIDPipe) id: string) {
const userId = request['user'].id;
return this.usersService.blockUser(userId, id);
}
}
5 changes: 3 additions & 2 deletions BE/src/users/users.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import { usersProvider } from './users.providers';
import { UserRepository } from './users.repository';
import { StorageModule } from '../storage/storage.module';
import { DatabaseModule } from '../database/database.module';
import { BlockRepository } from './block.repository';

@Module({
imports: [DatabaseModule, StorageModule],
controllers: [UsersController],
providers: [UsersService, ...usersProvider, UserRepository],
exports: [UserRepository, UsersService],
providers: [UsersService, ...usersProvider, UserRepository, BlockRepository],
exports: [UserRepository, UsersService, BlockRepository],
})
export class UsersModule {}
12 changes: 11 additions & 1 deletion BE/src/users/users.providers.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
import { Block } from './entities/block.entity';
import { User } from './entities/user.entity';
import { DataSource } from 'typeorm';
import { DATA_SOURCE, USERS_REPOSITORY } from './users.constants';
import {
BLOCK_REPOSITORY,
DATA_SOURCE,
USERS_REPOSITORY,
} from './users.constants';

export const usersProvider = [
{
provide: USERS_REPOSITORY,
useFactory: (dataSource: DataSource) => dataSource.getRepository(User),
inject: [DATA_SOURCE],
},
{
provide: BLOCK_REPOSITORY,
useFactory: (dataSource: DataSource) => dataSource.getRepository(Block),
inject: [DATA_SOURCE],
},
];
24 changes: 24 additions & 0 deletions BE/src/users/users.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import { UserRepository } from './users.repository';
import { CheckDuplicatedNameResponseDto } from './dto/check-duplicated-name-response.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { UpdateUserIpDto } from './dto/update-user-ip.dto';
import { BlockRepository } from './block.repository';

@Injectable()
export class UsersService {
constructor(
private userRepository: UserRepository,
private blockRepository: BlockRepository,
private readonly storageService: StorageService
) {}

Expand Down Expand Up @@ -113,4 +115,26 @@ export class UsersService {
async updateUserIp(id: string, updateUserIpDto: UpdateUserIpDto) {
return this.userRepository.update(id, updateUserIpDto);
}

async blockUser(blocker: string, blocked: string) {
if (blocker === blocked) {
throw new BadRequestException('자기 μžμ‹ μ„ 차단할 수 μ—†μŠ΅λ‹ˆλ‹€.');
}

const blockedUser = await this.userRepository.findById(blocked);
if (!blockedUser) {
throw new BadRequestException('μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” νšŒμ›μ„ 차단할 수 μ—†μŠ΅λ‹ˆλ‹€.');
}

const block = await this.blockRepository.findByBlockerAndBlocked(
blocker,
blocked
);
if (block) {
throw new BadRequestException('이미 μ°¨λ‹¨ν•œ νšŒμ›μž…λ‹ˆλ‹€.');
}

const blockerUser = await this.userRepository.findById(blocker);
return this.blockRepository.save(blockerUser, blockedUser);
}
}

0 comments on commit 1fde35d

Please sign in to comment.