diff --git a/src/main/generated/com/nexters/dailyphrase/prize/domain/QPrizeTicket.java b/src/main/generated/com/nexters/dailyphrase/prize/domain/QPrizeTicket.java index 0db4a1e..a2e13f6 100644 --- a/src/main/generated/com/nexters/dailyphrase/prize/domain/QPrizeTicket.java +++ b/src/main/generated/com/nexters/dailyphrase/prize/domain/QPrizeTicket.java @@ -30,6 +30,8 @@ public class QPrizeTicket extends EntityPathBase { public final NumberPath memberId = createNumber("memberId", Long.class); + public final EnumPath source = createEnum("source", com.nexters.dailyphrase.common.enums.PrizeTicketSource.class); + public final EnumPath status = createEnum("status", com.nexters.dailyphrase.common.enums.PrizeTicketStatus.class); //inherited diff --git a/src/main/java/com/nexters/dailyphrase/common/consts/DailyPhraseStatic.java b/src/main/java/com/nexters/dailyphrase/common/consts/DailyPhraseStatic.java index dddb6c6..84b6fab 100644 --- a/src/main/java/com/nexters/dailyphrase/common/consts/DailyPhraseStatic.java +++ b/src/main/java/com/nexters/dailyphrase/common/consts/DailyPhraseStatic.java @@ -26,4 +26,6 @@ public class DailyPhraseStatic { public static final int MAX_EVENT_TICKETS_PER_DAY = 10; public static final Long CURRENT_ACTIVE_EVENT_ID = 1L; + + public static final int SIGN_UP_TICKET_COUNT = 5; } diff --git a/src/main/java/com/nexters/dailyphrase/common/enums/PrizeTicketSource.java b/src/main/java/com/nexters/dailyphrase/common/enums/PrizeTicketSource.java new file mode 100644 index 0000000..91daa24 --- /dev/null +++ b/src/main/java/com/nexters/dailyphrase/common/enums/PrizeTicketSource.java @@ -0,0 +1,13 @@ +package com.nexters.dailyphrase.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum PrizeTicketSource { + SIGNUP("회원가입"), + SHARE("공유하기"); + + private final String description; +} diff --git a/src/main/java/com/nexters/dailyphrase/member/business/MemberLoginActionProcessor.java b/src/main/java/com/nexters/dailyphrase/member/business/MemberLoginActionProcessor.java new file mode 100644 index 0000000..a0cab69 --- /dev/null +++ b/src/main/java/com/nexters/dailyphrase/member/business/MemberLoginActionProcessor.java @@ -0,0 +1,36 @@ +package com.nexters.dailyphrase.member.business; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import com.nexters.dailyphrase.common.enums.PrizeTicketSource; +import com.nexters.dailyphrase.prize.business.PrizeEventMapper; +import com.nexters.dailyphrase.prize.implement.PrizeTicketCommandAdapter; +import com.nexters.dailyphrase.prize.implement.PrizeTicketQueryAdapter; + +import lombok.RequiredArgsConstructor; + +@Component +@RequiredArgsConstructor +public class MemberLoginActionProcessor { + + private final Logger logger = LogManager.getLogger(MemberLoginActionProcessor.class); + private final PrizeTicketQueryAdapter prizeTicketQueryAdapter; + private final PrizeTicketCommandAdapter prizeTicketCommandAdapter; + private final PrizeEventMapper prizeEventMapper; + + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void processLoginAction(final Long memberId) { + try { + if (!prizeTicketQueryAdapter.existsByMemberIdAndSource( + memberId, PrizeTicketSource.SIGNUP)) + prizeTicketCommandAdapter.createMultiple( + prizeEventMapper.toPrizeTicketList(memberId, PrizeTicketSource.SIGNUP)); + } catch (Exception e) { + logger.error("MemberService) 회원가입 응모권 발급 중 에러가 발생했습니다."); + } + } +} diff --git a/src/main/java/com/nexters/dailyphrase/member/business/MemberService.java b/src/main/java/com/nexters/dailyphrase/member/business/MemberService.java index 98e0018..d29558c 100644 --- a/src/main/java/com/nexters/dailyphrase/member/business/MemberService.java +++ b/src/main/java/com/nexters/dailyphrase/member/business/MemberService.java @@ -33,6 +33,7 @@ public class MemberService { private final FavoriteQueryAdapter favoriteQueryAdapter; private final FavoriteCommandAdapter favoriteCommandAdapter; private final SocialLoginServiceFactory socialLoginServiceFactory; + private final MemberLoginActionProcessor memberLoginActionProcessor; private final JwtTokenService jwtTokenService; private final MemberMapper memberMapper; @@ -46,6 +47,9 @@ public MemberResponseDTO.LoginMember login( jwtTokenService.generateAccessToken(member.getId(), member.getRole().name()); // TODO - Refresh 토큰을 Jwt로 발급하지 않고, Redis를 사용하는 방식도 고려하기 String refreshToken = jwtTokenService.generateRefreshToken(member.getId()); + + // NOTE - 회원가입 응모권 발급 + memberLoginActionProcessor.processLoginAction(member.getId()); return memberMapper.toLoginMember(member, accessToken, refreshToken); } diff --git a/src/main/java/com/nexters/dailyphrase/prize/business/PrizeEventMapper.java b/src/main/java/com/nexters/dailyphrase/prize/business/PrizeEventMapper.java index eea85fd..6345ca3 100644 --- a/src/main/java/com/nexters/dailyphrase/prize/business/PrizeEventMapper.java +++ b/src/main/java/com/nexters/dailyphrase/prize/business/PrizeEventMapper.java @@ -1,9 +1,13 @@ package com.nexters.dailyphrase.prize.business; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import com.nexters.dailyphrase.common.annotation.Mapper; +import com.nexters.dailyphrase.common.consts.DailyPhraseStatic; import com.nexters.dailyphrase.common.enums.PrizeEntryStatus; +import com.nexters.dailyphrase.common.enums.PrizeTicketSource; import com.nexters.dailyphrase.common.enums.PrizeTicketStatus; import com.nexters.dailyphrase.prize.domain.Prize; import com.nexters.dailyphrase.prize.domain.PrizeEntry; @@ -14,11 +18,15 @@ @Mapper public class PrizeEventMapper { public PrizeTicket toPrizeTicket( - Long memberId, PrizeTicketStatus prizeTicketStatus, Long eventId) { + Long memberId, + PrizeTicketStatus prizeTicketStatus, + Long eventId, + PrizeTicketSource source) { return PrizeTicket.builder() .memberId(memberId) .status(prizeTicketStatus) .eventId(eventId) + .source(source) .build(); } @@ -73,4 +81,18 @@ public PrizeEventResponseDTO.EnterPrizeEvent toEnterPrizeEvent(final PrizeEntry .status(prizeEntry.getStatus()) .build(); } + + public List toPrizeTicketList(Long memberId, PrizeTicketSource prizeTicketSource) { + Long eventId = DailyPhraseStatic.CURRENT_ACTIVE_EVENT_ID; + int limit = DailyPhraseStatic.SIGN_UP_TICKET_COUNT; + return IntStream.range(0, limit) + .mapToObj( + i -> + toPrizeTicket( + memberId, + PrizeTicketStatus.AVAILABLE, + eventId, + prizeTicketSource)) + .toList(); + } } diff --git a/src/main/java/com/nexters/dailyphrase/prize/business/PrizeEventService.java b/src/main/java/com/nexters/dailyphrase/prize/business/PrizeEventService.java index 29b3247..5a7cda7 100644 --- a/src/main/java/com/nexters/dailyphrase/prize/business/PrizeEventService.java +++ b/src/main/java/com/nexters/dailyphrase/prize/business/PrizeEventService.java @@ -12,6 +12,7 @@ import com.nexters.dailyphrase.common.consts.DailyPhraseStatic; import com.nexters.dailyphrase.common.enums.PrizeEntryStatus; import com.nexters.dailyphrase.common.enums.PrizeEventStatus; +import com.nexters.dailyphrase.common.enums.PrizeTicketSource; import com.nexters.dailyphrase.common.enums.PrizeTicketStatus; import com.nexters.dailyphrase.common.jwt.JwtTokenService; import com.nexters.dailyphrase.common.jwt.dto.AccessTokenInfo; @@ -89,7 +90,8 @@ public void issuePrizeTicket(final KakaolinkCallbackRequestDTO request) { if (count >= MAX_EVENT_TICKETS_PER_DAY) return; PrizeTicket prizeTicket = - prizeEventMapper.toPrizeTicket(memberId, PrizeTicketStatus.AVAILABLE, eventId); + prizeEventMapper.toPrizeTicket( + memberId, PrizeTicketStatus.AVAILABLE, eventId, PrizeTicketSource.SHARE); prizeTicketCommandAdapter.create(prizeTicket); } diff --git a/src/main/java/com/nexters/dailyphrase/prize/domain/PrizeTicket.java b/src/main/java/com/nexters/dailyphrase/prize/domain/PrizeTicket.java index 1196a79..e5e9528 100644 --- a/src/main/java/com/nexters/dailyphrase/prize/domain/PrizeTicket.java +++ b/src/main/java/com/nexters/dailyphrase/prize/domain/PrizeTicket.java @@ -3,6 +3,7 @@ import jakarta.persistence.*; import com.nexters.dailyphrase.common.domain.BaseDateTimeEntity; +import com.nexters.dailyphrase.common.enums.PrizeTicketSource; import com.nexters.dailyphrase.common.enums.PrizeTicketStatus; import lombok.*; @@ -24,6 +25,9 @@ public class PrizeTicket extends BaseDateTimeEntity { @Enumerated(EnumType.STRING) private PrizeTicketStatus status; + @Enumerated(EnumType.STRING) + private PrizeTicketSource source; + public void setStatus(PrizeTicketStatus status) { this.status = status; } diff --git a/src/main/java/com/nexters/dailyphrase/prize/domain/repository/PrizeTicketRepository.java b/src/main/java/com/nexters/dailyphrase/prize/domain/repository/PrizeTicketRepository.java index 77e53c2..ceaa8cf 100644 --- a/src/main/java/com/nexters/dailyphrase/prize/domain/repository/PrizeTicketRepository.java +++ b/src/main/java/com/nexters/dailyphrase/prize/domain/repository/PrizeTicketRepository.java @@ -4,13 +4,16 @@ import org.springframework.data.jpa.repository.JpaRepository; -import com.nexters.dailyphrase.common.enums.PrizeTicketStatus; +import com.nexters.dailyphrase.common.enums.PrizeTicketSource; import com.nexters.dailyphrase.prize.domain.PrizeTicket; public interface PrizeTicketRepository extends JpaRepository, PrizeTicketCustomRepository { - int countByMemberIdAndCreatedAtBetween( - Long memberId, LocalDateTime startDateTime, LocalDateTime endDateTime); + int countByMemberIdAndCreatedAtBetweenAndSource( + Long memberId, + LocalDateTime startDateTime, + LocalDateTime endDateTime, + PrizeTicketSource source); - int countByMemberIdAndStatus(Long memberId, PrizeTicketStatus status); + boolean existsByMemberIdAndSource(Long memberId, PrizeTicketSource source); } diff --git a/src/main/java/com/nexters/dailyphrase/prize/implement/PrizeTicketCommandAdapter.java b/src/main/java/com/nexters/dailyphrase/prize/implement/PrizeTicketCommandAdapter.java index d4ddf2d..fff04ce 100644 --- a/src/main/java/com/nexters/dailyphrase/prize/implement/PrizeTicketCommandAdapter.java +++ b/src/main/java/com/nexters/dailyphrase/prize/implement/PrizeTicketCommandAdapter.java @@ -1,5 +1,7 @@ package com.nexters.dailyphrase.prize.implement; +import java.util.List; + import com.nexters.dailyphrase.common.annotation.Adapter; import com.nexters.dailyphrase.prize.domain.PrizeTicket; import com.nexters.dailyphrase.prize.domain.repository.PrizeTicketRepository; @@ -14,4 +16,8 @@ public class PrizeTicketCommandAdapter { public void create(PrizeTicket prizeTicket) { prizeTicketRepository.save(prizeTicket); } + + public void createMultiple(List prizeTicketList) { + prizeTicketRepository.saveAll(prizeTicketList); + } } diff --git a/src/main/java/com/nexters/dailyphrase/prize/implement/PrizeTicketQueryAdapter.java b/src/main/java/com/nexters/dailyphrase/prize/implement/PrizeTicketQueryAdapter.java index 8674984..efb221c 100644 --- a/src/main/java/com/nexters/dailyphrase/prize/implement/PrizeTicketQueryAdapter.java +++ b/src/main/java/com/nexters/dailyphrase/prize/implement/PrizeTicketQueryAdapter.java @@ -5,6 +5,7 @@ import java.util.List; import com.nexters.dailyphrase.common.annotation.Adapter; +import com.nexters.dailyphrase.common.enums.PrizeTicketSource; import com.nexters.dailyphrase.common.enums.PrizeTicketStatus; import com.nexters.dailyphrase.prize.domain.PrizeTicket; import com.nexters.dailyphrase.prize.domain.repository.PrizeTicketRepository; @@ -21,12 +22,16 @@ public Integer countPrizeTicketByMemberIdAndLocalDate( LocalDateTime startOfDay = date.atStartOfDay(); LocalDateTime endOfDay = date.atTime(23, 59, 59); - return prizeTicketRepository.countByMemberIdAndCreatedAtBetween( - memberId, startOfDay, endOfDay); + return prizeTicketRepository.countByMemberIdAndCreatedAtBetweenAndSource( + memberId, startOfDay, endOfDay, PrizeTicketSource.SHARE); } public List findPrizeTicketByMemberIdAndStatus( final Long memberId, final PrizeTicketStatus status, final int count) { return prizeTicketRepository.findByMemberIdAndStatus(memberId, status, count); } + + public boolean existsByMemberIdAndSource(Long memberId, PrizeTicketSource prizeTicketSource) { + return prizeTicketRepository.existsByMemberIdAndSource(memberId, prizeTicketSource); + } }