Skip to content

Commit

Permalink
Merge branch 'develop' into feature/195-improve-mail-api
Browse files Browse the repository at this point in the history
  • Loading branch information
IW-MOON authored Apr 23, 2023
2 parents 7ef4d0e + 62791e2 commit 805e1d1
Show file tree
Hide file tree
Showing 15 changed files with 158 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ public void signUpEmailSend(String email) {

verifyEmail(email);

if(email.contains("+")) {
throw new PostNotFoundException("잘못된 이메일 형식입니다.");
}

String authToken = AuthTokenUtil.getAuthToken();

signUpEmailSendService.send(email, authToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,49 @@
import inspiration.aws.AwsSesService;
import inspiration.enumeration.ExceptionType;
import inspiration.exception.PostNotFoundException;
import inspiration.infrastructure.mail.MailProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

import org.springframework.web.util.UriComponentsBuilder;
import java.util.List;
import javax.mail.internet.MimeMessage;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

@Service
@RequiredArgsConstructor
@Slf4j
public class SignUpEmailSendService implements EmailSendService {


private final MailProperties mailProperties;
private final static String SUBJECT = "이메일 인증";

private final AwsSesService awsSesService;
private final JavaMailSender mailSender;
private final static String SUBJECT = "이메일 인증";

@Value("${ygtang.server.scheme}")
private String scheme;
@Value("${ygtang.server.host}")
private String host;
@Value("${ygtang.server.port}")
private String port;


@Override
public void send(String email, String authToken) {

String link = mailProperties.getSignUpEmailSendMail() + email + "&authToken=" + authToken;
String link = UriComponentsBuilder.newInstance()
.scheme(scheme)
.host(host)
.port(port)
.path("/api/v1/auth/email/signup")
.queryParam("email", URLEncoder.encode(email, StandardCharsets.UTF_8))
.queryParam("authToken", authToken)
.build(false)
.toUriString();

try {
awsSesService.send(SUBJECT, setHtml(link), List.of(email));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,16 @@
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Slf4j
Expand All @@ -50,6 +51,7 @@ public class InspirationService {
private final InspirationTagRepository inspirationTagRepository;
private final TagRepository tagRepository;
private final OpenGraphService openGraphService;
private final ThreadPoolTaskExecutor threadPoolTaskExecutor;

@Transactional(readOnly = true)
public RestPage<InspirationResponse> findInspirations(Pageable pageable, Long memberId) {
Expand Down Expand Up @@ -268,16 +270,19 @@ private Inspiration getInspiration(Long id) {
}

private RestPage<InspirationResponse> toRestPage(Page<Inspiration> inspirationPage) {
final Map<Long, OpenGraphResponse> inspirationOpenGraphMap;
inspirationOpenGraphMap = inspirationPage.getContent()
.parallelStream()
.collect(
Collectors.toMap(
Inspiration::getId,
it -> getOpenGraphResponse(it.getType(), it.getContent())
)
);

final Map<Long, OpenGraphResponse> inspirationOpenGraphMap = new ConcurrentHashMap<>();
// executor 에 작업 할당
final List<CompletableFuture<Void>> completableFutures = inspirationPage.map(
inspiration -> CompletableFuture.runAsync(
() -> inspirationOpenGraphMap.put(
inspiration.getId(),
getOpenGraphResponse(inspiration.getType(), inspiration.getContent())
),
threadPoolTaskExecutor
)
).toList();
// 비동기 작업 끝날때까지 대기
completableFutures.forEach(CompletableFuture::join);
return new RestPage<>(
inspirationPage.stream()
.peek(it -> it.setFilePath(getFilePath(it.getType(), it.getContent())))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ public class ExtraInfoRequest {
private GenderType gender;

@ApiModelProperty( notes = "UNDER_20S | EARLY_20S | LATE_20S | EARLY_30S | OLDER_35")
@NotNull(message = "나이는 필수 입력입니다.")
private AgeGroupType age;

@NotNull(message = "관심 직무는 필수 입력입니다.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@
public class MemberCountJobConfig {
static final String JOB_NAME = "member-count-job";
static final String STEP_NAME = "member-count-step";
private static final int CHUNK_SIZE = 1000;
private static final int CHUNK_SIZE = 10000;
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
private final SlackService slackService;

@Value("ygtang.temporary-directory-path")
@Value("${ygtang.temporary-directory-path}")
private String temporaryDirectoryPath;

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,18 @@ public class Member extends BaseTimeEntity {
@Column(nullable = false, length = 60)
private String password;

@Column(nullable = true)
@Column
@Enumerated(EnumType.STRING)
private GenderType gender;

@Column(nullable = true)
/**
* iOS 에서 나이가 필수값이라 때문에 리젝당함 (2023-04-04)
*/
@Column
@Enumerated(EnumType.STRING)
private AgeGroupType age_group;
private AgeGroupType ageGroup;

@Column(nullable = true)
@Column
private String job;

public void updatePassword(String password) {
Expand All @@ -49,10 +52,10 @@ public void updateNickname(String nickname) {
this.nickname = nickname;
}

public void updateExtraInfo(GenderType gender, AgeGroupType age_group, String job) {
public void updateExtraInfo(GenderType gender, AgeGroupType ageGroup, String job) {

this.gender = gender;
this.age_group = age_group;
this.ageGroup = ageGroup;
this.job = job;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,5 @@ public class MailProperties {
private int port;
private String userName;
private String password;
private String signUpEmailSendMail;
private String resetPasswordForAuthSendMail;
private String authToken;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package inspiration.infrastructure.spring;

import org.springframework.boot.task.TaskExecutorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.time.Duration;

@Configuration
public class ExecutorConfig {
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
return new TaskExecutorBuilder()
.corePoolSize(12)
.maxPoolSize(12)
.queueCapacity(200)
.awaitTermination(true)
.awaitTerminationPeriod(Duration.ofSeconds(10))
.threadNamePrefix("task-executor-")
.build();
}
}
5 changes: 4 additions & 1 deletion module-domain/src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ spring:
user: ENC(pD8lmKr4PXMRCUto6pMF9Ub/iJCxKveTODoqXQm1fDEB4rVN1Nzs6sftmidgYWOP)
password: ENC(MJISIAE2hpfyzQjAFQwM8o+Wtv5rHP5lJDwBq3mEIUkr93OEMj+uqYmXDjasb7El)
mail:
sign-up-email-send-mail: ENC(v8vfcMSRTQlJR/sRIpLnWAuYzJz0trJL6yKadnmztGC9N6dD1Bo1nh9xMSdFnHZky/TRWW9uf0oVteh6Z57R0YjLYnOEJAyDmCgrv+x5JqLTPlFlCPpVAwCFx29nJc/m)
reset-password-for-auth-send-mail: ENC(GeC90mA3UZZDdttZYktCwjx5gl00nT+ZGOOlCmT3UuTzwgvnGBqby+LjMl1BVfJ6B0leFjbJVUbkkykNQ0i/9/f6MPYopOgJy0sCaL8QlypSmzJy5Vkq98KTbAu18nsg)

logging:
Expand All @@ -31,6 +30,10 @@ ygtang:
username: ENC(pD8lmKr4PXMRCUto6pMF9Ub/iJCxKveTODoqXQm1fDEB4rVN1Nzs6sftmidgYWOP)
password: ENC(MJISIAE2hpfyzQjAFQwM8o+Wtv5rHP5lJDwBq3mEIUkr93OEMj+uqYmXDjasb7El)
driver-class-name: com.mysql.cj.jdbc.Driver
server:
scheme: https
host: ENC(nhcx6FgoC9f1sw8x+IXZxUeA7jVGC00faq6kqZ9qJK5ZgKS/ayDPiY+swiTOrb1e)
port: 443

uri:
webhook: ENC(KSZZjsE2e2j/6aQIb1EFZmIqM+S2qW2hY6/k9X97URbVEUcE6jNH60ZF186hVIpfmx3u4kZ3MgLboXvzId3CCFg3uIovOW5iiEh9T2zwf+wtK7GvcD0DaJ+H+xhRadViI5xoKD1aR6OMcVvDOwJurBVa6BFy0VemoIuSt+nQNYM=)
5 changes: 4 additions & 1 deletion module-domain/src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ spring:
user: ENC(pD8lmKr4PXMRCUto6pMF9Ub/iJCxKveTODoqXQm1fDEB4rVN1Nzs6sftmidgYWOP)
password: ENC(MJISIAE2hpfyzQjAFQwM8o+Wtv5rHP5lJDwBq3mEIUkr93OEMj+uqYmXDjasb7El)
mail:
sign-up-email-send-mail: ENC(TxvKgsUqqpgYeMzecLx4+iVEt2RQL1J8F24/ttMYgkboMeX2e1PE9L5VNk85RKVgZttx5x8p6dNin6mZaSZLomOSMlIiN2B5STL5LBGgmqhR8lYnKfVtyANliIit9pdH)
reset-password-for-auth-send-mail: ENC(2HO9hovu42xvdGvyYqoh2VhBxxl5Hp8gqopWj2vGlAiVrIBC0Bj0Be6iEbBVWuIWxgim0Uoznu3wRdT5LmbaKc/iLdluzHsB6xDbxiN5JA7PT3AxgLwZNAQ2q5bQ2v8w)

cloud:
Expand All @@ -27,3 +26,7 @@ ygtang:
username: ENC(pD8lmKr4PXMRCUto6pMF9Ub/iJCxKveTODoqXQm1fDEB4rVN1Nzs6sftmidgYWOP)
password: ENC(MJISIAE2hpfyzQjAFQwM8o+Wtv5rHP5lJDwBq3mEIUkr93OEMj+uqYmXDjasb7El)
driver-class-name: com.mysql.cj.jdbc.Driver
server:
scheme: http
host: localhost
port: 8080
5 changes: 4 additions & 1 deletion module-domain/src/main/resources/application-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ spring:
user: ENC(pD8lmKr4PXMRCUto6pMF9Ub/iJCxKveTODoqXQm1fDEB4rVN1Nzs6sftmidgYWOP)
password: ENC(MJISIAE2hpfyzQjAFQwM8o+Wtv5rHP5lJDwBq3mEIUkr93OEMj+uqYmXDjasb7El)
mail:
sign-up-email-send-mail: ENC(zyANvPjCAYiH+b6CSKvf0B3vMD1eU7NaOfqeUWVs2Mj4eCMvDa7Y6qpAV5h02jbihEC/I6zmjIZqsPu1VTdUadTTuVPVcLyqTJGlRYS5rLlEcXGhZ4zg+Nu8+3S8otsn)
reset-password-for-auth-send-mail: ENC(TtTKtnwv64ttIONkMuT1SF6r/iU2NWV+hI17DTupgugbuj50RsiIsEXowUUmFoVz7fh01FBNkq0dKhkaDEK+BLWtRchs9Z+koSAMSNqvGhby2+8rHzRfIL3FMTzEGeHt)

cloud:
Expand All @@ -26,6 +25,10 @@ ygtang:
username: ENC(pD8lmKr4PXMRCUto6pMF9Ub/iJCxKveTODoqXQm1fDEB4rVN1Nzs6sftmidgYWOP)
password: ENC(MJISIAE2hpfyzQjAFQwM8o+Wtv5rHP5lJDwBq3mEIUkr93OEMj+uqYmXDjasb7El)
driver-class-name: com.mysql.cj.jdbc.Driver
server:
scheme: https
host: ENC(cm4VELioPGIOdzRjWigLUeo7GDiwRwUK4CDjibCSt9ODl1CMwfUolW+eqeXKJ8Hj)
port: 443

uri:
webhook: ENC(d6rn2vUIq/fnrv6k5m9EhuVtKxJGXm6Qf5NPGgaPMHa1yBld8nFPwxTh/XX9iVqweVSvnLXj0RNYQ9vNsoOiR1YtfqQi7jBFDtGYT7T8KEHZ6FVnwx499LoHKHAZBKF4GoX1kawUV7iPP+tSr5UvNkZkjGEYUqBzqmVgXvTXZng=)
8 changes: 5 additions & 3 deletions module-domain/src/test/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ spring:
port: 587
username: username
password: password
sign-up-email-send-mail:
reset-password-for-auth-send-mail:
auth-token:

jwt:
secret:
Expand All @@ -43,4 +41,8 @@ ygtang:
jdbcUrl: jdbc:h2:mem:;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
username: sa
password:
driver-class-name: org.h2.Driver
driver-class-name: org.h2.Driver
server:
scheme: http
host: localhost
port: 8080
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
Expand Down Expand Up @@ -48,9 +49,26 @@ void sendEmailForSignup() throws Exception {
// then 1
.andExpect(status().isCreated());
// then 2
//String authToken = redisService.getData(RedisKey.EAUTH_SIGN_UP.getKey() + email);
//assertThat(authToken).isNotBlank();
//verify(signUpEmailSendService).send(any(), any());
verify(signUpEmailSendService).send(any(), any());
}

@DisplayName("인증 메일 발송: '+ '문자 포함된 이메일도 허용")
@Test
void sendEmailForSignup_withPlusCharacter() throws Exception {
// given
String email = "localpart+1@domain";
SendEmailRequest sendEmailRequest = new SendEmailRequest();
sendEmailRequest.setEmail(email);
doNothing().when(signUpEmailSendService).send(any(), any());
// when
mockMvc.perform(
post("/api/v1/auth/sends-email/signup")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsBytes(sendEmailRequest)))
// then 1
.andExpect(status().isCreated());
// then 2
verify(signUpEmailSendService).send(any(), any());
}

@DisplayName("인증 메일 링크 통해 이메일 소유 확인")
Expand All @@ -72,4 +90,4 @@ void authenticateEmailOfSignUp() throws Exception {
// then
.andExpect(status().isFound());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import inspiration.domain.member.Member;
import inspiration.domain.member.MemberRepository;
import inspiration.domain.member.request.SignUpRequest;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
Expand All @@ -21,8 +22,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
Expand Down Expand Up @@ -75,4 +75,38 @@ void signUp() throws Exception {
assertThat(member.get().getEmail()).isEqualTo(email);
assertThat(member.get().getNickname()).isEqualTo("nickname");
}
}

@DisplayName("회원 추가정보 수정: ageGroup이 null 이어도 성공한다.")
@Test
void testAgeGroupIsNull() throws Exception {
// given
String email = "localpart@domain";
SendEmailRequest sendEmailRequest = new SendEmailRequest();
sendEmailRequest.setEmail(email);
doNothing().when(signUpEmailSendService).send(any(), any());
mockMvc.perform(post("/api/v1/auth/sends-email/signup")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsBytes(sendEmailRequest)))
.andExpect(status().isCreated());
mockMvc.perform(get("/api/v1/auth/email/signup")
.queryParam("email", email))
.andExpect(status().isFound());
SignUpRequest signUpRequest = new SignUpRequest();
signUpRequest.setEmail(email);
signUpRequest.setNickName("nickname");
signUpRequest.setPassword("password");
signUpRequest.setConfirmPassword("password");
mockMvc.perform(
post("/api/v1/signup")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsBytes(signUpRequest)))
.andExpect(status().isCreated());
// when
mockMvc.perform(patch("/api/v1/signup/extra-informations")
.queryParam("email", email)
.contentType(MediaType.APPLICATION_JSON)
.content("{\"gender\":\"ETC\",\"ageGroup\":null,\"job\":\"job\"}")
// then
).andExpect(status().isOk());
}
}
Loading

0 comments on commit 805e1d1

Please sign in to comment.