Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
17afc57
Feat: 그룹 생성 기능 추가
stoneTiger0912 Jul 6, 2025
652997e
Feat: 그룹 생성 기능 추가
stoneTiger0912 Jul 6, 2025
46a8ad0
Feat: 에러 코드 추가
stoneTiger0912 Jul 6, 2025
c29e3be
Feat: 그룹 가입 신청 추가
stoneTiger0912 Jul 7, 2025
1f7f7d9
Merge: 머지 해결
stoneTiger0912 Jul 17, 2025
2884e2c
Feat: 가입 신청 요청 API 추가
stoneTiger0912 Jul 17, 2025
17ae1b0
Feat: 그룹 조회 에러코드 추가
stoneTiger0912 Jul 17, 2025
85de8e9
Feat: 그룹 가입신청 리스트 조회 API 추가
stoneTiger0912 Jul 17, 2025
03d5f15
Refactor: 그룹 권한 정보 통합
stoneTiger0912 Jul 17, 2025
ecce711
Merge: 파일 충돌 해결을 위한 머지
stoneTiger0912 Jul 21, 2025
bafafbf
Chore: 메서드 명 변경
stoneTiger0912 Jul 21, 2025
b0bd7d6
Feat: 가입 신청 응답 API 추가
stoneTiger0912 Jul 22, 2025
8d0e186
Fix: path 수정
stoneTiger0912 Jul 22, 2025
37cb49d
Chore: group_application 대신 group_join으로 변경
stoneTiger0912 Jul 23, 2025
7bade2e
Feat: 그룹 신청 삭제 API 추가
stoneTiger0912 Jul 28, 2025
70dbe62
Feat: 내가 신청한 그룹 신청리스트 조회
stoneTiger0912 Jul 28, 2025
4aa8b52
Fix: 그룹 요청 반환시 변수 생성안하고 반환
stoneTiger0912 Jul 29, 2025
9970443
Feat: test 코드 작성
stoneTiger0912 Jul 29, 2025
c263636
Fix: jpa 메서드명 수정
stoneTiger0912 Jul 30, 2025
8dd9ce9
Feat: 가입 신청 테스트 추가
stoneTiger0912 Jul 31, 2025
58298e2
Feat: 가입 신청 삭제 테스트 추가
stoneTiger0912 Jul 31, 2025
2061682
Merge: 머치 충돌 해결
stoneTiger0912 Aug 5, 2025
49b9d21
Chore: 테스트 임시 제거
stoneTiger0912 Aug 5, 2025
f05cedc
Merge: 머지 충돌 해결
stoneTiger0912 Aug 5, 2025
b42e7d1
Merge: 머지 충돌 해결
stoneTiger0912 Aug 5, 2025
1889acc
Merge: 머지 충돌 해결
stoneTiger0912 Aug 5, 2025
d741e7b
Merge: 머지 충돌 해결
stoneTiger0912 Aug 5, 2025
23d9a2a
Merge: 머지 충돌 해결
stoneTiger0912 Aug 5, 2025
44f25d9
Merge: 머지 충돌 해결
stoneTiger0912 Aug 5, 2025
cf90896
Fix: 승인 유저가 아닌 실제 유저가 가입되게 수정
stoneTiger0912 Aug 5, 2025
3541583
Fix: 오타 수정
stoneTiger0912 Aug 5, 2025
1f9191f
Feat: 검증 추가
stoneTiger0912 Aug 5, 2025
479ffb1
Feat: 어노테이션 추가
stoneTiger0912 Aug 5, 2025
c191b40
Fix: 에러코드 수정
stoneTiger0912 Aug 5, 2025
6de8c56
Delete: 안쓰는 클래스 삭제
stoneTiger0912 Aug 5, 2025
58cde79
Fix: 메서드 명확하게 수정
stoneTiger0912 Aug 5, 2025
c78033d
Fix: db 락 되게 설정
stoneTiger0912 Aug 5, 2025
167246d
Fix: 변수명 수정
stoneTiger0912 Aug 5, 2025
133ae96
Merge: 변수명 수정
stoneTiger0912 Aug 6, 2025
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
Expand Up @@ -23,9 +23,9 @@ public class GroupController {

@PostMapping("")
public ResponseEntity<GroupCreateResponse> create(
@AuthenticationPrincipal AuthPrinciple userAuth,
@AuthenticationPrincipal AuthPrinciple authPrinciple,
@Valid @RequestBody GroupCreateRequest req) {
GroupCreateResponse res = groupService.create(userAuth, req);
GroupCreateResponse res = groupService.create(authPrinciple, req);
return ResponseEntity.status(HttpStatus.CREATED).body(res);
}
}
12 changes: 4 additions & 8 deletions src/main/java/project/flipnote/group/entity/GroupPermission.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
package project.flipnote.group.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -23,11 +18,12 @@ public class GroupPermission {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Enumerated(EnumType.STRING)
@Column(nullable = false, length = 50, unique = true)
private String name;
private GroupPermissionStatus name;

@Builder
private GroupPermission(String name) {
private GroupPermission(GroupPermissionStatus name) {
this.name = name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package project.flipnote.group.entity;

public enum GroupPermissionStatus {
INVITE, KICK, JOIN_REQUEST_MANAGE
}
5 changes: 0 additions & 5 deletions src/main/java/project/flipnote/group/entity/GroupRole.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ public class GroupRolePermission {

@Enumerated(EnumType.STRING)
@Column(name = "role", nullable = false)
private GroupRole role;
private GroupMemberRole role;

@Builder
private GroupRolePermission(Group group, GroupPermission groupPermission, GroupRole role) {
private GroupRolePermission(Group group, GroupPermission groupPermission, GroupMemberRole role) {
this.group = group;
this.groupPermission = groupPermission;
this.role = role;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
@Getter
@RequiredArgsConstructor
public enum GroupErrorCode implements ErrorCode {
GROUP_NOT_FOUND(HttpStatus.NOT_FOUND, "GROUP_002", "그룹이 존재하지 않습니다."),
INVALID_MAX_MEMBER(HttpStatus.BAD_REQUEST, "GROUP_001", "최대 인원 수는 1 이상 100 이하여야 합니다.");

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

import org.hibernate.validator.constraints.URL;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import project.flipnote.group.entity.Category;

public class GroupCreateDto {
public record Request(
@NotBlank
@Size(max = 50)
String name,

@NotNull
Category category,

@NotBlank
String description,

@NotNull
Boolean applicationRequired,

@NotNull
Boolean publicVisible,

@NotNull
@Min(1)
@Max(100)
Integer maxMember,

@URL
String image
) {
}

public record Response(
Long groupId
){
public static Response from(Long groupId) {
return new Response(groupId);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@

import org.springframework.data.jpa.repository.JpaRepository;

import project.flipnote.group.entity.Group;

import org.springframework.stereotype.Repository;
import project.flipnote.group.entity.GroupMember;
import project.flipnote.user.entity.UserProfile;

import java.util.Optional;

@Repository
public interface GroupMemberRepository extends JpaRepository<GroupMember, Long> {
Optional<GroupMember> findByGroupAndUser(Group group, UserProfile userProfile);

long countByGroup_Id(Long groupId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import org.springframework.stereotype.Repository;

import project.flipnote.group.entity.GroupPermission;
import project.flipnote.group.entity.GroupPermissionStatus;

@Repository
public interface GroupPermissionRepository extends JpaRepository<GroupPermission, Long> {
GroupPermission findByName(GroupPermissionStatus name);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
package project.flipnote.group.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import jakarta.persistence.LockModeType;
import project.flipnote.group.entity.Group;
import project.flipnote.group.entity.GroupMember;

import java.util.List;
import java.util.Optional;

@Repository
public interface GroupRepository extends JpaRepository<Group, Long> {
Optional<Group> findById(Long groupId);

@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select g from Group g where g.id = :id")
Optional<Group> findByIdForUpdate(Long groupId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

import org.springframework.data.jpa.repository.JpaRepository;

import project.flipnote.group.entity.Group;
import project.flipnote.group.entity.GroupMemberRole;
import project.flipnote.group.entity.GroupPermission;
import org.springframework.stereotype.Repository;
import project.flipnote.group.entity.GroupRolePermission;

@Repository
public interface GroupRolePermissionRepository extends JpaRepository<GroupRolePermission, Long> {
boolean existsByGroupAndRoleAndGroupPermission(Group group, GroupMemberRole role, GroupPermission groupPermission);
}
20 changes: 10 additions & 10 deletions src/main/java/project/flipnote/group/service/GroupService.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import project.flipnote.group.entity.GroupMember;
import project.flipnote.group.entity.GroupMemberRole;
import project.flipnote.group.entity.GroupPermission;
import project.flipnote.group.entity.GroupRole;
import project.flipnote.group.entity.GroupRolePermission;
import project.flipnote.group.exception.GroupErrorCode;
import project.flipnote.group.model.GroupCreateRequest;
Expand All @@ -24,6 +23,7 @@
import project.flipnote.group.repository.GroupRepository;
import project.flipnote.group.repository.GroupRolePermissionRepository;
import project.flipnote.user.entity.UserProfile;
import project.flipnote.user.entity.UserStatus;
import project.flipnote.user.exception.UserErrorCode;
import project.flipnote.user.repository.UserProfileRepository;

Expand All @@ -40,18 +40,18 @@ public class GroupService {
private final UserProfileRepository userProfileRepository;

//유저 정보 조회
public UserProfile findUser(AuthPrinciple userAuth) {
return userProfileRepository.findById(userAuth.userId()).orElseThrow(
public UserProfile findUser(AuthPrinciple authPrinciple) {
return userProfileRepository.findByIdAndStatus(authPrinciple.userId(), UserStatus.ACTIVE).orElseThrow(
() -> new BizException(UserErrorCode.USER_NOT_FOUND)
);
}

//그룹 생성
@Transactional
public GroupCreateResponse create(AuthPrinciple userAuth, GroupCreateRequest req) {
public GroupCreateResponse create(AuthPrinciple authPrinciple, GroupCreateRequest req) {

//1. 유저 조회
UserProfile user = findUser(userAuth);
UserProfile userProfile = findUser(authPrinciple);

//2. 인원수 검증
validateMaxMember(req.maxMember());
Expand All @@ -60,21 +60,21 @@ public GroupCreateResponse create(AuthPrinciple userAuth, GroupCreateRequest req
Group group = createGroup(req);

//4. 그룹 회원 정보 생성
saveGroupOwner(group, user);
saveGroupOwner(group, userProfile);

//5. 그룹 내의 모든 권한 조회
initializeGroupPermissions(group);

return GroupCreateResponse.from(group.getId());
}

/*
최초 그룹 권한 설정
*/
private void initializeGroupPermissions(Group group) {
List<GroupPermission> groupPermissions = groupPermissionRepository.findAll();

List<GroupRolePermission> groupRolePermissions = Arrays.stream(GroupRole.values())
List<GroupRolePermission> groupRolePermissions = Arrays.stream(GroupMemberRole.values())
.flatMap(role -> groupPermissions.stream()
.map(permission -> GroupRolePermission.builder()
.group(group)
Expand All @@ -85,7 +85,7 @@ private void initializeGroupPermissions(Group group) {

groupRolePermissionRepository.saveAll(groupRolePermissions);
}

/*
그룹 생성 메서드
*/
Expand All @@ -106,7 +106,7 @@ private Group createGroup(GroupCreateRequest req) {

return saveGroup;
}

/*
그룹 생성시 오너 멤버 추가
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package project.flipnote.groupjoin.controller;

import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import lombok.RequiredArgsConstructor;
import project.flipnote.common.security.dto.AuthPrinciple;
import project.flipnote.groupjoin.model.*;
import project.flipnote.groupjoin.service.GroupJoinService;

@RestController
@RequestMapping("/v1")
@RequiredArgsConstructor
public class GroupJoinController {

private final GroupJoinService groupJoinService;

//가입 신청 요청
@PostMapping("/groups/{groupId}/joins")
public ResponseEntity<GroupJoinResponse> joinRequest(
@AuthenticationPrincipal AuthPrinciple authPrinciple,
@PathVariable("groupId") Long groupId,
@Valid @RequestBody GroupJoinRequest req) {
GroupJoinResponse res = groupJoinService.joinRequest(authPrinciple, groupId, req);

return ResponseEntity.status(HttpStatus.CREATED).body(res);
}

//그룹 내 가입 신청한 리스트 조회
@GetMapping("/groups/{groupId}/joins")
public ResponseEntity<GroupJoinListResponse> findGroupJoinList(
@AuthenticationPrincipal AuthPrinciple authPrinciple,
@PathVariable("groupId") Long groupId) {
GroupJoinListResponse res = groupJoinService.findGroupJoinList(authPrinciple, groupId);

return ResponseEntity.ok(res);
}

//가입 신청 응답
@PatchMapping("/groups/{groupId}/joins/{joinId}")
public ResponseEntity<GroupJoinRespondResponse> respondToJoinRequest(
@AuthenticationPrincipal AuthPrinciple authPrinciple,
@PathVariable("groupId") Long groupId,
@PathVariable("joinId") Long joinId,
@Valid @RequestBody GroupJoinRespondRequest req) {

GroupJoinRespondResponse res = groupJoinService.respondToJoinRequest(authPrinciple, groupId, joinId, req);

return ResponseEntity.ok(res);
}

//가입 신청 삭제
@DeleteMapping("/groups/{groupId}/joins/{joinId}")
public ResponseEntity<Void> groupJoinDelete(
@AuthenticationPrincipal AuthPrinciple authPrinciple,
@PathVariable("groupId") Long groupId,
@PathVariable("joinId") Long joinId
) {
groupJoinService.groupJoinDelete(authPrinciple, groupId, joinId);

return ResponseEntity.noContent().build();
}

//내가 신청한 가입신청 리스트 조회
@GetMapping("/groups/joins/me")
public ResponseEntity<FindGroupJoinListMeResponse> findGroupJoinMe(
@AuthenticationPrincipal AuthPrinciple authPrinciple
) {
FindGroupJoinListMeResponse res = groupJoinService.findGroupJoinListMe(authPrinciple);

return ResponseEntity.ok(res);
}
}
Loading
Loading