Skip to content
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

feat: Carpool close API #90

Merged
merged 3 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import com.fullcar.carpool.domain.carpool.CarpoolId;
import com.fullcar.carpool.domain.carpool.CarpoolRepository;
import com.fullcar.carpool.domain.carpool.Driver;
import com.fullcar.carpool.domain.form.Form;
import com.fullcar.carpool.domain.form.FormRepository;
import com.fullcar.carpool.domain.form.FormState;
import com.fullcar.carpool.presentation.carpool.dto.request.CarpoolRequestDto;
import com.fullcar.carpool.presentation.carpool.dto.response.CarpoolResponseDto;
import com.fullcar.carpool.presentation.carpool.dto.response.MyCarpoolDto;
Expand All @@ -13,6 +16,7 @@
import com.fullcar.member.domain.car.CarRepository;
import com.fullcar.member.domain.member.Member;

import com.fullcar.member.domain.member.MemberRepository;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.*;
Expand All @@ -29,6 +33,8 @@
public class CarpoolService {
private final CarpoolRepository carpoolRepository;
private final CarRepository carRepository; //:TODO Event 기반으둜 λ³€κ²½
private final MemberRepository memberRepository; //:TODO Event 기반으둜 λ³€κ²½
private final FormRepository formRepository;
private final CarpoolMapper carpoolMapper;

@Transactional
Expand Down Expand Up @@ -79,4 +85,34 @@ public List<MyCarpoolDto> getMyCarpoolList(Member member) {
.map(carpool -> carpoolMapper.toMyCarpoolDto(carpool, member))
.toList();
}

@Transactional
public CarpoolResponseDto.CarpoolDetailDtO closeCarpool(Member member, CarpoolId carpoolId) {
Carpool carpool = carpoolRepository.findByCarpoolIdAndIsDeletedOrThrow(carpoolId, false);
Car car = carRepository.findByCarIdAndIsDeletedOrThrow(member.getCarId(), false);

if (!carpool.isMyCarpool(member.getId())) {
throw new CustomException(ErrorCode.CANNOT_CLOSE_CARPOOL);
}
List<Form> forms = formRepository.findAllByCarpoolIdAndIsDeleted(carpoolId, false);

carpool.close();

for (Form form: forms) {
if (form.getFormState() == FormState.REQUEST) {
form.reject(
memberRepository.findByIdAndIsDeletedOrThrow(
form.getPassenger().getMemberId(),
false
)
);
}

} // TODO: N+1 문제 κ°œμ„  ν•„μš”.

carpoolRepository.save(carpool);
formRepository.saveAllAndFlush(forms);

return carpoolMapper.toDetailDto(carpool, member, car);
}
}
40 changes: 23 additions & 17 deletions src/main/java/com/fullcar/carpool/application/form/FormService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import com.fullcar.carpool.domain.carpool.Carpool;
import com.fullcar.carpool.domain.carpool.CarpoolId;
import com.fullcar.carpool.domain.carpool.CarpoolRepository;
import com.fullcar.carpool.domain.carpool.CarpoolState;
import com.fullcar.carpool.domain.form.*;
import com.fullcar.carpool.infra.NotificationClient;
import com.fullcar.carpool.domain.form.event.FormStateChangedEvent;
import com.fullcar.carpool.domain.service.NotificationService;
import com.fullcar.carpool.infra.dto.NotificationDto;
import com.fullcar.carpool.presentation.form.dto.request.FormRequestDto;
import com.fullcar.carpool.presentation.form.dto.request.FormUpdateDto;
import com.fullcar.carpool.presentation.form.dto.response.FormResponseDto;
Expand All @@ -14,6 +17,7 @@
import com.fullcar.member.domain.member.MemberRepository;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
Expand All @@ -29,13 +33,18 @@ public class FormService {
private final CarpoolRepository carpoolRepository;
private final MemberRepository memberRepository; //TODO: Event 기반으둜 λ³€κ²½ ν•„μš”.
private final FormMapper formMapper;
private final NotificationClient pushNotificationClient;
private final NotificationService notificationService;
private final ApplicationEventPublisher eventPublisher;

@Transactional
public FormResponseDto requestForm(Member member, CarpoolId carpoolId, FormRequestDto formRequestDto) {
Carpool carpool = carpoolRepository.findByCarpoolIdAndIsDeletedOrThrow(carpoolId, false);
Member driver = memberRepository.findByIdAndIsDeletedOrThrow(carpool.getDriver().getMemberId(), false);

if (carpool.getCarpoolState() == CarpoolState.CLOSE) {
throw new CustomException(ErrorCode.CANNOT_SEND_TO_CLOSED_CARPOOL);
}

if (carpool.isMyCarpool(member.getId())) {
throw new CustomException(ErrorCode.CANNOT_SEND_TO_OWN_CARPOOL);
}
Expand All @@ -53,7 +62,17 @@ public FormResponseDto requestForm(Member member, CarpoolId carpoolId, FormReque
}

Form form = formMapper.toEntity(member, carpoolId, formRequestDto);
pushNotificationClient.sendNotification(driver.getNickname(), driver.getDeviceToken(), "νƒ‘μŠΉ μš”μ²­μ΄ λ“€μ–΄μ™”μ–΄μš”!", "νƒ‘μŠΉμž 정보λ₯Ό ν™•μΈν•˜κ³  μŠΉμΈν•΄ μ£Όμ„Έμš”πŸš˜");

eventPublisher.publishEvent(
new FormStateChangedEvent(
NotificationDto.builder()
.nickName(driver.getNickname())
.deviceToken(driver.getDeviceToken())
.title(FormMessage.REQUEST_TITLE.getMessage())
.body(FormMessage.REQUEST_BODY.getMessage())
.build()
)
);

return formMapper.toDto(
formRepository.saveAndFlush(form),
Expand Down Expand Up @@ -95,27 +114,14 @@ public List<FormResponseDto> readReceivedFormList(Member member) {
@Transactional
public FormResponseDto.FormDetailDto updateForm(Member member, FormId formId, FormUpdateDto formUpdateDto) {
Form form = formRepository.findByFormIdAndIsDeletedOrThrow(formId, false);
form.changeFormState(formUpdateDto);

Member passenger = memberRepository.findByIdAndIsDeletedOrThrow(form.getPassenger().getMemberId(), false);
Carpool carpool = carpoolRepository.findByCarpoolIdAndIsDeletedOrThrow(form.getCarpoolId(), false);

if (!carpool.isMyCarpool(member.getId())) {
throw new CustomException(ErrorCode.CANNOT_CHANGE_FORM_STATE);
}

System.out.println(passenger.getDeviceToken());

if (formUpdateDto.getFormState() == FormState.ACCEPT) {
String title = "μΉ΄ν’€ 맀칭에 μ„±κ³΅ν–ˆμ–΄μš”!";
String body = "μš΄μ „μž 정보λ₯Ό 확인해 μ£Όμ„Έμš”πŸš˜";
pushNotificationClient.sendNotification(passenger.getNickname(), passenger.getDeviceToken(), title, body);
}
else if (formUpdateDto.getFormState() == FormState.REJECT) {
String title = "μΉ΄ν’€ 맀칭에 μ‹€νŒ¨ν–ˆμ–΄μš”.";
String body = "λ‹€λ₯Έ 카풀을 μ°Ύμ•„λ³ΌκΉŒμš”?πŸ’πŸ»β€β™€οΈ";
pushNotificationClient.sendNotification(passenger.getNickname(), passenger.getDeviceToken(), title, body);
}
form.changeFormState(formUpdateDto, passenger);

return formMapper.toDetailDto(
formRepository.saveAndFlush(form),
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/fullcar/carpool/domain/carpool/Carpool.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,8 @@ public class Carpool {
public boolean isMyCarpool(MemberId memberId) {
return this.getDriver().getMemberId().getId().equals(memberId.getId());
}

public void close() {
this.carpoolState = CarpoolState.CLOSE;
}
}
37 changes: 29 additions & 8 deletions src/main/java/com/fullcar/carpool/domain/form/Form.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.fullcar.carpool.domain.form;

import com.fullcar.carpool.domain.carpool.CarpoolId;
import com.fullcar.carpool.domain.form.event.FormStateChangedEvent;
import com.fullcar.carpool.infra.dto.NotificationDto;
import com.fullcar.carpool.presentation.form.dto.request.FormUpdateDto;
import com.fullcar.core.exception.CustomException;
import com.fullcar.core.response.ErrorCode;
import com.fullcar.member.domain.member.Member;
import jakarta.persistence.*;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.domain.AbstractAggregateRoot;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;
Expand All @@ -19,8 +23,7 @@
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@EntityListeners(AuditingEntityListener.class)
@Table(name = "form")
public class Form {
private static final String REJECT_MESSAGE = "μΉ΄ν’€ 맀칭에 μ‹€νŒ¨ν–ˆμ–΄μš”. λ‹€λ₯Έ 카풀을 μ°Ύμ•„λ³΄μ„Έμš”!";
public class Form extends AbstractAggregateRoot<Form> {

@EmbeddedId
private FormId formId;
Expand Down Expand Up @@ -60,32 +63,50 @@ public class Form {
@LastModifiedDate
private LocalDateTime updatedAt;

public void changeFormState(FormUpdateDto formUpdateDto) {
public void changeFormState(FormUpdateDto formUpdateDto, Member passenger) {
FormState formState = formUpdateDto.getFormState();

if (formState == FormState.ACCEPT) {
this.accept(formUpdateDto.getContact(), formUpdateDto.getToPassenger());
this.accept(formUpdateDto.getContact(), formUpdateDto.getToPassenger(), passenger);
}
else if (formState == FormState.REJECT) {
this.reject();
this.reject(passenger);
}
else {
throw new CustomException(ErrorCode.INVALID_FORM_STATE);
}
}

public void accept(String contact, String toPassenger) {
public void accept(String contact, String toPassenger, Member passenger) {
this.formState = FormState.ACCEPT;
this.resultMessage = ResultMessage.builder()
.contact(contact)
.toPassenger(toPassenger)
.build();

registerEvent(new FormStateChangedEvent(
NotificationDto.builder()
.nickName(passenger.getNickname())
.deviceToken(passenger.getDeviceToken())
.title(FormMessage.ACCEPT_TITLE.getMessage())
.body(FormMessage.ACCEPT_BODY.getMessage())
.build()
));
}

public void reject() {
public void reject(Member passenger) {
this.formState = FormState.REJECT;
this.resultMessage = ResultMessage.builder()
.toPassenger(REJECT_MESSAGE)
.toPassenger(FormMessage.REJECT_MESSAGE.getMessage())
.build();

registerEvent(new FormStateChangedEvent(
NotificationDto.builder()
.nickName(passenger.getNickname())
.deviceToken(passenger.getDeviceToken())
.title(FormMessage.REJECT_TITLE.getMessage())
.body(FormMessage.REJECT_BODY.getMessage())
.build()
));
}
}
18 changes: 18 additions & 0 deletions src/main/java/com/fullcar/carpool/domain/form/FormMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.fullcar.carpool.domain.form;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum FormMessage {
REJECT_MESSAGE("μΉ΄ν’€ 맀칭에 μ‹€νŒ¨ν–ˆμ–΄μš”. λ‹€λ₯Έ 카풀을 μ°Ύμ•„λ³΄μ„Έμš”!"),
REQUEST_TITLE("νƒ‘μŠΉ μš”μ²­μ΄ λ“€μ–΄μ™”μ–΄μš”!"),
REQUEST_BODY("νƒ‘μŠΉμž 정보λ₯Ό ν™•μΈν•˜κ³  μŠΉμΈν•΄ μ£Όμ„Έμš”πŸš˜"),
ACCEPT_TITLE("μΉ΄ν’€ 맀칭에 μ„±κ³΅ν–ˆμ–΄μš”!"),
ACCEPT_BODY("μš΄μ „μž 정보λ₯Ό 확인해 μ£Όμ„Έμš”πŸš˜"),
REJECT_TITLE("μΉ΄ν’€ 맀칭에 μ‹€νŒ¨ν–ˆμ–΄μš”."),
REJECT_BODY("λ‹€λ₯Έ 카풀을 μ°Ύμ•„λ³ΌκΉŒμš”?πŸ’πŸ»β€β™€οΈ");

private final String message;
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ List<Form> findReceivedForm(
@Param("memberId") Long memberId
);

List<Form> findAllByCarpoolIdAndIsDeleted(CarpoolId carpoolId, boolean isDeleted);

default Form findByFormIdAndIsDeletedOrThrow(FormId formId, boolean isDeleted) {
return findByFormIdAndIsDeleted(formId, isDeleted).orElseThrow(
() -> new CustomException(ErrorCode.NOT_EXIST_FORM)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.fullcar.carpool.domain.form.event;

import com.fullcar.carpool.infra.dto.NotificationDto;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class FormStateChangedEvent {
private NotificationDto notificationDto;
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.fullcar.carpool.domain.service;

import com.fullcar.carpool.infra.dto.NotificationDto;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public interface NotificationService {
void sendNotification(String nickname, String deviceToken, String title, String body);
void sendNotification(NotificationDto notificationDto);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.fullcar.carpool.infra;

import com.fullcar.carpool.domain.service.NotificationService;
import com.fullcar.carpool.infra.dto.NotificationDto;
import com.fullcar.core.exception.CustomException;
import com.fullcar.core.response.ErrorCode;
import com.google.firebase.messaging.FirebaseMessaging;
Expand All @@ -17,14 +18,14 @@ public class NotificationClient implements NotificationService {
private final FirebaseMessaging firebaseMessaging;

@Override
public void sendNotification(String nickname, String deviceToken, String title, String body) {
public void sendNotification(NotificationDto notificationDto) {
Notification notification = Notification.builder()
.setTitle(nickname + "λ‹˜! " + title)
.setBody(body)
.setTitle(notificationDto.getNickName() + "λ‹˜! " + notificationDto.getTitle())
.setBody(notificationDto.getBody())
.build();

Message message = Message.builder()
.setToken(deviceToken)
.setToken(notificationDto.getDeviceToken())
.setNotification(notification)
.build();

Expand Down
17 changes: 17 additions & 0 deletions src/main/java/com/fullcar/carpool/infra/dto/NotificationDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.fullcar.carpool.infra.dto;

import lombok.*;

@Getter
@Builder
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class NotificationDto {
private String nickName;

private String deviceToken;

private String title;

private String body;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.fullcar.carpool.infra.event;

import com.fullcar.carpool.infra.dto.NotificationDto;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class NotificationEvent {
private NotificationDto notificationDto;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.fullcar.carpool.infra.event;

import com.fullcar.carpool.domain.form.event.FormStateChangedEvent;
import com.fullcar.carpool.domain.service.NotificationService;
import com.fullcar.carpool.infra.dto.NotificationDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@RequiredArgsConstructor
@EnableAsync
public class NotificationEventListener {
private final NotificationService notificationService;

@Async
@EventListener
public void sendNotification(FormStateChangedEvent formStateChangedEvent) {
notificationService.sendNotification(formStateChangedEvent.getNotificationDto());
log.info("Notification send");
}
}
Loading
Loading