Skip to content

Commit

Permalink
Merge pull request #24 from KUSITMS-Team-A/feature/21-popup
Browse files Browse the repository at this point in the history
[#21] Feature:  팝업 기능 추가
  • Loading branch information
pdohyung authored Nov 21, 2023
2 parents e949f1b + 244d39a commit a8c89b0
Show file tree
Hide file tree
Showing 14 changed files with 400 additions and 22 deletions.
29 changes: 29 additions & 0 deletions src/main/java/com/backend/common/dto/PageResponseDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.backend.common.dto;

import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import java.util.List;

public record PageResponseDto<T>(
List<T> content,
long totalElements,
int totalPages,
int pageNumber,
int numberOfElements,
boolean hasNextPages
) {

public static <T> ResponseEntity<PageResponseDto> of(Page<T> page) {
return ResponseEntity.status(HttpStatus.OK)
.body(new PageResponseDto<>(
page.getContent(),
page.getTotalElements(),
page.getTotalPages(),
page.getNumber(),
page.getNumberOfElements(),
page.hasNext()
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
import com.backend.domain.auth.dto.LoginUser;
import com.backend.domain.auth.dto.request.JoinRequestDto;
import com.backend.domain.auth.dto.request.LoginRequestDto;
import com.backend.error.dto.ErrorResponse;
import com.backend.jwt.token.AccessToken;
import com.backend.jwt.token.RefreshToken;
import com.backend.jwt.token.Token;
import com.backend.domain.auth.service.AuthService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
Expand All @@ -36,7 +36,7 @@ public class AuthController {
@Operation(summary = "로그인", description = "로그인을 합니다.",
responses = {
@ApiResponse(responseCode = "200", description = "로그인 성공",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
content = @Content(schema = @Schema(implementation = String.class)))
})
@PostMapping("/login")
public ResponseEntity<String> signIn(@RequestBody @Valid LoginRequestDto loginDto, HttpServletResponse response) {
Expand All @@ -54,7 +54,7 @@ public ResponseEntity<String> signIn(@RequestBody @Valid LoginRequestDto loginDt
@ApiResponse(responseCode = "400", description = "이미 존재하는 이메일입니다."),
@ApiResponse(responseCode = "400", description = "잘못된 그룹 종류입니다. " +
"type에 총학생회, 단과대학생회, 과학생회만 입력할 수 있습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
content = @Content(schema = @Schema(implementation = String.class)))
})
@PostMapping("/join")
public ResponseEntity<String> signUp(@RequestBody @Valid JoinRequestDto joinDto) {
Expand All @@ -66,12 +66,12 @@ public ResponseEntity<String> signUp(@RequestBody @Valid JoinRequestDto joinDto)
@Operation(summary = "토큰 재발급", description = "401에러가 발생한 경우 (AccessToken이 만료된 경우) 토큰을 재발급합니다.",
responses = {
@ApiResponse(responseCode = "204", description = "토큰 재발급 성공",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
content = @Content(schema = @Schema(implementation = String.class)))
})
@PostMapping("/reissue")
public ResponseEntity<String> reissueToken(@CookieValue(name = "Authorization-refresh") String refreshToken,
public ResponseEntity<String> reissueToken(@Parameter @CookieValue(name = "Authorization-refresh") String refreshToken,
HttpServletResponse response) {
log.info("재발급 토큰 = {}", refreshToken);
log.info("기존 토큰 = {}", refreshToken);
Token token = authService.reissue(
RefreshToken.builder()
.header("Authorization-refresh")
Expand All @@ -81,17 +81,17 @@ public ResponseEntity<String> reissueToken(@CookieValue(name = "Authorization-re

setAccessToken(response, token.getAccessToken());
setRefreshToken(response, token.getRefreshToken());

log.info("재발급 토큰 = {}", token.getRefreshToken().getData());
return ResponseDto.created("토큰 재발급 성공");
}

@Operation(summary = "로그아웃", description = "로그아웃을 합니다.",
responses = {
@ApiResponse(responseCode = "204", description = "로그아웃 성공, AccessToken이 필요합니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
content = @Content(schema = @Schema(implementation = String.class)))
})
@PostMapping("/logout")
public ResponseEntity<String> logout(@Login LoginUser loginUser, HttpServletResponse response) {
public ResponseEntity<String> logout(@Login @Schema(hidden = true) LoginUser loginUser, HttpServletResponse response) {
authService.logout(loginUser);
log.info("이메일: {}", loginUser.getEmail());
removeCookie(response);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.backend.domain.contract.repository;

import com.backend.domain.contract.entity.Contract;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.Optional;

public interface ContractRepository extends JpaRepository<Contract, Long> {

@Query("SELECT c FROM Contract c JOIN c.university u JOIN u.user user " +
"WHERE user.id = :userId AND c.store.storeId = :storeId")
Optional<Contract> findContractByUserIdAndStoreId(@Param("userId") Long userId, @Param("storeId") Long storeId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.backend.domain.mail.dto.request.SmsRequest;
import com.backend.domain.mail.service.MailService;
import com.backend.error.ErrorCode;
import com.backend.error.dto.ErrorResponse;
import com.backend.error.exception.custom.BusinessException;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -27,7 +26,7 @@ public class MailController {
@Operation(summary = "메일 인증 코드 전송", description = "입력한 메일에 인증 코드를 전송합니다. 형식: [email protected]",
responses = {
@ApiResponse(responseCode = "200", description = "인증 코드 전송 성공, 보낸 인증 코드를 반환합니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
content = @Content(schema = @Schema(implementation = Integer.class)))
})
@GetMapping("/mail")
public ResponseEntity<Integer> sendCode(@Valid @RequestBody MailRequest emailRequest) {
Expand All @@ -37,7 +36,7 @@ public ResponseEntity<Integer> sendCode(@Valid @RequestBody MailRequest emailReq
@Operation(summary = "문자 인증 코드 전송", description = "입력한 번호에 인증 코드를 전송합니다. 형식: 01012345678",
responses = {
@ApiResponse(responseCode = "200", description = "인증 코드 전송 성공, 보낸 인증 코드를 반환합니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
content = @Content(schema = @Schema(implementation = Integer.class)))
})
@RateLimiter(name = "jedero", fallbackMethod = "rateLimiterFallback")
@GetMapping("/sms")
Expand Down
11 changes: 2 additions & 9 deletions src/main/java/com/backend/domain/mail/service/MailService.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Service
@RequiredArgsConstructor
@Slf4j
Expand Down Expand Up @@ -60,10 +56,7 @@ public int sendSMS(SmsRequest smsRequest) {
Message message = new Message();
this.messageService = NurigoApp.INSTANCE.initialize(apiKey, apiSecret, "https://api.coolsms.co.kr");

Random rand = new Random();
String code = IntStream.range(0, 4)
.mapToObj(i -> Integer.toString(rand.nextInt(10)))
.collect(Collectors.joining());
int code = (int) (Math.random() * 9000) + 1000;

message.setFrom(fromNumber);
message.setTo(smsRequest.toNumber());
Expand All @@ -72,6 +65,6 @@ public int sendSMS(SmsRequest smsRequest) {
SingleMessageSentResponse response = messageService.sendOne(new SingleMessageSendingRequest(message));
log.info("SMS 메세지 결과 = {}", response);

return Integer.parseInt(code);
return code;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.backend.domain.popup.controller;

import com.backend.common.dto.PageResponseDto;
import com.backend.common.dto.ResponseDto;
import com.backend.domain.auth.dto.Login;
import com.backend.domain.auth.dto.LoginUser;
import com.backend.domain.popup.dto.request.PopupCreateRequest;
import com.backend.domain.popup.dto.response.PopupGetResponseDto;
import com.backend.domain.popup.service.PopupService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
@RequestMapping("/popups")
public class PopupController {

private final PopupService popupService;

@GetMapping("/{pageNumber}")
@Operation(summary = "팝업 조회", description = "사용자가 작성한 팝업을 조회합니다.",
responses = {
@ApiResponse(responseCode = "200", description = "팝업 리스트를 반환합니다.",
content = @Content(schema = @Schema(implementation = PageResponseDto.class)))
})
public ResponseEntity<PageResponseDto> getPopups(@Login @Schema(hidden = true) LoginUser loginUser, @PathVariable int pageNumber) {
Page<PopupGetResponseDto> response = popupService.getPopups(loginUser, pageNumber);
return PageResponseDto.of(response);
}

@PostMapping
@Operation(summary = "팝업 생성", description = "팝업을 생성합니다.",
responses = {
@ApiResponse(responseCode = "200", description = "생성 성공",
content = @Content(schema = @Schema(implementation = String.class)))
})
public ResponseEntity<String> createPopup(@Login @Schema(hidden = true) LoginUser loginUser,
@Valid @RequestBody PopupCreateRequest popupCreateRequest) {
popupService.createPopup(loginUser, popupCreateRequest);
return ResponseDto.created("팝업 생성 성공");
}

@DeleteMapping("/{popupId}")
@Operation(summary = "팝업 삭제", description = "팝업을 삭제합니다.",
responses = {
@ApiResponse(responseCode = "200", description = "삭제 성공",
content = @Content(schema = @Schema(implementation = String.class)))
})
public ResponseEntity<String> deletePopup(@Login @Schema(hidden = true) LoginUser loginUser, @PathVariable Long popupId) {
popupService.deletePopup(loginUser, popupId);
return ResponseDto.ok("팝업 삭제 성공");
}
}
34 changes: 34 additions & 0 deletions src/main/java/com/backend/domain/popup/domain/EndDateType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.backend.domain.popup.domain;

import com.backend.error.ErrorCode;
import com.backend.error.exception.custom.BusinessException;
import com.fasterxml.jackson.annotation.JsonCreator;
import lombok.Getter;

import java.util.stream.Stream;

@Getter
public enum EndDateType {
ONE_DAY("하루", 1),
ONE_WEEK("일주일간", 7),
TWO_WEEK("2주간", 14),
ONE_MONTH("한달간", 30),
NO_LIMIT("제한 없음", 100_000);

private final String DateType;

private final int plusDate;

EndDateType(String dateType, int plusDate) {
DateType = dateType;
this.plusDate = plusDate;
}

@JsonCreator
public static EndDateType create(String request) {
return Stream.of(values())
.filter(value -> value.DateType.equalsIgnoreCase(request))
.findFirst()
.orElseThrow(() -> new BusinessException(ErrorCode.NOT_EXISTS_POPUP_DATE));
}
}
41 changes: 41 additions & 0 deletions src/main/java/com/backend/domain/popup/domain/Popup.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.backend.domain.popup.domain;

import com.backend.domain.contract.entity.Contract;
import com.backend.domain.store.entity.Store;
import jakarta.persistence.*;
import lombok.*;

import java.time.LocalDate;
import java.time.LocalDateTime;

@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "popup")
public class Popup {

@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
@Column(name = "popup_id")
private Long id;

private String title;

private String content;

private LocalDate startDate;

private LocalDate endDate;

private LocalDateTime reservation;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "store_id")
private Store store;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "contract_id")
private Contract contract;
}
19 changes: 19 additions & 0 deletions src/main/java/com/backend/domain/popup/domain/ReservationType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.backend.domain.popup.domain;

import lombok.Getter;

@Getter
public enum ReservationType {
NOW("실시간"),
RESERVATION("예약");

private final String reservationType;

ReservationType(String reservationType) {
this.reservationType = reservationType;
}

public static boolean isNow(String request) {
return NOW.getReservationType().equals(request);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.backend.domain.popup.dto.request;

import com.backend.domain.contract.entity.Contract;
import com.backend.domain.popup.domain.Popup;
import com.backend.domain.store.entity.Store;
import jakarta.validation.constraints.NotBlank;

import java.time.LocalDate;
import java.time.LocalDateTime;

public record PopupCreateRequest(@NotBlank String title, @NotBlank String content, @NotBlank String endDate,
@NotBlank String reservation, Long storeId) {
public Popup toEntity(LocalDate endDate, LocalDateTime reservation, Store store, Contract contract) {
return Popup.builder()
.title(title)
.content(content)
.startDate(LocalDate.now())
.endDate(endDate)
.reservation(reservation)
.store(store)
.contract(contract)
.build();
}
}
Loading

0 comments on commit a8c89b0

Please sign in to comment.