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

Api-v1.0.2-4 #540

Merged
merged 3 commits into from
Mar 8, 2023
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 @@ -2,8 +2,8 @@


import band.gosrock.api.alimTalk.dto.OrderAlimTalkDto;
import band.gosrock.api.alimTalk.service.helper.NcpHelper;
import band.gosrock.domain.common.alarm.OrderKakaoTalkAlarm;
import band.gosrock.infrastructure.config.alilmTalk.NcpHelper;
import band.gosrock.infrastructure.config.alilmTalk.dto.AlimTalkEventInfo;
import band.gosrock.infrastructure.config.alilmTalk.dto.AlimTalkOrderInfo;
import band.gosrock.infrastructure.config.alilmTalk.dto.AlimTalkUserInfo;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package band.gosrock.api.alimTalk.service;


import band.gosrock.api.alimTalk.service.helper.NcpHelper;
import band.gosrock.domain.common.alarm.UserKakaoTalkAlarm;
import band.gosrock.infrastructure.config.alilmTalk.NcpHelper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@


import band.gosrock.api.alimTalk.dto.OrderAlimTalkDto;
import band.gosrock.api.alimTalk.service.helper.NcpHelper;
import band.gosrock.domain.common.alarm.OrderKakaoTalkAlarm;
import band.gosrock.infrastructure.config.alilmTalk.NcpHelper;
import band.gosrock.infrastructure.config.alilmTalk.dto.AlimTalkEventInfo;
import band.gosrock.infrastructure.config.alilmTalk.dto.AlimTalkOrderInfo;
import band.gosrock.infrastructure.config.alilmTalk.dto.AlimTalkUserInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.bucket4j.Bucket;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
Expand All @@ -26,17 +28,28 @@ public class ThrottlingInterceptor implements HandlerInterceptor {
private final IPRateLimiter ipRateLimiter;
private final ObjectMapper objectMapper;

@Value("${acl.whiteList}")
private List<String> aclWhiteList;

private final SlackThrottleErrorSender slackThrottleErrorSender;

@Override
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response, Object handler)
throws IOException {
Long userId = SecurityUtils.getCurrentUserId();
String remoteAddr = request.getRemoteAddr();
log.info("remoteAddr : " + remoteAddr);

// next js ssr 대응
if (aclWhiteList.contains(remoteAddr)) {
log.info("white List pass" + remoteAddr);
return true;
}

Bucket bucket;
if (userId == 0L) {
// 익명 유저 ip 기반처리
String remoteAddr = request.getRemoteAddr();
bucket = ipRateLimiter.resolveBucket(remoteAddr);
} else {
// 비 익명 유저 유저 아이디 기반 처리
Expand Down
2 changes: 2 additions & 0 deletions DuDoong-Api/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ swagger:
throttle:
overdraft: ${RATE_LIMIT_OVERDRAFT:60}
greedyRefill: ${RATE_LIMIT_REFILL:60}

acl.whiteList : ${ACL_WHITELIST:127.0.0.1,127.0.0.2}
---
spring:
config:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package band.gosrock.job;


import band.gosrock.domain.common.alarm.SettlementKakaoTalkAlarm;
import band.gosrock.domain.domains.event.adaptor.EventAdaptor;
import band.gosrock.domain.domains.event.domain.Event;
import band.gosrock.domain.domains.host.adaptor.HostAdaptor;
import band.gosrock.domain.domains.host.domain.Host;
import band.gosrock.domain.domains.user.adaptor.UserAdaptor;
import band.gosrock.domain.domains.user.domain.User;
import band.gosrock.infrastructure.config.alilmTalk.NcpHelper;
import band.gosrock.parameter.EventJobParameter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Slf4j
@RequiredArgsConstructor
@Configuration
public class EventSettlementAlimTalkToHost {

private static final String JOB_NAME = "이벤트정산_알림톡발송_호스트";
private static final String BEAN_PREFIX = JOB_NAME + "_";

private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
private final EventAdaptor eventAdaptor;
private final HostAdaptor hostAdaptor;
private final UserAdaptor userAdaptor;
private final NcpHelper ncpHelper;

@Bean(BEAN_PREFIX + "eventJobParameter")
@JobScope
public EventJobParameter eventJobParameter() {
return new EventJobParameter(eventAdaptor);
}

@Qualifier(BEAN_PREFIX + "eventJobParameter")
private final EventJobParameter eventJobParameter;

@Bean(JOB_NAME)
public Job slackUserStatisticJob() {
return jobBuilderFactory.get(JOB_NAME).preventRestart().start(eventSettlement()).build();
}

@Bean(BEAN_PREFIX + "step")
@JobScope
public Step eventSettlement() {
return stepBuilderFactory
.get(BEAN_PREFIX + "step")
.tasklet(
(contribution, chunkContext) -> {
log.info(">>>>> 정산서 전송 안내 알림톡 스탭");
Event event = eventJobParameter.getEvent();
Host host = hostAdaptor.findById(event.getHostId());
User masterUser = userAdaptor.queryUser(host.getMasterUserId());

String to =
masterUser
.getProfile()
.getPhoneNumberVo()
.getNaverSmsToNumber();
String content =
SettlementKakaoTalkAlarm.creationOf(
masterUser.getProfile().getName());

ncpHelper.sendSettlementNcpAlimTalk(
to,
SettlementKakaoTalkAlarm.creationTemplateCode(),
content,
SettlementKakaoTalkAlarm.creationHeaderOf(),
masterUser.getProfile().getEmail(),
event.getEventBasic().getName());
return RepeatStatus.FINISHED;
})
.build();
}
}
1 change: 0 additions & 1 deletion DuDoong-Batch/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ spring:
- common
batch.job.names: ${job.name:NONE}


---
spring:
config:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package band.gosrock.domain.common.alarm;


import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class SettlementKakaoTalkAlarm {

public static String creationOf(String hostName) {
return "안녕하세요 " + hostName + "님!\n" + "이메일로 정산서 발송이 완료되어 안내드립니다.";
}

public static String creationHeaderOf() {
return "정산서 이메일 발송 안내";
}

public static String creationTemplateCode() {
return "settlement";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ public Object lock(final ProceedingJoinPoint joinPoint) throws Throwable {
try {
rLock.unlock();
} catch (IllegalMonitorStateException e) {
rLock.forceUnlock();
log.error(e + baseKey + dynamicKey);
throw e;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public void validItemStockEnough(Cart cart, TicketItem item) {

/** 이벤트가 현재 열려있는 상태인지 확인합니다. */
public void validEventIsOpen(Event event) {
event.validateStatusOpen();
event.validateNotOpenStatus();
}

/** 카트에 담길때 아이템이 한 종류인지 확인합니다. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ public Slice<Event> querySliceEventsByKeyword(String keyword, Pageable pageable)
return eventRepository.querySliceEventsByKeyword(keyword, pageable);
}

public List<Event> queryEventsByEndAtBefore(LocalDateTime time) {
return eventRepository.queryEventsByEndAtBefore(time);
public List<Event> queryEventsByEndAtBeforeAndStatusOpen(LocalDateTime time) {
return eventRepository.queryEventsByEndAtBeforeAndStatusOpen(time);
}

public List<Event> findAllByIds(List<Long> ids) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,16 @@ public Event(Long hostId, String name, LocalDateTime startAt, Long runTime) {
Events.raise(EventCreationEvent.of(hostId, name));
}

public void validateStartAt() {
if (this.getStartAt().isBefore(LocalDateTime.now()))
throw EventOpenTimeExpiredException.EXCEPTION;
}

public void validateOpenStatus() {
if (status == OPEN) throw CannotModifyOpenEventException.EXCEPTION;
// todo : 오픈 전과 후 검증 로직 이름 변경
}

public void validateStatusOpen() {
public void validateNotOpenStatus() {
if (status != OPEN) throw EventNotOpenException.EXCEPTION;
}

Expand Down Expand Up @@ -145,6 +149,7 @@ public void prepare() {
}

public void open() {
validateStartAt();
updateStatus(OPEN, AlreadyOpenStatusException.EXCEPTION);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public enum EventErrorCode implements BaseErrorCode {
ALREADY_DELETED_STATUS(BAD_REQUEST, "Event_400_12", "이미 삭제된 이벤트입니다."),
CANNOT_DELETE_BY_ISSUED_TICKET(BAD_REQUEST, "Event_400_13", "발급 티켓이 있는 이벤트는 삭제할 수 없습니다."),
CANNOT_DELETE_BY_OPEN_EVENT(BAD_REQUEST, "Event_400_14", "오픈 상태인 이벤트는 삭제할 수 없습니다."),
OPEN_TIME_EXPIRED(BAD_REQUEST, "Event_400_15", "오픈 예정 시간이 현재 시간보다 빠릅니다."),

USE_OTHER_API(BAD_REQUEST, "Event_400_8", "잘못된 접근입니다.");

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package band.gosrock.domain.domains.event.exception;


import band.gosrock.common.exception.DuDoongCodeException;

public class EventOpenTimeExpiredException extends DuDoongCodeException {

public static final DuDoongCodeException EXCEPTION = new EventOpenTimeExpiredException();

private EventOpenTimeExpiredException() {
super(EventErrorCode.OPEN_TIME_EXPIRED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ public interface EventCustomRepository {

Slice<Event> querySliceEventsByKeyword(String keyword, Pageable pageable);

List<Event> queryEventsByEndAtBefore(LocalDateTime time);
List<Event> queryEventsByEndAtBeforeAndStatusOpen(LocalDateTime time);
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ public Slice<Event> querySliceEventsByKeyword(String keyword, Pageable pageable)
}

@Override
public List<Event> queryEventsByEndAtBefore(LocalDateTime time) {
return queryFactory.selectFrom(event).where(endAtBefore(time), notEqClosed()).fetch();
public List<Event> queryEventsByEndAtBeforeAndStatusOpen(LocalDateTime time) {
return queryFactory.selectFrom(event).where(endAtBefore(time), statusEq(OPEN)).fetch();
}

private BooleanExpression hostIdIn(List<Long> hostId) {
Expand All @@ -83,8 +83,8 @@ private BooleanExpression statusEq(EventStatus status) {
return event.status.eq(status);
}

private BooleanExpression notEqClosed() {
return event.status.eq(CLOSED).not();
private BooleanExpression statusNotEq(EventStatus status) {
return event.status.eq(status).not();
}

private BooleanExpression nameContains(String keyword) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package band.gosrock.domain.domains.event.service;

import static band.gosrock.domain.domains.event.domain.QEvent.event;

import band.gosrock.common.annotation.DomainService;
import band.gosrock.domain.domains.event.adaptor.EventAdaptor;
Expand Down Expand Up @@ -71,7 +70,7 @@ public Event updateEventStatus(Event event, EventStatus status) {
}

public List<Event> closeExpiredEventsEndAtBefore(LocalDateTime time) {
List<Event> events = eventAdaptor.queryEventsByEndAtBefore(time);
List<Event> events = eventAdaptor.queryEventsByEndAtBeforeAndStatusOpen(time);
events.forEach(event -> updateEventStatus(event, EventStatus.CLOSED));
eventRepository.saveAll(events);
return events;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ public void validApproveStatePurchaseLimit(Order order) {

/** 이벤트가 열려있는 상태인지 */
public void validEventIsOpen(Event event) {
event.validateStatusOpen();
event.validateNotOpenStatus();
}

/** 아이템의 종류가 1종류인지. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ void setUp() {
@Test
public void 카트_티켓팅_이벤트_상태검증_성공() {
// given
willDoNothing().given(event).validateStatusOpen();
willDoNothing().given(event).validateNotOpenStatus();
// when
cartValidator.validEventIsOpen(event);
// then
Expand All @@ -109,7 +109,7 @@ void setUp() {
@Test
public void 카트_티켓팅_이벤트_상태검증_실패() {
// given
willThrow(EventNotOpenException.class).given(event).validateStatusOpen();
willThrow(EventNotOpenException.class).given(event).validateNotOpenStatus();
// when
// then
assertThrows(EventNotOpenException.class, () -> cartValidator.validEventIsOpen(event));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ void setup() {
@Test
void 이벤트_종료로_상태변경_테스트() {
// given
ReflectionTestUtils.setField(event, "status", EventStatus.OPEN);
final EventStatus originalStatus = event.getStatus();
final EventStatus expectedStatus = EventStatus.CLOSED;
// when
Expand All @@ -118,14 +119,30 @@ void setup() {
// given
final EventStatus originalStatus = event.getStatus();
final EventStatus expectedStatus = EventStatus.OPEN;
final LocalDateTime startAt = LocalDateTime.now().plusMinutes(1);
// when
when(eventBasic.getStartAt()).thenReturn(startAt);
event.setEventBasic(eventBasic);
event.open();
// then
assertEquals(expectedStatus, event.getStatus());
assertNotEquals(originalStatus, expectedStatus);
assertThrows(AlreadyOpenStatusException.class, () -> event.open());
}

@Test
void 오픈_시간_이전인_이벤트는_오픈할수_없음() {
// given
final EventStatus originalStatus = event.getStatus();
final LocalDateTime startAt = LocalDateTime.now().minusMinutes(1);
// when
when(eventBasic.getStartAt()).thenReturn(startAt);
event.setEventBasic(eventBasic);
// then
assertThrows(EventOpenTimeExpiredException.class, () -> event.open());
assertEquals(originalStatus, event.getStatus());
}

@Test
void 이벤트_준비중으로_상태변경_테스트() {
// given
Expand Down
Loading