Skip to content

Commit 0e99b53

Browse files
committed
feat: banner
1 parent d20d7c7 commit 0e99b53

File tree

16 files changed

+197
-5
lines changed

16 files changed

+197
-5
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.open3r.openmusic.domain.admin.banner.controller
2+
3+
import com.open3r.openmusic.domain.admin.banner.dto.request.BannerCreateRequest
4+
import com.open3r.openmusic.domain.admin.banner.service.AdminBannerService
5+
import com.open3r.openmusic.global.common.dto.response.BaseResponse
6+
import io.swagger.v3.oas.annotations.Operation
7+
import io.swagger.v3.oas.annotations.tags.Tag
8+
import org.springframework.security.access.prepost.PreAuthorize
9+
import org.springframework.web.bind.annotation.*
10+
11+
@Tag(name = "관리자: 배너", description = "Admin: Banner")
12+
@RestController
13+
@RequestMapping("/admin/banners")
14+
class AdminBannerController(
15+
private val adminBannerService: AdminBannerService
16+
) {
17+
@Operation(summary = "배너 생성")
18+
@PostMapping
19+
@PreAuthorize("hasRole('ADMIN')")
20+
fun createBanner(@RequestBody request: BannerCreateRequest) =
21+
BaseResponse(adminBannerService.createBanner(request), 201).toEntity()
22+
23+
@Operation(summary = "배너 삭제")
24+
@DeleteMapping("/{bannerId}")
25+
@PreAuthorize("hasRole('ADMIN')")
26+
fun deleteBanner(@PathVariable bannerId: Long) =
27+
BaseResponse(adminBannerService.deleteBanner(bannerId), 204).toEntity()
28+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.open3r.openmusic.domain.admin.banner.dto.request
2+
3+
import jakarta.validation.constraints.NotBlank
4+
import org.hibernate.validator.constraints.URL
5+
6+
data class BannerCreateRequest(
7+
@field:NotBlank
8+
@field:URL
9+
val url: String,
10+
@field:NotBlank
11+
@field:URL
12+
val imageUrl: String,
13+
)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.open3r.openmusic.domain.admin.banner.service
2+
3+
import com.open3r.openmusic.domain.admin.banner.dto.request.BannerCreateRequest
4+
import com.open3r.openmusic.domain.banner.dto.response.BannerResponse
5+
6+
interface AdminBannerService {
7+
fun createBanner(request: BannerCreateRequest): BannerResponse
8+
fun deleteBanner(bannerId: Long)
9+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.open3r.openmusic.domain.admin.banner.service.impl
2+
3+
import com.open3r.openmusic.domain.admin.banner.dto.request.BannerCreateRequest
4+
import com.open3r.openmusic.domain.admin.banner.service.AdminBannerService
5+
import com.open3r.openmusic.domain.banner.domain.entity.BannerEntity
6+
import com.open3r.openmusic.domain.banner.dto.response.BannerResponse
7+
import com.open3r.openmusic.domain.banner.repository.BannerRepository
8+
import org.springframework.stereotype.Service
9+
import org.springframework.transaction.annotation.Transactional
10+
11+
@Service
12+
class AdminBannerServiceImpl(
13+
private val bannerRepository: BannerRepository
14+
) : AdminBannerService {
15+
@Transactional
16+
override fun createBanner(request: BannerCreateRequest): BannerResponse {
17+
return BannerResponse.of(bannerRepository.save(BannerEntity(url = request.url, imageUrl = request.imageUrl)))
18+
}
19+
20+
@Transactional
21+
override fun deleteBanner(bannerId: Long) {
22+
bannerRepository.deleteById(bannerId)
23+
}
24+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.open3r.openmusic.domain.banner.controller
2+
3+
import com.open3r.openmusic.domain.banner.service.BannerService
4+
import com.open3r.openmusic.global.common.dto.response.BaseResponse
5+
import io.swagger.v3.oas.annotations.Operation
6+
import io.swagger.v3.oas.annotations.tags.Tag
7+
import org.springframework.web.bind.annotation.GetMapping
8+
import org.springframework.web.bind.annotation.PathVariable
9+
import org.springframework.web.bind.annotation.RequestMapping
10+
import org.springframework.web.bind.annotation.RestController
11+
12+
@Tag(name = "배너", description = "Banner")
13+
@RestController
14+
@RequestMapping("/banners")
15+
class BannerController(
16+
private val bannerService: BannerService
17+
) {
18+
@Operation(summary = "배너 목록 조회")
19+
@GetMapping
20+
fun getBanners() = BaseResponse(bannerService.getBanners(), 200).toEntity()
21+
22+
@Operation(summary = "배너 조회")
23+
@GetMapping("/{bannerId}")
24+
fun getBanner(@PathVariable bannerId: Long) = BaseResponse(bannerService.getBanner(bannerId), 200).toEntity()
25+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.open3r.openmusic.domain.banner.domain.entity
2+
3+
import com.open3r.openmusic.global.common.domain.entity.BaseEntity
4+
import jakarta.persistence.*
5+
6+
@Entity
7+
@Table(name = "banners")
8+
class BannerEntity(
9+
@Id
10+
@GeneratedValue(strategy = GenerationType.IDENTITY)
11+
val id: Long? = null,
12+
13+
@Column(name = "url", nullable = false, updatable = false)
14+
val url: String,
15+
16+
@Column(name = "image_url", nullable = false, updatable = false)
17+
val imageUrl: String,
18+
) : BaseEntity()
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.open3r.openmusic.domain.banner.dto.response
2+
3+
import com.open3r.openmusic.domain.banner.domain.entity.BannerEntity
4+
import java.time.LocalDateTime
5+
6+
data class BannerResponse(
7+
val id: Long,
8+
val url: String,
9+
val imageUrl: String,
10+
val createdAt: LocalDateTime,
11+
val updatedAt: LocalDateTime,
12+
) {
13+
companion object {
14+
fun of(banner: BannerEntity) = BannerResponse(
15+
id = banner.id!!,
16+
url = banner.url,
17+
imageUrl = banner.imageUrl,
18+
createdAt = banner.createdAt!!,
19+
updatedAt = banner.updatedAt!!,
20+
)
21+
}
22+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.open3r.openmusic.domain.banner.repository
2+
3+
import com.open3r.openmusic.domain.banner.domain.entity.BannerEntity
4+
import org.springframework.data.jpa.repository.JpaRepository
5+
6+
interface BannerRepository : JpaRepository<BannerEntity, Long>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.open3r.openmusic.domain.banner.service
2+
3+
import com.open3r.openmusic.domain.banner.dto.response.BannerResponse
4+
5+
interface BannerService {
6+
fun getBanners(): List<BannerResponse>
7+
fun getBanner(bannerId: Long): BannerResponse
8+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.open3r.openmusic.domain.banner.service.impl
2+
3+
import com.open3r.openmusic.domain.banner.dto.response.BannerResponse
4+
import com.open3r.openmusic.domain.banner.repository.BannerRepository
5+
import com.open3r.openmusic.domain.banner.service.BannerService
6+
import com.open3r.openmusic.global.error.CustomException
7+
import com.open3r.openmusic.global.error.ErrorCode
8+
import org.springframework.data.repository.findByIdOrNull
9+
import org.springframework.stereotype.Service
10+
import org.springframework.transaction.annotation.Transactional
11+
12+
@Service
13+
class BannerServiceImpl(
14+
private val bannerRepository: BannerRepository
15+
) : BannerService {
16+
@Transactional(readOnly = true)
17+
override fun getBanners(): List<BannerResponse> {
18+
return bannerRepository.findAll().map { BannerResponse.of(it) }
19+
}
20+
21+
@Transactional(readOnly = true)
22+
override fun getBanner(bannerId: Long): BannerResponse {
23+
return BannerResponse.of(
24+
bannerRepository.findByIdOrNull(bannerId) ?: throw CustomException(ErrorCode.BANNER_NOT_FOUND)
25+
)
26+
}
27+
}

src/main/kotlin/com/open3r/openmusic/domain/file/service/impl/FileServiceImpl.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ class FileServiceImpl(
2121

2222
override fun uploadFiles(files: List<MultipartFile>): List<FileUploadResponse> {
2323
return files.map {
24+
val type = it.contentType?.substringBefore("/") ?: "file"
25+
26+
if (type != "image" && type != "audio") {
27+
throw IllegalArgumentException("지원하지 않는 파일 형식입니다.")
28+
}
29+
2430
val name = "${UUID.randomUUID()}.${it.originalFilename?.substringAfterLast(".")}"
2531

2632
val metadata = ObjectMetadata().apply {

src/main/kotlin/com/open3r/openmusic/domain/user/controller/UserController.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ class UserController(
2525
@Operation(summary = "나 수정")
2626
@PatchMapping("/me")
2727
@PreAuthorize("isAuthenticated()")
28-
fun updateMe(@RequestBody @Valid request: UserUpdateRequest) = BaseResponse(userService.updateMe(request), 200).toEntity()
28+
fun updateMe(@RequestBody @Valid request: UserUpdateRequest) =
29+
BaseResponse(userService.updateMe(request), 200).toEntity()
2930

3031
@Operation(summary = "현재 재생 중인 노래 조회")
3132
@GetMapping("/me/now-playing")

src/main/kotlin/com/open3r/openmusic/global/config/discord/StartListener.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import java.time.Instant
1111
class StartListener(
1212
private val jda: JDA,
1313
private val discordProperties: DiscordProperties
14-
): ApplicationListener<ApplicationStartedEvent> {
14+
) : ApplicationListener<ApplicationStartedEvent> {
1515
override fun onApplicationEvent(event: ApplicationStartedEvent) {
1616
jda.getTextChannelById(discordProperties.channelId)?.sendMessageEmbeds(
1717
EmbedBuilder()

src/main/kotlin/com/open3r/openmusic/global/config/discord/StopListener.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import java.time.Instant
1111
class StopListener(
1212
private val jda: JDA,
1313
private val discordProperties: DiscordProperties
14-
): ApplicationListener<ContextClosedEvent> {
14+
) : ApplicationListener<ContextClosedEvent> {
1515
override fun onApplicationEvent(event: ContextClosedEvent) {
1616
jda.getTextChannelById(discordProperties.channelId)?.sendMessageEmbeds(
1717
EmbedBuilder()

src/main/kotlin/com/open3r/openmusic/global/config/swagger/SwaggerConfig.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ class SwaggerConfig {
3535
)
3636
.termsOfService("https://open3r.com/terms")
3737
)
38-
.servers(listOf(Server().apply { url = "https://api.openmusic.kr" }))
38+
.servers(listOf(
39+
Server().apply { url = "https://api.openmusic.kr" },
40+
Server().apply { url = "http://localhost:8080" }
41+
))
3942
.addSecurityItem(SecurityRequirement().addList("Authorization"))
4043
.components(
4144
Components()

src/main/kotlin/com/open3r/openmusic/global/error/ErrorCode.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ enum class ErrorCode(
6464
USER_QUEUE_ALREADY_EXISTS(HttpStatus.BAD_REQUEST, "User queue already exists"),
6565

6666
// Else
67-
MAX_UPLOAD_SIZE_EXCEEDED(HttpStatus.BAD_REQUEST, "Max upload size exceeded")
67+
MAX_UPLOAD_SIZE_EXCEEDED(HttpStatus.BAD_REQUEST, "Max upload size exceeded"),
6868

69+
// Banner
70+
BANNER_NOT_FOUND(HttpStatus.NOT_FOUND, "Banner not found"),
6971
}

0 commit comments

Comments
 (0)