Skip to content

Commit

Permalink
Batch-v1.0.2
Browse files Browse the repository at this point in the history
Batch-v1.0.2
  • Loading branch information
ImNM authored Mar 6, 2023
2 parents bb7d662 + 0b2f291 commit f2a7828
Show file tree
Hide file tree
Showing 15 changed files with 279 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import band.gosrock.api.auth.service.RefreshUseCase;
import band.gosrock.api.auth.service.RegisterUseCase;
import band.gosrock.api.auth.service.WithDrawUseCase;
import band.gosrock.api.auth.service.helper.CookieGenerateHelper;
import band.gosrock.api.auth.service.helper.CookieHelper;
import band.gosrock.api.config.rateLimit.UserRateLimiter;
import band.gosrock.common.annotation.ApiErrorCodeExample;
import band.gosrock.common.annotation.DevelopOnlyApi;
Expand All @@ -26,6 +26,7 @@
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -52,7 +53,7 @@ public class AuthController {
private final WithDrawUseCase withDrawUseCase;
private final LogoutUseCase logoutUseCase;

private final CookieGenerateHelper cookieGenerateHelper;
private final CookieHelper cookieHelper;

private final UserRateLimiter rateLimiter;

Expand Down Expand Up @@ -117,7 +118,7 @@ public OauthTokenResponse getCredentialFromKaKao(
public ResponseEntity<TokenAndUserResponse> developUserSign(@RequestParam("code") String code) {
TokenAndUserResponse tokenAndUserResponse = registerUseCase.upsertKakaoOauthUser(code);
return ResponseEntity.ok()
.headers(cookieGenerateHelper.getTokenCookies(tokenAndUserResponse))
.headers(cookieHelper.getTokenCookies(tokenAndUserResponse))
.body(tokenAndUserResponse);
}

Expand All @@ -138,7 +139,7 @@ public ResponseEntity<TokenAndUserResponse> kakaoAuthCheckRegisterValid(
TokenAndUserResponse tokenAndUserResponse =
registerUseCase.registerUserByOCIDToken(token, registerRequest);
return ResponseEntity.ok()
.headers(cookieGenerateHelper.getTokenCookies(tokenAndUserResponse))
.headers(cookieHelper.getTokenCookies(tokenAndUserResponse))
.body(tokenAndUserResponse);
}

Expand All @@ -150,7 +151,7 @@ public ResponseEntity<TokenAndUserResponse> kakaoOauthUserLogin(
@RequestParam("id_token") String token) {
TokenAndUserResponse tokenAndUserResponse = loginUseCase.execute(token);
return ResponseEntity.ok()
.headers(cookieGenerateHelper.getTokenCookies(tokenAndUserResponse))
.headers(cookieHelper.getTokenCookies(tokenAndUserResponse))
.body(tokenAndUserResponse);
}

Expand All @@ -164,24 +165,33 @@ public OauthUserInfoResponse kakaoOauthUserInfo(

@Operation(summary = "refreshToken 용입니다.")
@PostMapping("/token/refresh")
public ResponseEntity<TokenAndUserResponse> tokenRefresh(@RequestParam("token") String code) {
TokenAndUserResponse tokenAndUserResponse = refreshUseCase.execute(code);
public ResponseEntity<TokenAndUserResponse> tokenRefresh(
@CookieValue(value = "refreshToken", required = false) String refreshTokenCookie,
@RequestParam(value = "token", required = false, defaultValue = "")
String refreshToken) {

// 쿠키 우선시해서 리프레쉬.
TokenAndUserResponse tokenAndUserResponse =
refreshUseCase.execute(
refreshTokenCookie != null ? refreshTokenCookie : refreshToken);
return ResponseEntity.ok()
.headers(cookieGenerateHelper.getTokenCookies(tokenAndUserResponse))
.headers(cookieHelper.getTokenCookies(tokenAndUserResponse))
.body(tokenAndUserResponse);
}

@Operation(summary = "회원탈퇴를 합니다.")
@SecurityRequirement(name = "access-token")
@DeleteMapping("/me")
public void withDrawUser() {
public ResponseEntity withDrawUser() {
withDrawUseCase.execute();
return ResponseEntity.ok().headers(cookieHelper.deleteCookies()).body(null);
}

@Operation(summary = "로그아웃을 합니다.")
@SecurityRequirement(name = "access-token")
@PostMapping("/logout")
public void logoutUser() {
public ResponseEntity logoutUser() {
logoutUseCase.execute();
return ResponseEntity.ok().headers(cookieHelper.deleteCookies()).body(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

@Helper
@RequiredArgsConstructor
public class CookieGenerateHelper {
public class CookieHelper {
private final SpringEnvironmentHelper springEnvironmentHelper;

public HttpHeaders getTokenCookies(TokenAndUserResponse tokenAndUserResponse) {
Expand Down Expand Up @@ -41,4 +41,33 @@ public HttpHeaders getTokenCookies(TokenAndUserResponse tokenAndUserResponse) {
httpHeaders.add(HttpHeaders.SET_COOKIE, refreshToken.toString());
return httpHeaders;
}

public HttpHeaders deleteCookies() {
String sameSite = "None";

if (springEnvironmentHelper.isProdProfile()) {
sameSite = "Strict";
}

ResponseCookie accessToken =
ResponseCookie.from("accessToken", null)
.path("/")
.maxAge(0)
.sameSite(sameSite)
// .httpOnly(true)
.secure(true)
.build();
ResponseCookie refreshToken =
ResponseCookie.from("refreshToken", null)
.path("/")
.maxAge(0)
.sameSite(sameSite)
// .httpOnly(true)
.secure(true)
.build();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(HttpHeaders.SET_COOKIE, accessToken.toString());
httpHeaders.add(HttpHeaders.SET_COOKIE, refreshToken.toString());
return httpHeaders;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
Expand All @@ -16,6 +17,7 @@
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.WebUtils;

@RequiredArgsConstructor
@Component
Expand All @@ -38,6 +40,12 @@ protected void doFilterInternal(
}

private String resolveToken(HttpServletRequest request) {
// 쿠키방식 지원
Cookie accessTokenCookie = WebUtils.getCookie(request, "accessToken");
if (accessTokenCookie != null) {
return accessTokenCookie.getValue();
}
// 기존 jwt 방식 지원
String rawHeader = request.getHeader(DuDoongStatic.AUTH_HEADER);

if (rawHeader != null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ public class TicketItemResponse {
@Schema(description = "재고가 감소한 티켓인지 리턴")
private final Boolean isSold;

@Schema(description = "재고가 남아있는지 리턴")
private final Boolean isQuantityLeft;

public static TicketItemResponse from(TicketItem ticketItem, Boolean isAdmin) {

return TicketItemResponse.builder()
Expand All @@ -67,6 +70,7 @@ public static TicketItemResponse from(TicketItem ticketItem, Boolean isAdmin) {
.isQuantityPublic(ticketItem.getIsQuantityPublic())
.accountInfo(ticketItem.getAccountInfo())
.isSold(ticketItem.isSold())
.isQuantityLeft(ticketItem.isQuantityLeft())
.build();
}
}
65 changes: 65 additions & 0 deletions DuDoong-Batch/src/main/java/band/gosrock/job/EventExpiration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package band.gosrock.job;


import band.gosrock.domain.domains.event.domain.Event;
import band.gosrock.domain.domains.event.service.EventService;
import band.gosrock.parameter.DateTimeJobParameter;
import band.gosrock.slack.SlackEventExpirationSender;
import java.time.LocalDateTime;
import java.util.List;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Slf4j
@RequiredArgsConstructor
@Configuration
public class EventExpiration {

private static final String JOB_NAME = "이벤트_자동만료";
private static final String BEAN_PREFIX = JOB_NAME + "_";

private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;

private final SlackEventExpirationSender slackEventExpirationSender;
private final EventService eventService;

@Bean(BEAN_PREFIX + "dateTimeJobParameter")
@JobScope
public DateTimeJobParameter dateTimeJobParameter() {
return new DateTimeJobParameter();
}

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

@Bean(BEAN_PREFIX + "step")
@JobScope
public Step eventExpirationStep() {
return stepBuilderFactory
.get(BEAN_PREFIX + "step")
.tasklet(
(contribution, chunkContext) -> {
log.info(">>>>> 이벤트 자동 만료 작업 실행");
LocalDateTime time = dateTimeJobParameter().getTime();
List<Event> events = eventService.closeExpiredEventsEndAtBefore(time);
slackEventExpirationSender.execute(time, events);
return RepeatStatus.FINISHED;
})
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import band.gosrock.domain.domains.user.adaptor.UserAdaptor;
import band.gosrock.parameter.DateJobParameter;
import band.gosrock.slack.SlackSender;
import band.gosrock.slack.SlackUserNotificationSender;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
Expand All @@ -28,7 +28,7 @@ public class SlackUserStatistic {

private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
private final SlackSender slackSender;
private final SlackUserNotificationSender slackSender;

private final UserAdaptor userAdaptor;
private final DateJobParameter dateJobParameter;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package band.gosrock.parameter;


import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.beans.factory.annotation.Value;

@Getter
@NoArgsConstructor
public class DateTimeJobParameter {
private LocalDateTime time;

@Value("#{jobParameters[dateTime]}")
public void setDateTime(String dateTime) throws JobParametersInvalidException {
// 인자가 없다면 now 로 설정
if (Objects.isNull(dateTime)) this.time = LocalDateTime.now();
else {
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
this.time = LocalDateTime.parse(dateTime, formatter);
} catch (Exception e) {
throw new JobParametersInvalidException("올바르지 않은 시간 형식입니다");
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package band.gosrock.slack;

import static com.slack.api.model.block.Blocks.divider;
import static com.slack.api.model.block.Blocks.section;
import static com.slack.api.model.block.composition.BlockCompositions.plainText;

import band.gosrock.domain.domains.event.domain.Event;
import band.gosrock.infrastructure.config.slack.SlackServiceNotificationProvider;
import com.slack.api.model.block.Blocks;
import com.slack.api.model.block.LayoutBlock;
import com.slack.api.model.block.composition.MarkdownTextObject;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
@Slf4j
public class SlackEventExpirationSender {
private final SlackServiceNotificationProvider slackProvider;

public void execute(LocalDateTime time, List<Event> events) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
List<LayoutBlock> layoutBlocks = new ArrayList<>();

layoutBlocks.add(
Blocks.header(
headerBlockBuilder -> headerBlockBuilder.text(plainText("공연 자동 만료 알림"))));
layoutBlocks.add(divider());
MarkdownTextObject markdownDateTime =
MarkdownTextObject.builder().text("* 기준 시간:*\n" + time.format(formatter)).build();
MarkdownTextObject markdownTotalEvents =
MarkdownTextObject.builder().text("* 만료 공연 수:*\n" + events.size()).build();
layoutBlocks.add(
section(section -> section.fields(List.of(markdownDateTime, markdownTotalEvents))));
layoutBlocks.add(divider());

MarkdownTextObject markdownEventIdTitle =
MarkdownTextObject.builder().text("* 공연 ID:*\n").build();
MarkdownTextObject markdownEventNameTitle =
MarkdownTextObject.builder().text("* 공연 이름:*\n").build();
layoutBlocks.add(
section(
section ->
section.fields(
List.of(markdownEventIdTitle, markdownEventNameTitle))));

events.forEach(
event -> {
MarkdownTextObject markdownEventId =
MarkdownTextObject.builder().text(event.getId().toString()).build();
MarkdownTextObject markdownEventName =
MarkdownTextObject.builder()
.text(event.getEventBasic().getName())
.build();
layoutBlocks.add(
section(
section ->
section.fields(
List.of(markdownEventId, markdownEventName))));
});

slackProvider.sendNotification(layoutBlocks);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
@Component
@RequiredArgsConstructor
@Slf4j
public class SlackSender {
public class SlackUserNotificationSender {
private final SlackServiceNotificationProvider slackProvider;

public void execute(LocalDate date, Long todayUserCount, Long yesterdayCount) {
Expand Down
Loading

0 comments on commit f2a7828

Please sign in to comment.