diff --git a/backend/src/main/java/com/project/capstone/auth/domain/PrincipalDetails.java b/backend/src/main/java/com/project/capstone/auth/domain/PrincipalDetails.java index 9c03357b1d..6e9f9292b7 100644 --- a/backend/src/main/java/com/project/capstone/auth/domain/PrincipalDetails.java +++ b/backend/src/main/java/com/project/capstone/auth/domain/PrincipalDetails.java @@ -6,6 +6,7 @@ import org.springframework.security.core.userdetails.UserDetails; import java.util.Collection; +import java.util.UUID; @AllArgsConstructor public class PrincipalDetails implements UserDetails { @@ -27,6 +28,8 @@ public String getUsername() { return member.getEmail(); } + public String getUserId() {return member.getId().toString(); } + @Override public boolean isAccountNonExpired() { return true; diff --git a/backend/src/main/java/com/project/capstone/auth/jwt/JwtAuthenticationFilter.java b/backend/src/main/java/com/project/capstone/auth/jwt/JwtAuthenticationFilter.java index fde6025684..99e9e0c140 100644 --- a/backend/src/main/java/com/project/capstone/auth/jwt/JwtAuthenticationFilter.java +++ b/backend/src/main/java/com/project/capstone/auth/jwt/JwtAuthenticationFilter.java @@ -25,8 +25,9 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = jwtProvider.resolveToken(request); try { - String email = jwtProvider.validateTokenAndGetEmail(token); - Authentication authentication = jwtProvider.createAuthentication(email); + String id = jwtProvider.validateTokenAndGetId(token); + Authentication authentication = jwtProvider.createAuthentication(id); + log.info(authentication.getName()); SecurityContextHolder.getContext().setAuthentication(authentication); } catch (Exception e) { log.warn(e.getMessage()); diff --git a/backend/src/main/java/com/project/capstone/auth/jwt/JwtProvider.java b/backend/src/main/java/com/project/capstone/auth/jwt/JwtProvider.java index 69e8c321ab..f04072efb1 100644 --- a/backend/src/main/java/com/project/capstone/auth/jwt/JwtProvider.java +++ b/backend/src/main/java/com/project/capstone/auth/jwt/JwtProvider.java @@ -20,6 +20,7 @@ import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; +import java.util.UUID; @Slf4j @Component @@ -39,9 +40,9 @@ private void init() { key = Keys.hmacShaKeyFor(secret.getBytes()); } - public String generate(String email) { + public String generate(String id) { Claims claims = Jwts.claims(); - claims.put("email", email); + claims.put("id", id); return generateToken(claims); } @@ -74,17 +75,17 @@ public String resolveToken(HttpServletRequest request) { return null; } - public String validateTokenAndGetEmail(String token) { + public String validateTokenAndGetId(String token) { return Jwts.parserBuilder() .setSigningKey(key) .build() .parseClaimsJws(token) .getBody() - .get("email", String.class); + .get("id", String.class); } - public Authentication createAuthentication(String email) { - UserDetails userDetails = principalDetailService.loadUserByUsername(email); + public Authentication createAuthentication(String id) { + UserDetails userDetails = principalDetailService.loadUserByUsername(id); return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); } } diff --git a/backend/src/main/java/com/project/capstone/auth/service/AuthService.java b/backend/src/main/java/com/project/capstone/auth/service/AuthService.java index 621dc977a2..cd48022f04 100644 --- a/backend/src/main/java/com/project/capstone/auth/service/AuthService.java +++ b/backend/src/main/java/com/project/capstone/auth/service/AuthService.java @@ -29,6 +29,6 @@ public TokenResponse login(String email) { } private String generateToken(Member member) { - return jwtProvider.generate(member.getEmail()); + return jwtProvider.generate(member.getId().toString()); } } diff --git a/backend/src/main/java/com/project/capstone/auth/service/PrincipalDetailService.java b/backend/src/main/java/com/project/capstone/auth/service/PrincipalDetailService.java index 3ea1d0cc44..ef31fbb814 100644 --- a/backend/src/main/java/com/project/capstone/auth/service/PrincipalDetailService.java +++ b/backend/src/main/java/com/project/capstone/auth/service/PrincipalDetailService.java @@ -9,14 +9,16 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; +import java.util.UUID; + @Service @RequiredArgsConstructor public class PrincipalDetailService implements UserDetailsService { private final MemberRepository memberRepository; @Override - public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { - Member member = memberRepository.findMemberByEmail(email) - .orElseThrow(() -> new UsernameNotFoundException("이메일이 존재하지 않습니다.")); + public UserDetails loadUserByUsername(String id) throws UsernameNotFoundException { + Member member = memberRepository.findMemberById(UUID.fromString(id)) + .orElseThrow(() -> new UsernameNotFoundException("해당 멤버가 존재하지 않습니다.")); return new PrincipalDetails(member); } } diff --git a/backend/src/main/java/com/project/capstone/club/controller/ClubController.java b/backend/src/main/java/com/project/capstone/club/controller/ClubController.java new file mode 100644 index 0000000000..508063a297 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/club/controller/ClubController.java @@ -0,0 +1,73 @@ +package com.project.capstone.club.controller; + +import com.project.capstone.auth.domain.PrincipalDetails; +import com.project.capstone.club.controller.dto.ClubCreateRequest; +import com.project.capstone.club.controller.dto.ClubResponse; +import com.project.capstone.club.service.ClubService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/club") +@Slf4j +public class ClubController { + private final ClubService clubService; + // 모임 불러오기 + @GetMapping("/search/{id}") + public ResponseEntity getClub(@PathVariable Long id) { + ClubResponse clubResponse = clubService.getClub(id); + return ResponseEntity.ok().body(clubResponse); + } + + // 모임 주제별 검색 + @GetMapping("/search/topic") + public ResponseEntity> searchByTopic(@RequestParam String topic) { + List clubResponseList = clubService.searchByTopic(topic); + return ResponseEntity.ok().body(clubResponseList); + } + // 모임 이름으로 검색 + @GetMapping("/search/name") + public ResponseEntity searchByName(@RequestParam String name) { + List clubResponseList = clubService.searchByName(name); + return ResponseEntity.ok().body(clubResponseList); + } + // 모임 생성하기 + @PostMapping("/create") + public ResponseEntity createClub(@RequestBody ClubCreateRequest request, @AuthenticationPrincipal PrincipalDetails details) { + clubService.createClub(request, details.getUserId()); + return ResponseEntity.ok().body("모임 생성 완료"); + } + // 모임 가입하기 + @GetMapping("/join") + public ResponseEntity join(@AuthenticationPrincipal PrincipalDetails details, @RequestParam Long clubId) { + clubService.join(details.getUserId(), clubId); + return ResponseEntity.ok().body("모임 가입 완료"); + } + // 모임 탈퇴하기 + @GetMapping("/out") + public ResponseEntity out(@AuthenticationPrincipal PrincipalDetails details, @RequestParam Long clubId) { + clubService.out(details.getUserId(), clubId); + return ResponseEntity.ok().body("모임 탈퇴 완료"); + } + // 모임장 위임하기 + @PutMapping("/delegate") + public ResponseEntity delegateManager(@AuthenticationPrincipal PrincipalDetails details, + @RequestParam UUID memberId, @RequestParam Long clubId) { + clubService.delegateManager(details, memberId, clubId); + return ResponseEntity.ok().body("위임 완료"); + } + // 멤버 추방하기 + @GetMapping("/expel") + public ResponseEntity expelMember(@AuthenticationPrincipal PrincipalDetails details, + @RequestParam UUID memberId, @RequestParam Long clubId) { + clubService.expelMember(details, memberId, clubId); + return ResponseEntity.ok().body("추방 완료"); + } +} diff --git a/backend/src/main/java/com/project/capstone/club/controller/dto/ClubCreateRequest.java b/backend/src/main/java/com/project/capstone/club/controller/dto/ClubCreateRequest.java new file mode 100644 index 0000000000..0f556be5ed --- /dev/null +++ b/backend/src/main/java/com/project/capstone/club/controller/dto/ClubCreateRequest.java @@ -0,0 +1,12 @@ +package com.project.capstone.club.controller.dto; + +import com.project.capstone.club.domain.PublicStatus; + +public record ClubCreateRequest( + String topic, + String name, + int maximum, + PublicStatus publicStatus, + Integer password +) { +} diff --git a/backend/src/main/java/com/project/capstone/club/controller/dto/ClubResponse.java b/backend/src/main/java/com/project/capstone/club/controller/dto/ClubResponse.java new file mode 100644 index 0000000000..c47b916330 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/club/controller/dto/ClubResponse.java @@ -0,0 +1,20 @@ +package com.project.capstone.club.controller.dto; + +import com.project.capstone.club.domain.Club; +import com.project.capstone.club.domain.PublicStatus; + +import java.time.LocalDateTime; + +public record ClubResponse ( + Long id, + Long bookId, + String topic, + String name, + LocalDateTime createdAt, + int maximum, + PublicStatus publicstatus +) { + public ClubResponse(Club club) { + this(club.getId(), club.getBook() == null ? null : club.getBook().getId(), club.getTopic(), club.getName(), club.getCreatedAt(), club.getMaximum(), club.getPublicStatus()); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/project/capstone/club/domain/Club.java b/backend/src/main/java/com/project/capstone/club/domain/Club.java index c1b31f1799..000cb159ed 100644 --- a/backend/src/main/java/com/project/capstone/club/domain/Club.java +++ b/backend/src/main/java/com/project/capstone/club/domain/Club.java @@ -1,9 +1,8 @@ package com.project.capstone.club.domain; import com.project.capstone.book.domain.Book; -import com.project.capstone.common.domain.MemberClub; +import com.project.capstone.memberclub.domain.MemberClub; import com.project.capstone.content.domain.Content; -import com.project.capstone.member.domain.Member; import com.project.capstone.post.domain.Post; import jakarta.persistence.*; import lombok.AllArgsConstructor; @@ -16,6 +15,7 @@ import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import java.util.UUID; @Entity @EntityListeners(AuditingEntityListener.class) @@ -27,14 +27,17 @@ public class Club { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column(name = "manager_id", columnDefinition = "BINARY(16)") + private UUID managerId; private String topic; private String name; @Column(name = "created_at") @CreatedDate private LocalDateTime createdAt; private int maximum; - @Column(name = "is_public") - private boolean isPublic; + @Enumerated(EnumType.STRING) + @Column(name = "public_status") + private PublicStatus publicStatus; private Integer password; @OneToMany(mappedBy = "club") @@ -48,4 +51,5 @@ public class Club { @ManyToOne private Book book; + } diff --git a/backend/src/main/java/com/project/capstone/club/domain/ClubRepository.java b/backend/src/main/java/com/project/capstone/club/domain/ClubRepository.java new file mode 100644 index 0000000000..56c1815329 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/club/domain/ClubRepository.java @@ -0,0 +1,18 @@ +package com.project.capstone.club.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public interface ClubRepository extends JpaRepository { + List findClubsByTopic(String topic); + List findClubsByNameContaining(String name); + Optional findClubById(Long id); + @Modifying(clearAutomatically = true) + @Query("update Club c set c.managerId = :id") + void updateManager(UUID id); +} diff --git a/backend/src/main/java/com/project/capstone/club/domain/PublicStatus.java b/backend/src/main/java/com/project/capstone/club/domain/PublicStatus.java new file mode 100644 index 0000000000..4e47ba4bf5 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/club/domain/PublicStatus.java @@ -0,0 +1,25 @@ +package com.project.capstone.club.domain; + +import com.fasterxml.jackson.annotation.JsonCreator; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum PublicStatus { + PUBLIC("공개"), + PRIVATE("비공개"); + + private final String description; + + + @JsonCreator + public static PublicStatus from(String status) { + for (PublicStatus publicStatus : PublicStatus.values()) { + if (publicStatus.getDescription().equals(status)) { + return publicStatus; + } + } + throw new RuntimeException("잘못된 공개 여부입니다."); + } +} diff --git a/backend/src/main/java/com/project/capstone/club/exception/ClubException.java b/backend/src/main/java/com/project/capstone/club/exception/ClubException.java new file mode 100644 index 0000000000..5c5d579d6e --- /dev/null +++ b/backend/src/main/java/com/project/capstone/club/exception/ClubException.java @@ -0,0 +1,10 @@ +package com.project.capstone.club.exception; + +import com.project.capstone.common.exception.BaseException; +import com.project.capstone.common.exception.ExceptionType; + +public class ClubException extends BaseException { + public ClubException(ExceptionType exceptionType) { + super(exceptionType); + } +} diff --git a/backend/src/main/java/com/project/capstone/club/exception/ClubExceptionType.java b/backend/src/main/java/com/project/capstone/club/exception/ClubExceptionType.java new file mode 100644 index 0000000000..75fbf8de72 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/club/exception/ClubExceptionType.java @@ -0,0 +1,36 @@ +package com.project.capstone.club.exception; + +import com.project.capstone.common.exception.ExceptionType; + +import lombok.AllArgsConstructor; +import org.springframework.http.HttpStatus; + + +import static org.springframework.http.HttpStatus.*; + +@AllArgsConstructor +public enum ClubExceptionType implements ExceptionType { + + CLUB_NOT_FOUND(NOT_FOUND, 101, "해당 모임을 찾을 수 없습니다."), + EXIT_WITHOUT_DELEGATION(BAD_REQUEST, 102, "모임장은 위임 후 모임을 나갈 수 있습니다."), + UNAUTHORIZED_ACTION(UNAUTHORIZED, 103, "모임장만 할 수 있는 기능입니다.") + ; + + private final HttpStatus status; + private final int exceptionCode; + private final String message; + @Override + public HttpStatus httpStatus() { + return status; + } + + @Override + public int exceptionCode() { + return exceptionCode; + } + + @Override + public String message() { + return message; + } +} diff --git a/backend/src/main/java/com/project/capstone/club/service/ClubService.java b/backend/src/main/java/com/project/capstone/club/service/ClubService.java new file mode 100644 index 0000000000..23b82d3b96 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/club/service/ClubService.java @@ -0,0 +1,124 @@ +package com.project.capstone.club.service; + +import com.project.capstone.auth.domain.PrincipalDetails; +import com.project.capstone.club.controller.dto.ClubCreateRequest; +import com.project.capstone.club.controller.dto.ClubResponse; +import com.project.capstone.club.domain.Club; +import com.project.capstone.club.domain.ClubRepository; +import com.project.capstone.club.exception.ClubException; +import com.project.capstone.memberclub.domain.MemberClub; +import com.project.capstone.memberclub.domain.MemberClubRepository; +import com.project.capstone.member.domain.Member; +import com.project.capstone.member.domain.MemberRepository; +import com.project.capstone.member.exception.MemberException; +import com.project.capstone.memberclub.exception.MemberClubException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static com.project.capstone.club.exception.ClubExceptionType.*; +import static com.project.capstone.member.exception.MemberExceptionType.*; +import static com.project.capstone.memberclub.exception.MemberClubExceptionType.*; + +@Service +@Slf4j +@RequiredArgsConstructor +public class ClubService { + private final ClubRepository clubRepository; + private final MemberClubRepository memberClubRepository; + private final MemberRepository memberRepository; + + public List searchByTopic(String topic) { + List clubResponseList = new ArrayList<>(); + log.info(topic); + List clubList = clubRepository.findClubsByTopic(topic); + for (Club club : clubList) { + clubResponseList.add(new ClubResponse(club)); + } + return clubResponseList; + } + public List searchByName(String name) { + List clubResponseList = new ArrayList<>(); + List clubList = clubRepository.findClubsByNameContaining(name); + for (Club club : clubList) { + clubResponseList.add(new ClubResponse(club)); + } + return clubResponseList; + } + + @Transactional + public void createClub(ClubCreateRequest request, String memberId) { + Club savedClub = clubRepository.save(Club.builder() + .managerId(UUID.fromString(memberId)) + .topic(request.topic()) + .name(request.name()) + .maximum(request.maximum()) + .publicStatus(request.publicStatus()) + .password(request.password()) + .build()); + + join(memberId, savedClub.getId()); + } + + public void join(String memberId, Long clubId) { + Member member = memberRepository.findMemberById(UUID.fromString(memberId)).orElseThrow( + () -> new MemberException(MEMBER_NOT_FOUND) + ); + Club club = clubRepository.findClubById(clubId).orElseThrow( + () -> new ClubException(CLUB_NOT_FOUND) + ); + if (memberClubRepository.findMemberClubByMember_IdAndClub_Id(UUID.fromString(memberId), clubId).isPresent()) { + throw new MemberClubException(ALREADY_JOIN); + } + memberClubRepository.save(new MemberClub(null, member, club)); + } + + @Transactional + public void out(String userId, Long clubId) { + Club club = clubRepository.findClubById(clubId).orElseThrow( + () -> new ClubException(CLUB_NOT_FOUND) + ); + if (club.getManagerId().toString().equals(userId)) { + throw new ClubException(EXIT_WITHOUT_DELEGATION); + } + memberClubRepository.deleteMemberClubByClub_IdAndMember_Id(clubId, UUID.fromString(userId)); + } + + @Transactional + public void delegateManager(PrincipalDetails details, UUID memberId, Long clubId) { + checkIsManagerAndTargetIsClubMember(details, memberId, clubId); + clubRepository.updateManager(memberId); + } + + @Transactional + public void expelMember(PrincipalDetails details, UUID memberId, Long clubId) { + checkIsManagerAndTargetIsClubMember(details, memberId, clubId); + memberClubRepository.deleteMemberClubByClub_IdAndMember_Id(clubId, memberId); + } + + private void checkIsManagerAndTargetIsClubMember(PrincipalDetails details, UUID memberId, Long clubId) { + Club club = findClubById(clubId); + if (!club.getManagerId().toString().equals(details.getUserId())) { + throw new ClubException(UNAUTHORIZED_ACTION); + } + if (memberClubRepository.findMemberClubByMember_IdAndClub_Id(memberId, clubId).isEmpty()) { + throw new MemberClubException(MEMBERCLUB_NOT_FOUND); + } + } + + private Club findClubById(Long clubId) { + return clubRepository.findClubById(clubId).orElseThrow( + () -> new ClubException(CLUB_NOT_FOUND) + ); + } + + public ClubResponse getClub(Long clubId) { + Club club = findClubById(clubId); + return new ClubResponse(club); + } +} diff --git a/backend/src/main/java/com/project/capstone/common/exception/BaseException.java b/backend/src/main/java/com/project/capstone/common/exception/BaseException.java new file mode 100644 index 0000000000..9c016df8ff --- /dev/null +++ b/backend/src/main/java/com/project/capstone/common/exception/BaseException.java @@ -0,0 +1,13 @@ +package com.project.capstone.common.exception; + +import lombok.Getter; + +@Getter +public class BaseException extends RuntimeException { + private final ExceptionType exceptionType; + + public BaseException(ExceptionType exceptionType) { + super(exceptionType.message()); + this.exceptionType = exceptionType; + } +} diff --git a/backend/src/main/java/com/project/capstone/common/exception/ExceptionResponse.java b/backend/src/main/java/com/project/capstone/common/exception/ExceptionResponse.java new file mode 100644 index 0000000000..75a1ac1c07 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/common/exception/ExceptionResponse.java @@ -0,0 +1,9 @@ +package com.project.capstone.common.exception; + +public record ExceptionResponse ( + int exceptionCode, + String message +) { + +} + diff --git a/backend/src/main/java/com/project/capstone/common/exception/ExceptionType.java b/backend/src/main/java/com/project/capstone/common/exception/ExceptionType.java new file mode 100644 index 0000000000..3054fd9295 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/common/exception/ExceptionType.java @@ -0,0 +1,9 @@ +package com.project.capstone.common.exception; + +import org.springframework.http.HttpStatus; + +public interface ExceptionType { + HttpStatus httpStatus(); + int exceptionCode(); + String message(); +} diff --git a/backend/src/main/java/com/project/capstone/config/SecurityConfig.java b/backend/src/main/java/com/project/capstone/config/SecurityConfig.java index dd4baed188..68bbec8aa1 100644 --- a/backend/src/main/java/com/project/capstone/config/SecurityConfig.java +++ b/backend/src/main/java/com/project/capstone/config/SecurityConfig.java @@ -22,7 +22,7 @@ public class SecurityConfig { @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(authorizeRequest -> - authorizeRequest.requestMatchers("/auth/**").permitAll() + authorizeRequest.requestMatchers("/auth/**", "/club/search/**").permitAll() .anyRequest().authenticated()) .csrf(AbstractHttpConfigurer::disable) .cors(AbstractHttpConfigurer::disable) diff --git a/backend/src/main/java/com/project/capstone/exception/GlobalExceptionHandler.java b/backend/src/main/java/com/project/capstone/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000000..c698c307ff --- /dev/null +++ b/backend/src/main/java/com/project/capstone/exception/GlobalExceptionHandler.java @@ -0,0 +1,20 @@ +package com.project.capstone.exception; + +import com.project.capstone.common.exception.BaseException; +import com.project.capstone.common.exception.ExceptionResponse; +import com.project.capstone.common.exception.ExceptionType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +@RestControllerAdvice +public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { + + @ExceptionHandler + public ResponseEntity handleBaseException(BaseException e) { + ExceptionType type = e.getExceptionType(); + return ResponseEntity.status(type.httpStatus()).body(new ExceptionResponse(type.exceptionCode(), type.message())); + } + +} diff --git a/backend/src/main/java/com/project/capstone/member/domain/Member.java b/backend/src/main/java/com/project/capstone/member/domain/Member.java index e42c9a1f3b..30e8b0e554 100644 --- a/backend/src/main/java/com/project/capstone/member/domain/Member.java +++ b/backend/src/main/java/com/project/capstone/member/domain/Member.java @@ -2,7 +2,7 @@ import com.project.capstone.auth.controller.dto.SignupRequest; import com.project.capstone.comment.domain.Comment; -import com.project.capstone.common.domain.MemberClub; +import com.project.capstone.memberclub.domain.MemberClub; import com.project.capstone.content.domain.Content; import com.project.capstone.post.domain.Post; import jakarta.persistence.*; @@ -34,7 +34,6 @@ public class Member { private String name; private int age; private String gender; - private String role; @CreatedDate @Column(name = "created_at") private LocalDateTime createdAt; @@ -52,7 +51,7 @@ public class Member { private List contents = new ArrayList<>(); public Member(SignupRequest request) { - this(null, request.email(), request.name(), request.age(), request.gender(), "ROLE_USER", null, + this(null, request.email(), request.name(), request.age(), request.gender(), null, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); } } diff --git a/backend/src/main/java/com/project/capstone/member/domain/MemberRepository.java b/backend/src/main/java/com/project/capstone/member/domain/MemberRepository.java index 8351513308..0d6e816388 100644 --- a/backend/src/main/java/com/project/capstone/member/domain/MemberRepository.java +++ b/backend/src/main/java/com/project/capstone/member/domain/MemberRepository.java @@ -11,4 +11,5 @@ public interface MemberRepository extends JpaRepository { Member save(Member member); Optional findMemberByEmail(String email); + Optional findMemberById(UUID id); } diff --git a/backend/src/main/java/com/project/capstone/member/exception/MemberException.java b/backend/src/main/java/com/project/capstone/member/exception/MemberException.java new file mode 100644 index 0000000000..5a81dd33c1 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/member/exception/MemberException.java @@ -0,0 +1,10 @@ +package com.project.capstone.member.exception; + +import com.project.capstone.common.exception.BaseException; +import com.project.capstone.common.exception.ExceptionType; + +public class MemberException extends BaseException { + public MemberException(ExceptionType exceptionType) { + super(exceptionType); + } +} diff --git a/backend/src/main/java/com/project/capstone/member/exception/MemberExceptionType.java b/backend/src/main/java/com/project/capstone/member/exception/MemberExceptionType.java new file mode 100644 index 0000000000..e5f7847053 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/member/exception/MemberExceptionType.java @@ -0,0 +1,33 @@ +package com.project.capstone.member.exception; + +import com.project.capstone.common.exception.ExceptionType; +import lombok.AllArgsConstructor; +import org.springframework.http.HttpStatus; + +import static org.springframework.http.HttpStatus.*; + + +@AllArgsConstructor +public enum MemberExceptionType implements ExceptionType { + MEMBER_NOT_FOUND(NOT_FOUND, 201, "해당 멤버를 찾을 수 없습니다.") + ; + + private final HttpStatus status; + private final int exceptionCode; + private final String message; + + @Override + public HttpStatus httpStatus() { + return status; + } + + @Override + public int exceptionCode() { + return exceptionCode; + } + + @Override + public String message() { + return message; + } +} diff --git a/backend/src/main/java/com/project/capstone/common/domain/MemberClub.java b/backend/src/main/java/com/project/capstone/memberclub/domain/MemberClub.java similarity index 59% rename from backend/src/main/java/com/project/capstone/common/domain/MemberClub.java rename to backend/src/main/java/com/project/capstone/memberclub/domain/MemberClub.java index b1e7a8035c..9d2dd93f28 100644 --- a/backend/src/main/java/com/project/capstone/common/domain/MemberClub.java +++ b/backend/src/main/java/com/project/capstone/memberclub/domain/MemberClub.java @@ -1,10 +1,14 @@ -package com.project.capstone.common.domain; +package com.project.capstone.memberclub.domain; import com.project.capstone.club.domain.Club; import com.project.capstone.member.domain.Member; import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; @Entity +@AllArgsConstructor +@NoArgsConstructor public class MemberClub { @Id @@ -12,8 +16,11 @@ public class MemberClub { private Long id; @ManyToOne + @JoinColumn(name = "member_id") private Member member; @ManyToOne + @JoinColumn(name = "club_id") private Club club; + } diff --git a/backend/src/main/java/com/project/capstone/memberclub/domain/MemberClubRepository.java b/backend/src/main/java/com/project/capstone/memberclub/domain/MemberClubRepository.java new file mode 100644 index 0000000000..29e670e79b --- /dev/null +++ b/backend/src/main/java/com/project/capstone/memberclub/domain/MemberClubRepository.java @@ -0,0 +1,12 @@ +package com.project.capstone.memberclub.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; +import java.util.UUID; + + +public interface MemberClubRepository extends JpaRepository { + void deleteMemberClubByClub_IdAndMember_Id(Long clubId, UUID memberId); + Optional findMemberClubByMember_IdAndClub_Id(UUID memberId, Long clubId); +} diff --git a/backend/src/main/java/com/project/capstone/memberclub/exception/MemberClubException.java b/backend/src/main/java/com/project/capstone/memberclub/exception/MemberClubException.java new file mode 100644 index 0000000000..1cb43ed957 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/memberclub/exception/MemberClubException.java @@ -0,0 +1,10 @@ +package com.project.capstone.memberclub.exception; + +import com.project.capstone.common.exception.BaseException; +import com.project.capstone.common.exception.ExceptionType; + +public class MemberClubException extends BaseException { + public MemberClubException(ExceptionType exceptionType) { + super(exceptionType); + } +} diff --git a/backend/src/main/java/com/project/capstone/memberclub/exception/MemberClubExceptionType.java b/backend/src/main/java/com/project/capstone/memberclub/exception/MemberClubExceptionType.java new file mode 100644 index 0000000000..147aa022ce --- /dev/null +++ b/backend/src/main/java/com/project/capstone/memberclub/exception/MemberClubExceptionType.java @@ -0,0 +1,34 @@ +package com.project.capstone.memberclub.exception; + +import com.project.capstone.common.exception.ExceptionType; +import lombok.AllArgsConstructor; +import org.springframework.http.HttpStatus; + +import static org.springframework.http.HttpStatus.*; + + +@AllArgsConstructor +public enum MemberClubExceptionType implements ExceptionType { + ALREADY_JOIN(BAD_REQUEST, 301, "이미 가입한 모임입니다."), + MEMBERCLUB_NOT_FOUND(NOT_FOUND, 302, "위임 또는 추방하려는 멤버가 모임 구성원이 아닙니다."); + ; + + private final HttpStatus status; + private final int exceptionCode; + private final String message; + + @Override + public HttpStatus httpStatus() { + return status; + } + + @Override + public int exceptionCode() { + return exceptionCode; + } + + @Override + public String message() { + return message; + } +} diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 27d0c13119..96d105d2a2 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -8,6 +8,11 @@ spring: jpa: hibernate: ddl-auto: create + defer-datasource-initialization: true + + sql: + init: + mode: always jwt: secret: gDpXHGuTSnwn6IkHoQE0TyrHT4qGDsbAm6L21qSbzUe8s/Nvo2JsiJyawX8fvUD6 Nh4CdIeQxAqnAzysgk+nUw== \ No newline at end of file diff --git a/backend/src/main/resources/data.sql b/backend/src/main/resources/data.sql new file mode 100644 index 0000000000..cd94ec6aaf --- /dev/null +++ b/backend/src/main/resources/data.sql @@ -0,0 +1,43 @@ +insert into member (id, email, name, age, gender, created_at) values +(UNHEX(REPLACE("3f06af63-a93c-11e4-9797-00505690773f", "-","")), 'example1@gmail.com', '홍길동1', 17, '남자', '2023-05-16 15:48:57.450179'); +insert into member (id, email, name, age, gender, created_at) values +(UNHEX(REPLACE("8fbcec61-e527-15ee-bd3d-0242ac120002", "-","")), 'example2@gmail.com', '홍길동2', 17, '남자', '2023-05-26 15:48:57.450179'); +insert into member (id, email, name, age, gender, created_at) values +(UNHEX(REPLACE("8fbcec62-e527-14ee-bd3d-0242ac120002", "-","")), 'example3@gmail.com', '홍길동3', 17, '남자', '2023-05-26 15:48:57.450179'); +insert into member (id, email, name, age, gender, created_at) values +(UNHEX(REPLACE("8fbcec63-e527-10ee-bd3d-0242ac120002", "-","")), 'example4@gmail.com', '홍길동4', 17, '남자', '2023-05-26 15:48:57.450179'); +insert into member (id, email, name, age, gender, created_at) values +(UNHEX(REPLACE("8fbcec64-e527-11ee-bd3d-0242ac120002", "-","")), 'example5@gmail.com', '홍길동5', 17, '남자', '2023-05-26 15:48:57.450179'); +insert into member (id, email, name, age, gender, created_at) values +(UNHEX(REPLACE("8fbcec65-e527-12ee-bd3d-0242ac120002", "-","")), 'example6@gmail.com', '홍길동6', 17, '남자', '2023-05-26 15:48:57.450179'); + +insert into book (id, title, category_1d, category_2d, category_3d, author, publisher, publish_date) values +(1, '제목1', '카테고리1', '카테고리2', '카테고리3', '저자1', '출판사1', '2022-04-10'); +insert into book (id, title, category_1d, category_2d, category_3d, author, publisher, publish_date) values +(2, '제목2', '카테고리1', '카테고리2', '카테고리3', '저자2', '출판사2', '2022-04-10'); +insert into book (id, title, category_1d, category_2d, category_3d, author, publisher, publish_date) values +(3, '제목3', '카테고리1', '카테고리2', '카테고리3', '저자3', '출판사3', '2022-04-10'); +insert into book (id, title, category_1d, category_2d, category_3d, author, publisher, publish_date) values +(4, '제목4', '카테고리1', '카테고리2', '카테고리3', '저자4', '출판사4', '2022-04-10'); +insert into book (id, title, category_1d, category_2d, category_3d, author, publisher, publish_date) values +(5, '제목5', '카테고리1', '카테고리2', '카테고리3', '저자5', '출판사5', '2022-04-10'); + + +insert into club (id, manager_id, topic, name, created_at, maximum, public_status, password, book_id) values +(1, UNHEX(REPLACE("3f06af63-a93c-11e4-9797-00505690773f", "-","")), '역사', '길동1의 모임', '2023-05-26 15:48:57.450179', 10, 'PUBLIC', null, 1); +insert into club (id, manager_id, topic, name, created_at, maximum, public_status, password, book_id) values +(2, UNHEX(REPLACE("8fbcec61-e527-15ee-bd3d-0242ac120002", "-","")), '경제', '길동2의 모임', '2023-05-26 15:48:57.450179', 10, 'PUBLIC', null, null); +insert into club (id, manager_id, topic, name, created_at, maximum, public_status, password, book_id) values +(3, UNHEX(REPLACE("8fbcec62-e527-14ee-bd3d-0242ac120002", "-","")), '종교', '길동3의 모임', '2023-05-26 15:48:57.450179', 10, 'PUBLIC', null, 2); +insert into club (id, manager_id, topic, name, created_at, maximum, public_status, password, book_id) values +(4, UNHEX(REPLACE("8fbcec63-e527-10ee-bd3d-0242ac120002", "-","")), '사회', '길동4의 모임', '2023-05-26 15:48:57.450179', 10, 'PUBLIC', null, 3); + +insert into club (id, manager_id, topic, name, created_at, maximum, public_status, password, book_id) values +(5, UNHEX(REPLACE("3f06af63-a93c-11e4-9797-00505690773f", "-","")), '역사', '길동1의 모임', '2023-05-26 15:48:57.450179', 10, 'PUBLIC', null, 1); +insert into club (id, manager_id, topic, name, created_at, maximum, public_status, password, book_id) values +(6, UNHEX(REPLACE("8fbcec61-e527-15ee-bd3d-0242ac120002", "-","")), '경제', '길동2의 모임', '2023-05-26 15:48:57.450179', 10, 'PUBLIC', null, null); +insert into club (id, manager_id, topic, name, created_at, maximum, public_status, password, book_id) values +(7, UNHEX(REPLACE("8fbcec62-e527-14ee-bd3d-0242ac120002", "-","")), '종교', '길동3의 모임', '2023-05-26 15:48:57.450179', 10, 'PUBLIC', null, 2); +insert into club (id, manager_id, topic, name, created_at, maximum, public_status, password, book_id) values +(8, UNHEX(REPLACE("8fbcec63-e527-10ee-bd3d-0242ac120002", "-","")), '사회', '길동4의 모임', '2023-05-26 15:48:57.450179', 10, 'PUBLIC', null, 3); +