-
Notifications
You must be signed in to change notification settings - Fork 0
예약 관련 API 구현 #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
예약 관련 API 구현 #13
Changes from 77 commits
d871d1e
4ded58a
ee9414b
5b9ae36
2b69792
e3bdeff
9b6dadc
f4445f7
32fccd2
23facd4
48f1163
c486189
b93c7e5
b74ba19
1b9d997
e3f8058
0547ba4
11b459f
b6112ce
da45910
f009fff
fa08218
da518e9
b0595cd
c899c9e
90eef65
7d9197a
7a67585
7f68719
c5f7ff8
42677f6
df17223
376a2dd
9f15d49
1244937
2d8fbd1
2e8bca6
57a6005
7ccd125
e874dd5
d718797
15b664e
db185b1
9277295
fe23637
68642b0
db72ca2
45dea30
3bb7f85
2f21141
abc7887
4004d58
8d1ba97
2908844
91d1883
ee899a5
1fefa79
890503d
17924bf
3722765
d801fb8
d9afdba
b2f87ca
e6ef27a
11a4732
1f49f8c
73601f3
270c3c0
14c9560
4758692
43d4533
4351345
b5265f6
d0550f9
8afd3ad
cf4a344
3ec3ae5
514d708
aa7dbff
d5dcdd8
4ec7711
521775c
1164ef3
db80837
f5be9c2
95b0ec7
8ff4892
6d8e231
65383e2
8ae38b9
a70d313
74f1d19
c0bff35
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,10 @@ | ||
| package com.ampersand.groom.domain.auth.application.service; | ||
|
|
||
| import com.ampersand.groom.domain.auth.application.port.AuthPort; | ||
| import com.ampersand.groom.domain.auth.expection.*; | ||
| import com.ampersand.groom.domain.auth.domain.JwtToken; | ||
| import com.ampersand.groom.domain.auth.expection.*; | ||
| import com.ampersand.groom.domain.auth.presentation.data.request.SignupRequest; | ||
| import com.ampersand.groom.domain.member.domain.constant.MemberRole; | ||
| import com.ampersand.groom.domain.member.persistence.entity.MemberJpaEntity; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.beans.factory.annotation.Value; | ||
|
|
@@ -29,18 +30,18 @@ public class AuthService { | |
| public JwtToken signIn(String email, String password) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 로그인이라는 메서드 내에서 로직이 너무 많은 책임을 가지고있음. 비밀번호, 유저 접근 권한, 토큰 생성등 다양한 기능들은 코드만 보고는 읽기가 어려워보임. private으로 몇군데 분리를 시켜놓고 도메인 행위가 잘 나타났으면 좋겠음
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| MemberJpaEntity user = authPort.findMembersByCriteria(email) | ||
| .orElseThrow(()->new UserNotFoundException()); | ||
| .orElseThrow(() -> new UserNotFoundException()); | ||
|
|
||
| if(!user.getIsAvailable()) { | ||
| if (!user.getIsAvailable()) { | ||
| throw new UserForbiddenException(); | ||
| } | ||
|
|
||
| if (!passwordEncoder.matches(password, user.getPassword())) { | ||
| throw new PasswordInvalidException(); | ||
| } | ||
|
|
||
| String accessToken = jwtService.createAccessToken(email); | ||
| String refreshToken = jwtService.createRefreshToken(email); | ||
| String accessToken = jwtService.createAccessToken(email, user.getRole()); | ||
| String refreshToken = jwtService.createRefreshToken(email, user.getRole()); | ||
|
|
||
| return JwtToken.builder() | ||
| .accessToken(accessToken) | ||
|
|
@@ -67,10 +68,10 @@ public JwtToken refreshToken(String refreshToken) { | |
| } | ||
|
|
||
| MemberJpaEntity user = authPort.findMembersByCriteria(email) | ||
| .orElseThrow(()->new UserNotFoundException()); | ||
| .orElseThrow(() -> new UserNotFoundException()); | ||
|
|
||
| String newAccessToken = jwtService.createAccessToken(email); | ||
| String newRefreshToken = jwtService.createRefreshToken(email); | ||
| String newAccessToken = jwtService.createAccessToken(email, user.getRole()); | ||
| String newRefreshToken = jwtService.createRefreshToken(email, user.getRole()); | ||
|
|
||
| return JwtToken.builder() | ||
| .accessToken(newAccessToken) | ||
|
|
@@ -93,6 +94,7 @@ public void signup(SignupRequest request) { | |
| .password(passwordEncoder.encode(request.getPassword())) | ||
| .generation(1) | ||
| .isAvailable(true) | ||
| .role(MemberRole.ROLE_STUDENT) | ||
| .build(); | ||
|
|
||
| authPort.save(newUser); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package com.ampersand.groom.domain.booking.application; | ||
|
|
||
| import com.ampersand.groom.domain.booking.application.port.BookingApplicationPort; | ||
| import com.ampersand.groom.domain.booking.application.usecase.*; | ||
| import com.ampersand.groom.domain.booking.presentation.data.response.GetBookingResponse; | ||
| import com.ampersand.groom.domain.booking.presentation.data.response.GetPlaceResponse; | ||
| import com.ampersand.groom.global.annotation.adapter.Adapter; | ||
| import com.ampersand.groom.global.annotation.adapter.constant.AdapterType; | ||
| import lombok.RequiredArgsConstructor; | ||
|
|
||
| import java.time.LocalDate; | ||
| import java.util.List; | ||
|
|
||
| @Adapter(AdapterType.INBOUND) | ||
| @RequiredArgsConstructor | ||
| public class BookingApplicationAdapter implements BookingApplicationPort { | ||
|
|
||
| private final FindPlaceByBookingAvailabilityUseCase findPlaceByBookingAvailabilityUseCase; | ||
| private final FindBookingByDateAndTimeAndPlaceUseCase findBookingByDateAndTimeAndPlaceUseCase; | ||
| private final CreateBookingUseCase createBookingUseCase; | ||
| private final UpdateBookingUseCase updateBookingUseCase; | ||
| private final DeleteBookingUseCase deleteBookingUseCase; | ||
|
|
||
| @Override | ||
| public List<GetPlaceResponse> findPlaceByBookingAvailability(LocalDate date, String time, String placeType) { | ||
| return findPlaceByBookingAvailabilityUseCase.execute(date, time, placeType); | ||
| } | ||
|
|
||
| @Override | ||
| public List<GetBookingResponse> findBookingByDateAndTimeAndPlace(LocalDate date, String time, String place) { | ||
| return findBookingByDateAndTimeAndPlaceUseCase.execute(date, time, place); | ||
| } | ||
|
|
||
| @Override | ||
| public void createBooking(String time, String place, List<Long> participants) { | ||
| createBookingUseCase.execute(time, place, participants); | ||
| } | ||
|
|
||
| @Override | ||
| public void updateBooking(Long id, String time, String place, List<Long> participants) { | ||
| updateBookingUseCase.execute(id, time, place, participants); | ||
| } | ||
|
|
||
| @Override | ||
| public void deleteBooking(Long id) { | ||
| deleteBookingUseCase.execute(id); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package com.ampersand.groom.domain.booking.application.port; | ||
|
|
||
| import com.ampersand.groom.domain.booking.presentation.data.response.GetBookingResponse; | ||
| import com.ampersand.groom.domain.booking.presentation.data.response.GetPlaceResponse; | ||
|
|
||
| import java.time.LocalDate; | ||
| import java.util.List; | ||
|
|
||
| public interface BookingApplicationPort { | ||
| List<GetPlaceResponse> findPlaceByBookingAvailability(LocalDate date, String time, String placeType); | ||
|
|
||
| List<GetBookingResponse> findBookingByDateAndTimeAndPlace(LocalDate date, String time, String place); | ||
|
|
||
| void createBooking(String time, String place, List<Long> participants); | ||
|
|
||
| void updateBooking(Long id, String time, String place, List<Long> participants); | ||
|
|
||
| void deleteBooking(Long id); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package com.ampersand.groom.domain.booking.application.port; | ||
|
|
||
| import com.ampersand.groom.domain.booking.domain.Booking; | ||
| import com.ampersand.groom.domain.member.domain.Member; | ||
|
|
||
| import java.time.LocalDate; | ||
| import java.util.List; | ||
|
|
||
| public interface BookingPersistencePort { | ||
| List<Booking> findBookingByDateAndTimeAndPlace(LocalDate date, String time, String place); | ||
|
|
||
| Booking findBookingByIdWithLock(Long bookingId); | ||
|
|
||
| Boolean ExistsBookingByDateAndTimeAndPlace(LocalDate date, String time, String place); | ||
|
|
||
| void saveBooking(Booking booking); | ||
|
|
||
| void deleteBookingById(Long bookingId); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.ampersand.groom.domain.booking.application.port; | ||
|
|
||
| import com.ampersand.groom.domain.booking.domain.Place; | ||
|
|
||
| import java.time.LocalDate; | ||
| import java.util.List; | ||
|
|
||
| public interface PlacePersistencePort { | ||
| List<Place> findPlaceByBookingAvailability(LocalDate date, String time, String placeType); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package com.ampersand.groom.domain.booking.application.port; | ||
|
|
||
| import com.ampersand.groom.domain.booking.domain.TimeSlot; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public interface TimeSlotPersistencePort { | ||
| List<TimeSlot> findAllTimeSlots(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| package com.ampersand.groom.domain.booking.application.usecase; | ||
|
|
||
| import com.ampersand.groom.domain.booking.application.port.BookingPersistencePort; | ||
| import com.ampersand.groom.domain.booking.application.port.TimeSlotPersistencePort; | ||
| import com.ampersand.groom.domain.booking.domain.Booking; | ||
| import com.ampersand.groom.domain.booking.domain.TimeSlot; | ||
| import com.ampersand.groom.domain.booking.exception.DuplicateBookingException; | ||
| import com.ampersand.groom.domain.booking.exception.InvalidBookingParticipantsException; | ||
| import com.ampersand.groom.domain.booking.exception.InvalidBookingInfomationException; | ||
| import com.ampersand.groom.domain.booking.exception.MaxCapacityExceededException; | ||
| import com.ampersand.groom.domain.member.application.port.MemberPersistencePort; | ||
| import com.ampersand.groom.domain.member.domain.Member; | ||
| import com.ampersand.groom.global.annotation.usecase.UseCaseWithTransaction; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.security.core.context.SecurityContextHolder; | ||
|
|
||
| import java.time.LocalDate; | ||
| import java.util.*; | ||
|
|
||
| @UseCaseWithTransaction | ||
| @RequiredArgsConstructor | ||
| public class CreateBookingUseCase { | ||
|
|
||
| private final MemberPersistencePort memberPersistencePort; | ||
| private final BookingPersistencePort bookingPersistencePort; | ||
| private final TimeSlotPersistencePort timeSlotPersistencePort; | ||
|
|
||
| public void execute(String time, String place, List<Long> participants) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. time과 place에 대한 index를 생성해 타게하면 성능 향상
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| List<TimeSlot> availableTimeSlots = timeSlotPersistencePort.findAllTimeSlots(); | ||
| TimeSlot selectedTimeSlot = availableTimeSlots.stream() | ||
| .filter(timeSlot -> timeSlot.getPlace().getPlaceName().equals(place)) | ||
| .filter(timeSlot -> timeSlot.getTimeSlotId().timeLabel().equals(time)) | ||
| .findAny() | ||
| .orElseThrow(InvalidBookingInfomationException::new); | ||
| if(selectedTimeSlot.getPlace().getMaxCapacity() < participants.size() + 1) { | ||
| throw new MaxCapacityExceededException(); | ||
| } | ||
| bookingPersistencePort.findBookingByDateAndTimeAndPlace(LocalDate.now(), selectedTimeSlot.getTimeSlotId().timeLabel(), place) | ||
| .stream() | ||
| .findAny() | ||
| .ifPresent(booking -> { | ||
| throw new DuplicateBookingException(); | ||
| }); | ||
| List<Member> participantEntities = memberPersistencePort.findMembersByIds(participants); | ||
| String email = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString(); | ||
|
||
| Member president = memberPersistencePort.findMemberByEmail(email); | ||
| if (participantEntities.size() != participants.size() || | ||
| participantEntities.stream().anyMatch(member -> member.getId().equals(president.getId()))) { | ||
| throw new InvalidBookingParticipantsException(); | ||
| } | ||
| Booking newBooking = Booking.builder() | ||
| .bookingDate(LocalDate.now()) | ||
| .timeSlot(selectedTimeSlot) | ||
| .president(president) | ||
| .participants(participantEntities) | ||
| .build(); | ||
| bookingPersistencePort.saveBooking(newBooking); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package com.ampersand.groom.domain.booking.application.usecase; | ||
|
|
||
| import com.ampersand.groom.domain.booking.application.port.BookingPersistencePort; | ||
| import com.ampersand.groom.domain.booking.domain.Booking; | ||
| import com.ampersand.groom.domain.booking.exception.NotBookingPresidentException; | ||
| import com.ampersand.groom.global.annotation.usecase.UseCaseWithTransaction; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.security.core.context.SecurityContextHolder; | ||
|
|
||
| @UseCaseWithTransaction | ||
| @RequiredArgsConstructor | ||
| public class DeleteBookingUseCase { | ||
|
|
||
| private final BookingPersistencePort bookingPersistencePort; | ||
|
|
||
| public void execute(Long bookingId) { | ||
| Booking booking = bookingPersistencePort.findBookingByIdWithLock(bookingId); | ||
| if (!booking.getPresident().getEmail().equals(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString())) { | ||
| throw new NotBookingPresidentException(); | ||
| } | ||
| bookingPersistencePort.deleteBookingById(bookingId); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package com.ampersand.groom.domain.booking.application.usecase; | ||
|
|
||
| import com.ampersand.groom.domain.booking.persistence.BookingPersistenceAdapter; | ||
| import com.ampersand.groom.domain.booking.persistence.mapper.BookingMapper; | ||
| import com.ampersand.groom.domain.booking.presentation.data.response.GetBookingResponse; | ||
| import com.ampersand.groom.global.annotation.usecase.UseCaseWithReadOnlyTransaction; | ||
| import lombok.RequiredArgsConstructor; | ||
|
|
||
| import java.time.LocalDate; | ||
| import java.util.List; | ||
|
|
||
| @RequiredArgsConstructor | ||
| @UseCaseWithReadOnlyTransaction | ||
| public class FindBookingByDateAndTimeAndPlaceUseCase { | ||
|
|
||
| private final BookingPersistenceAdapter bookingPersistenceAdapter; | ||
| private final BookingMapper bookingMapper; | ||
|
|
||
|
||
| public List<GetBookingResponse> execute(LocalDate date, String time, String place) { | ||
| return bookingPersistenceAdapter.findBookingByDateAndTimeAndPlace(date, time, place).stream() | ||
| .map(bookingMapper::toResponse) | ||
| .toList(); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
캐시 버저닝에 관한 고민을 해보고 어떻게 버저닝을 할건지에 대한 고민을 나중에라도 해보면 좋겠음.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현재는 단순히 TTL로 2시간만 설정되어 있는데
더 공부해보고 고민해보도록 하겠습니다
감사합니다❤️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이런거 생각해보세요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵 조언 감사합니다