Skip to content

Commit

Permalink
Merge branch 'dev' into feat/#16/question-register-get-api
Browse files Browse the repository at this point in the history
  • Loading branch information
hyun2371 authored Aug 4, 2024
2 parents 671162c + 5b1615f commit 492a88d
Show file tree
Hide file tree
Showing 38 changed files with 1,554 additions and 18 deletions.
8 changes: 7 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,17 @@ dependencies {
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

// S3

/*JWT 관련 라이브러리*/
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
implementation 'io.jsonwebtoken:jjwt-impl:0.12.3'
implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3'

implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

//spring bean validation
implementation 'org.springframework.boot:spring-boot-starter-validation'

}

tasks.named('test') {
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/com/dnd/gongmuin/auth/cotroller/AuthController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.dnd.gongmuin.auth.cotroller;

import java.net.URI;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import lombok.RequiredArgsConstructor;

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

@GetMapping("signin/kakao")
public ResponseEntity<?> kakaoLoginRedirect() {
HttpHeaders httpHeaders = new HttpHeaders();
// 카카오 로그인 페이지로 리다이렉트
httpHeaders.setLocation(URI.create("/oauth2/authorization/kakao"));
return new ResponseEntity<>(httpHeaders, HttpStatus.MOVED_PERMANENTLY);
}
}

64 changes: 64 additions & 0 deletions src/main/java/com/dnd/gongmuin/auth/domain/Auth.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.dnd.gongmuin.auth.domain;

import static jakarta.persistence.ConstraintMode.*;

import com.dnd.gongmuin.member.domain.Member;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.ForeignKey;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class Auth {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Enumerated(EnumType.STRING)
@Column(name = "provider", nullable = false)
private Provider provider;

@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false)
private AuthStatus status;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id",
nullable = false,
foreignKey = @ForeignKey(NO_CONSTRAINT))
private Member member;

@Builder
private Auth(Provider provider, AuthStatus status, Member member) {
this.provider = provider;
this.status = status;
this.member = member;
}

public static Auth of(Provider provider, AuthStatus status, Member member) {
return Auth.builder()
.provider(provider)
.status(status)
.member(member)
.build();
}

public void updateStatus() {
this.status = AuthStatus.OLD;
}
}
14 changes: 14 additions & 0 deletions src/main/java/com/dnd/gongmuin/auth/domain/AuthStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.dnd.gongmuin.auth.domain;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum AuthStatus {

NEW("신규"),
OLD("기존");

private final String label;
}
26 changes: 26 additions & 0 deletions src/main/java/com/dnd/gongmuin/auth/domain/Provider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.dnd.gongmuin.auth.domain;

import java.util.Arrays;

import com.dnd.gongmuin.auth.exception.AuthErrorCode;
import com.dnd.gongmuin.common.exception.runtime.NotFoundException;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum Provider {

KAKAO("kakao"),
NAVER("naver");

private final String provider;

public static Provider fromProviderName(String providerName) {
return Arrays.stream(values())
.filter(provider -> provider.getProvider().equalsIgnoreCase(providerName))
.findFirst()
.orElseThrow(() -> new NotFoundException(AuthErrorCode.NOT_FOUND_PROVIDER));
}
}
18 changes: 18 additions & 0 deletions src/main/java/com/dnd/gongmuin/auth/exception/AuthErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.dnd.gongmuin.auth.exception;

import com.dnd.gongmuin.common.exception.ErrorCode;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum AuthErrorCode implements ErrorCode {

UNSUPPORTED_SOCIAL_LOGIN("해당 소셜 로그인은 지원되지 않습니다.", "AUHT_001"),
NOT_FOUND_PROVIDER("알맞은 Provider를 찾을 수 없습니다.", "AUTH_002"),
NOT_FOUND_AUTH("회원의 AUTH를 찾을 수 없습니다.", "AUTH_003");

private final String message;
private final String code;
}
13 changes: 13 additions & 0 deletions src/main/java/com/dnd/gongmuin/auth/repository/AuthRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.dnd.gongmuin.auth.repository;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;

import com.dnd.gongmuin.auth.domain.Auth;
import com.dnd.gongmuin.member.domain.Member;

public interface AuthRepository extends JpaRepository<Auth, Long> {

Optional<Auth> findByMember(Member member);
}
52 changes: 52 additions & 0 deletions src/main/java/com/dnd/gongmuin/auth/service/AuthService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.dnd.gongmuin.auth.service;

import java.util.Objects;

import org.springframework.stereotype.Service;

import com.dnd.gongmuin.auth.domain.Auth;
import com.dnd.gongmuin.auth.domain.AuthStatus;
import com.dnd.gongmuin.auth.domain.Provider;
import com.dnd.gongmuin.auth.exception.AuthErrorCode;
import com.dnd.gongmuin.auth.repository.AuthRepository;
import com.dnd.gongmuin.common.exception.runtime.NotFoundException;
import com.dnd.gongmuin.member.domain.Member;
import com.dnd.gongmuin.member.service.MemberService;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class AuthService {

private final AuthRepository authRepository;
private final MemberService memberService;

public void saveOrUpdate(Member savedMember) {
Auth findedOrCreatedAuth = authRepository.findByMember(savedMember)
.map(auth -> {
if (!memberService.isOfficialEmail(savedMember)) {
auth.updateStatus();
}
return auth;
})
.orElse(createAuth(savedMember));

authRepository.save(findedOrCreatedAuth);
}

public boolean isAuthStatusOld(Member member) {
Auth findAuth = authRepository.findByMember(member)
.orElseThrow(() -> new NotFoundException(AuthErrorCode.NOT_FOUND_AUTH));

return Objects.equals(findAuth.getStatus(), AuthStatus.OLD);
}

private Auth createAuth(Member savedMember) {
String providerName = memberService.parseProviderFromSocialEmail(savedMember);
Provider provider = Provider.fromProviderName(providerName);

return Auth.of(provider, AuthStatus.NEW, savedMember);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.dnd.gongmuin.common.exception.runtime;

import com.dnd.gongmuin.common.exception.ErrorCode;

import lombok.Getter;

@Getter
public class CustomJwtException extends RuntimeException {

private final String code;

public CustomJwtException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.code = errorCode.getCode();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.dnd.gongmuin.member.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
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.dnd.gongmuin.member.dto.request.AdditionalInfoRequest;
import com.dnd.gongmuin.member.dto.request.ValidateNickNameRequest;
import com.dnd.gongmuin.member.dto.response.SignUpResponse;
import com.dnd.gongmuin.member.dto.response.ValidateNickNameResponse;
import com.dnd.gongmuin.member.service.MemberService;
import com.dnd.gongmuin.security.oauth2.CustomOauth2User;

import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/auth")
public class MemberController {

private final MemberService memberService;

@PostMapping("/check-nickname")
public ResponseEntity<ValidateNickNameResponse> checkNickName(
@RequestBody ValidateNickNameRequest validateNickNameRequest) {
return ResponseEntity.ok(memberService.isDuplicatedNickname(validateNickNameRequest));
}

@PostMapping("/member")
public ResponseEntity<SignUpResponse> signUp(@RequestBody AdditionalInfoRequest request,
@AuthenticationPrincipal CustomOauth2User loginMember) {
SignUpResponse response = memberService.signUp(request, loginMember.getEmail());

return ResponseEntity.ok(response);
}

}
44 changes: 39 additions & 5 deletions src/main/java/com/dnd/gongmuin/member/domain/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,31 +25,31 @@ public class Member extends TimeBaseEntity {
@Column(name = "member_id")
private Long id;

@Column(name = "nickname", nullable = false)
@Column(name = "nickname")
private String nickname;

@Column(name = "social_name", nullable = false)
private String socialName;

@Enumerated(STRING)
@Column(name = "job_group", nullable = false)
@Column(name = "job_group")
private JobGroup jobGroup;

@Enumerated(STRING)
@Column(name = "job_category", nullable = false)
@Column(name = "job_category")
private JobCategory jobCategory;

@Column(name = "social_email", nullable = false)
private String socialEmail;

@Column(name = "official_email", nullable = false)
@Column(name = "official_email")
private String officialEmail;

@Column(name = "credit", nullable = false)
private int credit;

@Builder
public Member(String nickname, String socialName, JobGroup jobGroup, JobCategory jobCategory, String socialEmail,
private Member(String nickname, String socialName, JobGroup jobGroup, JobCategory jobCategory, String socialEmail,
String officialEmail, int credit) {
this.nickname = nickname;
this.socialName = socialName;
Expand All @@ -59,4 +59,38 @@ public Member(String nickname, String socialName, JobGroup jobGroup, JobCategory
this.officialEmail = officialEmail;
this.credit = credit;
}

public static Member of(String socialName, String socialEmail, int credit) {
return Member.builder()
.socialName(socialName)
.socialEmail(socialEmail)
.credit(credit)
.build();
}

public static Member of(String nickname, String socialName, JobGroup jobGroup, JobCategory jobCategory,
String socialEmail, String officialEmail, int credit) {
return Member.builder()
.nickname(nickname)
.socialName(socialName)
.jobGroup(jobGroup)
.jobCategory(jobCategory)
.socialEmail(socialEmail)
.officialEmail(officialEmail)
.credit(credit)
.build();
}

public void updateSocialEmail(String socialEmail) {
this.socialEmail = socialEmail;
}

public void updateAdditionalInfo(String nickname, String officialEmail,
JobGroup jobGroup, JobCategory jobCategory) {
this.nickname = nickname;
this.officialEmail = officialEmail;
this.jobGroup = jobGroup;
this.jobCategory = jobCategory;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.dnd.gongmuin.member.dto.request;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

public record AdditionalInfoRequest(

@NotBlank(message = "공무원 이메일은 필수 입력 항목입니다.")
String officialEmail,
@NotBlank(message = "닉네임은 필수 입력 항목입니다.")
@Size(min = 2, max = 12, message = "닉네임은 최소 2자리 이상 최대 12자 이하입니다.")
String nickname,
@NotBlank(message = "직군은 필수 입력 항목입니다.")
String jobGroup,
@NotBlank(message = "직렬은 필수 입력 항목입니다.")
String jobCategory
) {
}
Loading

0 comments on commit 492a88d

Please sign in to comment.