Skip to content

Commit

Permalink
Merge pull request #20 from KUSITMS-Team-A/feature/19-sms-api
Browse files Browse the repository at this point in the history
[#19] Feature: 문자 인증 코드를 전송합니다.
  • Loading branch information
pdohyung authored Nov 19, 2023
2 parents 90e74cf + 820fe95 commit 1d08066
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 8 deletions.
7 changes: 7 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ dependencies {
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'
//s3
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
//sms
implementation 'net.nurigo:sdk:4.3.0'

//RateLimiter
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation group: 'io.github.resilience4j', name: 'resilience4j-spring-boot3', version: '2.1.0'
}

tasks.named('test') {
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1 +1 @@
rootProject.name = 'Backend'
rootProject.name = 'backend'
1 change: 1 addition & 0 deletions src/main/java/com/backend/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
.requestMatchers(mvcMatcherBuilder.pattern("/api/**")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("/mail/**")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("/s3/create")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("/sms")).permitAll()
.anyRequest().authenticated())
.exceptionHandling()
.authenticationEntryPoint(entryPoint);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package com.backend.domain.mail.controller;

import com.backend.domain.mail.dto.request.MailRequest;
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;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
Expand All @@ -17,8 +24,31 @@ public class MailController {

private final MailService mailService;

@PostMapping("/mail")
@Operation(summary = "메일 인증 코드 전송", description = "입력한 메일에 인증 코드를 전송합니다. 형식: [email protected]",
responses = {
@ApiResponse(responseCode = "200", description = "인증 코드 전송 성공, 보낸 인증 코드를 반환합니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
@GetMapping("/mail")
public ResponseEntity<Integer> sendCode(@Valid @RequestBody MailRequest emailRequest) {
return ResponseEntity.ok(mailService.sendAuthenticationCode(emailRequest));
}

@Operation(summary = "문자 인증 코드 전송", description = "입력한 번호에 인증 코드를 전송합니다. 형식: 01012345678",
responses = {
@ApiResponse(responseCode = "200", description = "인증 코드 전송 성공, 보낸 인증 코드를 반환합니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
@RateLimiter(name = "jedero", fallbackMethod = "rateLimiterFallback")
@GetMapping("/sms")
public ResponseEntity<Integer> sendSMS(@Valid @RequestBody SmsRequest smsRequest) {
int result = mailService.sendSMS(smsRequest);
return ResponseEntity.ok(result);
}

public ResponseEntity<String> rateLimiterFallback(Throwable t) {
// HttpHeaders responseHeaders = new HttpHeaders();
// responseHeaders.set("Retry-After", "10s");
throw new BusinessException(ErrorCode.TOO_MANY_SMS);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.backend.domain.mail.dto.request;

import jakarta.validation.constraints.NotEmpty;

public record SmsRequest(@NotEmpty String toNumber) {
}
47 changes: 45 additions & 2 deletions src/main/java/com/backend/domain/mail/service/MailService.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,45 @@
package com.backend.domain.mail.service;

import com.backend.domain.mail.dto.request.MailRequest;
import com.backend.domain.mail.dto.request.SmsRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.nurigo.sdk.NurigoApp;
import net.nurigo.sdk.message.model.Message;
import net.nurigo.sdk.message.request.SingleMessageSendingRequest;
import net.nurigo.sdk.message.response.SingleMessageSentResponse;
import net.nurigo.sdk.message.service.DefaultMessageService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
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
public class MailService {

private final JavaMailSender javaMailSender;
@Value("{mail.mail.username}")

private DefaultMessageService messageService;

@Value("${spring.mail.username}")
private String username;

@Value("${coolsms.api.key}")
private String apiKey;

@Value("${coolsms.api.secret}")
private String apiSecret;

@Value("${coolsms.api.fromNumber}")
private String fromNumber;


public int sendAuthenticationCode(MailRequest mailRequest) {
int code = (int) (Math.random() * 900000) + 100000;

Expand All @@ -31,4 +55,23 @@ public int sendAuthenticationCode(MailRequest mailRequest) {

return code;
}
}

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());

message.setFrom(fromNumber);
message.setTo(smsRequest.toNumber());
message.setText("[제대로] 인증번호를 입력해주세요.\n인증번호: " + code);

SingleMessageSentResponse response = messageService.sendOne(new SingleMessageSendingRequest(message));
log.info("SMS 메세지 결과 = {}", response);

return Integer.parseInt(code);
}
}
3 changes: 2 additions & 1 deletion src/main/java/com/backend/error/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ public enum ErrorCode {
INVALID_GROUP_TYPE(BAD_REQUEST, "잘못된 그룹 종류입니다."),
INVALID_PASSWORD(BAD_REQUEST, "잘못된 비밀번호입니다."),
IMAGE_UPLOAD_FAIL(BAD_REQUEST, "이미지 업로드에 실패했습니다."),
INVALID_FILE(BAD_REQUEST, "잘못된 파일 형식입니다.");
INVALID_FILE(BAD_REQUEST, "잘못된 파일 형식입니다."),
TOO_MANY_SMS(TOO_MANY_REQUESTS, "짧은 시간에 너무 많은 요청을 보냈습니다. 1분 후에 재시도하세요.");

private final int code;
private final String message;
Expand Down

0 comments on commit 1d08066

Please sign in to comment.