diff --git a/src/main/java/com/uspray/uspray/DTO/group/request/GroupMemberRequestDto.java b/src/main/java/com/uspray/uspray/DTO/group/request/GroupMemberRequestDto.java new file mode 100644 index 00000000..bfd22c02 --- /dev/null +++ b/src/main/java/com/uspray/uspray/DTO/group/request/GroupMemberRequestDto.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 GroupMemberRequestDto { + + @NotNull + private String username; +} 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..256b04fa --- /dev/null +++ b/src/main/java/com/uspray/uspray/DTO/group/request/GroupRequestDto.java @@ -0,0 +1,18 @@ +package com.uspray.uspray.DTO.group.request; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class GroupRequestDto { + + @NotBlank + @Size(min = 1, max = 15, message = "공백 포함 15자 이내로 입력해주세요.") + private String name; +} 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/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..e0a28ae6 --- /dev/null +++ b/src/main/java/com/uspray/uspray/DTO/group/response/GroupResponseDto.java @@ -0,0 +1,38 @@ +package com.uspray.uspray.DTO.group.response; + +import com.querydsl.core.annotations.QueryProjection; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Getter +@NoArgsConstructor +@Builder +@Schema(description = "모임 응답 DTO") +public class GroupResponseDto { + + private Long id; + + private String name; + + private String lastPrayContent; + + private Integer memberCount; + + private Integer prayCount; + + 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/InitDb.java b/src/main/java/com/uspray/uspray/InitDb.java index ea9ef927..55d377ee 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,15 @@ public void dbInit() { .authority(Authority.ROLE_USER) .build(); em.persist(member); - + + Group group = Group.builder() + .leader(member) + .name("테스트 모임") + .build(); + group.addMember(member); + member.joinGroup(group); + em.persist(group); + Category category = Category.builder() .name("기타 카테고리") .color("#FFFFFF") 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..c01a5897 --- /dev/null +++ b/src/main/java/com/uspray/uspray/controller/GroupController.java @@ -0,0 +1,101 @@ +package com.uspray.uspray.controller; + +import com.uspray.uspray.DTO.ApiResponseDto; +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; +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.security.core.annotation.AuthenticationPrincipal; +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") +@RequiredArgsConstructor +@SecurityRequirement(name = "JWT Auth") +public class GroupController { + + private final GroupFacadeService groupFacadeService; + + @GetMapping + public ApiResponseDto getGroupList( + @Parameter(hidden = true) @AuthenticationPrincipal User user) { + return ApiResponseDto.success(SuccessStatus.GET_GROUP_LIST_SUCCESS, + groupFacadeService.getGroupList(user.getUsername())); + } + + @PostMapping + public ApiResponseDto createGroup( + @Parameter(hidden = true) @AuthenticationPrincipal User user, + @Valid @RequestBody GroupRequestDto groupRequestDto) { + groupFacadeService.createGroup(user.getUsername(), groupRequestDto); + 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) { + groupFacadeService.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 GroupMemberRequestDto groupLeaderRequestDto) { + groupFacadeService.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 GroupMemberRequestDto groupMemberRequestDto) { + groupFacadeService.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) { + groupFacadeService.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) { + groupFacadeService.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, + @PathVariable Long 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/domain/Group.java b/src/main/java/com/uspray/uspray/domain/Group.java index 80945b30..b99050a5 100644 --- a/src/main/java/com/uspray/uspray/domain/Group.java +++ b/src/main/java/com/uspray/uspray/domain/Group.java @@ -1,15 +1,17 @@ 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 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; import lombok.NoArgsConstructor; @@ -24,7 +26,56 @@ 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; + @Builder + public Group(String name, Member leader) { + this.name = name; + this.members.add(leader); + this.leader = leader; + } + + public void changeName(String name) { + this.name = name; + } + + 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); + } + + 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/domain/Member.java b/src/main/java/com/uspray/uspray/domain/Member.java index e0889603..b8364ac2 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; @@ -26,56 +23,69 @@ @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; - - @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; + } + + public void joinGroup(Group group) { + this.groups.add(group); + } + + 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) { + 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/ErrorStatus.java b/src/main/java/com/uspray/uspray/exception/ErrorStatus.java index e8ef47f7..54080936 100644 --- a/src/main/java/com/uspray/uspray/exception/ErrorStatus.java +++ b/src/main/java/com/uspray/uspray/exception/ErrorStatus.java @@ -20,6 +20,9 @@ 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, "이미 존재하는 모임 이름입니다."), + ALREADY_EXIST_GROUP_MEMBER_EXCEPTION(HttpStatus.BAD_REQUEST, "이미 존재하는 모임 회원입니다."), + LEADER_CANNOT_LEAVE_GROUP_EXCEPTION(HttpStatus.BAD_REQUEST, "모임장은 모임을 떠날 수 없습니다."), ALREADY_SHARED_EXCEPTION(HttpStatus.BAD_REQUEST, "이미 공유된 기도제목입니다."), /* * 401 UNAUTHORIZED @@ -29,7 +32,8 @@ 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 */ @@ -40,8 +44,9 @@ 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 3d57a079..41db1657 100644 --- a/src/main/java/com/uspray/uspray/exception/SuccessStatus.java +++ b/src/main/java/com/uspray/uspray/exception/SuccessStatus.java @@ -33,6 +33,13 @@ 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, "모임 목록 조회에 성공했습니다."), + GET_GROUP_DETAIL_SUCCESS(HttpStatus.OK, "모임 상세 조회에 성공했습니다."), + 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 */ @@ -42,6 +49,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 @@ -49,7 +57,9 @@ 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, "모임 삭제에 성공했습니다."), + LEAVE_GROUP_SUCCESS(HttpStatus.NO_CONTENT, "모임 탈퇴에 성공했습니다."); private final HttpStatus httpStatus; diff --git a/src/main/java/com/uspray/uspray/infrastructure/GroupRepository.java b/src/main/java/com/uspray/uspray/infrastructure/GroupRepository.java index 4c77372c..ca1bfa21 100644 --- a/src/main/java/com/uspray/uspray/infrastructure/GroupRepository.java +++ b/src/main/java/com/uspray/uspray/infrastructure/GroupRepository.java @@ -1,11 +1,17 @@ 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 { + + Boolean existsByName(String name); 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..1473b758 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; @@ -9,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/infrastructure/querydsl/group/GroupRepositoryCustom.java b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryCustom.java new file mode 100644 index 00000000..67bfd7cd --- /dev/null +++ b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryCustom.java @@ -0,0 +1,13 @@ +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 { + + 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..b58df3ad --- /dev/null +++ b/src/main/java/com/uspray/uspray/infrastructure/querydsl/group/GroupRepositoryImpl.java @@ -0,0 +1,41 @@ +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.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; + +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class GroupRepositoryImpl implements GroupRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + @Override + public List findGroupListByMember(Member target) { + + return queryFactory + .select(new QGroupResponseDto( + 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, member) + .where(group.members.contains(target)) + .groupBy(group.id) + .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/GroupFacadeService.java b/src/main/java/com/uspray/uspray/service/GroupFacadeService.java new file mode 100644 index 00000000..15e32433 --- /dev/null +++ b/src/main/java/com/uspray/uspray/service/GroupFacadeService.java @@ -0,0 +1,121 @@ +package com.uspray.uspray.service; + +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; +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.infrastructure.GroupRepository; +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 +public class GroupFacadeService { + + 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()) + .leader(member) + .build(); + 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); + + 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); + + group.checkLeaderAuthorization(member); + group.checkGroupMember(newLeader); + group.changeLeader(memberRepository.getMemberByUserId(groupLeaderRequestDto.getUsername())); + } + + @Transactional + 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()); + + group.checkLeaderAuthorization(leader); + if (group.getLeader().equals(kickedMember)) { + throw new CustomException(ErrorStatus.LEADER_CANNOT_LEAVE_GROUP_EXCEPTION, ErrorStatus.LEADER_CANNOT_LEAVE_GROUP_EXCEPTION.getMessage()); + } + group.checkGroupMember(kickedMember); + 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()); + + group.checkGroupMember(member); + 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()); + } + group.checkGroupMember(member); + member.leaveGroup(group); + group.kickMember(member); + } + + @Transactional + public void deleteGroup(String username, Long groupId) { + Member leader = memberRepository.getMemberByUserId(username); + Group group = groupRepository.getGroupById(groupId); + + group.checkLeaderAuthorization(leader); + Set members = group.getMembers(); + for (Member member : members) { + member.leaveGroup(group); + group.kickMember(member); + } + groupRepository.delete(group); + } +} 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);