Skip to content

Commit

Permalink
Merge pull request #125 from onetime-with-members/test
Browse files Browse the repository at this point in the history
Test to Develop
  • Loading branch information
bbbang105 authored Dec 1, 2024
2 parents d6e0b89 + 332553a commit 486927f
Show file tree
Hide file tree
Showing 28 changed files with 2,671 additions and 76 deletions.
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

0 comments on commit 486927f

Please sign in to comment.