-
Notifications
You must be signed in to change notification settings - Fork 4
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/CK-240] 골룸 관련 부분 의존성 리팩토링을 한다 #207
Merged
Merged
Changes from 6 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
b58e6db
refactor: GoalRoom 관련 패키지 의존성 분리
miseongk 1d3c2b6
refactor: 리뷰 반영 및 골룸 생성 로직 변경
miseongk 8081ae4
feat: GoalRoom과 GoalRoomMember, GoalRoomPendingMember의 양방향 의존성 제거
miseongk c36adf9
feat: 골룸 생성 시 리더 업데이트하는 로직 이벤트 분리
miseongk 4aa6c86
feat: 골룸 나갈 때 빈 골룸을 삭제하는 로직 이벤트 분리
miseongk 838c213
feat: 인증피드 등록 시 달성률 업데이트 로직 이벤트 분리
miseongk 343c6d1
refactor: 요구 사항 반영 (DashBoardCheckFeedService)
miseongk 127df8e
refactor: CheckFeed 생성 시 달성률 업데이트 이벤트 네이밍 변경
miseongk 660af6f
refactor: 골룸 생성, 나가기 이벤트 네이밍 변경
miseongk a18c81a
feat: 골룸 참여 시, 골룸 펜딩 멤버 테이블에 락이 걸리도록 수정
miseongk 731c8a4
refactor: 골룸 시작, 나가기 쿼리 수정
miseongk c30ea37
chore: merge conflict 해결
miseongk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
45 changes: 45 additions & 0 deletions
45
.../kirikiri/src/main/java/co/kirikiri/checkfeed/controller/GoalRoomCheckFeedController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package co.kirikiri.checkfeed.controller; | ||
|
||
import co.kirikiri.checkfeed.service.GoalRoomCheckFeedService; | ||
import co.kirikiri.checkfeed.service.dto.request.CheckFeedRequest; | ||
import co.kirikiri.checkfeed.service.dto.response.GoalRoomCheckFeedResponse; | ||
import co.kirikiri.common.interceptor.Authenticated; | ||
import co.kirikiri.common.resolver.MemberIdentifier; | ||
import java.net.URI; | ||
import java.util.List; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.ModelAttribute; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
@RequestMapping("/goal-rooms/{goalRoomId}/checkFeeds") | ||
@RequiredArgsConstructor | ||
public class GoalRoomCheckFeedController { | ||
|
||
private final GoalRoomCheckFeedService goalRoomCheckFeedService; | ||
|
||
@PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}) | ||
@Authenticated | ||
public ResponseEntity<Void> createCheckFeed(@MemberIdentifier final String identifier, | ||
@PathVariable("goalRoomId") final Long goalRoomId, | ||
@ModelAttribute final CheckFeedRequest checkFeedRequest) { | ||
final String imageUrl = goalRoomCheckFeedService.createCheckFeed(identifier, goalRoomId, checkFeedRequest); | ||
return ResponseEntity.created(URI.create(imageUrl)).build(); | ||
} | ||
|
||
@GetMapping | ||
@Authenticated | ||
public ResponseEntity<List<GoalRoomCheckFeedResponse>> findGoalRoomCheckFeeds( | ||
@MemberIdentifier final String identifier, | ||
@PathVariable("goalRoomId") final Long goalRoomId) { | ||
final List<GoalRoomCheckFeedResponse> response = goalRoomCheckFeedService.findGoalRoomCheckFeeds(identifier, | ||
goalRoomId); | ||
return ResponseEntity.ok(response); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
backend/kirikiri/src/main/java/co/kirikiri/checkfeed/persistence/CheckFeedRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package co.kirikiri.checkfeed.persistence; | ||
|
||
import co.kirikiri.checkfeed.domain.CheckFeed; | ||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.jpa.repository.Query; | ||
import org.springframework.data.repository.query.Param; | ||
|
||
public interface CheckFeedRepository extends JpaRepository<CheckFeed, Long> { | ||
|
||
@Query("SELECT cf" | ||
+ " FROM CheckFeed cf" | ||
+ " WHERE cf.goalRoomMemberId = :goalRoomMemberId" | ||
+ " AND cf.createdAt >= :start" | ||
+ " AND cf.createdAt < :end") | ||
Optional<CheckFeed> findByGoalRoomMemberIdAndDateTime(final Long goalRoomMemberId, final LocalDateTime start, | ||
final LocalDateTime end); | ||
|
||
@Query("SELECT COUNT(cf)" | ||
+ " FROM CheckFeed cf" | ||
+ " WHERE cf.goalRoomMemberId = :goalRoomMemberId" | ||
+ " AND cf.goalRoomRoadmapNodeId = :goalRoomRoadmapNodeId") | ||
int countByGoalRoomMemberIdAndGoalRoomRoadmapNodeId(final Long goalRoomMemberId, final Long goalRoomRoadmapNodeId); | ||
|
||
@Query(value = "SELECT cf.* FROM check_feed as cf " | ||
+ "LEFT JOIN goal_room_member as gm ON cf.goal_room_member_id = gm.id " | ||
+ "JOIN goal_room as g ON gm.goal_room_id = g.id " | ||
+ "WHERE g.id = :goalRoomId " | ||
+ "ORDER BY cf.created_at DESC ", nativeQuery = true) | ||
List<CheckFeed> findByGoalRoomIdOrderByCreatedAtDesc(@Param("goalRoomId") final Long goalRoomId); | ||
|
||
List<CheckFeed> findByGoalRoomRoadmapNodeIdOrderByCreatedAtDesc(final Long goalRoomRoadmapNodeId); | ||
} |
51 changes: 51 additions & 0 deletions
51
...ri/src/main/java/co/kirikiri/checkfeed/service/AccomplishmentRateUpdateEventListener.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package co.kirikiri.checkfeed.service; | ||
|
||
import co.kirikiri.checkfeed.service.event.AccomplishmentRateUpdateEvent; | ||
import co.kirikiri.common.aop.ExceptionConvert; | ||
import co.kirikiri.common.exception.NotFoundException; | ||
import co.kirikiri.goalroom.domain.GoalRoom; | ||
import co.kirikiri.goalroom.domain.GoalRoomMember; | ||
import co.kirikiri.goalroom.persistence.GoalRoomMemberRepository; | ||
import co.kirikiri.goalroom.persistence.GoalRoomRepository; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import org.springframework.transaction.event.TransactionPhase; | ||
import org.springframework.transaction.event.TransactionalEventListener; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
@ExceptionConvert | ||
public class AccomplishmentRateUpdateEventListener { | ||
|
||
private final GoalRoomRepository goalRoomRepository; | ||
private final GoalRoomMemberRepository goalRoomMemberRepository; | ||
|
||
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) | ||
@Transactional | ||
public void handleUpdateAccomplishmentRate(final AccomplishmentRateUpdateEvent accomplishmentRateUpdateEvent) { | ||
final GoalRoom goalRoom = findGoalRoomById(accomplishmentRateUpdateEvent.goalRoomId()); | ||
final GoalRoomMember goalRoomMember = findGoalRoomMemberById(accomplishmentRateUpdateEvent.goalRoomMemberId()); | ||
|
||
updateAccomplishmentRate(goalRoom, goalRoomMember, accomplishmentRateUpdateEvent.pastCheckCount()); | ||
} | ||
|
||
private GoalRoom findGoalRoomById(final Long goalRoomId) { | ||
return goalRoomRepository.findById(goalRoomId) | ||
.orElseThrow(() -> new NotFoundException("존재하지 않는 골룸입니다.")); | ||
} | ||
|
||
private GoalRoomMember findGoalRoomMemberById(final Long goalRoomMemberId) { | ||
return goalRoomMemberRepository.findById(goalRoomMemberId) | ||
.orElseThrow(() -> new NotFoundException("존재하지 않는 골룸 멤버입니다.")); | ||
} | ||
|
||
private void updateAccomplishmentRate(final GoalRoom goalRoom, final GoalRoomMember goalRoomMember, | ||
final int pastCheckCount) { | ||
final int wholeCheckCount = goalRoom.getAllCheckCount(); | ||
final int memberCheckCount = pastCheckCount + 1; | ||
final Double accomplishmentRate = 100 * memberCheckCount / (double) wholeCheckCount; | ||
|
||
goalRoomMember.updateAccomplishmentRate(accomplishmentRate); | ||
} | ||
} |
60 changes: 60 additions & 0 deletions
60
...d/kirikiri/src/main/java/co/kirikiri/checkfeed/service/DashBoardCheckFeedServiceImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package co.kirikiri.checkfeed.service; | ||
|
||
import co.kirikiri.checkfeed.domain.CheckFeed; | ||
import co.kirikiri.checkfeed.persistence.CheckFeedRepository; | ||
import co.kirikiri.common.aop.ExceptionConvert; | ||
import co.kirikiri.common.service.FileService; | ||
import co.kirikiri.goalroom.domain.GoalRoom; | ||
import co.kirikiri.goalroom.domain.GoalRoomRoadmapNode; | ||
import co.kirikiri.goalroom.service.DashBoardCheckFeedService; | ||
import co.kirikiri.goalroom.service.dto.response.DashBoardCheckFeedResponse; | ||
import java.net.URL; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.HttpMethod; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
@Transactional | ||
@RequiredArgsConstructor | ||
@ExceptionConvert | ||
public class DashBoardCheckFeedServiceImpl implements DashBoardCheckFeedService { | ||
|
||
private final CheckFeedRepository checkFeedRepository; | ||
private final FileService fileService; | ||
|
||
@Override | ||
@Transactional(readOnly = true) | ||
public List<DashBoardCheckFeedResponse> findCheckFeedsByNodeAndGoalRoomStatus(final GoalRoom goalRoom, | ||
final Optional<GoalRoomRoadmapNode> currentGoalRoomRoadmapNode) { | ||
final List<CheckFeed> checkFeeds = findCheckFeeds(goalRoom, currentGoalRoomRoadmapNode); | ||
return makeCheckFeedResponses(checkFeeds); | ||
} | ||
|
||
private List<CheckFeed> findCheckFeeds(final GoalRoom goalRoom, | ||
final Optional<GoalRoomRoadmapNode> currentGoalRoomRoadmapNode) { | ||
if (goalRoom.isCompleted()) { | ||
return checkFeedRepository.findByGoalRoomIdOrderByCreatedAtDesc(goalRoom.getId()); | ||
} | ||
if (goalRoom.isRunning() && currentGoalRoomRoadmapNode.isPresent()) { | ||
return checkFeedRepository.findByGoalRoomRoadmapNodeIdOrderByCreatedAtDesc( | ||
currentGoalRoomRoadmapNode.get().getId()); | ||
} | ||
return Collections.emptyList(); | ||
} | ||
|
||
private List<DashBoardCheckFeedResponse> makeCheckFeedResponses(final List<CheckFeed> checkFeeds) { | ||
return checkFeeds.stream() | ||
.map(this::makeCheckFeedResponse) | ||
.toList(); | ||
} | ||
|
||
private DashBoardCheckFeedResponse makeCheckFeedResponse(final CheckFeed checkFeed) { | ||
final URL checkFeedImageUrl = fileService.generateUrl(checkFeed.getServerFilePath(), HttpMethod.GET); | ||
return new DashBoardCheckFeedResponse(checkFeed.getId(), checkFeedImageUrl.toExternalForm(), | ||
checkFeed.getDescription(), checkFeed.getCreatedAt().toLocalDate()); | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이벤트랑 이벤트 리스너 자체에 무엇을 할지 들어나있는거 같아요! 이벤트는 단순히 인증피드 등록을 한다는 것을 발행하고 그것을 Listen 하는 쪽에서 구체적인 행위를 하면 좋을 것 같네요.
https://techblog.woowahan.com/7835/
위 링크의
무엇을 이벤트로 발행할 것인가?
부분 읽어보시면 좋을 것 같아요!There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오 그렇군요!
이벤트 자체에 의도를 담으면 개념적인 결합도는 아직 높은 상태인 것이군요!
덕분에 아주 중요한 것을 깨달았어요 👍👍
이벤트에 의도가 드러나지 않게 모두 수정하겠습니다!