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

[Feat] 클라이밍 채널 권한 위임 / 참여자 독서 현황 조회 / 메모 수정 API #45

Merged
merged 13 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
import lombok.RequiredArgsConstructor;
import org.bookwoori.core.domain.climbing.dto.request.ClimbingChannelCreateRequestDto;
import org.bookwoori.core.domain.climbing.dto.request.ClimbingChannelUpdateRequestDto;
import org.bookwoori.core.domain.climbing.dto.request.ClimbingMemoUpdateRequestDto;
import org.bookwoori.core.domain.climbing.dto.request.ClimbingRoleDelegateRequestDto;
import org.bookwoori.core.domain.climbing.facade.ClimbingFacade;
import org.bookwoori.core.domain.climbing.facade.ClimbingMemberFacade;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -25,6 +28,7 @@
public class ClimbingController {

private final ClimbingFacade climbingFacade;
private final ClimbingMemberFacade climbingMemberFacade;

@Operation(summary = "클라이밍 채널 생성", description = "클라이밍 채널을 생성합니다.")
@PostMapping
Expand Down Expand Up @@ -62,5 +66,28 @@ public ResponseEntity<?> getClimbingDetails(
return ResponseEntity.ok(climbingFacade.getClimbingDetails(climbingId));
}

@Operation(summary = "클라이밍 채널 권한 위임", description = "클라이밍 채널의 OWNER가 권한을 위임합니다.")
@PatchMapping("/{climbingId}/members")
public ResponseEntity<?> delegateClimbingRole(
@PathVariable("climbingId") final Long climbingId,
@RequestBody ClimbingRoleDelegateRequestDto requestDto) {
climbingMemberFacade.delegateClimbingRole(climbingId, requestDto);
return ResponseEntity.ok().build();
}

@Operation(summary = "클라이밍 채널 참여자 조회", description = "클라이밍 채널 참여자 목록 / 참여자 독서 현황을 조회합니다.")
@GetMapping("/{climbingId}/members")
public ResponseEntity<?> getClimbingMembers(
@PathVariable("climbingId") final Long climbingId) {
return ResponseEntity.ok(climbingMemberFacade.getClimbingMembers(climbingId));
}

@Operation(summary = "클라이밍 채널 참여자 메모 수정", description = "클라이밍 채널 참여자의 메모를 수정합니다.")
@PatchMapping("/{climbingId}/members/memo")
public ResponseEntity<?> getClimbingMemberMemo(
gkdudans marked this conversation as resolved.
Show resolved Hide resolved
@PathVariable("climbingId") final Long climbingId,
@RequestBody @Valid ClimbingMemoUpdateRequestDto requestDto) {
climbingMemberFacade.updateClimbingMemberMemo(climbingId, requestDto);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.bookwoori.core.domain.climbing.dto.request;

import jakarta.validation.constraints.Size;

public record ClimbingMemoUpdateRequestDto(
@Size(max = 10, message = "INVALID_INPUT_LENGTH-메모는 10자 이내여야 합니다.")
String memo) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.bookwoori.core.domain.climbing.dto.request;

public record ClimbingRoleDelegateRequestDto(
Long memberId) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.bookwoori.core.domain.climbing.dto.response;

import org.bookwoori.core.domain.climbingMember.entity.ClimbingMember;
import org.bookwoori.core.domain.record.entity.ReadingStatus;

public record ClimbingMemberUnitDto(
Long memberId,
String profileImg,
int level,
String mountain,
ReadingStatus status,
int currentPage,
String memo
) {

public static ClimbingMemberUnitDto from(ClimbingMember member, ReadingStatus status,
int currentPage) {
return new ClimbingMemberUnitDto(
member.getMember().getMemberId(),
member.getMember().getProfileImg(),
member.getMember().getGrade().getLevel(),
member.getMember().getGrade().getMountain(),
status,
currentPage,
member.getMemo()
);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.bookwoori.core.domain.climbing.facade;

import java.time.LocalDate;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
Expand All @@ -12,14 +13,18 @@
import org.bookwoori.core.domain.climbing.entity.Climbing;
import org.bookwoori.core.domain.climbing.entity.ClimbingStatus;
import org.bookwoori.core.domain.climbing.service.ClimbingService;
import org.bookwoori.core.domain.climbingMember.entity.ClimbingMember;
import org.bookwoori.core.domain.climbingMember.entity.ClimbingRole;
import org.bookwoori.core.domain.climbingMember.service.ClimbingMemberService;
import org.bookwoori.core.domain.member.entity.Member;
import org.bookwoori.core.domain.member.service.MemberService;
import org.bookwoori.core.domain.record.entity.ReadingStatus;
import org.bookwoori.core.domain.record.service.RecordService;
import org.bookwoori.core.domain.server.entity.Server;
import org.bookwoori.core.domain.server.service.ServerService;
import org.bookwoori.core.global.exception.CustomException;
import org.bookwoori.core.global.exception.ErrorCode;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -33,6 +38,33 @@ public class ClimbingFacade {
private final ServerService serverService;
private final BookService bookService;
private final ClimbingMemberService climbingMemberService;
private final RecordService recordService;

@Scheduled(cron = "0 0 0 * * *")
public void updateClimbingStatus() {
LocalDate today = LocalDate.now();
List<Climbing> climbingList = climbingService.getAllClimbings();
for (Climbing climbing : climbingList) {
if (climbing.getStartDate().isAfter(today) && climbing.getEndDate()
.isAfter(today)) {
climbing.updateStatus(ClimbingStatus.RUNNING);
} else if (climbing.getEndDate().isBefore(today)) {
List<ClimbingMember> climbingMemberList = climbingMemberService.findMembersByClimbing(
climbing);
boolean allFinished = climbingMemberList.stream()
.allMatch(
member -> recordService.getClimbingMemberRecord(member, climbing.getBook())
.map(record -> record.getStatus() == ReadingStatus.FINISHED)
.orElse(false));
if (allFinished) {
climbing.updateStatus(ClimbingStatus.FINISHED);
} else {
climbing.updateStatus(ClimbingStatus.FAILED);
}
}
climbingService.saveClimbingChannel(climbing);
}
}

public void createClimbing(ClimbingChannelCreateRequestDto requestDto) {
Member currentMember = memberService.getCurrentMember();
Expand Down Expand Up @@ -60,6 +92,9 @@ public boolean toggleParticipation(Long climbingId) {
Climbing climbing = climbingService.getClimbingById(climbingId);
boolean isJoined = climbingMemberService.isJoined(currentMember, climbing);
if (isJoined) {
if (climbingMemberService.isOwner(currentMember, climbing)) {
throw new CustomException(ErrorCode.OWNER_CANNOT_LEAVE);
}
climbingMemberService.removeMember(currentMember, climbing);
return false;
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package org.bookwoori.core.domain.climbing.facade;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.bookwoori.core.domain.climbing.dto.request.ClimbingMemoUpdateRequestDto;
import org.bookwoori.core.domain.climbing.dto.request.ClimbingRoleDelegateRequestDto;
import org.bookwoori.core.domain.climbing.dto.response.ClimbingMemberUnitDto;
import org.bookwoori.core.domain.climbing.entity.Climbing;
import org.bookwoori.core.domain.climbing.service.ClimbingService;
import org.bookwoori.core.domain.climbingMember.entity.ClimbingMember;
import org.bookwoori.core.domain.climbingMember.service.ClimbingMemberService;
import org.bookwoori.core.domain.member.entity.Member;
import org.bookwoori.core.domain.member.service.MemberService;
import org.bookwoori.core.domain.record.entity.ReadingStatus;
import org.bookwoori.core.domain.record.entity.Record;
import org.bookwoori.core.domain.record.service.RecordService;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
@RequiredArgsConstructor
@Transactional
public class ClimbingMemberFacade {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💊 ClimbingMemberFacade를 따로 두지 않고 ClimbingFacade 하나로 처리해도 되지 않을까요? Server 도메인에서는 따로 구분하지 않았어서 말해봅니당

Copy link
Contributor Author

@gkdudans gkdudans Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ClimbingFacade가 너무 길어지기도 하고 Climbing 자체에 관련된 부분 / ClimbingMember 관련된 부분으로 나누어도 괜찮을 거 같아서 그렇게 만들었는데 하나로 합치는 게 좋을까욤


private final MemberService memberService;
private final ClimbingService climbingService;
private final ClimbingMemberService climbingMemberService;
private final RecordService recordService;

@Transactional(readOnly = true)
public List<ClimbingMemberUnitDto> getClimbingMembers(Long climbingId) {
gkdudans marked this conversation as resolved.
Show resolved Hide resolved
Climbing climbing = climbingService.getClimbingById(climbingId);
List<ClimbingMember> climbingMemberList = climbingMemberService.findMembersByClimbing(
gkdudans marked this conversation as resolved.
Show resolved Hide resolved
climbing);
return climbingMemberList.stream()
.map(member -> {
Optional<Record> record = recordService.getClimbingMemberRecord(member,
climbing.getBook());
ReadingStatus status = record.map(Record::getStatus).orElse(ReadingStatus.UNREAD);
int currentPage = record.map(Record::getCurrentPage).orElse(0);
return ClimbingMemberUnitDto.from(member, status, currentPage);
})
.collect(Collectors.toList());
}


public void updateClimbingMemberMemo(Long climbingId, ClimbingMemoUpdateRequestDto requestDto) {
Member currentMember = memberService.getCurrentMember();
gkdudans marked this conversation as resolved.
Show resolved Hide resolved
ClimbingMember climbingMember = climbingMemberService.findByMemberAndClimbing(currentMember,
climbingId);
climbingMember.updateMemo(requestDto.memo());
}

public void delegateClimbingRole(Long climbingId, ClimbingRoleDelegateRequestDto requestDto) {
Member currentMember = memberService.getCurrentMember();
Member newOwner = memberService.getMemberById(requestDto.memberId());
climbingMemberService.delegateClimbingRole(climbingId, currentMember, newOwner);
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package org.bookwoori.core.domain.climbing.service;

import java.time.LocalDate;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.bookwoori.core.domain.climbing.entity.Climbing;
import org.bookwoori.core.domain.climbing.entity.ClimbingStatus;
import org.bookwoori.core.domain.climbing.repository.ClimbingRepository;
import org.bookwoori.core.domain.member.entity.Member;
import org.bookwoori.core.global.exception.CustomException;
import org.bookwoori.core.global.exception.ErrorCode;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -40,21 +37,9 @@ public List<Climbing> getReadyClimbings(Long serverId) {
return climbingRepository.findReadyClimbings(serverId);
}

@Scheduled(cron = "0 0 0 * * *")
public void updateClimbingStatus() {
LocalDate today = LocalDate.now();
List<Climbing> climbingList = climbingRepository.findAll();

for (Climbing climbing : climbingList) {
if (climbing.getStartDate().isAfter(today) && climbing.getEndDate()
.isAfter(today)) {
climbing.updateStatus(ClimbingStatus.RUNNING);
}
// } else if (climbing.getEndDate().isBefore(today)) {
// climbing.updateStatus(ClimbingStatus.COMPLETED);
// }
climbingRepository.save(climbing);
}
@Transactional(readOnly = true)
public List<Climbing> getAllClimbings() {
return climbingRepository.findAll();
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,12 @@ public ClimbingMember(Member member, Climbing climbing, ClimbingRole role) {
this.hasShared = false;
this.memo = null;
}

public void updateMemo(String memo) {
this.memo = memo;
}

public void updateRole(ClimbingRole climbingRole) {
this.role = climbingRole;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.bookwoori.core.domain.climbingMember.repository;

import java.util.List;
import java.util.Optional;
import org.bookwoori.core.domain.climbing.entity.Climbing;
import org.bookwoori.core.domain.climbingMember.entity.ClimbingMember;
Expand All @@ -13,4 +14,8 @@ public interface ClimbingMemberRepository extends JpaRepository<ClimbingMember,
boolean existsByMemberAndClimbing(Member member, Climbing climbing);

int countByClimbing(Climbing climbing);

List<ClimbingMember> findByClimbing(Climbing climbing);

Optional<ClimbingMember> findByMemberAndClimbing_ClimbingId(Member member, Long climbingId);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package org.bookwoori.core.domain.climbingMember.service;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.bookwoori.core.domain.climbing.entity.Climbing;
import org.bookwoori.core.domain.climbingMember.entity.ClimbingMember;
import org.bookwoori.core.domain.climbingMember.entity.ClimbingRole;
import org.bookwoori.core.domain.climbingMember.repository.ClimbingMemberRepository;
import org.bookwoori.core.domain.member.entity.Member;
import org.bookwoori.core.global.exception.CustomException;
import org.bookwoori.core.global.exception.ErrorCode;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -42,4 +45,26 @@ public boolean isOwner(Member member, Climbing climbing) {
public int getMemberCount(Climbing climbing) {
return climbingMemberRepository.countByClimbing(climbing);
}

@Transactional(readOnly = true)
public List<ClimbingMember> findMembersByClimbing(Climbing climbing) {
gkdudans marked this conversation as resolved.
Show resolved Hide resolved
return climbingMemberRepository.findByClimbing(climbing);
}

@Transactional(readOnly = true)
public ClimbingMember findByMemberAndClimbing(Member member, Long climbingId) {
return climbingMemberRepository.findByMemberAndClimbing_ClimbingId(member, climbingId)
.orElseThrow(() -> new CustomException(ErrorCode.CLIMBINGMEMBER_NOT_FOUND));
}

public void delegateClimbingRole(Long climbingId, Member currentMember,
Member newOwner) {
ClimbingMember currentClimbingMember = findByMemberAndClimbing(currentMember, climbingId);
ClimbingMember newClimbingOwner = findByMemberAndClimbing(newOwner, climbingId);
if (currentClimbingMember.getRole() != ClimbingRole.OWNER) {
throw new CustomException(ErrorCode.ACCESS_DENIED);
}
currentClimbingMember.updateRole(ClimbingRole.MEMBER);
newClimbingOwner.updateRole(ClimbingRole.OWNER);
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package org.bookwoori.core.domain.member.entity;

import jakarta.persistence.*;
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.Table;
import jakarta.validation.constraints.NotNull;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.bookwoori.core.global.BaseTimeEntity;
import org.bookwoori.core.global.s3.S3Util;
import org.springframework.web.multipart.MultipartFile;

@Entity
@Table(name = "member")
Expand Down Expand Up @@ -66,5 +71,4 @@ public void updateMember(String nickname, String profileImgUrl) {
this.nickname = nickname;
this.profileImg = profileImgUrl;
}

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package org.bookwoori.core.domain.record.entity;

import com.fasterxml.jackson.annotation.JsonCreator;
import org.bookwoori.core.domain.member.entity.Grade;
import org.bookwoori.core.global.exception.CustomException;
import org.bookwoori.core.global.exception.ErrorCode;

public enum ReadingStatus {
UNREAD,
WISH,
READING,
FINISHED;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package org.bookwoori.core.domain.record.repository;

import java.util.Optional;
import org.bookwoori.core.domain.book.entity.Book;
import org.bookwoori.core.domain.member.entity.Member;
import org.bookwoori.core.domain.record.entity.Record;
import org.springframework.data.jpa.repository.JpaRepository;

public interface RecordRepository extends JpaRepository<Record, Long> {

Optional<Record> findByMemberAndBook(Member climbingMember, Book book);
}
Loading