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

골 참여자 방출 기능 구현 #99

Merged
merged 32 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
d6df41a
refacotr: exception 클래스명 리네이밍
jhsseonn Mar 29, 2024
7440c2d
refacotr: exception 클래스명 리네이밍
jhsseonn Mar 29, 2024
ce65227
feat: 골 참여자 방출 기능 구현
jhsseonn Mar 29, 2024
8097b98
feat: 골 참여자 방출 컨트롤러 기능 구현
jhsseonn Mar 29, 2024
c69a1d4
feat: 방출한 사용자의 모든 스탬프 삭제 기능 구현
jhsseonn Mar 29, 2024
4ee2bd6
test: 골 팀 삭제했을 경우 삭제 상태가 거짓인지 반환하는 테스트 추가
jhsseonn Mar 29, 2024
04042d2
docs: api 문서 업데이트
jhsseonn Mar 29, 2024
0d8fe1d
refactor: 골 참여자 방출 api 형식 변경
jhsseonn Mar 29, 2024
3100d79
docs: api 문서 업데이트
jhsseonn Mar 29, 2024
5b4f9e0
docs: api 문서 업데이트
jhsseonn Mar 29, 2024
c3b55c5
docs: 논의사항 편집
jhsseonn Mar 29, 2024
157465a
refactor: 주석 제거
jhsseonn Apr 3, 2024
d070051
refactor: teams 팀원 제거 로직 수정
jhsseonn Apr 3, 2024
a3b8651
refactor: teams 팀원 제거 로직 수정
jhsseonn Apr 3, 2024
4996979
refactor: 골 참여자 방출 로직 수정
jhsseonn Apr 3, 2024
c8d2760
refactor: 골 참여자 방출 컨트롤러 로직 수정
jhsseonn Apr 3, 2024
1683ec2
refactor: 골 참여자 방출 메서드명 변경
jhsseonn Apr 3, 2024
4ca692c
refactor: 골 참여자 방출 메서드명 변경
jhsseonn Apr 3, 2024
07dc4bc
docs: api 문서 업데이트
jhsseonn Apr 3, 2024
c6517ad
refactor: #100 골 팀 골, 사용자 fk명 수정 (#101)
jhsseonn Mar 30, 2024
62ea675
ci: #89 Flyway 적용 (#95)
JJ503 Mar 31, 2024
42d3d58
docs: api 문서 업데이트
jhsseonn Mar 29, 2024
41c9d66
Merge branch 'develop' into feature/90
jhsseonn Apr 3, 2024
80fbb73
refactor: 골 참여자 방출시 hardDelete하도록 로직 변경
jhsseonn Apr 19, 2024
e3ff334
ci: 브랜치 최신화
jhsseonn Apr 19, 2024
13c9f2e
refactor: isDeletedFalse 삭제
jhsseonn May 3, 2024
560e6ca
refactor: 골 팀 hardDelete 로직 수정
jhsseonn May 6, 2024
80a9449
docs: api 문서 업데이트
jhsseonn May 6, 2024
f0daa20
docs: api 문서 업데이트
jhsseonn May 6, 2024
43a95f3
refactor: 테스트 필드명 변경
jhsseonn May 20, 2024
a8a8d1e
refactor: 객체 assertSotfly 외부에서 선언
jhsseonn May 20, 2024
4d35b0d
docs: api 문서 업데이트
jhsseonn May 20, 2024
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
6 changes: 6 additions & 0 deletions src/docs/asciidoc/goal.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,9 @@ operation::goal-controller-test/요청한_내용으로_골을_수정한다[snipp
operation::goal-controller-test/골_초대를_수락한다[snippets='http-request,path-parameters,request-headers']
==== 응답
operation::goal-controller-test/골_초대를_수락한다[snippets='http-response']

=== 골 참여자 방출
==== 요청
operation::goal-controller-test/골_참여자를_방출한다[snippets='http-request,path-parameters,request-headers']
==== 응답
operation::goal-controller-test/골_참여자를_방출한다[snippets='http-response']
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public enum ExceptionMessage {
INVALID_GOAL_DAYS("골 날짜 수가 범위 밖입니다.(범위: 1~100)"),
INVALID_USERS_SIZE("골 참여자 수가 범위 밖입니다.(범위: 1~5명)"),
INVALID_USER_TO_PARTICIPATE("골에 참여할 수 없는 사용자입니다. 골에는 친구인 사용자만 초대할 수 있습니다."),
INVALID_USER_TO_DELETE("골 참여자가 아닌 사용자는 삭제할 수 없습니다."),
READ_GOAL_FORBIDDEN("골을 조회할 권한이 없습니다."),
INVALID_GOAL_ACCEPT("초대받은 골이 아닙니다."),
INVALID_GOAL_ACCEPT_MANAGER("골 관리자는 골 초대 수락을 할 수 없습니다."),
Expand All @@ -61,6 +62,7 @@ public enum ExceptionMessage {
MANAGER_GOAL_ACCEPT_INVALID("골 관리자는 골 수락을 할 수 없습니다."),
NOT_FOUND_MANAGER("골의 관리자를 찾을 수 없습니다."),
FORBIDDEN_USER_TO_READ_GOAL("골을 조회할 권한이 없습니다."),
FORBIDDEN_USER_TO_DELETE_USER("골 참여자를 삭제할 권한이 없습니다."),

// 콕 찌르기
SENDER_NOT_IN_GOAL_TEAM("콕 찌르기 요청자가 해당 골의 팀원이 아닙니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
import com.backend.blooming.friend.application.exception.FriendAcceptanceForbiddenException;
import com.backend.blooming.friend.application.exception.FriendRequestNotAllowedException;
import com.backend.blooming.friend.application.exception.NotFoundFriendRequestException;
import com.backend.blooming.goal.application.exception.DeleteGoalForbiddenException;
import com.backend.blooming.goal.application.exception.ForbiddenGoalToDeleteException;
import com.backend.blooming.goal.application.exception.ForbiddenGoalToPokeException;
import com.backend.blooming.goal.application.exception.ForbiddenGoalToReadException;
import com.backend.blooming.goal.application.exception.InvalidGoalAcceptException;
import com.backend.blooming.goal.application.exception.InvalidGoalException;
import com.backend.blooming.goal.application.exception.NotFoundGoalException;
import com.backend.blooming.goal.application.exception.UpdateGoalForbiddenException;
import com.backend.blooming.goal.application.exception.ForbiddenGoalToUpdateException;
import com.backend.blooming.image.infrastructure.exception.UploadImageException;
import com.backend.blooming.notification.application.exception.NotFoundGoalManagerException;
import com.backend.blooming.report.application.exception.InvalidGoalReportException;
Expand Down Expand Up @@ -194,19 +194,19 @@ public ResponseEntity<ExceptionResponse> handleDeleteFriendForbiddenException(
.body(new ExceptionResponse(exception.getMessage()));
}

@ExceptionHandler(DeleteGoalForbiddenException.class)
@ExceptionHandler(ForbiddenGoalToDeleteException.class)
public ResponseEntity<ExceptionResponse> handleDeleteGoalForbiddenException(
final DeleteGoalForbiddenException exception, final HttpServletRequest request
final ForbiddenGoalToDeleteException exception, final HttpServletRequest request
) {
logWarn(exception, request);

return ResponseEntity.status(HttpStatus.FORBIDDEN)
.body(new ExceptionResponse(exception.getMessage()));
}

@ExceptionHandler(UpdateGoalForbiddenException.class)
@ExceptionHandler(ForbiddenGoalToUpdateException.class)
public ResponseEntity<ExceptionResponse> handleUpdateGoalForbiddenException(
final UpdateGoalForbiddenException exception, final HttpServletRequest request
final ForbiddenGoalToUpdateException exception, final HttpServletRequest request
) {
logWarn(exception, request);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
import com.backend.blooming.goal.application.exception.ForbiddenGoalToReadException;
import com.backend.blooming.goal.application.exception.InvalidGoalException;
import com.backend.blooming.goal.application.exception.NotFoundGoalException;
import com.backend.blooming.goal.application.exception.UpdateGoalForbiddenException;
import com.backend.blooming.goal.application.exception.ForbiddenGoalToUpdateException;
import com.backend.blooming.goal.domain.Goal;
import com.backend.blooming.goal.domain.GoalTeam;
import com.backend.blooming.goal.infrastructure.repository.GoalRepository;
import com.backend.blooming.notification.application.NotificationService;
import com.backend.blooming.stamp.application.StampService;
import com.backend.blooming.stamp.domain.Stamp;
import com.backend.blooming.stamp.infrastructure.repository.StampRepository;
import com.backend.blooming.user.application.exception.NotFoundUserException;
Expand All @@ -36,6 +37,7 @@ public class GoalService {
private final FriendRepository friendRepository;
private final StampRepository stampRepository;
private final NotificationService notificationService;
private final StampService stampService;

public Long createGoal(final CreateGoalDto createGoalDto) {
final List<User> users = getUsers(createGoalDto.teamUserIds());
Expand Down Expand Up @@ -139,7 +141,7 @@ public ReadGoalDetailDto update(final Long userId, final Long goalId, final Upda

private void validateUserToUpdate(final Goal goal, final Long userId) {
if (!goal.isManager(userId)) {
throw new UpdateGoalForbiddenException.ForbiddenUserToUpdate();
throw new ForbiddenGoalToUpdateException.ForbiddenUserToUpdateGoalToUpdate();
}
}

Expand Down Expand Up @@ -171,4 +173,11 @@ public void acceptGoalRequest(final Long userId, final Long goalId) {
final Goal goal = getGoal(goalId);
goal.updateAccepted(user);
}

public void deleteUser(final Long userId, final Long goalId, final Long managerId) {
Copy link
Member

Choose a reason for hiding this comment

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

managerId에 들어오는 값은 항상 매니저가 아니라고 생각합니다.
그래서 해당 변수를 userId로 하고, userId deleteUserId라고 하는 건 어떨까요?
이건 그냥 제안사항이기에 효선님께서 판단해 주시고 더 적절하다고 생각되는 것으로 수정해 주시면 됩니다!

Copy link
Member Author

Choose a reason for hiding this comment

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

좋습니다! managerId를 userId로 바꾸고 현 userId를 deleteUserId로 바꾸는 게 좋은 것 같네요!

final User user = getUser(userId);
final Goal goal = getGoal(goalId);
goal.deleteUser(user, managerId);
stampService.deleteAllByGoalIdAndUserId(goalId, userId);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.backend.blooming.goal.application.exception;

import com.backend.blooming.exception.BloomingException;
import com.backend.blooming.exception.ExceptionMessage;

public class ForbiddenGoalToDeleteException extends BloomingException {

private ForbiddenGoalToDeleteException(final ExceptionMessage exceptionMessage) {
super(exceptionMessage);
}

public static class ForbiddenUserToDeleteGoal extends ForbiddenGoalToDeleteException {

public ForbiddenUserToDeleteGoal() {
super(ExceptionMessage.DELETE_GOAL_FORBIDDEN);
}
}

public static class ForbiddenUserToDeleteUser extends ForbiddenGoalToDeleteException {

public ForbiddenUserToDeleteUser() {
super(ExceptionMessage.FORBIDDEN_USER_TO_DELETE_USER);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.backend.blooming.goal.application.exception;

import com.backend.blooming.exception.BloomingException;
import com.backend.blooming.exception.ExceptionMessage;

public class ForbiddenGoalToUpdateException extends BloomingException {

private ForbiddenGoalToUpdateException(final ExceptionMessage exceptionMessage) {
super(exceptionMessage);
}

public static class ForbiddenUserToUpdateGoalToUpdate extends ForbiddenGoalToUpdateException {

public ForbiddenUserToUpdateGoalToUpdate() {
super(ExceptionMessage.UPDATE_GOAL_FORBIDDEN);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,11 @@ public InvalidInvalidUpdateEndDate() {
super(ExceptionMessage.INVALID_UPDATE_END_DATE);
}
}

public static class InvalidInvalidUserToDelete extends InvalidGoalException {

public InvalidInvalidUserToDelete() {
super(ExceptionMessage.INVALID_USER_TO_DELETE);
}
}
}

This file was deleted.

22 changes: 20 additions & 2 deletions src/main/java/com/backend/blooming/goal/domain/Goal.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.backend.blooming.goal.domain;

import com.backend.blooming.common.entity.BaseTimeEntity;
import com.backend.blooming.goal.application.exception.DeleteGoalForbiddenException;
import com.backend.blooming.goal.application.exception.ForbiddenGoalToDeleteException;
import com.backend.blooming.goal.application.exception.InvalidGoalAcceptException;
import com.backend.blooming.goal.application.exception.InvalidGoalException;
import com.backend.blooming.user.domain.User;
Expand Down Expand Up @@ -107,7 +107,7 @@ public void updateDeleted(final Long userId) {

private void validUserToDelete(final Long userId) {
if (!isManager(userId)) {
throw new DeleteGoalForbiddenException();
throw new ForbiddenGoalToDeleteException.ForbiddenUserToDeleteGoal();
}
}
public boolean isTeam(final User user) {
Expand Down Expand Up @@ -139,4 +139,22 @@ private void validateUserToAccept(final User user) {
public boolean isTeamAndAccepted(final User user) {
return teams.isTeamAndAccepted(user);
}

public void deleteUser(final User user, final Long managerId) {
validUserToDelete(user);
validUserToDeleteUser(managerId);
teams.deleteUser(user.getId());
Copy link
Member

Choose a reason for hiding this comment

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

굳이 user가 아닌 user.getId()를 전달하는 이유가 있을까요?
user에 id는 어차피 들어있고 user.equals(user)라고 하면 더 편할 것 같은데 해당 로직을 user.getId.equals(userId)로 되어 있어 여쭤봅니다!

Copy link
Member Author

Choose a reason for hiding this comment

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

여기까진 미처 생각을 못한 것 같습니다..! user 전체 넘겨주는 것으로 수정했습니다!

}

private void validUserToDelete(final User user) {
if (!this.isTeam(user)) {
throw new InvalidGoalException.InvalidInvalidUserToDelete();
}
}

private void validUserToDeleteUser(final Long userId) {
if (!isManager(userId)) {
throw new ForbiddenGoalToDeleteException.ForbiddenUserToDeleteUser();
}
}
Comment on lines +156 to +160
Copy link
Member

Choose a reason for hiding this comment

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

해당 부분은 생각하지 못했는데 좋네요! 👍

}
8 changes: 8 additions & 0 deletions src/main/java/com/backend/blooming/goal/domain/GoalTeam.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,12 @@ private void processDefaultManager(final User user, final Goal goal) {
public void updateAccepted() {
this.accepted = true;
}

public void updateDeleted() {
Copy link
Member

Choose a reason for hiding this comment

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

그냥 delete라고 하는 것이 더 적절하다고 생각합니다.
왜냐하면 해당 메서드는 deleted의 값을 매개변수로 주입해 바꾸는 것이 아니라 무조건 삭제의 의미인 true로 바꾸는 것이기에 그냥 delete()라는 메서드명으로 삭제한다는 의미를 명확하게 전달하는 것이 더 좋다고 생각합니다.

this.deleted = true;
}

public boolean isDeletedFalse() {
Copy link
Member

Choose a reason for hiding this comment

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

해당 메서드를 만들어 사용하는 이유는 무엇일까요?
lombok을 통해 만들어지는 !isDeleted()를 사용하지 않은 이유가 있을까요?

Copy link
Member Author

@jhsseonn jhsseonn Apr 3, 2024

Choose a reason for hiding this comment

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

final List<User> usersBeforeUpdate = this.goalTeams.stream()
                                                           .filter(GoalTeam::isDeletedFalse)
                                                           .map(GoalTeam::getUser)
                                                           .toList();

위 같은 로직에서 filter를 걸 때 !isDeleted()를 사용하게 되면 goalTeam -> !goalTeam.isDeleted()로 사용하게 됩니다. 이것이 반복되니 아예 따로 deleted가 false인지를 true로 반환하는 메서드를 만들어서 간결하게 표현하는 것이 낫지 않나 생각해 따로 메서드를 만들었습니다.

Copy link
Member

Choose a reason for hiding this comment

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

저는 오히려 동일한 로직이 추가되어 코드의 중복이 발생하는 것이 아닌가 하는 의문이 있습니다.

또한, 해당 메서드를 사용할 것이라면 isNotDeleted()는 어떨까요?
GoalTeams 객체 외부에서는 deleted가 boolean 타입인지 다른 타입인지 알 필요가 없다고 생각합니다.

Copy link
Member Author

Choose a reason for hiding this comment

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

고민해봤는데 isDeletedFalse 자체가 굳이 필요하지 않은 메서드를 만든 것 같아 삭제하고 isDeleted의 True/False 여부 확인으로 수정했습니다!

return !this.deleted;
}
}
18 changes: 18 additions & 0 deletions src/main/java/com/backend/blooming/goal/domain/Teams.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public static Teams create(final List<User> users, final Goal goal) {
validateUsersSize(users);
final List<GoalTeam> goalTeams = users.stream()
.map(user -> new GoalTeam(user, goal))
.filter(GoalTeam::isDeletedFalse)
.toList();
return new Teams(goalTeams);
}
Expand All @@ -50,6 +51,7 @@ private static void validateUsersSize(final List<User> users) {
public List<GoalTeam> update(final List<User> users, final Goal goal) {
validateUsersSize(users);
final List<User> usersBeforeUpdate = this.goalTeams.stream()
.filter(GoalTeam::isDeletedFalse)
.map(GoalTeam::getUser)
.toList();
final List<GoalTeam> updatedUsers = users.stream()
Expand Down Expand Up @@ -78,4 +80,20 @@ public boolean isTeamAndAccepted(final User user) {
return goalTeams.stream()
.anyMatch(goalTeam -> goalTeam.getUser().equals(user) && goalTeam.isAccepted());
}

public void deleteUser(final Long userId) {
this.goalTeams.forEach(goalTeam -> {
if (goalTeam.getUser().getId().equals(userId)) {
goalTeam.updateDeleted();
}
});
Copy link
Member

Choose a reason for hiding this comment

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

개인적으로 아래와 같은 for문을 통해 break를 추가하면 어떨까 하는 생각이 있습니다.
현재는 물론 최대 5명이기에 상관없긴 하지만, 팀원이 많아질 수 있다면 결국 성능상 아주 조금은 낮아지지 않을까 해서요!
물론 정말 완벽한 성능 개선을 생각한다면 좀 더 고민해 봐야 하긴 하지만요...ㅎㅎ

Suggested change
this.goalTeams.forEach(goalTeam -> {
if (goalTeam.getUser().getId().equals(userId)) {
goalTeam.updateDeleted();
}
});
for (GoalTeam goalTeam : goalTeams) {
if (goalTeam.getUser().getId().equals(userId)) {
goalTeam.updateDeleted();
break;
}
}

Copy link
Member Author

Choose a reason for hiding this comment

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

위에서 코멘트 남긴대로 for문 돌다가 if문에서 걸리면 goalTeam delete 해주고 Teams에서는 remove해주는 식으로 구현했습니다. 감사합니다!

final List<GoalTeam> updatedGoalTeams = this.goalTeams.stream()
.filter(GoalTeam::isDeletedFalse)
.toList();
updateGoalTeams(updatedGoalTeams);
}

private void updateGoalTeams(final List<GoalTeam> goalTeams) {
this.goalTeams = goalTeams;
}
Copy link
Member

Choose a reason for hiding this comment

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

이렇게 하더라도 goalTeam 테이블에서 삭제된 사용자가 제거되거나 goalId를 null로 만드는 등의 행위는 하지 않을 것으로 보이는데, 삭제 후 다시 조회했을 때 삭제된 사용자는 불러와지지 않나요? 어떤 의미가 있는 것인지 궁금합니다.
또한, 팀원을 softDelete하는 것과 hardDelete하는 것 중 뭐가 더 적절할지도 고민이네요!

Copy link
Member Author

Choose a reason for hiding this comment

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

이렇게 하면 삭제된 사용자는 불러와지지 않습니다. updateGoalTeams를 하지 않을 경우, 삭제된 사용자가 그대로 goalTeams에 남아있기 때문에 삭제를 하지 않은 사용자들만 다시 goalTeams에 할당했습니다. 그런데 너무 어렵게 생각한 것 같네요.. 정수님이 밑에서 피드백 주신대로 for문 돌면서 if문 걸리면 delete하고 goalTeams에서도 remove 하는 방식으로 수정했습니다!

softDelete vs hardDelete 관련해서는 골 팀은 hardDelete를 해도 문제가 없을 것 같아요. 정말 단지 골 참여자 목록에 추가하기 위해 만들어진 테이블이기 때문에 소속 되어있던 골에서 방출되면 더 이상 테이블의 존재 의미가 없어지긴 합니다. 추후 분석용 데이터로서는 어느정도 의미가 있을까요? 딱히 생각나는 활용방안이 없어서 저는 hardDelete를 해도 좋을 것 같습니다.

Copy link
Member

Choose a reason for hiding this comment

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

hardDelete를 해도 괜찮을 것 같습니다.
원래 해당 리뷰를 작성할 때 팀원 정보가 스탬프에 영향을 주지 않을까 했었는데, user를 fk로 사용하고 있어 큰 문제가 없을 것 같습니다.
그래서 결론적으로는 hardDelete로 하면 좋을 것 같네요!

Copy link
Member

@JJ503 JJ503 Apr 7, 2024

Choose a reason for hiding this comment

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

그런데 TeamsdeleteUser에서는 현재는 soft delete로 처리하고 있는 것 같은데 맞을까요?
코멘트와 로직이 서로 달라 여쭤봅니다.

Copy link
Member Author

Choose a reason for hiding this comment

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

hardDelete로 구현하기로 결정된 게 아니라고 판단해 로직을 추가하지 않았습니다. 로직 추가해서 리뷰 재요청하도록 하겠습니다.

}
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,17 @@ public ResponseEntity<Void> acceptGoal(
return ResponseEntity.noContent()
.build();
}

// TO DO: api 형식에서 /user는 불필요할까요?
@DeleteMapping(value = "/{goalId}/user/{userId}", headers = "X-API-VERSION=1")
Copy link
Member

Choose a reason for hiding this comment

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

저는 필요하다고 생각합니다!

Copy link
Member

Choose a reason for hiding this comment

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

그리고 이건 그냥 TODO 팁 아닌 팁인데, template에 todo가 있어 todo라고만 적어도 todo 주석이 자동생성됩니다.
또한, TODO는 붙여 적어줘야 아래 이미지처럼 Intellij가 todo임을 인지할 수 있고, 커밋 시에도 경고를 통해 todo가 있음을 계속 상기시켜 줍니다.
현재 방식처럼 사용하시는 게 편하시다면 상관없지만, 그냥 혹시 모르실까 해서 말씀드립니다!
image

public ResponseEntity<Void> deleteUser(
@PathVariable("goalId") final Long goalId,
@PathVariable("userId") final Long userId,
@Authenticated AuthenticatedUser authenticatedUser
) {
goalService.deleteUser(userId, goalId, authenticatedUser.userId());

return ResponseEntity.noContent()
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,13 @@ private void validateUserToRead(final Goal goal, final User user) {
throw new ForbiddenStampToReadException();
}
}

/*
TO DO: 골 아이디와 사용자 아이디를 받아서 모든 스탬프를 삭제하는 로직을 스탬프 서비스에 구현했는데,
골 서비스에서 한꺼번에 구현하는 것이 나을까요?
*/
public void deleteAllByGoalIdAndUserId(final Long goalId, final Long userId) {
final List<Stamp> stamps = stampRepository.findAllByGoalIdAndUserId(goalId, userId);
stamps.forEach(Stamp::delete);
}
Copy link
Member

Choose a reason for hiding this comment

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

해당 부분은 좀 고민이 되네요....
일당 당장의 생각은 Goal 패키지에서 stamp가 어떻게 삭제되는지는 알 필요가 없다고 생각하긴 합니다. 그리고 StampService와 GoalService에서 순환참조가 일어나지 않고 있으므로 문제는 없다고 생각합니다. 그래서 일단은 현재처럼 진행하고 나중에 전체적으로 의존성과 관련해 리팩터링에 대한 논의를 하면 좋을 것 같긴 합니다!

Copy link
Member Author

Choose a reason for hiding this comment

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

좋습니다! 그러면 지금은 일단 이렇게 두고, 의존성 관련 리팩터링에 대한 논의 후에 정해진 대로 리팩터링 하는 것으로 해요!

}
4 changes: 4 additions & 0 deletions src/main/java/com/backend/blooming/stamp/domain/Stamp.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,8 @@ private String processDefaultStampImageUrl(final String stampImageUrl) {

return stampImageUrl;
}

public void delete() {
this.deleted = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,11 @@ SELECT EXISTS(
WHERE s.id = :stampId
""")
Optional<Stamp> findByIdAndFetchGoalAndUser(final Long stampId);

@Query("""
SELECT s
FROM Stamp s
WHERE s.goal.id = :goalId AND s.user.id = :userId
""")
List<Stamp> findAllByGoalIdAndUserId(final Long goalId, final Long userId);
Comment on lines +47 to +52
Copy link
Member

Choose a reason for hiding this comment

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

jpa 네이밍만으로 안 되기에 쿼리문을 사용한 것이 맞을까요?
궁금해서 여쭤봅니다!

Copy link
Member Author

Choose a reason for hiding this comment

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

네 맞습니다! 네이밍만으로 조회가 불가하다고 판단해 쿼리문 사용했습니다!

}
Loading
Loading