diff --git a/flask/Dockerfile b/flask/Dockerfile new file mode 100644 index 00000000..af5f83fe --- /dev/null +++ b/flask/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3.8-alpine + +COPY . /app + +WORKDIR /app + +RUN pip install Flask-Mail + +RUN pip install flask + +RUN chmod +x /app/app.py + +CMD ["python3", "app.py"] \ No newline at end of file diff --git a/flask/app.py b/flask/app.py new file mode 100644 index 00000000..8df67459 --- /dev/null +++ b/flask/app.py @@ -0,0 +1,42 @@ +from flask import Flask, request, Response +import smtplib +from email.mime.text import MIMEText + +app = Flask(__name__) + +# HTTP POST 요청을 처리하는 엔드포인트 +@app.route('/email', methods=['POST']) +def sendEmailEndpoint(): + + try: + jsonRequest = request.get_json() + + subject = str(jsonRequest.get('subject')[0]) + text = str(jsonRequest.get('text')[0]) + email = str(jsonRequest.get('email')[0]) + username = str(jsonRequest.get('username')[0]) + password = str(jsonRequest.get('password')[0]) + + smtp = smtplib.SMTP('smtp.gmail.com', 587) + smtp.ehlo() + smtp.starttls() + smtp.login(username, password) + + msg = MIMEText(text, "html") + msg['Subject'] = subject + + smtp.sendmail(username, email, msg.as_string()) + smtp.quit() + + response = Response("Email sent successfully", status=200) + + return response + + except Exception as e: + error_message = str(e) + response = Response("Failed to send email: " + error_message, status=500) + + return response + +if __name__ == '__main__': + app.run('0.0.0.0', port=5000, debug=True) \ No newline at end of file diff --git a/flask/start.sh b/flask/start.sh new file mode 100644 index 00000000..e1dc92d8 --- /dev/null +++ b/flask/start.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# Docker 이미지 빌드 +docker build -t flask-app:v1 . + +# Docker 컨테이너 실행 +docker run -d -p 80:5000 flask-app:v1 \ No newline at end of file diff --git a/k8s/backend.yaml b/k8s/backend.yaml index 0a988366..5dfc6020 100644 --- a/k8s/backend.yaml +++ b/k8s/backend.yaml @@ -15,7 +15,7 @@ spec: containers: - name: backend # 여러분의 backend image 주소를 입력해주세요. -> 빌드 후 빌드 이미지 경로 새로 넣기 - image: krmp-d2hub-idock.9rum.cc/dev-test/repo_1414cba4227e + image: krmp-d2hub-idock.9rum.cc/dev-test/repo_64cf4065f88f env: - name: TOKEN_SECRET valueFrom: @@ -58,7 +58,7 @@ spec: name: secrets key: MYSQL_ROOT_PASSWORD - name: MYSQL_USERNAME - valueFrom: + valueFrom: secretKeyRef: name: secrets key: MYSQL_USERNAME @@ -77,6 +77,11 @@ spec: secretKeyRef: name: secrets key: API_SERVER_URL + - name: FLASK_MAIL_SERVER + valueFrom: + secretKeyRef: + name: secrets + key: FLASK_MAIL_SERVER ports: - containerPort: 8080 resources: diff --git a/k8s/configs/default.conf b/k8s/configs/default.conf index d7a7d9dc..6d32d6e0 100644 --- a/k8s/configs/default.conf +++ b/k8s/configs/default.conf @@ -1,6 +1,9 @@ server { - listen 80; - server_tokens off; #nginx 버전 정보 숨기기 + listen 80; + server_tokens off; #nginx 버전 정보 숨기기 + + error_log /tmp/error.log; + access_log /tmp/access.log main; location / { proxy_pass http://frontend.default.svc.cluster.local:3000; @@ -12,5 +15,5 @@ server { proxy_connect_timeout 60s; # 연결 타임아웃 설정 proxy_send_timeout 60s; # 소켓 타임아웃 설정 proxy_read_timeout 300s; # 프록시 서버로부터 응답을 읽어들이는 데 허용되는 시간 - } -} + } +} \ No newline at end of file diff --git a/k8s/create-k8s-secret.sh b/k8s/create-k8s-secret.sh index 59e0351a..8e2dd98f 100755 --- a/k8s/create-k8s-secret.sh +++ b/k8s/create-k8s-secret.sh @@ -21,7 +21,9 @@ kubectl create secret generic $SECRET_NAME \ --from-literal=MYSQL_PASSWORD="$MYSQL_PASSWORD" \ --from-literal=DOMAIN="$DOMAIN" \ --from-literal=GOOGLE_MAP_API_KEY="$GOOGLE_MAP_API_KEY" \ - --from-literal=API_SERVER_URL="$API_SERVER_URL" + --from-literal=API_SERVER_URL="$API_SERVER_URL" \ + --from-literal=NEXT_PUBLIC_KAKAOMAP_APPKEY="$NEXT_PUBLIC_KAKAOMAP_APPKEY" \ + --from-literal=FLASK_MAIL_SERVER="$FLASK_MAIL_SERVER" echo "Kubernetes secret $SECRET_NAME has been created or updated with the environment variables." diff --git a/k8s/frontend.yaml b/k8s/frontend.yaml index 11d76d02..f1bb6707 100644 --- a/k8s/frontend.yaml +++ b/k8s/frontend.yaml @@ -15,7 +15,7 @@ spec: containers: - name: frontend # 여러분의 image 주소를 입력해주세요. - image: krmp-d2hub-idock.9rum.cc/dev-test/repo_eb6339562f9c + image: krmp-d2hub-idock.9rum.cc/dev-test/repo_23d8d3138910 --- apiVersion: v1 kind: Service diff --git a/src/main/java/com/bungaebowling/server/_core/config/AwsS3Config.java b/src/main/java/com/bungaebowling/server/_core/config/AwsS3Config.java index d70b4559..ccb3b25f 100644 --- a/src/main/java/com/bungaebowling/server/_core/config/AwsS3Config.java +++ b/src/main/java/com/bungaebowling/server/_core/config/AwsS3Config.java @@ -59,7 +59,6 @@ public AmazonS3 amazonS3ClientForDeploy() { clientConfiguration.setProxyPort(proxyPort); clientConfiguration.setProxyProtocol(Protocol.HTTP); - AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(endpoint, null); return AmazonS3ClientBuilder @@ -70,4 +69,4 @@ public AmazonS3 amazonS3ClientForDeploy() { .withRegion(region) .build(); } -} +} \ No newline at end of file diff --git a/src/main/java/com/bungaebowling/server/_core/config/MailConfig.java b/src/main/java/com/bungaebowling/server/_core/config/MailConfig.java index 6183d0f5..0cc4bb7d 100644 --- a/src/main/java/com/bungaebowling/server/_core/config/MailConfig.java +++ b/src/main/java/com/bungaebowling/server/_core/config/MailConfig.java @@ -3,6 +3,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.JavaMailSenderImpl; @@ -20,6 +21,7 @@ public class MailConfig { private String password; @Bean + @Profile({"local", "product", "test", "deploy"}) public JavaMailSender javaMailService() { JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl(); diff --git a/src/main/java/com/bungaebowling/server/_core/config/RestTemplateConfig.java b/src/main/java/com/bungaebowling/server/_core/config/RestTemplateConfig.java index cdb7e9e9..b55fcf7f 100644 --- a/src/main/java/com/bungaebowling/server/_core/config/RestTemplateConfig.java +++ b/src/main/java/com/bungaebowling/server/_core/config/RestTemplateConfig.java @@ -1,5 +1,6 @@ package com.bungaebowling.server._core.config; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; @@ -12,11 +13,17 @@ @Configuration public class RestTemplateConfig { + @Value("krmp-proxy.9rum.cc") + private String proxyHost; + + @Value("3128") + private int proxyPort; + @Bean @Profile("deploy") public RestTemplate restTemplateForDeploy() { SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); - Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("krmp-proxy.9rum.cc", 3128)); + Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)); requestFactory.setProxy(proxy); return new RestTemplate(requestFactory); diff --git a/src/main/java/com/bungaebowling/server/_core/errors/GlobalExceptionHandler.java b/src/main/java/com/bungaebowling/server/_core/errors/GlobalExceptionHandler.java index c978717f..133a4119 100644 --- a/src/main/java/com/bungaebowling/server/_core/errors/GlobalExceptionHandler.java +++ b/src/main/java/com/bungaebowling/server/_core/errors/GlobalExceptionHandler.java @@ -3,13 +3,11 @@ import com.bungaebowling.server._core.errors.exception.CustomException; import com.bungaebowling.server._core.errors.exception.ErrorCode; import com.bungaebowling.server._core.utils.ApiUtils; -import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; -@Slf4j @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(CustomException.class) @@ -19,7 +17,6 @@ public ResponseEntity customError(CustomException e) { @ExceptionHandler(Exception.class) public ResponseEntity unknownServerError(Exception e) { - log.error("unknown 에러 발생", e); var status = HttpStatus.INTERNAL_SERVER_ERROR; var response = ApiUtils.error(e.getMessage(), ErrorCode.UNKNOWN_SERVER_ERROR); return ResponseEntity.status(status).body(response); diff --git a/src/main/java/com/bungaebowling/server/_core/utils/AwsS3Service.java b/src/main/java/com/bungaebowling/server/_core/utils/AwsS3Service.java index 016f9172..f8e47268 100644 --- a/src/main/java/com/bungaebowling/server/_core/utils/AwsS3Service.java +++ b/src/main/java/com/bungaebowling/server/_core/utils/AwsS3Service.java @@ -148,4 +148,4 @@ private String fileWhiteList(String fileName) { return caseInSensitiveFileName; } -} +} \ No newline at end of file diff --git a/src/main/java/com/bungaebowling/server/score/controller/ScoreController.java b/src/main/java/com/bungaebowling/server/score/controller/ScoreController.java index a4b0982b..99025375 100644 --- a/src/main/java/com/bungaebowling/server/score/controller/ScoreController.java +++ b/src/main/java/com/bungaebowling/server/score/controller/ScoreController.java @@ -74,4 +74,4 @@ public ResponseEntity deleteScore( return ResponseEntity.ok(ApiUtils.success()); } -} +} \ No newline at end of file diff --git a/src/main/java/com/bungaebowling/server/score/service/ScoreService.java b/src/main/java/com/bungaebowling/server/score/service/ScoreService.java index 1f9d9a55..c5f5660d 100644 --- a/src/main/java/com/bungaebowling/server/score/service/ScoreService.java +++ b/src/main/java/com/bungaebowling/server/score/service/ScoreService.java @@ -214,4 +214,4 @@ public int findMinScore(List scores) { .min() .orElse(0); } -} +} \ No newline at end of file diff --git a/src/main/java/com/bungaebowling/server/user/controller/UserController.java b/src/main/java/com/bungaebowling/server/user/controller/UserController.java index db47f2a2..03fa7cf9 100644 --- a/src/main/java/com/bungaebowling/server/user/controller/UserController.java +++ b/src/main/java/com/bungaebowling/server/user/controller/UserController.java @@ -27,7 +27,7 @@ @RequestMapping("/api") public class UserController { - final private UserService userService; + private final UserService userService; @PostMapping("/join") public ResponseEntity join(@RequestBody @Valid UserRequest.JoinDto requestDto, Errors errors) throws URISyntaxException { diff --git a/src/main/java/com/bungaebowling/server/user/dto/UserRequest.java b/src/main/java/com/bungaebowling/server/user/dto/UserRequest.java index 7fe1c732..5b8ef338 100644 --- a/src/main/java/com/bungaebowling/server/user/dto/UserRequest.java +++ b/src/main/java/com/bungaebowling/server/user/dto/UserRequest.java @@ -34,7 +34,6 @@ public User createUser(District district, String encodedPassword) { return User.builder() .name(name) .email(email) - .role(Role.ROLE_USER) .password(encodedPassword) .district(district) .build(); diff --git a/src/main/java/com/bungaebowling/server/user/service/UserService.java b/src/main/java/com/bungaebowling/server/user/service/UserService.java index 110e693a..51b46527 100644 --- a/src/main/java/com/bungaebowling/server/user/service/UserService.java +++ b/src/main/java/com/bungaebowling/server/user/service/UserService.java @@ -22,18 +22,26 @@ import jakarta.mail.internet.MimeMessage; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; import org.springframework.web.multipart.MultipartFile; import java.security.SecureRandom; import java.time.LocalDateTime; +import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -57,12 +65,21 @@ public class UserService { private final PasswordEncoder passwordEncoder; private final JavaMailSender javaMailSender; + private final RestTemplate restTemplate; private final AwsS3Service awsS3Service; private final ScoreService scoreService; + private final Environment environment; + @Value("${bungaebowling.domain}") private String domain; + @Value("${mail.server}") + private String mailServer; + @Value("${mail.username}") + private String username; + @Value("${mail.password}") + private String password; @Transactional public UserResponse.JoinDto join(UserRequest.JoinDto requestDto) { @@ -147,6 +164,35 @@ public void sendVerificationMail(Long userId) { String subject = "[번개볼링] 이메일 인증을 완료해주세요."; String text = "링크를 클릭하여 인증을 완료해주세요!"; + if (Arrays.asList(environment.getActiveProfiles()).contains("deploy")) { + sendMailToMailServer(user, subject, text); + } else { + sendMail(user, subject, text); + } + } + + private void sendMailToMailServer(User user, String subject, String text) { + try { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + + MultiValueMap requests = new LinkedMultiValueMap<>(); + requests.add("subject", subject); + requests.add("text", text); + requests.add("email", user.getEmail()); + requests.add("username", username); + requests.add("password", password); + + HttpEntity> request = new HttpEntity<>(requests, httpHeaders); + String requestURL = "http://" + mailServer + "/email"; + + restTemplate.postForEntity(requestURL, request, String.class); + } catch (Exception e) { + throw new CustomException(ErrorCode.EMAIL_SEND_LIMIT_EXCEEDED); + } + } + + private void sendMail(User user, String subject, String text) { try { MimeMessage mimeMessage = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "utf-8"); @@ -271,15 +317,10 @@ public void sendVerificationMailForPasswordReset(UserRequest.SendVerificationMai String subject = "[번개볼링] 비밀번호 초기화 및 임시 비밀번호 발급을 위한 이메일 인증을 완료해주세요."; String text = "링크를 클릭하여 인증을 완료해주세요!"; - try { - MimeMessage mimeMessage = javaMailSender.createMimeMessage(); - MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "utf-8"); - helper.setTo(user.getEmail()); - helper.setSubject(subject); - helper.setText(text, true); - javaMailSender.send(mimeMessage); - } catch (Exception e) { - throw new CustomException(ErrorCode.EMAIL_SEND_LIMIT_EXCEEDED); + if (Arrays.asList(environment.getActiveProfiles()).contains("deploy")) { + sendMailToMailServer(user, subject, text); + } else { + sendMail(user, subject, text); } } @@ -293,17 +334,11 @@ public void confirmEmailAndSendTempPassword(UserRequest.ConfirmEmailAndSendTempP String subject = "[번개볼링] 임시 비밀번호"; String text = "임시 비밀번호는 " + tempPassword + " 입니다.
*비밀번호를 변경해주세요." + "
*기존의 비밀번호는 사용할 수 없습니다."; - try { - MimeMessage mimeMessage = javaMailSender.createMimeMessage(); - MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "utf-8"); - helper.setTo(user.getEmail()); - helper.setSubject(subject); - helper.setText(text, true); - javaMailSender.send(mimeMessage); - } catch (Exception e) { - throw new CustomException(ErrorCode.EMAIL_SEND_LIMIT_EXCEEDED); + if (Arrays.asList(environment.getActiveProfiles()).contains("deploy")) { + sendMailToMailServer(user, subject, text); + } else { + sendMail(user, subject, text); } - } public UserResponse.GetRecordDto getRecords(Long userId) { @@ -356,6 +391,4 @@ public String getRamdomPassword(int length) { return stringBuilder.toString(); } - - } \ No newline at end of file diff --git a/src/main/resources/application-deploy.yml b/src/main/resources/application-deploy.yml index 15019aaa..f33d6a19 100644 --- a/src/main/resources/application-deploy.yml +++ b/src/main/resources/application-deploy.yml @@ -55,6 +55,7 @@ mail: port: 587 username: ${GMAIL_USERNAME} password: ${GMAIL_APPLICATION_PASSWORD} + server: ${FLASK_MAIL_SERVER} # aws s3 config cloud: @@ -74,4 +75,4 @@ cloud: google: api: places: - key: ${GOOGLE_MAP_API_KEY} + key: ${GOOGLE_MAP_API_KEY} \ No newline at end of file diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 3560462f..60ebd2f3 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -61,6 +61,7 @@ mail: port: 587 username: ${GMAIL_USERNAME} password: ${GMAIL_APPLICATION_PASSWORD} + server: flask-mail-server # aws s3 config cloud: diff --git a/src/main/resources/application-product.yml b/src/main/resources/application-product.yml index c2a753a6..9a055d38 100644 --- a/src/main/resources/application-product.yml +++ b/src/main/resources/application-product.yml @@ -61,6 +61,7 @@ mail: port: 587 username: ${GMAIL_USERNAME} password: ${GMAIL_APPLICATION_PASSWORD} + server: flask-mail-server # aws s3 config cloud: diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml index 802f2909..701bf7ec 100644 --- a/src/main/resources/application-test.yml +++ b/src/main/resources/application-test.yml @@ -63,6 +63,7 @@ mail: port: 587 username: bungaebowling55@gmail.com password: gmailApplicationPassword + server: flask-mail-server # aws s3 config cloud: