Skip to content

Commit 0868531

Browse files
authored
Merge pull request #142 from Route-Box/feature/#102
Feat: 유저 푸시 토큰 추가 API
2 parents b286603 + 066e770 commit 0868531

10 files changed

Lines changed: 161 additions & 0 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.routebox.routebox.application.user_mobile
2+
3+
import com.routebox.routebox.application.user_mobile.dto.UpdateUserMobileCommand
4+
import com.routebox.routebox.domain.user_mobile.UserMobile
5+
import com.routebox.routebox.domain.user_mobile.UserMobileService
6+
import jakarta.transaction.Transactional
7+
import org.springframework.stereotype.Component
8+
9+
@Component
10+
class UpdateUserMobileUseCase(
11+
private val userMobileService: UserMobileService,
12+
) {
13+
@Transactional
14+
operator fun invoke(command: UpdateUserMobileCommand): Long {
15+
// user 푸시 이력 조회
16+
val userMobile = userMobileService.get(command.userId)
17+
18+
// 이미 있으면 수정
19+
if (userMobile !== null) {
20+
userMobile.update(command.pushToken, command.os)
21+
userMobileService.create(userMobile)
22+
return userMobile.id
23+
} else {
24+
// 없으면 새로 추가
25+
val newMobile = UserMobile(
26+
userId = command.userId,
27+
pushToken = command.pushToken,
28+
osType = command.os,
29+
)
30+
31+
val userMobileId = userMobileService.create(newMobile)
32+
return userMobileId
33+
}
34+
}
35+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.routebox.routebox.application.user_mobile.dto
2+
3+
data class UpdateUserMobileCommand(
4+
val userId: Long,
5+
val os: String,
6+
val pushToken: String?,
7+
)

src/main/kotlin/com/routebox/routebox/controller/user/UserController.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ import com.routebox.routebox.application.user.CheckNicknameAvailabilityUseCase
44
import com.routebox.routebox.application.user.GetUserProfileUseCase
55
import com.routebox.routebox.application.user.GetUserUseCase
66
import com.routebox.routebox.application.user.UpdateUserInfoUseCase
7+
import com.routebox.routebox.application.user_mobile.UpdateUserMobileUseCase
78
import com.routebox.routebox.controller.user.dto.CheckNicknameAvailabilityResponse
89
import com.routebox.routebox.controller.user.dto.UpdateUserInfoRequest
10+
import com.routebox.routebox.controller.user.dto.UpdateUserMobileRequest
11+
import com.routebox.routebox.controller.user.dto.UpdateUserMobileResponse
912
import com.routebox.routebox.controller.user.dto.UserProfileResponse
1013
import com.routebox.routebox.controller.user.dto.UserResponse
1114
import com.routebox.routebox.domain.validation.Nickname
@@ -25,6 +28,7 @@ import org.springframework.web.bind.annotation.GetMapping
2528
import org.springframework.web.bind.annotation.ModelAttribute
2629
import org.springframework.web.bind.annotation.PatchMapping
2730
import org.springframework.web.bind.annotation.PathVariable
31+
import org.springframework.web.bind.annotation.PutMapping
2832
import org.springframework.web.bind.annotation.RequestMapping
2933
import org.springframework.web.bind.annotation.RestController
3034

@@ -37,6 +41,7 @@ class UserController(
3741
private val getUserProfileUseCase: GetUserProfileUseCase,
3842
private val checkNicknameAvailabilityUseCase: CheckNicknameAvailabilityUseCase,
3943
private val updateUserInfoUseCase: UpdateUserInfoUseCase,
44+
private val updateUserMobileUseCase: UpdateUserMobileUseCase,
4045
) {
4146
@Operation(
4247
summary = "내 유저 정보 조회",
@@ -106,4 +111,20 @@ class UserController(
106111
val updateUserInfo = updateUserInfoUseCase(request.toCommand(userPrincipal.userId))
107112
return UserResponse.from(updateUserInfo)
108113
}
114+
115+
@Operation(
116+
summary = "유저 푸시 정보 입력",
117+
security = [SecurityRequirement(name = "access-token")],
118+
)
119+
@ApiResponses(
120+
ApiResponse(responseCode = "200"),
121+
)
122+
@PutMapping("/v1/users/mobile")
123+
fun updateUserMobile(
124+
@AuthenticationPrincipal userPrincipal: UserPrincipal,
125+
@ModelAttribute @Valid request: UpdateUserMobileRequest,
126+
): UpdateUserMobileResponse {
127+
val id = updateUserMobileUseCase(request.toCommand(userPrincipal.userId))
128+
return UpdateUserMobileResponse(id)
129+
}
109130
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.routebox.routebox.controller.user.dto
2+
3+
import com.routebox.routebox.application.user_mobile.dto.UpdateUserMobileCommand
4+
import io.swagger.v3.oas.annotations.media.Schema
5+
6+
data class UpdateUserMobileRequest(
7+
@Schema(description = "OS (iOS, Android)")
8+
var os: String,
9+
10+
@Schema(description = "FCM 토큰")
11+
var pushToken: String,
12+
) {
13+
fun toCommand(userId: Long): UpdateUserMobileCommand =
14+
UpdateUserMobileCommand(
15+
userId = userId,
16+
os = os,
17+
pushToken = pushToken,
18+
)
19+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.routebox.routebox.controller.user.dto
2+
3+
import io.swagger.v3.oas.annotations.media.Schema
4+
5+
data class UpdateUserMobileResponse(
6+
@Schema(description = "Id(PK) of user mobile", example = "1")
7+
val id: Long,
8+
)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.routebox.routebox.domain.user_mobile
2+
3+
import com.routebox.routebox.domain.common.TimeTrackedBaseEntity
4+
import jakarta.persistence.Column
5+
import jakarta.persistence.Entity
6+
import jakarta.persistence.GeneratedValue
7+
import jakarta.persistence.GenerationType
8+
import jakarta.persistence.Id
9+
10+
@Entity
11+
class UserMobile(
12+
userId: Long,
13+
pushToken: String?,
14+
osType: String,
15+
id: Long = 0,
16+
) : TimeTrackedBaseEntity() {
17+
@Id
18+
@GeneratedValue(strategy = GenerationType.IDENTITY)
19+
@Column(name = "user_mobile_id")
20+
val id: Long = id
21+
22+
@Column(name = "user_id", nullable = false)
23+
val userId: Long = userId
24+
25+
@Column
26+
var pushToken: String? = pushToken
27+
28+
@Column
29+
var osType: String = osType
30+
31+
fun update(pushToken: String?, osType: String) {
32+
this.pushToken = pushToken
33+
this.osType = osType
34+
}
35+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.routebox.routebox.domain.user_mobile
2+
3+
import com.routebox.routebox.infrastructure.user_mobile.UserMobileRepository
4+
import org.springframework.stereotype.Service
5+
6+
@Service
7+
class UserMobileService(private val userMobileRepository: UserMobileRepository) {
8+
fun get(userId: Long): UserMobile? {
9+
return userMobileRepository.findByUserId(userId)
10+
}
11+
12+
fun create(userMobile: UserMobile): Long {
13+
return userMobileRepository.save(userMobile).id
14+
}
15+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.routebox.routebox.infrastructure.user_mobile
2+
3+
import com.routebox.routebox.domain.user_mobile.UserMobile
4+
import org.springframework.data.jpa.repository.JpaRepository
5+
6+
interface UserMobileRepository : JpaRepository<UserMobile, Long> {
7+
fun findByUserId(userId: Long): UserMobile?
8+
}

src/main/resources/schema.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,3 +298,12 @@ CREATE TABLE comment_report (
298298
);
299299
-- CREATE INDEX idx__comment_report__reporter_id ON comment_report (reporter_id);
300300
-- CREATE INDEX idx__comment_report__reported_comment_id ON comment_report (reported_comment_id);
301+
302+
CREATE TABLE user_mobile (
303+
user_mobile_id BIGINT AUTO_INCREMENT PRIMARY KEY,
304+
user_id BIGINT NOT NULL,
305+
push_token TEXT,
306+
os_type VARCHAR(10) NOT NULL,
307+
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '생성 시간',
308+
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '업데이트 시간'
309+
);

src/test/kotlin/com/routebox/routebox/controller/user/UserControllerTest.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.routebox.routebox.application.user.GetUserUseCase
66
import com.routebox.routebox.application.user.UpdateUserInfoUseCase
77
import com.routebox.routebox.application.user.dto.GetUserProfileResult
88
import com.routebox.routebox.application.user.dto.UpdateUserInfoResult
9+
import com.routebox.routebox.application.user_mobile.UpdateUserMobileUseCase
910
import com.routebox.routebox.config.ControllerTestConfig
1011
import com.routebox.routebox.controller.user.dto.UpdateUserInfoRequest
1112
import com.routebox.routebox.domain.user.constant.Gender
@@ -46,6 +47,9 @@ class UserControllerTest @Autowired constructor(private val mvc: MockMvc) {
4647
@MockBean
4748
lateinit var checkNicknameAvailabilityUseCase: CheckNicknameAvailabilityUseCase
4849

50+
@MockBean
51+
lateinit var updateUserMobileUseCase: UpdateUserMobileUseCase
52+
4953
private fun verifyEveryMocksShouldHaveNoMoreInteractions() {
5054
then(getUserUseCase).shouldHaveNoMoreInteractions()
5155
then(getUserProfileUseCase).shouldHaveNoMoreInteractions()

0 commit comments

Comments
 (0)