From bfe5ccd6f63bd57728096c4fed5d780736a82045 Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Wed, 15 Nov 2023 15:06:28 +0900 Subject: [PATCH 01/20] feat: add group entity --- .../java/com/uspray/uspray/domain/Group.java | 21 ++++++++++++------- .../java/com/uspray/uspray/domain/Member.java | 20 ++++++++++-------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/uspray/uspray/domain/Group.java b/src/main/java/com/uspray/uspray/domain/Group.java index 80945b30..c95bdcbd 100644 --- a/src/main/java/com/uspray/uspray/domain/Group.java +++ b/src/main/java/com/uspray/uspray/domain/Group.java @@ -1,14 +1,12 @@ package com.uspray.uspray.domain; import com.uspray.uspray.common.domain.AuditingTimeEntity; + +import java.util.HashSet; import java.util.List; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.OneToMany; -import javax.persistence.Table; +import java.util.Set; +import javax.persistence.*; + import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -24,6 +22,15 @@ public class Group extends AuditingTimeEntity { @Column(name = "group_id") private Long id; + private String name; + + @OneToOne + @JoinColumn(name = "leader_id", referencedColumnName = "member_id") + private Member leader; + + @ManyToMany(mappedBy = "groups") + private Set members = new HashSet<>(); + @OneToMany(mappedBy = "group", orphanRemoval = true) private List groupPrayList; diff --git a/src/main/java/com/uspray/uspray/domain/Member.java b/src/main/java/com/uspray/uspray/domain/Member.java index e0889603..bf52ecdb 100644 --- a/src/main/java/com/uspray/uspray/domain/Member.java +++ b/src/main/java/com/uspray/uspray/domain/Member.java @@ -3,15 +3,12 @@ import com.uspray.uspray.DTO.notification.NotificationAgreeDto; import com.uspray.uspray.Enums.Authority; import com.uspray.uspray.common.domain.AuditingTimeEntity; + +import java.util.HashSet; import java.util.List; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.OneToMany; +import java.util.Set; +import javax.persistence.*; + import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -49,10 +46,15 @@ public class Member extends AuditingTimeEntity { @Enumerated(EnumType.STRING) private Authority authority; + @ManyToMany + @JoinTable(name = "member_group", + joinColumns = @JoinColumn(name = "member_id"), + inverseJoinColumns = @JoinColumn(name = "group_id")) + private Set groups = new HashSet<>(); + @OneToMany(mappedBy = "author") private List groupPrayList; - public void changeFirebaseToken(String firebaseToken) { this.firebaseToken = firebaseToken; } From c4a2a4cb091297340ab6b793472f4c55db2b185a Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Wed, 15 Nov 2023 15:07:22 +0900 Subject: [PATCH 02/20] feat: add Group list service --- .../group/response/GroupListResponseDto.java | 15 ++++++++ .../DTO/group/response/GroupResponseDto.java | 19 +++++++++++ .../uspray/controller/GroupController.java | 32 +++++++++++++++++ .../uspray/exception/SuccessStatus.java | 1 + .../infrastructure/GroupRepository.java | 6 +++- .../infrastructure/HistoryRepository.java | 1 + .../querydsl/group/GroupRepositoryCustom.java | 11 ++++++ .../querydsl/group/GroupRepositoryImpl.java | 34 +++++++++++++++++++ .../history}/HistoryRepositoryCustom.java | 2 +- .../history/HistoryRepositoryImpl.java | 2 +- .../uspray/uspray/service/GroupService.java | 26 ++++++++++++++ 11 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/uspray/uspray/DTO/group/response/GroupListResponseDto.java create mode 100644 src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java create mode 100644 src/main/java/com/uspray/uspray/controller/GroupController.java create mode 100644 src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryCustom.java create mode 100644 src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java rename src/main/java/com/uspray/uspray/infrastructure/{ => querydsl/history}/HistoryRepositoryCustom.java (86%) create mode 100644 src/main/java/com/uspray/uspray/service/GroupService.java diff --git a/src/main/java/com/uspray/uspray/DTO/group/response/GroupListResponseDto.java b/src/main/java/com/uspray/uspray/DTO/group/response/GroupListResponseDto.java new file mode 100644 index 00000000..a822badb --- /dev/null +++ b/src/main/java/com/uspray/uspray/DTO/group/response/GroupListResponseDto.java @@ -0,0 +1,15 @@ +package com.uspray.uspray.DTO.group.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class GroupListResponseDto { + + List groupList; +} diff --git a/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java b/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java new file mode 100644 index 00000000..7d1f8da1 --- /dev/null +++ b/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java @@ -0,0 +1,19 @@ +package com.uspray.uspray.DTO.group.response; + +import com.uspray.uspray.domain.Group; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "모임 응답 DTO") +public class GroupResponseDto { + + private Group group; + + private Boolean isLeader; + +} diff --git a/src/main/java/com/uspray/uspray/controller/GroupController.java b/src/main/java/com/uspray/uspray/controller/GroupController.java new file mode 100644 index 00000000..77260b96 --- /dev/null +++ b/src/main/java/com/uspray/uspray/controller/GroupController.java @@ -0,0 +1,32 @@ +package com.uspray.uspray.controller; + +import com.uspray.uspray.DTO.ApiResponseDto; +import com.uspray.uspray.DTO.group.response.GroupListResponseDto; +import com.uspray.uspray.exception.SuccessStatus; +import com.uspray.uspray.service.GroupService; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.User; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/group") +@Tag(name = "Group", description = "모임 API") +@RequiredArgsConstructor +@SecurityRequirement(name = "JWT Auth") +public class GroupController { + + private final GroupService groupService; + + @GetMapping + public ApiResponseDto getGroupList( + @Parameter(hidden = true) @AuthenticationPrincipal User user) { + return ApiResponseDto.success(SuccessStatus.GET_GROUP_LIST_SUCCESS, + groupService.getGroupList(user.getUsername())); + } +} diff --git a/src/main/java/com/uspray/uspray/exception/SuccessStatus.java b/src/main/java/com/uspray/uspray/exception/SuccessStatus.java index 3d57a079..1901f5d3 100644 --- a/src/main/java/com/uspray/uspray/exception/SuccessStatus.java +++ b/src/main/java/com/uspray/uspray/exception/SuccessStatus.java @@ -33,6 +33,7 @@ public enum SuccessStatus { GET_HISTORY_DETAIL_SUCCESS(HttpStatus.OK, "히스토리 상세 조회에 성공했습니다."), INCREASE_PRAY_COUNT_SUCCESS(HttpStatus.OK, "기도 횟수 추가에 성공했습니다."), COMPLETE_PRAY_SUCCESS(HttpStatus.OK, "기도제목 완료에 성공했습니다."), + GET_GROUP_LIST_SUCCESS(HttpStatus.OK, "모임 목록 조회에 성공했습니다."), /* * 201 created */ diff --git a/src/main/java/com/uspray/uspray/infrastructure/GroupRepository.java b/src/main/java/com/uspray/uspray/infrastructure/GroupRepository.java index 4c77372c..a3d6104b 100644 --- a/src/main/java/com/uspray/uspray/infrastructure/GroupRepository.java +++ b/src/main/java/com/uspray/uspray/infrastructure/GroupRepository.java @@ -1,11 +1,15 @@ package com.uspray.uspray.infrastructure; import com.uspray.uspray.domain.Group; +import com.uspray.uspray.domain.Member; import com.uspray.uspray.exception.ErrorStatus; import com.uspray.uspray.exception.model.NotFoundException; +import com.uspray.uspray.infrastructure.querydsl.group.GroupRepositoryCustom; import org.springframework.data.jpa.repository.JpaRepository; -public interface GroupRepository extends JpaRepository { +import java.util.List; + +public interface GroupRepository extends JpaRepository, GroupRepositoryCustom { default Group getGroupById(Long id) { return this.findById(id).orElseThrow( diff --git a/src/main/java/com/uspray/uspray/infrastructure/HistoryRepository.java b/src/main/java/com/uspray/uspray/infrastructure/HistoryRepository.java index 79ba2215..8458d150 100644 --- a/src/main/java/com/uspray/uspray/infrastructure/HistoryRepository.java +++ b/src/main/java/com/uspray/uspray/infrastructure/HistoryRepository.java @@ -2,6 +2,7 @@ import com.uspray.uspray.domain.History; import com.uspray.uspray.domain.Member; +import com.uspray.uspray.infrastructure.querydsl.history.HistoryRepositoryCustom; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryCustom.java b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryCustom.java new file mode 100644 index 00000000..13132364 --- /dev/null +++ b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryCustom.java @@ -0,0 +1,11 @@ +package com.uspray.uspray.infrastructure.querydsl.group; + +import com.uspray.uspray.DTO.group.response.GroupResponseDto; +import com.uspray.uspray.domain.Member; + +import java.util.List; + +public interface GroupRepositoryCustom { + + List findGroupListByMember(Member member); +} diff --git a/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java new file mode 100644 index 00000000..a9ca8b7f --- /dev/null +++ b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java @@ -0,0 +1,34 @@ +package com.uspray.uspray.infrastructure.querydsl.group; + +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.impl.JPAQueryFactory; +import com.uspray.uspray.DTO.group.response.GroupResponseDto; +import com.uspray.uspray.domain.Group; +import com.uspray.uspray.domain.Member; +import com.uspray.uspray.domain.QGroup; +import com.uspray.uspray.domain.QMember; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class GroupRepositoryImpl implements GroupRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + @Override + public List findGroupListByMember(Member member) { + + QGroup group = QGroup.group; + QMember memberEntity = QMember.member; + + return queryFactory + .select(Projections.constructor(GroupResponseDto.class, group, group.leader.eq(member))) + .from(group) + .leftJoin(group.members, memberEntity) + .where(group.members.contains(member)) + .fetch(); + } +} diff --git a/src/main/java/com/uspray/uspray/infrastructure/HistoryRepositoryCustom.java b/src/main/java/com/uspray/uspray/infrastructure/querydsl/history/HistoryRepositoryCustom.java similarity index 86% rename from src/main/java/com/uspray/uspray/infrastructure/HistoryRepositoryCustom.java rename to src/main/java/com/uspray/uspray/infrastructure/querydsl/history/HistoryRepositoryCustom.java index dcd1a0f6..85a5b5f8 100644 --- a/src/main/java/com/uspray/uspray/infrastructure/HistoryRepositoryCustom.java +++ b/src/main/java/com/uspray/uspray/infrastructure/querydsl/history/HistoryRepositoryCustom.java @@ -1,4 +1,4 @@ -package com.uspray.uspray.infrastructure; +package com.uspray.uspray.infrastructure.querydsl.history; import com.uspray.uspray.domain.History; import java.time.LocalDate; diff --git a/src/main/java/com/uspray/uspray/infrastructure/querydsl/history/HistoryRepositoryImpl.java b/src/main/java/com/uspray/uspray/infrastructure/querydsl/history/HistoryRepositoryImpl.java index 9fce18a6..ef478827 100644 --- a/src/main/java/com/uspray/uspray/infrastructure/querydsl/history/HistoryRepositoryImpl.java +++ b/src/main/java/com/uspray/uspray/infrastructure/querydsl/history/HistoryRepositoryImpl.java @@ -3,7 +3,7 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import com.uspray.uspray.domain.History; import com.uspray.uspray.domain.QHistory; -import com.uspray.uspray.infrastructure.HistoryRepositoryCustom; + import java.time.LocalDate; import java.util.List; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/uspray/uspray/service/GroupService.java b/src/main/java/com/uspray/uspray/service/GroupService.java new file mode 100644 index 00000000..e162dd6e --- /dev/null +++ b/src/main/java/com/uspray/uspray/service/GroupService.java @@ -0,0 +1,26 @@ +package com.uspray.uspray.service; + +import com.uspray.uspray.DTO.group.response.GroupListResponseDto; +import com.uspray.uspray.DTO.group.response.GroupResponseDto; +import com.uspray.uspray.domain.Group; +import com.uspray.uspray.domain.Member; +import com.uspray.uspray.infrastructure.GroupRepository; +import com.uspray.uspray.infrastructure.MemberRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class GroupService { + + private final GroupRepository groupRepository; + private final MemberRepository memberRepository; + + public GroupListResponseDto getGroupList(String username) { + Member member = memberRepository.getMemberByUserId(username); + List groupList = groupRepository.findGroupListByMember(member); + return new GroupListResponseDto(groupList); + } +} From c85a4661f02c54a8787b227e90023e2822669913 Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Wed, 15 Nov 2023 15:25:09 +0900 Subject: [PATCH 03/20] refactor: add group description and change Dto --- .../uspray/DTO/group/response/GroupResponseDto.java | 8 ++++++-- src/main/java/com/uspray/uspray/domain/Group.java | 2 ++ .../querydsl/group/GroupRepositoryImpl.java | 6 +++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java b/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java index 7d1f8da1..e5d6f418 100644 --- a/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java +++ b/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java @@ -12,8 +12,12 @@ @Schema(description = "모임 응답 DTO") public class GroupResponseDto { - private Group group; + private Long id; - private Boolean isLeader; + private String name; + + private String description; + + private Integer memberCount; } diff --git a/src/main/java/com/uspray/uspray/domain/Group.java b/src/main/java/com/uspray/uspray/domain/Group.java index c95bdcbd..adc21226 100644 --- a/src/main/java/com/uspray/uspray/domain/Group.java +++ b/src/main/java/com/uspray/uspray/domain/Group.java @@ -24,6 +24,8 @@ public class Group extends AuditingTimeEntity { private String name; + private String description; + @OneToOne @JoinColumn(name = "leader_id", referencedColumnName = "member_id") private Member leader; diff --git a/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java index a9ca8b7f..54a7c338 100644 --- a/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java +++ b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java @@ -25,7 +25,11 @@ public List findGroupListByMember(Member member) { QMember memberEntity = QMember.member; return queryFactory - .select(Projections.constructor(GroupResponseDto.class, group, group.leader.eq(member))) + .select(Projections.constructor(GroupResponseDto.class, + group.id, + group.name, + group.description, + group.members.size())) .from(group) .leftJoin(group.members, memberEntity) .where(group.members.contains(member)) From 406a88076c04e586eb94bf8fce89ec7d1e6d0c52 Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Wed, 15 Nov 2023 15:39:32 +0900 Subject: [PATCH 04/20] feat: add group create service --- .../DTO/group/request/GroupRequestDto.java | 15 +++++++++++++ .../uspray/controller/GroupController.java | 14 ++++++++++--- .../java/com/uspray/uspray/domain/Group.java | 21 +++++++++++++++++++ .../uspray/exception/SuccessStatus.java | 2 ++ .../uspray/uspray/service/GroupService.java | 12 +++++++++++ 5 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java diff --git a/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java b/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java new file mode 100644 index 00000000..5473518a --- /dev/null +++ b/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java @@ -0,0 +1,15 @@ +package com.uspray.uspray.DTO.group.request; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class GroupRequestDto { + + private String name; + + private String description; +} diff --git a/src/main/java/com/uspray/uspray/controller/GroupController.java b/src/main/java/com/uspray/uspray/controller/GroupController.java index 77260b96..06426a85 100644 --- a/src/main/java/com/uspray/uspray/controller/GroupController.java +++ b/src/main/java/com/uspray/uspray/controller/GroupController.java @@ -1,6 +1,7 @@ package com.uspray.uspray.controller; import com.uspray.uspray.DTO.ApiResponseDto; +import com.uspray.uspray.DTO.group.request.GroupRequestDto; import com.uspray.uspray.DTO.group.response.GroupListResponseDto; import com.uspray.uspray.exception.SuccessStatus; import com.uspray.uspray.service.GroupService; @@ -10,9 +11,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.userdetails.User; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/group") @@ -29,4 +28,13 @@ public ApiResponseDto getGroupList( return ApiResponseDto.success(SuccessStatus.GET_GROUP_LIST_SUCCESS, groupService.getGroupList(user.getUsername())); } + + @PostMapping + public ApiResponseDto createGroup( + @Parameter(hidden = true) @AuthenticationPrincipal User user, + @RequestBody GroupRequestDto groupRequestDto) { + groupService.createGroup(user.getUsername(), groupRequestDto); + return ApiResponseDto.success(SuccessStatus.CREATE_GROUP_SUCCESS, + SuccessStatus.CREATE_GROUP_SUCCESS.getMessage()); + } } diff --git a/src/main/java/com/uspray/uspray/domain/Group.java b/src/main/java/com/uspray/uspray/domain/Group.java index adc21226..57c58978 100644 --- a/src/main/java/com/uspray/uspray/domain/Group.java +++ b/src/main/java/com/uspray/uspray/domain/Group.java @@ -8,6 +8,7 @@ import javax.persistence.*; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -36,4 +37,24 @@ public class Group extends AuditingTimeEntity { @OneToMany(mappedBy = "group", orphanRemoval = true) private List groupPrayList; + @Builder + public Group(String name, String description, Member leader) { + this.name = name; + this.description = description; + this.members.add(leader); + this.leader = leader; + } + + public void changeName(String name) { + this.name = name; + } + + public void changeDescription(String description) { + this.description = description; + } + + public void changeLeader(Member leader) { + this.leader = leader; + } + } diff --git a/src/main/java/com/uspray/uspray/exception/SuccessStatus.java b/src/main/java/com/uspray/uspray/exception/SuccessStatus.java index 1901f5d3..0fb8c12b 100644 --- a/src/main/java/com/uspray/uspray/exception/SuccessStatus.java +++ b/src/main/java/com/uspray/uspray/exception/SuccessStatus.java @@ -34,6 +34,7 @@ public enum SuccessStatus { INCREASE_PRAY_COUNT_SUCCESS(HttpStatus.OK, "기도 횟수 추가에 성공했습니다."), COMPLETE_PRAY_SUCCESS(HttpStatus.OK, "기도제목 완료에 성공했습니다."), GET_GROUP_LIST_SUCCESS(HttpStatus.OK, "모임 목록 조회에 성공했습니다."), + /* * 201 created */ @@ -43,6 +44,7 @@ public enum SuccessStatus { CREATE_CATEGORY_SUCCESS(HttpStatus.CREATED, "카테고리 생성에 성공했습니다."), SHARE_PRAY_SUCCESS(HttpStatus.CREATED, "기도제목 공유에 성공했습니다."), SHARE_PRAY_AGREE_SUCCESS(HttpStatus.CREATED, "기도제목 공유 수락에 성공했습니다."), + CREATE_GROUP_SUCCESS(HttpStatus.CREATED, "모임 생성에 성공했습니다."), /* * 204 deleted diff --git a/src/main/java/com/uspray/uspray/service/GroupService.java b/src/main/java/com/uspray/uspray/service/GroupService.java index e162dd6e..bceb6d15 100644 --- a/src/main/java/com/uspray/uspray/service/GroupService.java +++ b/src/main/java/com/uspray/uspray/service/GroupService.java @@ -1,5 +1,6 @@ package com.uspray.uspray.service; +import com.uspray.uspray.DTO.group.request.GroupRequestDto; import com.uspray.uspray.DTO.group.response.GroupListResponseDto; import com.uspray.uspray.DTO.group.response.GroupResponseDto; import com.uspray.uspray.domain.Group; @@ -10,6 +11,7 @@ import org.springframework.stereotype.Service; import java.util.List; +import java.util.Set; @Service @RequiredArgsConstructor @@ -23,4 +25,14 @@ public GroupListResponseDto getGroupList(String username) { List groupList = groupRepository.findGroupListByMember(member); return new GroupListResponseDto(groupList); } + + public void createGroup(String username, GroupRequestDto groupRequestDto) { + Member member = memberRepository.getMemberByUserId(username); + Group group = Group.builder() + .name(groupRequestDto.getName()) + .description(groupRequestDto.getDescription()) + .leader(member) + .build(); + groupRepository.save(group); + } } From 256fdc449e2549fba6a16ce17f81f3009055cb5f Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Wed, 15 Nov 2023 15:39:32 +0900 Subject: [PATCH 05/20] feat: add group create service --- .../DTO/group/request/GroupRequestDto.java | 15 +++++++++++++ .../uspray/controller/GroupController.java | 14 ++++++++++--- .../java/com/uspray/uspray/domain/Group.java | 21 +++++++++++++++++++ .../uspray/exception/SuccessStatus.java | 2 ++ .../uspray/uspray/service/GroupService.java | 12 +++++++++++ 5 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java diff --git a/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java b/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java new file mode 100644 index 00000000..5473518a --- /dev/null +++ b/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java @@ -0,0 +1,15 @@ +package com.uspray.uspray.DTO.group.request; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class GroupRequestDto { + + private String name; + + private String description; +} diff --git a/src/main/java/com/uspray/uspray/controller/GroupController.java b/src/main/java/com/uspray/uspray/controller/GroupController.java index 77260b96..06426a85 100644 --- a/src/main/java/com/uspray/uspray/controller/GroupController.java +++ b/src/main/java/com/uspray/uspray/controller/GroupController.java @@ -1,6 +1,7 @@ package com.uspray.uspray.controller; import com.uspray.uspray.DTO.ApiResponseDto; +import com.uspray.uspray.DTO.group.request.GroupRequestDto; import com.uspray.uspray.DTO.group.response.GroupListResponseDto; import com.uspray.uspray.exception.SuccessStatus; import com.uspray.uspray.service.GroupService; @@ -10,9 +11,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.userdetails.User; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/group") @@ -29,4 +28,13 @@ public ApiResponseDto getGroupList( return ApiResponseDto.success(SuccessStatus.GET_GROUP_LIST_SUCCESS, groupService.getGroupList(user.getUsername())); } + + @PostMapping + public ApiResponseDto createGroup( + @Parameter(hidden = true) @AuthenticationPrincipal User user, + @RequestBody GroupRequestDto groupRequestDto) { + groupService.createGroup(user.getUsername(), groupRequestDto); + return ApiResponseDto.success(SuccessStatus.CREATE_GROUP_SUCCESS, + SuccessStatus.CREATE_GROUP_SUCCESS.getMessage()); + } } diff --git a/src/main/java/com/uspray/uspray/domain/Group.java b/src/main/java/com/uspray/uspray/domain/Group.java index adc21226..a72cdc5d 100644 --- a/src/main/java/com/uspray/uspray/domain/Group.java +++ b/src/main/java/com/uspray/uspray/domain/Group.java @@ -8,6 +8,7 @@ import javax.persistence.*; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -36,4 +37,24 @@ public class Group extends AuditingTimeEntity { @OneToMany(mappedBy = "group", orphanRemoval = true) private List groupPrayList; + @Builder + public Group(String name, String description, Member leader) { + this.name = name; + this.description = description; + this.members.add(leader); + this.leader = leader; + } + + private void changeName(String name) { + this.name = name; + } + + private void changeDescription(String description) { + this.description = description; + } + + private void changeLeader(Member leader) { + this.leader = leader; + } + } diff --git a/src/main/java/com/uspray/uspray/exception/SuccessStatus.java b/src/main/java/com/uspray/uspray/exception/SuccessStatus.java index 1901f5d3..0fb8c12b 100644 --- a/src/main/java/com/uspray/uspray/exception/SuccessStatus.java +++ b/src/main/java/com/uspray/uspray/exception/SuccessStatus.java @@ -34,6 +34,7 @@ public enum SuccessStatus { INCREASE_PRAY_COUNT_SUCCESS(HttpStatus.OK, "기도 횟수 추가에 성공했습니다."), COMPLETE_PRAY_SUCCESS(HttpStatus.OK, "기도제목 완료에 성공했습니다."), GET_GROUP_LIST_SUCCESS(HttpStatus.OK, "모임 목록 조회에 성공했습니다."), + /* * 201 created */ @@ -43,6 +44,7 @@ public enum SuccessStatus { CREATE_CATEGORY_SUCCESS(HttpStatus.CREATED, "카테고리 생성에 성공했습니다."), SHARE_PRAY_SUCCESS(HttpStatus.CREATED, "기도제목 공유에 성공했습니다."), SHARE_PRAY_AGREE_SUCCESS(HttpStatus.CREATED, "기도제목 공유 수락에 성공했습니다."), + CREATE_GROUP_SUCCESS(HttpStatus.CREATED, "모임 생성에 성공했습니다."), /* * 204 deleted diff --git a/src/main/java/com/uspray/uspray/service/GroupService.java b/src/main/java/com/uspray/uspray/service/GroupService.java index e162dd6e..bceb6d15 100644 --- a/src/main/java/com/uspray/uspray/service/GroupService.java +++ b/src/main/java/com/uspray/uspray/service/GroupService.java @@ -1,5 +1,6 @@ package com.uspray.uspray.service; +import com.uspray.uspray.DTO.group.request.GroupRequestDto; import com.uspray.uspray.DTO.group.response.GroupListResponseDto; import com.uspray.uspray.DTO.group.response.GroupResponseDto; import com.uspray.uspray.domain.Group; @@ -10,6 +11,7 @@ import org.springframework.stereotype.Service; import java.util.List; +import java.util.Set; @Service @RequiredArgsConstructor @@ -23,4 +25,14 @@ public GroupListResponseDto getGroupList(String username) { List groupList = groupRepository.findGroupListByMember(member); return new GroupListResponseDto(groupList); } + + public void createGroup(String username, GroupRequestDto groupRequestDto) { + Member member = memberRepository.getMemberByUserId(username); + Group group = Group.builder() + .name(groupRequestDto.getName()) + .description(groupRequestDto.getDescription()) + .leader(member) + .build(); + groupRepository.save(group); + } } From f22b0474ff2b804de6e6f7fc8916c1add6441ea3 Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Wed, 15 Nov 2023 21:48:10 +0900 Subject: [PATCH 06/20] refactor: change GroupResponseDto --- .../response/GroupDetailResponseDto.java | 21 ++++ .../DTO/group/response/GroupResponseDto.java | 10 +- .../uspray/controller/GroupController.java | 1 + .../java/com/uspray/uspray/domain/Group.java | 13 +-- .../java/com/uspray/uspray/domain/Member.java | 110 +++++++++--------- .../uspray/exception/SuccessStatus.java | 1 + .../querydsl/group/GroupRepositoryCustom.java | 2 + .../querydsl/group/GroupRepositoryImpl.java | 30 ++--- .../uspray/service/GroupPrayService.java | 1 + .../uspray/uspray/service/GroupService.java | 7 +- 10 files changed, 115 insertions(+), 81 deletions(-) create mode 100644 src/main/java/com/uspray/uspray/DTO/group/response/GroupDetailResponseDto.java diff --git a/src/main/java/com/uspray/uspray/DTO/group/response/GroupDetailResponseDto.java b/src/main/java/com/uspray/uspray/DTO/group/response/GroupDetailResponseDto.java new file mode 100644 index 00000000..bb5bd747 --- /dev/null +++ b/src/main/java/com/uspray/uspray/DTO/group/response/GroupDetailResponseDto.java @@ -0,0 +1,21 @@ +package com.uspray.uspray.DTO.group.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class GroupDetailResponseDto { + + private Long id; + + private String name; + + private String description; + + private String leader; + + private String memberCount; +} diff --git a/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java b/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java index e5d6f418..db66323b 100644 --- a/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java +++ b/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java @@ -3,12 +3,16 @@ import com.uspray.uspray.domain.Group; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import java.time.LocalDateTime; + @Getter @NoArgsConstructor @AllArgsConstructor +@Builder @Schema(description = "모임 응답 DTO") public class GroupResponseDto { @@ -16,8 +20,12 @@ public class GroupResponseDto { private String name; - private String description; + private String lastPrayContent; private Integer memberCount; + private Integer prayCount; + + private LocalDateTime updatedAt; + } diff --git a/src/main/java/com/uspray/uspray/controller/GroupController.java b/src/main/java/com/uspray/uspray/controller/GroupController.java index 06426a85..e766451f 100644 --- a/src/main/java/com/uspray/uspray/controller/GroupController.java +++ b/src/main/java/com/uspray/uspray/controller/GroupController.java @@ -2,6 +2,7 @@ import com.uspray.uspray.DTO.ApiResponseDto; import com.uspray.uspray.DTO.group.request.GroupRequestDto; +import com.uspray.uspray.DTO.group.response.GroupDetailResponseDto; import com.uspray.uspray.DTO.group.response.GroupListResponseDto; import com.uspray.uspray.exception.SuccessStatus; import com.uspray.uspray.service.GroupService; diff --git a/src/main/java/com/uspray/uspray/domain/Group.java b/src/main/java/com/uspray/uspray/domain/Group.java index a72cdc5d..5ac61c1e 100644 --- a/src/main/java/com/uspray/uspray/domain/Group.java +++ b/src/main/java/com/uspray/uspray/domain/Group.java @@ -25,8 +25,6 @@ public class Group extends AuditingTimeEntity { private String name; - private String description; - @OneToOne @JoinColumn(name = "leader_id", referencedColumnName = "member_id") private Member leader; @@ -38,22 +36,17 @@ public class Group extends AuditingTimeEntity { private List groupPrayList; @Builder - public Group(String name, String description, Member leader) { + public Group(String name, Member leader) { this.name = name; - this.description = description; this.members.add(leader); this.leader = leader; } - private void changeName(String name) { + public void changeName(String name) { this.name = name; } - private void changeDescription(String description) { - this.description = description; - } - - private void changeLeader(Member leader) { + public void changeLeader(Member leader) { this.leader = leader; } diff --git a/src/main/java/com/uspray/uspray/domain/Member.java b/src/main/java/com/uspray/uspray/domain/Member.java index bf52ecdb..fba873e5 100644 --- a/src/main/java/com/uspray/uspray/domain/Member.java +++ b/src/main/java/com/uspray/uspray/domain/Member.java @@ -23,61 +23,61 @@ @Where(clause = "deleted=false") public class Member extends AuditingTimeEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "member_id") - private Long id; - - private String userId; - private String password; - - private String name; - private String phone; - private String birth; - private String gender; - private String firebaseToken; - - private Boolean firstNotiAgree = true; - private Boolean secondNotiAgree= true; - private Boolean thirdNotiAgree = true; - - private final Boolean deleted = false; - - @Enumerated(EnumType.STRING) - private Authority authority; - - @ManyToMany - @JoinTable(name = "member_group", - joinColumns = @JoinColumn(name = "member_id"), - inverseJoinColumns = @JoinColumn(name = "group_id")) - private Set groups = new HashSet<>(); - - @OneToMany(mappedBy = "author") - private List groupPrayList; - - public void changeFirebaseToken(String firebaseToken) { - this.firebaseToken = firebaseToken; - } - - public void changePhone(String phone) { - this.phone = phone; - } - - public void changePw(String pw) { - this.password = pw; - } - - @Builder - public Member(String userId, String password, String name, String phone, String birth, - String gender, Authority authority) { - this.userId = userId; - this.password = password; - this.name = name; - this.phone = phone; - this.birth = birth; - this.gender = gender; - this.authority = authority; - } + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "member_id") + private Long id; + + private String userId; + private String password; + + private String name; + private String phone; + private String birth; + private String gender; + private String firebaseToken; + + private Boolean firstNotiAgree = true; + private Boolean secondNotiAgree = true; + private Boolean thirdNotiAgree = true; + + private final Boolean deleted = false; + + @Enumerated(EnumType.STRING) + private Authority authority; + + @ManyToMany + @JoinTable(name = "member_group", + joinColumns = @JoinColumn(name = "member_id"), + inverseJoinColumns = @JoinColumn(name = "group_id")) + private Set groups = new HashSet<>(); + + @OneToMany(mappedBy = "author") + private List groupPrayList; + + public void changeFirebaseToken(String firebaseToken) { + this.firebaseToken = firebaseToken; + } + + public void changePhone(String phone) { + this.phone = phone; + } + + public void changePw(String pw) { + this.password = pw; + } + + @Builder + public Member(String userId, String password, String name, String phone, String birth, + String gender, Authority authority) { + this.userId = userId; + this.password = password; + this.name = name; + this.phone = phone; + this.birth = birth; + this.gender = gender; + this.authority = authority; + } public void changeNotificationSetting(NotificationAgreeDto notificationAgreeDto) { switch (notificationAgreeDto.getNotificationType()) { diff --git a/src/main/java/com/uspray/uspray/exception/SuccessStatus.java b/src/main/java/com/uspray/uspray/exception/SuccessStatus.java index 0fb8c12b..c5ebd70d 100644 --- a/src/main/java/com/uspray/uspray/exception/SuccessStatus.java +++ b/src/main/java/com/uspray/uspray/exception/SuccessStatus.java @@ -34,6 +34,7 @@ public enum SuccessStatus { INCREASE_PRAY_COUNT_SUCCESS(HttpStatus.OK, "기도 횟수 추가에 성공했습니다."), COMPLETE_PRAY_SUCCESS(HttpStatus.OK, "기도제목 완료에 성공했습니다."), GET_GROUP_LIST_SUCCESS(HttpStatus.OK, "모임 목록 조회에 성공했습니다."), + GET_GROUP_DETAIL_SUCCESS(HttpStatus.OK, "모임 상세 조회에 성공했습니다."), /* * 201 created diff --git a/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryCustom.java b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryCustom.java index 13132364..67bfd7cd 100644 --- a/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryCustom.java +++ b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryCustom.java @@ -1,8 +1,10 @@ package com.uspray.uspray.infrastructure.querydsl.group; import com.uspray.uspray.DTO.group.response.GroupResponseDto; +import com.uspray.uspray.domain.Group; import com.uspray.uspray.domain.Member; +import java.time.LocalDateTime; import java.util.List; public interface GroupRepositoryCustom { diff --git a/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java index 54a7c338..b62998f7 100644 --- a/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java +++ b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java @@ -3,10 +3,7 @@ import com.querydsl.core.types.Projections; import com.querydsl.jpa.impl.JPAQueryFactory; import com.uspray.uspray.DTO.group.response.GroupResponseDto; -import com.uspray.uspray.domain.Group; -import com.uspray.uspray.domain.Member; -import com.uspray.uspray.domain.QGroup; -import com.uspray.uspray.domain.QMember; +import com.uspray.uspray.domain.*; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -23,16 +20,23 @@ public List findGroupListByMember(Member member) { QGroup group = QGroup.group; QMember memberEntity = QMember.member; + QGroupPray groupPray = QGroupPray.groupPray; return queryFactory - .select(Projections.constructor(GroupResponseDto.class, - group.id, - group.name, - group.description, - group.members.size())) - .from(group) - .leftJoin(group.members, memberEntity) - .where(group.members.contains(member)) - .fetch(); + .select(Projections.constructor( + GroupResponseDto.class, + group.id, + group.name, + groupPray.content.max(), + group.members.size(), + group.groupPrayList.size(), + groupPray.createdAt.max() + )) + .from(group) + .leftJoin(group.groupPrayList, groupPray) + .leftJoin(group.members, memberEntity) + .where(group.members.contains(member)) + .groupBy(group.id) + .fetch(); } } diff --git a/src/main/java/com/uspray/uspray/service/GroupPrayService.java b/src/main/java/com/uspray/uspray/service/GroupPrayService.java index 7492661a..11f4bc16 100644 --- a/src/main/java/com/uspray/uspray/service/GroupPrayService.java +++ b/src/main/java/com/uspray/uspray/service/GroupPrayService.java @@ -32,6 +32,7 @@ public void createGroupPray(GroupPrayRequestDto groupPrayRequestDto, String user .content(groupPrayRequestDto.getContent()) .build(); groupPrayRepository.save(groupPray); + group.changeUpdatedAt(); } @Transactional diff --git a/src/main/java/com/uspray/uspray/service/GroupService.java b/src/main/java/com/uspray/uspray/service/GroupService.java index bceb6d15..bd9b8cf0 100644 --- a/src/main/java/com/uspray/uspray/service/GroupService.java +++ b/src/main/java/com/uspray/uspray/service/GroupService.java @@ -1,6 +1,7 @@ package com.uspray.uspray.service; import com.uspray.uspray.DTO.group.request.GroupRequestDto; +import com.uspray.uspray.DTO.group.response.GroupDetailResponseDto; import com.uspray.uspray.DTO.group.response.GroupListResponseDto; import com.uspray.uspray.DTO.group.response.GroupResponseDto; import com.uspray.uspray.domain.Group; @@ -9,9 +10,9 @@ import com.uspray.uspray.infrastructure.MemberRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; -import java.util.Set; @Service @RequiredArgsConstructor @@ -20,19 +21,21 @@ public class GroupService { private final GroupRepository groupRepository; private final MemberRepository memberRepository; + @Transactional(readOnly = true) public GroupListResponseDto getGroupList(String username) { Member member = memberRepository.getMemberByUserId(username); List groupList = groupRepository.findGroupListByMember(member); return new GroupListResponseDto(groupList); } + @Transactional public void createGroup(String username, GroupRequestDto groupRequestDto) { Member member = memberRepository.getMemberByUserId(username); Group group = Group.builder() .name(groupRequestDto.getName()) - .description(groupRequestDto.getDescription()) .leader(member) .build(); + member.getGroups().add(group); groupRepository.save(group); } } From 0109e53919803fa3b26ba7418186dc0d85f0e1d1 Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Wed, 15 Nov 2023 21:49:55 +0900 Subject: [PATCH 07/20] chore: remove unnecessary code --- src/main/java/com/uspray/uspray/service/GroupPrayService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/uspray/uspray/service/GroupPrayService.java b/src/main/java/com/uspray/uspray/service/GroupPrayService.java index 11f4bc16..7492661a 100644 --- a/src/main/java/com/uspray/uspray/service/GroupPrayService.java +++ b/src/main/java/com/uspray/uspray/service/GroupPrayService.java @@ -32,7 +32,6 @@ public void createGroupPray(GroupPrayRequestDto groupPrayRequestDto, String user .content(groupPrayRequestDto.getContent()) .build(); groupPrayRepository.save(groupPray); - group.changeUpdatedAt(); } @Transactional From c179e8470dc2931308e37a3efa958e50c445a15a Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Wed, 15 Nov 2023 22:01:05 +0900 Subject: [PATCH 08/20] feat: add validation to GroupResponseDto --- .../com/uspray/uspray/DTO/group/request/GroupRequestDto.java | 5 +++-- .../java/com/uspray/uspray/controller/GroupController.java | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java b/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java index 5473518a..d0ddfb5a 100644 --- a/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java +++ b/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java @@ -4,12 +4,13 @@ import lombok.Getter; import lombok.NoArgsConstructor; +import javax.validation.constraints.NotNull; + @Getter @NoArgsConstructor @AllArgsConstructor public class GroupRequestDto { + @NotNull(message = "모임 이름을 입력해주세요.") private String name; - - private String description; } diff --git a/src/main/java/com/uspray/uspray/controller/GroupController.java b/src/main/java/com/uspray/uspray/controller/GroupController.java index e766451f..6f04e77c 100644 --- a/src/main/java/com/uspray/uspray/controller/GroupController.java +++ b/src/main/java/com/uspray/uspray/controller/GroupController.java @@ -14,6 +14,8 @@ import org.springframework.security.core.userdetails.User; import org.springframework.web.bind.annotation.*; +import javax.validation.Valid; + @RestController @RequestMapping("/group") @Tag(name = "Group", description = "모임 API") @@ -33,7 +35,7 @@ public ApiResponseDto getGroupList( @PostMapping public ApiResponseDto createGroup( @Parameter(hidden = true) @AuthenticationPrincipal User user, - @RequestBody GroupRequestDto groupRequestDto) { + @Valid @RequestBody GroupRequestDto groupRequestDto) { groupService.createGroup(user.getUsername(), groupRequestDto); return ApiResponseDto.success(SuccessStatus.CREATE_GROUP_SUCCESS, SuccessStatus.CREATE_GROUP_SUCCESS.getMessage()); From aa89bcae3fb55a8f50412a79e744b4b8b8454ba8 Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Wed, 15 Nov 2023 22:58:14 +0900 Subject: [PATCH 09/20] feat: add changeGroupName, changeGroupLeader, kickGroupMember, deleteGroup --- .../group/request/GroupKickRequestDto.java | 16 +++++ .../group/request/GroupLeaderRequestDto.java | 16 +++++ .../uspray/controller/GroupController.java | 42 ++++++++++- .../java/com/uspray/uspray/domain/Group.java | 4 ++ .../java/com/uspray/uspray/domain/Member.java | 4 ++ .../uspray/uspray/exception/ErrorStatus.java | 6 +- .../uspray/exception/SuccessStatus.java | 6 +- .../infrastructure/GroupPrayRepository.java | 3 + .../infrastructure/GroupRepository.java | 2 + .../uspray/uspray/service/GroupService.java | 70 ++++++++++++++++++- 10 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/uspray/uspray/DTO/group/request/GroupKickRequestDto.java create mode 100644 src/main/java/com/uspray/uspray/DTO/group/request/GroupLeaderRequestDto.java diff --git a/src/main/java/com/uspray/uspray/DTO/group/request/GroupKickRequestDto.java b/src/main/java/com/uspray/uspray/DTO/group/request/GroupKickRequestDto.java new file mode 100644 index 00000000..06e9e2a1 --- /dev/null +++ b/src/main/java/com/uspray/uspray/DTO/group/request/GroupKickRequestDto.java @@ -0,0 +1,16 @@ +package com.uspray.uspray.DTO.group.request; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class GroupKickRequestDto { + + @NotNull + private String username; +} diff --git a/src/main/java/com/uspray/uspray/DTO/group/request/GroupLeaderRequestDto.java b/src/main/java/com/uspray/uspray/DTO/group/request/GroupLeaderRequestDto.java new file mode 100644 index 00000000..28b9881d --- /dev/null +++ b/src/main/java/com/uspray/uspray/DTO/group/request/GroupLeaderRequestDto.java @@ -0,0 +1,16 @@ +package com.uspray.uspray.DTO.group.request; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class GroupLeaderRequestDto { + + @NotNull + private String username; +} diff --git a/src/main/java/com/uspray/uspray/controller/GroupController.java b/src/main/java/com/uspray/uspray/controller/GroupController.java index 6f04e77c..7642d7cd 100644 --- a/src/main/java/com/uspray/uspray/controller/GroupController.java +++ b/src/main/java/com/uspray/uspray/controller/GroupController.java @@ -1,8 +1,9 @@ package com.uspray.uspray.controller; import com.uspray.uspray.DTO.ApiResponseDto; +import com.uspray.uspray.DTO.group.request.GroupKickRequestDto; +import com.uspray.uspray.DTO.group.request.GroupLeaderRequestDto; import com.uspray.uspray.DTO.group.request.GroupRequestDto; -import com.uspray.uspray.DTO.group.response.GroupDetailResponseDto; import com.uspray.uspray.DTO.group.response.GroupListResponseDto; import com.uspray.uspray.exception.SuccessStatus; import com.uspray.uspray.service.GroupService; @@ -40,4 +41,43 @@ public ApiResponseDto createGroup( return ApiResponseDto.success(SuccessStatus.CREATE_GROUP_SUCCESS, SuccessStatus.CREATE_GROUP_SUCCESS.getMessage()); } + + @PutMapping("/{groupId}/change-name") + public ApiResponseDto changeGroupName( + @Parameter(hidden = true) @AuthenticationPrincipal User user, + @PathVariable Long groupId, + @Valid @RequestBody GroupRequestDto groupRequestDto) { + groupService.changeGroupName(user.getUsername(), groupId, groupRequestDto); + return ApiResponseDto.success(SuccessStatus.CHANGE_GROUP_NAME_SUCCESS, + SuccessStatus.CHANGE_GROUP_NAME_SUCCESS.getMessage()); + } + + @PutMapping("/{groupId}/change-leader") + public ApiResponseDto changeGroupLeader( + @Parameter(hidden = true) @AuthenticationPrincipal User user, + @PathVariable Long groupId, + @Valid @RequestBody GroupLeaderRequestDto groupLeaderRequestDto) { + groupService.changeGroupLeader(user.getUsername(), groupId, groupLeaderRequestDto); + return ApiResponseDto.success(SuccessStatus.CHANGE_GROUP_LEADER_SUCCESS, + SuccessStatus.CHANGE_GROUP_LEADER_SUCCESS.getMessage()); + } + + @DeleteMapping("/{groupId}/kick") + public ApiResponseDto kickGroupMember( + @Parameter(hidden = true) @AuthenticationPrincipal User user, + @PathVariable Long groupId, + @Valid @RequestBody GroupKickRequestDto groupKickRequestDto) { + groupService.kickGroupMember(user.getUsername(), groupId, groupKickRequestDto); + return ApiResponseDto.success(SuccessStatus.KICK_GROUP_MEMBER_SUCCESS, + SuccessStatus.KICK_GROUP_MEMBER_SUCCESS.getMessage()); + } + + @DeleteMapping("/{groupId}") + public ApiResponseDto deleteGroup( + @Parameter(hidden = true) @AuthenticationPrincipal User user, + @PathVariable Long groupId) { + groupService.deleteGroup(user.getUsername(), groupId); + return ApiResponseDto.success(SuccessStatus.DELETE_GROUP_SUCCESS, + SuccessStatus.DELETE_GROUP_SUCCESS.getMessage()); + } } diff --git a/src/main/java/com/uspray/uspray/domain/Group.java b/src/main/java/com/uspray/uspray/domain/Group.java index 5ac61c1e..a1716ab1 100644 --- a/src/main/java/com/uspray/uspray/domain/Group.java +++ b/src/main/java/com/uspray/uspray/domain/Group.java @@ -50,4 +50,8 @@ public void changeLeader(Member leader) { this.leader = leader; } + public void kickMember(Member member) { + this.members.remove(member); + } + } diff --git a/src/main/java/com/uspray/uspray/domain/Member.java b/src/main/java/com/uspray/uspray/domain/Member.java index fba873e5..39741154 100644 --- a/src/main/java/com/uspray/uspray/domain/Member.java +++ b/src/main/java/com/uspray/uspray/domain/Member.java @@ -67,6 +67,10 @@ public void changePw(String pw) { this.password = pw; } + public void leaveGroup(Group group) { + this.groups.remove(group); + } + @Builder public Member(String userId, String password, String name, String phone, String birth, String gender, Authority authority) { diff --git a/src/main/java/com/uspray/uspray/exception/ErrorStatus.java b/src/main/java/com/uspray/uspray/exception/ErrorStatus.java index cafcced2..370577e3 100644 --- a/src/main/java/com/uspray/uspray/exception/ErrorStatus.java +++ b/src/main/java/com/uspray/uspray/exception/ErrorStatus.java @@ -20,6 +20,8 @@ public enum ErrorStatus { CATEGORY_LIMIT_EXCEPTION(HttpStatus.BAD_REQUEST, "카테고리는 최대 7개까지 생성 가능합니다."), ALREADY_PRAYED_TODAY(HttpStatus.BAD_REQUEST, "오늘 이미 기도한 기도제목입니다."), CATEGORY_DUPLICATE_EXCEPTION(HttpStatus.BAD_REQUEST, "이미 존재하는 카테고리입니다."), + ALREADY_EXIST_GROUP_NAME_EXCEPTION(HttpStatus.BAD_REQUEST, "이미 존재하는 모임 이름입니다."), + /* * 401 UNAUTHORIZED */ @@ -28,6 +30,7 @@ public enum ErrorStatus { SHARE_NOT_AUTHORIZED_EXCEPTION(HttpStatus.UNAUTHORIZED, "기도제목을 공유할 권한이 없습니다."), DELETE_NOT_AUTHORIZED_EXCEPTION(HttpStatus.UNAUTHORIZED, "기도제목을 삭제할 권한이 없습니다."), CATEGORY_UNAUTHORIZED_EXCEPTION(HttpStatus.UNAUTHORIZED, "해당 카테고리에 대한 권한이 없습니다."), + GROUP_UNAUTHORIZED_EXCEPTION(HttpStatus.UNAUTHORIZED, "해당 모임에 대한 권한이 없습니다."), /** * 404 NOT FOUND @@ -39,7 +42,8 @@ public enum ErrorStatus { PRAY_ALREADY_DELETED_EXCEPTION(HttpStatus.NOT_FOUND, "원본 기도제목이 삭제되었습니다."), NOT_FOUND_SHARED_PRAY_EXCEPTION(HttpStatus.NOT_FOUND, "해당 공유기도제목을 찾을 수 없습니다."), HISTORY_NOT_FOUND_EXCEPTION(HttpStatus.NOT_FOUND, "해당 히스토리를 찾을 수 없습니다."), - CATEGORY_NOT_FOUND_EXCEPTION(HttpStatus.NOT_FOUND, "해당 카테고리를 찾을 수 없습니다."); + CATEGORY_NOT_FOUND_EXCEPTION(HttpStatus.NOT_FOUND, "해당 카테고리를 찾을 수 없습니다."), + GROUP_MEMBER_NOT_FOUND_EXCEPTION(HttpStatus.NOT_FOUND, "해당 멤버를 모임에서 찾을 수 없습니다."); private final HttpStatus httpStatus; private final String message; diff --git a/src/main/java/com/uspray/uspray/exception/SuccessStatus.java b/src/main/java/com/uspray/uspray/exception/SuccessStatus.java index c5ebd70d..c51fc5e9 100644 --- a/src/main/java/com/uspray/uspray/exception/SuccessStatus.java +++ b/src/main/java/com/uspray/uspray/exception/SuccessStatus.java @@ -35,6 +35,9 @@ public enum SuccessStatus { COMPLETE_PRAY_SUCCESS(HttpStatus.OK, "기도제목 완료에 성공했습니다."), GET_GROUP_LIST_SUCCESS(HttpStatus.OK, "모임 목록 조회에 성공했습니다."), GET_GROUP_DETAIL_SUCCESS(HttpStatus.OK, "모임 상세 조회에 성공했습니다."), + CHANGE_GROUP_NAME_SUCCESS(HttpStatus.OK, "모임 이름 변경에 성공했습니다."), + CHANGE_GROUP_LEADER_SUCCESS(HttpStatus.OK, "모임 리더 위임에 성공했습니다."), + KICK_GROUP_MEMBER_SUCCESS(HttpStatus.OK, "모임 멤버 내보내기에 성공했습니다."), /* * 201 created @@ -53,7 +56,8 @@ public enum SuccessStatus { DELETE_PRAY_SUCCESS(HttpStatus.NO_CONTENT, "기도제목 삭제에 성공했습니다."), DELETE_GROUP_PRAY_SUCCESS(HttpStatus.NO_CONTENT, "모임 기도제목 삭제에 성공했습니다."), WITHDRAWAL_SUCCESS(HttpStatus.NO_CONTENT, "회원 탈퇴에 성공했습니다."), - DELETE_CATEGORY_SUCCESS(HttpStatus.NO_CONTENT, "카테고리 삭제에 성공했습니다."); + DELETE_CATEGORY_SUCCESS(HttpStatus.NO_CONTENT, "카테고리 삭제에 성공했습니다."), + DELETE_GROUP_SUCCESS(HttpStatus.NO_CONTENT, "모임 삭제에 성공했습니다."); private final HttpStatus httpStatus; diff --git a/src/main/java/com/uspray/uspray/infrastructure/GroupPrayRepository.java b/src/main/java/com/uspray/uspray/infrastructure/GroupPrayRepository.java index bb9ee9d9..b868997e 100644 --- a/src/main/java/com/uspray/uspray/infrastructure/GroupPrayRepository.java +++ b/src/main/java/com/uspray/uspray/infrastructure/GroupPrayRepository.java @@ -1,5 +1,6 @@ package com.uspray.uspray.infrastructure; +import com.uspray.uspray.domain.Group; import com.uspray.uspray.domain.GroupPray; import com.uspray.uspray.exception.ErrorStatus; import com.uspray.uspray.exception.model.NotFoundException; @@ -9,6 +10,8 @@ public interface GroupPrayRepository extends JpaRepository, GroupPrayRepositoryCustom { + void deleteAllByGroup(Group group); + default GroupPray getGroupPrayById(Long id) { return this.findById(id).orElseThrow( () -> new NotFoundException(ErrorStatus.NOT_FOUND_GROUP_PRAY_EXCEPTION, diff --git a/src/main/java/com/uspray/uspray/infrastructure/GroupRepository.java b/src/main/java/com/uspray/uspray/infrastructure/GroupRepository.java index a3d6104b..ca1bfa21 100644 --- a/src/main/java/com/uspray/uspray/infrastructure/GroupRepository.java +++ b/src/main/java/com/uspray/uspray/infrastructure/GroupRepository.java @@ -11,6 +11,8 @@ public interface GroupRepository extends JpaRepository, GroupRepositoryCustom { + Boolean existsByName(String name); + default Group getGroupById(Long id) { return this.findById(id).orElseThrow( () -> new NotFoundException(ErrorStatus.NOT_FOUND_GROUP_EXCEPTION, diff --git a/src/main/java/com/uspray/uspray/service/GroupService.java b/src/main/java/com/uspray/uspray/service/GroupService.java index bd9b8cf0..f8ae671a 100644 --- a/src/main/java/com/uspray/uspray/service/GroupService.java +++ b/src/main/java/com/uspray/uspray/service/GroupService.java @@ -1,11 +1,16 @@ package com.uspray.uspray.service; +import com.uspray.uspray.DTO.group.request.GroupKickRequestDto; +import com.uspray.uspray.DTO.group.request.GroupLeaderRequestDto; import com.uspray.uspray.DTO.group.request.GroupRequestDto; -import com.uspray.uspray.DTO.group.response.GroupDetailResponseDto; import com.uspray.uspray.DTO.group.response.GroupListResponseDto; import com.uspray.uspray.DTO.group.response.GroupResponseDto; import com.uspray.uspray.domain.Group; import com.uspray.uspray.domain.Member; +import com.uspray.uspray.exception.ErrorStatus; +import com.uspray.uspray.exception.model.CustomException; +import com.uspray.uspray.exception.model.NotFoundException; +import com.uspray.uspray.infrastructure.GroupPrayRepository; import com.uspray.uspray.infrastructure.GroupRepository; import com.uspray.uspray.infrastructure.MemberRepository; import lombok.RequiredArgsConstructor; @@ -13,6 +18,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Set; @Service @RequiredArgsConstructor @@ -20,6 +26,7 @@ public class GroupService { private final GroupRepository groupRepository; private final MemberRepository memberRepository; + private final GroupPrayRepository groupPrayRepository; @Transactional(readOnly = true) public GroupListResponseDto getGroupList(String username) { @@ -38,4 +45,65 @@ public void createGroup(String username, GroupRequestDto groupRequestDto) { member.getGroups().add(group); groupRepository.save(group); } + + @Transactional + public void changeGroupName(String username, Long groupId, GroupRequestDto groupRequestDto) { + Member member = memberRepository.getMemberByUserId(username); + Group group = groupRepository.getGroupById(groupId); + + if (!group.getLeader().equals(member)) { + throw new CustomException(ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION, ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION.getMessage()); + } + if (group.getName().equals(groupRequestDto.getName()) || groupRepository.existsByName(groupRequestDto.getName())) { + throw new CustomException(ErrorStatus.ALREADY_EXIST_GROUP_NAME_EXCEPTION, ErrorStatus.ALREADY_EXIST_GROUP_NAME_EXCEPTION.getMessage()); + } + group.changeName(groupRequestDto.getName()); + } + + @Transactional + public void changeGroupLeader(String username, Long groupId, GroupLeaderRequestDto groupLeaderRequestDto) { + Member member = memberRepository.getMemberByUserId(username); + Group group = groupRepository.getGroupById(groupId); + + if (!group.getLeader().equals(member)) { + throw new CustomException(ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION, ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION.getMessage()); + } + if (!group.getMembers().contains(memberRepository.getMemberByUserId(groupLeaderRequestDto.getUsername()))) { + throw new NotFoundException(ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION, ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION.getMessage()); + } + group.changeLeader(memberRepository.getMemberByUserId(groupLeaderRequestDto.getUsername())); + } + + @Transactional + public void kickGroupMember(String username, Long groupId, GroupKickRequestDto groupKickRequestDto) { + Member leader = memberRepository.getMemberByUserId(username); + Group group = groupRepository.getGroupById(groupId); + Member kickedMember = memberRepository.getMemberByUserId(groupKickRequestDto.getUsername()); + + if (!group.getLeader().equals(leader)) { + throw new CustomException(ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION, ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION.getMessage()); + } + if (!group.getMembers().contains(kickedMember)) { + throw new NotFoundException(ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION, ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION.getMessage()); + } + group.kickMember(memberRepository.getMemberByUserId(groupKickRequestDto.getUsername())); + kickedMember.leaveGroup(group); + } + + @Transactional + public void deleteGroup(String username, Long groupId) { + Member leader = memberRepository.getMemberByUserId(username); + Group group = groupRepository.getGroupById(groupId); + + if (!group.getLeader().equals(leader)) { + throw new CustomException(ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION, ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION.getMessage()); + } + Set members = group.getMembers(); + for (Member member : members) { + member.leaveGroup(group); + group.kickMember(member); + } + groupRepository.delete(group); + groupPrayRepository.deleteAllByGroup(group); + } } From 713e55b89d362254f490a729c92cbd648b3d78b2 Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Thu, 16 Nov 2023 20:41:17 +0900 Subject: [PATCH 10/20] feat: add validation to GroupRequestDto --- .../uspray/uspray/DTO/group/request/GroupRequestDto.java | 6 ++++-- .../java/com/uspray/uspray/service/GroupPrayService.java | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java b/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java index d0ddfb5a..4cc187c9 100644 --- a/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java +++ b/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java @@ -4,13 +4,15 @@ import lombok.Getter; import lombok.NoArgsConstructor; -import javax.validation.constraints.NotNull; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; @Getter @NoArgsConstructor @AllArgsConstructor public class GroupRequestDto { - @NotNull(message = "모임 이름을 입력해주세요.") + @NotBlank(message = "모임 이름을 입력해주세요.") + @Size(min = 1, max = 15, message = "모임 이름은 공백 포함 15자 이내로 입력해주세요.") private String name; } diff --git a/src/main/java/com/uspray/uspray/service/GroupPrayService.java b/src/main/java/com/uspray/uspray/service/GroupPrayService.java index 7492661a..fa8c021e 100644 --- a/src/main/java/com/uspray/uspray/service/GroupPrayService.java +++ b/src/main/java/com/uspray/uspray/service/GroupPrayService.java @@ -42,6 +42,7 @@ public void updateGroupPray(GroupPrayUpdateDto groupPrayUpdateDto) { } //groupId와 자신의 Id를 이용해 group pray들 반환 + 작성자인지 and 좋아요를 눌렀는지 확인 가능 + @Transactional(readOnly = true) public List getGroupPray(Long groupId, String userId) { Member member = memberRepository.getMemberByUserId(userId); Group group = groupRepository.getGroupById(groupId); From 42079d39f046f31ab1cd3682cc7c6a9239dfc377 Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Fri, 17 Nov 2023 14:51:34 +0900 Subject: [PATCH 11/20] chore: fix tab indent --- .../uspray/controller/GroupController.java | 34 +++++++++---------- .../infrastructure/HistoryRepository.java | 8 ++--- .../uspray/uspray/service/GroupService.java | 6 ++-- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/uspray/uspray/controller/GroupController.java b/src/main/java/com/uspray/uspray/controller/GroupController.java index 7642d7cd..32ceef47 100644 --- a/src/main/java/com/uspray/uspray/controller/GroupController.java +++ b/src/main/java/com/uspray/uspray/controller/GroupController.java @@ -28,28 +28,28 @@ public class GroupController { @GetMapping public ApiResponseDto getGroupList( - @Parameter(hidden = true) @AuthenticationPrincipal User user) { + @Parameter(hidden = true) @AuthenticationPrincipal User user) { return ApiResponseDto.success(SuccessStatus.GET_GROUP_LIST_SUCCESS, - groupService.getGroupList(user.getUsername())); + groupService.getGroupList(user.getUsername())); } @PostMapping public ApiResponseDto createGroup( - @Parameter(hidden = true) @AuthenticationPrincipal User user, - @Valid @RequestBody GroupRequestDto groupRequestDto) { + @Parameter(hidden = true) @AuthenticationPrincipal User user, + @Valid @RequestBody GroupRequestDto groupRequestDto) { groupService.createGroup(user.getUsername(), groupRequestDto); return ApiResponseDto.success(SuccessStatus.CREATE_GROUP_SUCCESS, - SuccessStatus.CREATE_GROUP_SUCCESS.getMessage()); + SuccessStatus.CREATE_GROUP_SUCCESS.getMessage()); } @PutMapping("/{groupId}/change-name") public ApiResponseDto changeGroupName( - @Parameter(hidden = true) @AuthenticationPrincipal User user, - @PathVariable Long groupId, - @Valid @RequestBody GroupRequestDto groupRequestDto) { + @Parameter(hidden = true) @AuthenticationPrincipal User user, + @PathVariable Long groupId, + @Valid @RequestBody GroupRequestDto groupRequestDto) { groupService.changeGroupName(user.getUsername(), groupId, groupRequestDto); return ApiResponseDto.success(SuccessStatus.CHANGE_GROUP_NAME_SUCCESS, - SuccessStatus.CHANGE_GROUP_NAME_SUCCESS.getMessage()); + SuccessStatus.CHANGE_GROUP_NAME_SUCCESS.getMessage()); } @PutMapping("/{groupId}/change-leader") @@ -59,25 +59,25 @@ public ApiResponseDto changeGroupLeader( @Valid @RequestBody GroupLeaderRequestDto groupLeaderRequestDto) { groupService.changeGroupLeader(user.getUsername(), groupId, groupLeaderRequestDto); return ApiResponseDto.success(SuccessStatus.CHANGE_GROUP_LEADER_SUCCESS, - SuccessStatus.CHANGE_GROUP_LEADER_SUCCESS.getMessage()); + SuccessStatus.CHANGE_GROUP_LEADER_SUCCESS.getMessage()); } @DeleteMapping("/{groupId}/kick") public ApiResponseDto kickGroupMember( - @Parameter(hidden = true) @AuthenticationPrincipal User user, - @PathVariable Long groupId, - @Valid @RequestBody GroupKickRequestDto groupKickRequestDto) { + @Parameter(hidden = true) @AuthenticationPrincipal User user, + @PathVariable Long groupId, + @Valid @RequestBody GroupKickRequestDto groupKickRequestDto) { groupService.kickGroupMember(user.getUsername(), groupId, groupKickRequestDto); return ApiResponseDto.success(SuccessStatus.KICK_GROUP_MEMBER_SUCCESS, - SuccessStatus.KICK_GROUP_MEMBER_SUCCESS.getMessage()); + SuccessStatus.KICK_GROUP_MEMBER_SUCCESS.getMessage()); } @DeleteMapping("/{groupId}") public ApiResponseDto deleteGroup( - @Parameter(hidden = true) @AuthenticationPrincipal User user, - @PathVariable Long groupId) { + @Parameter(hidden = true) @AuthenticationPrincipal User user, + @PathVariable Long groupId) { groupService.deleteGroup(user.getUsername(), groupId); return ApiResponseDto.success(SuccessStatus.DELETE_GROUP_SUCCESS, - SuccessStatus.DELETE_GROUP_SUCCESS.getMessage()); + SuccessStatus.DELETE_GROUP_SUCCESS.getMessage()); } } diff --git a/src/main/java/com/uspray/uspray/infrastructure/HistoryRepository.java b/src/main/java/com/uspray/uspray/infrastructure/HistoryRepository.java index 8458d150..1473b758 100644 --- a/src/main/java/com/uspray/uspray/infrastructure/HistoryRepository.java +++ b/src/main/java/com/uspray/uspray/infrastructure/HistoryRepository.java @@ -10,11 +10,11 @@ @Repository public interface HistoryRepository extends JpaRepository, HistoryRepositoryCustom { - + Page findByMemberAndOriginPrayIdIsNull(Member member, Pageable pageable); - + Page findByMemberAndOriginPrayIdIsNotNull(Member member, Pageable pageable); - - + + History findByIdAndMember(Long historyId, Member member); } diff --git a/src/main/java/com/uspray/uspray/service/GroupService.java b/src/main/java/com/uspray/uspray/service/GroupService.java index f8ae671a..91b3d5c6 100644 --- a/src/main/java/com/uspray/uspray/service/GroupService.java +++ b/src/main/java/com/uspray/uspray/service/GroupService.java @@ -39,9 +39,9 @@ public GroupListResponseDto getGroupList(String username) { public void createGroup(String username, GroupRequestDto groupRequestDto) { Member member = memberRepository.getMemberByUserId(username); Group group = Group.builder() - .name(groupRequestDto.getName()) - .leader(member) - .build(); + .name(groupRequestDto.getName()) + .leader(member) + .build(); member.getGroups().add(group); groupRepository.save(group); } From e0650acac5531334462d1486e00e5b128e76cf56 Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Fri, 17 Nov 2023 15:35:03 +0900 Subject: [PATCH 12/20] feat: add addGroupMember, leaveGroup --- .../group/request/GroupLeaderRequestDto.java | 16 -------- ...estDto.java => GroupMemberRequestDto.java} | 2 +- .../uspray/controller/GroupController.java | 29 +++++++++++--- .../java/com/uspray/uspray/domain/Group.java | 4 ++ .../java/com/uspray/uspray/domain/Member.java | 4 ++ .../uspray/uspray/exception/ErrorStatus.java | 2 + .../uspray/exception/SuccessStatus.java | 4 +- .../uspray/uspray/service/GroupService.java | 39 ++++++++++++++++--- 8 files changed, 72 insertions(+), 28 deletions(-) delete mode 100644 src/main/java/com/uspray/uspray/DTO/group/request/GroupLeaderRequestDto.java rename src/main/java/com/uspray/uspray/DTO/group/request/{GroupKickRequestDto.java => GroupMemberRequestDto.java} (88%) diff --git a/src/main/java/com/uspray/uspray/DTO/group/request/GroupLeaderRequestDto.java b/src/main/java/com/uspray/uspray/DTO/group/request/GroupLeaderRequestDto.java deleted file mode 100644 index 28b9881d..00000000 --- a/src/main/java/com/uspray/uspray/DTO/group/request/GroupLeaderRequestDto.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.uspray.uspray.DTO.group.request; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import javax.validation.constraints.NotNull; - -@Getter -@NoArgsConstructor -@AllArgsConstructor -public class GroupLeaderRequestDto { - - @NotNull - private String username; -} diff --git a/src/main/java/com/uspray/uspray/DTO/group/request/GroupKickRequestDto.java b/src/main/java/com/uspray/uspray/DTO/group/request/GroupMemberRequestDto.java similarity index 88% rename from src/main/java/com/uspray/uspray/DTO/group/request/GroupKickRequestDto.java rename to src/main/java/com/uspray/uspray/DTO/group/request/GroupMemberRequestDto.java index 06e9e2a1..bfd22c02 100644 --- a/src/main/java/com/uspray/uspray/DTO/group/request/GroupKickRequestDto.java +++ b/src/main/java/com/uspray/uspray/DTO/group/request/GroupMemberRequestDto.java @@ -9,7 +9,7 @@ @Getter @NoArgsConstructor @AllArgsConstructor -public class GroupKickRequestDto { +public class GroupMemberRequestDto { @NotNull private String username; diff --git a/src/main/java/com/uspray/uspray/controller/GroupController.java b/src/main/java/com/uspray/uspray/controller/GroupController.java index 32ceef47..3d85a8e0 100644 --- a/src/main/java/com/uspray/uspray/controller/GroupController.java +++ b/src/main/java/com/uspray/uspray/controller/GroupController.java @@ -1,8 +1,7 @@ package com.uspray.uspray.controller; import com.uspray.uspray.DTO.ApiResponseDto; -import com.uspray.uspray.DTO.group.request.GroupKickRequestDto; -import com.uspray.uspray.DTO.group.request.GroupLeaderRequestDto; +import com.uspray.uspray.DTO.group.request.GroupMemberRequestDto; import com.uspray.uspray.DTO.group.request.GroupRequestDto; import com.uspray.uspray.DTO.group.response.GroupListResponseDto; import com.uspray.uspray.exception.SuccessStatus; @@ -11,6 +10,7 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.data.repository.query.Param; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.userdetails.User; import org.springframework.web.bind.annotation.*; @@ -56,7 +56,7 @@ public ApiResponseDto changeGroupName( public ApiResponseDto changeGroupLeader( @Parameter(hidden = true) @AuthenticationPrincipal User user, @PathVariable Long groupId, - @Valid @RequestBody GroupLeaderRequestDto groupLeaderRequestDto) { + @Valid @RequestBody GroupMemberRequestDto groupLeaderRequestDto) { groupService.changeGroupLeader(user.getUsername(), groupId, groupLeaderRequestDto); return ApiResponseDto.success(SuccessStatus.CHANGE_GROUP_LEADER_SUCCESS, SuccessStatus.CHANGE_GROUP_LEADER_SUCCESS.getMessage()); @@ -66,12 +66,31 @@ public ApiResponseDto changeGroupLeader( public ApiResponseDto kickGroupMember( @Parameter(hidden = true) @AuthenticationPrincipal User user, @PathVariable Long groupId, - @Valid @RequestBody GroupKickRequestDto groupKickRequestDto) { - groupService.kickGroupMember(user.getUsername(), groupId, groupKickRequestDto); + @Valid @RequestBody GroupMemberRequestDto groupMemberRequestDto) { + groupService.kickGroupMember(user.getUsername(), groupId, groupMemberRequestDto); return ApiResponseDto.success(SuccessStatus.KICK_GROUP_MEMBER_SUCCESS, SuccessStatus.KICK_GROUP_MEMBER_SUCCESS.getMessage()); } + @PostMapping("/{groupId}/member") + public ApiResponseDto addGroupMember( + @Parameter(hidden = true) @AuthenticationPrincipal User user, + @PathVariable Long groupId, + @Valid @RequestBody GroupMemberRequestDto groupMemberRequestDto) { + groupService.addGroupMember(user.getUsername(), groupId, groupMemberRequestDto); + return ApiResponseDto.success(SuccessStatus.ADD_GROUP_MEMBER_SUCCESS, + SuccessStatus.ADD_GROUP_MEMBER_SUCCESS.getMessage()); + } + + @DeleteMapping("/{groupId}/leave") + public ApiResponseDto leaveGroup( + @Parameter(hidden = true) @AuthenticationPrincipal User user, + @PathVariable Long groupId) { + groupService.leaveGroup(user.getUsername(), groupId); + return ApiResponseDto.success(SuccessStatus.LEAVE_GROUP_SUCCESS, + SuccessStatus.LEAVE_GROUP_SUCCESS.getMessage()); + } + @DeleteMapping("/{groupId}") public ApiResponseDto deleteGroup( @Parameter(hidden = true) @AuthenticationPrincipal User user, diff --git a/src/main/java/com/uspray/uspray/domain/Group.java b/src/main/java/com/uspray/uspray/domain/Group.java index a1716ab1..8b168f10 100644 --- a/src/main/java/com/uspray/uspray/domain/Group.java +++ b/src/main/java/com/uspray/uspray/domain/Group.java @@ -50,6 +50,10 @@ public void changeLeader(Member leader) { this.leader = leader; } + public void addMember(Member member) { + this.members.add(member); + } + public void kickMember(Member member) { this.members.remove(member); } diff --git a/src/main/java/com/uspray/uspray/domain/Member.java b/src/main/java/com/uspray/uspray/domain/Member.java index 39741154..b8364ac2 100644 --- a/src/main/java/com/uspray/uspray/domain/Member.java +++ b/src/main/java/com/uspray/uspray/domain/Member.java @@ -67,6 +67,10 @@ public void changePw(String pw) { this.password = pw; } + public void joinGroup(Group group) { + this.groups.add(group); + } + public void leaveGroup(Group group) { this.groups.remove(group); } diff --git a/src/main/java/com/uspray/uspray/exception/ErrorStatus.java b/src/main/java/com/uspray/uspray/exception/ErrorStatus.java index 370577e3..08f1db75 100644 --- a/src/main/java/com/uspray/uspray/exception/ErrorStatus.java +++ b/src/main/java/com/uspray/uspray/exception/ErrorStatus.java @@ -21,6 +21,8 @@ public enum ErrorStatus { ALREADY_PRAYED_TODAY(HttpStatus.BAD_REQUEST, "오늘 이미 기도한 기도제목입니다."), CATEGORY_DUPLICATE_EXCEPTION(HttpStatus.BAD_REQUEST, "이미 존재하는 카테고리입니다."), ALREADY_EXIST_GROUP_NAME_EXCEPTION(HttpStatus.BAD_REQUEST, "이미 존재하는 모임 이름입니다."), + ALREADY_EXIST_GROUP_MEMBER_EXCEPTION(HttpStatus.BAD_REQUEST, "이미 존재하는 모임 회원입니다."), + LEADER_CANNOT_LEAVE_GROUP_EXCEPTION(HttpStatus.BAD_REQUEST, "모임장은 모임을 떠날 수 없습니다."), /* * 401 UNAUTHORIZED diff --git a/src/main/java/com/uspray/uspray/exception/SuccessStatus.java b/src/main/java/com/uspray/uspray/exception/SuccessStatus.java index c51fc5e9..41db1657 100644 --- a/src/main/java/com/uspray/uspray/exception/SuccessStatus.java +++ b/src/main/java/com/uspray/uspray/exception/SuccessStatus.java @@ -38,6 +38,7 @@ public enum SuccessStatus { CHANGE_GROUP_NAME_SUCCESS(HttpStatus.OK, "모임 이름 변경에 성공했습니다."), CHANGE_GROUP_LEADER_SUCCESS(HttpStatus.OK, "모임 리더 위임에 성공했습니다."), KICK_GROUP_MEMBER_SUCCESS(HttpStatus.OK, "모임 멤버 내보내기에 성공했습니다."), + ADD_GROUP_MEMBER_SUCCESS(HttpStatus.OK, "모임 멤버 추가하기에 성공했습니다."), /* * 201 created @@ -57,7 +58,8 @@ public enum SuccessStatus { DELETE_GROUP_PRAY_SUCCESS(HttpStatus.NO_CONTENT, "모임 기도제목 삭제에 성공했습니다."), WITHDRAWAL_SUCCESS(HttpStatus.NO_CONTENT, "회원 탈퇴에 성공했습니다."), DELETE_CATEGORY_SUCCESS(HttpStatus.NO_CONTENT, "카테고리 삭제에 성공했습니다."), - DELETE_GROUP_SUCCESS(HttpStatus.NO_CONTENT, "모임 삭제에 성공했습니다."); + DELETE_GROUP_SUCCESS(HttpStatus.NO_CONTENT, "모임 삭제에 성공했습니다."), + LEAVE_GROUP_SUCCESS(HttpStatus.NO_CONTENT, "모임 탈퇴에 성공했습니다."); private final HttpStatus httpStatus; diff --git a/src/main/java/com/uspray/uspray/service/GroupService.java b/src/main/java/com/uspray/uspray/service/GroupService.java index 91b3d5c6..a5343dc3 100644 --- a/src/main/java/com/uspray/uspray/service/GroupService.java +++ b/src/main/java/com/uspray/uspray/service/GroupService.java @@ -1,7 +1,6 @@ package com.uspray.uspray.service; -import com.uspray.uspray.DTO.group.request.GroupKickRequestDto; -import com.uspray.uspray.DTO.group.request.GroupLeaderRequestDto; +import com.uspray.uspray.DTO.group.request.GroupMemberRequestDto; import com.uspray.uspray.DTO.group.request.GroupRequestDto; import com.uspray.uspray.DTO.group.response.GroupListResponseDto; import com.uspray.uspray.DTO.group.response.GroupResponseDto; @@ -61,7 +60,7 @@ public void changeGroupName(String username, Long groupId, GroupRequestDto group } @Transactional - public void changeGroupLeader(String username, Long groupId, GroupLeaderRequestDto groupLeaderRequestDto) { + public void changeGroupLeader(String username, Long groupId, GroupMemberRequestDto groupLeaderRequestDto) { Member member = memberRepository.getMemberByUserId(username); Group group = groupRepository.getGroupById(groupId); @@ -75,7 +74,7 @@ public void changeGroupLeader(String username, Long groupId, GroupLeaderRequestD } @Transactional - public void kickGroupMember(String username, Long groupId, GroupKickRequestDto groupKickRequestDto) { + public void kickGroupMember(String username, Long groupId, GroupMemberRequestDto groupKickRequestDto) { Member leader = memberRepository.getMemberByUserId(username); Group group = groupRepository.getGroupById(groupId); Member kickedMember = memberRepository.getMemberByUserId(groupKickRequestDto.getUsername()); @@ -86,8 +85,38 @@ public void kickGroupMember(String username, Long groupId, GroupKickRequestDto g if (!group.getMembers().contains(kickedMember)) { throw new NotFoundException(ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION, ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION.getMessage()); } - group.kickMember(memberRepository.getMemberByUserId(groupKickRequestDto.getUsername())); kickedMember.leaveGroup(group); + group.kickMember(kickedMember); + } + + // 일단은 관리자만 회원을 추가할 수 있게끔 설정해두었습니다 + // 추후 수정될 수 있음 -> 초대 링크 생성하고 링크 방문시 수락으로 변경 예정 + @Transactional + public void addGroupMember(String username, Long groupId, GroupMemberRequestDto groupAddRequestDto) { + Member member = memberRepository.getMemberByUserId(username); + Group group = groupRepository.getGroupById(groupId); + Member addedMember = memberRepository.getMemberByUserId(groupAddRequestDto.getUsername()); + + if (!group.getMembers().contains(member)) { + throw new CustomException(ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION, ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION.getMessage()); + } + if (group.getMembers().contains(addedMember)) { + throw new CustomException(ErrorStatus.ALREADY_EXIST_GROUP_MEMBER_EXCEPTION, ErrorStatus.ALREADY_EXIST_GROUP_MEMBER_EXCEPTION.getMessage()); + } + addedMember.joinGroup(group); + group.addMember(addedMember); + } + + @Transactional + public void leaveGroup(String username, Long groupId) { + Member member = memberRepository.getMemberByUserId(username); + Group group = groupRepository.getGroupById(groupId); + + if (group.getLeader().equals(member)) { + throw new CustomException(ErrorStatus.LEADER_CANNOT_LEAVE_GROUP_EXCEPTION, ErrorStatus.LEADER_CANNOT_LEAVE_GROUP_EXCEPTION.getMessage()); + } + member.leaveGroup(group); + group.kickMember(member); } @Transactional From 344ec5295e86abb46f9ba6db11ec64efc3f8946d Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Fri, 17 Nov 2023 15:38:35 +0900 Subject: [PATCH 13/20] feat: add Group to initDb --- src/main/java/com/uspray/uspray/InitDb.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/uspray/uspray/InitDb.java b/src/main/java/com/uspray/uspray/InitDb.java index ea9ef927..bcb8a8fe 100644 --- a/src/main/java/com/uspray/uspray/InitDb.java +++ b/src/main/java/com/uspray/uspray/InitDb.java @@ -2,10 +2,8 @@ import com.uspray.uspray.Enums.Authority; import com.uspray.uspray.Enums.PrayType; -import com.uspray.uspray.domain.Category; -import com.uspray.uspray.domain.History; -import com.uspray.uspray.domain.Member; -import com.uspray.uspray.domain.Pray; +import com.uspray.uspray.domain.*; + import java.time.LocalDate; import javax.annotation.PostConstruct; import javax.persistence.EntityManager; @@ -45,7 +43,13 @@ public void dbInit() { .authority(Authority.ROLE_USER) .build(); em.persist(member); - + + Group group = Group.builder() + .leader(member) + .name("테스트 모임") + .build(); + em.persist(group); + Category category = Category.builder() .name("기타 카테고리") .color("#FFFFFF") From aa518d2ebba7fc0cef020d4f634e91cb7da460fe Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Sat, 18 Nov 2023 14:13:17 +0900 Subject: [PATCH 14/20] fix: fix certain logic that prevents group leaders from leaving a group --- .../com/uspray/uspray/DTO/group/request/GroupRequestDto.java | 4 ++-- src/main/java/com/uspray/uspray/service/GroupService.java | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java b/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java index 4cc187c9..256b04fa 100644 --- a/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java +++ b/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java @@ -12,7 +12,7 @@ @AllArgsConstructor public class GroupRequestDto { - @NotBlank(message = "모임 이름을 입력해주세요.") - @Size(min = 1, max = 15, message = "모임 이름은 공백 포함 15자 이내로 입력해주세요.") + @NotBlank + @Size(min = 1, max = 15, message = "공백 포함 15자 이내로 입력해주세요.") private String name; } diff --git a/src/main/java/com/uspray/uspray/service/GroupService.java b/src/main/java/com/uspray/uspray/service/GroupService.java index a5343dc3..67d2bcb0 100644 --- a/src/main/java/com/uspray/uspray/service/GroupService.java +++ b/src/main/java/com/uspray/uspray/service/GroupService.java @@ -82,6 +82,9 @@ public void kickGroupMember(String username, Long groupId, GroupMemberRequestDto if (!group.getLeader().equals(leader)) { throw new CustomException(ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION, ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION.getMessage()); } + if (group.getLeader().equals(kickedMember)) { + throw new CustomException(ErrorStatus.LEADER_CANNOT_LEAVE_GROUP_EXCEPTION, ErrorStatus.LEADER_CANNOT_LEAVE_GROUP_EXCEPTION.getMessage()); + } if (!group.getMembers().contains(kickedMember)) { throw new NotFoundException(ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION, ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION.getMessage()); } @@ -89,8 +92,6 @@ public void kickGroupMember(String username, Long groupId, GroupMemberRequestDto group.kickMember(kickedMember); } - // 일단은 관리자만 회원을 추가할 수 있게끔 설정해두었습니다 - // 추후 수정될 수 있음 -> 초대 링크 생성하고 링크 방문시 수락으로 변경 예정 @Transactional public void addGroupMember(String username, Long groupId, GroupMemberRequestDto groupAddRequestDto) { Member member = memberRepository.getMemberByUserId(username); From 65007f17175bd56dc16dd5c18ddf431115d5fd55 Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Sat, 18 Nov 2023 14:13:51 +0900 Subject: [PATCH 15/20] fix: build connection between member and group --- src/main/java/com/uspray/uspray/InitDb.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/uspray/uspray/InitDb.java b/src/main/java/com/uspray/uspray/InitDb.java index bcb8a8fe..55d377ee 100644 --- a/src/main/java/com/uspray/uspray/InitDb.java +++ b/src/main/java/com/uspray/uspray/InitDb.java @@ -48,6 +48,8 @@ public void dbInit() { .leader(member) .name("테스트 모임") .build(); + group.addMember(member); + member.joinGroup(group); em.persist(group); Category category = Category.builder() From bb96f67c552dc344b64dbc8f13b9abbfd54f9b6e Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Fri, 24 Nov 2023 15:22:30 +0900 Subject: [PATCH 16/20] chore: change import to static import --- .../querydsl/group/GroupRepositoryImpl.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java index b62998f7..a23b32d0 100644 --- a/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java +++ b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java @@ -1,5 +1,9 @@ package com.uspray.uspray.infrastructure.querydsl.group; +import static com.uspray.uspray.domain.QGroup.group; +import static com.uspray.uspray.domain.QMember.member; +import static com.uspray.uspray.domain.QGroupPray.groupPray; + import com.querydsl.core.types.Projections; import com.querydsl.jpa.impl.JPAQueryFactory; import com.uspray.uspray.DTO.group.response.GroupResponseDto; @@ -16,11 +20,7 @@ public class GroupRepositoryImpl implements GroupRepositoryCustom { private final JPAQueryFactory queryFactory; @Override - public List findGroupListByMember(Member member) { - - QGroup group = QGroup.group; - QMember memberEntity = QMember.member; - QGroupPray groupPray = QGroupPray.groupPray; + public List findGroupListByMember(Member target) { return queryFactory .select(Projections.constructor( @@ -34,8 +34,8 @@ public List findGroupListByMember(Member member) { )) .from(group) .leftJoin(group.groupPrayList, groupPray) - .leftJoin(group.members, memberEntity) - .where(group.members.contains(member)) + .leftJoin(group.members, member) + .where(group.members.contains(target)) .groupBy(group.id) .fetch(); } From ddc1d52a4843231afdbb3182a5d45c8cdfa35bd7 Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Fri, 24 Nov 2023 15:46:27 +0900 Subject: [PATCH 17/20] refactor: apply facade design pattern --- .../uspray/controller/GroupController.java | 21 +++++++++---------- .../infrastructure/GroupPrayRepository.java | 3 --- ...upService.java => GroupFacadeService.java} | 5 +---- 3 files changed, 11 insertions(+), 18 deletions(-) rename src/main/java/com/uspray/uspray/service/{GroupService.java => GroupFacadeService.java} (96%) diff --git a/src/main/java/com/uspray/uspray/controller/GroupController.java b/src/main/java/com/uspray/uspray/controller/GroupController.java index 3d85a8e0..c01a5897 100644 --- a/src/main/java/com/uspray/uspray/controller/GroupController.java +++ b/src/main/java/com/uspray/uspray/controller/GroupController.java @@ -5,12 +5,11 @@ import com.uspray.uspray.DTO.group.request.GroupRequestDto; import com.uspray.uspray.DTO.group.response.GroupListResponseDto; import com.uspray.uspray.exception.SuccessStatus; -import com.uspray.uspray.service.GroupService; +import com.uspray.uspray.service.GroupFacadeService; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.data.repository.query.Param; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.userdetails.User; import org.springframework.web.bind.annotation.*; @@ -24,20 +23,20 @@ @SecurityRequirement(name = "JWT Auth") public class GroupController { - private final GroupService groupService; + private final GroupFacadeService groupFacadeService; @GetMapping public ApiResponseDto getGroupList( @Parameter(hidden = true) @AuthenticationPrincipal User user) { return ApiResponseDto.success(SuccessStatus.GET_GROUP_LIST_SUCCESS, - groupService.getGroupList(user.getUsername())); + groupFacadeService.getGroupList(user.getUsername())); } @PostMapping public ApiResponseDto createGroup( @Parameter(hidden = true) @AuthenticationPrincipal User user, @Valid @RequestBody GroupRequestDto groupRequestDto) { - groupService.createGroup(user.getUsername(), groupRequestDto); + groupFacadeService.createGroup(user.getUsername(), groupRequestDto); return ApiResponseDto.success(SuccessStatus.CREATE_GROUP_SUCCESS, SuccessStatus.CREATE_GROUP_SUCCESS.getMessage()); } @@ -47,7 +46,7 @@ public ApiResponseDto changeGroupName( @Parameter(hidden = true) @AuthenticationPrincipal User user, @PathVariable Long groupId, @Valid @RequestBody GroupRequestDto groupRequestDto) { - groupService.changeGroupName(user.getUsername(), groupId, groupRequestDto); + groupFacadeService.changeGroupName(user.getUsername(), groupId, groupRequestDto); return ApiResponseDto.success(SuccessStatus.CHANGE_GROUP_NAME_SUCCESS, SuccessStatus.CHANGE_GROUP_NAME_SUCCESS.getMessage()); } @@ -57,7 +56,7 @@ public ApiResponseDto changeGroupLeader( @Parameter(hidden = true) @AuthenticationPrincipal User user, @PathVariable Long groupId, @Valid @RequestBody GroupMemberRequestDto groupLeaderRequestDto) { - groupService.changeGroupLeader(user.getUsername(), groupId, groupLeaderRequestDto); + groupFacadeService.changeGroupLeader(user.getUsername(), groupId, groupLeaderRequestDto); return ApiResponseDto.success(SuccessStatus.CHANGE_GROUP_LEADER_SUCCESS, SuccessStatus.CHANGE_GROUP_LEADER_SUCCESS.getMessage()); } @@ -67,7 +66,7 @@ public ApiResponseDto kickGroupMember( @Parameter(hidden = true) @AuthenticationPrincipal User user, @PathVariable Long groupId, @Valid @RequestBody GroupMemberRequestDto groupMemberRequestDto) { - groupService.kickGroupMember(user.getUsername(), groupId, groupMemberRequestDto); + groupFacadeService.kickGroupMember(user.getUsername(), groupId, groupMemberRequestDto); return ApiResponseDto.success(SuccessStatus.KICK_GROUP_MEMBER_SUCCESS, SuccessStatus.KICK_GROUP_MEMBER_SUCCESS.getMessage()); } @@ -77,7 +76,7 @@ public ApiResponseDto addGroupMember( @Parameter(hidden = true) @AuthenticationPrincipal User user, @PathVariable Long groupId, @Valid @RequestBody GroupMemberRequestDto groupMemberRequestDto) { - groupService.addGroupMember(user.getUsername(), groupId, groupMemberRequestDto); + groupFacadeService.addGroupMember(user.getUsername(), groupId, groupMemberRequestDto); return ApiResponseDto.success(SuccessStatus.ADD_GROUP_MEMBER_SUCCESS, SuccessStatus.ADD_GROUP_MEMBER_SUCCESS.getMessage()); } @@ -86,7 +85,7 @@ public ApiResponseDto addGroupMember( public ApiResponseDto leaveGroup( @Parameter(hidden = true) @AuthenticationPrincipal User user, @PathVariable Long groupId) { - groupService.leaveGroup(user.getUsername(), groupId); + groupFacadeService.leaveGroup(user.getUsername(), groupId); return ApiResponseDto.success(SuccessStatus.LEAVE_GROUP_SUCCESS, SuccessStatus.LEAVE_GROUP_SUCCESS.getMessage()); } @@ -95,7 +94,7 @@ public ApiResponseDto leaveGroup( public ApiResponseDto deleteGroup( @Parameter(hidden = true) @AuthenticationPrincipal User user, @PathVariable Long groupId) { - groupService.deleteGroup(user.getUsername(), groupId); + groupFacadeService.deleteGroup(user.getUsername(), groupId); return ApiResponseDto.success(SuccessStatus.DELETE_GROUP_SUCCESS, SuccessStatus.DELETE_GROUP_SUCCESS.getMessage()); } diff --git a/src/main/java/com/uspray/uspray/infrastructure/GroupPrayRepository.java b/src/main/java/com/uspray/uspray/infrastructure/GroupPrayRepository.java index b868997e..bb9ee9d9 100644 --- a/src/main/java/com/uspray/uspray/infrastructure/GroupPrayRepository.java +++ b/src/main/java/com/uspray/uspray/infrastructure/GroupPrayRepository.java @@ -1,6 +1,5 @@ package com.uspray.uspray.infrastructure; -import com.uspray.uspray.domain.Group; import com.uspray.uspray.domain.GroupPray; import com.uspray.uspray.exception.ErrorStatus; import com.uspray.uspray.exception.model.NotFoundException; @@ -10,8 +9,6 @@ public interface GroupPrayRepository extends JpaRepository, GroupPrayRepositoryCustom { - void deleteAllByGroup(Group group); - default GroupPray getGroupPrayById(Long id) { return this.findById(id).orElseThrow( () -> new NotFoundException(ErrorStatus.NOT_FOUND_GROUP_PRAY_EXCEPTION, diff --git a/src/main/java/com/uspray/uspray/service/GroupService.java b/src/main/java/com/uspray/uspray/service/GroupFacadeService.java similarity index 96% rename from src/main/java/com/uspray/uspray/service/GroupService.java rename to src/main/java/com/uspray/uspray/service/GroupFacadeService.java index 67d2bcb0..af079e7f 100644 --- a/src/main/java/com/uspray/uspray/service/GroupService.java +++ b/src/main/java/com/uspray/uspray/service/GroupFacadeService.java @@ -9,7 +9,6 @@ import com.uspray.uspray.exception.ErrorStatus; import com.uspray.uspray.exception.model.CustomException; import com.uspray.uspray.exception.model.NotFoundException; -import com.uspray.uspray.infrastructure.GroupPrayRepository; import com.uspray.uspray.infrastructure.GroupRepository; import com.uspray.uspray.infrastructure.MemberRepository; import lombok.RequiredArgsConstructor; @@ -21,11 +20,10 @@ @Service @RequiredArgsConstructor -public class GroupService { +public class GroupFacadeService { private final GroupRepository groupRepository; private final MemberRepository memberRepository; - private final GroupPrayRepository groupPrayRepository; @Transactional(readOnly = true) public GroupListResponseDto getGroupList(String username) { @@ -134,6 +132,5 @@ public void deleteGroup(String username, Long groupId) { group.kickMember(member); } groupRepository.delete(group); - groupPrayRepository.deleteAllByGroup(group); } } From 985c120a17666d08e4e785ecad6ccc788c573296 Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Fri, 24 Nov 2023 16:00:23 +0900 Subject: [PATCH 18/20] refactor: move validation logic to domain --- .../java/com/uspray/uspray/domain/Group.java | 20 +++++++++++ .../uspray/service/GroupFacadeService.java | 34 +++++-------------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/uspray/uspray/domain/Group.java b/src/main/java/com/uspray/uspray/domain/Group.java index 8b168f10..b99050a5 100644 --- a/src/main/java/com/uspray/uspray/domain/Group.java +++ b/src/main/java/com/uspray/uspray/domain/Group.java @@ -7,6 +7,9 @@ import java.util.Set; import javax.persistence.*; +import com.uspray.uspray.exception.ErrorStatus; +import com.uspray.uspray.exception.model.CustomException; +import com.uspray.uspray.exception.model.NotFoundException; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -58,4 +61,21 @@ public void kickMember(Member member) { this.members.remove(member); } + public void validateGroupName(String newName) { + if (this.name.equals(newName)) { + throw new CustomException(ErrorStatus.ALREADY_EXIST_GROUP_NAME_EXCEPTION, ErrorStatus.ALREADY_EXIST_GROUP_NAME_EXCEPTION.getMessage()); + } + } + + public void checkLeaderAuthorization(Member member) { + if (!this.leader.equals(member)) { + throw new CustomException(ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION, ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION.getMessage()); + } + } + + public void checkGroupMember(Member member) { + if (!this.members.contains(member)) { + throw new NotFoundException(ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION, ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION.getMessage()); + } + } } diff --git a/src/main/java/com/uspray/uspray/service/GroupFacadeService.java b/src/main/java/com/uspray/uspray/service/GroupFacadeService.java index af079e7f..bdbd7f99 100644 --- a/src/main/java/com/uspray/uspray/service/GroupFacadeService.java +++ b/src/main/java/com/uspray/uspray/service/GroupFacadeService.java @@ -8,7 +8,6 @@ import com.uspray.uspray.domain.Member; import com.uspray.uspray.exception.ErrorStatus; import com.uspray.uspray.exception.model.CustomException; -import com.uspray.uspray.exception.model.NotFoundException; import com.uspray.uspray.infrastructure.GroupRepository; import com.uspray.uspray.infrastructure.MemberRepository; import lombok.RequiredArgsConstructor; @@ -48,26 +47,19 @@ public void changeGroupName(String username, Long groupId, GroupRequestDto group Member member = memberRepository.getMemberByUserId(username); Group group = groupRepository.getGroupById(groupId); - if (!group.getLeader().equals(member)) { - throw new CustomException(ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION, ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION.getMessage()); - } - if (group.getName().equals(groupRequestDto.getName()) || groupRepository.existsByName(groupRequestDto.getName())) { - throw new CustomException(ErrorStatus.ALREADY_EXIST_GROUP_NAME_EXCEPTION, ErrorStatus.ALREADY_EXIST_GROUP_NAME_EXCEPTION.getMessage()); - } + group.validateGroupName(groupRequestDto.getName()); + group.checkLeaderAuthorization(member); group.changeName(groupRequestDto.getName()); } @Transactional public void changeGroupLeader(String username, Long groupId, GroupMemberRequestDto groupLeaderRequestDto) { Member member = memberRepository.getMemberByUserId(username); + Member newLeader = memberRepository.getMemberByUserId(groupLeaderRequestDto.getUsername()); Group group = groupRepository.getGroupById(groupId); - if (!group.getLeader().equals(member)) { - throw new CustomException(ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION, ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION.getMessage()); - } - if (!group.getMembers().contains(memberRepository.getMemberByUserId(groupLeaderRequestDto.getUsername()))) { - throw new NotFoundException(ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION, ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION.getMessage()); - } + group.checkLeaderAuthorization(member); + group.checkGroupMember(newLeader); group.changeLeader(memberRepository.getMemberByUserId(groupLeaderRequestDto.getUsername())); } @@ -77,15 +69,11 @@ public void kickGroupMember(String username, Long groupId, GroupMemberRequestDto Group group = groupRepository.getGroupById(groupId); Member kickedMember = memberRepository.getMemberByUserId(groupKickRequestDto.getUsername()); - if (!group.getLeader().equals(leader)) { - throw new CustomException(ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION, ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION.getMessage()); - } + group.checkLeaderAuthorization(leader); if (group.getLeader().equals(kickedMember)) { throw new CustomException(ErrorStatus.LEADER_CANNOT_LEAVE_GROUP_EXCEPTION, ErrorStatus.LEADER_CANNOT_LEAVE_GROUP_EXCEPTION.getMessage()); } - if (!group.getMembers().contains(kickedMember)) { - throw new NotFoundException(ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION, ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION.getMessage()); - } + group.checkGroupMember(kickedMember); kickedMember.leaveGroup(group); group.kickMember(kickedMember); } @@ -96,9 +84,7 @@ public void addGroupMember(String username, Long groupId, GroupMemberRequestDto Group group = groupRepository.getGroupById(groupId); Member addedMember = memberRepository.getMemberByUserId(groupAddRequestDto.getUsername()); - if (!group.getMembers().contains(member)) { - throw new CustomException(ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION, ErrorStatus.GROUP_MEMBER_NOT_FOUND_EXCEPTION.getMessage()); - } + group.checkGroupMember(member); if (group.getMembers().contains(addedMember)) { throw new CustomException(ErrorStatus.ALREADY_EXIST_GROUP_MEMBER_EXCEPTION, ErrorStatus.ALREADY_EXIST_GROUP_MEMBER_EXCEPTION.getMessage()); } @@ -123,9 +109,7 @@ public void deleteGroup(String username, Long groupId) { Member leader = memberRepository.getMemberByUserId(username); Group group = groupRepository.getGroupById(groupId); - if (!group.getLeader().equals(leader)) { - throw new CustomException(ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION, ErrorStatus.GROUP_UNAUTHORIZED_EXCEPTION.getMessage()); - } + group.checkLeaderAuthorization(leader); Set members = group.getMembers(); for (Member member : members) { member.leaveGroup(group); From 2c46ffaeca629d8de2995791d7dfdb54fc18e26d Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Fri, 24 Nov 2023 16:03:22 +0900 Subject: [PATCH 19/20] fix: add a validation logic --- src/main/java/com/uspray/uspray/service/GroupFacadeService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/uspray/uspray/service/GroupFacadeService.java b/src/main/java/com/uspray/uspray/service/GroupFacadeService.java index bdbd7f99..15e32433 100644 --- a/src/main/java/com/uspray/uspray/service/GroupFacadeService.java +++ b/src/main/java/com/uspray/uspray/service/GroupFacadeService.java @@ -100,6 +100,7 @@ public void leaveGroup(String username, Long groupId) { if (group.getLeader().equals(member)) { throw new CustomException(ErrorStatus.LEADER_CANNOT_LEAVE_GROUP_EXCEPTION, ErrorStatus.LEADER_CANNOT_LEAVE_GROUP_EXCEPTION.getMessage()); } + group.checkGroupMember(member); member.leaveGroup(group); group.kickMember(member); } From e6c367e16594f95d04026f3f0c6ea1dc7965d55f Mon Sep 17 00:00:00 2001 From: Sion Shin Date: Fri, 24 Nov 2023 17:06:31 +0900 Subject: [PATCH 20/20] refactor: change querydsl projections to QGroupResponseDto constructor --- .../uspray/DTO/group/response/GroupResponseDto.java | 13 ++++++++++--- .../querydsl/group/GroupRepositoryImpl.java | 5 ++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java b/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java index db66323b..e0a28ae6 100644 --- a/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java +++ b/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java @@ -1,8 +1,7 @@ package com.uspray.uspray.DTO.group.response; -import com.uspray.uspray.domain.Group; +import com.querydsl.core.annotations.QueryProjection; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -11,7 +10,6 @@ @Getter @NoArgsConstructor -@AllArgsConstructor @Builder @Schema(description = "모임 응답 DTO") public class GroupResponseDto { @@ -28,4 +26,13 @@ public class GroupResponseDto { private LocalDateTime updatedAt; + @QueryProjection + public GroupResponseDto(Long id, String name, String lastPrayContent, Integer memberCount, Integer prayCount, LocalDateTime updatedAt) { + this.id = id; + this.name = name; + this.lastPrayContent = lastPrayContent; + this.memberCount = memberCount; + this.prayCount = prayCount; + this.updatedAt = updatedAt; + } } diff --git a/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java index a23b32d0..b58df3ad 100644 --- a/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java +++ b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java @@ -4,9 +4,9 @@ import static com.uspray.uspray.domain.QMember.member; import static com.uspray.uspray.domain.QGroupPray.groupPray; -import com.querydsl.core.types.Projections; import com.querydsl.jpa.impl.JPAQueryFactory; import com.uspray.uspray.DTO.group.response.GroupResponseDto; +import com.uspray.uspray.DTO.group.response.QGroupResponseDto; import com.uspray.uspray.domain.*; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -23,8 +23,7 @@ public class GroupRepositoryImpl implements GroupRepositoryCustom { public List findGroupListByMember(Member target) { return queryFactory - .select(Projections.constructor( - GroupResponseDto.class, + .select(new QGroupResponseDto( group.id, group.name, groupPray.content.max(),