diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/board/controller/BoardController.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/board/controller/BoardController.java new file mode 100644 index 0000000..373cc77 --- /dev/null +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/board/controller/BoardController.java @@ -0,0 +1,49 @@ +package kr.hs.dgsw.SOPO_server_v2.domain.board.controller; + +import kr.hs.dgsw.SOPO_server_v2.domain.board.dto.BoardLoadRes; +import kr.hs.dgsw.SOPO_server_v2.domain.board.dto.BoardUpdateReq; +import kr.hs.dgsw.SOPO_server_v2.domain.board.service.BoardService; +import kr.hs.dgsw.SOPO_server_v2.global.response.Response; +import kr.hs.dgsw.SOPO_server_v2.global.response.ResponseData; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/board") +@RequiredArgsConstructor +public class BoardController { + private final BoardService boardService; + + @GetMapping("/all") + public ResponseData> getBoards() { + return boardService.getBoards(); + } + + @PostMapping + public ResponseData createBoard() { + return boardService.createBoard(); + } + + @GetMapping + public ResponseData getBoard(Long boardId) { + return boardService.findOneBoard(boardId); + } + + @PatchMapping + public Response loadBoard(Long boardId, BoardUpdateReq updateReq) { + return boardService.loadBoard(boardId, updateReq); + } + + @DeleteMapping + public Response deleteBoard(Long boardId) { + return boardService.deleteBoard(boardId); + } + +} diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/board/repository/BoardRepository.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/board/repository/BoardRepository.java new file mode 100644 index 0000000..596f585 --- /dev/null +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/board/repository/BoardRepository.java @@ -0,0 +1,9 @@ +package kr.hs.dgsw.SOPO_server_v2.domain.board.repository; + +import kr.hs.dgsw.SOPO_server_v2.domain.board.entity.BoardEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface BoardRepository extends JpaRepository { +} diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/board/service/BoardService.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/board/service/BoardService.java new file mode 100644 index 0000000..af45ad0 --- /dev/null +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/board/service/BoardService.java @@ -0,0 +1,95 @@ +package kr.hs.dgsw.SOPO_server_v2.domain.board.service; + +import jakarta.transaction.Transactional; +import kr.hs.dgsw.SOPO_server_v2.domain.board.dto.BoardLoadRes; +import kr.hs.dgsw.SOPO_server_v2.domain.board.dto.BoardUpdateReq; +import kr.hs.dgsw.SOPO_server_v2.domain.board.entity.BoardEntity; +import kr.hs.dgsw.SOPO_server_v2.domain.board.repository.BoardRepository; +import kr.hs.dgsw.SOPO_server_v2.domain.member.entity.MemberEntity; +import kr.hs.dgsw.SOPO_server_v2.domain.member.enums.MemberCategory; +import kr.hs.dgsw.SOPO_server_v2.global.error.custom.board.BoardNotFound; +import kr.hs.dgsw.SOPO_server_v2.global.error.custom.member.MemberNotCoincideException; +import kr.hs.dgsw.SOPO_server_v2.global.infra.security.GetCurrentMember; +import kr.hs.dgsw.SOPO_server_v2.global.response.ResponseData; +import kr.hs.dgsw.SOPO_server_v2.global.response.Response; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Transactional +@RequiredArgsConstructor +public class BoardService { + + private final BoardRepository boardRepository; + private final GetCurrentMember getCurrentMember; + + // 게시글 전체 조회 + public ResponseData> getBoards() { + List boardList = boardRepository.findAll(); + List boardLoadResList = boardList.stream().map( + BoardLoadRes::of + ).toList(); + + return ResponseData.of(HttpStatus.OK, "게시물 전체 조회 완료", boardLoadResList); + } + + // 빈 게시글 생성 + public ResponseData createBoard() { + MemberEntity curMember = getCurrentMember.current(); + + BoardEntity board = BoardEntity.builder() + .boardTitle(null) + .boardContent(null) + .file(null) + .member(curMember) + .build(); + + return ResponseData.of(HttpStatus.OK, "빈 게시물 생성 완료", board.getBoardId()); + } + + // 게시글 업데이트 + public Response loadBoard(Long boardId, BoardUpdateReq updateReq) { + MemberEntity curMember = getCurrentMember.current(); + + BoardEntity board = boardRepository.findById(boardId) + .orElseThrow(() -> BoardNotFound.EXCEPTION); + + // 만약 현재 로그인 유저와 Load 하려는 유저가 다르고, admin 아니라면 + if (!board.getMember().getMemberId().equals(curMember.getMemberId()) && curMember.getMemberCategory() == MemberCategory.USER) { + throw MemberNotCoincideException.EXCEPTION; + } + + board.update(updateReq); + return Response.of(HttpStatus.OK, "게시물 업데이트 완료"); + } + + // 게시글 단일 조회 + public ResponseData findOneBoard(Long boardId) { + BoardEntity board = boardRepository.findById(boardId) + .orElseThrow(() -> BoardNotFound.EXCEPTION); + BoardLoadRes boardLoadRes = BoardLoadRes.of(board); + return ResponseData.of(HttpStatus.OK, "게시물 단일 조회 완료", boardLoadRes); + } + + // 게시글 삭제 + @Transactional + public Response deleteBoard(Long boardId) { + MemberEntity curMember = getCurrentMember.current(); + + BoardEntity board = boardRepository.findById(boardId) + .orElseThrow(() -> BoardNotFound.EXCEPTION); + + // 만약 만든 사람과 삭제하려는 사람이 일치하지 않고 admin 아니라면.. error + if (!board.getMember().getMemberId().equals(curMember.getMemberId()) && curMember.getMemberCategory() == MemberCategory.USER) { + throw MemberNotCoincideException.EXCEPTION; + } + + boardRepository.deleteById(boardId); + return Response.of(HttpStatus.OK, "게시물 삭제 완료"); + } + + +} \ No newline at end of file diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/comment/entity/CommentEntity.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/comment/entity/CommentEntity.java new file mode 100644 index 0000000..9a5adc7 --- /dev/null +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/comment/entity/CommentEntity.java @@ -0,0 +1,63 @@ +package kr.hs.dgsw.SOPO_server_v2.domain.comment.entity; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import kr.hs.dgsw.SOPO_server_v2.domain.board.entity.BoardEntity; +import kr.hs.dgsw.SOPO_server_v2.domain.member.entity.MemberEntity; +import kr.hs.dgsw.SOPO_server_v2.global.common.entity.BaseTimeEntity; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; +import org.hibernate.annotations.DynamicUpdate; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Entity +@Table(name = "tbl_comment") +@NoArgsConstructor +@DynamicUpdate +@ToString +@SuperBuilder +public class CommentEntity extends BaseTimeEntity { // 부모 + + // 댓글 아이디 + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "comment_id") + private Long commentId; + + // 댓글 내용 + @Column(name = "comment_content") + private String commentContent; + + // 자식 댓글 + @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true) + private List children = new ArrayList<>(); + + // 게시물 아이디 + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "board_id", nullable = false) + private BoardEntity board; + + // 유저 아이디 + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = false) + @OnDelete(action = OnDeleteAction.CASCADE) + private MemberEntity member; + + +} diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/comment/entity/SubCommentEntity.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/comment/entity/SubCommentEntity.java new file mode 100644 index 0000000..11c709d --- /dev/null +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/comment/entity/SubCommentEntity.java @@ -0,0 +1,46 @@ +package kr.hs.dgsw.SOPO_server_v2.domain.comment.entity; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import kr.hs.dgsw.SOPO_server_v2.domain.member.entity.MemberEntity; +import kr.hs.dgsw.SOPO_server_v2.global.common.entity.BaseTimeEntity; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.hibernate.annotations.DynamicUpdate; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; + +@Getter +@Entity +@Table(name = "tbl_sub_comment") +@NoArgsConstructor +@DynamicUpdate +@SuperBuilder +public class SubCommentEntity extends BaseTimeEntity { + + // 대댓글 아이디 + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long subCommentId; + + // 대댓글 내용 + private String content; + + // 부모 댓글 + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "parent_id") + private CommentEntity parent; + + // 유저 아이디 + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = false) + @OnDelete(action = OnDeleteAction.CASCADE) + private MemberEntity member; +} diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/contest/controller/ContestController.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/contest/controller/ContestController.java new file mode 100644 index 0000000..d44b80c --- /dev/null +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/contest/controller/ContestController.java @@ -0,0 +1,53 @@ +package kr.hs.dgsw.SOPO_server_v2.domain.contest.controller; + +import kr.hs.dgsw.SOPO_server_v2.domain.contest.dto.ContestLoadRes; +import kr.hs.dgsw.SOPO_server_v2.domain.contest.dto.ContestUpdateReq; +import kr.hs.dgsw.SOPO_server_v2.domain.contest.service.ContestService; +import kr.hs.dgsw.SOPO_server_v2.global.response.Response; +import kr.hs.dgsw.SOPO_server_v2.global.response.ResponseData; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/contest") +@RequiredArgsConstructor +public class ContestController { + private final ContestService contestService; + + @GetMapping("/all") + public ResponseData> getContests() { + return contestService.getContests(); + } + + @PostMapping + public ResponseData createContest() { + return contestService.createContest(); + } + + @GetMapping + public ResponseData getContest(Long contestId) { + return contestService.findOneContest(contestId); + } + + @PatchMapping + public Response loadContest(Long contestId, ContestUpdateReq updateReq) { + return contestService.loadContest(contestId, updateReq); + } + + @DeleteMapping + public Response deleteContest(Long contestId) { + return contestService.deleteContest(contestId); + } + + @PatchMapping("/state") + public Response changeContestState(Long contestId) { + return contestService.changeContestState(contestId); + } +} diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/contest/entity/ContestEntity.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/contest/entity/ContestEntity.java index 8b7e2f4..6aee5b3 100644 --- a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/contest/entity/ContestEntity.java +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/contest/entity/ContestEntity.java @@ -86,4 +86,11 @@ public void likeUpdate(int contestLikeCount) { this.contestLikeCount += contestLikeCount; } + public void stateUpdateActive() { + this.contestState = ContestState.ACTIVE; + } + + public void stateUpdateDisabled() { + this.contestState = ContestState.DISABLED; + } } diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/contest/repository/ContestRepository.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/contest/repository/ContestRepository.java new file mode 100644 index 0000000..67621a9 --- /dev/null +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/contest/repository/ContestRepository.java @@ -0,0 +1,9 @@ +package kr.hs.dgsw.SOPO_server_v2.domain.contest.repository; + +import kr.hs.dgsw.SOPO_server_v2.domain.contest.entity.ContestEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ContestRepository extends JpaRepository { +} diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/contest/service/ContestService.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/contest/service/ContestService.java new file mode 100644 index 0000000..152d46f --- /dev/null +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/contest/service/ContestService.java @@ -0,0 +1,114 @@ +package kr.hs.dgsw.SOPO_server_v2.domain.contest.service; + +import jakarta.transaction.Transactional; +import kr.hs.dgsw.SOPO_server_v2.domain.contest.dto.ContestLoadRes; +import kr.hs.dgsw.SOPO_server_v2.domain.contest.dto.ContestUpdateReq; +import kr.hs.dgsw.SOPO_server_v2.domain.contest.entity.ContestEntity; +import kr.hs.dgsw.SOPO_server_v2.domain.contest.enums.ContestState; +import kr.hs.dgsw.SOPO_server_v2.domain.contest.repository.ContestRepository; +import kr.hs.dgsw.SOPO_server_v2.domain.member.entity.MemberEntity; +import kr.hs.dgsw.SOPO_server_v2.domain.member.enums.MemberCategory; +import kr.hs.dgsw.SOPO_server_v2.global.error.custom.contest.ContestNotFound; +import kr.hs.dgsw.SOPO_server_v2.global.error.custom.member.MemberNotCoincideException; +import kr.hs.dgsw.SOPO_server_v2.global.infra.security.GetCurrentMember; +import kr.hs.dgsw.SOPO_server_v2.global.response.Response; +import kr.hs.dgsw.SOPO_server_v2.global.response.ResponseData; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Transactional +@RequiredArgsConstructor +public class ContestService { // 대회 전환 필요 -> ACTIVE + private final ContestRepository contestRepository; + private final GetCurrentMember getCurrentMember; + // 대회 전체 조회 + public ResponseData> getContests() { + List contestList = contestRepository.findAll(); + List contestLoadRes = contestList.stream().map( + ContestLoadRes :: of + ).toList(); + + return ResponseData.of(HttpStatus.OK, "대회 전체 조회 완료", contestLoadRes); + } + + // 빈 대회 생성 + public ResponseData createContest() { + + MemberEntity curMember = getCurrentMember.current(); + ContestEntity contest = ContestEntity.builder() + .member(curMember) + .build(); + return ResponseData.of(HttpStatus.OK, "대회 생성 완료", contest.getContestId()); + } + + // 대회 업데이트 + public Response loadContest(Long contestId, ContestUpdateReq updateReq) { + + MemberEntity curMember = getCurrentMember.current(); + + ContestEntity contest = contestRepository.findById(contestId) + .orElseThrow(() -> ContestNotFound.EXCEPTION); + + // 만약 현재 로그인 유저와 Load 하려는 유저가 다르다면 + if (!contest.getMember().getMemberId().equals(curMember.getMemberId()) && curMember.getMemberCategory() == MemberCategory.USER) { + throw MemberNotCoincideException.EXCEPTION; + } + + contest.update(updateReq); + + return Response.of(HttpStatus.OK, "대회 업데이트 완료"); + } + + // 대회 단일 조회 + public ResponseData findOneContest(Long contestId) { + + ContestEntity contest = contestRepository.findById(contestId) + .orElseThrow(() -> ContestNotFound.EXCEPTION); + + ContestLoadRes contestLoadRes = ContestLoadRes.of(contest); + + return ResponseData.of(HttpStatus.OK, "대회 조회 완료", contestLoadRes); + } + + // 대회 삭제 + public Response deleteContest(Long contestId) { + + MemberEntity curMember = getCurrentMember.current(); + + ContestEntity contest = contestRepository.findById(contestId) + .orElseThrow(() -> ContestNotFound.EXCEPTION); + + if (!contest.getMember().getMemberId().equals(curMember.getMemberId()) && curMember.getMemberCategory() == MemberCategory.USER) { + throw MemberNotCoincideException.EXCEPTION; + } + + contestRepository.deleteById(contestId); + return Response.of(HttpStatus.OK, "대회 삭제 완료"); + } + + // 대회 상태 변경 + public Response changeContestState(Long contestId) { + + MemberEntity curMember = getCurrentMember.current(); + + ContestEntity contest = contestRepository.findById(contestId) + .orElseThrow(() -> ContestNotFound.EXCEPTION); + + if (!contest.getMember().getMemberId().equals(curMember.getMemberId()) && curMember.getMemberCategory() == MemberCategory.USER) { + throw MemberNotCoincideException.EXCEPTION; + } + + if (contest.getContestState() == ContestState.ACTIVE) { + contest.stateUpdateDisabled(); + } else { + contest.stateUpdateActive(); + } + + return Response.of(HttpStatus.OK, "대회 상태 변경 성공!"); + } + +} diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/like/controller/LikeController.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/like/controller/LikeController.java new file mode 100644 index 0000000..2269eec --- /dev/null +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/like/controller/LikeController.java @@ -0,0 +1,23 @@ +package kr.hs.dgsw.SOPO_server_v2.domain.like.controller; + +import kr.hs.dgsw.SOPO_server_v2.domain.like.enums.LikeCategory; +import kr.hs.dgsw.SOPO_server_v2.domain.like.service.LikeService; +import kr.hs.dgsw.SOPO_server_v2.global.response.Response; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/like") +@RequiredArgsConstructor +public class LikeController { + private final LikeService likeService; + + @PatchMapping + public Response patch(@RequestParam Long id, @RequestParam LikeCategory category) { + return likeService.toggle(id, category); + } + +} diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/like/entity/LikeEntity.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/like/entity/LikeEntity.java new file mode 100644 index 0000000..de7caa7 --- /dev/null +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/like/entity/LikeEntity.java @@ -0,0 +1,50 @@ +package kr.hs.dgsw.SOPO_server_v2.domain.like.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import kr.hs.dgsw.SOPO_server_v2.domain.board.entity.BoardEntity; +import kr.hs.dgsw.SOPO_server_v2.domain.contest.entity.ContestEntity; +import kr.hs.dgsw.SOPO_server_v2.domain.like.enums.LikeCategory; +import kr.hs.dgsw.SOPO_server_v2.domain.member.entity.MemberEntity; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Entity(name = "tbl_like") +@Getter +@NoArgsConstructor +@SuperBuilder +public class LikeEntity { + + // 좋아요 idx + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long likeIdx; + + // 유저 idx + @ManyToOne() + @JoinColumn(name = "fk_member_id") + private MemberEntity member; // param으로 좋아요 타입 받기 + + // 좋아요 타입 + @Enumerated(EnumType.STRING) + private LikeCategory likeCategory; + + // 게시물 idx + @ManyToOne() + @JoinColumn(name = "fk_board_id") + private BoardEntity board; + + // 대회 idx + @ManyToOne() + @JoinColumn(name = "fk_contest_id") + private ContestEntity contest; + +} diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/like/enums/LikeCategory.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/like/enums/LikeCategory.java new file mode 100644 index 0000000..541a04f --- /dev/null +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/like/enums/LikeCategory.java @@ -0,0 +1,7 @@ +package kr.hs.dgsw.SOPO_server_v2.domain.like.enums; + +public enum LikeCategory { + BOARD, + CONTEST, + PROFILE +} diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/like/repository/LikeRepository.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/like/repository/LikeRepository.java new file mode 100644 index 0000000..133f190 --- /dev/null +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/like/repository/LikeRepository.java @@ -0,0 +1,14 @@ +package kr.hs.dgsw.SOPO_server_v2.domain.like.repository; + +import kr.hs.dgsw.SOPO_server_v2.domain.board.entity.BoardEntity; +import kr.hs.dgsw.SOPO_server_v2.domain.contest.entity.ContestEntity; +import kr.hs.dgsw.SOPO_server_v2.domain.like.entity.LikeEntity; +import kr.hs.dgsw.SOPO_server_v2.domain.member.entity.MemberEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface LikeRepository extends JpaRepository { + Optional findByMemberAndBoard(MemberEntity member, BoardEntity board); + Optional findByMemberAndContest(MemberEntity member, ContestEntity contest); +} diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/like/service/LikeService.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/like/service/LikeService.java new file mode 100644 index 0000000..236d0bb --- /dev/null +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/like/service/LikeService.java @@ -0,0 +1,97 @@ +package kr.hs.dgsw.SOPO_server_v2.domain.like.service; + +import jakarta.transaction.Transactional; +import kr.hs.dgsw.SOPO_server_v2.domain.board.entity.BoardEntity; +import kr.hs.dgsw.SOPO_server_v2.domain.board.repository.BoardRepository; +import kr.hs.dgsw.SOPO_server_v2.domain.contest.entity.ContestEntity; +import kr.hs.dgsw.SOPO_server_v2.domain.contest.repository.ContestRepository; +import kr.hs.dgsw.SOPO_server_v2.domain.like.entity.LikeEntity; +import kr.hs.dgsw.SOPO_server_v2.domain.like.enums.LikeCategory; +import kr.hs.dgsw.SOPO_server_v2.domain.like.repository.LikeRepository; +import kr.hs.dgsw.SOPO_server_v2.domain.member.entity.MemberEntity; +import kr.hs.dgsw.SOPO_server_v2.global.error.custom.board.BoardNotFound; +import kr.hs.dgsw.SOPO_server_v2.global.error.custom.contest.ContestNotFound; +import kr.hs.dgsw.SOPO_server_v2.global.infra.security.GetCurrentMember; +import kr.hs.dgsw.SOPO_server_v2.global.response.Response; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Service +@RequiredArgsConstructor +@Transactional +public class LikeService { + // 멤버 필요 + private final BoardRepository boardRepository; + private final ContestRepository contestRepository; + private final LikeRepository likeRepository; + private final GetCurrentMember getCurrentMember; + + public Response toggle(Long id, LikeCategory category) { + MemberEntity curMember = getCurrentMember.current(); + // 토큰 가져오기 + // 게시물 좋아요일 때 + if (category == LikeCategory.BOARD) { + BoardEntity board = boardRepository.findById(id) + .orElseThrow(() -> BoardNotFound.EXCEPTION); + + Optional like = likeRepository.findByMemberAndBoard(curMember, board); + + if (like.isEmpty()) { + addBoardLike(curMember, board); + board.likeUpdate(1); + } else { + boardRepository.delete(like.get().getBoard()); + board.likeUpdate(-1); + } + } + + // 대회 좋아요일 때 + else if (category == LikeCategory.CONTEST) { + // 토큰 가져오기 + ContestEntity contest = contestRepository.findById(id) + .orElseThrow( () -> ContestNotFound.EXCEPTION); + + Optional like = likeRepository.findByMemberAndContest(curMember, contest); + + if (like.isEmpty()) { + addContestLike(curMember, contest); + contest.likeUpdate(1); + } else { + contestRepository.delete(like.get().getContest()); + contest.likeUpdate(1); + } + } + + // else if (프로필) {} + + return Response.of(HttpStatus.OK, "좋아요 생성/취소 완료"); + + + + } + + private void addBoardLike(MemberEntity member, BoardEntity board) { + likeRepository.save( + LikeEntity.builder() + .board(board) + .member(member) + .likeCategory(LikeCategory.BOARD) + .build() + ); + } + + public void addContestLike(MemberEntity member, ContestEntity contest) { + likeRepository.save( + LikeEntity.builder() + .contest(contest) + .member(member) + .likeCategory(LikeCategory.CONTEST) + .build() + ); + } + + // 프로필 +} diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/presentation/controller/MemberController.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/presentation/controller/MemberController.java index f722937..f35610d 100644 --- a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/presentation/controller/MemberController.java +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/presentation/controller/MemberController.java @@ -14,17 +14,8 @@ @RequiredArgsConstructor public class MemberController { private final MemberService memberService; - private final MemberProfileService memberProfileService; - @PatchMapping("/profile") - public Response modifyMember( - @RequestBody MemberModifyReq memberModifyReq){ - return memberProfileService.memberModify(memberModifyReq); - } - @PatchMapping() - public Response deleteMember( - @RequestParam String memberId - ){ - return memberService.deleteMember(memberId); + public Response deleteMember(){ + return memberService.deleteMember(); } } diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/presentation/controller/MemberProfileController.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/presentation/controller/MemberProfileController.java new file mode 100644 index 0000000..1c5864d --- /dev/null +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/presentation/controller/MemberProfileController.java @@ -0,0 +1,31 @@ +package kr.hs.dgsw.SOPO_server_v2.domain.member.presentation.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import kr.hs.dgsw.SOPO_server_v2.domain.member.presentation.dto.req.MemberModifyReq; +import kr.hs.dgsw.SOPO_server_v2.domain.member.presentation.dto.res.ReadProfileRes; +import kr.hs.dgsw.SOPO_server_v2.domain.member.service.MemberProfileService; +import kr.hs.dgsw.SOPO_server_v2.global.response.Response; +import kr.hs.dgsw.SOPO_server_v2.global.response.ResponseData; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "Profile", description = "Profile Api") +@RestController +@RequestMapping(value = "/profile") +@RequiredArgsConstructor +public class MemberProfileController { + + private final MemberProfileService memberProfileService; + + @PatchMapping("") + public Response modifyMember( + @RequestBody MemberModifyReq memberModifyReq) { + return memberProfileService.memberModify(memberModifyReq); + } + + @GetMapping + public ResponseData loadProfile(){ + return memberProfileService.loadProfile(); + } +} + diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/presentation/dto/res/ReadProfileRes.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/presentation/dto/res/ReadProfileRes.java new file mode 100644 index 0000000..377fb08 --- /dev/null +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/presentation/dto/res/ReadProfileRes.java @@ -0,0 +1,19 @@ +package kr.hs.dgsw.SOPO_server_v2.domain.member.presentation.dto.res; + +import kr.hs.dgsw.SOPO_server_v2.domain.member.entity.MemberEntity; + +public record ReadProfileRes( + String memberId, + String memberName, + String memberEmail, + String memberSchool +) { + public static ReadProfileRes of(MemberEntity member){ + return new ReadProfileRes( + member.getMemberId(), + member.getMemberName(), + member.getMemberEmail(), + member.getMemberSchool() + ); + } +} diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/presentation/dto/res/loadProfileRes.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/presentation/dto/res/loadProfileRes.java deleted file mode 100644 index c7252ea..0000000 --- a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/presentation/dto/res/loadProfileRes.java +++ /dev/null @@ -1,8 +0,0 @@ -package kr.hs.dgsw.SOPO_server_v2.domain.member.presentation.dto.res; - -public record loadProfileRes( - String memberName, - String memberEmail - - ) { -} diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/service/MemberProfileService.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/service/MemberProfileService.java index d60916d..953f2e6 100644 --- a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/service/MemberProfileService.java +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/service/MemberProfileService.java @@ -3,11 +3,13 @@ import kr.hs.dgsw.SOPO_server_v2.domain.auth.service.AuthEmailService; import kr.hs.dgsw.SOPO_server_v2.domain.member.entity.MemberEntity; import kr.hs.dgsw.SOPO_server_v2.domain.member.presentation.dto.req.MemberModifyReq; +import kr.hs.dgsw.SOPO_server_v2.domain.member.presentation.dto.res.ReadProfileRes; import kr.hs.dgsw.SOPO_server_v2.domain.member.repository.MemberRepository; import kr.hs.dgsw.SOPO_server_v2.global.error.custom.email.CodeIsWrongException; import kr.hs.dgsw.SOPO_server_v2.global.error.custom.member.NeedAuthCode; import kr.hs.dgsw.SOPO_server_v2.global.infra.security.GetCurrentMember; import kr.hs.dgsw.SOPO_server_v2.global.response.Response; +import kr.hs.dgsw.SOPO_server_v2.global.response.ResponseData; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -53,7 +55,10 @@ public Response memberModify(MemberModifyReq memberModifyReq) { return Response.of(HttpStatus.OK, "성공"); } - public Response loadProfile(){ - return null; + @Transactional(rollbackFor = Exception.class) + public ResponseData loadProfile(){ + MemberEntity member = getCurrentMember.current(); + + return ResponseData.of(HttpStatus.OK, "조회 성공", ReadProfileRes.of(memberRepository.findByMemberId(member.getMemberId()))); } } diff --git a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/service/MemberService.java b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/service/MemberService.java index 6495ca3..e59b6a5 100644 --- a/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/service/MemberService.java +++ b/src/main/java/kr/hs/dgsw/SOPO_server_v2/domain/member/service/MemberService.java @@ -19,14 +19,9 @@ public class MemberService { private final GetCurrentMember getCurrentMember; @Transactional(rollbackFor = Exception.class) - public Response deleteMember(String memberId){ - MemberEntity member = memberRepository.findByMemberId(memberId); - - if (!getCurrentMember.current().equals(member)) - throw MemberNotCoincideException.EXCEPTION; - + public Response deleteMember(){ + MemberEntity member = getCurrentMember.current(); member.setMemberState(MemberState.DELETED); - return Response.of(HttpStatus.OK, "성공"); }