diff --git a/server/build.gradle b/server/build.gradle index e101f2eaf..a12f54b6e 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -35,6 +35,7 @@ dependencies { implementation 'io.jsonwebtoken:jjwt:0.9.1' implementation 'javax.xml.bind:jaxb-api:2.3.1' + implementation 'com.auth0:java-jwt:4.4.0' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' diff --git a/server/src/main/java/server/haengdong/application/AuthService.java b/server/src/main/java/server/haengdong/application/AuthService.java index d9352ad53..78242c783 100644 --- a/server/src/main/java/server/haengdong/application/AuthService.java +++ b/server/src/main/java/server/haengdong/application/AuthService.java @@ -2,31 +2,43 @@ import java.util.Map; +import lombok.extern.slf4j.Slf4j; import server.haengdong.domain.TokenProvider; +import server.haengdong.domain.user.Role; import server.haengdong.exception.AuthenticationException; import server.haengdong.exception.HaengdongErrorCode; +@Slf4j public class AuthService { - private static final String TOKEN_NAME = "eventToken"; + private static final String TOKEN_NAME = "accessToken"; private static final String CLAIM_SUB = "sub"; + private static final String ROLE = "role"; private final TokenProvider tokenProvider; + private final EventService eventService; - public AuthService(TokenProvider tokenProvider) { + public AuthService(TokenProvider tokenProvider, EventService eventService) { this.tokenProvider = tokenProvider; + this.eventService = eventService; } - public String createToken(String eventId) { - Map payload = Map.of(CLAIM_SUB, eventId); + public String createGuestToken(Long userId) { + Map payload = Map.of(CLAIM_SUB, userId, ROLE, Role.GUEST); return tokenProvider.createToken(payload); } - public String findEventIdByToken(String token) { + public String createMemberToken(Long userId) { + Map payload = Map.of(CLAIM_SUB, userId, ROLE, Role.MEMBER); + + return tokenProvider.createToken(payload); + } + + public Long findUserIdByToken(String token) { validateToken(token); Map payload = tokenProvider.getPayload(token); - return (String) payload.get(CLAIM_SUB); + return (Long) payload.get(CLAIM_SUB); } private void validateToken(String token) { @@ -38,4 +50,13 @@ private void validateToken(String token) { public String getTokenName() { return TOKEN_NAME; } + + public void checkAuth(String eventToken, Long userId) { + boolean hasEvent = eventService.existsByTokenAndUserId(eventToken, userId); + + if (!hasEvent) { + log.warn("[행사 접근 불가] Cookie EventId = {}, UserId = {}", eventToken, userId); + throw new AuthenticationException(HaengdongErrorCode.FORBIDDEN); + } + } } diff --git a/server/src/main/java/server/haengdong/application/BillService.java b/server/src/main/java/server/haengdong/application/BillService.java index 407914d29..461ae6b52 100644 --- a/server/src/main/java/server/haengdong/application/BillService.java +++ b/server/src/main/java/server/haengdong/application/BillService.java @@ -15,8 +15,8 @@ import server.haengdong.domain.bill.BillRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.member.MemberRepository; +import server.haengdong.domain.eventmember.EventMember; +import server.haengdong.domain.eventmember.EventMemberRepository; import server.haengdong.domain.step.Steps; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; @@ -28,22 +28,22 @@ public class BillService { private final BillRepository billRepository; private final EventRepository eventRepository; - private final MemberRepository memberRepository; + private final EventMemberRepository eventMemberRepository; @Transactional public void saveBill(String eventToken, BillAppRequest request) { Event event = getEvent(eventToken); List memberIds = request.memberIds(); - List members = memberIds.stream() + List eventMembers = memberIds.stream() .map(this::findMember) .toList(); - Bill bill = request.toBill(event, members); + Bill bill = request.toBill(event, eventMembers); billRepository.save(bill); } - private Member findMember(Long memberId) { - return memberRepository.findById(memberId) + private EventMember findMember(Long memberId) { + return eventMemberRepository.findById(memberId) .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND)); } diff --git a/server/src/main/java/server/haengdong/application/MemberService.java b/server/src/main/java/server/haengdong/application/EventMemberService.java similarity index 70% rename from server/src/main/java/server/haengdong/application/MemberService.java rename to server/src/main/java/server/haengdong/application/EventMemberService.java index 840c4f769..823c25945 100644 --- a/server/src/main/java/server/haengdong/application/MemberService.java +++ b/server/src/main/java/server/haengdong/application/EventMemberService.java @@ -16,18 +16,18 @@ import server.haengdong.domain.bill.BillRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.member.MemberRepository; -import server.haengdong.domain.member.UpdatedMembers; +import server.haengdong.domain.eventmember.EventMember; +import server.haengdong.domain.eventmember.EventMemberRepository; +import server.haengdong.domain.eventmember.UpdatedMembers; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; @RequiredArgsConstructor @Transactional(readOnly = true) @Service -public class MemberService { +public class EventMemberService { - private final MemberRepository memberRepository; + private final EventMemberRepository eventMemberRepository; private final EventRepository eventRepository; private final BillRepository billRepository; @@ -40,12 +40,12 @@ public MembersSaveAppResponse saveMembers(String token, MembersSaveAppRequest re validateMemberSave(memberNames, event); - List members = memberNames.stream() - .map(name -> new Member(event, name)) + List eventMembers = memberNames.stream() + .map(name -> new EventMember(event, name)) .toList(); - List savedMembers = memberRepository.saveAll(members); - return MembersSaveAppResponse.of(savedMembers); + List savedEventMembers = eventMemberRepository.saveAll(eventMembers); + return MembersSaveAppResponse.of(savedEventMembers); } private void validateMemberSave(List memberNames, Event event) { @@ -59,7 +59,7 @@ private void validateMemberSave(List memberNames, Event event) { } private boolean isDuplicatedMemberNames(Set uniqueMemberNames, Event event) { - return memberRepository.findAllByEvent(event).stream() + return eventMemberRepository.findAllByEvent(event).stream() .anyMatch(member -> uniqueMemberNames.contains(member.getName())); } @@ -68,7 +68,7 @@ public List getCurrentMembers(String token) { return billRepository.findFirstByEventOrderByIdDesc(event) .map(Bill::getMembers) - .orElseGet(() -> memberRepository.findAllByEvent(event)) + .orElseGet(() -> eventMemberRepository.findAllByEvent(event)) .stream() .map(MemberAppResponse::of) .toList(); @@ -77,38 +77,38 @@ public List getCurrentMembers(String token) { public MembersDepositAppResponse findAllMembers(String token) { Event event = getEvent(token); - List members = memberRepository.findAllByEvent(event); + List eventMembers = eventMemberRepository.findAllByEvent(event); - return MembersDepositAppResponse.of(members); + return MembersDepositAppResponse.of(eventMembers); } @Transactional public void updateMembers(String token, MembersUpdateAppRequest request) { Event event = getEvent(token); UpdatedMembers updatedMembers = new UpdatedMembers(request.toMembers(event)); - List originMembers = memberRepository.findAllByEvent(event); + List originEventMembers = eventMemberRepository.findAllByEvent(event); - updatedMembers.validateUpdatable(originMembers); - memberRepository.saveAll(updatedMembers.getMembers()); + updatedMembers.validateUpdatable(originEventMembers); + eventMemberRepository.saveAll(updatedMembers.getMembers()); } @Transactional public void deleteMember(String token, Long memberId) { - memberRepository.findById(memberId) + eventMemberRepository.findById(memberId) .ifPresent(member -> deleteMember(token, member)); } - private void deleteMember(String token, Member member) { - Event event = member.getEvent(); + private void deleteMember(String token, EventMember eventMember) { + Event event = eventMember.getEvent(); if (event.isTokenMismatch(token)) { throw new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND); } billRepository.findAllByEvent(event).stream() - .filter(bill -> bill.containMember(member)) - .forEach(bill -> bill.removeMemberBillDetail(member)); + .filter(bill -> bill.containMember(eventMember)) + .forEach(bill -> bill.removeMemberBillDetail(eventMember)); billRepository.flush(); - memberRepository.delete(member); + eventMemberRepository.delete(eventMember); } private Event getEvent(String token) { diff --git a/server/src/main/java/server/haengdong/application/EventService.java b/server/src/main/java/server/haengdong/application/EventService.java index 1823cf8f1..b087e46fd 100644 --- a/server/src/main/java/server/haengdong/application/EventService.java +++ b/server/src/main/java/server/haengdong/application/EventService.java @@ -8,6 +8,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.request.EventGuestAppRequest; import server.haengdong.application.request.EventLoginAppRequest; import server.haengdong.application.request.EventUpdateAppRequest; import server.haengdong.application.response.EventAppResponse; @@ -23,7 +24,8 @@ import server.haengdong.domain.event.EventImage; import server.haengdong.domain.event.EventImageRepository; import server.haengdong.domain.event.EventRepository; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; +import server.haengdong.domain.eventmember.EventMemberRepository; import server.haengdong.exception.AuthenticationException; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; @@ -39,16 +41,32 @@ public class EventService { private final RandomValueProvider randomValueProvider; private final BillRepository billRepository; private final EventImageRepository eventImageRepository; + private final EventMemberRepository eventMemberRepository; + private final UserService userService; @Value("${image.base-url}") private String baseUrl; + @Transactional + public EventAppResponse saveEventGuest(EventGuestAppRequest request) { + Long userId = userService.joinGuest(request.toUserRequest()); + String token = randomValueProvider.createRandomValue(); + Event event = new Event(request.eventName(), userId, token); + eventRepository.save(event); + + eventMemberRepository.save(new EventMember(event, request.nickname())); + return EventAppResponse.of(event); + } + @Transactional public EventAppResponse saveEvent(EventAppRequest request) { String token = randomValueProvider.createRandomValue(); - Event event = request.toEvent(token); + Event event = new Event(request.name(), request.userId(), token); eventRepository.save(event); + String nickname = userService.findNicknameById(request.userId()); + eventMemberRepository.save(new EventMember(event, nickname)); + return EventAppResponse.of(event); } @@ -58,11 +76,10 @@ public EventDetailAppResponse findEvent(String token) { return EventDetailAppResponse.of(event); } - public void validatePassword(EventLoginAppRequest request) throws HaengdongException { + public EventAppResponse findByGuestPassword(EventLoginAppRequest request) { Event event = getEvent(request.token()); - if (event.isPasswordMismatch(request.password())) { - throw new AuthenticationException(HaengdongErrorCode.PASSWORD_INVALID); - } + userService.validateUser(event.getUserId(), request.password()); + return EventAppResponse.of(event); } public List getMemberBillReports(String token) { @@ -77,14 +94,14 @@ public List getMemberBillReports(String token) { .toList(); } - private MemberBillReportAppResponse createMemberBillReportResponse(Entry entry) { - Member member = entry.getKey(); + private MemberBillReportAppResponse createMemberBillReportResponse(Entry entry) { + EventMember eventMember = entry.getKey(); Long price = entry.getValue(); return new MemberBillReportAppResponse( - member.getId(), - member.getName(), - member.isDeposited(), + eventMember.getId(), + eventMember.getName(), + eventMember.isDeposited(), price ); } @@ -175,4 +192,8 @@ public List findImagesDateBefore(Instant date) { .map(EventImageSaveAppResponse::of) .toList(); } + + public boolean existsByTokenAndUserId(String eventToken, Long userId) { + return eventRepository.existsByTokenAndUserId(eventToken, userId); + } } diff --git a/server/src/main/java/server/haengdong/application/KakaoClient.java b/server/src/main/java/server/haengdong/application/KakaoClient.java new file mode 100644 index 000000000..4981549b6 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/KakaoClient.java @@ -0,0 +1,46 @@ +package server.haengdong.application; + +import lombok.RequiredArgsConstructor; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestClient; +import server.haengdong.application.response.KakaoTokenResponse; +import server.haengdong.config.KakaoProperties; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@EnableConfigurationProperties(KakaoProperties.class) +@Component +public class KakaoClient { + + private final KakaoProperties kakaoProperties; + private final RestClient restClient; + + public KakaoTokenResponse join(String code, String redirectUri) { + MultiValueMap params = new LinkedMultiValueMap<>(); + params.add("grant_type", "authorization_code"); + params.add("client_id", kakaoProperties.clientId()); + params.add("redirect_uri", redirectUri); + params.add("code", code); + + try { + return restClient.post() + .uri(kakaoProperties.baseUri() + kakaoProperties.tokenRequestUri()) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE) + .body(params) + .retrieve() + .body(KakaoTokenResponse.class); + } catch (Exception e) { + throw new HaengdongException(HaengdongErrorCode.KAKAO_LOGIN_FAIL, e); + } + } + + public String getClientId() { + return kakaoProperties.clientId(); + } +} diff --git a/server/src/main/java/server/haengdong/application/KakaoUserService.java b/server/src/main/java/server/haengdong/application/KakaoUserService.java new file mode 100644 index 000000000..6ba52f5b5 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/KakaoUserService.java @@ -0,0 +1,32 @@ +package server.haengdong.application; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.interfaces.DecodedJWT; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import server.haengdong.application.response.KakaoTokenResponse; + +@RequiredArgsConstructor +@Service +public class KakaoUserService { + + private static final String NICKNAME_KEY = "nickname"; + + private final UserService userService; + private final KakaoClient kakaoClient; + + public Long joinByKakao(String code, String redirectUri) { + KakaoTokenResponse kakaoToken = kakaoClient.join(code, redirectUri); + String idToken = kakaoToken.idToken(); + DecodedJWT decodedJWT = JWT.decode(idToken); + + String memberNumber = decodedJWT.getSubject(); + String nickname = decodedJWT.getClaim(NICKNAME_KEY).asString(); + + return userService.join(memberNumber, nickname); + } + + public String getClientId() { + return kakaoClient.getClientId(); + } +} diff --git a/server/src/main/java/server/haengdong/application/UserService.java b/server/src/main/java/server/haengdong/application/UserService.java new file mode 100644 index 000000000..2c7078544 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/UserService.java @@ -0,0 +1,69 @@ +package server.haengdong.application; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import server.haengdong.application.request.UserGuestSaveAppRequest; +import server.haengdong.application.request.UserUpdateAppRequest; +import server.haengdong.domain.user.User; +import server.haengdong.domain.user.UserRepository; +import server.haengdong.exception.AuthenticationException; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@RequiredArgsConstructor +@Service +public class UserService { + private final UserRepository userRepository; + + private final EventMemberService eventMemberService; + private final KakaoClient kakaoClient; + + @Transactional + public Long joinGuest(UserGuestSaveAppRequest request) { + User user = request.toUser(); + + User savedUser = userRepository.save(user); + return savedUser.getId(); + } + + @Transactional + public Long join(String memberNumber, String nickname) { + User user = userRepository.findByMemberNumber(memberNumber) + .orElseGet(() -> userRepository.save(User.createMember(nickname, memberNumber))); + + return user.getId(); + } + + @Transactional(readOnly = true) + public void validateUser(Long id, String password) { + User user = getUser(id); + + if (user.isPasswordMismatch(password)) { + throw new AuthenticationException(HaengdongErrorCode.PASSWORD_INVALID); + } + } + + @Transactional + public void updateUser(UserUpdateAppRequest request) { + User user = getUser(request.id()); + + if (request.isNicknameExist()) { + user.changeNickname(request.nickname()); + } + if (request.isAccountExist()) { + user.changeAccount(request.bankName(), request.accountNumber()); + } + } + + @Transactional(readOnly = true) + public String findNicknameById(Long id) { + User user = getUser(id); + return user.getNickname(); + } + + private User getUser(Long id) { + return userRepository.findById(id) + .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.PASSWORD_INVALID)); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/BillAppRequest.java b/server/src/main/java/server/haengdong/application/request/BillAppRequest.java index 8eb945263..07faed97c 100644 --- a/server/src/main/java/server/haengdong/application/request/BillAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/BillAppRequest.java @@ -2,7 +2,7 @@ import java.util.List; import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; import server.haengdong.domain.event.Event; public record BillAppRequest( @@ -11,7 +11,7 @@ public record BillAppRequest( List memberIds ) { - public Bill toBill(Event event, List members) { - return Bill.create(event, title, price, members); + public Bill toBill(Event event, List eventMembers) { + return Bill.create(event, title, price, eventMembers); } } diff --git a/server/src/main/java/server/haengdong/application/request/EventAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java index 20ec16d88..d286fe819 100644 --- a/server/src/main/java/server/haengdong/application/request/EventAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/EventAppRequest.java @@ -2,9 +2,9 @@ import server.haengdong.domain.event.Event; -public record EventAppRequest(String name, String password) { +public record EventAppRequest(String name, Long userId) { public Event toEvent(String token) { - return new Event(name, password, token); + return new Event(name, userId, token); } } diff --git a/server/src/main/java/server/haengdong/application/request/EventGuestAppRequest.java b/server/src/main/java/server/haengdong/application/request/EventGuestAppRequest.java new file mode 100644 index 000000000..0c04a29dc --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/EventGuestAppRequest.java @@ -0,0 +1,11 @@ +package server.haengdong.application.request; + +public record EventGuestAppRequest( + String eventName, + String nickname, + String password +) { + public UserGuestSaveAppRequest toUserRequest() { + return new UserGuestSaveAppRequest(nickname, password); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java index 77df0625b..510c904b4 100644 --- a/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/MemberUpdateAppRequest.java @@ -1,7 +1,7 @@ package server.haengdong.application.request; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; import server.haengdong.domain.event.Event; public record MemberUpdateAppRequest( @@ -10,7 +10,7 @@ public record MemberUpdateAppRequest( boolean isDeposited ) { - public Member toMember(Event event) { - return new Member(id, event, name, isDeposited); + public EventMember toMember(Event event) { + return new EventMember(id, event, name, isDeposited); } } diff --git a/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java index aa3253504..ee08c239e 100644 --- a/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java +++ b/server/src/main/java/server/haengdong/application/request/MembersUpdateAppRequest.java @@ -2,11 +2,11 @@ import java.util.List; import server.haengdong.domain.event.Event; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; public record MembersUpdateAppRequest(List members) { - public List toMembers(Event event) { + public List toMembers(Event event) { return members.stream() .map(memberRequest -> memberRequest.toMember(event)) .toList(); diff --git a/server/src/main/java/server/haengdong/application/request/UserGuestSaveAppRequest.java b/server/src/main/java/server/haengdong/application/request/UserGuestSaveAppRequest.java new file mode 100644 index 000000000..21a10a706 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/UserGuestSaveAppRequest.java @@ -0,0 +1,17 @@ +package server.haengdong.application.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.domain.user.User; + +public record UserGuestSaveAppRequest( + + @NotBlank(message = "닉네임은 공백일 수 없습니다.") + String nickname, + + @NotBlank(message = "비밀번호는 공백일 수 없습니다.") + String password +) { + public User toUser() { + return User.createGuest(nickname, password); + } +} diff --git a/server/src/main/java/server/haengdong/application/request/UserUpdateAppRequest.java b/server/src/main/java/server/haengdong/application/request/UserUpdateAppRequest.java new file mode 100644 index 000000000..a174cd943 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/request/UserUpdateAppRequest.java @@ -0,0 +1,17 @@ +package server.haengdong.application.request; + +public record UserUpdateAppRequest( + Long id, + String nickname, + String bankName, + String accountNumber +) { + public boolean isNicknameExist() { + return nickname != null && !nickname.isBlank(); + } + + public boolean isAccountExist() { + return accountNumber != null && !accountNumber.isBlank() + && bankName != null && !bankName.isBlank(); + } +} diff --git a/server/src/main/java/server/haengdong/application/response/BillDetailAppResponse.java b/server/src/main/java/server/haengdong/application/response/BillDetailAppResponse.java index 6618135cb..9c9e11ca2 100644 --- a/server/src/main/java/server/haengdong/application/response/BillDetailAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/BillDetailAppResponse.java @@ -12,7 +12,7 @@ public record BillDetailAppResponse( public static BillDetailAppResponse of(BillDetail billDetail) { return new BillDetailAppResponse( billDetail.getId(), - billDetail.getMember().getName(), + billDetail.getEventMember().getName(), billDetail.getPrice(), billDetail.isFixed() ); diff --git a/server/src/main/java/server/haengdong/application/response/EventAppResponse.java b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java index f331d0011..1e900a13b 100644 --- a/server/src/main/java/server/haengdong/application/response/EventAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/EventAppResponse.java @@ -2,9 +2,12 @@ import server.haengdong.domain.event.Event; -public record EventAppResponse(String token) { +public record EventAppResponse( + String token, + Long userId +) { public static EventAppResponse of(Event event) { - return new EventAppResponse(event.getToken()); + return new EventAppResponse(event.getToken(), event.getUserId()); } } diff --git a/server/src/main/java/server/haengdong/application/response/KakaoTokenResponse.java b/server/src/main/java/server/haengdong/application/response/KakaoTokenResponse.java new file mode 100644 index 000000000..5dff47918 --- /dev/null +++ b/server/src/main/java/server/haengdong/application/response/KakaoTokenResponse.java @@ -0,0 +1,12 @@ +package server.haengdong.application.response; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public record KakaoTokenResponse( + @JsonProperty("access_token") + String accessToken, + + @JsonProperty("id_token") + String idToken +) { +} diff --git a/server/src/main/java/server/haengdong/application/response/LastBillMemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/LastBillMemberAppResponse.java index abefe009a..a259d83a7 100644 --- a/server/src/main/java/server/haengdong/application/response/LastBillMemberAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/LastBillMemberAppResponse.java @@ -1,10 +1,10 @@ package server.haengdong.application.response; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; public record LastBillMemberAppResponse(Long id, String name) { - public static LastBillMemberAppResponse of(Member member) { - return new LastBillMemberAppResponse(member.getId(), member.getName()); + public static LastBillMemberAppResponse of(EventMember eventMember) { + return new LastBillMemberAppResponse(eventMember.getId(), eventMember.getName()); } } diff --git a/server/src/main/java/server/haengdong/application/response/MemberAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberAppResponse.java index 98579b2d1..869f2a238 100644 --- a/server/src/main/java/server/haengdong/application/response/MemberAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/MemberAppResponse.java @@ -1,13 +1,13 @@ package server.haengdong.application.response; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; public record MemberAppResponse( Long id, String name ) { - public static MemberAppResponse of(Member member) { - return new MemberAppResponse(member.getId(), member.getName()); + public static MemberAppResponse of(EventMember eventMember) { + return new MemberAppResponse(eventMember.getId(), eventMember.getName()); } } diff --git a/server/src/main/java/server/haengdong/application/response/MemberDepositAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberDepositAppResponse.java index bb09e02df..05a909a86 100644 --- a/server/src/main/java/server/haengdong/application/response/MemberDepositAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/MemberDepositAppResponse.java @@ -1,6 +1,6 @@ package server.haengdong.application.response; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; public record MemberDepositAppResponse( Long id, @@ -8,7 +8,7 @@ public record MemberDepositAppResponse( boolean isDeposited ) { - public static MemberDepositAppResponse of(Member member) { - return new MemberDepositAppResponse(member.getId(), member.getName(), member.isDeposited()); + public static MemberDepositAppResponse of(EventMember eventMember) { + return new MemberDepositAppResponse(eventMember.getId(), eventMember.getName(), eventMember.isDeposited()); } } diff --git a/server/src/main/java/server/haengdong/application/response/MemberSaveAppResponse.java b/server/src/main/java/server/haengdong/application/response/MemberSaveAppResponse.java index bd1d117f2..0d339d5a7 100644 --- a/server/src/main/java/server/haengdong/application/response/MemberSaveAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/MemberSaveAppResponse.java @@ -1,13 +1,13 @@ package server.haengdong.application.response; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; public record MemberSaveAppResponse( Long id, String name ) { - public static MemberSaveAppResponse of(Member member) { - return new MemberSaveAppResponse(member.getId(), member.getName()); + public static MemberSaveAppResponse of(EventMember eventMember) { + return new MemberSaveAppResponse(eventMember.getId(), eventMember.getName()); } } diff --git a/server/src/main/java/server/haengdong/application/response/MembersDepositAppResponse.java b/server/src/main/java/server/haengdong/application/response/MembersDepositAppResponse.java index 007904d25..66ba3602c 100644 --- a/server/src/main/java/server/haengdong/application/response/MembersDepositAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/MembersDepositAppResponse.java @@ -1,14 +1,14 @@ package server.haengdong.application.response; import java.util.List; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; public record MembersDepositAppResponse( List members ) { - public static MembersDepositAppResponse of(List members) { - return new MembersDepositAppResponse(members.stream() + public static MembersDepositAppResponse of(List eventMembers) { + return new MembersDepositAppResponse(eventMembers.stream() .map(MemberDepositAppResponse::of) .toList()); } diff --git a/server/src/main/java/server/haengdong/application/response/MembersSaveAppResponse.java b/server/src/main/java/server/haengdong/application/response/MembersSaveAppResponse.java index c81fe0996..d90d71db8 100644 --- a/server/src/main/java/server/haengdong/application/response/MembersSaveAppResponse.java +++ b/server/src/main/java/server/haengdong/application/response/MembersSaveAppResponse.java @@ -1,15 +1,15 @@ package server.haengdong.application.response; import java.util.List; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; public record MembersSaveAppResponse( List members ) { - public static MembersSaveAppResponse of(List members) { + public static MembersSaveAppResponse of(List eventMembers) { return new MembersSaveAppResponse( - members.stream() + eventMembers.stream() .map(MemberSaveAppResponse::of) .toList() ); diff --git a/server/src/main/java/server/haengdong/config/AdminInterceptor.java b/server/src/main/java/server/haengdong/config/AdminInterceptor.java index acfe99789..527cdbbf7 100644 --- a/server/src/main/java/server/haengdong/config/AdminInterceptor.java +++ b/server/src/main/java/server/haengdong/config/AdminInterceptor.java @@ -15,6 +15,8 @@ @Slf4j public class AdminInterceptor implements HandlerInterceptor { + public static final String LOGIN_MEMBER_REQUEST = "loginUserId"; + private static final String ADMIN_URI_REGEX = "/api/admin/events/([^/]+)"; private static final Pattern ADMIN_URI_PATTERN = Pattern.compile(ADMIN_URI_REGEX); private static final int EVENT_TOKEN_MATCHER_INDEX = 1; @@ -39,18 +41,15 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons private void validateToken(HttpServletRequest request) { String token = authenticationExtractor.extract(request, authService.getTokenName()); - String tokenEventId = authService.findEventIdByToken(token); + Long userId = authService.findUserIdByToken(token); String uri = request.getRequestURI(); - Matcher matcher = ADMIN_URI_PATTERN.matcher(uri); if (!matcher.find()) { throw new AuthenticationException(HaengdongErrorCode.FORBIDDEN); } - String eventToken = matcher.group(EVENT_TOKEN_MATCHER_INDEX); - if (!tokenEventId.equals(eventToken)) { - log.warn("[행사 접근 불가] Cookie EventId = {}, URL EventId = {}", tokenEventId, eventToken); - throw new AuthenticationException(HaengdongErrorCode.FORBIDDEN); - } + + authService.checkAuth(eventToken, userId); + request.setAttribute(LOGIN_MEMBER_REQUEST, userId); } } diff --git a/server/src/main/java/server/haengdong/config/AuthenticationPrincipalArgumentResolver.java b/server/src/main/java/server/haengdong/config/AuthenticationPrincipalArgumentResolver.java new file mode 100644 index 000000000..383f5b536 --- /dev/null +++ b/server/src/main/java/server/haengdong/config/AuthenticationPrincipalArgumentResolver.java @@ -0,0 +1,25 @@ +package server.haengdong.config; + +import static server.haengdong.config.AdminInterceptor.LOGIN_MEMBER_REQUEST; + +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.core.MethodParameter; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArgumentResolver { + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.hasParameterAnnotation(Login.class) && parameter.getParameterType().equals(Long.class); + } + + @Override + public Long resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { + HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); + + return (Long) request.getAttribute(LOGIN_MEMBER_REQUEST); + } +} diff --git a/server/src/main/java/server/haengdong/config/KakaoConfig.java b/server/src/main/java/server/haengdong/config/KakaoConfig.java new file mode 100644 index 000000000..029a91725 --- /dev/null +++ b/server/src/main/java/server/haengdong/config/KakaoConfig.java @@ -0,0 +1,34 @@ +package server.haengdong.config; + +import java.time.Duration; +import org.springframework.boot.web.client.ClientHttpRequestFactories; +import org.springframework.boot.web.client.ClientHttpRequestFactorySettings; +import org.springframework.boot.web.client.RestClientCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.JdkClientHttpRequestFactory; +import org.springframework.web.client.RestClient; + +@Configuration +public class KakaoConfig { + + @Bean + public RestClient restClient(RestClient.Builder restClientBuilder) { + return restClientBuilder.build(); + } + + @Bean + public RestClientCustomizer restClientCustomizer() { + return restClientBuilder -> restClientBuilder + .requestFactory(clientHttpRequestFactory()); + } + + private ClientHttpRequestFactory clientHttpRequestFactory() { + ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.DEFAULTS + .withConnectTimeout(Duration.ofSeconds(3L)) + .withReadTimeout(Duration.ofSeconds(30L)); + + return ClientHttpRequestFactories.get(JdkClientHttpRequestFactory.class, settings); + } +} diff --git a/server/src/main/java/server/haengdong/config/KakaoProperties.java b/server/src/main/java/server/haengdong/config/KakaoProperties.java new file mode 100644 index 000000000..c4dcc32db --- /dev/null +++ b/server/src/main/java/server/haengdong/config/KakaoProperties.java @@ -0,0 +1,12 @@ +package server.haengdong.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("kakao") +public record KakaoProperties( + String baseUri, + String clientId, + String tokenRequestUri, + String oauthCodeUri +) { +} diff --git a/server/src/main/java/server/haengdong/config/Login.java b/server/src/main/java/server/haengdong/config/Login.java new file mode 100644 index 000000000..76786ffd5 --- /dev/null +++ b/server/src/main/java/server/haengdong/config/Login.java @@ -0,0 +1,12 @@ +package server.haengdong.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface Login { + boolean required() default true; +} diff --git a/server/src/main/java/server/haengdong/config/WebMvcConfig.java b/server/src/main/java/server/haengdong/config/WebMvcConfig.java index 43f858db3..bd7c95126 100644 --- a/server/src/main/java/server/haengdong/config/WebMvcConfig.java +++ b/server/src/main/java/server/haengdong/config/WebMvcConfig.java @@ -9,6 +9,7 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import server.haengdong.application.AuthService; +import server.haengdong.application.EventService; import server.haengdong.domain.TokenProvider; import server.haengdong.infrastructure.auth.AuthenticationExtractor; import server.haengdong.infrastructure.auth.JwtTokenProvider; @@ -20,6 +21,7 @@ public class WebMvcConfig implements WebMvcConfigurer { private final TokenProperties tokenProperties; + private final EventService eventService; @Value("${cors.max-age}") private Long maxAge; @@ -50,7 +52,7 @@ public AdminInterceptor adminInterceptor() { @Bean public AuthService authService() { - return new AuthService(tokenProvider()); + return new AuthService(tokenProvider(), eventService); } @Bean diff --git a/server/src/main/java/server/haengdong/domain/bill/Bill.java b/server/src/main/java/server/haengdong/domain/bill/Bill.java index 747a526e0..43c33dab7 100644 --- a/server/src/main/java/server/haengdong/domain/bill/Bill.java +++ b/server/src/main/java/server/haengdong/domain/bill/Bill.java @@ -20,7 +20,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import server.haengdong.domain.BaseEntity; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; import server.haengdong.domain.event.Event; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; @@ -73,18 +73,18 @@ private void validatePrice(Long price) { } } - public static Bill create(Event event, String title, Long price, List members) { + public static Bill create(Event event, String title, Long price, List eventMembers) { Bill bill = new Bill(event, title, price); - bill.resetBillDetails(members); + bill.resetBillDetails(eventMembers); return bill; } - public void resetBillDetails(List members) { + public void resetBillDetails(List eventMembers) { this.billDetails.clear(); - Iterator priceIterator = distributePrice(members.size()).iterator(); + Iterator priceIterator = distributePrice(eventMembers.size()).iterator(); - for (Member member : members) { - BillDetail billDetail = new BillDetail(this, member, priceIterator.next(), false); + for (EventMember eventMember : eventMembers) { + BillDetail billDetail = new BillDetail(this, eventMember, priceIterator.next(), false); this.billDetails.add(billDetail); } } @@ -112,9 +112,9 @@ private List distributePrice(int memberCount) { return results; } - public void removeMemberBillDetail(Member member) { + public void removeMemberBillDetail(EventMember eventMember) { BillDetail foundBillDetail = billDetails.stream() - .filter(billDetail -> billDetail.isMember(member)) + .filter(billDetail -> billDetail.isMember(eventMember)) .findFirst() .orElseThrow(() -> new HaengdongException(HaengdongErrorCode.MEMBER_NOT_FOUND)); @@ -130,16 +130,16 @@ public void update(String title, Long price) { resetBillDetails(); } - public boolean containMember(Member member) { + public boolean containMember(EventMember eventMember) { return billDetails.stream() - .anyMatch(billDetail -> billDetail.isMember(member)); + .anyMatch(billDetail -> billDetail.isMember(eventMember)); } public boolean isSameMembers(Bill other) { - Set members = Set.copyOf(this.getMembers()); - Set otherMembers = Set.copyOf(other.getMembers()); + Set eventMembers = Set.copyOf(this.getMembers()); + Set otherEventMembers = Set.copyOf(other.getMembers()); - return members.equals(otherMembers); + return eventMembers.equals(otherEventMembers); } public boolean isSamePrice(Long price) { @@ -151,9 +151,9 @@ public boolean isFixed() { .anyMatch(BillDetail::isFixed); } - public List getMembers() { + public List getMembers() { return billDetails.stream() - .map(BillDetail::getMember) + .map(BillDetail::getEventMember) .toList(); } } diff --git a/server/src/main/java/server/haengdong/domain/bill/BillDetail.java b/server/src/main/java/server/haengdong/domain/bill/BillDetail.java index 8a754b2b9..856bdaf45 100644 --- a/server/src/main/java/server/haengdong/domain/bill/BillDetail.java +++ b/server/src/main/java/server/haengdong/domain/bill/BillDetail.java @@ -12,7 +12,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import server.haengdong.domain.BaseEntity; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @@ -29,7 +29,7 @@ public class BillDetail extends BaseEntity { @JoinColumn(name = "member_id", nullable = false) @ManyToOne(fetch = FetchType.LAZY) - private Member member; + private EventMember eventMember; @Column(nullable = false) private Long price; @@ -37,9 +37,9 @@ public class BillDetail extends BaseEntity { @Column(nullable = false) private boolean isFixed; - public BillDetail(Bill bill, Member member, Long price, boolean isFixed) { + public BillDetail(Bill bill, EventMember eventMember, Long price, boolean isFixed) { this.bill = bill; - this.member = member; + this.eventMember = eventMember; this.price = price; this.isFixed = isFixed; } @@ -56,7 +56,7 @@ public boolean isSameId(Long id) { return this.id.equals(id); } - public boolean isMember(Member member) { - return this.member.equals(member); + public boolean isMember(EventMember eventMember) { + return this.eventMember.equals(eventMember); } } diff --git a/server/src/main/java/server/haengdong/domain/bill/BillRepository.java b/server/src/main/java/server/haengdong/domain/bill/BillRepository.java index 23efe487c..351d8e656 100644 --- a/server/src/main/java/server/haengdong/domain/bill/BillRepository.java +++ b/server/src/main/java/server/haengdong/domain/bill/BillRepository.java @@ -14,7 +14,7 @@ public interface BillRepository extends JpaRepository { select b from Bill b join fetch b.billDetails bd - join fetch bd.member + join fetch bd.eventMember where b.event = :event """) List findAllByEvent(Event event); diff --git a/server/src/main/java/server/haengdong/domain/bill/MemberBillReport.java b/server/src/main/java/server/haengdong/domain/bill/MemberBillReport.java index ee16824d0..07a98c804 100644 --- a/server/src/main/java/server/haengdong/domain/bill/MemberBillReport.java +++ b/server/src/main/java/server/haengdong/domain/bill/MemberBillReport.java @@ -5,22 +5,22 @@ import java.util.List; import java.util.Map; import lombok.Getter; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; @Getter public class MemberBillReport { - private final Map reports; + private final Map reports; - private MemberBillReport(Map reports) { + private MemberBillReport(Map reports) { this.reports = reports; } public static MemberBillReport createByBills(List bills) { - Map reports = bills.stream() + Map reports = bills.stream() .flatMap(bill -> bill.getBillDetails().stream()) .collect(toMap( - BillDetail::getMember, + BillDetail::getEventMember, BillDetail::getPrice, Long::sum )); diff --git a/server/src/main/java/server/haengdong/domain/event/Event.java b/server/src/main/java/server/haengdong/domain/event/Event.java index a7cc00fb3..87cf3a9bd 100644 --- a/server/src/main/java/server/haengdong/domain/event/Event.java +++ b/server/src/main/java/server/haengdong/domain/event/Event.java @@ -7,7 +7,6 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import java.time.Instant; import java.util.Arrays; import lombok.AccessLevel; import lombok.Getter; @@ -35,7 +34,7 @@ public class Event extends BaseEntity { private String name; @Embedded - @AttributeOverride(name = "value", column = @Column(name = "password", nullable = false)) + @AttributeOverride(name = "value", column = @Column(name = "password")) private Password password; @Column(nullable = false, unique = true) @@ -44,6 +43,8 @@ public class Event extends BaseEntity { @Column(length = MAX_ACCOUNT_NUMBER_LENGTH) private String account; + @Column(nullable = false) + private Long userId; public Event(String name, String password, String token) { validateName(name); @@ -51,6 +52,14 @@ public Event(String name, String password, String token) { this.password = new Password(password); this.token = token; this.account = ""; + this.userId = 0L; + } + + public Event(String name, Long userId, String token) { + validateName(name); + this.name = name; + this.userId = userId; + this.token = token; } private void validateName(String name) { diff --git a/server/src/main/java/server/haengdong/domain/event/EventRepository.java b/server/src/main/java/server/haengdong/domain/event/EventRepository.java index 09526125e..0f85d5274 100644 --- a/server/src/main/java/server/haengdong/domain/event/EventRepository.java +++ b/server/src/main/java/server/haengdong/domain/event/EventRepository.java @@ -8,4 +8,6 @@ public interface EventRepository extends JpaRepository { Optional findByToken(String token); + + boolean existsByTokenAndUserId(String token, Long userId); } diff --git a/server/src/main/java/server/haengdong/domain/member/Member.java b/server/src/main/java/server/haengdong/domain/eventmember/EventMember.java similarity index 87% rename from server/src/main/java/server/haengdong/domain/member/Member.java rename to server/src/main/java/server/haengdong/domain/eventmember/EventMember.java index 2c9cb41d6..f512e7764 100644 --- a/server/src/main/java/server/haengdong/domain/member/Member.java +++ b/server/src/main/java/server/haengdong/domain/eventmember/EventMember.java @@ -1,4 +1,4 @@ -package server.haengdong.domain.member; +package server.haengdong.domain.eventmember; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -23,7 +23,7 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"event_id", "name"})}) @Entity -public class Member extends BaseEntity { +public class EventMember extends BaseEntity { private static final int MIN_NAME_LENGTH = 1; private static final int MAX_NAME_LENGTH = 8; @@ -42,11 +42,11 @@ public class Member extends BaseEntity { @Column(nullable = false) private boolean isDeposited; - public Member(Event event, String name) { + public EventMember(Event event, String name) { this(null, event, name, false); } - public Member(Long id, Event event, String name, boolean isDeposited) { + public EventMember(Long id, Event event, String name, boolean isDeposited) { validateName(name); this.id = id; this.event = event; @@ -74,8 +74,8 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { return false; } - Member member = (Member) o; - return Objects.equals(id, member.id); + EventMember eventMember = (EventMember) o; + return Objects.equals(id, eventMember.id); } @Override diff --git a/server/src/main/java/server/haengdong/domain/eventmember/EventMemberRepository.java b/server/src/main/java/server/haengdong/domain/eventmember/EventMemberRepository.java new file mode 100644 index 000000000..a1fc12562 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/eventmember/EventMemberRepository.java @@ -0,0 +1,10 @@ +package server.haengdong.domain.eventmember; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import server.haengdong.domain.event.Event; + +public interface EventMemberRepository extends JpaRepository { + + List findAllByEvent(Event event); +} diff --git a/server/src/main/java/server/haengdong/domain/eventmember/UpdatedMembers.java b/server/src/main/java/server/haengdong/domain/eventmember/UpdatedMembers.java new file mode 100644 index 000000000..f4b88af9d --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/eventmember/UpdatedMembers.java @@ -0,0 +1,67 @@ +package server.haengdong.domain.eventmember; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +public class UpdatedMembers { + + private final Set eventMembers; + + public UpdatedMembers(List eventMembers) { + validateMemberUnique(eventMembers); + validateNameUnique(eventMembers); + this.eventMembers = new HashSet<>(eventMembers); + } + + private void validateMemberUnique(List eventMembers) { + if (eventMembers.size() != Set.copyOf(eventMembers).size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + } + + private void validateNameUnique(List eventMembers) { + Set uniqueNames = eventMembers.stream() + .map(EventMember::getName) + .collect(Collectors.toSet()); + if (eventMembers.size() != uniqueNames.size()) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); + } + } + + public void validateUpdatable(List originEventMembers) { + Set uniqueEventMembers = Set.copyOf(originEventMembers); + validateUpdatedMembersExist(uniqueEventMembers); + validateUpdatedNamesUnique(uniqueEventMembers); + } + + private void validateUpdatedMembersExist(Set originEventMembers) { + if (!this.eventMembers.equals(originEventMembers)) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_UPDATE_MISMATCH); + } + } + + private void validateUpdatedNamesUnique(Set originEventMembers) { + boolean duplicated = originEventMembers.stream() + .anyMatch(this::isMemberNameUpdated); + + if (duplicated) { + throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); + } + } + + private boolean isMemberNameUpdated(EventMember originMembers) { + return this.eventMembers.stream() + .filter(member -> !member.getId().equals(originMembers.getId())) + .anyMatch(member -> member.hasName(originMembers.getName())); + } + + public List getMembers() { + return eventMembers.stream().toList(); + } +} + + diff --git a/server/src/main/java/server/haengdong/domain/member/MemberRepository.java b/server/src/main/java/server/haengdong/domain/member/MemberRepository.java deleted file mode 100644 index 15d57f4ba..000000000 --- a/server/src/main/java/server/haengdong/domain/member/MemberRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package server.haengdong.domain.member; - -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; -import server.haengdong.domain.event.Event; - -public interface MemberRepository extends JpaRepository { - - List findAllByEvent(Event event); -} diff --git a/server/src/main/java/server/haengdong/domain/member/UpdatedMembers.java b/server/src/main/java/server/haengdong/domain/member/UpdatedMembers.java deleted file mode 100644 index 3a588c077..000000000 --- a/server/src/main/java/server/haengdong/domain/member/UpdatedMembers.java +++ /dev/null @@ -1,67 +0,0 @@ -package server.haengdong.domain.member; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import server.haengdong.exception.HaengdongErrorCode; -import server.haengdong.exception.HaengdongException; - -public class UpdatedMembers { - - private final Set members; - - public UpdatedMembers(List members) { - validateMemberUnique(members); - validateNameUnique(members); - this.members = new HashSet<>(members); - } - - private void validateMemberUnique(List members) { - if (members.size() != Set.copyOf(members).size()) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); - } - } - - private void validateNameUnique(List members) { - Set uniqueNames = members.stream() - .map(Member::getName) - .collect(Collectors.toSet()); - if (members.size() != uniqueNames.size()) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_CHANGE_DUPLICATE); - } - } - - public void validateUpdatable(List originMembers) { - Set uniqueMembers = Set.copyOf(originMembers); - validateUpdatedMembersExist(uniqueMembers); - validateUpdatedNamesUnique(uniqueMembers); - } - - private void validateUpdatedMembersExist(Set originMembers) { - if (!this.members.equals(originMembers)) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_UPDATE_MISMATCH); - } - } - - private void validateUpdatedNamesUnique(Set originMembers) { - boolean duplicated = originMembers.stream() - .anyMatch(this::isMemberNameUpdated); - - if (duplicated) { - throw new HaengdongException(HaengdongErrorCode.MEMBER_NAME_DUPLICATE); - } - } - - private boolean isMemberNameUpdated(Member originMembers) { - return this.members.stream() - .filter(member -> !member.getId().equals(originMembers.getId())) - .anyMatch(member -> member.hasName(originMembers.getName())); - } - - public List getMembers() { - return members.stream().toList(); - } -} - - diff --git a/server/src/main/java/server/haengdong/domain/step/Step.java b/server/src/main/java/server/haengdong/domain/step/Step.java index 834d3e715..ed82d2ee4 100644 --- a/server/src/main/java/server/haengdong/domain/step/Step.java +++ b/server/src/main/java/server/haengdong/domain/step/Step.java @@ -5,26 +5,26 @@ import java.util.List; import java.util.Set; import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; import server.haengdong.exception.HaengdongErrorCode; import server.haengdong.exception.HaengdongException; public class Step { private final List bills; - private final Set members; + private final Set eventMembers; - private Step(List bills, Set members) { + private Step(List bills, Set eventMembers) { this.bills = bills; - this.members = members; + this.eventMembers = eventMembers; } public static Step of(Bill bill) { List bills = new ArrayList<>(); bills.add(bill); - Set members = new HashSet<>(bill.getMembers()); + Set eventMembers = new HashSet<>(bill.getMembers()); - return new Step(bills, members); + return new Step(bills, eventMembers); } public void add(Bill bill) { @@ -36,15 +36,15 @@ public void add(Bill bill) { } public boolean isNotSameMember(Bill bill) { - Set otherMembers = Set.copyOf(bill.getMembers()); - return !members.equals(otherMembers); + Set otherEventMembers = Set.copyOf(bill.getMembers()); + return !eventMembers.equals(otherEventMembers); } public List getBills() { return bills; } - public Set getMembers() { - return members; + public Set getMembers() { + return eventMembers; } } diff --git a/server/src/main/java/server/haengdong/domain/user/Role.java b/server/src/main/java/server/haengdong/domain/user/Role.java new file mode 100644 index 000000000..921af7ae5 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/user/Role.java @@ -0,0 +1,5 @@ +package server.haengdong.domain.user; + +public enum Role { + GUEST, MEMBER +} diff --git a/server/src/main/java/server/haengdong/domain/user/User.java b/server/src/main/java/server/haengdong/domain/user/User.java new file mode 100644 index 000000000..31d1fff56 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/user/User.java @@ -0,0 +1,82 @@ +package server.haengdong.domain.user; + +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 lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import server.haengdong.domain.BaseEntity; +import server.haengdong.domain.event.Bank; +import server.haengdong.exception.HaengdongErrorCode; +import server.haengdong.exception.HaengdongException; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "users") +@Entity +public class User extends BaseEntity { + + private static final int MIN_ACCOUNT_NUMBER_LENGTH = 8; + private static final int MAX_ACCOUNT_NUMBER_LENGTH = 30; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + private String nickname; + + private String password; + + private String bank; + + @Column(length = MAX_ACCOUNT_NUMBER_LENGTH) + private String accountNumber; + + private String memberNumber; + + private User(String nickname, String password, String bank, String accountNumber, String memberNumber) { + this.nickname = nickname; + this.password = password; + this.bank = bank; + this.accountNumber = accountNumber; + this.memberNumber = memberNumber; + } + + public static User createGuest(String nickName, String password) { + return new User(nickName, password, null, null, null); + } + + public static User createMember(String nickName, String memberNumber) { + return new User(nickName, null, null, null, memberNumber); + } + + public void changeNickname(String nickname) { + this.nickname = nickname; + } + + public void changeAccount(String bankName, String accountNumber) { + validateBankName(bankName); + validateAccountNumber(accountNumber); + } + + private void validateBankName(String bankName) { + Bank.isExists(bankName); + } + + private void validateAccountNumber(String accountNumber) { + int accountLength = accountNumber.trim().length(); + if (accountLength < MIN_ACCOUNT_NUMBER_LENGTH || MAX_ACCOUNT_NUMBER_LENGTH < accountLength) { + throw new HaengdongException( + HaengdongErrorCode.ACCOUNT_LENGTH_INVALID, MIN_ACCOUNT_NUMBER_LENGTH, MAX_ACCOUNT_NUMBER_LENGTH); + } + } + + public boolean isPasswordMismatch(String rawPassword) { + return !password.matches(rawPassword); + } +} diff --git a/server/src/main/java/server/haengdong/domain/user/UserRepository.java b/server/src/main/java/server/haengdong/domain/user/UserRepository.java new file mode 100644 index 000000000..77c601634 --- /dev/null +++ b/server/src/main/java/server/haengdong/domain/user/UserRepository.java @@ -0,0 +1,9 @@ +package server.haengdong.domain.user; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserRepository extends JpaRepository { + + Optional findByMemberNumber(String memberNumber); +} diff --git a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java index 39b1014b0..1bdb96c0a 100644 --- a/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java +++ b/server/src/main/java/server/haengdong/exception/HaengdongErrorCode.java @@ -42,6 +42,8 @@ public enum HaengdongErrorCode { FORBIDDEN("접근할 수 없는 행사입니다."), + KAKAO_LOGIN_FAIL("카카오 인증에 실패했습니다."), + /* Request Validation */ REQUEST_EMPTY("입력 값은 공백일 수 없습니다.") diff --git a/server/src/main/java/server/haengdong/presentation/EventController.java b/server/src/main/java/server/haengdong/presentation/EventController.java index 47bdd4fce..326eafd5a 100644 --- a/server/src/main/java/server/haengdong/presentation/EventController.java +++ b/server/src/main/java/server/haengdong/presentation/EventController.java @@ -14,12 +14,13 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import server.haengdong.application.AuthService; -import server.haengdong.application.response.EventImageAppResponse; import server.haengdong.application.EventService; +import server.haengdong.application.response.EventAppResponse; +import server.haengdong.application.response.EventImageAppResponse; import server.haengdong.application.response.MemberBillReportAppResponse; import server.haengdong.infrastructure.auth.CookieProperties; +import server.haengdong.presentation.request.EventGuestSaveRequest; import server.haengdong.presentation.request.EventLoginRequest; -import server.haengdong.presentation.request.EventSaveRequest; import server.haengdong.presentation.response.EventDetailResponse; import server.haengdong.presentation.response.EventImagesResponse; import server.haengdong.presentation.response.EventResponse; @@ -50,11 +51,12 @@ public ResponseEntity getMemberBillReports(@PathVaria .body(MemberBillReportsResponse.of(memberBillReports)); } - @PostMapping("/api/events") - public ResponseEntity saveEvent(@Valid @RequestBody EventSaveRequest request) { - EventResponse eventResponse = EventResponse.of(eventService.saveEvent(request.toAppRequest())); + @PostMapping("/api/events/guest") + public ResponseEntity saveEventGuest(@Valid @RequestBody EventGuestSaveRequest request) { + EventAppResponse eventAppResponse = eventService.saveEventGuest(request.toAppRequest()); + EventResponse eventResponse = EventResponse.of(eventAppResponse); - String jwtToken = authService.createToken(eventResponse.eventId()); + String jwtToken = authService.createGuestToken(eventAppResponse.userId()); ResponseCookie responseCookie = createResponseCookie(jwtToken); return ResponseEntity.ok() @@ -67,8 +69,8 @@ public ResponseEntity loginEvent( @PathVariable("eventId") String token, @Valid @RequestBody EventLoginRequest request ) { - eventService.validatePassword(request.toAppRequest(token)); - String jwtToken = authService.createToken(token); + EventAppResponse response = eventService.findByGuestPassword(request.toAppRequest(token)); + String jwtToken = authService.createGuestToken(response.userId()); ResponseCookie responseCookie = createResponseCookie(jwtToken); return ResponseEntity.ok() diff --git a/server/src/main/java/server/haengdong/presentation/MemberController.java b/server/src/main/java/server/haengdong/presentation/EventMemberController.java similarity index 76% rename from server/src/main/java/server/haengdong/presentation/MemberController.java rename to server/src/main/java/server/haengdong/presentation/EventMemberController.java index f5662f9b2..08d3af273 100644 --- a/server/src/main/java/server/haengdong/presentation/MemberController.java +++ b/server/src/main/java/server/haengdong/presentation/EventMemberController.java @@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.MemberService; +import server.haengdong.application.EventMemberService; import server.haengdong.application.response.MemberAppResponse; import server.haengdong.presentation.response.CurrentMembersResponse; import server.haengdong.presentation.response.MembersResponse; @@ -15,20 +15,20 @@ @Slf4j @RequiredArgsConstructor @RestController -public class MemberController { +public class EventMemberController { - private final MemberService memberService; + private final EventMemberService eventMemberService; @GetMapping("/api/events/{eventId}/members") public ResponseEntity findAllMembers(@PathVariable("eventId") String token) { - MembersResponse response = MembersResponse.of(memberService.findAllMembers(token)); + MembersResponse response = MembersResponse.of(eventMemberService.findAllMembers(token)); return ResponseEntity.ok(response); } @GetMapping("/api/events/{eventId}/members/current") public ResponseEntity getCurrentMembers(@PathVariable("eventId") String token) { - List currentMembers = memberService.getCurrentMembers(token); + List currentMembers = eventMemberService.getCurrentMembers(token); return ResponseEntity.ok() .body(CurrentMembersResponse.of(currentMembers)); diff --git a/server/src/main/java/server/haengdong/presentation/UserController.java b/server/src/main/java/server/haengdong/presentation/UserController.java new file mode 100644 index 000000000..f8a029028 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/UserController.java @@ -0,0 +1,77 @@ +package server.haengdong.presentation; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseCookie; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import server.haengdong.application.AuthService; +import server.haengdong.application.KakaoUserService; +import server.haengdong.application.UserService; +import server.haengdong.config.Login; +import server.haengdong.infrastructure.auth.CookieProperties; +import server.haengdong.presentation.request.UserUpdateRequest; +import server.haengdong.presentation.response.KakaoClientId; + +@Slf4j +@RequiredArgsConstructor +@EnableConfigurationProperties(CookieProperties.class) +@Controller +public class UserController { + + private final UserService userService; + private final KakaoUserService kakaoUserService; + private final AuthService authService; + private final CookieProperties cookieProperties; + + @PatchMapping("/api/admin/users") + public ResponseEntity updateUser( + @Login Long userId, + @Valid @RequestBody UserUpdateRequest request + ) { + userService.updateUser(request.toAppRequest(userId)); + return ResponseEntity.ok().build(); + } + + @GetMapping("/api/kakao-client-id") + public ResponseEntity getKakaoClientId() { + String clientId = kakaoUserService.getClientId(); + KakaoClientId kakaoClientId = new KakaoClientId(clientId); + + return ResponseEntity.ok(kakaoClientId); + } + + @GetMapping("/api/login/kakao") + public ResponseEntity kakaoLogin( + @RequestParam String code, + @RequestParam("redirect_uri") String redirectUri + ) { + log.info("Kakao login code, redirectUri: {}, {}", code, redirectUri); + Long userId = kakaoUserService.joinByKakao(code, redirectUri); + String jwtToken = authService.createGuestToken(userId); + + ResponseCookie responseCookie = createResponseCookie(jwtToken); + return ResponseEntity.ok() + .header(HttpHeaders.SET_COOKIE, responseCookie.toString()) + .build(); + } + + private ResponseCookie createResponseCookie(String token) { + return ResponseCookie.from(authService.getTokenName(), token) + .httpOnly(cookieProperties.httpOnly()) + .secure(cookieProperties.secure()) + .domain(cookieProperties.domain()) + .path(cookieProperties.path()) + .sameSite(cookieProperties.sameSite()) + .maxAge(cookieProperties.maxAge()) + .build(); + } + +} diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java b/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java index 81434aeba..2dd84d449 100644 --- a/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java +++ b/server/src/main/java/server/haengdong/presentation/admin/AdminEventController.java @@ -15,7 +15,11 @@ import org.springframework.web.multipart.MultipartFile; import server.haengdong.application.EventImageFacadeService; import server.haengdong.application.EventService; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.config.Login; +import server.haengdong.presentation.request.EventSaveRequest; import server.haengdong.presentation.request.EventUpdateRequest; +import server.haengdong.presentation.response.EventResponse; @Slf4j @RequiredArgsConstructor @@ -25,6 +29,12 @@ public class AdminEventController { private final EventService eventService; private final EventImageFacadeService eventImageFacadeService; + @PostMapping("/api/admin/events") + public ResponseEntity saveEvent(@Login Long userId, @Valid @RequestBody EventSaveRequest request) { + EventResponse eventResponse = EventResponse.of(eventService.saveEvent(new EventAppRequest(request.eventName(), userId))); + return ResponseEntity.ok(eventResponse); + } + @PostMapping("/api/admin/events/{eventId}/auth") public ResponseEntity authenticate() { return ResponseEntity.ok().build(); diff --git a/server/src/main/java/server/haengdong/presentation/admin/AdminMemberController.java b/server/src/main/java/server/haengdong/presentation/admin/AdminMemberController.java index 22cb0190a..be7c3c3c5 100644 --- a/server/src/main/java/server/haengdong/presentation/admin/AdminMemberController.java +++ b/server/src/main/java/server/haengdong/presentation/admin/AdminMemberController.java @@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import server.haengdong.application.MemberService; +import server.haengdong.application.EventMemberService; import server.haengdong.application.response.MembersSaveAppResponse; import server.haengdong.presentation.request.MembersSaveRequest; import server.haengdong.presentation.request.MembersUpdateRequest; @@ -21,14 +21,14 @@ @RestController public class AdminMemberController { - private final MemberService memberService; + private final EventMemberService eventMemberService; @PostMapping("/api/admin/events/{eventId}/members") public ResponseEntity saveMembers( @PathVariable("eventId") String token, @Valid @RequestBody MembersSaveRequest request ) { - MembersSaveAppResponse response = memberService.saveMembers(token, request.toAppRequest()); + MembersSaveAppResponse response = eventMemberService.saveMembers(token, request.toAppRequest()); return ResponseEntity.ok(MembersSaveResponse.of(response)); } @@ -38,7 +38,7 @@ public ResponseEntity updateMembers( @PathVariable("eventId") String token, @Valid @RequestBody MembersUpdateRequest request ) { - memberService.updateMembers(token, request.toAppRequest()); + eventMemberService.updateMembers(token, request.toAppRequest()); return ResponseEntity.ok().build(); } @@ -48,7 +48,7 @@ public ResponseEntity deleteMember( @PathVariable("eventId") String token, @PathVariable("memberId") Long memberId ) { - memberService.deleteMember(token, memberId); + eventMemberService.deleteMember(token, memberId); return ResponseEntity.ok().build(); } diff --git a/server/src/main/java/server/haengdong/presentation/request/EventGuestSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventGuestSaveRequest.java new file mode 100644 index 000000000..3354e6cb4 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/EventGuestSaveRequest.java @@ -0,0 +1,21 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.application.request.EventGuestAppRequest; + +public record EventGuestSaveRequest( + + @NotBlank(message = "행사 이름은 공백일 수 없습니다.") + String eventName, + + @NotBlank(message = "행사 이름은 공백일 수 없습니다.") + String nickname, + + @NotBlank(message = "비밀번호는 공백일 수 없습니다.") + String password +) { + + public EventGuestAppRequest toAppRequest() { + return new EventGuestAppRequest(eventName, nickname, password); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java index 6bd7cd006..e50e8a44f 100644 --- a/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java +++ b/server/src/main/java/server/haengdong/presentation/request/EventSaveRequest.java @@ -1,18 +1,9 @@ package server.haengdong.presentation.request; import jakarta.validation.constraints.NotBlank; -import server.haengdong.application.request.EventAppRequest; public record EventSaveRequest( - @NotBlank(message = "행사 이름은 공백일 수 없습니다.") - String eventName, - - @NotBlank(message = "비밀번호는 공백일 수 없습니다.") - String password + String eventName ) { - - public EventAppRequest toAppRequest() { - return new EventAppRequest(eventName, password); - } } diff --git a/server/src/main/java/server/haengdong/presentation/request/UserGuestSaveRequest.java b/server/src/main/java/server/haengdong/presentation/request/UserGuestSaveRequest.java new file mode 100644 index 000000000..f2469b35c --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/UserGuestSaveRequest.java @@ -0,0 +1,17 @@ +package server.haengdong.presentation.request; + +import jakarta.validation.constraints.NotBlank; +import server.haengdong.application.request.UserGuestSaveAppRequest; + +public record UserGuestSaveRequest( + + @NotBlank(message = "닉네임은 공백일 수 없습니다.") + String nickname, + + @NotBlank(message = "비밀번호는 공백일 수 없습니다.") + String password +) { + public UserGuestSaveAppRequest toAppRequest() { + return new UserGuestSaveAppRequest(nickname, password); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/request/UserUpdateRequest.java b/server/src/main/java/server/haengdong/presentation/request/UserUpdateRequest.java new file mode 100644 index 000000000..ba9c6197c --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/request/UserUpdateRequest.java @@ -0,0 +1,13 @@ +package server.haengdong.presentation.request; + +import server.haengdong.application.request.UserUpdateAppRequest; + +public record UserUpdateRequest( + String nickname, + String bankName, + String accountNumber +) { + public UserUpdateAppRequest toAppRequest(Long userId) { + return new UserUpdateAppRequest(userId, nickname, bankName, accountNumber); + } +} diff --git a/server/src/main/java/server/haengdong/presentation/response/KakaoClientId.java b/server/src/main/java/server/haengdong/presentation/response/KakaoClientId.java new file mode 100644 index 000000000..f3fa62992 --- /dev/null +++ b/server/src/main/java/server/haengdong/presentation/response/KakaoClientId.java @@ -0,0 +1,6 @@ +package server.haengdong.presentation.response; + +public record KakaoClientId( + String clientId +) { +} diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml index e3d8d5e8a..a6553aa14 100644 --- a/server/src/main/resources/application.yml +++ b/server/src/main/resources/application.yml @@ -69,6 +69,13 @@ server: enabled: true threads: max: 50 + +kakao: + base-uri: https://kauth.kakao.com + token-request-uri: /oauth/token + client-id: 52f24834ff7304ed2c47294b3f57b053 + oauth-code-uri: https://kauth.kakao.com/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code&scope=openid + --- spring: diff --git a/server/src/main/resources/config b/server/src/main/resources/config index f7a9ac8ef..9b8b97777 160000 --- a/server/src/main/resources/config +++ b/server/src/main/resources/config @@ -1 +1 @@ -Subproject commit f7a9ac8efafd2bd87f53acc53a133a6933e3a7d8 +Subproject commit 9b8b97777048f7afa19bacac7da704d91adabdb1 diff --git a/server/src/test/java/server/haengdong/application/BillServiceTest.java b/server/src/test/java/server/haengdong/application/BillServiceTest.java index 6d2b7aa8d..61be03598 100644 --- a/server/src/test/java/server/haengdong/application/BillServiceTest.java +++ b/server/src/test/java/server/haengdong/application/BillServiceTest.java @@ -23,8 +23,8 @@ import server.haengdong.domain.bill.BillRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.member.MemberRepository; +import server.haengdong.domain.eventmember.EventMember; +import server.haengdong.domain.eventmember.EventMemberRepository; import server.haengdong.exception.HaengdongException; import server.haengdong.support.fixture.Fixture; @@ -40,22 +40,24 @@ class BillServiceTest extends ServiceTestSupport { private BillRepository billRepository; @Autowired - private MemberRepository memberRepository; + private EventMemberRepository eventMemberRepository; @DisplayName("전체 지출 내역을 조회한다.") @Test void findSteps() { Event event = Fixture.EVENT1; eventRepository.save(event); - Member member1 = new Member(event, "토다리"); - Member member2 = new Member(event, "쿠키"); - Member member3 = new Member(event, "소하"); - Member member4 = new Member(event, "웨디"); - memberRepository.saveAll(List.of(member1, member2, member3, member4)); - Bill bill1 = Bill.create(event, "행동대장 회식1", 100000L, List.of(member1, member2, member3)); - Bill bill2 = Bill.create(event, "행동대장 회식2", 200000L, List.of(member1, member2, member3, member4)); - Bill bill3 = Bill.create(event, "행동대장 회식3", 300000L, List.of(member1, member2, member3, member4)); - Bill bill4 = Bill.create(event, "행동대장 회식4", 400000L, List.of(member2, member3, member4)); + EventMember eventMember1 = new EventMember(event, "토다리"); + EventMember eventMember2 = new EventMember(event, "쿠키"); + EventMember eventMember3 = new EventMember(event, "소하"); + EventMember eventMember4 = new EventMember(event, "웨디"); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2, eventMember3, eventMember4)); + Bill bill1 = Bill.create(event, "행동대장 회식1", 100000L, List.of(eventMember1, eventMember2, eventMember3)); + Bill bill2 = Bill.create(event, "행동대장 회식2", 200000L, List.of( + eventMember1, eventMember2, eventMember3, eventMember4)); + Bill bill3 = Bill.create(event, "행동대장 회식3", 300000L, List.of( + eventMember1, eventMember2, eventMember3, eventMember4)); + Bill bill4 = Bill.create(event, "행동대장 회식4", 400000L, List.of(eventMember2, eventMember3, eventMember4)); billRepository.saveAll(List.of(bill1, bill2, bill3, bill4)); List steps = billService.findSteps(event.getToken()); @@ -72,9 +74,9 @@ void findSteps() { assertThat(steps.get(0).members()).hasSize(3) .extracting(MemberAppResponse::id, MemberAppResponse::name) .containsExactlyInAnyOrder( - tuple(member1.getId(), member1.getName()), - tuple(member2.getId(), member2.getName()), - tuple(member3.getId(), member3.getName()) + tuple(eventMember1.getId(), eventMember1.getName()), + tuple(eventMember2.getId(), eventMember2.getName()), + tuple(eventMember3.getId(), eventMember3.getName()) ); assertThat(steps.get(1).bills()).hasSize(2) @@ -88,10 +90,10 @@ void findSteps() { assertThat(steps.get(1).members()).hasSize(4) .extracting(MemberAppResponse::id, MemberAppResponse::name) .containsExactlyInAnyOrder( - tuple(member1.getId(), member1.getName()), - tuple(member2.getId(), member2.getName()), - tuple(member3.getId(), member3.getName()), - tuple(member4.getId(), member4.getName()) + tuple(eventMember1.getId(), eventMember1.getName()), + tuple(eventMember2.getId(), eventMember2.getName()), + tuple(eventMember3.getId(), eventMember3.getName()), + tuple(eventMember4.getId(), eventMember4.getName()) ); assertThat(steps.get(2).bills()).hasSize(1) @@ -104,9 +106,9 @@ void findSteps() { assertThat(steps.get(2).members()).hasSize(3) .extracting(MemberAppResponse::id, MemberAppResponse::name) .containsExactlyInAnyOrder( - tuple(member2.getId(), member2.getName()), - tuple(member3.getId(), member3.getName()), - tuple(member4.getId(), member4.getName()) + tuple(eventMember2.getId(), eventMember2.getName()), + tuple(eventMember3.getId(), eventMember3.getName()), + tuple(eventMember4.getId(), eventMember4.getName()) ); } @@ -116,10 +118,10 @@ void saveBill() { Event event = Fixture.EVENT1; Event savedEvent = eventRepository.save(event); - Member member1 = Fixture.MEMBER1; - Member member2 = Fixture.MEMBER2; - memberRepository.saveAll(List.of(member1, member2)); - List memberIds = List.of(member1.getId(), member2.getId()); + EventMember eventMember1 = Fixture.EVENT_MEMBER_1; + EventMember eventMember2 = Fixture.EVENT_MEMBER_2; + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2)); + List memberIds = List.of(eventMember1.getId(), eventMember2.getId()); BillAppRequest billAppRequest = new BillAppRequest("뽕족", 10_000L, memberIds); billService.saveBill(event.getToken(), billAppRequest); @@ -138,12 +140,12 @@ void saveBillTest1() { Event event = Fixture.EVENT1; eventRepository.save(event); - Member member1 = Fixture.MEMBER1; - Member member2 = Fixture.MEMBER2; - List members = List.of(member1, member2); - memberRepository.saveAll(members); + EventMember eventMember1 = Fixture.EVENT_MEMBER_1; + EventMember eventMember2 = Fixture.EVENT_MEMBER_2; + List eventMembers = List.of(eventMember1, eventMember2); + eventMemberRepository.saveAll(eventMembers); - BillAppRequest request = new BillAppRequest("뽕족", 10_000L, List.of(member1.getId(), member2.getId())); + BillAppRequest request = new BillAppRequest("뽕족", 10_000L, List.of(eventMember1.getId(), eventMember2.getId())); billService.saveBill(event.getToken(), request); @@ -153,10 +155,10 @@ void saveBillTest1() { assertThat(billDetails) .hasSize(2) - .extracting("member", "price") + .extracting("eventMember", "price") .containsExactlyInAnyOrder( - tuple(member1, 5_000L), - tuple(member2, 5_000L) + tuple(eventMember1, 5_000L), + tuple(eventMember2, 5_000L) ); } @@ -166,12 +168,12 @@ void saveBill1() { Event event = Fixture.EVENT1; eventRepository.save(event); - Member member1 = Fixture.MEMBER1; - Member member2 = Fixture.MEMBER2; - List members = List.of(member1, member2); - memberRepository.saveAll(members); + EventMember eventMember1 = Fixture.EVENT_MEMBER_1; + EventMember eventMember2 = Fixture.EVENT_MEMBER_2; + List eventMembers = List.of(eventMember1, eventMember2); + eventMemberRepository.saveAll(eventMembers); - BillAppRequest request = new BillAppRequest("뽕족", 10_000L, List.of(member1.getId(), member2.getId())); + BillAppRequest request = new BillAppRequest("뽕족", 10_000L, List.of(eventMember1.getId(), eventMember2.getId())); assertThatThrownBy(() -> billService.saveBill("wrongToken", request)) .isInstanceOf(HaengdongException.class); @@ -222,13 +224,13 @@ void updateBill1() { void updateBill2() { Event event = Fixture.EVENT1; eventRepository.save(event); - Member member1 = new Member(event, "감자"); - Member member2 = new Member(event, "고구마"); - Member member3 = new Member(event, "당근"); - Member member4 = new Member(event, "양파"); - List members = List.of(member1, member2, member3, member4); - memberRepository.saveAll(members); - Bill bill = Bill.create(event, "뽕족", 10_000L, members); + EventMember eventMember1 = new EventMember(event, "감자"); + EventMember eventMember2 = new EventMember(event, "고구마"); + EventMember eventMember3 = new EventMember(event, "당근"); + EventMember eventMember4 = new EventMember(event, "양파"); + List eventMembers = List.of(eventMember1, eventMember2, eventMember3, eventMember4); + eventMemberRepository.saveAll(eventMembers); + Bill bill = Bill.create(event, "뽕족", 10_000L, eventMembers); bill.getBillDetails().forEach(billDetail -> billDetail.updateIsFixed(true)); billRepository.save(bill); BillUpdateAppRequest request = new BillUpdateAppRequest("인생맥주", 20_000L); @@ -248,11 +250,11 @@ void updateBill2() { void deleteBill() { Event event = Fixture.EVENT1; eventRepository.save(event); - Member member1 = new Member(event, "토다리"); - Member member2 = new Member(event, "쿠키"); - memberRepository.saveAll(List.of(member1, member2)); + EventMember eventMember1 = new EventMember(event, "토다리"); + EventMember eventMember2 = new EventMember(event, "쿠키"); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2)); - Bill bill = Bill.create(event, "뽕족", 10000L, List.of(member1, member2)); + Bill bill = Bill.create(event, "뽕족", 10000L, List.of(eventMember1, eventMember2)); billRepository.save(bill); Long billId = bill.getId(); @@ -273,11 +275,11 @@ void deleteBill1() { void updateBillDetailsTest1() { Event event1 = Fixture.EVENT1; eventRepository.save(event1); - Member member1 = new Member(event1, "토다리"); - Member member2 = new Member(event1, "쿠키"); - memberRepository.saveAll(List.of(member1, member2)); + EventMember eventMember1 = new EventMember(event1, "토다리"); + EventMember eventMember2 = new EventMember(event1, "쿠키"); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2)); - Bill bill = Bill.create(event1, "뽕족", 10000L, List.of(member1, member2)); + Bill bill = Bill.create(event1, "뽕족", 10000L, List.of(eventMember1, eventMember2)); billRepository.save(bill); List billDetails = bill.getBillDetails(); @@ -297,11 +299,11 @@ void updateBillDetailsTest1() { void updateBillDetailsTest2() { Event event1 = Fixture.EVENT1; eventRepository.save(event1); - Member member1 = new Member(event1, "토다리"); - Member member2 = new Member(event1, "쿠키"); - memberRepository.saveAll(List.of(member1, member2)); + EventMember eventMember1 = new EventMember(event1, "토다리"); + EventMember eventMember2 = new EventMember(event1, "쿠키"); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2)); - Bill bill = Bill.create(event1, "뽕족", 10000L, List.of(member1, member2)); + Bill bill = Bill.create(event1, "뽕족", 10000L, List.of(eventMember1, eventMember2)); billRepository.save(bill); List billDetails = bill.getBillDetails(); @@ -329,12 +331,12 @@ void findBillDetailsTest() { Event event1 = Fixture.EVENT1; eventRepository.save(event1); - Member member1 = Fixture.MEMBER1; - Member member2 = Fixture.MEMBER2; - List members = List.of(member1, member2); - memberRepository.saveAll(members); + EventMember eventMember1 = Fixture.EVENT_MEMBER_1; + EventMember eventMember2 = Fixture.EVENT_MEMBER_2; + List eventMembers = List.of(eventMember1, eventMember2); + eventMemberRepository.saveAll(eventMembers); - Bill bill = Bill.create(event1, "뽕족", 10000L, members); + Bill bill = Bill.create(event1, "뽕족", 10000L, eventMembers); billRepository.save(bill); BillDetailsAppResponse response = billService.findBillDetails(event1.getToken(), bill.getId()); diff --git a/server/src/test/java/server/haengdong/application/MemberServiceTest.java b/server/src/test/java/server/haengdong/application/EventEventMemberServiceTest.java similarity index 57% rename from server/src/test/java/server/haengdong/application/MemberServiceTest.java rename to server/src/test/java/server/haengdong/application/EventEventMemberServiceTest.java index 662156a33..7b6552add 100644 --- a/server/src/test/java/server/haengdong/application/MemberServiceTest.java +++ b/server/src/test/java/server/haengdong/application/EventEventMemberServiceTest.java @@ -9,9 +9,9 @@ import static server.haengdong.support.fixture.Fixture.BILL1; import static server.haengdong.support.fixture.Fixture.EVENT1; import static server.haengdong.support.fixture.Fixture.EVENT2; -import static server.haengdong.support.fixture.Fixture.MEMBER1; -import static server.haengdong.support.fixture.Fixture.MEMBER2; -import static server.haengdong.support.fixture.Fixture.MEMBER3; +import static server.haengdong.support.fixture.Fixture.EVENT_MEMBER_1; +import static server.haengdong.support.fixture.Fixture.EVENT_MEMBER_2; +import static server.haengdong.support.fixture.Fixture.EVENT_MEMBER_3; import java.util.List; import org.assertj.core.groups.Tuple; @@ -32,17 +32,17 @@ import server.haengdong.domain.bill.BillRepository; import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.member.MemberRepository; +import server.haengdong.domain.eventmember.EventMember; +import server.haengdong.domain.eventmember.EventMemberRepository; import server.haengdong.exception.HaengdongException; -class MemberServiceTest extends ServiceTestSupport { +class EventEventMemberServiceTest extends ServiceTestSupport { @Autowired - private MemberService memberService; + private EventMemberService eventMemberService; @Autowired - private MemberRepository memberRepository; + private EventMemberRepository eventMemberRepository; @Autowired private EventRepository eventRepository; @@ -56,22 +56,22 @@ void saveMembersTest() { Event event = EVENT1; String memberName1 = "웨디"; String memberName2 = "쿠키"; - Member member1 = new Member(event, memberName1); - Member member2 = new Member(event, memberName2); + EventMember eventMember1 = new EventMember(event, memberName1); + EventMember eventMember2 = new EventMember(event, memberName2); eventRepository.save(event); MembersSaveAppRequest request = new MembersSaveAppRequest( List.of( - new MemberSaveAppRequest(member1.getName()), - new MemberSaveAppRequest(member2.getName()) + new MemberSaveAppRequest(eventMember1.getName()), + new MemberSaveAppRequest(eventMember2.getName()) ) ); - MembersSaveAppResponse response = memberService.saveMembers(event.getToken(), request); + MembersSaveAppResponse response = eventMemberService.saveMembers(event.getToken(), request); - List savedMembers = memberRepository.findAll(); + List savedEventMembers = eventMemberRepository.findAll(); assertAll( - () -> assertThat(savedMembers) - .extracting(Member::getName) + () -> assertThat(savedEventMembers) + .extracting(EventMember::getName) .containsExactlyInAnyOrder(memberName1, memberName2), () -> assertThat(response.members()) .extracting(MemberSaveAppResponse::id, MemberSaveAppResponse::name) @@ -86,18 +86,18 @@ void saveMembersTest() { @Test void saveMembersTest1() { Event event = EVENT1; - Member member1 = MEMBER1; - Member member2 = MEMBER2; + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; eventRepository.save(event); - memberRepository.save(member1); + eventMemberRepository.save(eventMember1); MembersSaveAppRequest request = new MembersSaveAppRequest( List.of( - new MemberSaveAppRequest(member1.getName()), - new MemberSaveAppRequest(member2.getName()) + new MemberSaveAppRequest(eventMember1.getName()), + new MemberSaveAppRequest(eventMember2.getName()) ) ); - assertThatThrownBy(() -> memberService.saveMembers(event.getToken(), request)) + assertThatThrownBy(() -> eventMemberService.saveMembers(event.getToken(), request)) .isInstanceOf(HaengdongException.class) .hasMessage("현재 참여하고 있는 인원이 존재합니다."); } @@ -114,7 +114,7 @@ void saveMembersTest2() { ) ); - assertThatThrownBy(() -> memberService.saveMembers(event.getToken(), request)) + assertThatThrownBy(() -> eventMemberService.saveMembers(event.getToken(), request)) .isInstanceOf(HaengdongException.class) .hasMessageContaining("행사에 중복된 참여자 이름이 존재합니다."); } @@ -123,13 +123,13 @@ void saveMembersTest2() { @Test void deleteMemberTest() { Event event = EVENT1; - Member member = MEMBER1; + EventMember eventMember = EVENT_MEMBER_1; eventRepository.save(event); - memberRepository.save(member); + eventMemberRepository.save(eventMember); - memberService.deleteMember(event.getToken(), member.getId()); + eventMemberService.deleteMember(event.getToken(), eventMember.getId()); - assertThat(memberRepository.findById(member.getId())).isEmpty(); + assertThat(eventMemberRepository.findById(eventMember.getId())).isEmpty(); } @DisplayName("다른 이벤트의 참여 인원을 삭제하는 경우 예외가 발생한다.") @@ -137,41 +137,41 @@ void deleteMemberTest() { void deleteMemberTest1() { Event event1 = EVENT1; Event event2 = EVENT2; - Member member = new Member(EVENT2, "감자"); + EventMember eventMember = new EventMember(EVENT2, "감자"); eventRepository.saveAll(List.of(event1, event2)); - memberRepository.save(member); + eventMemberRepository.save(eventMember); - assertThatThrownBy(() -> memberService.deleteMember(event1.getToken(), member.getId())) + assertThatThrownBy(() -> eventMemberService.deleteMember(event1.getToken(), eventMember.getId())) .isInstanceOf(HaengdongException.class); - assertThat(memberRepository.findById(member.getId())).isNotEmpty(); + assertThat(eventMemberRepository.findById(eventMember.getId())).isNotEmpty(); } @DisplayName("행사 참여 인원을 삭제하는 경우 해당 참여자가 포함된 Bill이 초기화된다.") @Test void deleteMemberTest2() { Event event1 = EVENT1; - Member member1 = MEMBER1; - Member member2 = MEMBER2; - List members = List.of(member1, member2); - Bill bill = Bill.create(event1, "title", 10000L, members); + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; + List eventMembers = List.of(eventMember1, eventMember2); + Bill bill = Bill.create(event1, "title", 10000L, eventMembers); eventRepository.save(event1); - memberRepository.saveAll(members); + eventMemberRepository.saveAll(eventMembers); - BillDetail billDetail1 = getDetailByMember(bill, member1); - BillDetail billDetail2 = getDetailByMember(bill, member2); + BillDetail billDetail1 = getDetailByMember(bill, eventMember1); + BillDetail billDetail2 = getDetailByMember(bill, eventMember2); billDetail1.updatePrice(8000L); billDetail1.updateIsFixed(false); billDetail2.updatePrice(2000L); billDetail2.updateIsFixed(true); billRepository.save(bill); - memberService.deleteMember(event1.getToken(), member1.getId()); + eventMemberService.deleteMember(event1.getToken(), eventMember1.getId()); Bill bill1 = billRepository.findAllByEvent(event1).get(0); List bill1Details = bill1.getBillDetails(); assertAll( - () -> assertThat(memberRepository.findById(member1.getId())).isEmpty(), + () -> assertThat(eventMemberRepository.findById(eventMember1.getId())).isEmpty(), () -> assertThat(bill1Details).doesNotContain(billDetail1), () -> { BillDetail foundDetail = bill1Details.stream() @@ -182,10 +182,10 @@ void deleteMemberTest2() { ); } - private BillDetail getDetailByMember(Bill bill, Member member) { + private BillDetail getDetailByMember(Bill bill, EventMember eventMember) { return bill.getBillDetails() .stream() - .filter(billDetail -> billDetail.isMember(member)) + .filter(billDetail -> billDetail.isMember(eventMember)) .findFirst() .orElseThrow(); } @@ -194,21 +194,21 @@ private BillDetail getDetailByMember(Bill bill, Member member) { @Test void updateMembersNameTest() { Event event = EVENT1; - Member member = MEMBER1; + EventMember eventMember = EVENT_MEMBER_1; eventRepository.save(event); - memberRepository.save(member); + eventMemberRepository.save(eventMember); MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( List.of( - new MemberUpdateAppRequest(member.getId(), "수정된이름", true) + new MemberUpdateAppRequest(eventMember.getId(), "수정된이름", true) ) ); - memberService.updateMembers(event.getToken(), membersUpdateAppRequest); + eventMemberService.updateMembers(event.getToken(), membersUpdateAppRequest); - Member updatedMember = memberRepository.findById(member.getId()).orElseThrow(); + EventMember updatedEventMember = eventMemberRepository.findById(eventMember.getId()).orElseThrow(); assertAll( - () -> assertThat(updatedMember.getName()).isEqualTo("수정된이름"), - () -> assertTrue(updatedMember.isDeposited()) + () -> assertThat(updatedEventMember.getName()).isEqualTo("수정된이름"), + () -> assertTrue(updatedEventMember.isDeposited()) ); } @@ -216,21 +216,21 @@ void updateMembersNameTest() { @Test void updateMembersIsDepositedTest() { Event event = EVENT1; - Member member = MEMBER1; + EventMember eventMember = EVENT_MEMBER_1; eventRepository.save(event); - memberRepository.save(member); + eventMemberRepository.save(eventMember); MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( List.of( - new MemberUpdateAppRequest(member.getId(), member.getName(), false) + new MemberUpdateAppRequest(eventMember.getId(), eventMember.getName(), false) ) ); - memberService.updateMembers(event.getToken(), membersUpdateAppRequest); + eventMemberService.updateMembers(event.getToken(), membersUpdateAppRequest); - Member updatedMember = memberRepository.findById(member.getId()).orElseThrow(); + EventMember updatedEventMember = eventMemberRepository.findById(eventMember.getId()).orElseThrow(); assertAll( - () -> assertThat(updatedMember.getName()).isEqualTo(member.getName()), - () -> assertFalse(updatedMember.isDeposited()) + () -> assertThat(updatedEventMember.getName()).isEqualTo(eventMember.getName()), + () -> assertFalse(updatedEventMember.isDeposited()) ); } @@ -238,17 +238,17 @@ void updateMembersIsDepositedTest() { @Test void updateMembersTest2() { Event event = EVENT1; - Member member = MEMBER1; + EventMember eventMember = EVENT_MEMBER_1; eventRepository.save(event); - memberRepository.save(member); + eventMemberRepository.save(eventMember); MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( List.of( - new MemberUpdateAppRequest(member.getId(), "수정", true), - new MemberUpdateAppRequest(member.getId(), "수정수정", false) + new MemberUpdateAppRequest(eventMember.getId(), "수정", true), + new MemberUpdateAppRequest(eventMember.getId(), "수정수정", false) ) ); - assertThatThrownBy(() -> memberService.updateMembers(event.getToken(), membersUpdateAppRequest)) + assertThatThrownBy(() -> eventMemberService.updateMembers(event.getToken(), membersUpdateAppRequest)) .isInstanceOf(HaengdongException.class) .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); } @@ -257,18 +257,18 @@ void updateMembersTest2() { @Test void updateMembersTest3() { Event event = EVENT1; - Member member1 = MEMBER1; - Member member2 = MEMBER2; + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; eventRepository.save(event); - memberRepository.saveAll(List.of(member1, member2)); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2)); MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( List.of( - new MemberUpdateAppRequest(member1.getId(), "수정", true), - new MemberUpdateAppRequest(member2.getId(), "수정", false) + new MemberUpdateAppRequest(eventMember1.getId(), "수정", true), + new MemberUpdateAppRequest(eventMember2.getId(), "수정", false) ) ); - assertThatThrownBy(() -> memberService.updateMembers(event.getToken(), membersUpdateAppRequest)) + assertThatThrownBy(() -> eventMemberService.updateMembers(event.getToken(), membersUpdateAppRequest)) .isInstanceOf(HaengdongException.class) .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); } @@ -278,16 +278,16 @@ void updateMembersTest3() { void updateMembersTest4() { Event event1 = EVENT1; Event event2 = EVENT2; - Member member = new Member(event2, "이상"); + EventMember eventMember = new EventMember(event2, "이상"); eventRepository.saveAll(List.of(event1, event2)); - memberRepository.save(member); + eventMemberRepository.save(eventMember); MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( List.of( - new MemberUpdateAppRequest(member.getId(), "수정", true) + new MemberUpdateAppRequest(eventMember.getId(), "수정", true) ) ); - assertThatThrownBy(() -> memberService.updateMembers(event1.getToken(), membersUpdateAppRequest)) + assertThatThrownBy(() -> eventMemberService.updateMembers(event1.getToken(), membersUpdateAppRequest)) .isInstanceOf(HaengdongException.class) .hasMessage("업데이트 요청된 참여자 ID 목록과 기존 행사 참여자 ID 목록이 일치하지 않습니다."); } @@ -296,17 +296,17 @@ void updateMembersTest4() { @Test void updateMembersTest5() { Event event1 = EVENT1; - Member member1 = MEMBER1; - Member member2 = MEMBER2; + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; eventRepository.save(event1); - memberRepository.saveAll(List.of(member1, member2)); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2)); MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( List.of( - new MemberUpdateAppRequest(member1.getId(), member2.getName(), true) + new MemberUpdateAppRequest(eventMember1.getId(), eventMember2.getName(), true) ) ); - assertThatThrownBy(() -> memberService.updateMembers(event1.getToken(), membersUpdateAppRequest)) + assertThatThrownBy(() -> eventMemberService.updateMembers(event1.getToken(), membersUpdateAppRequest)) .isInstanceOf(HaengdongException.class) .hasMessage("업데이트 요청된 참여자 ID 목록과 기존 행사 참여자 ID 목록이 일치하지 않습니다."); } @@ -315,18 +315,18 @@ void updateMembersTest5() { @Test void updateMembersTest6() { Event event = EVENT1; - Member member1 = MEMBER1; - Member member2 = MEMBER2; + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; eventRepository.save(event); - memberRepository.saveAll(List.of(member1, member2)); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2)); MembersUpdateAppRequest membersUpdateAppRequest = new MembersUpdateAppRequest( List.of( - new MemberUpdateAppRequest(member1.getId(), member2.getName(), true), - new MemberUpdateAppRequest(member2.getId(), member1.getName(), false) + new MemberUpdateAppRequest(eventMember1.getId(), eventMember2.getName(), true), + new MemberUpdateAppRequest(eventMember2.getId(), eventMember1.getName(), false) ) ); - assertThatThrownBy(() -> memberService.updateMembers(event.getToken(), membersUpdateAppRequest)) + assertThatThrownBy(() -> eventMemberService.updateMembers(event.getToken(), membersUpdateAppRequest)) .isInstanceOf(HaengdongException.class) .hasMessage("행사에 중복된 참여자 이름이 존재합니다."); } @@ -336,21 +336,21 @@ void updateMembersTest6() { void findAllMembersTest() { Event event = EVENT1; Bill bill = BILL1; - Member member1 = MEMBER1; - Member member2 = MEMBER2; - Member member3 = MEMBER3; + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; + EventMember eventMember3 = EVENT_MEMBER_3; eventRepository.save(event); - memberRepository.saveAll(List.of(member1, member2, member3)); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2, eventMember3)); billRepository.save(bill); - MembersDepositAppResponse membersDepositAppResponse = memberService.findAllMembers(event.getToken()); + MembersDepositAppResponse membersDepositAppResponse = eventMemberService.findAllMembers(event.getToken()); assertThat(membersDepositAppResponse.members()).hasSize(3) .extracting(MemberDepositAppResponse::name, MemberDepositAppResponse::isDeposited) .containsExactlyInAnyOrder( - tuple(member1.getName(), member1.isDeposited()), - tuple(member2.getName(), member2.isDeposited()), - tuple(member3.getName(), member3.isDeposited()) + tuple(eventMember1.getName(), eventMember1.isDeposited()), + tuple(eventMember2.getName(), eventMember2.isDeposited()), + tuple(eventMember3.getName(), eventMember3.isDeposited()) ); } @@ -358,31 +358,31 @@ void findAllMembersTest() { @Test void getCurrentMembersTest() { Event event = EVENT1; - Member member1 = MEMBER1; - Member member2 = MEMBER2; - Member member3 = MEMBER3; - Bill bill1 = Bill.create(event, "title1", 100000L, List.of(member1)); - Bill bill2 = Bill.create(event, "title2", 200000L, List.of(member1, member2, member3)); - Bill bill3 = Bill.create(event, "title2", 200000L, List.of(member1, member2, member3)); + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; + EventMember eventMember3 = EVENT_MEMBER_3; + Bill bill1 = Bill.create(event, "title1", 100000L, List.of(eventMember1)); + Bill bill2 = Bill.create(event, "title2", 200000L, List.of(eventMember1, eventMember2, eventMember3)); + Bill bill3 = Bill.create(event, "title2", 200000L, List.of(eventMember1, eventMember2, eventMember3)); eventRepository.save(event); - memberRepository.saveAll(List.of(member1, member2, member3)); + eventMemberRepository.saveAll(List.of(eventMember1, eventMember2, eventMember3)); billRepository.saveAll(List.of(bill1, bill2, bill3)); - List currentMembers = memberService.getCurrentMembers(event.getToken()); + List currentMembers = eventMemberService.getCurrentMembers(event.getToken()); assertThat(currentMembers).hasSize(3) .extracting(MemberAppResponse::id, MemberAppResponse::name) .containsExactlyInAnyOrder( - tuple(member1.getId(), member1.getName()), - tuple(member2.getId(), member2.getName()), - tuple(member3.getId(), member3.getName()) + tuple(eventMember1.getId(), eventMember1.getName()), + tuple(eventMember2.getId(), eventMember2.getName()), + tuple(eventMember3.getId(), eventMember3.getName()) ); } @DisplayName("행사가 없으면 현재 참여 인원을 조회할 수 없다.") @Test void getCurrentMembersTest1() { - assertThatThrownBy(() -> memberService.getCurrentMembers("token")) + assertThatThrownBy(() -> eventMemberService.getCurrentMembers("token")) .isInstanceOf(HaengdongException.class); } } diff --git a/server/src/test/java/server/haengdong/application/EventServiceTest.java b/server/src/test/java/server/haengdong/application/EventServiceTest.java index a1607c79f..aa8e88cc1 100644 --- a/server/src/test/java/server/haengdong/application/EventServiceTest.java +++ b/server/src/test/java/server/haengdong/application/EventServiceTest.java @@ -13,7 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.mock.mockito.MockBean; -import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.request.EventGuestAppRequest; import server.haengdong.application.request.EventUpdateAppRequest; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; @@ -22,12 +22,12 @@ import server.haengdong.domain.RandomValueProvider; import server.haengdong.domain.bill.Bill; import server.haengdong.domain.bill.BillRepository; +import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventImage; import server.haengdong.domain.event.EventImageRepository; -import server.haengdong.domain.member.Member; -import server.haengdong.domain.member.MemberRepository; -import server.haengdong.domain.event.Event; import server.haengdong.domain.event.EventRepository; +import server.haengdong.domain.eventmember.EventMember; +import server.haengdong.domain.eventmember.EventMemberRepository; import server.haengdong.exception.HaengdongException; import server.haengdong.support.fixture.Fixture; @@ -43,7 +43,7 @@ class EventServiceTest extends ServiceTestSupport { private BillRepository billRepository; @Autowired - private MemberRepository memberRepository; + private EventMemberRepository eventMemberRepository; @Autowired private EventImageRepository eventImageRepository; @@ -56,11 +56,11 @@ class EventServiceTest extends ServiceTestSupport { @DisplayName("행사를 생성한다") @Test - void saveEventTest() { - EventAppRequest request = new EventAppRequest("test", "1234"); + void saveEventGuestTest() { + EventGuestAppRequest request = new EventGuestAppRequest("test", "nickname", "1234"); given(randomValueProvider.createRandomValue()).willReturn("TOKEN"); - EventAppResponse response = eventService.saveEvent(request); + EventAppResponse response = eventService.saveEventGuest(request); assertThat(response.token()).isEqualTo("TOKEN"); } @@ -149,16 +149,16 @@ void updateEventTest3() { void getMemberBillReports() { Event event = Fixture.EVENT1; Event savedEvent = eventRepository.save(event); - List members = List.of( - new Member(savedEvent, "소하"), - new Member(savedEvent, "감자"), - new Member(savedEvent, "쿠키"), - new Member(savedEvent, "고구마") + List eventMembers = List.of( + new EventMember(savedEvent, "소하"), + new EventMember(savedEvent, "감자"), + new EventMember(savedEvent, "쿠키"), + new EventMember(savedEvent, "고구마") ); - memberRepository.saveAll(members); + eventMemberRepository.saveAll(eventMembers); List bills = List.of( - Bill.create(savedEvent, "뽕족", 60_000L, members), - Bill.create(savedEvent, "인생네컷", 20_000L, members) + Bill.create(savedEvent, "뽕족", 60_000L, eventMembers), + Bill.create(savedEvent, "인생네컷", 20_000L, eventMembers) ); billRepository.saveAll(bills); diff --git a/server/src/test/java/server/haengdong/config/AdminInterceptorTest.java b/server/src/test/java/server/haengdong/config/AdminInterceptorTest.java deleted file mode 100644 index f66da7fd1..000000000 --- a/server/src/test/java/server/haengdong/config/AdminInterceptorTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package server.haengdong.config; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; -import server.haengdong.application.AuthService; -import server.haengdong.exception.AuthenticationException; -import server.haengdong.infrastructure.auth.AuthenticationExtractor; - -class AdminInterceptorTest { - - private AuthService authService; - private AuthenticationExtractor authenticationExtractor; - private AdminInterceptor adminInterceptor; - - @BeforeEach - public void setUp() { - authService = mock(AuthService.class); - authenticationExtractor = mock(AuthenticationExtractor.class); - adminInterceptor = new AdminInterceptor(authService, authenticationExtractor); - } - - @DisplayName("쿠키의 JWT 에서 eventToken 과 uri 의 eventToken 이 일치하면 관리자이다.") - @ParameterizedTest - @ValueSource(strings = {"/api/admin/events/12345", "/api/admin/events/12345/bills"}) - void validateToken1(String uri) { - MockHttpServletRequest request = new MockHttpServletRequest("GET", uri); - MockHttpServletResponse response = new MockHttpServletResponse(); - when(authService.findEventIdByToken(any())).thenReturn("12345"); - - boolean preHandle = adminInterceptor.preHandle(request, response, new Object()); - - assertThat(preHandle).isTrue(); - } - - @DisplayName("쿠키의 JWT 에서 eventToken 과 uri 의 eventToken 이 일치하지 않으면 거절당한다.") - @ParameterizedTest - @ValueSource(strings = {"/api/admin/events/12345", "/api/admin/events/12345/bills"}) - void validateToken2(String uri) { - MockHttpServletRequest request = new MockHttpServletRequest("GET", uri); - MockHttpServletResponse response = new MockHttpServletResponse(); - when(authService.findEventIdByToken(any())).thenReturn("125"); - - assertThatThrownBy(() -> adminInterceptor.preHandle(request, response, new Object())) - .isInstanceOf(AuthenticationException.class); - } -} diff --git a/server/src/test/java/server/haengdong/docs/AdminBillControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/AdminBillControllerDocsTest.java index 1c275801e..d6e796dd9 100644 --- a/server/src/test/java/server/haengdong/docs/AdminBillControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/AdminBillControllerDocsTest.java @@ -62,7 +62,7 @@ void saveAllBill() throws Exception { parameterWithName("eventId").description("행사 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") + cookieWithName("accessToken").description("행사 관리자 토큰") ), requestFields( fieldWithPath("title").description("생성할 지출 제목"), @@ -94,7 +94,7 @@ void updateBill() throws Exception { parameterWithName("billId").description("지출 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") + cookieWithName("accessToken").description("행사 관리자 토큰") ), requestFields( fieldWithPath("title").description("수정할 지출 제목"), @@ -130,7 +130,7 @@ void updateBillDetailsTest() throws Exception { parameterWithName("billId").description("지출 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") + cookieWithName("accessToken").description("행사 관리자 토큰") ), requestFields( fieldWithPath("billDetails").type(JsonFieldType.ARRAY) @@ -164,7 +164,7 @@ void deleteBill() throws Exception { parameterWithName("billId").description("지출 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") + cookieWithName("accessToken").description("행사 관리자 토큰") ) )); } diff --git a/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java index b5bb5cda8..71f18fe58 100644 --- a/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/AdminEventControllerDocsTest.java @@ -1,5 +1,7 @@ package server.haengdong.docs; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.springframework.restdocs.cookies.CookieDocumentation.cookieWithName; import static org.springframework.restdocs.cookies.CookieDocumentation.requestCookies; @@ -13,6 +15,7 @@ import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; import static org.springframework.restdocs.request.RequestDocumentation.partWithName; import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; @@ -28,8 +31,12 @@ import org.springframework.restdocs.payload.JsonFieldType; import server.haengdong.application.EventImageFacadeService; import server.haengdong.application.EventService; +import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.response.EventAppResponse; import server.haengdong.presentation.admin.AdminEventController; +import server.haengdong.presentation.request.EventSaveRequest; import server.haengdong.presentation.request.EventUpdateRequest; +import server.haengdong.support.fixture.Fixture; class AdminEventControllerDocsTest extends RestDocsSupport { @@ -58,7 +65,7 @@ void authenticateTest() throws Exception { parameterWithName("eventId").description("행사 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰").optional() + cookieWithName("accessToken").description("행사 관리자 토큰").optional() ) ) ); @@ -86,7 +93,7 @@ void updateEventTest() throws Exception { parameterWithName("eventId").description("행사 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") + cookieWithName("accessToken").description("행사 관리자 토큰") ), requestFields( fieldWithPath("eventName").type(JsonFieldType.STRING) @@ -122,7 +129,7 @@ void uploadImages() throws Exception { parameterWithName("eventId").description("행사 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") + cookieWithName("accessToken").description("행사 관리자 토큰") ), requestParts( partWithName("images").description("행사 이미지") @@ -149,7 +156,40 @@ void deleteImage() throws Exception { parameterWithName("imageId").description("이미지 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 관리자 토큰") + cookieWithName("accessToken").description("행사 관리자 토큰") + ) + ) + ); + } + + @DisplayName("이벤트를 생성한다.") + @Test + void saveEvent() throws Exception { + EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리"); + String requestBody = objectMapper.writeValueAsString(eventSaveRequest); + String eventId = "쿠키 토큰"; + EventAppResponse eventAppResponse = new EventAppResponse(eventId, 1L); + given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); + + mockMvc.perform(post("/api/admin/events") + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + .cookie(Fixture.EVENT_COOKIE)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo( + document("createEvent", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + requestFields( + fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름") + ), + requestCookies( + cookieWithName("accessToken").description("행사 관리자 토큰") + ), + responseFields( + fieldWithPath("eventId").type(JsonFieldType.STRING) + .description("행사 ID") ) ) ); diff --git a/server/src/test/java/server/haengdong/docs/AdminMemberControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/AdminEventEventMemberControllerDocsTest.java similarity index 92% rename from server/src/test/java/server/haengdong/docs/AdminMemberControllerDocsTest.java rename to server/src/test/java/server/haengdong/docs/AdminEventEventMemberControllerDocsTest.java index 9d70673f9..8353d9b8d 100644 --- a/server/src/test/java/server/haengdong/docs/AdminMemberControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/AdminEventEventMemberControllerDocsTest.java @@ -27,7 +27,7 @@ import org.springframework.http.MediaType; import org.springframework.restdocs.payload.JsonFieldType; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import server.haengdong.application.MemberService; +import server.haengdong.application.EventMemberService; import server.haengdong.application.response.MemberSaveAppResponse; import server.haengdong.application.response.MembersSaveAppResponse; import server.haengdong.presentation.admin.AdminMemberController; @@ -36,13 +36,13 @@ import server.haengdong.presentation.request.MembersSaveRequest; import server.haengdong.presentation.request.MembersUpdateRequest; -class AdminMemberControllerDocsTest extends RestDocsSupport { +class AdminEventEventMemberControllerDocsTest extends RestDocsSupport { - private final MemberService memberService = mock(MemberService.class); + private final EventMemberService eventMemberService = mock(EventMemberService.class); @Override protected Object initController() { - return new AdminMemberController(memberService); + return new AdminMemberController(eventMemberService); } @DisplayName("행사 참여자를 추가한다.") @@ -62,7 +62,7 @@ void saveMemberTest() throws Exception { new MemberSaveAppResponse(2L, "소하") ) ); - given(memberService.saveMembers(eventToken, membersSaveRequest.toAppRequest())) + given(eventMemberService.saveMembers(eventToken, membersSaveRequest.toAppRequest())) .willReturn(appResponse); mockMvc.perform(post("/api/admin/events/{eventId}/members", "망쵸토큰") @@ -83,7 +83,7 @@ void saveMemberTest() throws Exception { parameterWithName("eventId").description("행사 ID") ), requestCookies( - cookieWithName("eventToken").description("토큰 토큰") + cookieWithName("accessToken").description("토큰 토큰") ), requestFields( fieldWithPath("members").type(JsonFieldType.ARRAY) @@ -122,7 +122,7 @@ void deleteMember() throws Exception { parameterWithName("memberId").description("삭제할 참여자 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 토큰") + cookieWithName("accessToken").description("행사 토큰") ) ) ); @@ -155,7 +155,7 @@ void updateMembers() throws Exception { parameterWithName("eventId").description("행사 ID") ), requestCookies( - cookieWithName("eventToken").description("행사 토큰") + cookieWithName("accessToken").description("행사 토큰") ), requestFields( fieldWithPath("members").type(JsonFieldType.ARRAY) diff --git a/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java index 0716a2123..33baef08b 100644 --- a/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/BillControllerDocsTest.java @@ -27,7 +27,7 @@ import server.haengdong.application.response.MemberAppResponse; import server.haengdong.application.response.StepAppResponse; import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; import server.haengdong.presentation.BillController; import server.haengdong.support.fixture.Fixture; @@ -46,8 +46,8 @@ void findBills() throws Exception { Bill bill = Fixture.BILL1; List bills = List.of(BillAppResponse.of(bill)); - Member member = Fixture.MEMBER1; - List members = List.of(MemberAppResponse.of(member)); + EventMember eventMember = Fixture.EVENT_MEMBER_1; + List members = List.of(MemberAppResponse.of(eventMember)); StepAppResponse stepAppResponse = new StepAppResponse(bills, members); given(billService.findSteps(anyString())).willReturn(List.of(stepAppResponse)); @@ -62,8 +62,8 @@ void findBills() throws Exception { .andExpect(jsonPath("$.steps[0].bills[0].price").value(bill.getPrice())) .andExpect(jsonPath("$.steps[0].bills[0].isFixed").value(bill.isFixed())) .andExpect(jsonPath("$.steps[0].members").isArray()) - .andExpect(jsonPath("$.steps[0].members[0].id").value(member.getId())) - .andExpect(jsonPath("$.steps[0].members[0].name").value(member.getName())) + .andExpect(jsonPath("$.steps[0].members[0].id").value(eventMember.getId())) + .andExpect(jsonPath("$.steps[0].members[0].name").value(eventMember.getName())) .andDo(document("findBills", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), diff --git a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java index 0918721fd..461756a4b 100644 --- a/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/EventControllerDocsTest.java @@ -31,15 +31,15 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import server.haengdong.application.AuthService; import server.haengdong.application.EventService; -import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.request.EventGuestAppRequest; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.application.response.EventImageAppResponse; import server.haengdong.application.response.MemberBillReportAppResponse; import server.haengdong.infrastructure.auth.CookieProperties; import server.haengdong.presentation.EventController; +import server.haengdong.presentation.request.EventGuestSaveRequest; import server.haengdong.presentation.request.EventLoginRequest; -import server.haengdong.presentation.request.EventSaveRequest; class EventControllerDocsTest extends RestDocsSupport { @@ -124,38 +124,39 @@ void getMemberBillReports() throws Exception { ); } - @DisplayName("이벤트를 생성한다.") + @DisplayName("비회원으로 이벤트를 생성한다.") @Test - void saveEvent() throws Exception { - EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리", "0987"); + void saveEventGuest() throws Exception { + EventGuestSaveRequest eventSaveRequest = new EventGuestSaveRequest("토다리", "nickname", "1234"); String requestBody = objectMapper.writeValueAsString(eventSaveRequest); String eventId = "쿠키 토큰"; - EventAppResponse eventAppResponse = new EventAppResponse(eventId); - given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); - given(authService.createToken(eventId)).willReturn("jwtToken"); - given(authService.getTokenName()).willReturn("eventToken"); + EventAppResponse eventAppResponse = new EventAppResponse(eventId, 1L); + given(eventService.saveEventGuest(any(EventGuestAppRequest.class))).willReturn(eventAppResponse); + given(authService.createGuestToken(1L)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("accessToken"); - mockMvc.perform(post("/api/events") + mockMvc.perform(post("/api/events/guest") .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) - .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(cookie().value("accessToken", "jwtToken")) .andExpect(jsonPath("$.eventId").value("쿠키 토큰")) .andDo( - document("createEvent", + document("createGuestEvent", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), requestFields( fieldWithPath("eventName").type(JsonFieldType.STRING).description("행사 이름"), - fieldWithPath("password").type(JsonFieldType.STRING).description("행사 비밀 번호") + fieldWithPath("nickname").type(JsonFieldType.STRING).description("비회원 닉네임"), + fieldWithPath("password").type(JsonFieldType.STRING).description("비회원 비밀번호") ), responseFields( fieldWithPath("eventId").type(JsonFieldType.STRING) .description("행사 ID") ), responseCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") + cookieWithName("accessToken").description("행사 관리자용 토큰") ) ) ); @@ -167,14 +168,15 @@ void loginEvent() throws Exception { String token = "TOKEN"; EventLoginRequest eventLoginRequest = new EventLoginRequest("1234"); String requestBody = objectMapper.writeValueAsString(eventLoginRequest); - given(authService.createToken(token)).willReturn("jwtToken"); - given(authService.getTokenName()).willReturn("eventToken"); + given(authService.createGuestToken(1L)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("accessToken"); + given(eventService.findByGuestPassword(any())).willReturn(new EventAppResponse("TOKEN", 1L)); mockMvc.perform(post("/api/events/{eventId}/login", token) .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) - .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(cookie().value("accessToken", "jwtToken")) .andExpect(status().isOk()) .andDo( document("eventLogin", @@ -188,7 +190,7 @@ void loginEvent() throws Exception { .description("행사 비밀 번호") ), responseCookies( - cookieWithName("eventToken").description("행사 관리자용 토큰") + cookieWithName("accessToken").description("행사 관리자용 토큰") ) ) ); diff --git a/server/src/test/java/server/haengdong/docs/MemberControllerDocsTest.java b/server/src/test/java/server/haengdong/docs/EventEventMemberControllerDocsTest.java similarity index 92% rename from server/src/test/java/server/haengdong/docs/MemberControllerDocsTest.java rename to server/src/test/java/server/haengdong/docs/EventEventMemberControllerDocsTest.java index 2997ad4ee..c725f186c 100644 --- a/server/src/test/java/server/haengdong/docs/MemberControllerDocsTest.java +++ b/server/src/test/java/server/haengdong/docs/EventEventMemberControllerDocsTest.java @@ -21,19 +21,19 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.restdocs.payload.JsonFieldType; -import server.haengdong.application.MemberService; +import server.haengdong.application.EventMemberService; import server.haengdong.application.response.MemberAppResponse; import server.haengdong.application.response.MemberDepositAppResponse; import server.haengdong.application.response.MembersDepositAppResponse; -import server.haengdong.presentation.MemberController; +import server.haengdong.presentation.EventMemberController; -class MemberControllerDocsTest extends RestDocsSupport { +class EventEventMemberControllerDocsTest extends RestDocsSupport { - private final MemberService memberService = mock(MemberService.class); + private final EventMemberService eventMemberService = mock(EventMemberService.class); @Override protected Object initController() { - return new MemberController(memberService); + return new EventMemberController(eventMemberService); } @DisplayName("행사에 참여한 전체 인원을 조회한다.") @@ -46,7 +46,7 @@ void findAllMembersTest() throws Exception { ); MembersDepositAppResponse memberAppResponse = new MembersDepositAppResponse(members); - given(memberService.findAllMembers(anyString())).willReturn(memberAppResponse); + given(eventMemberService.findAllMembers(anyString())).willReturn(memberAppResponse); mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) .andDo(print()) @@ -90,7 +90,7 @@ void getCurrentMembers() throws Exception { new MemberAppResponse(2L, "백호") ); - given(memberService.getCurrentMembers(any())).willReturn(members); + given(eventMemberService.getCurrentMembers(any())).willReturn(members); mockMvc.perform(get("/api/events/{eventId}/members/current", "TOKEN")) .andExpect(status().isOk()) diff --git a/server/src/test/java/server/haengdong/domain/bill/BillTest.java b/server/src/test/java/server/haengdong/domain/bill/BillTest.java index d1c2e3d8c..3e56daac9 100644 --- a/server/src/test/java/server/haengdong/domain/bill/BillTest.java +++ b/server/src/test/java/server/haengdong/domain/bill/BillTest.java @@ -10,7 +10,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; import server.haengdong.exception.HaengdongException; class BillTest { @@ -54,8 +54,8 @@ void createBill() { @DisplayName("지출에 멤버별 고정 금액이 설정되어 있는지 확인한다.") @Test void isFixed1() { - List members = List.of(new Member(EVENT1, "감자"), new Member(EVENT1, "고구마")); - Bill fixedBill = Bill.create(EVENT1, "인생네컷", 2_000L, members); + List eventMembers = List.of(new EventMember(EVENT1, "감자"), new EventMember(EVENT1, "고구마")); + Bill fixedBill = Bill.create(EVENT1, "인생네컷", 2_000L, eventMembers); assertThat(fixedBill.isFixed()).isEqualTo(false); } @@ -63,12 +63,12 @@ void isFixed1() { @DisplayName("같은 멤버 목록을 가지고 있는지 비교한다.") @Test void isSameMember1() { - Member member1 = new Member(1L, EVENT1, "감자", false); - Member member2 = new Member(2L, EVENT1, "고구마", false); - Member member3 = new Member(3L, EVENT1, "당근", false); + EventMember eventMember1 = new EventMember(1L, EVENT1, "감자", false); + EventMember eventMember2 = new EventMember(2L, EVENT1, "고구마", false); + EventMember eventMember3 = new EventMember(3L, EVENT1, "당근", false); - List members1 = List.of(member1, member2, member3); - List members2 = List.of(member2, member3, member1); + List members1 = List.of(eventMember1, eventMember2, eventMember3); + List members2 = List.of(eventMember2, eventMember3, eventMember1); Bill bill1 = Bill.create(EVENT1, "뽕족", 20_000L, members1); Bill bill2 = Bill.create(EVENT1, "인생네컷", 30_000L, members2); @@ -81,12 +81,12 @@ void isSameMember1() { @DisplayName("같은 멤버 목록을 가지고 있는지 비교한다.") @Test void isSameMember2() { - Member member1 = new Member(1L, EVENT1, "감자", false); - Member member2 = new Member(2L, EVENT1, "고구마", false); - Member member3 = new Member(3L, EVENT1, "당근", false); + EventMember eventMember1 = new EventMember(1L, EVENT1, "감자", false); + EventMember eventMember2 = new EventMember(2L, EVENT1, "고구마", false); + EventMember eventMember3 = new EventMember(3L, EVENT1, "당근", false); - List members1 = List.of(member1, member2, member3); - List members2 = List.of(member2, member1); + List members1 = List.of(eventMember1, eventMember2, eventMember3); + List members2 = List.of(eventMember2, eventMember1); Bill bill1 = Bill.create(EVENT1, "뽕족", 20_000L, members1); Bill bill2 = Bill.create(EVENT1, "인생네컷", 30_000L, members2); diff --git a/server/src/test/java/server/haengdong/domain/eventmember/EventMemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/eventmember/EventMemberBillReportTest.java new file mode 100644 index 000000000..6d9eef909 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/eventmember/EventMemberBillReportTest.java @@ -0,0 +1,42 @@ +package server.haengdong.domain.eventmember; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.bill.Bill; +import server.haengdong.domain.event.Event; +import server.haengdong.domain.bill.MemberBillReport; +import server.haengdong.support.fixture.Fixture; + +class EventMemberBillReportTest { + + @DisplayName("지출 목록으로 참가자 정산 리포트를 생성한다.") + @Test + void createByBills() { + Event event = Fixture.EVENT1; + EventMember eventMember1 = new EventMember(1L, event, "소하", false); + EventMember eventMember2 = new EventMember(2L, event, "감자", false); + EventMember eventMember3 = new EventMember(3L, event, "쿠키", false); + EventMember eventMember4 = new EventMember(4L, event, "고구마", false); + List eventMembers = List.of(eventMember1, eventMember2, eventMember3, eventMember4); + List bills = List.of( + Bill.create(event, "뽕족", 60_000L, eventMembers), + Bill.create(event, "인생네컷", 20_000L, eventMembers) + ); + + MemberBillReport memberBillReport = MemberBillReport.createByBills(bills); + + assertThat(memberBillReport.getReports()) + .containsAllEntriesOf( + Map.of( + eventMember1, 20_000L, + eventMember2, 20_000L, + eventMember3, 20_000L, + eventMember4, 20_000L + ) + ); + } +} diff --git a/server/src/test/java/server/haengdong/domain/eventmember/UpdatedMembersTest.java b/server/src/test/java/server/haengdong/domain/eventmember/UpdatedMembersTest.java new file mode 100644 index 000000000..35cfc5f92 --- /dev/null +++ b/server/src/test/java/server/haengdong/domain/eventmember/UpdatedMembersTest.java @@ -0,0 +1,121 @@ +package server.haengdong.domain.eventmember; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import server.haengdong.domain.event.Event; +import server.haengdong.exception.HaengdongException; + +class UpdatedMembersTest { + + @DisplayName("이벤트 이름들은 중복될 수 없다.") + @Test + void validateNameUnique() { + Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); + List eventMembers = List.of( + new EventMember(1L, event, "고구마", false), + new EventMember(2L, event, "감자", false), + new EventMember(3L, event, "감자", false) + ); + + assertThatThrownBy(() -> new UpdatedMembers(eventMembers)) + .isInstanceOf(HaengdongException.class) + .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); + } + + @DisplayName("이벤트 회원들은 중복될 수 없다.") + @Test + void validateMemberUnique() { + Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); + EventMember eventMember1 = new EventMember(1L, event, "고구마", false); + EventMember eventMember2 = new EventMember(2L, event, "감자", false); + List eventMembers = List.of(eventMember1, eventMember2, eventMember2); + + + assertThatThrownBy(() -> new UpdatedMembers(eventMembers)) + .isInstanceOf(HaengdongException.class) + .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); + } + + @DisplayName("이벤트 이름들로 이벤트 참여자들을 생성한다.") + @Test + void create() { + Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); + EventMember eventMember1 = new EventMember(1L, event, "고구마", false); + EventMember eventMember2 = new EventMember(2L, event, "감자", false); + EventMember eventMember3 = new EventMember(3L, event, "당근", false); + List eventMembers = List.of(eventMember1, eventMember2, eventMember3); + + UpdatedMembers eventUpdatedMembers = new UpdatedMembers(eventMembers); + assertThat(eventUpdatedMembers.getMembers()).hasSize(3) + .containsExactlyInAnyOrder(eventMember1, eventMember2, eventMember3); + } + + @DisplayName("이벤트의 참여자들 전체가 존재하지 않으면 업데이트할 수 없다.") + @Test + void validateUpdatedMembersExist() { + Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); + EventMember eventMember1 = new EventMember(1L, event, "고구마", false); + EventMember eventMember2 = new EventMember(2L, event, "감자", false); + EventMember eventMember3 = new EventMember(3L, event, "당근", false); + EventMember eventMember4 = new EventMember(4L, event, "양파", false); + List eventMembers = List.of(eventMember1, eventMember2, eventMember3, eventMember4); + + EventMember updateEventMember1 = new EventMember(1L, event, "토다리", false); + EventMember updateEventMember2 = new EventMember(2L, event, "쿠키", false); + EventMember updateEventMember3 = new EventMember(3L, event, "백호", false); + UpdatedMembers updatedMembers = new UpdatedMembers(List.of( + updateEventMember1, updateEventMember2, updateEventMember3)); + + assertThatThrownBy(() -> updatedMembers.validateUpdatable(eventMembers)) + .isInstanceOf(HaengdongException.class) + .hasMessage("업데이트 요청된 참여자 ID 목록과 기존 행사 참여자 ID 목록이 일치하지 않습니다."); + } + + @DisplayName("업데이트할 이름 중에 기존 이벤트의 참여자들의 이름과 중복되면 업데이트할 수 없다.") + @Test + void validateUpdatedNamesUnique() { + Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); + EventMember eventMember1 = new EventMember(1L, event, "고구마", false); + EventMember eventMember2 = new EventMember(2L, event, "감자", false); + EventMember eventMember3 = new EventMember(3L, event, "당근", false); + EventMember eventMember4 = new EventMember(4L, event, "양파", false); + List eventMembers = List.of(eventMember1, eventMember2, eventMember3, eventMember4); + + EventMember updateEventMember1 = new EventMember(1L, event, "토다리", false); + EventMember updateEventMember2 = new EventMember(2L, event, "쿠키", false); + EventMember updateEventMember3 = new EventMember(3L, event, "백호", false); + EventMember updateEventMember4 = new EventMember(4L, event, "감자", false); + UpdatedMembers updatedMembers = new UpdatedMembers(List.of( + updateEventMember1, updateEventMember2, updateEventMember3, updateEventMember4)); + + assertThatThrownBy(() -> updatedMembers.validateUpdatable(eventMembers)) + .isInstanceOf(HaengdongException.class) + .hasMessage("행사에 중복된 참여자 이름이 존재합니다."); + } + + @DisplayName("이벤트의 참여자들 전체를 업데이트 검증한다.") + @Test + void validateUpdatable() { + Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); + EventMember eventMember1 = new EventMember(1L, event, "고구마", false); + EventMember eventMember2 = new EventMember(2L, event, "감자", false); + EventMember eventMember3 = new EventMember(3L, event, "당근", false); + EventMember eventMember4 = new EventMember(4L, event, "양파", false); + List eventMembers = List.of(eventMember1, eventMember2, eventMember3, eventMember4); + + EventMember updateEventMember1 = new EventMember(1L, event, "토다리", false); + EventMember updateEventMember2 = new EventMember(2L, event, "쿠키", false); + EventMember updateEventMember3 = new EventMember(3L, event, "백호", false); + EventMember updateEventMember4 = new EventMember(4L, event, "망쵸", false); + UpdatedMembers updatedMembers = new UpdatedMembers(List.of( + updateEventMember1, updateEventMember2, updateEventMember3, updateEventMember4)); + + assertThatCode(() -> updatedMembers.validateUpdatable(eventMembers)) + .doesNotThrowAnyException(); + } +} diff --git a/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java b/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java deleted file mode 100644 index 187d117f7..000000000 --- a/server/src/test/java/server/haengdong/domain/member/MemberBillReportTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package server.haengdong.domain.member; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.List; -import java.util.Map; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.event.Event; -import server.haengdong.domain.bill.MemberBillReport; -import server.haengdong.support.fixture.Fixture; - -class MemberBillReportTest { - - @DisplayName("지출 목록으로 참가자 정산 리포트를 생성한다.") - @Test - void createByBills() { - Event event = Fixture.EVENT1; - Member member1 = new Member(1L, event, "소하", false); - Member member2 = new Member(2L, event, "감자", false); - Member member3 = new Member(3L, event, "쿠키", false); - Member member4 = new Member(4L, event, "고구마", false); - List members = List.of(member1, member2, member3, member4); - List bills = List.of( - Bill.create(event, "뽕족", 60_000L, members), - Bill.create(event, "인생네컷", 20_000L, members) - ); - - MemberBillReport memberBillReport = MemberBillReport.createByBills(bills); - - assertThat(memberBillReport.getReports()) - .containsAllEntriesOf( - Map.of( - member1, 20_000L, - member2, 20_000L, - member3, 20_000L, - member4, 20_000L - ) - ); - } -} diff --git a/server/src/test/java/server/haengdong/domain/member/UpdatedMembersTest.java b/server/src/test/java/server/haengdong/domain/member/UpdatedMembersTest.java deleted file mode 100644 index 9f0338ffb..000000000 --- a/server/src/test/java/server/haengdong/domain/member/UpdatedMembersTest.java +++ /dev/null @@ -1,118 +0,0 @@ -package server.haengdong.domain.member; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.List; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import server.haengdong.domain.event.Event; -import server.haengdong.exception.HaengdongException; - -class UpdatedMembersTest { - - @DisplayName("이벤트 이름들은 중복될 수 없다.") - @Test - void validateNameUnique() { - Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); - List members = List.of( - new Member(1L, event, "고구마", false), - new Member(2L, event, "감자", false), - new Member(3L, event, "감자", false) - ); - - assertThatThrownBy(() -> new UpdatedMembers(members)) - .isInstanceOf(HaengdongException.class) - .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); - } - - @DisplayName("이벤트 회원들은 중복될 수 없다.") - @Test - void validateMemberUnique() { - Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); - Member member1 = new Member(1L, event, "고구마", false); - Member member2 = new Member(2L, event, "감자", false); - List members = List.of(member1, member2, member2); - - - assertThatThrownBy(() -> new UpdatedMembers(members)) - .isInstanceOf(HaengdongException.class) - .hasMessage("중복된 참여 인원 이름 변경 요청이 존재합니다."); - } - - @DisplayName("이벤트 이름들로 이벤트 참여자들을 생성한다.") - @Test - void create() { - Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); - Member member1 = new Member(1L, event, "고구마", false); - Member member2 = new Member(2L, event, "감자", false); - Member member3 = new Member(3L, event, "당근", false); - List members = List.of(member1, member2, member3); - - UpdatedMembers eventUpdatedMembers = new UpdatedMembers(members); - assertThat(eventUpdatedMembers.getMembers()).hasSize(3) - .containsExactlyInAnyOrder(member1, member2, member3); - } - - @DisplayName("이벤트의 참여자들 전체가 존재하지 않으면 업데이트할 수 없다.") - @Test - void validateUpdatedMembersExist() { - Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); - Member member1 = new Member(1L, event, "고구마", false); - Member member2 = new Member(2L, event, "감자", false); - Member member3 = new Member(3L, event, "당근", false); - Member member4 = new Member(4L, event, "양파", false); - List members = List.of(member1, member2, member3, member4); - - Member updateMember1 = new Member(1L, event, "토다리", false); - Member updateMember2 = new Member(2L, event, "쿠키", false); - Member updateMember3 = new Member(3L, event, "백호", false); - UpdatedMembers updatedMembers = new UpdatedMembers(List.of(updateMember1, updateMember2, updateMember3)); - - assertThatThrownBy(() -> updatedMembers.validateUpdatable(members)) - .isInstanceOf(HaengdongException.class) - .hasMessage("업데이트 요청된 참여자 ID 목록과 기존 행사 참여자 ID 목록이 일치하지 않습니다."); - } - - @DisplayName("업데이트할 이름 중에 기존 이벤트의 참여자들의 이름과 중복되면 업데이트할 수 없다.") - @Test - void validateUpdatedNamesUnique() { - Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); - Member member1 = new Member(1L, event, "고구마", false); - Member member2 = new Member(2L, event, "감자", false); - Member member3 = new Member(3L, event, "당근", false); - Member member4 = new Member(4L, event, "양파", false); - List members = List.of(member1, member2, member3, member4); - - Member updateMember1 = new Member(1L, event, "토다리", false); - Member updateMember2 = new Member(2L, event, "쿠키", false); - Member updateMember3 = new Member(3L, event, "백호", false); - Member updateMember4 = new Member(4L, event, "감자", false); - UpdatedMembers updatedMembers = new UpdatedMembers(List.of(updateMember1, updateMember2, updateMember3, updateMember4)); - - assertThatThrownBy(() -> updatedMembers.validateUpdatable(members)) - .isInstanceOf(HaengdongException.class) - .hasMessage("행사에 중복된 참여자 이름이 존재합니다."); - } - - @DisplayName("이벤트의 참여자들 전체를 업데이트 검증한다.") - @Test - void validateUpdatable() { - Event event = new Event("행동대장 회식", "1234", "1231415jaksdf"); - Member member1 = new Member(1L, event, "고구마", false); - Member member2 = new Member(2L, event, "감자", false); - Member member3 = new Member(3L, event, "당근", false); - Member member4 = new Member(4L, event, "양파", false); - List members = List.of(member1, member2, member3, member4); - - Member updateMember1 = new Member(1L, event, "토다리", false); - Member updateMember2 = new Member(2L, event, "쿠키", false); - Member updateMember3 = new Member(3L, event, "백호", false); - Member updateMember4 = new Member(4L, event, "망쵸", false); - UpdatedMembers updatedMembers = new UpdatedMembers(List.of(updateMember1, updateMember2, updateMember3, updateMember4)); - - assertThatCode(() -> updatedMembers.validateUpdatable(members)) - .doesNotThrowAnyException(); - } -} diff --git a/server/src/test/java/server/haengdong/domain/step/StepTest.java b/server/src/test/java/server/haengdong/domain/step/StepTest.java index 5c5631840..53421d511 100644 --- a/server/src/test/java/server/haengdong/domain/step/StepTest.java +++ b/server/src/test/java/server/haengdong/domain/step/StepTest.java @@ -8,7 +8,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; import server.haengdong.exception.HaengdongException; class StepTest { @@ -16,14 +16,14 @@ class StepTest { @DisplayName("회원 구성이 같은 지출은 Step에 추가될 수 있다.") @Test void add1() { - Member member1 = new Member(1L, EVENT1, "감자", false); - Member member2 = new Member(2L, EVENT1, "고구마", false); - Member member3 = new Member(3L, EVENT1, "당근", false); - Member member4 = new Member(4L, EVENT1, "양파", false); - Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(member1, member2, member3, member4)); + EventMember eventMember1 = new EventMember(1L, EVENT1, "감자", false); + EventMember eventMember2 = new EventMember(2L, EVENT1, "고구마", false); + EventMember eventMember3 = new EventMember(3L, EVENT1, "당근", false); + EventMember eventMember4 = new EventMember(4L, EVENT1, "양파", false); + Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(eventMember1, eventMember2, eventMember3, eventMember4)); Step step = Step.of(bill1); - Bill bill2 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(member2, member3, member1, member4)); + Bill bill2 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(eventMember2, eventMember3, eventMember1, eventMember4)); step.add(bill2); @@ -35,14 +35,14 @@ void add1() { @DisplayName("회원 구성이 댜른 지출은 Step에 추가될 수 없다.") @Test void add2() { - Member member1 = new Member(1L, EVENT1, "감자", false); - Member member2 = new Member(2L, EVENT1, "고구마", false); - Member member3 = new Member(3L, EVENT1, "당근", false); - Member member4 = new Member(4L, EVENT1, "양파", false); - Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(member1, member2, member3, member4)); + EventMember eventMember1 = new EventMember(1L, EVENT1, "감자", false); + EventMember eventMember2 = new EventMember(2L, EVENT1, "고구마", false); + EventMember eventMember3 = new EventMember(3L, EVENT1, "당근", false); + EventMember eventMember4 = new EventMember(4L, EVENT1, "양파", false); + Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(eventMember1, eventMember2, eventMember3, eventMember4)); Step step = Step.of(bill1); - Bill bill2 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(member2, member3, member1)); + Bill bill2 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(eventMember2, eventMember3, eventMember1)); assertThatThrownBy(() -> step.add(bill2)) .isInstanceOf(HaengdongException.class); diff --git a/server/src/test/java/server/haengdong/domain/step/StepsTest.java b/server/src/test/java/server/haengdong/domain/step/StepsTest.java index 799cb0d4c..e0b3df857 100644 --- a/server/src/test/java/server/haengdong/domain/step/StepsTest.java +++ b/server/src/test/java/server/haengdong/domain/step/StepsTest.java @@ -8,22 +8,22 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; class StepsTest { @DisplayName("지출 목록 순으로 같은 회원 구성인 경우 같은 Step으로 묶는다.") @Test void of() { - Member member1 = new Member(1L, EVENT1, "감자", false); - Member member2 = new Member(2L, EVENT1, "고구마", false); - Member member3 = new Member(3L, EVENT1, "당근", false); - Member member4 = new Member(4L, EVENT1, "양파", false); - Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(member1, member2)); - Bill bill2 = Bill.create(EVENT1, "용용선생", 20_000L, List.of(member2, member1)); - Bill bill3 = Bill.create(EVENT1, "보승회관", 30_000L, List.of(member1, member2, member3)); - Bill bill4 = Bill.create(EVENT1, "감자", 40_000L, List.of(member1, member2, member3, member4)); - Bill bill5 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(member2, member3, member1, member4)); + EventMember eventMember1 = new EventMember(1L, EVENT1, "감자", false); + EventMember eventMember2 = new EventMember(2L, EVENT1, "고구마", false); + EventMember eventMember3 = new EventMember(3L, EVENT1, "당근", false); + EventMember eventMember4 = new EventMember(4L, EVENT1, "양파", false); + Bill bill1 = Bill.create(EVENT1, "뽕족", 10_000L, List.of(eventMember1, eventMember2)); + Bill bill2 = Bill.create(EVENT1, "용용선생", 20_000L, List.of(eventMember2, eventMember1)); + Bill bill3 = Bill.create(EVENT1, "보승회관", 30_000L, List.of(eventMember1, eventMember2, eventMember3)); + Bill bill4 = Bill.create(EVENT1, "감자", 40_000L, List.of(eventMember1, eventMember2, eventMember3, eventMember4)); + Bill bill5 = Bill.create(EVENT1, "인생네컷", 5_000L, List.of(eventMember2, eventMember3, eventMember1, eventMember4)); List bills = List.of(bill1, bill2, bill3, bill4, bill5); Steps step = Steps.of(bills); @@ -34,15 +34,15 @@ void of() { () -> assertThat(steps.get(0).getBills()).hasSize(2) .containsExactly(bill1, bill2), () -> assertThat(steps.get(0).getMembers()).hasSize(2) - .containsExactly(member1, member2), + .containsExactly(eventMember1, eventMember2), () -> assertThat(steps.get(1).getBills()).hasSize(1) .containsExactly(bill3), () -> assertThat(steps.get(1).getMembers()).hasSize(3) - .containsExactly(member1, member2, member3), + .containsExactly(eventMember1, eventMember2, eventMember3), () -> assertThat(steps.get(2).getBills()).hasSize(2) .containsExactly(bill4, bill5), () -> assertThat(steps.get(2).getMembers()).hasSize(4) - .containsExactly(member1, member2, member3, member4) + .containsExactly(eventMember1, eventMember2, eventMember3, eventMember4) ); } } diff --git a/server/src/test/java/server/haengdong/presentation/BillControllerTest.java b/server/src/test/java/server/haengdong/presentation/BillControllerTest.java index b6658d7b6..8bf5539d7 100644 --- a/server/src/test/java/server/haengdong/presentation/BillControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/BillControllerTest.java @@ -17,7 +17,7 @@ import server.haengdong.application.response.MemberAppResponse; import server.haengdong.application.response.StepAppResponse; import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; import server.haengdong.support.fixture.Fixture; class BillControllerTest extends ControllerTestSupport { @@ -28,8 +28,8 @@ void findBills() throws Exception { Bill bill = Fixture.BILL1; List bills = List.of(BillAppResponse.of(bill)); - Member member = Fixture.MEMBER1; - List members = List.of(MemberAppResponse.of(member)); + EventMember eventMember = Fixture.EVENT_MEMBER_1; + List members = List.of(MemberAppResponse.of(eventMember)); StepAppResponse stepAppResponse = new StepAppResponse(bills, members); given(billService.findSteps(anyString())).willReturn(List.of(stepAppResponse)); @@ -44,8 +44,8 @@ void findBills() throws Exception { .andExpect(jsonPath("$.steps[0].bills[0].price").value(bill.getPrice())) .andExpect(jsonPath("$.steps[0].bills[0].isFixed").value(bill.isFixed())) .andExpect(jsonPath("$.steps[0].members").isArray()) - .andExpect(jsonPath("$.steps[0].members[0].id").value(member.getId())) - .andExpect(jsonPath("$.steps[0].members[0].name").value(member.getName())); + .andExpect(jsonPath("$.steps[0].members[0].id").value(eventMember.getId())) + .andExpect(jsonPath("$.steps[0].members[0].name").value(eventMember.getName())); } @DisplayName("참여자별 지출 금액을 조회한다.") diff --git a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java index 3d7763ee0..c215715f4 100644 --- a/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java +++ b/server/src/test/java/server/haengdong/presentation/ControllerTestSupport.java @@ -12,8 +12,8 @@ import server.haengdong.application.BillService; import server.haengdong.application.EventImageFacadeService; import server.haengdong.application.EventService; -import server.haengdong.application.ImageService; -import server.haengdong.application.MemberService; +import server.haengdong.application.EventMemberService; +import server.haengdong.application.UserService; import server.haengdong.presentation.admin.AdminBillController; import server.haengdong.presentation.admin.AdminEventController; import server.haengdong.presentation.admin.AdminMemberController; @@ -24,7 +24,7 @@ AdminBillController.class, AdminMemberController.class, EventController.class, - MemberController.class, + EventMemberController.class, BillController.class }, excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {WebMvcConfigurer.class})} @@ -44,11 +44,14 @@ public abstract class ControllerTestSupport { protected AuthService authService; @MockBean - protected MemberService memberService; + protected EventMemberService eventMemberService; @MockBean protected BillService billService; @MockBean protected EventImageFacadeService eventImageFacadeService; + + @MockBean + protected UserService userService; } diff --git a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java index 90e7fd618..f7a471f38 100644 --- a/server/src/test/java/server/haengdong/presentation/EventControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventControllerTest.java @@ -16,13 +16,12 @@ import org.springframework.http.MediaType; import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import server.haengdong.application.request.EventAppRequest; +import server.haengdong.application.request.EventGuestAppRequest; import server.haengdong.application.response.EventAppResponse; import server.haengdong.application.response.EventDetailAppResponse; import server.haengdong.application.response.EventImageAppResponse; import server.haengdong.application.response.MemberBillReportAppResponse; -import server.haengdong.presentation.request.EventLoginRequest; -import server.haengdong.presentation.request.EventSaveRequest; +import server.haengdong.presentation.request.EventGuestSaveRequest; class EventControllerTest extends ControllerTestSupport { @@ -66,41 +65,24 @@ void getMemberBillReports() throws Exception { @DisplayName("이벤트를 생성한다.") @Test - void saveEvent() throws Exception { - EventSaveRequest eventSaveRequest = new EventSaveRequest("토다리", "0987"); + void saveEventGuest() throws Exception { + EventGuestSaveRequest eventSaveRequest = new EventGuestSaveRequest("토다리", "nick", "0987"); String requestBody = objectMapper.writeValueAsString(eventSaveRequest); String eventId = "망쵸토큰"; - EventAppResponse eventAppResponse = new EventAppResponse(eventId); - given(eventService.saveEvent(any(EventAppRequest.class))).willReturn(eventAppResponse); - given(authService.createToken(eventId)).willReturn("jwtToken"); - given(authService.getTokenName()).willReturn("eventToken"); + EventAppResponse eventAppResponse = new EventAppResponse(eventId, 1L); + given(eventService.saveEventGuest(any(EventGuestAppRequest.class))).willReturn(eventAppResponse); + given(authService.createGuestToken(1L)).willReturn("jwtToken"); + given(authService.getTokenName()).willReturn("accessToken"); - mockMvc.perform(post("/api/events") + mockMvc.perform(post("/api/events/guest") .contentType(MediaType.APPLICATION_JSON) .content(requestBody)) .andDo(print()) .andExpect(status().isOk()) - .andExpect(cookie().value("eventToken", "jwtToken")) + .andExpect(cookie().value("accessToken", "jwtToken")) .andExpect(jsonPath("$.eventId").value("망쵸토큰")); } - @DisplayName("행사 어드민이 로그인한다.") - @Test - void loginEvent() throws Exception { - String token = "TOKEN"; - EventLoginRequest eventLoginRequest = new EventLoginRequest("1234"); - String requestBody = objectMapper.writeValueAsString(eventLoginRequest); - given(authService.createToken(token)).willReturn("jwtToken"); - given(authService.getTokenName()).willReturn("eventToken"); - - mockMvc.perform(post("/api/events/{eventId}/login", token) - .contentType(MediaType.APPLICATION_JSON) - .content(requestBody)) - .andDo(print()) - .andExpect(cookie().value("eventToken", "jwtToken")) - .andExpect(status().isOk()); - } - @DisplayName("행사 이미지를 조회한다.") @Test void findAllImages() throws Exception { diff --git a/server/src/test/java/server/haengdong/presentation/MemberControllerTest.java b/server/src/test/java/server/haengdong/presentation/EventEventMemberControllerTest.java similarity index 50% rename from server/src/test/java/server/haengdong/presentation/MemberControllerTest.java rename to server/src/test/java/server/haengdong/presentation/EventEventMemberControllerTest.java index ff824831b..89bda729c 100644 --- a/server/src/test/java/server/haengdong/presentation/MemberControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/EventEventMemberControllerTest.java @@ -7,9 +7,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static server.haengdong.support.fixture.Fixture.MEMBER1; -import static server.haengdong.support.fixture.Fixture.MEMBER2; -import static server.haengdong.support.fixture.Fixture.MEMBER3; +import static server.haengdong.support.fixture.Fixture.EVENT_MEMBER_1; +import static server.haengdong.support.fixture.Fixture.EVENT_MEMBER_2; +import static server.haengdong.support.fixture.Fixture.EVENT_MEMBER_3; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -18,60 +18,60 @@ import server.haengdong.application.response.MemberAppResponse; import server.haengdong.application.response.MemberDepositAppResponse; import server.haengdong.application.response.MembersDepositAppResponse; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; -class MemberControllerTest extends ControllerTestSupport { +class EventEventMemberControllerTest extends ControllerTestSupport { @DisplayName("행사에 참여한 전체 인원을 조회한다.") @Test void findAllMembersTest() throws Exception { - Member member1 = MEMBER1; - Member member2 = MEMBER2; - Member member3 = MEMBER3; + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; + EventMember eventMember3 = EVENT_MEMBER_3; List members = List.of( - MemberDepositAppResponse.of(member1), - MemberDepositAppResponse.of(member2), - MemberDepositAppResponse.of(member3) + MemberDepositAppResponse.of(eventMember1), + MemberDepositAppResponse.of(eventMember2), + MemberDepositAppResponse.of(eventMember3) ); MembersDepositAppResponse memberAppResponse = new MembersDepositAppResponse(members); - given(memberService.findAllMembers(anyString())).willReturn(memberAppResponse); + given(eventMemberService.findAllMembers(anyString())).willReturn(memberAppResponse); mockMvc.perform(get("/api/events/{eventId}/members", "TOKEN")) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.members").isArray()) - .andExpect(jsonPath("$.members[0].id").value(member1.getId())) - .andExpect(jsonPath("$.members[0].name").value(member1.getName())) - .andExpect(jsonPath("$.members[0].isDeposited").value(member1.isDeposited())) - .andExpect(jsonPath("$.members[1].id").value(member2.getId())) - .andExpect(jsonPath("$.members[1].name").value(member2.getName())) - .andExpect(jsonPath("$.members[1].isDeposited").value(member2.isDeposited())) - .andExpect(jsonPath("$.members[2].id").value(member3.getId())) - .andExpect(jsonPath("$.members[2].name").value(member3.getName())) - .andExpect(jsonPath("$.members[2].isDeposited").value(member3.isDeposited())); + .andExpect(jsonPath("$.members[0].id").value(eventMember1.getId())) + .andExpect(jsonPath("$.members[0].name").value(eventMember1.getName())) + .andExpect(jsonPath("$.members[0].isDeposited").value(eventMember1.isDeposited())) + .andExpect(jsonPath("$.members[1].id").value(eventMember2.getId())) + .andExpect(jsonPath("$.members[1].name").value(eventMember2.getName())) + .andExpect(jsonPath("$.members[1].isDeposited").value(eventMember2.isDeposited())) + .andExpect(jsonPath("$.members[2].id").value(eventMember3.getId())) + .andExpect(jsonPath("$.members[2].name").value(eventMember3.getName())) + .andExpect(jsonPath("$.members[2].isDeposited").value(eventMember3.isDeposited())); } @DisplayName("현재 참여 인원을 조회합니다.") @Test void getCurrentMembers() throws Exception { - Member member1 = MEMBER1; - Member member2 = MEMBER2; + EventMember eventMember1 = EVENT_MEMBER_1; + EventMember eventMember2 = EVENT_MEMBER_2; List members = List.of( - MemberAppResponse.of(member1), - MemberAppResponse.of(member2) + MemberAppResponse.of(eventMember1), + MemberAppResponse.of(eventMember2) ); - given(memberService.getCurrentMembers(any())).willReturn(members); + given(eventMemberService.getCurrentMembers(any())).willReturn(members); mockMvc.perform(get("/api/events/{eventId}/members/current", "TOKEN") .accept(MediaType.APPLICATION_JSON)) .andDo(print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.members").isArray()) - .andExpect(jsonPath("$.members[0].id").value(member1.getId())) - .andExpect(jsonPath("$.members[0].name").value(member1.getName())) - .andExpect(jsonPath("$.members[1].id").value(member2.getId())) - .andExpect(jsonPath("$.members[1].name").value(member2.getName())); + .andExpect(jsonPath("$.members[0].id").value(eventMember1.getId())) + .andExpect(jsonPath("$.members[0].name").value(eventMember1.getName())) + .andExpect(jsonPath("$.members[1].id").value(eventMember2.getId())) + .andExpect(jsonPath("$.members[1].name").value(eventMember2.getName())); } } diff --git a/server/src/test/java/server/haengdong/presentation/admin/AdminMemberControllerTest.java b/server/src/test/java/server/haengdong/presentation/admin/AdminEventEventMemberControllerTest.java similarity index 96% rename from server/src/test/java/server/haengdong/presentation/admin/AdminMemberControllerTest.java rename to server/src/test/java/server/haengdong/presentation/admin/AdminEventEventMemberControllerTest.java index 6afb013f9..f00dd6059 100644 --- a/server/src/test/java/server/haengdong/presentation/admin/AdminMemberControllerTest.java +++ b/server/src/test/java/server/haengdong/presentation/admin/AdminEventEventMemberControllerTest.java @@ -22,7 +22,7 @@ import server.haengdong.presentation.request.MembersSaveRequest; import server.haengdong.presentation.request.MembersUpdateRequest; -class AdminMemberControllerTest extends ControllerTestSupport { +class AdminEventEventMemberControllerTest extends ControllerTestSupport { @DisplayName("행사 참여자를 추가한다.") @Test @@ -41,7 +41,7 @@ void saveMemberTest() throws Exception { new MemberSaveAppResponse(2L, "소하") ) ); - given(memberService.saveMembers(eventToken, membersSaveRequest.toAppRequest())) + given(eventMemberService.saveMembers(eventToken, membersSaveRequest.toAppRequest())) .willReturn(appResponse); mockMvc.perform(post("/api/admin/events/{eventId}/members", "망쵸토큰") diff --git a/server/src/test/java/server/haengdong/support/fixture/Fixture.java b/server/src/test/java/server/haengdong/support/fixture/Fixture.java index e05b43c23..0bb7ea555 100644 --- a/server/src/test/java/server/haengdong/support/fixture/Fixture.java +++ b/server/src/test/java/server/haengdong/support/fixture/Fixture.java @@ -2,17 +2,17 @@ import jakarta.servlet.http.Cookie; import server.haengdong.domain.bill.Bill; -import server.haengdong.domain.member.Member; +import server.haengdong.domain.eventmember.EventMember; import server.haengdong.domain.event.Event; public class Fixture { public static final Event EVENT1 = new Event("쿠키", "1234", "TOKEN1"); public static final Event EVENT2 = new Event("웨디", "1234", "TOKEN2"); - public static final Cookie EVENT_COOKIE = new Cookie("eventToken", "토큰토큰"); - public static final Member MEMBER1 = new Member(EVENT1, "토다리"); - public static final Member MEMBER2 = new Member(EVENT1, "쿠키"); - public static final Member MEMBER3 = new Member(EVENT1, "소하"); + public static final Cookie EVENT_COOKIE = new Cookie("accessToken", "토큰토큰"); + public static final EventMember EVENT_MEMBER_1 = new EventMember(EVENT1, "토다리"); + public static final EventMember EVENT_MEMBER_2 = new EventMember(EVENT1, "쿠키"); + public static final EventMember EVENT_MEMBER_3 = new EventMember(EVENT1, "소하"); public static final Bill BILL1 = new Bill(EVENT1, "행동대장 회식", 10000L); public static final Bill BILL2 = new Bill(EVENT2, "행동대장 회식2", 20000L); }