Skip to content

Commit

Permalink
Feat/#3 post application (#4)
Browse files Browse the repository at this point in the history
* chore: restdocs를 위한 설정 (#3)

* chore: restdocs를 위한 설정 (#3)

* feat: 지원서 제출을 위한 엔티티 생성 (#3)

* feat: 개인정보 보호를 위한 암호화 설정 (#3)

* test: 지원서 작성 api 문서 작성 (#3)

* feat: 지원서 작성 api 완성 (#3)
  • Loading branch information
birdieHyun authored Oct 18, 2023
1 parent 7d0e87f commit 01c1803
Show file tree
Hide file tree
Showing 21 changed files with 718 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/docs/asciidoc/api/application/application.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
=== 지원서 작성

==== HTTP Request

include::{snippets}/application-create-doc/http-request.adoc[]
include::{snippets}/application-create-doc/request-fields.adoc[]
42 changes: 42 additions & 0 deletions src/docs/asciidoc/common.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
== Host

|===
| 환경 | Host

| Production
| `api.yonsei-golf.co.kr`
|===

[[HTTP-STATUS-CODE]]
== HTTP status codes

|===
| 상태 코드 | 설명

| `200 OK`
| 성공

| `400 Bad Request`
| 잘못된 요청

| `401 Unauthorized`
| 비인증 상태

| `403 Forbidden`
| 권한 거부

| `404 Not Found`
| 존재하지 않는 요청 리소스

| `500 Internal Server Error`
| 서버 에러
|===

=== Common Response
include::{snippets}/common-docs/custom-response-fields.adoc[]

=== Response Example
include::{snippets}/common-docs/http-response.adoc[]

=== Response Error Example
include::{snippets}/error-docs/http-response.adoc[]
18 changes: 18 additions & 0 deletions src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
ifndef::snippets[]
:snippets: ../build/generated-snippets
endif::[]
= yonsei-golf REST API 문서
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 2

:sectlinks:

[[Common-API]]
= 공통 API
include::common.adoc[]

[[ Application-API ]]
include::api/application/application.adoc[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package yonseigolf.server.apply.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import yonseigolf.server.apply.dto.request.ApplicationRequest;
import yonseigolf.server.apply.service.ApplyService;
import yonseigolf.server.util.CustomResponse;

@Controller
public class ApplicationController {

private final ApplyService applicationService;

public ApplicationController(ApplyService applicationService) {

this.applicationService = applicationService;
}

@PostMapping("/application")
public ResponseEntity<CustomResponse> apply(@RequestBody ApplicationRequest request) {

applicationService.apply(request);

return ResponseEntity
.ok()
.body(new CustomResponse(
"success",
200,
"연세골프 지원서 제출 성공"
));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package yonseigolf.server.apply.dto.request;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ApplicationRequest {

private String name;
private String photo;
private long age;
private long studentId;
private String major;
private String phoneNumber;
private long golfDuration;
private long roundCount;
private boolean lessonStatus;
private boolean clubStatus;
private String selfIntroduction;
private String applyReason;
private String skillEvaluation;
private String golfMemory;
// 다른 동아리 활동 질문
private String otherClub;
private String swingVideo;
private LocalDateTime submitTime;
}
70 changes: 70 additions & 0 deletions src/main/java/yonseigolf/server/apply/entity/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package yonseigolf.server.apply.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import yonseigolf.server.apply.dto.request.ApplicationRequest;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.time.LocalDateTime;

@Entity
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Application {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String photo;
private long age;
private long studentId;
private String major;
private String phoneNumber;
private long golfDuration;
private long roundCount;
private boolean lessonStatus;
private boolean clubStatus;
private String selfIntroduction;
private String applyReason;
private String skillEvaluation;
private String golfMemory;
// 다른 동아리 활동 질문
private String otherClub;
private String swingVideo;
private LocalDateTime submitTime;
private Boolean passFail;
private String etc;
private Long interviewId;

public static Application of(ApplicationRequest request) {

return Application.builder()
.name(request.getName())
.photo(request.getPhoto())
.age(request.getAge())
.studentId(request.getStudentId())
.major(request.getMajor())
.phoneNumber(request.getPhoneNumber())
.golfDuration(request.getGolfDuration())
.roundCount(request.getRoundCount())
.lessonStatus(request.isLessonStatus())
.clubStatus(request.isClubStatus())
.selfIntroduction(request.getSelfIntroduction())
.applyReason(request.getApplyReason())
.skillEvaluation(request.getSkillEvaluation())
.golfMemory(request.getGolfMemory())
.otherClub(request.getOtherClub())
.swingVideo(request.getSwingVideo())
.submitTime(LocalDateTime.now())
.build();

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package yonseigolf.server.apply.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import yonseigolf.server.apply.entity.Application;

public interface ApplicationRepository extends JpaRepository<Application, Long> {

}
24 changes: 24 additions & 0 deletions src/main/java/yonseigolf/server/apply/service/ApplyService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package yonseigolf.server.apply.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import yonseigolf.server.apply.dto.request.ApplicationRequest;
import yonseigolf.server.apply.entity.Application;
import yonseigolf.server.apply.repository.ApplicationRepository;

@Service
public class ApplyService {

private final ApplicationRepository applicationRepository;

@Autowired
public ApplyService(ApplicationRepository applicationRepository) {

this.applicationRepository = applicationRepository;
}

public void apply(ApplicationRequest request) {

applicationRepository.save(Application.of(request));
}
}
82 changes: 82 additions & 0 deletions src/main/java/yonseigolf/server/util/AesEncryptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package yonseigolf.server.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

@Component
public class AesEncryptor {

private String ALGORITHM;
private String KEY_STR;
private byte[] KEY;

@Autowired
public AesEncryptor(@Value("${ALGORITHM}") String algorithm,
@Value("${SECRET_KEY}") String keyStr) {
this.ALGORITHM = algorithm;
this.KEY_STR = keyStr;
this.KEY = KEY_STR.getBytes(StandardCharsets.UTF_8);
}

public String encrypt(String data) {

if (data == null) {
return null;
}

byte[] encryptedBytes = null;
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
SecretKeySpec secretKey = new SecretKeySpec(KEY, "AES");

byte[] iv = new byte[16]; // IV length should be 16 bytes for AES
new SecureRandom().nextBytes(iv);
IvParameterSpec ivSpec = new IvParameterSpec(iv);

cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));

byte[] finalData = new byte[iv.length + encryptedBytes.length];
System.arraycopy(iv, 0, finalData, 0, iv.length);
System.arraycopy(encryptedBytes, 0, finalData, iv.length, encryptedBytes.length);

encryptedBytes = finalData;
} catch (Exception e) {
e.printStackTrace();
}
return Base64.getEncoder().encodeToString(encryptedBytes);
}

public String decrypt(String encryptedData) {

if (encryptedData == null) {
return null;
}

byte[] decryptedBytes = null;
try {
Cipher cipher = Cipher.getInstance(ALGORITHM);
SecretKeySpec secretKey = new SecretKeySpec(KEY, "AES");

byte[] decodedData = Base64.getDecoder().decode(encryptedData);
byte[] iv = new byte[16]; // extracting IV from encrypted data
System.arraycopy(decodedData, 0, iv, 0, 16);

IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);

decryptedBytes = cipher.doFinal(decodedData, 16, decodedData.length - 16);
} catch (Exception e) {
e.printStackTrace();
}
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
}
20 changes: 20 additions & 0 deletions src/main/java/yonseigolf/server/util/CustomErrorResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package yonseigolf.server.util;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class CustomErrorResponse {

private String status;
private int code;
private String message;
private Object data = null;

public CustomErrorResponse(String status, int code, String message) {
this.status = status;
this.code = code;
this.message = message;
}
}
21 changes: 21 additions & 0 deletions src/main/java/yonseigolf/server/util/CustomResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package yonseigolf.server.util;


import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class CustomResponse<T> {

private String status;
private int code;
private String message;
private T data;

public CustomResponse(String status, int code, String message) {
this.status = status;
this.code = code;
this.message = message;
}
}
11 changes: 11 additions & 0 deletions src/test/java/yonseigolf/server/ServerApplicationTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package yonseigolf.server;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ServerApplicationTests {
@Test
void contextLoads() {
}
}
Loading

0 comments on commit 01c1803

Please sign in to comment.