Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Phase 1 #30

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
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
5 changes: 4 additions & 1 deletion fillin/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,7 @@ out/
**/build/**
**/.gradle/**
**/gradle/**
.idea/**
.idea/**

### secret
**/resources/secret
16 changes: 15 additions & 1 deletion fillin/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

// versions
val guavaVersion: String by properties

plugins {
java
id("org.springframework.boot") version "2.7.17"
id("io.spring.dependency-management") version "1.0.15.RELEASE"
kotlin("plugin.spring") apply true
kotlin("jvm") apply true

}

group = "com.teamfillin"
Expand All @@ -27,14 +31,24 @@ repositories {

dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-validation")
compileOnly("org.projectlombok:lombok")
runtimeOnly("com.h2database:h2")
runtimeOnly("com.mysql:mysql-connector-j")
annotationProcessor("org.projectlombok:lombok")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
testImplementation("org.springframework.boot:spring-boot-starter-test")

// guava
implementation("com.google.guava:guava:$guavaVersion")

// apache
implementation("org.apache.commons:commons-lang3:3.14.0")

// jwt
implementation("io.jsonwebtoken:jjwt:0.12.3")

// kotlin
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
Expand Down
5 changes: 4 additions & 1 deletion fillin/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
springBootVersion=2.7.17
springDependencyManagementVersion=1.0.15.RELEASE
kotlinVersion=1.6.21
kotlinSpringVersion=1.6.21
kotlinSpringVersion=1.6.21

# guava
guavaVersion=32.1.3-jre
11 changes: 11 additions & 0 deletions fillin/lombok.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
lombok.allArgsConstructor.flagUsage = error
lombok.requiredArgsConstructor.flagUsage = error
lombok.noArgsConstructor.flagUsage = error
lombok.getter.flagUsage = error
lombok.data.flagUsage = error
lombok.setter.flagUsage = error
lombok.equalsAndHashCode.flagUsage = error
lombok.var.flagUsage = error
lombok.val.flagUsage = error
lombok.value.flagUsage = error
lombok.toString.flagUsage = error
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class CoreConfiguration {
public static Map<String, Object> getProperties() {
Map<String, Object> additionalProperties = new ConcurrentHashMap<>();

additionalProperties.put("spring.config.location", "classpath:/core/, classpath:/");
additionalProperties.put("spring.config.location", "classpath:/");
return additionalProperties;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.context.annotation.Configuration;

/**
Expand All @@ -13,6 +14,9 @@
exclude = {
// jdbc datasource
DataSourceAutoConfiguration.class,

// Spring Security off
SecurityAutoConfiguration.class
}
)
public class DisableAutoConfiguration {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@EnableJpaAuditing
@SpringBootApplication
public class FillinApplication {

Expand Down
17 changes: 17 additions & 0 deletions fillin/src/main/java/com/teamfillin/fillin/FillinErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.teamfillin.fillin;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.http.HttpStatus;

public interface FillinErrorCode {

@NotNull
String name();

@NotNull
HttpStatus status();

@Nullable
String defaultMessage();
}
64 changes: 64 additions & 0 deletions fillin/src/main/java/com/teamfillin/fillin/FillinException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.teamfillin.fillin;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.util.StringUtils;

import lombok.Builder;

public class FillinException extends RuntimeException {
@NotNull
protected final FillinErrorCode errorCode;

@Nullable
protected final String message;

@Nullable
protected final String log;

private FillinException(@NotNull FillinErrorCode errorCode) {
super(makeMessage(errorCode, null));
this.errorCode = errorCode;
this.message = errorCode.defaultMessage();
this.log = null;
}

@Builder
private FillinException(@NotNull FillinErrorCode errorCode, @Nullable String message, @Nullable String log) {
super(makeMessage(errorCode, message));
this.errorCode = errorCode;
this.log = log;
this.message = StringUtils.hasText(message) ? message : errorCode.defaultMessage();
}

public static FillinException from(@NotNull FillinErrorCode errorCode) {
return new FillinException(errorCode);
}

private static String makeMessage(@NotNull FillinErrorCode errorCode, @Nullable String detailMessage) {
return StringUtils.hasText(detailMessage)
? errorCode.name() + ": " + detailMessage
: StringUtils.hasText(errorCode.defaultMessage())
? errorCode.name() + ": " + errorCode.defaultMessage()
: errorCode.name();
}

@NotNull
public FillinErrorCode getErrorCode() {
return errorCode;
}

@Nullable
public String getLog() {
return log;
}

@Override
public String toString() {
return message != null
? errorCode.name() + ": " + message
: StringUtils.hasText(errorCode.defaultMessage())
? errorCode.name() + ": " + errorCode.defaultMessage()
: errorCode.name();
}
}
130 changes: 130 additions & 0 deletions fillin/src/main/java/com/teamfillin/fillin/api/FillinApiResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package com.teamfillin.fillin.api;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.teamfillin.fillin.FillinErrorCode;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class FillinApiResponse {
private final int status;

private final boolean success;

@Nullable
private final Object data;

@Nullable
private final String message;

private FillinApiResponse(int status, boolean success) {
this.status = status;
this.success = success;
this.data = null;
this.message = null;
}

private FillinApiResponse(int status, boolean success, @Nullable Object data, @Nullable String message) {
this.status = status;
this.success = success;
this.data = data;
this.message = message;
}

public static ResponseEntity<FillinApiResponse> success() {
return success(HttpStatus.OK);
}

public static ResponseEntity<FillinApiResponse> success(@NotNull HttpStatus status) {
return ResponseEntity
.status(status)
.body(successBody(status));
}

public static ResponseEntity<FillinApiResponse> success(@NotNull Object data) {
return success(HttpStatus.OK, data);
}

public static ResponseEntity<FillinApiResponse> success(
@NotNull HttpStatus httpStatus,
@NotNull Object data,
@Nullable String message
) {
return ResponseEntity
.status(httpStatus)
.body(successBody(httpStatus, data, message));
}

public static ResponseEntity<FillinApiResponse> success(@NotNull HttpStatus httpStatus, @NotNull Object data) {
return ResponseEntity
.status(httpStatus)
.body(successBody(httpStatus, data));
}

public static ResponseEntity<FillinApiResponse> success(@NotNull HttpStatus httpStatus, @Nullable String message) {
return ResponseEntity
.status(httpStatus)
.body(successBody(httpStatus, null, message));
}

public static ResponseEntity<FillinApiResponse> failure(@NotNull FillinErrorCode errorCode) {
return ResponseEntity
.status(errorCode.status())
.body(failureBody(errorCode));
}

public static ResponseEntity<FillinApiResponse> failure(@NotNull FillinErrorCode errorCode,
@NotNull String message) {
return ResponseEntity
.status(errorCode.status())
.body(failureBody(errorCode.status(), message));
}

private static FillinApiResponse failureBody(@NotNull FillinErrorCode errorCode) {
return StringUtils.hasText(errorCode.defaultMessage())
? failureBody(errorCode.status(), errorCode.defaultMessage())
: new FillinApiResponse(errorCode.status().value(), false);
}

private static FillinApiResponse failureBody(@NotNull HttpStatus httpStatus, @NotNull String message) {
return new FillinApiResponse(httpStatus.value(), false, null, message);
}

private static FillinApiResponse successBody(@NotNull HttpStatus httpStatus) {
return new FillinApiResponse(httpStatus.value(), true);
}

private static FillinApiResponse successBody(@NotNull HttpStatus httpStatus, @NotNull Object data) {
return successBody(httpStatus, data, null);
}

private static FillinApiResponse successBody(
@NotNull HttpStatus httpStatus,
@Nullable Object data,
@Nullable String message
) {
return new FillinApiResponse(httpStatus.value(), true, data, message);
}

public int getStatus() {
return status;
}

public boolean isSuccess() {
return success;
}

@Nullable
public Object getData() {
return data;
}

@Nullable
public String getMessage() {
return message;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.teamfillin.fillin.api;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import com.teamfillin.fillin.FillinException;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestControllerAdvice
public class FillinExceptionHandler {
@ExceptionHandler(FillinException.class)
ResponseEntity<FillinApiResponse> handleFillinException(FillinException e) {
return FillinApiResponse.failure(e.getErrorCode());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.teamfillin.fillin.api.account;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.teamfillin.fillin.api.FillinApiResponse;
import com.teamfillin.fillin.api.token.AccessToken;
import com.teamfillin.fillin.api.token.TokenHandler;
import com.teamfillin.fillin.domain.account.AccountAccessResult;
import com.teamfillin.fillin.domain.account.AccountCreateCommand;
import com.teamfillin.fillin.domain.account.AccountService;

@RestController
public class AccountApi {
private final AccountService accountService;
private final TokenHandler tokenHandler;

public AccountApi(
AccountService accountService,
TokenHandler tokenHandler
) {
this.accountService = accountService;
this.tokenHandler = tokenHandler;
}

@PostMapping("/auth")
public ResponseEntity<FillinApiResponse> loginOrJoin(
@RequestBody AccountRequest accountRequest
) {
final AccountCreateCommand command = new AccountCreateCommand(
accountRequest.getSocial(),
accountRequest.getIdKey()
);

final AccountAccessResult accountAccessResult = accountService.loginOrJoin(command);
final AccessToken accessToken = tokenHandler.generateAccessTokenFrom(accountAccessResult);

return switch (accountAccessResult.getProcedure()) {
case JOIN ->
FillinApiResponse.success(HttpStatus.CREATED, AccountResponse.from(accountAccessResult, accessToken));
case LOGIN -> // Client 에 해당 api 200 상태코드 적용 가능 여부 확인 필요!
FillinApiResponse.success(HttpStatus.OK, AccountResponse.from(accountAccessResult, accessToken));
};
}
}
Loading