Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/user-service/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter-validation'

// MyBatis
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.5'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.gltkorea.icebang.common.utils;

import java.security.SecureRandom;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import org.springframework.stereotype.Component;

@Component
public class RandomPasswordGenerator {

private static final String LOWERCASE = "abcdefghijklmnopqrstuvwxyz";
private static final String UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String DIGITS = "0123456789";
private static final String SPECIAL_CHARS = "!@#$%^&*()-_+=<>?";

private final SecureRandom random = new SecureRandom();

public String generate(int length) {
if (length < 8) {
length = 8;
}

StringBuilder passwordBuilder = new StringBuilder();
passwordBuilder.append(getRandomChar(LOWERCASE));
passwordBuilder.append(getRandomChar(UPPERCASE));
passwordBuilder.append(getRandomChar(DIGITS));
passwordBuilder.append(getRandomChar(SPECIAL_CHARS));

// 나머지 길이를 채우기 위해 모든 문자 집합을 사용
String allChars = LOWERCASE + UPPERCASE + DIGITS + SPECIAL_CHARS;
IntStream.range(4, length)
.forEach(
i -> {
passwordBuilder.append(getRandomChar(allChars));
});

// 생성된 문자열을 리스트로 변환하여 섞기
List<Character> passwordChars =
passwordBuilder.chars().mapToObj(c -> (char) c).collect(Collectors.toList());

Collections.shuffle(passwordChars, random);

// 다시 문자열로 합치기
return passwordChars.stream()
.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
.toString();
}

// 특정 문자열에서 랜덤으로 한 문자 선택
private char getRandomChar(String charSet) {
int randomIndex = random.nextInt(charSet.length());
return charSet.charAt(randomIndex);
}

// 기본 길이로 비밀번호 생성
public String generate() {
return generate(12); // 기본 길이를 12로 설정
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.gltkorea.icebang.domain.auth.controller;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.gltkorea.icebang.common.dto.ApiResponse;
import com.gltkorea.icebang.domain.auth.dto.RegisterDto;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping("/v0/auth")
@RequiredArgsConstructor
public class AuthController {

@PostMapping("/register")
public ApiResponse<String> register(@Valid @RequestBody RegisterDto registerDto) {

throw new RuntimeException("Not implemented");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.gltkorea.icebang.domain.auth.dto;

import java.math.BigInteger;
import java.util.Set;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class RegisterDto {

@NotBlank(message = "사용자명은 필수입니다")
private String userName;

@NotBlank(message = "이메일은 필수입니다")
@Email(message = "올바른 이메일 형식이 아닙니다")
private String email;

@NotNull(message = "조직 선택은 필수입니다")
private BigInteger orgId;

@NotNull(message = "부서 선택은 필수입니다")
private BigInteger deptId;

@NotNull(message = "직책 선택은 필수입니다")
private BigInteger positionId;

@NotNull(message = "역할 선택은 필수입니다")
private Set<BigInteger> roleIds;

@Null private String password;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.gltkorea.icebang.domain.auth.service;

import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.gltkorea.icebang.common.utils.RandomPasswordGenerator;
import com.gltkorea.icebang.domain.auth.dto.RegisterDto;
import com.gltkorea.icebang.domain.email.dto.EmailRequest;
import com.gltkorea.icebang.domain.email.service.EmailService;
import com.gltkorea.icebang.mapper.AuthMapper;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
@Transactional
public class AuthService {
private final AuthMapper authMapper;
private final RandomPasswordGenerator passwordGenerator;
private final PasswordEncoder passwordEncoder;
private final EmailService emailService;

public void registerUser(RegisterDto registerDto) {
String randomPassword = passwordGenerator.generate();
String hashedPassword = passwordEncoder.encode(randomPassword);

registerDto.setPassword(hashedPassword);

// @TODO:: Auth mapper 호출하여 insert

EmailRequest emailRequest =
EmailRequest.builder()
.to(registerDto.getEmail())
.subject("[ice-bang] 비밀번호")
.body(randomPassword)
.build();

emailService.send(emailRequest);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.gltkorea.icebang.domain.email.dto;

import java.util.List;

import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
public class EmailRequest {
private String to;
private String subject;
private String body;
private List<String> cc;
private List<String> bcc;
private boolean isHtml;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.gltkorea.icebang.domain.email.service;

import com.gltkorea.icebang.domain.email.dto.EmailRequest;

public interface EmailService {
void send(EmailRequest emailRequest);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.gltkorea.icebang.domain.email.service;

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.stereotype.Service;

import com.gltkorea.icebang.domain.email.dto.EmailRequest;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
@ConditionalOnMissingBean(EmailService.class)
public class EmailServiceImpl implements EmailService {
@Override
public void send(EmailRequest emailRequest) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.gltkorea.icebang.domain.email.service;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

import com.gltkorea.icebang.domain.email.dto.EmailRequest;

import lombok.extern.slf4j.Slf4j;

@Service
@Profile({"unit-test", "local", "develop"})
@Slf4j
public class MockEmailService implements EmailService {

@Override
public void send(EmailRequest emailRequest) {
log.info("Mock send mail to: {}", emailRequest.getTo());
log.info("Subject: {}", emailRequest.getSubject());
log.info("Body: {}", emailRequest.getBody());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.gltkorea.icebang.domain.user.service;

import org.springframework.stereotype.Service;

import com.gltkorea.icebang.domain.auth.dto.RegisterDto;
import com.gltkorea.icebang.entity.Users;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class UserService {
// private final UserMapper userMapper;

public void registerUser(RegisterDto registerDto) {
Users user =
Users.builder()
.name(registerDto.getUserName())
.email(registerDto.getEmail())
.password(registerDto.getPassword())
.status("PENDING")
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.gltkorea.icebang.entity;

import java.math.BigInteger;
import java.time.LocalDateTime;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

@Data
@Builder
@AllArgsConstructor
public class Users {
private BigInteger id;
private String name;
private String email;
private String password;
private String status;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.gltkorea.icebang.mapper;

import org.apache.ibatis.annotations.Mapper;

import com.gltkorea.icebang.domain.auth.dto.RegisterDto;

@Mapper
public interface AuthMapper {
void registerUser(RegisterDto registerDto);
}
21 changes: 21 additions & 0 deletions apps/user-service/src/main/resources/mybatis/mapper/AuthMapper.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.gltkorea.icebang.mapper.AuthMapper">
<insert id="registerUser" parameterType="com.gltkorea.icebang.domain.auth.dto.RegisterDto">
<selectKey keyProperty="id" resultType="java.math.BigInteger" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO users (name, email, password)
VALUES (#{name}, #{email}, #{password})

INSERT INTO user_organizations (user_id, organization_id, department_id, position_id, status)
VALUES (#{id}, #{organizationId}, #{departmentId}, #{positionId}, #{status})

INSERT INTO user_roles (user_organization_id, role_id)
SELECT uo.id, #{roleId}
FROM user_organizations uo
WHERE uo.user_id = #{id}
</insert>
</mapper>
Loading
Loading