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

Test to Develop #125

Merged
merged 42 commits into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3d45295
#107 [style] : 배포용 CICD 스크립트 이름을 변경한다
bbbang105 Nov 8, 2024
54372af
#107 [feat] : 테스트 서버용 CICD 스크립트를 추가한다
bbbang105 Nov 8, 2024
1191cd7
#112 [chore] : REST Docs & Swagger 관련 의존성을 추가한다
bbbang105 Nov 13, 2024
cc0a2fc
#112 [feat] : SwaggerConfig를 추가한다
bbbang105 Nov 13, 2024
751b27e
#112 [chore] : GitHub Actions 빌드 과정에서 테스트를 진행하도록 변경한다
bbbang105 Nov 13, 2024
34c9414
#112 [docs] : 초기 문서를 추가한다
bbbang105 Nov 13, 2024
ea6c1db
Merge pull request #113 from onetime-with-members/feature/#112/restdocs
bbbang105 Nov 13, 2024
8827c2d
#114 [feat] : Swagger 테스트 시 토큰을 추가할 수 있다
bbbang105 Nov 13, 2024
d1ff086
#114 [style] : API 버전을 명시한다
bbbang105 Nov 13, 2024
05ca964
#114 [feat] : Contact 내용을 추가한다
bbbang105 Nov 13, 2024
fa6d4e6
#114 [fix] : 서버 포트를 명시하여 스웨거 에러를 해결한다
bbbang105 Nov 13, 2024
77c529b
#114 [feat] : 컨트롤러 단위 테스트 설정을 추가한다
bbbang105 Nov 13, 2024
dd5272c
#114 [feat] : Event API 테스트 코드를 작성한다
bbbang105 Nov 13, 2024
6699d36
Merge pull request #116 from onetime-with-members/feature/#114/testcode
bbbang105 Nov 13, 2024
cb38234
#114 [feat] : User API 테스트 코드를 작성한다
bbbang105 Nov 13, 2024
278116c
#114 [feat] : Url API 테스트 코드를 작성한다
bbbang105 Nov 13, 2024
61383de
#114 [feat] : Token API 테스트 코드를 작성한다
bbbang105 Nov 13, 2024
3008756
#114 [style] : 공백을 추가한다
bbbang105 Nov 13, 2024
4db2ad8
#114 [feat] : Swagger 문서를 알파벳 순서로 정렬한다
bbbang105 Nov 13, 2024
0a43dde
#114 [feat] : Schedule API 테스트 코드를 작성한다
bbbang105 Nov 13, 2024
f7b82f2
#114 [feat] : Member API 테스트 코드를 작성한다
bbbang105 Nov 13, 2024
44a3fdf
#114 [feat] : Fixed API 테스트 코드를 작성한다
bbbang105 Nov 13, 2024
06a99e6
Merge pull request #117 from onetime-with-members/feature/#114/testcode
bbbang105 Nov 13, 2024
c61eea1
#115 [style] : Event API 설명을 구체화한다
bbbang105 Nov 13, 2024
e2e1893
#115 [style] : Fixed API 설명을 구체화한다
bbbang105 Nov 13, 2024
bb367b7
#115 [style] : Member API 설명을 구체화한다
bbbang105 Nov 13, 2024
5a4c51f
#115 [style] : Schedule API 설명을 구체화한다
bbbang105 Nov 13, 2024
78816cc
#115 [style] : Token API 설명을 구체화한다
bbbang105 Nov 13, 2024
902b204
#115 [style] : Url API 설명을 구체화하고, 변수명을 수정한다
bbbang105 Nov 13, 2024
b28b374
#115 [style] : User API 설명을 구체화한다
bbbang105 Nov 13, 2024
48514b7
Merge pull request #118 from onetime-with-members/feature/#115/add-an…
bbbang105 Nov 13, 2024
89dfc14
#119 [feat] : 이벤트 제목을 수정하는 기능을 추가한다
bbbang105 Nov 13, 2024
ace836b
#119 [feat] : 유저가 해당 이벤트의 생성자인지 검증하는 기능을 추가한다
bbbang105 Nov 13, 2024
3122be0
#119 [feat] : 유저는 생성한 이벤트 제목을 수정할 수 있다
bbbang105 Nov 13, 2024
f080ed9
#119 [feat] : 이벤트 제목 수정 테스트 코드를 작성하여 문서화한다
bbbang105 Nov 13, 2024
a5465f2
Merge pull request #120 from onetime-with-members/feature/#119/mod-ev…
bbbang105 Nov 13, 2024
7acc869
#121 [fix] : Origin을 추가해 CORS 문제를 해결한다
bbbang105 Nov 17, 2024
547df04
#121 [fix] : 도메인 오타를 수정한다
bbbang105 Nov 17, 2024
670b32e
Merge pull request #122 from onetime-with-members/fix/#121/swagger-cors
bbbang105 Nov 17, 2024
d8c0382
Update README.md
bbbang105 Nov 20, 2024
dbf89da
#123 [fix] : 가장 많이 되는 시간 조회 문제를 해결한다
bbbang105 Dec 1, 2024
332553a
Merge pull request #124 from onetime-with-members/fix/#123/most-error
bbbang105 Dec 1, 2024
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
4 changes: 2 additions & 2 deletions .github/workflows/cicd.yml → .github/workflows/dev-cicd.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Onetime CI/CD with Gradle
name: Onetime DEV CI/CD with Gradle

on:
push:
Expand Down Expand Up @@ -36,7 +36,7 @@ jobs:
run: chmod +x ./gradlew

- name: ⏱️gradle build 중입니다.
run: ./gradlew build -x test
run: ./gradlew clean build openapi3 asciidoctor

- name: ⏱️Docker Hub에 로그인합니다.
uses: docker/login-action@v2
Expand Down
61 changes: 61 additions & 0 deletions .github/workflows/test-cicd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Onetime TEST CI/CD with Gradle

on:
push:
branches: [ "test" ]
pull_request:
branches: [ "test" ]

permissions:
contents: read

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: ⏱️Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'

- name: ⏱️Gradle Caching - 빌드 시간 향상
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-

- name: ⏱️gradle build를 위한 권한을 부여합니다.
run: chmod +x ./gradlew

- name: ⏱️gradle build 중입니다.
run: ./gradlew clean build openapi3 asciidoctor

- name: ⏱️Docker Hub에 로그인합니다.
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}

- name: ⏱️Docker image build 후 Docker hub에 push합니다.
run: |
docker build -f Dockerfile -t ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }} .
docker push ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}

- name: ⏱️Docker hub에서 pull 후 deploy합니다.
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.GCP_TEST_SERVER_HOST }}
username: ${{ secrets.GCP_TEST_SERVER_USERNAME }}
key: ${{ secrets.GCP_SSH_KEY }}
script: |
sudo chmod 777 ./deploy.sh
./deploy.sh
sudo docker image prune -f
70 changes: 69 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,69 @@
# backend
# OneTime Backend 🚀

## 🌐 System Architecture

<img width="925" alt="image" src="https://github.com/user-attachments/assets/12ebde7d-4623-4af8-9417-7d968c91c5fa">

## 🧱 ERD

<img width="1085" alt="원타임_ERD" src="https://github.com/user-attachments/assets/ae6386ad-4ef7-4196-bc38-fde5bdfc4591">


## 📄 API Documentation

[📝 REST Docs + Swagger](https://onetime-test.store/swagger-ui/index.html#/)

## 🔒 Rules

### Branch

- 생성한 이슈에 따라서 브랜치 생성 `Ex) feature/#4/login`
- `main branch` : 개발 최종 완료 시 merge
- `develop branch` : 배포 서버용
- `test branch` : 테스트 서버용
- `feature branch` : 각 새로운 기능 개발
- `hotfix branch` : 배포 이후 긴급 수정

### **Commit Message**

- 이슈 번호 붙여서 커밋 `Ex) #4 [feat] : 로그인 기능을 추가한다`
- Body는 추가 설명 필요하면 사용

| ***작업태그*** | ***내용*** |
| --- | --- |
| **feat** | 새로운 기능 추가 / 일부 코드 추가 / 일부 코드 수정 (리팩토링과 구분) / 디자인 요소 수정 |
| **fix** | 버그 수정 |
| **refactor** | 코드 리팩토링 |
| **style** | 코드 의미에 영향을 주지 않는 변경사항 (코드 포맷팅, 오타 수정, 변수명 변경, 에셋 추가) |
| **chore** | 빌드 부분 혹은 패키지 매니저 수정 사항 / 파일 이름 변경 및 위치 변경 / 파일 삭제 |
| **docs** | 문서 추가 및 수정 |
| **rename** | 패키지 혹은 폴더명, 클래스명 수정 (단독으로 시행하였을 시) |
| **remove** | 패키지 혹은 폴더, 클래스를 삭제하였을 때 (단독으로 시행하였을 시) |

### Naming

- **패키지명** : 한 단어 소문자 사용 `Ex) service`
- **클래스명** : 파스칼 케이스 사용 `Ex) JwtUtil`
- **메서드명** : 카멜 케이스 사용, 동사로 시작 `Ex) getUserScraps`
- **변수명** : 카멜 케이스 사용 `Ex) jwtToken`
- **상수명** : 대문자 사용 `Ex) EXPIRATION_TIME`
- **컬럼명** : 스네이크 케이스 사용 `Ex) user_id`


### API Response

```json
{
"code": "201",
"message": "이벤트 생성에 성공했습니다.",
"payload": {
"event_id": "5e35b658-ee4b-4c52-98dc-94b79f0e64c9"
},
"is_success": true
}
```

- `is_success` : 성공 여부
- `code` : 성공 코드, HTTP 상태 코드와 동일
- `message` : 성공 메세지
- `payload` : 데이터가 들어가는 곳
72 changes: 71 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ plugins {
id 'java'
id 'org.springframework.boot' version '3.3.2'
id 'io.spring.dependency-management' version '1.1.6'

// REST Docs
id "org.asciidoctor.jvm.convert" version "3.3.2"
id 'com.epages.restdocs-api-spec' version '0.19.2'
id 'org.hidetake.swagger.generator' version '2.18.2'
}

group = 'side'
Expand Down Expand Up @@ -50,10 +55,75 @@ dependencies {
implementation 'io.jsonwebtoken:jjwt-api:0.12.2'
implementation 'io.jsonwebtoken:jjwt-impl:0.12.2'
implementation 'io.jsonwebtoken:jjwt-jackson:0.12.2'
// REST Docs & Swagger
testImplementation 'com.epages:restdocs-api-spec-mockmvc:0.19.2'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc:3.0.0'
testImplementation 'com.squareup.okhttp3:mockwebserver'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
}

// QueryDSL 디렉토리
def querydslDir = "src/main/generated"

// REST Docs & Swagger 설정
ext {
snippetsDir = file('build/generated-snippets')
}

tasks.named('test') {
useJUnitPlatform()
outputs.dir snippetsDir
}

sourceSets {
test {
java {
srcDirs = ['src/test/java']
}
}
}

def serverUrl = "https://onetime-test.store"

openapi3 {
server = serverUrl
title = "OneTime API Documentation"
description = "Spring REST Docs with Swagger UI."
version = "0.0.1"
outputFileNamePrefix = 'open-api-3.0.1'
format = 'json'
outputDirectory = 'build/resources/main/static/docs'
}

tasks.withType(GenerateSwaggerUI).configureEach {
dependsOn 'openapi3'

delete file('src/main/resources/static/docs/')
copy {
from "build/resources/main/static/docs"
into "src/main/resources/static/docs/"
}
}

tasks.named('asciidoctor') {
inputs.dir snippetsDir
dependsOn test
}

tasks.named("bootJar") {
dependsOn asciidoctor
from("${asciidoctor.outputDir}") {
into 'static/docs'
}
dependsOn ':openapi3'
}

tasks.register('copyDocument', Copy) {
dependsOn asciidoctor
from file(project.layout.buildDirectory.dir("docs/asciidoc").get().asFile.path)
into file("src/main/resources/static/docs")
}

def querydslDir = "src/main/generated"
tasks.named("build") {
dependsOn copyDocument
}
83 changes: 75 additions & 8 deletions src/main/java/side/onetime/controller/EventController.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import side.onetime.dto.event.request.CreateEventRequest;
import side.onetime.dto.event.request.ModifyUserCreatedEventTitleRequest;
import side.onetime.dto.event.response.*;
import side.onetime.global.common.ApiResponse;
import side.onetime.global.common.status.SuccessStatus;
Expand All @@ -18,7 +19,16 @@
public class EventController {
private final EventService eventService;

// 이벤트 생성 API
/**
* 이벤트 생성 API
*
* 이 API는 새로운 이벤트를 생성합니다. 인증된 유저와 익명 유저 모두 이벤트를 생성할 수 있으며,
* 인증된 유저의 경우 추가적인 정보가 저장됩니다.
*
* @param createEventRequest 생성할 이벤트에 대한 요청 데이터 (제목, 시작/종료 시간, 카테고리, 설문 범위 등)
* @param authorizationHeader 인증된 유저의 토큰 (선택 사항)
* @return 생성된 이벤트의 ID
*/
@PostMapping
public ResponseEntity<ApiResponse<CreateEventResponse>> createEvent(
@Valid @RequestBody CreateEventRequest createEventRequest,
Expand All @@ -34,19 +44,34 @@ public ResponseEntity<ApiResponse<CreateEventResponse>> createEvent(
return ApiResponse.onSuccess(SuccessStatus._CREATED_EVENT, createEventResponse);
}

// 이벤트 조회 API
/**
* 이벤트 조회 API
*
* 이 API는 특정 이벤트의 세부 정보를 조회합니다. 이벤트의 제목, 시간, 카테고리 등의 정보를 제공하며
* 인증된 유저일 경우 추가적인 정보가 포함될 수 있습니다.
*
* @param authorizationHeader 인증된 유저의 토큰 (선택 사항)
* @param eventId 조회할 이벤트의 ID
* @return 조회한 이벤트의 세부 정보
*/
@GetMapping("/{event_id}")
public ResponseEntity<ApiResponse<GetEventResponse>> getEvent(
@RequestHeader(value = "Authorization", required = false) String authorizationHeader,
@PathVariable("event_id") String eventId) {

GetEventResponse getEventResponse = eventService.getEvent(eventId, authorizationHeader);


return ApiResponse.onSuccess(SuccessStatus._GET_EVENT, getEventResponse);
}

// 참여자 조회 API
/**
* 참여자 조회 API
*
* 이 API는 특정 이벤트에 참여한 모든 참여자의 이름 목록을 조회합니다.
*
* @param eventId 참여자 목록을 조회할 이벤트의 ID
* @return 해당 이벤트에 참여한 참여자의 이름 목록
*/
@GetMapping("/{event_id}/participants")
public ResponseEntity<ApiResponse<GetParticipantsResponse>> getParticipants(
@PathVariable("event_id") String eventId) {
Expand All @@ -55,7 +80,14 @@ public ResponseEntity<ApiResponse<GetParticipantsResponse>> getParticipants(
return ApiResponse.onSuccess(SuccessStatus._GET_PARTICIPANTS, getParticipantsResponse);
}

// 가장 많이 되는 시간 조회 API
/**
* 가장 많이 되는 시간 조회 API
*
* 이 API는 특정 이벤트에서 가장 많이 가능한 시간대를 조회하여, 가능 인원과 해당 시간대 정보를 제공합니다.
*
* @param eventId 조회할 이벤트의 ID
* @return 가능 인원이 많은 시간대와 관련 세부 정보
*/
@GetMapping("/{event_id}/most")
public ResponseEntity<ApiResponse<List<GetMostPossibleTime>>> getMostPossibleTime(
@PathVariable("event_id") String eventId) {
Expand All @@ -64,7 +96,14 @@ public ResponseEntity<ApiResponse<List<GetMostPossibleTime>>> getMostPossibleTim
return ApiResponse.onSuccess(SuccessStatus._GET_MOST_POSSIBLE_TIME, getMostPossibleTimes);
}

// 유저 참여 이벤트 목록 조회 API
/**
* 유저 참여 이벤트 목록 조회 API
*
* 이 API는 인증된 유저가 참여한 모든 이벤트 목록을 조회합니다. 유저의 참여 상태, 이벤트 정보 등이 포함됩니다.
*
* @param authorizationHeader 인증된 유저의 토큰
* @return 유저가 참여한 이벤트 목록
*/
@GetMapping("/user/all")
public ResponseEntity<ApiResponse<List<GetUserParticipatedEventsResponse>>> getUserParticipatedEvents(
@RequestHeader("Authorization") String authorizationHeader) {
Expand All @@ -73,7 +112,15 @@ public ResponseEntity<ApiResponse<List<GetUserParticipatedEventsResponse>>> getU
return ApiResponse.onSuccess(SuccessStatus._GET_USER_PARTICIPATED_EVENTS, getUserParticipatedEventsResponses);
}

// 유저가 생성한 이벤트 삭제 API
/**
* 유저가 생성한 이벤트 삭제 API
*
* 이 API는 인증된 유저가 생성한 특정 이벤트를 삭제합니다.
*
* @param authorizationHeader 인증된 유저의 토큰
* @param eventId 삭제할 이벤트의 ID
* @return 삭제 성공 여부
*/
@DeleteMapping("/{event_id}")
public ResponseEntity<ApiResponse<SuccessStatus>> removeUserCreatedEvent(
@RequestHeader("Authorization") String authorizationHeader,
Expand All @@ -82,4 +129,24 @@ public ResponseEntity<ApiResponse<SuccessStatus>> removeUserCreatedEvent(
eventService.removeUserCreatedEvent(authorizationHeader, eventId);
return ApiResponse.onSuccess(SuccessStatus._REMOVE_USER_CREATED_EVENT);
}
}

/**
* 유저가 생성한 이벤트 제목 수정 API
*
* 이 API는 인증된 유저가 생성한 특정 이벤트의 제목을 수정합니다.
*
* @param authorizationHeader 인증된 유저의 토큰
* @param eventId 제목을 수정할 이벤트의 ID
* @param modifyUserCreatedEventTitleRequest 새로운 제목 정보가 담긴 요청 데이터
* @return 수정 성공 여부
*/
@PutMapping("/{event_id}")
public ResponseEntity<ApiResponse<SuccessStatus>> modifyUserCreatedEventTitle(
@RequestHeader("Authorization") String authorizationHeader,
@PathVariable("event_id") String eventId,
@Valid @RequestBody ModifyUserCreatedEventTitleRequest modifyUserCreatedEventTitleRequest) {

eventService.modifyUserCreatedEventTitle(authorizationHeader, eventId, modifyUserCreatedEventTitleRequest);
return ApiResponse.onSuccess(SuccessStatus._MODIFY_USER_CREATED_EVENT_TITLE);
}
}
Loading