Skip to content

Commit

Permalink
Feat/#112/단축 url 로직 수정, 1등 추첨 로직 추가 (#116)
Browse files Browse the repository at this point in the history
* [feat] RandomUtis getPositiveNumber 메서드 생성

1~max까지의 값을 반환하는 메서드 생성

* [feat] 1등 추첨 시 에러 처리를 위한 에러 코드 추가

* [feat] 1등 추첨 응답을 위한 response 클래스 생성

* [feat] 1등 추첨 응답을 위한 service 클래스 생성

날짜 및 회원 정보 조회 검사 후 추첨 진행
날짜가 유효하지 않을 시 추첨 불가능

* [docs] TopPrizeWinnerSerivce jacoco 문서 추가

* [feat] 1등 추첨 시 검사를 위한 에러코드 추가

* [feat] 1등 추첨 api 추가

* [docs] javadoc 문서 미비한 부분 수정

* [feat] originalUrl 반환하는 응답 클래스

* [feat] 변환된 응답 타입을 이용한 서비스 로직 수정

* [feat] 변환된 응답 타입을 이용한 컨트롤러 로직 수정
  • Loading branch information
gichan222 authored Aug 20, 2024
1 parent 9999377 commit 60fb2da
Show file tree
Hide file tree
Showing 14 changed files with 172 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
import lombok.RequiredArgsConstructor;
import softeer.team_pineapple_be.domain.admin.request.EventScheduleUpdateRequest;
import softeer.team_pineapple_be.domain.admin.response.EventScheduleResponse;
import softeer.team_pineapple_be.domain.admin.response.TopPrizeWinnerResponse;
import softeer.team_pineapple_be.domain.admin.service.EventDayInfoService;
import softeer.team_pineapple_be.domain.admin.service.TopPrizeWinnerService;
import softeer.team_pineapple_be.domain.draw.request.DrawDailyMessageModifyRequest;
import softeer.team_pineapple_be.domain.draw.request.DrawPrizeRequest;
import softeer.team_pineapple_be.domain.draw.request.DrawProbabilityRequest;
Expand Down Expand Up @@ -53,6 +55,7 @@ public class AdminController {
private final QuizHistoryService quizHistoryService;
private final EventDayInfoService eventDayInfoService;
private final DrawHistoryService drawHistoryService;
private final TopPrizeWinnerService topPrizeWinnerService;

@Operation(summary = "날짜에 해당하는 퀴즈 정보 가져오기")
@GetMapping("/quiz/{day}")
Expand Down Expand Up @@ -178,4 +181,10 @@ public ResponseEntity<DrawHistoryPageResponse> getDrawHistory(
return ResponseEntity.ok(drawHistoryService.getDrawHistory(page, limit, sort));

}

@Operation(summary = "1등 추첨")
@GetMapping("/topPrizeWinner")
public ResponseEntity<TopPrizeWinnerResponse> getTopPrizeWinner(){
return ResponseEntity.ok(topPrizeWinnerService.getTopPrizeWinner());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
public enum AdminErrorCode implements ErrorCode {
NOT_EVENT_DAY(HttpStatus.BAD_REQUEST, "이벤트 기간이 아닙니다."),
NOT_ZIP_FILE(HttpStatus.BAD_REQUEST, "집 파일 형식이 아닙니다."),
SAVE_FAILURE(HttpStatus.BAD_REQUEST, "저장 중 에러가 발생했습니다");
SAVE_FAILURE(HttpStatus.BAD_REQUEST, "저장 중 에러가 발생했습니다"),
CAN_NOT_DRAW_TOP_PRIZE_WINNER(HttpStatus.BAD_REQUEST, "1등 추첨 가능 날짜가 아닙니다.");

private final HttpStatus httpStatus;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package softeer.team_pineapple_be.domain.admin.response;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
* 1등 응답을 위한 response클래스
*/
@Getter
@AllArgsConstructor
public class TopPrizeWinnerResponse {
private String phoneNumber;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package softeer.team_pineapple_be.domain.admin.service;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import softeer.team_pineapple_be.domain.admin.domain.EventDayInfo;
import softeer.team_pineapple_be.domain.admin.exception.AdminErrorCode;
import softeer.team_pineapple_be.domain.admin.repisotory.EventDayInfoRepository;
import softeer.team_pineapple_be.domain.admin.response.TopPrizeWinnerResponse;
import softeer.team_pineapple_be.domain.draw.domain.DrawHistory;
import softeer.team_pineapple_be.domain.draw.domain.DrawRewardInfo;
import softeer.team_pineapple_be.domain.draw.exception.DrawErrorCode;
import softeer.team_pineapple_be.domain.draw.repository.DrawHistoryRepository;
import softeer.team_pineapple_be.domain.draw.repository.DrawRewardInfoRepository;
import softeer.team_pineapple_be.global.common.utils.RandomUtils;
import softeer.team_pineapple_be.global.exception.RestApiException;

import java.time.LocalDate;

/**
* 1등 추첨을 위한 클래스
*/
@Service
@RequiredArgsConstructor
public class TopPrizeWinnerService {

private final EventDayInfoRepository eventDayInfoRepository;
private final DrawHistoryRepository drawHistoryRepository;
private final DrawRewardInfoRepository drawRewardInfoRepository;

private static final int SCHEDULE_LENGTH = 14;
private static final byte TOP_PRIZE_REWARD_ID = 1;

/**
* 1등을 추첨하는 메서드
* @return 1등 당첨된 유저에 대한 핸드폰 번호를 담고있는 객체
*/
@Transactional
public TopPrizeWinnerResponse getTopPrizeWinner() {
validateDrawDate();

long totalCount = drawHistoryRepository.count();
Long topPrizeIndex = RandomUtils.getPositiveNumber(totalCount);

DrawHistory drawHistory = findDrawHistoryById(topPrizeIndex);
DrawRewardInfo drawRewardInfo = findDrawRewardInfoById(TOP_PRIZE_REWARD_ID);

processReward(drawRewardInfo);
saveTopPrizeDrawHistory(drawHistory);

return new TopPrizeWinnerResponse(drawHistory.getPhoneNumber());
}

private void validateDrawDate() {
EventDayInfo eventDayInfo = eventDayInfoRepository.findById(SCHEDULE_LENGTH)
.orElseThrow(() -> new RestApiException(AdminErrorCode.NOT_EVENT_DAY));

LocalDate drawDate = LocalDate.now();
if (!drawDate.isAfter(eventDayInfo.getEventDate())) {
throw new RestApiException(AdminErrorCode.CAN_NOT_DRAW_TOP_PRIZE_WINNER);
}
}

private DrawHistory findDrawHistoryById(Long id) {
return drawHistoryRepository.findById(id)
.orElseThrow(() -> new RestApiException(DrawErrorCode.NOT_VALID_WINNER));
}

private DrawRewardInfo findDrawRewardInfoById(byte id) {
return drawRewardInfoRepository.findById(id)
.orElseThrow(() -> new RestApiException(DrawErrorCode.NO_PRIZE));
}

private void processReward(DrawRewardInfo drawRewardInfo) {
if (drawRewardInfo.getStock() <= 0) {
throw new RestApiException(DrawErrorCode.NO_PRIZE);
}
drawRewardInfo.decreaseStock();
drawRewardInfoRepository.save(drawRewardInfo);
}

private void saveTopPrizeDrawHistory(DrawHistory drawHistory) {
DrawHistory topPrizeDrawHistory = new DrawHistory(TOP_PRIZE_REWARD_ID, drawHistory.getPhoneNumber());
drawHistoryRepository.save(topPrizeDrawHistory);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public enum DrawErrorCode implements ErrorCode {
NOT_PRIZE_OWNER(HttpStatus.BAD_REQUEST, " 해당 상품의 당첨자가 아닙니다."),
NOT_VALID_DATE(HttpStatus.BAD_REQUEST, "상품 추첨이 가능하지 않은 날짜입니다."),
NO_DAILY_INFO(HttpStatus.BAD_REQUEST, "일자별 응모 정보가 존재하지 않습니다"),
NOT_VALID_WINNER(HttpStatus.BAD_REQUEST, "유효하지 않은 당첨자입니다."),
DAILY_INFO_WIN_IMAGE_UPLOAD_FAILED(HttpStatus.BAD_REQUEST, "응모 성공 이미지 업로드에 실패했습니다."),
DAILY_INFO_LOSE_IMAGE_UPLOAD_FAILED(HttpStatus.BAD_REQUEST, "응모 실패 이미지 업로드에 실패했습니다."),
NO_PRIZE_PROBABILITY(HttpStatus.BAD_REQUEST, "확률 정보가 존재하지 않습니다.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import java.util.HashMap;
import java.util.Map;

/**
* 멀티파트 파일으로 형변환을 해주는 클래스
*/
@RequiredArgsConstructor
public class MultipartFileWrapper implements MultipartFile {
private final InputStream inputStream;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
import java.util.ArrayList;
import java.util.List;

/**
* S3 파일 삭제를 담당하는 클래스
*/
@RequiredArgsConstructor
@Service
public class S3DeleteService {
Expand All @@ -21,6 +24,10 @@ public class S3DeleteService {
@Value("${cloud.aws.s3.bucket}")
private String bucket;

/**
* folder경로에 대한 전체 삭제
* @param folderName 삭제하고자 하는 폴더명
*/
public void deleteFolder(String folderName) {
ListObjectsV2Request request = new ListObjectsV2Request()
.withBucketName(bucket)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ public Integer getSecureRandomNumberLessThen(int max) {
}

public Integer getBase56Index(){return secureRandom.nextInt(0,56);}

public Long getPositiveNumber(long max){ return secureRandom.nextLong(1,max+1);}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
* cors 오류를 해결 설정
*/
@Configuration
public class CorsMvcConfig implements WebMvcConfigurer {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package softeer.team_pineapple_be.global.shortenurl.controller;

import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -8,12 +10,19 @@
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RestController;
import softeer.team_pineapple_be.global.auth.annotation.Auth;
import softeer.team_pineapple_be.global.shortenurl.response.ShortenOriginalUrlResponse;
import softeer.team_pineapple_be.global.shortenurl.response.ShortenUrlResponse;
import softeer.team_pineapple_be.global.shortenurl.service.ShortenUrlService;

import java.io.IOException;

/**
* 단축 url 요청을 처리하는 클래스
*/
@Tag(name = "단축 URL API", description = "단축 URL 처리")
@Controller
@RestController
@RequiredArgsConstructor
public class ShortenUrlController {

Expand All @@ -28,8 +37,7 @@ public ResponseEntity<ShortenUrlResponse> getShortenUrl() {

@Operation(summary = "단축 URL을 통해 원본 URL로 리다이렉트")
@GetMapping("/redirect/{shortenUrl}")
public String redirectShortenUrl(@PathVariable String shortenUrl) {
String redirectUrl = shortenUrlService.redirectUrl(shortenUrl);
return "redirect:" + redirectUrl;
public ResponseEntity<ShortenOriginalUrlResponse> redirectShortenUrl(@PathVariable String shortenUrl) {
return ResponseEntity.ok(shortenUrlService.redirectUrl(shortenUrl));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import softeer.team_pineapple_be.global.exception.ErrorCode;
import org.springframework.http.HttpStatus;

/**
* 단축 url 에러 코드
*/
@Getter
@RequiredArgsConstructor
public enum ShortenUrlErrorCode implements ErrorCode {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

import java.util.Optional;

/**
* 단축 url 관련 정보를 담당하는 레포지토리
*/
public interface ShortenUrlRepository extends JpaRepository<ShortenUrl, Long> {
Optional<ShortenUrl> findByShortenUrl(String shortenUrl);
Optional<ShortenUrl> findByOriginalUrl(String originalUrl);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package softeer.team_pineapple_be.global.shortenurl.response;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
* original url을 응답하는 클래스
*/
@Getter
@AllArgsConstructor
public class ShortenOriginalUrlResponse {
private String originalUrl;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@
import softeer.team_pineapple_be.global.shortenurl.domain.ShortenUrl;
import softeer.team_pineapple_be.global.shortenurl.exception.ShortenUrlErrorCode;
import softeer.team_pineapple_be.global.shortenurl.repository.ShortenUrlRepository;
import softeer.team_pineapple_be.global.shortenurl.response.ShortenOriginalUrlResponse;
import softeer.team_pineapple_be.global.shortenurl.response.ShortenUrlResponse;

/**
* 단축 url 처리를 담당하는 클래스
*/
@Service
@RequiredArgsConstructor
public class ShortenUrlService {
Expand All @@ -31,6 +35,10 @@ public class ShortenUrlService {
private final CommentRepository commentRepository;
private final AuthMemberService authMemberService;

/**
* 단축 url을 생성해주는 메서드
* @return 생성된 단축 url
*/
@Transactional
public ShortenUrlResponse getShortenUrl() {
Comment comment = findTodayComment();
Expand All @@ -41,12 +49,17 @@ public ShortenUrlResponse getShortenUrl() {
.orElseGet(() -> new ShortenUrlResponse(generateAndSaveShortenUrl(originalUrl)));
}

/**
* 단축 url이 들어왔을 때 원본 url을 반환하는 메서드
* @param shortenUrl 요청된 단축 url
* @return 반환하고자 하는 url
*/
@Transactional
public String redirectUrl(String shortenUrl) {
public ShortenOriginalUrlResponse redirectUrl(String shortenUrl) {
ShortenUrl shortenUrlEntity = shortenUrlRepository.findByShortenUrl(shortenUrl)
.orElseThrow(
() -> new RestApiException(ShortenUrlErrorCode.NOT_EXISTS));
return shortenUrlEntity.getOriginalUrl();
return new ShortenOriginalUrlResponse(shortenUrlEntity.getOriginalUrl());
}

private String buildOriginalUrl(Long commentId) {
Expand Down

0 comments on commit 60fb2da

Please sign in to comment.