Skip to content

Commit 7b85558

Browse files
committed
feat: 6차 mvp
1 parent dddc7ed commit 7b85558

File tree

6 files changed

+128
-190
lines changed

6 files changed

+128
-190
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.ddd.sonnypolabobe.domain.sticker.controller
2+
3+
import com.ddd.sonnypolabobe.domain.sticker.dto.StickerUseRequest
4+
import com.ddd.sonnypolabobe.domain.sticker.service.StickerService
5+
import com.ddd.sonnypolabobe.domain.user.dto.UserDto
6+
import com.ddd.sonnypolabobe.global.response.ApplicationResponse
7+
import io.swagger.v3.oas.annotations.Operation
8+
import io.swagger.v3.oas.annotations.tags.Tag
9+
import jakarta.validation.Valid
10+
import org.springframework.security.core.context.SecurityContextHolder
11+
import org.springframework.web.bind.annotation.GetMapping
12+
import org.springframework.web.bind.annotation.PostMapping
13+
import org.springframework.web.bind.annotation.RequestBody
14+
import org.springframework.web.bind.annotation.RequestMapping
15+
import org.springframework.web.bind.annotation.RestController
16+
17+
@RestController
18+
@RequestMapping("/api/v1/stickers")
19+
class StickerController(
20+
private val stickerService: StickerService
21+
) {
22+
23+
@Tag(name = "1.5.0")
24+
@Operation(
25+
summary = "스티커 사용 이력 저장", description = "보드에 사용한 스티커 ID를 배열에 담아 모두 보내주세요."
26+
)
27+
@PostMapping("/use")
28+
fun useSticker(
29+
@RequestBody @Valid request: StickerUseRequest
30+
) : ApplicationResponse<Nothing> {
31+
val user = SecurityContextHolder.getContext().authentication.principal as UserDto.Companion.Res
32+
stickerService.use(request, user)
33+
return ApplicationResponse.ok()
34+
}
35+
36+
@Tag(name = "1.5.0")
37+
@Operation(
38+
summary = "최근 사용한 스티커 조회", description = "최근 30일 이내에 사용한 스티커를 조회합니다."
39+
)
40+
@GetMapping("/recent-use")
41+
fun getRecentUseSticker() : ApplicationResponse<Set<String>> {
42+
val user = SecurityContextHolder.getContext().authentication.principal as UserDto.Companion.Res
43+
return ApplicationResponse.ok(stickerService.getRecentUse(user))
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.ddd.sonnypolabobe.domain.sticker.dto
2+
3+
import io.swagger.v3.oas.annotations.media.Schema
4+
import jakarta.validation.constraints.NotBlank
5+
6+
@Schema(description = "스티커 사용 이력 저장")
7+
data class StickerUseRequest(
8+
@field:Schema(description = "스티커 ID 리스트", example = "[\"STK_0001\",\"STK_0001\"]")
9+
val stickerIds: List<String>,
10+
@field:Schema(description = "게시글 ID", example = "adksjfldskjglaijg")
11+
@field:NotBlank(message = "게시글 ID는 필수입니다.")
12+
val boardId: String,
13+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.ddd.sonnypolabobe.domain.sticker.repository
2+
3+
import com.ddd.sonnypolabobe.domain.sticker.dto.StickerUseRequest
4+
import com.ddd.sonnypolabobe.domain.user.dto.UserDto
5+
6+
interface StickerJooqRepository {
7+
fun insertAll(request: StickerUseRequest, user: UserDto.Companion.Res)
8+
fun readAllByUserId(userId: Long): Set<String>
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.ddd.sonnypolabobe.domain.sticker.repository
2+
3+
import com.ddd.sonnypolabobe.domain.sticker.dto.StickerUseRequest
4+
import com.ddd.sonnypolabobe.domain.user.dto.UserDto
5+
import com.ddd.sonnypolabobe.global.util.DateConverter
6+
import com.ddd.sonnypolabobe.global.util.UuidConverter
7+
import com.ddd.sonnypolabobe.jooq.polabo.tables.references.STICKER_USE_HISTORY
8+
import org.jooq.DSLContext
9+
import org.springframework.stereotype.Repository
10+
import java.time.LocalDateTime
11+
12+
@Repository
13+
class StickerJooqRepositoryImpl(private val dslContext: DSLContext) : StickerJooqRepository{
14+
override fun insertAll(request: StickerUseRequest, user: UserDto.Companion.Res) {
15+
dslContext.batchInsert(
16+
request.stickerIds.map {
17+
STICKER_USE_HISTORY.newRecord().apply {
18+
this.userId = user.id
19+
this.stickerId = it
20+
this.boardId = UuidConverter.uuidToByteArray(UuidConverter.stringToUUID(request.boardId))
21+
this.createdAt = DateConverter.convertToKst(LocalDateTime.now())
22+
}
23+
}
24+
).execute()
25+
26+
}
27+
28+
override fun readAllByUserId(userId: Long): Set<String> {
29+
return dslContext.select(STICKER_USE_HISTORY.STICKER_ID)
30+
.from(STICKER_USE_HISTORY)
31+
.where(STICKER_USE_HISTORY.USER_ID.eq(userId).and(
32+
STICKER_USE_HISTORY.CREATED_AT.gt(
33+
DateConverter.convertToKst(LocalDateTime.now().minusDays(30))
34+
)
35+
))
36+
.fetchInto(String::class.java)
37+
.toSet()
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.ddd.sonnypolabobe.domain.sticker.service
2+
3+
import com.ddd.sonnypolabobe.domain.sticker.dto.StickerUseRequest
4+
import com.ddd.sonnypolabobe.domain.sticker.repository.StickerJooqRepository
5+
import com.ddd.sonnypolabobe.domain.user.dto.UserDto
6+
import org.springframework.stereotype.Service
7+
import org.springframework.transaction.annotation.Transactional
8+
9+
@Service
10+
class StickerService(
11+
private val stickerJooqRepository: StickerJooqRepository
12+
) {
13+
@Transactional
14+
fun use(request: StickerUseRequest, user: UserDto.Companion.Res) {
15+
stickerJooqRepository.insertAll(request, user)
16+
}
17+
18+
@Transactional(readOnly = true)
19+
fun getRecentUse(user: UserDto.Companion.Res): Set<String> {
20+
return stickerJooqRepository.readAllByUserId(user.id)
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -1,196 +1,6 @@
11
package com.ddd.sonnypolabobe
22

3-
import org.junit.jupiter.api.Test
4-
import org.springframework.boot.test.context.SpringBootTest
5-
import java.util.*
6-
73
//@SpringBootTest
84
class SonnyPolaboBeApplicationTests {
95

10-
@Test
11-
fun contextLoads() {
12-
println(solution(2, 10, intArrayOf(7,4,5,6))) // 8
13-
// println(solution(arrayOf(
14-
// intArrayOf(1,2,1),
15-
// intArrayOf(8,2,0),
16-
// intArrayOf(1,7,2)
17-
// ), intArrayOf(0, 0))) // true
18-
// println(solution(arrayOf(
19-
// intArrayOf(1,2,3,2,1),
20-
// intArrayOf(4,2,0,7,2),
21-
// intArrayOf(1,3,3,8,1),
22-
// intArrayOf(2,0,1,1,1),
23-
// intArrayOf(8,2,8,1,1)
24-
// ), intArrayOf(0, 0))) // false
25-
26-
// println(solution(arrayOf(
27-
// intArrayOf(1,2,3,2,1),
28-
// intArrayOf(4,2,0,7,1),
29-
// intArrayOf(1,3,2,8,1),
30-
// intArrayOf(2,0,1,1,1),
31-
// intArrayOf(8,2,1,2,1)
32-
// ), intArrayOf(4,3)
33-
// )) // true
34-
// println(solution(
35-
// intArrayOf(23), // 고객 수
36-
// intArrayOf(12, 3, 19), // 모델 처리량
37-
// intArrayOf(28, 10, 35) // 모델 비용
38-
// ))
39-
40-
}
41-
42-
fun solution(bridge_length: Int, weight: Int, truck_weights: IntArray): Int {
43-
var answer = 0
44-
45-
val queue: Queue<Int> = LinkedList()
46-
var totalWeight = 0
47-
48-
for(truck in truck_weights) {
49-
queue.add(truck)
50-
}
51-
52-
val bridge = LinkedList(List(bridge_length) { 0 })
53-
54-
while(bridge.isNotEmpty()) {
55-
answer++
56-
57-
totalWeight -= bridge.poll() // 다리를 건넌 트럭의 무게를 빼준다.
58-
59-
if(queue.isNotEmpty()) {
60-
val nextWeight = queue.peek()
61-
if(nextWeight + totalWeight <= weight ) {
62-
totalWeight += nextWeight
63-
bridge.add(queue.poll())
64-
} else {
65-
bridge.add(0)
66-
}
67-
}
68-
69-
70-
}
71-
72-
73-
// while (bridge.isNotEmpty()) {
74-
// answer++
75-
// totalWeight -= bridge.poll()
76-
//
77-
// if (waiting.isNotEmpty()) {
78-
// val nextWeight = waiting.peek()
79-
//
80-
// if (totalWeight + nextWeight <= weight) {
81-
// totalWeight += nextWeight
82-
// bridge.add(waiting.poll())
83-
// } else {
84-
// bridge.add(0)
85-
// }
86-
// }
87-
// }
88-
return answer
89-
}
90-
91-
92-
// fun solution(map : Array<IntArray>, entrancePoint: IntArray) : Boolean {
93-
// // 출발점에서 닭가슴살을 찾을 수 있는지 여부가 answer
94-
// // 닭가슴살은 7
95-
// // 액상 과당은 0, 초콜릿은 8 이라고 할 때
96-
// // map에서 출발점을 기준으로는 좌우로만 갈 수 있다.
97-
// // 이후에는 위 아래로 갈 수 있다.
98-
// // 그 다음에는 좌우로만 갈 수 있다. 이 구성을 반복한다고 할 때 이동 방향으로는 현재 위치의 숫자만큼 간다.
99-
// // 이동의 도착점에 액상 과당이나 초콜릿이 있다면 false를 반환한다.
100-
// // 영역을 벗어나도 false를 반환한다.
101-
//
102-
// var answer = false
103-
// var x = entrancePoint[0]
104-
// var y = entrancePoint[1]
105-
// var direction = if (x % 2 == 0) 0 else 2
106-
// var nextX = 0
107-
// var nextY = 0
108-
//
109-
// while (true) {
110-
// if (map[x][y] == 7) {
111-
// answer = true
112-
// break
113-
// }
114-
// if (map[x][y] == 0 || map[x][y] == 8) {
115-
// break
116-
// }
117-
// when (direction) {
118-
// 0 -> {
119-
// nextX = x
120-
// nextY = y + map[x][y]
121-
// }
122-
// 1 -> {
123-
// nextX = x + map[x][y]
124-
// nextY = y
125-
// }
126-
// 2 -> {
127-
// nextX = x
128-
// nextY = y - map[x][y]
129-
// }
130-
// 3 -> {
131-
// nextX = x - map[x][y]
132-
// nextY = y
133-
// }
134-
// }
135-
// if (nextX < 0 || nextX >= map.size || nextY < 0 || nextY >= map[0].size) {
136-
// break
137-
// }
138-
// x = nextX
139-
// y = nextY
140-
// direction = (direction + 1) % 4 // 방향을 바꾼다.
141-
// }
142-
// return answer
143-
//
144-
// }
145-
146-
// fun solution(customers : IntArray, modelCapacities: IntArray, modelCosts: IntArray) : Int {
147-
// var answer = 0
148-
//
149-
// // 매 시간 고객의 접수 건을 담고 있는 배열 customers
150-
// // 각 모델의 처리량을 담고 있는 배열 modelCapacities 예를 들면, A-12, B-3, C-19
151-
// // 각 모델의 비용을 담고 있는 배열 modelCosts 예를 들면, A-28, B-10, C-35
152-
// // 각 모델은 1시간에 위 처리량만큼 처리할 수 있다.
153-
//
154-
// // 최소 비용으로 처리하고자 할 때, 그 비용을 반환한다.
155-
//
156-
// // 모델의 처리량과 비용을 (처리량, 비용) 쌍으로 묶고, 처리량이 큰 순으로 정렬
157-
// val pair = modelCapacities.zip(modelCosts).sortedByDescending { it.first }
158-
//
159-
// for (customer in customers) {
160-
// var minCost = Int.MAX_VALUE
161-
//
162-
// for (i in pair.indices) {
163-
// val (capacity, cost) = pair[i]
164-
// val fullModelsNeeded = customer / capacity
165-
// val remainder = customer % capacity
166-
//
167-
// // 총 비용 계산
168-
// var totalCost = cost * fullModelsNeeded
169-
//
170-
// // 잔여 고객 처리 비용 추가
171-
// if (remainder > 0) {
172-
// // 잔여 고객을 처리하기 위한 최소 비용을 계산
173-
// var extraCost = Int.MAX_VALUE
174-
// for (j in pair.indices) {
175-
// val (extraCapacity, extraCostValue) = pair[j]
176-
// if (extraCapacity >= remainder) {
177-
// extraCost = minOf(extraCost, extraCostValue)
178-
// }
179-
// }
180-
// totalCost += extraCost
181-
// }
182-
//
183-
// // 최소 비용 업데이트
184-
// minCost = minOf(minCost, totalCost)
185-
// }
186-
// answer += minCost
187-
// }
188-
//
189-
// return answer
190-
// }
191-
192-
193-
194-
195-
1966
}

0 commit comments

Comments
 (0)