Skip to content

Commit

Permalink
Merge pull request #11 from Nangman-Archive/develop
Browse files Browse the repository at this point in the history
feat: 사용자 차단 도메인 구현
  • Loading branch information
giwoong01 authored May 6, 2024
2 parents 52dd150 + 39452b8 commit ff862a6
Show file tree
Hide file tree
Showing 14 changed files with 345 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ out/
### prod yml file ###
src/**/application-prod.yml
src/**/application-dev.yml
src/**/application-local.yml
### NetBeans ###
/nbproject/private/
/nbbuild/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.example.copro.member.domain;

import static com.querydsl.core.types.PathMetadataFactory.*;

import com.querydsl.core.types.dsl.*;

import com.querydsl.core.types.PathMetadata;
import javax.annotation.processing.Generated;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.dsl.PathInits;


/**
* QBlockedMemberMapping is a Querydsl query type for BlockedMemberMapping
*/
@Generated("com.querydsl.codegen.DefaultEntitySerializer")
public class QBlockedMemberMapping extends EntityPathBase<BlockedMemberMapping> {

private static final long serialVersionUID = 16622364L;

private static final PathInits INITS = PathInits.DIRECT2;

public static final QBlockedMemberMapping blockedMemberMapping = new QBlockedMemberMapping("blockedMemberMapping");

public final QMember blockedMember;

public final NumberPath<Long> id = createNumber("id", Long.class);

public final QMember member;

public QBlockedMemberMapping(String variable) {
this(BlockedMemberMapping.class, forVariable(variable), INITS);
}

public QBlockedMemberMapping(Path<? extends BlockedMemberMapping> path) {
this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS));
}

public QBlockedMemberMapping(PathMetadata metadata) {
this(metadata, PathInits.getFor(metadata, INITS));
}

public QBlockedMemberMapping(PathMetadata metadata, PathInits inits) {
this(BlockedMemberMapping.class, metadata, inits);
}

public QBlockedMemberMapping(Class<? extends BlockedMemberMapping> type, PathMetadata metadata, PathInits inits) {
super(type, metadata, inits);
this.blockedMember = inits.isInitialized("blockedMember") ? new QMember(forProperty("blockedMember")) : null;
this.member = inits.isInitialized("member") ? new QMember(forProperty("member")) : null;
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public class QMember extends EntityPathBase<Member> {

public static final QMember member = new QMember("member1");

public final ListPath<BlockedMemberMapping, QBlockedMemberMapping> blockedMemberMappings = this.<BlockedMemberMapping, QBlockedMemberMapping>createList("blockedMemberMappings", BlockedMemberMapping.class, QBlockedMemberMapping.class, PathInits.DIRECT2);

public final NumberPath<Integer> career = createNumber("career", Integer.class);

public final StringPath email = createString("email");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.example.copro.member.api;

import com.example.copro.global.template.RspTemplate;
import com.example.copro.member.api.dto.request.BlockedMemberReqDto;
import com.example.copro.member.application.BlockedMemberService;
import com.example.copro.member.domain.Member;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "blockedMember", description = "BlockedMember Controller")
@RestController
@RequestMapping("/api")
public class BlockedMemberController {
private final BlockedMemberService blockedMemberService;

public BlockedMemberController(BlockedMemberService blockedMemberService) {
this.blockedMemberService = blockedMemberService;
}

@Operation(summary = "유저 차단", description = "해당 유저를 차단 목록에 추가합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "유저 차단 성공"),
@ApiResponse(responseCode = "400", description = "잘못된 요청 값"),
@ApiResponse(responseCode = "401", description = "헤더 없음 or 토큰 불일치", content = @Content(schema = @Schema(example = "INVALID_HEADER or INVALID_TOKEN")))
})
@PostMapping("/add-blocked")
public RspTemplate<String> addBlockedMember(@AuthenticationPrincipal Member member,
@Valid @RequestBody BlockedMemberReqDto blockedMemberReqDto) {
blockedMemberService.addBlockedMember(member, blockedMemberReqDto);
return new RspTemplate<>(HttpStatus.OK, "유저 차단 완료");
}

@Operation(summary = "유저 차단 취소", description = "해당 유저를 차단 목록에서 취소합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "유저 차단 취소 성공"),
@ApiResponse(responseCode = "400", description = "잘못된 요청 값"),
@ApiResponse(responseCode = "401", description = "헤더 없음 or 토큰 불일치", content = @Content(schema = @Schema(example = "INVALID_HEADER or INVALID_TOKEN")))
})
@PostMapping("/cancel-blocked")
public RspTemplate<String> cancelBlockedMember(@AuthenticationPrincipal Member member,
@Valid @RequestBody BlockedMemberReqDto blockedMemberReqDto) {
blockedMemberService.cancelBlockedMember(member, blockedMemberReqDto);
return new RspTemplate<>(HttpStatus.OK, "유저 차단 취소 완료");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.example.copro.member.api.dto.request;

import jakarta.validation.constraints.NotNull;

public record BlockedMemberReqDto(
@NotNull
Long blockedMemberId
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.example.copro.member.application;

import com.example.copro.member.api.dto.request.BlockedMemberReqDto;
import com.example.copro.member.domain.Member;
import com.example.copro.member.domain.repository.BlockedMemberMappingRepository;
import com.example.copro.member.domain.repository.MemberRepository;
import com.example.copro.member.exception.ExistsBlockedMemberException;
import com.example.copro.member.exception.MemberNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(readOnly = true)
public class BlockedMemberService {
private final BlockedMemberMappingRepository blockedMemberMappingRepository;
private final MemberRepository memberRepository;

public BlockedMemberService(BlockedMemberMappingRepository blockedMemberMappingRepository,
MemberRepository memberRepository) {
this.blockedMemberMappingRepository = blockedMemberMappingRepository;
this.memberRepository = memberRepository;
}

@Transactional
public void addBlockedMember(Member member, BlockedMemberReqDto blockedMemberReqDto) {
Member getMember = memberRepository.findById(member.getMemberId()).orElseThrow(MemberNotFoundException::new);
Member blockedMember = memberRepository.findById(blockedMemberReqDto.blockedMemberId()).orElseThrow(MemberNotFoundException::new);

validateExistsBlockedMember(getMember, blockedMember);

getMember.addBlockedMember(blockedMember);
memberRepository.save(getMember);
}

private void validateExistsBlockedMember(Member member, Member blockedMember) {
if (blockedMemberMappingRepository.existsByMemberAndBlockedMember(member, blockedMember)) {
throw new ExistsBlockedMemberException();
}
}

@Transactional
public void cancelBlockedMember(Member member, BlockedMemberReqDto blockedMemberReqDto) {
Member getMember = memberRepository.findById(member.getMemberId()).orElseThrow(MemberNotFoundException::new);
Member blockedMember = memberRepository.findById(blockedMemberReqDto.blockedMemberId()).orElseThrow(MemberNotFoundException::new);

getMember.cancelBlockedMember(blockedMember);
memberRepository.save(getMember);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.example.copro.member.domain;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class BlockedMemberMapping {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@JoinColumn(name = "member_id")
private Member member;

@ManyToOne
@JoinColumn(name = "blocked_member_id")
private Member blockedMember;

public BlockedMemberMapping(Member member, Member blockedMember) {
this.member = member;
this.blockedMember = blockedMember;
}
}
20 changes: 20 additions & 0 deletions src/main/java/com/example/copro/member/domain/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ public class Member {
@OneToMany(mappedBy = "member", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<MemberLike> memberLikes = new ArrayList<>();

@OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
private List<BlockedMemberMapping> blockedMemberMappings = new ArrayList<>();

@Builder
private Member(Role role, String email, String name, String picture, SocialType socialType, boolean firstLogin, int career, int viewType) {
this.role = role;
Expand Down Expand Up @@ -193,6 +196,23 @@ private MemberScrapBoard findScrapBoard(Board board) {
.orElse(null);
}

public void addBlockedMember(Member blockedMember) {
BlockedMemberMapping blockedMemberMapping = new BlockedMemberMapping(this, blockedMember);
this.blockedMemberMappings.add(blockedMemberMapping);
}

public void cancelBlockedMember(Member blockedMember) {
BlockedMemberMapping blockedMemberMapping = findBlockedMember(blockedMember);
this.blockedMemberMappings.remove(blockedMemberMapping);
}

private BlockedMemberMapping findBlockedMember(Member blockedMember) {
return blockedMemberMappings.stream()
.filter(blockedMemberMapping -> blockedMemberMapping.getBlockedMember().equals(blockedMember))
.findFirst()
.orElse(null);
}

public void updateImage(String picture) {
this.picture = picture;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.copro.member.domain.repository;

import com.example.copro.member.domain.BlockedMemberMapping;
import com.example.copro.member.domain.Member;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface BlockedMemberMappingRepository extends JpaRepository<BlockedMemberMapping, Long> {
Page<BlockedMemberMapping> findByMember(Member member, Pageable pageable);
boolean existsByMemberAndBlockedMember(Member member, Member blockedMember);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.copro.member.exception;

import com.example.copro.global.error.exception.InvalidGroupException;

public class ExistsBlockedMemberException extends InvalidGroupException {
public ExistsBlockedMemberException(String message) {
super(message);
}

public ExistsBlockedMemberException() {
this("이미 차단 목록에 추가 되었습니다.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.example.copro.member.api.dto.response.MemberLikeResDto;
import com.example.copro.member.domain.Member;
import com.example.copro.member.mypage.api.dto.request.UpdateViewTypeReqDto;
import com.example.copro.member.mypage.api.dto.response.BlockedMemberResDto;
import com.example.copro.member.mypage.api.dto.response.DeleteAccountResDto;
import com.example.copro.member.mypage.api.dto.response.MyProfileInfoResDto;
import com.example.copro.member.mypage.api.dto.response.MyScrapBoardsResDto;
Expand Down Expand Up @@ -62,6 +63,19 @@ public RspTemplate<Page<MemberLikeResDto>> memberLikeList(@AuthenticationPrincip
return new RspTemplate<>(HttpStatus.OK, "내 관심 프로필 목록", memberLikeResDtos);
}

@Operation(summary = "내 차단 유저 목록 ", description = "본인이 차단한 유저의 목록을 불러옵니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "차단한 유저 불러오기 성공"),
@ApiResponse(responseCode = "401", description = "헤더 없음 or 토큰 불일치", content = @Content(schema = @Schema(example = "INVALID_HEADER or INVALID_TOKEN")))
})
@GetMapping("/blocked")
public RspTemplate<Page<BlockedMemberResDto>> blockedMemberList(@AuthenticationPrincipal Member member,
@RequestParam(value = "page", defaultValue = "0") int page,
@RequestParam(value = "size", defaultValue = "10") int size) {
Page<BlockedMemberResDto> blockedMemberResDtos = myPageService.blockedMemberList(member, page, size);
return new RspTemplate<>(HttpStatus.OK, "내 차단 유저 목록", blockedMemberResDtos);
}

@Operation(summary = "내 관심 게시물 목록", description = "내 관심 게시물 목록을 불러옵니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "내 관심 게시물 불러오기 성공"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.example.copro.member.mypage.api.dto.response;

import com.example.copro.member.domain.BlockedMemberMapping;
import lombok.Builder;

@Builder
public record BlockedMemberResDto(
Long blockedMemberId,
String name,
String email,
String picture,
String occupation,
String language,
int career,
String gitHubUrl,
boolean isBlocked
) {
public static BlockedMemberResDto of (BlockedMemberMapping blockedMemberMapping, boolean isBlocked) {
return BlockedMemberResDto.builder()
.blockedMemberId(blockedMemberMapping.getBlockedMember().getMemberId())
.name(blockedMemberMapping.getBlockedMember().getNickName())
.email(blockedMemberMapping.getBlockedMember().getEmail())
.picture(blockedMemberMapping.getBlockedMember().getPicture())
.occupation(blockedMemberMapping.getBlockedMember().getOccupation())
.language(blockedMemberMapping.getBlockedMember().getLanguage())
.career(blockedMemberMapping.getBlockedMember().getCareer())
.gitHubUrl(blockedMemberMapping.getBlockedMember().getGitHubUrl())
.isBlocked(isBlocked)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@
import com.example.copro.comment.domain.Comment;
import com.example.copro.comment.domain.repository.CommentRepository;
import com.example.copro.member.api.dto.response.MemberLikeResDto;
import com.example.copro.member.domain.BlockedMemberMapping;
import com.example.copro.member.domain.Member;
import com.example.copro.member.domain.MemberLike;
import com.example.copro.member.domain.MemberScrapBoard;
import com.example.copro.member.domain.repository.BlockedMemberMappingRepository;
import com.example.copro.member.domain.repository.MemberLikeRepository;
import com.example.copro.member.domain.repository.MemberRepository;
import com.example.copro.member.domain.repository.MemberScrapBoardRepository;
import com.example.copro.member.exception.MemberNotFoundException;
import com.example.copro.member.mypage.api.dto.request.UpdateViewTypeReqDto;
import com.example.copro.member.mypage.api.dto.response.BlockedMemberResDto;
import com.example.copro.member.mypage.api.dto.response.DeleteAccountResDto;
import com.example.copro.member.mypage.api.dto.response.MyProfileInfoResDto;
import com.example.copro.member.mypage.api.dto.response.MyScrapBoardsResDto;
Expand All @@ -33,6 +36,7 @@ public class MyPageService {
private final MemberScrapBoardRepository memberScrapBoardRepository;
private final MemberLikeRepository memberLikeRepository;
private final CommentRepository commentRepository;
private final BlockedMemberMappingRepository blockedMemberMappingRepository;

// 본인 프로필 정보
public MyProfileInfoResDto myProfileInfo(Member member) {
Expand All @@ -57,6 +61,21 @@ private MemberLikeResDto mapToMemberLike(Member member, MemberLike memberLike) {
return MemberLikeResDto.of(memberLike, isLike, likeMembersCount);
}

// 내 차단 사용자 목록
public Page<BlockedMemberResDto> blockedMemberList(Member member, int page, int size) {
Page<BlockedMemberMapping> blockedMembers = blockedMemberMappingRepository
.findByMember(member, PageRequest.of(page, size));

return blockedMembers.map(blockedMemberMapping -> mapToBlockedMember(member, blockedMemberMapping));
}

private BlockedMemberResDto mapToBlockedMember(Member member, BlockedMemberMapping blockedMemberMapping) {
boolean isBlocked = blockedMemberMappingRepository
.existsByMemberAndBlockedMember(member, blockedMemberMapping.getBlockedMember());

return BlockedMemberResDto.of(blockedMemberMapping, isBlocked);
}

// 내 관심 게시물 목록
public Page<MyScrapBoardsResDto> boardLikeList(Member member, int page, int size) {
Page<MemberScrapBoard> boards = memberScrapBoardRepository.findByMember(member, PageRequest.of(page, size));
Expand Down
Loading

0 comments on commit ff862a6

Please sign in to comment.