Skip to content

Commit 55edcd2

Browse files
authored
Release 0.0.3 (#130)
2 parents 2fbedd8 + b7160c3 commit 55edcd2

File tree

15 files changed

+154
-12
lines changed

15 files changed

+154
-12
lines changed

.github/workflows/deploy.yml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ jobs:
1212
build:
1313
name: Deploy API specification
1414
runs-on: ubuntu-latest
15+
if: github.ref_name == 'dev'
1516
environment: ${{ github.ref_name }}
1617
steps:
1718
- name: Checkout repository
@@ -95,7 +96,7 @@ jobs:
9596
host: ${{ secrets.EC2_HOST }}
9697
username: ${{ secrets.EC2_USER }}
9798
key: ${{ secrets.EC2_PRIVATE_KEY }}
98-
source: docker/docker-compose.yml
99+
source: docker/docker-compose-${{ github.ref_name }}.yml
99100
target: "~"
100101
strip_components: 1
101102
- name: Build and deploy container to AWS EC2
@@ -106,9 +107,12 @@ jobs:
106107
key: ${{ secrets.EC2_PRIVATE_KEY }}
107108
script: |
108109
aws secretsmanager get-secret-value --secret-id ${{ github.ref_name }}-env --region ap-northeast-2 --query SecretString --output text | jq -r '. | to_entries | map("\(.key)=\(.value)") | .[]' > .env
109-
aws s3 cp s3://${{ secrets.API_SPECIFICATION_BUCKET }}/api.yml .
110110
export IMAGE_URI=${{ secrets.ECR_REGISTRY }}/${{ secrets.ECR_REPOSITORY }}:${{ github.sha }}
111-
docker-compose --env-file .env up -d --build
111+
docker-compose -f docker-compose-${{ github.ref_name }}.yml --env-file .env up -d --build
112+
if [ "${{ github.ref_name }}" = "dev" ]; then
113+
aws s3 cp s3://${{ secrets.API_SPECIFICATION_BUCKET }}/api.yml .
114+
docker restart swagger
115+
fi
112116
notify-discord:
113117
name: Notify Discord
114118
runs-on: ubuntu-latest
@@ -127,7 +131,7 @@ jobs:
127131
"embeds": [
128132
{
129133
"title": "**${{ github.ref_name == 'prod' && '프로덕션' || '개발' }} 환경 배포 성공**",
130-
"description": "프로젝트가 성공적으로 배포되었습니다.",
134+
"description": "서버가 성공적으로 배포되었습니다.",
131135
"color": 3066993,
132136
"fields": [
133137
{

api/src/main/kotlin/com/gotchai/api/presentation/v1/admin/AdminController.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,14 @@ class AdminController(
3131
) {
3232
adminCommandUseCase.deleteExamHistoryByExamIdAndUserId(examId, userId)
3333
}
34+
35+
@DeleteMapping("/admin/users/{userId}/badges/{badgeId}")
36+
fun deleteUserBadge(
37+
@PathVariable
38+
userId: Long,
39+
@PathVariable
40+
badgeId: Long
41+
) {
42+
adminCommandUseCase.deleteUserBadgeByBadgeIdAndUserId(userId, badgeId)
43+
}
3444
}

api/src/test/kotlin/com/gotchai/api/presentation/v1/admin/AdminControllerTest.kt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.gotchai.api.presentation.v1.admin
22

33
import com.gotchai.api.common.ControllerTest
44
import com.gotchai.api.docs.createExamRequestFields
5+
import com.gotchai.api.docs.errorResponseFields
56
import com.gotchai.api.docs.examResponseFields
67
import com.gotchai.api.fixture.createCreateExamRequest
78
import com.gotchai.api.global.dto.ApiResponse
@@ -11,6 +12,7 @@ import com.gotchai.api.util.desc
1112
import com.gotchai.api.util.document
1213
import com.gotchai.api.util.expectError
1314
import com.gotchai.domain.admin.port.`in`.AdminCommandUseCase
15+
import com.gotchai.domain.badge.exception.UserBadgeNotFoundException
1416
import com.gotchai.domain.exam.exception.ExamHistoryNotFoundException
1517
import com.gotchai.domain.fixture.ID
1618
import com.gotchai.domain.fixture.createExam
@@ -87,6 +89,50 @@ class AdminControllerTest : ControllerTest() {
8789
"userId" desc "유저 식별자",
8890
"examId" desc "테스트 식별자"
8991
)
92+
responseBody(errorResponseFields)
93+
}
94+
}
95+
}
96+
}
97+
98+
describe("deleteUserBadge()는") {
99+
context("유저가 취득한 뱃지가 존재하는 경우") {
100+
every { adminCommandUseCase.deleteUserBadgeByBadgeIdAndUserId(ID, ID) } just runs
101+
102+
it("상태 코드 200을 반환한다.") {
103+
webClient
104+
.delete()
105+
.uri("/api/v1/admin/users/{userId}/badges/{badgeId}", ID, ID)
106+
.exchange()
107+
.expectStatus()
108+
.isOk
109+
.expectBody<Void>()
110+
.document("유저가 취득한 뱃지 삭제 성공(200)") {
111+
pathParams(
112+
"userId" desc "유저 식별자",
113+
"badgeId" desc "뱃지 식별자"
114+
)
115+
}
116+
}
117+
}
118+
119+
context("유저가 취득한 뱃지가 존재하지 않는 경우") {
120+
every { adminCommandUseCase.deleteUserBadgeByBadgeIdAndUserId(ID, ID) } throws UserBadgeNotFoundException()
121+
122+
it("상태 코드 404를 반환한다.") {
123+
webClient
124+
.delete()
125+
.uri("/api/v1/admin/users/{userId}/badges/{badgeId}", ID, ID)
126+
.exchange()
127+
.expectStatus()
128+
.isNotFound
129+
.expectError()
130+
.document("유저가 취득한 뱃지 삭제 실패(404)") {
131+
pathParams(
132+
"userId" desc "유저 식별자",
133+
"badgeId" desc "뱃지 식별자"
134+
)
135+
responseBody(errorResponseFields)
90136
}
91137
}
92138
}

docker/docker-compose-local.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ services:
99
- "name=redis"
1010
- "mode=standalone"
1111
mysql:
12-
image: mysql:8.4.3
12+
image: mysql
1313
container_name: mysql
1414
restart: always
1515
ports:

docker/docker-compose-prod.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
services:
2+
gotchai-server:
3+
image: ${IMAGE_URI}
4+
container_name: gotchai-server
5+
restart: always
6+
environment:
7+
- TZ=Asia/Seoul
8+
ports:
9+
- "8080:8080"
10+
depends_on:
11+
- redis
12+
env_file:
13+
- .env
14+
redis:
15+
image: redis:alpine
16+
container_name: redis
17+
ports:
18+
- "6379:6379"
19+
environment:
20+
- TZ=Asia/Seoul
21+
command: [ "redis-server", "--maxmemory", "64mb" ]

domain/src/main/kotlin/com/gotchai/domain/admin/adapter/in/AdminCommandService.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package com.gotchai.domain.admin.adapter.`in`
33
import com.gotchai.domain.admin.dto.command.CreateExamCommand
44
import com.gotchai.domain.admin.exception.InvalidFileException
55
import com.gotchai.domain.admin.port.`in`.AdminCommandUseCase
6+
import com.gotchai.domain.badge.exception.UserBadgeNotFoundException
7+
import com.gotchai.domain.badge.port.out.UserBadgeCommandPort
8+
import com.gotchai.domain.badge.port.out.UserBadgeQueryPort
69
import com.gotchai.domain.exam.entity.Exam
710
import com.gotchai.domain.exam.exception.ExamHistoryNotFoundException
811
import com.gotchai.domain.exam.port.out.ExamCommandPort
@@ -20,6 +23,8 @@ class AdminCommandService(
2023
private val examHistoryQueryPort: ExamHistoryQueryPort,
2124
private val examHistoryCommandPort: ExamHistoryCommandPort,
2225
private val quizHistoryCommandPort: QuizHistoryCommandPort,
26+
private val userBadgeQueryPort: UserBadgeQueryPort,
27+
private val userBadgeCommandPort: UserBadgeCommandPort,
2328
private val objectStorageProvider: ObjectStorageProvider
2429
) : AdminCommandUseCase {
2530
@Transactional
@@ -55,4 +60,14 @@ class AdminCommandService(
5560
quizHistoryCommandPort.deleteQuizHistoriesByExamHistoryId(examHistory.id)
5661
examHistoryCommandPort.deleteExamHistoryByExamIdAndUserId(examId, userId)
5762
}
63+
64+
@Transactional
65+
override fun deleteUserBadgeByBadgeIdAndUserId(
66+
badgeId: Long,
67+
userId: Long
68+
) {
69+
val userBadge = userBadgeQueryPort.getUserBadgeByBadgeIdAndUserId(badgeId, userId) ?: throw UserBadgeNotFoundException()
70+
71+
userBadgeCommandPort.deleteUserBadgeById(userBadge.id)
72+
}
5873
}

domain/src/main/kotlin/com/gotchai/domain/admin/port/in/AdminCommandUseCase.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,9 @@ interface AdminCommandUseCase {
1010
examId: Long,
1111
userId: Long
1212
)
13+
14+
fun deleteUserBadgeByBadgeIdAndUserId(
15+
badgeId: Long,
16+
userId: Long
17+
)
1318
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.gotchai.domain.badge.exception
2+
3+
import com.gotchai.domain.global.exception.ServerException
4+
5+
class UserBadgeNotFoundException(
6+
override val message: String = "유저가 취득한 뱃지를 찾을 수 없습니다."
7+
) : ServerException(status = 404, message)

domain/src/main/kotlin/com/gotchai/domain/badge/port/out/UserBadgeCommandPort.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ import com.gotchai.domain.badge.entity.UserBadge
44

55
interface UserBadgeCommandPort {
66
fun createUserBadge(creation: UserBadge.Creation): UserBadge
7+
8+
fun deleteUserBadgeById(id: Long)
79
}

0 commit comments

Comments
 (0)