Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package project.flipnote.infra.config;
package project.flipnote.common.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,25 @@
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import project.flipnote.common.model.response.CursorPagingResponse;
import project.flipnote.common.security.dto.AuthPrinciple;
import project.flipnote.group.model.FindGroupMemberResponse;
import project.flipnote.group.model.GroupCreateRequest;
import project.flipnote.group.model.GroupCreateResponse;
import project.flipnote.group.model.GroupDetailResponse;
import project.flipnote.group.model.GroupInfo;
import project.flipnote.group.model.GroupListRequest;
import project.flipnote.group.model.GroupPutRequest;
import project.flipnote.group.model.GroupPutResponse;
import project.flipnote.group.service.GroupService;
Expand Down Expand Up @@ -78,4 +83,15 @@ public ResponseEntity<FindGroupMemberResponse> findGroupMembers(

return ResponseEntity.ok(res);
}

//그룹 전체 조회
@GetMapping
public ResponseEntity<CursorPagingResponse<GroupInfo>> findGroup(
@AuthenticationPrincipal AuthPrinciple authPrinciple,
@Valid @ModelAttribute GroupListRequest req
) {
CursorPagingResponse<GroupInfo> res = groupService.findGroup(authPrinciple, req);

return ResponseEntity.ok(res);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ public class GroupRolePermission {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "group_id", nullable = false)
private Group group;

@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "group_permission_id", nullable = false)
private GroupPermission groupPermission;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ public enum GroupErrorCode implements ErrorCode {
OTHER_USER_EXIST_IN_GROUP(HttpStatus.CONFLICT, "GROUP_005", "그룹내 오너 제외 유저가 존재합니다."),
GROUP_IS_ALREADY_MAX_MEMBER(HttpStatus.CONFLICT, "GROUP_006", "그룹 정원이 가득 찼습니다."),
ALREADY_GROUP_MEMBER(HttpStatus.CONFLICT, "GROUP_007", "이미 그룹 회원입니다."),
INVALID_MEMBER_COUNT(HttpStatus.BAD_REQUEST, "GROUP_008", "그룹 내에 인원수보다 많게 수정해야합니다.");
INVALID_MEMBER_COUNT(HttpStatus.BAD_REQUEST, "GROUP_008", "현재 그룹 인원수보다 작게 설정할 수 없습니다."),
INVALID_CATEGORY(HttpStatus.BAD_REQUEST, "GROUP_009", "지원하지 않는 카테고리입니다." );

private final HttpStatus httpStatus;
private final String code;
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/project/flipnote/group/model/GroupInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package project.flipnote.group.model;

import project.flipnote.group.entity.Category;

public record GroupInfo(
Long groupId,
String name,
String description,
Category category,
String imageUrl) {
public static GroupInfo from(Long groupId, String name, String description, Category category, String imageUrl) {
return new GroupInfo(groupId, name, description, category, imageUrl);
}
}
20 changes: 20 additions & 0 deletions src/main/java/project/flipnote/group/model/GroupListRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package project.flipnote.group.model;

import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;

import lombok.Getter;
import lombok.Setter;
import project.flipnote.common.model.request.CursorPagingRequest;

@Setter
@Getter
public class GroupListRequest extends CursorPagingRequest {

private String category;

@Override
public PageRequest getPageRequest() {
return PageRequest.of(0, getSize(), Sort.by(Sort.Direction.DESC, "id"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import java.util.List;

import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;

import lombok.RequiredArgsConstructor;
Expand All @@ -19,6 +18,7 @@ public class GroupMemberRepositoryImpl implements GroupMemberRepositoryCustom {
QUserProfile userProfile = QUserProfile.userProfile;
QGroupMember groupMember = QGroupMember.groupMember;

@Override
public List<GroupMemberInfo> findGroupMembers(Long groupId) {
return queryFactory.select(Projections.constructor(
GroupMemberInfo.class,
Expand All @@ -32,5 +32,4 @@ public List<GroupMemberInfo> findGroupMembers(Long groupId) {
.where(groupMember.group.id.eq(groupId))
.fetch();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import project.flipnote.group.entity.Group;

@Repository
public interface GroupRepository extends JpaRepository<Group, Long> {
public interface GroupRepository extends JpaRepository<Group, Long>, GroupRepositoryCustom {

Optional<Group> findByIdAndDeletedAtIsNull(Long groupId);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package project.flipnote.group.repository;

import java.util.List;

import project.flipnote.group.entity.Category;
import project.flipnote.group.model.GroupInfo;

public interface GroupRepositoryCustom {
List<GroupInfo> findAllByCursor(Long lastId, Category category, int pageSize);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package project.flipnote.group.repository;

import java.util.List;


import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;

import lombok.RequiredArgsConstructor;
import project.flipnote.group.entity.Category;
import project.flipnote.group.entity.QGroup;
import project.flipnote.group.model.GroupInfo;

@RequiredArgsConstructor
public class GroupRepositoryImpl implements GroupRepositoryCustom {

private final JPAQueryFactory queryFactory;

QGroup group = QGroup.group;

@Override
public List<GroupInfo> findAllByCursor(Long lastId, Category category, int pageSize) {
BooleanBuilder where = new BooleanBuilder()
.and(group.deletedAt.isNull());

if (lastId != null) {
where.and(group.id.lt(lastId));
}

if (category != null) {
where.and(group.category.eq(category));
}

return queryFactory.select(Projections.constructor(
GroupInfo.class,
group.id,
group.name,
group.description,
group.category,
group.imageUrl
))
.from(group)
.where(where)
.orderBy(group.id.desc())
.limit(pageSize+1)
.fetch();
}

}
67 changes: 58 additions & 9 deletions src/main/java/project/flipnote/group/service/GroupService.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import project.flipnote.common.exception.BizException;
import project.flipnote.common.model.response.CursorPagingResponse;
import project.flipnote.common.security.dto.AuthPrinciple;
import project.flipnote.group.entity.Category;
import project.flipnote.group.entity.Group;
import project.flipnote.group.entity.GroupMember;
import project.flipnote.group.entity.GroupMemberRole;
Expand All @@ -21,6 +23,8 @@
import project.flipnote.group.model.GroupCreateRequest;
import project.flipnote.group.model.GroupCreateResponse;
import project.flipnote.group.model.GroupDetailResponse;
import project.flipnote.group.model.GroupInfo;
import project.flipnote.group.model.GroupListRequest;
import project.flipnote.group.model.GroupMemberInfo;
import project.flipnote.group.model.GroupPutRequest;
import project.flipnote.group.model.GroupPutResponse;
Expand All @@ -40,6 +44,8 @@
@Transactional(readOnly = true)
public class GroupService {

private static final int SIZE = 10;

private final GroupRepository groupRepository;
private final GroupMemberRepository groupMemberRepository;
private final GroupPermissionRepository groupPermissionRepository;
Expand All @@ -50,12 +56,21 @@ public class GroupService {
/*
유저 정보 조회
*/
public UserProfile validateUser(AuthPrinciple authPrinciple) {
public UserProfile getUser(AuthPrinciple authPrinciple) {
return userProfileRepository.findByIdAndStatus(authPrinciple.userId(), UserStatus.ACTIVE).orElseThrow(
() -> new BizException(UserErrorCode.USER_NOT_FOUND)
);
}

/*
유저 정보 조회
*/
public void validateUser(AuthPrinciple authPrinciple) {
if(!userProfileRepository.existsByIdAndStatus(authPrinciple.userId(), UserStatus.ACTIVE)) {
throw new BizException(UserErrorCode.USER_NOT_FOUND);
}
}

/*
그룹 내 유저 검증
*/
Expand Down Expand Up @@ -99,7 +114,7 @@ public Group getGroup(Long groupId) {
public GroupCreateResponse create(AuthPrinciple authPrinciple, GroupCreateRequest req) {

//1. 유저 조회
UserProfile user = validateUser(authPrinciple);
UserProfile user = getUser(authPrinciple);

//2. 인원수 검증
validateMaxMember(req.maxMember());
Expand Down Expand Up @@ -199,7 +214,7 @@ private void validateUserCount(Group group, int maxMember) {
public GroupPutResponse changeGroup(AuthPrinciple authPrinciple, GroupPutRequest req, Long groupId) {

//1. 유저 조회
UserProfile user = validateUser(authPrinciple);
UserProfile user = getUser(authPrinciple);

//2. 인원수 검증
validateMaxMember(req.maxMember());
Expand All @@ -223,8 +238,8 @@ public GroupPutResponse changeGroup(AuthPrinciple authPrinciple, GroupPutRequest
/*
그룹 내 오너를 제외한 인원이 존재하는 경우 체크
*/
private boolean checkUserNotExistInGroup(UserProfile user, Long groupId) {
long count = groupMemberRepository.countByGroup_idAndUser_idNot(groupId, user.getId());
private boolean checkUserNotExistInGroup(UserProfile user, Group group) {
long count = groupMemberRepository.countByGroup_idAndUser_idNot(group.getId(), user.getId());
if (count > 0) {
return false;
}
Expand All @@ -248,7 +263,7 @@ public GroupDetailResponse findGroupDetail(AuthPrinciple authPrinciple, Long gro
Group group = getGroup(groupId);

//2. 유저 조회
UserProfile user = validateUser(authPrinciple);
UserProfile user = getUser(authPrinciple);

//3. 그룹 내 유저 조회
validateGroupInUser(user, groupId);
Expand All @@ -263,7 +278,7 @@ public void deleteGroup(AuthPrinciple authPrinciple, Long groupId) {
Group group = getGroup(groupId);

//2. 유저 조회
UserProfile user = validateUser(authPrinciple);
UserProfile user = getUser(authPrinciple);

//3. 그룹 내 유저 조회
GroupMember groupMember = getGroupMember(user, groupId);
Expand All @@ -274,10 +289,12 @@ public void deleteGroup(AuthPrinciple authPrinciple, Long groupId) {
}

//5. 오너를 제외한 모든 유저가 없어야 삭제 가능
if (!checkUserNotExistInGroup(user, groupId)) {
if (!checkUserNotExistInGroup(user, group)) {
throw new BizException(GroupErrorCode.OTHER_USER_EXIST_IN_GROUP);
}

groupMemberRepository.delete(groupMember);

groupRepository.delete(group);

}
Expand All @@ -294,7 +311,7 @@ public FindGroupMemberResponse findGroupMembers(AuthPrinciple authPrinciple, Lon
validateGroup(groupId);

//2. 유저 조회
UserProfile user = validateUser(authPrinciple);
UserProfile user = getUser(authPrinciple);

//3. 그룹 내 유저 조회
validateGroupInUser(user, groupId);
Expand All @@ -305,6 +322,38 @@ public FindGroupMemberResponse findGroupMembers(AuthPrinciple authPrinciple, Lon
return FindGroupMemberResponse.from(groupMembers);
}

public CursorPagingResponse<GroupInfo> findGroup(AuthPrinciple authPrinciple, GroupListRequest req) {
//1. 유저 검증
validateUser(authPrinciple);

//2. 카테고리 변환
Category category = convertCategory(req.getCategory());

List<GroupInfo> groups = groupRepository.findAllByCursor(req.getCursorId(), category, req.getSize());

boolean hasNext = groups.size() > req.getSize();

if (hasNext) {
groups = groups.subList(0, req.getSize());
}

Long nextCursor = hasNext ? groups.get(groups.size() - 1).groupId() : null;

return CursorPagingResponse.of(groups, hasNext, nextCursor);
}

private Category convertCategory(String rawCategory) {
Category category = null;
if (rawCategory != null && !rawCategory.isBlank()) {
try {
category = Category.valueOf(rawCategory.trim().toUpperCase());
} catch (IllegalArgumentException e) {
throw new BizException(GroupErrorCode.INVALID_CATEGORY);
}
}
return category;
}

/**
* 해당 회원에 그룹에 존재하는지 확인
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ public interface UserProfileRepository extends JpaRepository<UserProfile, Long>

@Query("SELECT up.nickname FROM UserProfile up WHERE up.id = :userId")
Optional<String> findNicknameById(@Param("userId") Long userId);

boolean existsByIdAndStatus(Long userId, UserStatus userStatus);
}
Loading