Skip to content

Commit

Permalink
refactor: 쿠폰, 알림 코드 개선 (#180)
Browse files Browse the repository at this point in the history
* refactor: coupon 발행 및 삭제 스타일 변경

* refactor: My Coupon 조회 코드 개선

* refactor: 쿠폰 등록, 사용 코드 개선

* refactor: FCM 및 알림 코드 개선
  • Loading branch information
hongdosan authored Nov 29, 2023
1 parent 9c086d1 commit 6a6ced1
Show file tree
Hide file tree
Showing 25 changed files with 849 additions and 2,609 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public void issue() {
}
}

public void registerQueue(Long memberId, String couponName) {
public void registerQueue(String couponName, Long memberId) {
double registerTime = System.currentTimeMillis();
validateRegisterQueue(couponName);
couponManageRepository.addIfAbsentQueue(couponName, memberId, registerTime);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public static MyCouponResponse toMyResponse(CouponWallet couponWallet) {
Coupon coupon = couponWallet.getCoupon();

return MyCouponResponse.builder()
.walletId(couponWallet.getId())
.id(coupon.getId())
.name(coupon.getName())
.description(coupon.getDescription())
Expand Down
55 changes: 29 additions & 26 deletions src/main/java/com/moabam/api/application/coupon/CouponService.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import com.moabam.api.dto.coupon.CouponStatusRequest;
import com.moabam.api.dto.coupon.CreateCouponRequest;
import com.moabam.api.dto.coupon.MyCouponResponse;
import com.moabam.global.auth.model.AuthMember;
import com.moabam.global.common.util.ClockHolder;
import com.moabam.global.error.exception.BadRequestException;
import com.moabam.global.error.exception.ConflictException;
Expand All @@ -42,29 +41,47 @@ public class CouponService {
private final CouponWalletSearchRepository couponWalletSearchRepository;

@Transactional
public void create(AuthMember admin, CreateCouponRequest request) {
validateAdminRole(admin);
public void create(CreateCouponRequest request, Long adminId, Role role) {
validateAdminRole(role);
validateConflictName(request.name());
validateConflictStartAt(request.startAt());
validatePeriod(request.startAt(), request.openAt());

Coupon coupon = CouponMapper.toEntity(admin.id(), request);
Coupon coupon = CouponMapper.toEntity(adminId, request);

couponRepository.save(coupon);
}

@Transactional
public void use(Long memberId, Long couponWalletId) {
CouponWallet couponWallet = getWalletByIdAndMemberId(couponWalletId, memberId);
public void delete(Long couponId, Role role) {
validateAdminRole(role);

Coupon coupon = couponRepository.findById(couponId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON));

couponRepository.delete(coupon);
couponManageService.deleteQueue(coupon.getName());
}

@Transactional
public void use(Long couponWalletId, Long memberId) {
CouponWallet couponWallet = couponWalletSearchRepository.findByIdAndMemberId(couponWalletId, memberId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON_WALLET));
Coupon coupon = couponWallet.getCoupon();
BugType bugType = coupon.getType().getBugType();

if (coupon.getType().isDiscount()) {
throw new BadRequestException(ErrorMessage.INVALID_DISCOUNT_COUPON);
}

bugService.applyCoupon(memberId, bugType, coupon.getPoint());
couponWalletRepository.delete(couponWallet);
}

@Transactional
public void discount(Long memberId, Long couponWalletId) {
CouponWallet couponWallet = getWalletByIdAndMemberId(couponWalletId, memberId);
public void discount(Long couponWalletId, Long memberId) {
CouponWallet couponWallet = couponWalletSearchRepository.findByIdAndMemberId(couponWalletId, memberId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON_WALLET));
Coupon coupon = couponWallet.getCoupon();

if (!coupon.getType().isDiscount()) {
Expand All @@ -74,15 +91,6 @@ public void discount(Long memberId, Long couponWalletId) {
couponWalletRepository.delete(couponWallet);
}

@Transactional
public void delete(AuthMember admin, Long couponId) {
validateAdminRole(admin);
Coupon coupon = couponRepository.findById(couponId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON));
couponRepository.delete(coupon);
couponManageService.deleteQueue(coupon.getName());
}

public CouponResponse getById(Long couponId) {
Coupon coupon = couponRepository.findById(couponId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON));
Expand All @@ -97,18 +105,13 @@ public List<CouponResponse> getAllByStatus(CouponStatusRequest request) {
return CouponMapper.toResponses(coupons);
}

public List<MyCouponResponse> getWallet(Long couponId, AuthMember authMember) {
public List<MyCouponResponse> getAllByWalletIdAndMemberId(Long couponWalletId, Long memberId) {
List<CouponWallet> couponWallets =
couponWalletSearchRepository.findAllByCouponIdAndMemberId(couponId, authMember.id());
couponWalletSearchRepository.findAllByIdAndMemberId(couponWalletId, memberId);

return CouponMapper.toMyResponses(couponWallets);
}

public CouponWallet getWalletByIdAndMemberId(Long couponWalletId, Long memberId) {
return couponWalletSearchRepository.findByIdAndMemberId(couponWalletId, memberId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON_WALLET));
}

private void validatePeriod(LocalDate startAt, LocalDate openAt) {
LocalDate now = clockHolder.date();

Expand All @@ -121,8 +124,8 @@ private void validatePeriod(LocalDate startAt, LocalDate openAt) {
}
}

private void validateAdminRole(AuthMember admin) {
if (!admin.role().equals(Role.ADMIN)) {
private void validateAdminRole(Role role) {
if (!role.equals(Role.ADMIN)) {
throw new NotFoundException(ErrorMessage.MEMBER_NOT_FOUND);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import com.moabam.api.domain.room.Participant;
import com.moabam.api.domain.room.repository.ParticipantSearchRepository;
import com.moabam.api.infrastructure.fcm.FcmService;
import com.moabam.global.auth.model.AuthMember;
import com.moabam.global.common.util.ClockHolder;
import com.moabam.global.error.exception.ConflictException;
import com.moabam.global.error.exception.NotFoundException;
Expand All @@ -40,14 +39,14 @@ public class NotificationService {
private final ParticipantSearchRepository participantSearchRepository;

@Transactional
public void sendKnock(AuthMember member, Long targetId, Long roomId) {
public void sendKnock(Long roomId, Long targetId, Long memberId, String memberNickname) {
roomService.validateRoomById(roomId);
validateConflictKnock(member.id(), targetId, roomId);
validateConflictKnock(roomId, targetId, memberId);
String fcmToken = fcmService.findTokenByMemberId(targetId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_FCM_TOKEN));

fcmService.sendAsync(fcmToken, String.format(KNOCK_BODY, member.nickname()));
notificationRepository.saveKnock(member.id(), targetId, roomId);
fcmService.sendAsync(fcmToken, String.format(KNOCK_BODY, memberNickname));
notificationRepository.saveKnock(roomId, targetId, memberId);
}

public void sendCouponIssueResult(Long memberId, String couponName, String body) {
Expand All @@ -74,7 +73,7 @@ public List<Long> getMyKnockStatusInRoom(Long memberId, Long roomId, List<Partic
.toList();

Predicate<Long> knockPredicate = targetId ->
notificationRepository.existsKnockByKey(memberId, targetId, roomId);
notificationRepository.existsKnockByKey(roomId, targetId, memberId);

Map<Boolean, List<Long>> knockStatus = filteredParticipants.stream()
.map(Participant::getMemberId)
Expand All @@ -83,8 +82,8 @@ public List<Long> getMyKnockStatusInRoom(Long memberId, Long roomId, List<Partic
return knockStatus.get(true);
}

private void validateConflictKnock(Long memberId, Long targetId, Long roomId) {
if (notificationRepository.existsKnockByKey(memberId, targetId, roomId)) {
private void validateConflictKnock(Long roomId, Long targetId, Long memberId) {
if (notificationRepository.existsKnockByKey(roomId, targetId, memberId)) {
throw new ConflictException(ErrorMessage.CONFLICT_KNOCK);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public void confirm(Long memberId, ConfirmPaymentRequest request) {
payment.confirm(response.paymentKey(), response.approvedAt());

if (payment.isCouponApplied()) {
couponService.discount(memberId, payment.getCouponWalletId());
couponService.discount(payment.getCouponWalletId(), memberId);
}
bugService.charge(memberId, payment.getProduct());
} catch (MoabamException exception) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,23 @@ public class CouponWalletSearchRepository {

private final JPAQueryFactory jpaQueryFactory;

public List<CouponWallet> findAllByCouponIdAndMemberId(Long couponId, Long memberId) {
public List<CouponWallet> findAllByIdAndMemberId(Long couponWalletId, Long memberId) {
return jpaQueryFactory
.selectFrom(couponWallet)
.join(couponWallet.coupon, coupon).fetchJoin()
.where(
DynamicQuery.generateEq(couponId, couponWallet.coupon.id::eq),
DynamicQuery.generateEq(couponWalletId, couponWallet.id::eq),
DynamicQuery.generateEq(memberId, couponWallet.memberId::eq)
)
.fetch();
}

public Optional<CouponWallet> findByIdAndMemberId(Long id, Long memberId) {
public Optional<CouponWallet> findByIdAndMemberId(Long couponWalletId, Long memberId) {
return Optional.ofNullable(jpaQueryFactory
.selectFrom(couponWallet)
.join(couponWallet.coupon, coupon).fetchJoin()
.where(
couponWallet.id.eq(id),
couponWallet.id.eq(couponWalletId),
couponWallet.memberId.eq(memberId))
.fetchOne()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,27 @@
@RequiredArgsConstructor
public class NotificationRepository {

private static final String KNOCK_KEY = "room_%s_member_%s_knocks_%s";
private static final String KNOCK_KEY = "roomId=%s_targetId=%s_memberId=%s";
private static final long EXPIRE_KNOCK = 12;

private final ValueRedisRepository valueRedisRepository;

public void saveKnock(Long memberId, Long targetId, Long roomId) {
String knockKey =
String.format(KNOCK_KEY, requireNonNull(roomId), requireNonNull(memberId), requireNonNull(targetId));
public void saveKnock(Long roomId, Long targetId, Long memberId) {
String knockKey = String.format(
KNOCK_KEY,
requireNonNull(roomId),
requireNonNull(targetId),
requireNonNull(memberId));

valueRedisRepository.save(knockKey, BLANK, Duration.ofHours(EXPIRE_KNOCK));
}

public boolean existsKnockByKey(Long memberId, Long targetId, Long roomId) {
String knockKey =
String.format(KNOCK_KEY, requireNonNull(roomId), requireNonNull(memberId), requireNonNull(targetId));
public boolean existsKnockByKey(Long roomId, Long targetId, Long memberId) {
String knockKey = String.format(
KNOCK_KEY,
requireNonNull(roomId),
requireNonNull(targetId),
requireNonNull(memberId));

return valueRedisRepository.hasKey(requireNonNull(knockKey));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

@Builder
public record MyCouponResponse(
Long walletId,
Long id,
String name,
String description,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ public class FcmRepository {

private final ValueRedisRepository valueRedisRepository;

public void saveToken(Long memberId, String fcmToken) {
public void saveToken(String fcmToken, Long memberId) {
String tokenKey = String.valueOf(requireNonNull(memberId));

valueRedisRepository.save(
String.valueOf(requireNonNull(memberId)),
tokenKey,
requireNonNull(fcmToken),
Duration.ofDays(EXPIRE_FCM_TOKEN)
);
Duration.ofDays(EXPIRE_FCM_TOKEN));
}

public void deleteTokenByMemberId(Long memberId) {
Expand All @@ -33,8 +34,4 @@ public void deleteTokenByMemberId(Long memberId) {
public String findTokenByMemberId(Long memberId) {
return valueRedisRepository.get(String.valueOf(requireNonNull(memberId)));
}

public boolean existsTokenByMemberId(Long memberId) {
return valueRedisRepository.hasKey(String.valueOf(requireNonNull(memberId)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.Message;
import com.google.firebase.messaging.Notification;
import com.moabam.global.auth.model.AuthMember;

import lombok.RequiredArgsConstructor;

Expand All @@ -18,16 +17,14 @@ public class FcmService {
private final FirebaseMessaging firebaseMessaging;
private final FcmRepository fcmRepository;

// TODO : 세연님 로그인 시, 해당 메서드 사용해서 해당 유저의 FCM TOKEN 저장하면 됩니다. Front와 상의 후 삭제예정
public void createToken(AuthMember authMember, String fcmToken) {
public void createToken(String fcmToken, Long memberId) {
if (fcmToken == null || fcmToken.isBlank()) {
return;
}

fcmRepository.saveToken(authMember.id(), fcmToken);
fcmRepository.saveToken(fcmToken, memberId);
}

// TODO : 세연님 로그아웃 시, 해당 메서드 사용해서 해당 유저의 FCM TOKEN 삭제하시면 됩니다. (이 코드는 원하시면 변경하셔도 됩니다.)
public void deleteTokenByMemberId(Long memberId) {
fcmRepository.deleteTokenByMemberId(memberId);
}
Expand Down
30 changes: 16 additions & 14 deletions src/main/java/com/moabam/api/presentation/CouponController.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ public class CouponController {

@PostMapping("/admins/coupons")
@ResponseStatus(HttpStatus.CREATED)
public void create(@Auth AuthMember admin, @Valid @RequestBody CreateCouponRequest request) {
couponService.create(admin, request);
public void create(@Valid @RequestBody CreateCouponRequest request, @Auth AuthMember admin) {
couponService.create(request, admin.id(), admin.role());
}

@DeleteMapping("/admins/coupons/{couponId}")
@ResponseStatus(HttpStatus.OK)
public void delete(@Auth AuthMember admin, @PathVariable("couponId") Long couponId) {
couponService.delete(admin, couponId);
public void delete(@PathVariable("couponId") Long couponId, @Auth AuthMember admin) {
couponService.delete(couponId, admin.role());
}

@GetMapping("/coupons/{couponId}")
Expand All @@ -55,22 +55,24 @@ public List<CouponResponse> getAllByStatus(@Valid @RequestBody CouponStatusReque
return couponService.getAllByStatus(request);
}

@PostMapping("/coupons")
@GetMapping({"/my-coupons", "/my-coupons/{couponWalletId}"})
@ResponseStatus(HttpStatus.OK)
public void registerQueue(@Auth AuthMember authMember, @RequestParam("couponName") String couponName) {
couponManageService.registerQueue(authMember.id(), couponName);
public List<MyCouponResponse> getAllByWalletIdAndMemberId(
@PathVariable(value = "couponWalletId", required = false) Long couponWalletId,
@Auth AuthMember authMember
) {
return couponService.getAllByWalletIdAndMemberId(couponWalletId, authMember.id());
}

@GetMapping({"/my-coupons", "/my-coupons/{couponId}"})
@PostMapping("/my-coupons/{couponWalletId}")
@ResponseStatus(HttpStatus.OK)
public List<MyCouponResponse> getWallet(@Auth AuthMember authMember,
@PathVariable(value = "couponId", required = false) Long couponId) {
return couponService.getWallet(couponId, authMember);
public void use(@PathVariable("couponWalletId") Long couponWalletId, @Auth AuthMember authMember) {
couponService.use(couponWalletId, authMember.id());
}

@PostMapping("/my-coupons/{couponWalletId}")
@PostMapping("/coupons")
@ResponseStatus(HttpStatus.OK)
public void use(@Auth AuthMember authMember, @PathVariable("couponWalletId") Long couponWalletId) {
couponService.use(authMember.id(), couponWalletId);
public void registerQueue(@RequestParam("couponName") String couponName, @Auth AuthMember authMember) {
couponManageService.registerQueue(couponName, authMember.id());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@ public class NotificationController {

@GetMapping("/rooms/{roomId}/members/{memberId}")
@ResponseStatus(HttpStatus.OK)
public void sendKnockNotification(@Auth AuthMember member, @PathVariable("roomId") Long roomId,
@PathVariable("memberId") Long memberId) {
notificationService.sendKnock(member, memberId, roomId);
public void sendKnock(
@PathVariable("roomId") Long roomId,
@PathVariable("memberId") Long memberId,
@Auth AuthMember authMember
) {
notificationService.sendKnock(roomId, memberId, authMember.id(), authMember.nickname());
}

@PostMapping
@ResponseStatus(HttpStatus.OK)
public void createFcmToken(@Auth AuthMember authMember, @RequestParam("fcmToken") String fcmToken) {
fcmService.createToken(authMember, fcmToken);
public void createFcmToken(@RequestParam("fcmToken") String fcmToken, @Auth AuthMember authMember) {
fcmService.createToken(fcmToken, authMember.id());
}
}
Loading

0 comments on commit 6a6ced1

Please sign in to comment.