Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,29 @@ import com.damaba.damaba.domain.file.File
import com.damaba.damaba.domain.file.Image
import com.damaba.damaba.domain.promotion.PromotionValidator
import com.damaba.damaba.domain.promotion.constant.PromotionType
import com.damaba.damaba.domain.promotion.exception.PromotionAuthorHiddenPermissionDeniedException
import com.damaba.damaba.domain.region.Region
import com.damaba.damaba.domain.user.User
import java.time.LocalDate

data class PostPromotionCommand(
val authorId: Long,
val requestUser: User,
val promotionType: PromotionType,
val title: String,
val content: String,
val externalLink: String?,
val startedAt: LocalDate?,
val endedAt: LocalDate?,
val isAuthorHidden: Boolean,
val photographyTypes: Set<PhotographyType>,
val images: List<File>,
val activeRegions: Set<Region>,
val hashtags: Set<String>,
) {
init {
if (isAuthorHidden && !requestUser.isAdmin) {
throw PromotionAuthorHiddenPermissionDeniedException()
}
PromotionValidator.validateTitle(title)
PromotionValidator.validateContent(content)
if (images.isEmpty() || images.size > 10) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,14 @@ class PromotionService(
@Transactional
fun postPromotion(command: PostPromotionCommand): Promotion = promotionRepo.create(
Promotion.create(
authorId = command.authorId,
authorId = command.requestUser.id,
promotionType = command.promotionType,
title = command.title,
content = command.content,
externalLink = command.externalLink,
startedAt = command.startedAt,
endedAt = command.endedAt,
isAuthorHidden = command.isAuthorHidden,
photographyTypes = command.photographyTypes,
images = command.images.map { file -> Image(file.name, file.url) },
activeRegions = command.activeRegions.map { region -> Region(region.category, region.name) }.toSet(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ class PromotionController(private val promotionService: PromotionService) {
@AuthenticationPrincipal requestUser: User,
@RequestBody request: PostPromotionRequest,
): ResponseEntity<PromotionResponse> {
val promotion = promotionService.postPromotion(request.toCommand(requestUser.id))
val promotion = promotionService.postPromotion(request.toCommand(requestUser))
return ResponseEntity
.created(URI.create("/api/v*/promotions/${promotion.id}"))
.body(PromotionMapper.INSTANCE.toPromotionResponse(promotion))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.damaba.damaba.controller.common.ImageRequest
import com.damaba.damaba.controller.region.RegionRequest
import com.damaba.damaba.domain.common.constant.PhotographyType
import com.damaba.damaba.domain.promotion.constant.PromotionType
import com.damaba.damaba.domain.user.User
import com.damaba.damaba.mapper.ImageMapper
import com.damaba.damaba.mapper.RegionMapper
import io.swagger.v3.oas.annotations.media.Schema
Expand All @@ -30,6 +31,9 @@ data class PostPromotionRequest(
@Schema(description = "이벤트 종료일")
val endedAt: LocalDate?,

@Schema(description = "작성자 정보 숨김 여부. 관리자만 true로 설정할 수 있습니다.", example = "false")
val isAuthorHidden: Boolean = false,

@Schema(description = "촬영 종류")
val photographyTypes: Set<PhotographyType>,

Expand All @@ -42,14 +46,15 @@ data class PostPromotionRequest(
@Schema(description = "해시태그 리스트", example = "[\"수원핫플\", \"스냅사진\"]")
val hashtags: Set<String>,
) {
fun toCommand(requestUserId: Long) = PostPromotionCommand(
authorId = requestUserId,
fun toCommand(requestUser: User) = PostPromotionCommand(
requestUser = requestUser,
promotionType = promotionType,
title = title,
content = content,
externalLink = externalLink,
startedAt = startedAt,
endedAt = endedAt,
isAuthorHidden = isAuthorHidden,
photographyTypes = photographyTypes,
images = images.map { ImageMapper.INSTANCE.toImage(it) },
activeRegions = activeRegions.map { regionRequest -> RegionMapper.INSTANCE.toRegion(regionRequest) }.toSet(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ data class PromotionResponse(
@Schema(description = "조회수", example = "15")
val viewCount: Long,

@Schema(description = "작성자 정보 숨김 여부", example = "false")
val isAuthorHidden: Boolean,

@Schema(description = "촬영 종류 리스트")
val photographyTypes: Set<PhotographyType>,

Expand Down Expand Up @@ -84,6 +87,9 @@ data class PromotionDetailResponse(
@Schema(description = "게시글 저장 여부. 이미 저장한 게시글이라면 <code>true</code>")
val isSaved: Boolean,

@Schema(description = "작성자 정보 숨김 여부", example = "false")
val isAuthorHidden: Boolean,

@Schema(description = "촬영 종류 리스트")
val photographyTypes: Set<PhotographyType>,

Expand Down Expand Up @@ -119,6 +125,9 @@ data class PromotionListItemResponse(
@Schema(description = "게시글 저장 여부. 이미 저장한 게시글이라면 <code>true</code>")
val isSaved: Boolean,

@Schema(description = "작성자 정보 숨김 여부", example = "false")
val isAuthorHidden: Boolean,

@Schema(description = "촬영 종류")
val photographyTypes: Set<PhotographyType>,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Promotion(
startedAt: LocalDate?,
endedAt: LocalDate?,
viewCount: Long,
isAuthorHidden: Boolean,
photographyTypes: Set<PhotographyType>,
images: List<Image>,
activeRegions: Set<Region>,
Expand All @@ -24,6 +25,9 @@ class Promotion(
var authorId: Long? = authorId
private set

var isAuthorHidden: Boolean = isAuthorHidden
private set

var promotionType: PromotionType = promotionType
private set

Expand Down Expand Up @@ -102,6 +106,7 @@ class Promotion(
externalLink: String?,
startedAt: LocalDate?,
endedAt: LocalDate?,
isAuthorHidden: Boolean,
photographyTypes: Set<PhotographyType>,
images: List<Image>,
activeRegions: Set<Region>,
Expand All @@ -116,6 +121,7 @@ class Promotion(
startedAt = startedAt,
endedAt = endedAt,
viewCount = 0,
isAuthorHidden = isAuthorHidden,
photographyTypes = photographyTypes,
images = images,
activeRegions = activeRegions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ data class PromotionDetail(
val viewCount: Long,
val saveCount: Long,
val isSaved: Boolean,
val isAuthorHidden: Boolean,
val photographyTypes: Set<PhotographyType>,
val images: List<Image>,
val activeRegions: Set<Region>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ data class PromotionListItem(
val endedAt: LocalDate?,
val saveCount: Long,
val isSaved: Boolean,
val isAuthorHidden: Boolean,
val photographyTypes: Set<PhotographyType>,
val images: List<Image>,
val activeRegions: Set<Region>,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.damaba.damaba.domain.promotion.exception

import com.damaba.damaba.domain.exception.CustomException

class PromotionAuthorHiddenPermissionDeniedException :
CustomException(
httpStatusCode = 403,
code = "PROMOTION_AUTHOR_HIDDEN_PERMISSION_DENIED",
message = "작성자 정보 숨김은 관리자만 설정할 수 있습니다.",
)
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class PromotionJpaEntity(
startedAt: LocalDate?,
endedAt: LocalDate?,
viewCount: Long,
isAuthorHidden: Boolean,
) : TimeTrackedJpaEntity() {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand Down Expand Up @@ -70,6 +71,10 @@ class PromotionJpaEntity(
var viewCount: Long = viewCount
private set

@Column(name = "is_author_hidden", nullable = false)
var isAuthorHidden: Boolean = isAuthorHidden
private set

@Column(name = "deleted_at")
var deletedAt: LocalDateTime? = null
private set
Expand Down Expand Up @@ -105,6 +110,7 @@ class PromotionJpaEntity(
startedAt = this.startedAt,
endedAt = this.endedAt,
viewCount = this.viewCount,
isAuthorHidden = this.isAuthorHidden,
photographyTypes = this.photographyTypes.map { it.type }.toCollection(LinkedHashSet()),
images = this.images.map { it.toImage() },
activeRegions = this.activeRegions.map { it.toRegion() }.toCollection(LinkedHashSet()),
Expand Down Expand Up @@ -183,6 +189,7 @@ class PromotionJpaEntity(
startedAt = promotion.startedAt,
endedAt = promotion.endedAt,
viewCount = promotion.viewCount,
isAuthorHidden = promotion.isAuthorHidden,
)
promotionJpaEntity.photographyTypes.addAll(
promotion.photographyTypes.map {
Expand Down
5 changes: 5 additions & 0 deletions src/main/kotlin/com/damaba/damaba/mapper/PromotionMapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,19 @@ import org.mapstruct.factory.Mappers

@Mapper(uses = [UserMapper::class, ImageMapper::class, RegionMapper::class])
interface PromotionMapper {
@Mapping(source = "authorHidden", target = "isAuthorHidden")
fun toPromotionResponse(promotion: Promotion): PromotionResponse

@Mapping(source = "saved", target = "isSaved")
@Mapping(source = "authorHidden", target = "isAuthorHidden")
fun toPromotionDetailResponse(promotionDetail: PromotionDetail): PromotionDetailResponse

@Mapping(source = "saved", target = "isSaved")
@Mapping(source = "authorHidden", target = "isAuthorHidden")
fun toPromotionListItemResponse(promotionListItem: PromotionListItem): PromotionListItemResponse

@Mapping(source = "promotion.id", target = "id")
@Mapping(source = "promotion.authorHidden", target = "isAuthorHidden")
fun toPromotionDetail(
promotion: Promotion,
author: User?,
Expand All @@ -30,6 +34,7 @@ interface PromotionMapper {
): PromotionDetail

@Mapping(source = "promotion.id", target = "id")
@Mapping(source = "promotion.authorHidden", target = "isAuthorHidden")
fun toPromotionListItem(
promotion: Promotion,
author: User?,
Expand Down
25 changes: 13 additions & 12 deletions src/main/resources/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -112,18 +112,19 @@ CREATE INDEX idx__photographer_save__photographer_id ON photographer_save (photo

CREATE TABLE promotion
(
id BIGINT NOT NULL AUTO_INCREMENT,
author_id BIGINT COMMENT '(FK) id of user(author)',
promotion_type VARCHAR(255) NOT NULL,
title VARCHAR(20) NOT NULL,
content VARCHAR(500) NOT NULL,
external_link VARCHAR(255),
started_at DATE,
ended_at DATE,
view_count BIGINT NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL,
deleted_at TIMESTAMP,
id BIGINT NOT NULL AUTO_INCREMENT,
author_id BIGINT COMMENT '(FK) id of user(author)',
is_author_hidden BOOLEAN NOT NULL DEFAULT FALSE,
promotion_type VARCHAR(255) NOT NULL,
title VARCHAR(20) NOT NULL,
content VARCHAR(500) NOT NULL,
external_link VARCHAR(255),
started_at DATE,
ended_at DATE,
view_count BIGINT NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL,
deleted_at TIMESTAMP,
PRIMARY KEY (id)
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import com.damaba.damaba.domain.file.File
import com.damaba.damaba.domain.file.Image
import com.damaba.damaba.domain.promotion.constant.PromotionType
import com.damaba.damaba.domain.region.Region
import com.damaba.damaba.domain.user.User
import com.damaba.damaba.util.RandomTestUtils.Companion.randomLong
import com.damaba.damaba.util.RandomTestUtils.Companion.randomString
import com.damaba.damaba.util.fixture.FileFixture.createImage
import com.damaba.damaba.util.fixture.UserFixture.createUser
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.catchThrowable
import org.junit.jupiter.params.ParameterizedTest
Expand Down Expand Up @@ -59,21 +61,24 @@ class PostPromotionUseCaseCommandTest {
)

private fun createCommand(
requestUser: User = createUser(),
title: String = "Valid title",
content: String = "Valid content",
promotionType: PromotionType = PromotionType.FREE,
isAuthorHidden: Boolean = false,
photographyTypes: Set<PhotographyType> = setOf(PhotographyType.SNAP),
images: List<File> = List(3) { createImage() },
activeRegions: Set<Region> = setOf(Region("서울", "강남구")),
hashtags: Set<String> = setOf("tag1", "tag2"),
) = PostPromotionCommand(
authorId = randomLong(),
requestUser = requestUser,
promotionType = promotionType,
title = title,
content = content,
externalLink = "https://example.com",
startedAt = LocalDate.now(),
endedAt = LocalDate.now().plusDays(1),
isAuthorHidden = isAuthorHidden,
photographyTypes = photographyTypes,
images = images,
activeRegions = activeRegions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -507,13 +507,14 @@ class PromotionServiceTest {
}

private fun createPostPromotionCommand() = PostPromotionCommand(
authorId = randomLong(),
requestUser = createUser(),
promotionType = PromotionType.FREE,
title = randomString(len = 10),
content = randomString(),
externalLink = randomString(),
startedAt = randomLocalDate(),
endedAt = randomLocalDate(),
isAuthorHidden = false,
photographyTypes = setOf(PhotographyType.SNAP),
images = generateRandomList(maxSize = 10) { createImage() },
activeRegions = generateRandomSet(maxSize = 5) { createRegion() },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.damaba.damaba.domain.promotion.exception

import org.assertj.core.api.Assertions.assertThat
import kotlin.test.Test

class PromotionAuthorHiddenPermissionDeniedExceptionTest {
@Test
fun `PromotionAuthorHiddenPermissionDeniedException 생성 시 올바른 속성값을 가진다`() {
// given & when
val exception = PromotionAuthorHiddenPermissionDeniedException()

// then
assertThat(exception.httpStatusCode).isEqualTo(403)
assertThat(exception.code).isEqualTo("PROMOTION_AUTHOR_HIDDEN_PERMISSION_DENIED")
assertThat(exception.message).isEqualTo("작성자 정보 숨김은 관리자만 설정할 수 있습니다.")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ object PromotionFixture {
startedAt: LocalDate? = randomLocalDate(),
endedAt: LocalDate? = randomLocalDate(),
viewCount: Long = randomLong(),
isAuthorHidden: Boolean = false,
photographyTypes: Set<PhotographyType> = setOf(PhotographyType.SNAP),
images: List<Image> = generateRandomList(maxSize = 10) { createImage() },
activeRegions: Set<Region> = generateRandomSet(maxSize = 5) { createRegion() },
Expand All @@ -45,6 +46,7 @@ object PromotionFixture {
startedAt = startedAt,
endedAt = endedAt,
viewCount = viewCount,
isAuthorHidden = isAuthorHidden,
photographyTypes = photographyTypes,
images = images,
activeRegions = activeRegions,
Expand All @@ -63,6 +65,7 @@ object PromotionFixture {
viewCount: Long = randomLong(),
saveCount: Long = randomLong(),
isSaved: Boolean = randomBoolean(),
isAuthorHidden: Boolean = false,
photographyTypes: Set<PhotographyType> = setOf(PhotographyType.SNAP),
images: List<Image> = generateRandomList(maxSize = 10) { createImage() },
activeRegions: Set<Region> = generateRandomSet(maxSize = 5) { createRegion() },
Expand All @@ -79,6 +82,7 @@ object PromotionFixture {
viewCount = viewCount,
saveCount = saveCount,
isSaved = isSaved,
isAuthorHidden = isAuthorHidden,
photographyTypes = photographyTypes,
images = images,
activeRegions = activeRegions,
Expand All @@ -93,6 +97,7 @@ object PromotionFixture {
endedAt: LocalDate? = randomLocalDate(),
saveCount: Long = randomLong(),
isSaved: Boolean = randomBoolean(),
isAuthorHidden: Boolean = false,
photographyTypes: Set<PhotographyType> = setOf(PhotographyType.SNAP),
images: List<Image> = generateRandomList(maxSize = 10) { createImage() },
activeRegions: Set<Region> = generateRandomSet(maxSize = 5) { createRegion() },
Expand All @@ -105,6 +110,7 @@ object PromotionFixture {
endedAt = endedAt,
saveCount = saveCount,
isSaved = isSaved,
isAuthorHidden = isAuthorHidden,
photographyTypes = photographyTypes,
images = images,
activeRegions = activeRegions,
Expand Down
Loading