Skip to content

Commit

Permalink
Merge pull request #50 from YAPP-Github/develop
Browse files Browse the repository at this point in the history
fix: Resolve conflict.
  • Loading branch information
Park-Young-Hun authored Feb 4, 2024
2 parents d21bc98 + beaae11 commit c24a3c6
Show file tree
Hide file tree
Showing 20 changed files with 263 additions and 4 deletions.
1 change: 0 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ jobs:
- name: Set up Environment
working-directory: ./src/main
run: |
mkdir ./resources
cd ./resources
touch ./application.yml
echo "${{ secrets.APPLICATION_YML }}" | base64 --decode >> application.yml
Expand Down
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ dependencies {
implementation 'io.jsonwebtoken:jjwt-impl:0.11.5'
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5'
implementation 'com.auth0:java-jwt:4.4.0'

// SMTP 설정
implementation 'org.springframework.boot:spring-boot-starter-mail'

// Thymeleaf 설정
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.fullcar.carpool.domain.carpool.CarpoolState;
import com.fullcar.carpool.domain.carpool.MoodType;
import com.fullcar.carpool.domain.carpool.PeriodType;
import com.fullcar.member.domain.member.Gender;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
Expand Down Expand Up @@ -45,7 +46,7 @@ public class CarpoolResponseDto {
private String companyName;

@Schema(description = "성별")
private String gender;
private Gender gender;

@Schema(description = "생성 Timestamp")
private LocalDateTime createdAt;
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/fullcar/core/response/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public enum ErrorCode {

/* 400 BAD REQUEST */
FAILED_TO_GENERATE_PUBLIC_KEY(BAD_REQUEST, "애플 공개키 생성 중 문제 발생"),
EMAIL_ADDRESS_IN_BLACKLIST(BAD_REQUEST, "블랙리스트에 있는 이메일 주소입니다."),

/* 401 UNAUTHORIZED */
UNAUTHORIZED_KAKAO_TOKEN(UNAUTHORIZED, "유효하지 않은 카카오 토큰"),
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/fullcar/core/response/SuccessCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public enum SuccessCode {
/* 200 OK */
SIGNIN_SUCCESS(OK, "소셜로그인 성공"),
GET_NEW_TOKEN_SUCCESS(OK, "토큰 재발급 성공"),
READ_SUCCESS(OK, "조회 성공");
READ_SUCCESS(OK, "조회 성공"),
EMAIL_SENT_SUCCESS(OK, "인증메일 발송 성공");

private final HttpStatus status;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.fullcar.member.application.member;

import com.fullcar.member.infra.EmailMessage;
import com.fullcar.member.domain.member.Member;
import com.fullcar.member.presentation.member.dto.request.EmailRequestDto;
import com.fullcar.member.presentation.member.dto.response.MemberGetResponseDto;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
Expand All @@ -14,6 +16,16 @@ public MemberGetResponseDto toDto(Member member) {
return MemberGetResponseDto.builder()
.nickname(member.getNickname())
.companyName(member.getCompany().getCompanyName())
.email(member.getEmail())
.gender(member.getGender())
.carId(member.getCarId())
.build();
}

public EmailMessage toEntity(EmailRequestDto emailRequestDto) {
return EmailMessage.builder()
.to(emailRequestDto.getEmail())
.subject("[FullCar] 회사 이메일 인증")
.build();
}
}
25 changes: 25 additions & 0 deletions src/main/java/com/fullcar/member/domain/blacklist/Blacklist.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.fullcar.member.domain.blacklist;

import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import static lombok.AccessLevel.PROTECTED;

@Entity
@Getter
@NoArgsConstructor(access = PROTECTED)
@AllArgsConstructor(access = PROTECTED)
@EntityListeners(AuditingEntityListener.class)
@Builder
public class Blacklist {
@EmbeddedId
private BlacklistId id;

private String email;
}
21 changes: 21 additions & 0 deletions src/main/java/com/fullcar/member/domain/blacklist/BlacklistId.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.fullcar.member.domain.blacklist;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.io.Serializable;

import static lombok.AccessLevel.PROTECTED;

@Embeddable
@Getter
@NoArgsConstructor(access = PROTECTED)
@AllArgsConstructor
public class BlacklistId implements Serializable {

@Column(name = "id")
private Long id;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.fullcar.member.domain.blacklist;

import com.fullcar.core.exception.CustomException;
import com.fullcar.core.response.ErrorCode;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface BlacklistRepository extends JpaRepository<Blacklist, BlacklistId> {
boolean existsByEmail(String email);

default void findByEmailThrow(String email) {
if (existsByEmail(email)) {
throw new CustomException(ErrorCode.EMAIL_ADDRESS_IN_BLACKLIST);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.fullcar.member.domain.blacklist.service;

import com.fullcar.core.id.SnowFlake;
import com.fullcar.member.domain.blacklist.BlacklistId;
import org.springframework.stereotype.Service;

@Service
public class BlacklistIdService {
private final SnowFlake snowFlake;

public BlacklistIdService() {
snowFlake = new SnowFlake(255);
}

public BlacklistId nextId() {
return new BlacklistId(snowFlake.nextId());
}
}
7 changes: 7 additions & 0 deletions src/main/java/com/fullcar/member/domain/member/Gender.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.fullcar.member.domain.member;

public enum Gender {
FEMALE,
MALE,
NONE
}
2 changes: 1 addition & 1 deletion src/main/java/com/fullcar/member/domain/member/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public class Member {

private String email;

private String gender;
private Gender gender;

@Builder.Default
@Column(name = "onboarding_flag")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.fullcar.member.domain.member.service;

import com.fullcar.member.presentation.member.dto.request.EmailRequestDto;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public interface MailService {
void sendMail(EmailRequestDto emailRequestDto);
}
11 changes: 11 additions & 0 deletions src/main/java/com/fullcar/member/infra/EmailMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.fullcar.member.infra;

import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class EmailMessage {
private String to;
private String subject;
}
50 changes: 50 additions & 0 deletions src/main/java/com/fullcar/member/infra/MailClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.fullcar.member.infra;

import com.fullcar.member.application.member.MemberMapper;
import com.fullcar.member.domain.blacklist.BlacklistRepository;
import com.fullcar.member.domain.member.service.MailService;
import com.fullcar.member.presentation.member.dto.request.EmailRequestDto;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.RequiredArgsConstructor;
import org.springframework.core.io.ClassPathResource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring6.SpringTemplateEngine;

@Service
@RequiredArgsConstructor
public class MailClient implements MailService {
private final BlacklistRepository blacklistRepository;
private final JavaMailSender javaMailSender;
private final SpringTemplateEngine templateEngine;
private final MemberMapper memberMapper;

@Override
public void sendMail(EmailRequestDto emailRequestDto) {
String email = emailRequestDto.getEmail();
String emailDomain = email.substring(email.lastIndexOf("@")+1);
blacklistRepository.findByEmailThrow(emailDomain);

EmailMessage emailMessage = memberMapper.toEntity(emailRequestDto);
MimeMessage mimeMessage = javaMailSender.createMimeMessage();

try {
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
mimeMessageHelper.setTo(emailMessage.getTo());
mimeMessageHelper.setSubject(emailMessage.getSubject());
mimeMessageHelper.setText(setContext(),true);
mimeMessageHelper.addInline("image", new ClassPathResource("static/images/fullcar_logo.png"));
javaMailSender.send(mimeMessage);
} catch (MessagingException e) {
throw new RuntimeException(e);
}
}

public String setContext() {
Context context = new Context();
return templateEngine.process("email", context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import com.fullcar.core.response.SuccessCode;
import com.fullcar.member.application.member.MemberService;
import com.fullcar.member.domain.member.Member;
import com.fullcar.member.domain.member.service.MailService;
import com.fullcar.member.presentation.member.dto.request.CompanyRequestDto;
import com.fullcar.member.presentation.member.dto.request.EmailRequestDto;
import com.fullcar.member.presentation.member.dto.response.MemberGetResponseDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
Expand All @@ -22,6 +24,7 @@
public class MemberController {

private final MemberService memberService;
private final MailService mailService;

@Operation(summary = "회사 선택 API")
@ApiResponses({
Expand All @@ -44,4 +47,15 @@ public ApiResponse<MemberGetResponseDto> getMember(@CurrentMember Member member)
MemberGetResponseDto response = memberService.getMember(member);
return ApiResponse.success(SuccessCode.READ_SUCCESS, response);
}

@Operation(summary = "회사 메일 인증 API")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "인증메일 발송 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "500", description = "서버 내부 오류", content = @Content)
})
@PostMapping("/onboarding/company/email")
public ApiResponse<Object> sendAuthenticationMail(@RequestBody EmailRequestDto emailRequestDto) {
mailService.sendMail(emailRequestDto);
return ApiResponse.success(SuccessCode.EMAIL_SENT_SUCCESS);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.fullcar.member.presentation.member.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class EmailRequestDto {
@Schema(description = "회사 이메일", example = "[email protected]")
private String email;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.fullcar.member.presentation.member.dto.response;

import com.fullcar.member.domain.car.CarId;
import com.fullcar.member.domain.member.Gender;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;

Expand All @@ -15,4 +17,14 @@ public class MemberGetResponseDto {

@Schema(description = "회사명", example = "현대 자동차")
private String companyName;

@Schema(description = "회사 이메일", example = "[email protected]")
private String email;

@Schema(description = "성별", example = "MALE")
private Gender gender;

@Schema(description = "차량 id")
private CarId carId;

}
Binary file added src/main/resources/static/images/fullcar_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions src/main/resources/templates/email.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="UTF-8">

<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

<body style="font-family: 'Noto Sans', 'Arial', 'sans-serif'; margin: 0; padding: 0;">
<div class="container" style="margin: auto;">
<div class="logo">
<img src="cid:image" alt="Fullcar 로고">
</div>
<p style="margin-top: 20px; padding: 0;">안녕하세요.</p><br>
<p style="margin-top: 10px;">회사 메일 인증을 통한 안전한 <span class="highlight" style="color: #6C7AF1; font-weight: bold;">카풀 서비스 풀카</span>입니다.</p>
<p style="margin-top: 10px; margin-bottom: 10px;">풀카 이용을 위해 <span class="highlight" style="color: #6C7AF1; font-weight: bold;">아래 버튼을 클릭</span>해 인증을 진행해 주세요.</p>

<script th:inline="javascript">
$("#bt").click(function() {
alert('성공');
});

</script>

<button type="button" id="bt" onclick="alert('성공')" style="display: inline-block; text-decoration: none; font-weight: 500;
color: #fff;
background-color: #6C7AF1;
padding: 15px 36px;
border-color: #6C7AF1;
border-radius: 8px;
font-size: 14px;
margin-top: 20px;
transition: background-color 0.3s;">회사 메일 인증하기</button>
<div class="help-text">
<a href="#" style="display: block; color: #505967; margin-top: 20px; text-decoration: underline;">인증이 잘 되지 않나요?</a>
</div>
</div>
</body>

</html>

0 comments on commit c24a3c6

Please sign in to comment.