diff --git a/adapters/in-web/src/main/kotlin/com/pokit/category/CategoryController.kt b/adapters/in-web/src/main/kotlin/com/pokit/category/v1/CategoryController.kt similarity index 92% rename from adapters/in-web/src/main/kotlin/com/pokit/category/CategoryController.kt rename to adapters/in-web/src/main/kotlin/com/pokit/category/v1/CategoryController.kt index e2e1464a..1118bb08 100644 --- a/adapters/in-web/src/main/kotlin/com/pokit/category/CategoryController.kt +++ b/adapters/in-web/src/main/kotlin/com/pokit/category/v1/CategoryController.kt @@ -1,13 +1,13 @@ -package com.pokit.category +package com.pokit.category.v1 import com.pokit.auth.config.ErrorOperation import com.pokit.auth.model.PrincipalUser import com.pokit.category.dto.CategoriesResponse -import com.pokit.category.dto.request.CreateCategoryRequest -import com.pokit.category.dto.request.toDto -import com.pokit.category.dto.response.CategoryCountResponse -import com.pokit.category.dto.response.CategoryResponse -import com.pokit.category.dto.response.toResponse +import com.pokit.category.v1.dto.request.CreateCategoryRequest +import com.pokit.category.v1.dto.request.toDto +import com.pokit.category.v1.dto.response.CategoryCountResponse +import com.pokit.category.v1.dto.response.CategoryResponse +import com.pokit.category.v1.dto.response.toResponse import com.pokit.category.exception.CategoryErrorCode import com.pokit.category.model.CategoryImage import com.pokit.category.port.`in`.CategoryUseCase diff --git a/adapters/in-web/src/main/kotlin/com/pokit/category/CategoryShareController.kt b/adapters/in-web/src/main/kotlin/com/pokit/category/v1/CategoryShareController.kt similarity index 94% rename from adapters/in-web/src/main/kotlin/com/pokit/category/CategoryShareController.kt rename to adapters/in-web/src/main/kotlin/com/pokit/category/v1/CategoryShareController.kt index 0fe2e501..7471be03 100644 --- a/adapters/in-web/src/main/kotlin/com/pokit/category/CategoryShareController.kt +++ b/adapters/in-web/src/main/kotlin/com/pokit/category/v1/CategoryShareController.kt @@ -1,9 +1,9 @@ -package com.pokit.category +package com.pokit.category.v1 import com.pokit.auth.aop.KakaoAuth import com.pokit.auth.model.PrincipalUser -import com.pokit.category.dto.request.DuplicateCategoryRequest -import com.pokit.category.dto.response.SharedContentsResponse +import com.pokit.category.v1.dto.request.DuplicateCategoryRequest +import com.pokit.category.v1.dto.response.SharedContentsResponse import com.pokit.category.port.`in`.CategoryUseCase import com.pokit.common.wrapper.ResponseWrapper.wrapOk import com.pokit.common.wrapper.ResponseWrapper.wrapUnit diff --git a/adapters/in-web/src/main/kotlin/com/pokit/category/dto/request/CreateCategoryRequest.kt b/adapters/in-web/src/main/kotlin/com/pokit/category/v1/dto/request/CreateCategoryRequest.kt similarity index 92% rename from adapters/in-web/src/main/kotlin/com/pokit/category/dto/request/CreateCategoryRequest.kt rename to adapters/in-web/src/main/kotlin/com/pokit/category/v1/dto/request/CreateCategoryRequest.kt index e28450bb..eb307723 100644 --- a/adapters/in-web/src/main/kotlin/com/pokit/category/dto/request/CreateCategoryRequest.kt +++ b/adapters/in-web/src/main/kotlin/com/pokit/category/v1/dto/request/CreateCategoryRequest.kt @@ -1,4 +1,4 @@ -package com.pokit.category.dto.request +package com.pokit.category.v1.dto.request import com.pokit.category.dto.CategoryCommand import jakarta.validation.constraints.NotBlank diff --git a/adapters/in-web/src/main/kotlin/com/pokit/category/dto/request/DuplicateCategoryRequest.kt b/adapters/in-web/src/main/kotlin/com/pokit/category/v1/dto/request/DuplicateCategoryRequest.kt similarity index 86% rename from adapters/in-web/src/main/kotlin/com/pokit/category/dto/request/DuplicateCategoryRequest.kt rename to adapters/in-web/src/main/kotlin/com/pokit/category/v1/dto/request/DuplicateCategoryRequest.kt index 7963de61..ad1428b0 100644 --- a/adapters/in-web/src/main/kotlin/com/pokit/category/dto/request/DuplicateCategoryRequest.kt +++ b/adapters/in-web/src/main/kotlin/com/pokit/category/v1/dto/request/DuplicateCategoryRequest.kt @@ -1,4 +1,4 @@ -package com.pokit.category.dto.request +package com.pokit.category.v1.dto.request import jakarta.validation.constraints.Size diff --git a/adapters/in-web/src/main/kotlin/com/pokit/category/dto/request/UpdateCategoryRequest.kt b/adapters/in-web/src/main/kotlin/com/pokit/category/v1/dto/request/UpdateCategoryRequest.kt similarity index 92% rename from adapters/in-web/src/main/kotlin/com/pokit/category/dto/request/UpdateCategoryRequest.kt rename to adapters/in-web/src/main/kotlin/com/pokit/category/v1/dto/request/UpdateCategoryRequest.kt index 53a63f39..61ce5521 100644 --- a/adapters/in-web/src/main/kotlin/com/pokit/category/dto/request/UpdateCategoryRequest.kt +++ b/adapters/in-web/src/main/kotlin/com/pokit/category/v1/dto/request/UpdateCategoryRequest.kt @@ -1,4 +1,4 @@ -package com.pokit.category.dto.request +package com.pokit.category.v1.dto.request import com.pokit.category.dto.CategoryCommand import jakarta.validation.constraints.NotBlank diff --git a/adapters/in-web/src/main/kotlin/com/pokit/category/dto/response/CategoryResponse.kt b/adapters/in-web/src/main/kotlin/com/pokit/category/v1/dto/response/CategoryResponse.kt similarity index 91% rename from adapters/in-web/src/main/kotlin/com/pokit/category/dto/response/CategoryResponse.kt rename to adapters/in-web/src/main/kotlin/com/pokit/category/v1/dto/response/CategoryResponse.kt index 48829e66..4553f662 100644 --- a/adapters/in-web/src/main/kotlin/com/pokit/category/dto/response/CategoryResponse.kt +++ b/adapters/in-web/src/main/kotlin/com/pokit/category/v1/dto/response/CategoryResponse.kt @@ -1,4 +1,4 @@ -package com.pokit.category.dto.response +package com.pokit.category.v1.dto.response import com.pokit.category.model.Category import com.pokit.category.model.CategoryImage diff --git a/adapters/in-web/src/main/kotlin/com/pokit/category/dto/response/SharedContentsResponse.kt b/adapters/in-web/src/main/kotlin/com/pokit/category/v1/dto/response/SharedContentsResponse.kt similarity index 98% rename from adapters/in-web/src/main/kotlin/com/pokit/category/dto/response/SharedContentsResponse.kt rename to adapters/in-web/src/main/kotlin/com/pokit/category/v1/dto/response/SharedContentsResponse.kt index 24ee61a1..63aee8ab 100644 --- a/adapters/in-web/src/main/kotlin/com/pokit/category/dto/response/SharedContentsResponse.kt +++ b/adapters/in-web/src/main/kotlin/com/pokit/category/v1/dto/response/SharedContentsResponse.kt @@ -1,4 +1,4 @@ -package com.pokit.category.dto.response +package com.pokit.category.v1.dto.response import com.pokit.category.model.Category import com.pokit.common.dto.DateFormatters diff --git a/adapters/in-web/src/main/kotlin/com/pokit/category/v2/CategoryControllerV2.kt b/adapters/in-web/src/main/kotlin/com/pokit/category/v2/CategoryControllerV2.kt new file mode 100644 index 00000000..4e7842fb --- /dev/null +++ b/adapters/in-web/src/main/kotlin/com/pokit/category/v2/CategoryControllerV2.kt @@ -0,0 +1,50 @@ +package com.pokit.category.v2 + +import com.pokit.auth.config.ErrorOperation +import com.pokit.auth.model.PrincipalUser +import com.pokit.category.exception.CategoryErrorCode +import com.pokit.category.port.`in`.CategoryUseCase +import com.pokit.category.v1.dto.response.CategoryResponse +import com.pokit.category.v1.dto.response.toResponse +import com.pokit.category.v2.dto.request.CreateCategoryRequestV2 +import com.pokit.category.v2.dto.request.toDto +import com.pokit.common.wrapper.ResponseWrapper.wrapOk +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import jakarta.validation.Valid +import org.springframework.http.ResponseEntity +import org.springframework.security.core.annotation.AuthenticationPrincipal +import org.springframework.web.bind.annotation.* + +@Tag(name = "Category API Ver2") +@RestController +@RequestMapping("/api/v2/category") +class CategoryControllerV2( + private val categoryUseCase: CategoryUseCase +) { + @Operation(summary = "포킷 생성 API Ver2") + @ErrorOperation(CategoryErrorCode::class) + @PostMapping + fun createCategory( + @AuthenticationPrincipal user: PrincipalUser, + @Valid @RequestBody request: CreateCategoryRequestV2 + ): ResponseEntity { + return categoryUseCase.create(request.toDto(), user.id) + .toResponse() + .wrapOk() + } + + @Operation(summary = "포킷 추가 API Ver2") + @ErrorOperation(CategoryErrorCode::class) + @PatchMapping("/{categoryId}") + fun updateCategory( + @AuthenticationPrincipal user: PrincipalUser, + @Valid @RequestBody request: CreateCategoryRequestV2, + @PathVariable categoryId: Long, + ): ResponseEntity { + return categoryUseCase.update(request.toDto(), user.id, categoryId) + .toResponse() + .wrapOk() + } + +} diff --git a/adapters/in-web/src/main/kotlin/com/pokit/category/v2/dto/request/CreateCategoryRequestV2.kt b/adapters/in-web/src/main/kotlin/com/pokit/category/v2/dto/request/CreateCategoryRequestV2.kt new file mode 100644 index 00000000..5d59a293 --- /dev/null +++ b/adapters/in-web/src/main/kotlin/com/pokit/category/v2/dto/request/CreateCategoryRequestV2.kt @@ -0,0 +1,23 @@ +package com.pokit.category.v2.dto.request + +import com.pokit.category.dto.CategoryCommand +import com.pokit.category.model.OpenType +import com.pokit.user.model.InterestType +import jakarta.validation.constraints.NotBlank +import jakarta.validation.constraints.Size + +data class CreateCategoryRequestV2( + @field:NotBlank(message = "포킷 명은 필수 값입니다.") + @field:Size(min = 1, max = 10, message = "최대 10자까지 입력 가능합니다.") + val categoryName: String, + val categoryImageId: Int, + val openType: String, + val keywordType: String, +) + +internal fun CreateCategoryRequestV2.toDto() = CategoryCommand( + categoryName = this.categoryName, + categoryImageId = this.categoryImageId, + openType = OpenType.of(this.openType), + keywordType = InterestType.of(this.keywordType) +) diff --git a/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/category/persist/CategoryEntity.kt b/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/category/persist/CategoryEntity.kt index 84f33f7d..4c41b779 100644 --- a/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/category/persist/CategoryEntity.kt +++ b/adapters/out-persistence/src/main/kotlin/com/pokit/out/persistence/category/persist/CategoryEntity.kt @@ -3,6 +3,7 @@ package com.pokit.out.persistence.category.persist import com.pokit.category.model.Category import com.pokit.category.model.OpenType import com.pokit.out.persistence.BaseEntity +import com.pokit.user.model.InterestType import jakarta.persistence.* // 포킷 엔티티 @@ -32,7 +33,11 @@ class CategoryEntity( var userCount: Int = 0, @Column(name = "is_shared") - var isShared: Boolean = false + var isShared: Boolean = false, + + @Column(name = "keyword") + @Enumerated(EnumType.STRING) + var keyword: InterestType = InterestType.DEFAULT, ) : BaseEntity() { @Column(name = "is_deleted") @@ -51,7 +56,8 @@ class CategoryEntity( image = CategoryImageEntity.of(category.categoryImage), openType = category.openType, userCount = category.userCount, - isShared = category.isShared + isShared = category.isShared, + keyword = category.keyword ) } } @@ -64,5 +70,6 @@ fun CategoryEntity.toDomain() = Category( createdAt = this.createdAt, openType = this.openType, userCount = this.userCount, - isShared = this.isShared + isShared = this.isShared, + keyword = this.keyword ) diff --git a/application/src/main/kotlin/com/pokit/category/port/service/CategoryService.kt b/application/src/main/kotlin/com/pokit/category/port/service/CategoryService.kt index 9ad5f270..633c572d 100644 --- a/application/src/main/kotlin/com/pokit/category/port/service/CategoryService.kt +++ b/application/src/main/kotlin/com/pokit/category/port/service/CategoryService.kt @@ -55,7 +55,8 @@ class CategoryService( categoryName = command.categoryName, categoryImage = categoryImage, userId = userId, - openType = OpenType.PRIVATE, + openType = command.openType, + keyword = command.keywordType ) ) } @@ -67,7 +68,7 @@ class CategoryService( val categoryImage = categoryImagePort.loadById(categoryCommand.categoryImageId) ?: throw NotFoundCustomException(CategoryErrorCode.NOT_FOUND_CATEGORY_IMAGE) - category.update(categoryCommand.categoryName, categoryImage) + category.update(categoryCommand, categoryImage) return categoryPort.persist(category) } diff --git a/application/src/main/kotlin/com/pokit/user/port/service/UserService.kt b/application/src/main/kotlin/com/pokit/user/port/service/UserService.kt index 939e52b8..fdcc617a 100644 --- a/application/src/main/kotlin/com/pokit/user/port/service/UserService.kt +++ b/application/src/main/kotlin/com/pokit/user/port/service/UserService.kt @@ -15,6 +15,7 @@ import com.pokit.user.dto.request.UserCommand import com.pokit.user.exception.UserErrorCode import com.pokit.user.model.FcmToken import com.pokit.user.model.Interest +import com.pokit.user.model.InterestType import com.pokit.user.model.User import com.pokit.user.port.`in`.UserUseCase import com.pokit.user.port.out.FcmTokenPort @@ -58,6 +59,7 @@ class UserService( categoryName = UNCATEGORIZED.displayName, categoryImage = image, openType = OpenType.PRIVATE, + keyword = InterestType.DEFAULT ) categoryPort.persist(category) diff --git a/domain/src/main/kotlin/com/pokit/category/dto/CategoriesResponse.kt b/domain/src/main/kotlin/com/pokit/category/dto/CategoriesResponse.kt index 2da2719e..f608075e 100644 --- a/domain/src/main/kotlin/com/pokit/category/dto/CategoriesResponse.kt +++ b/domain/src/main/kotlin/com/pokit/category/dto/CategoriesResponse.kt @@ -10,7 +10,9 @@ data class CategoriesResponse( var categoryName: String, var categoryImage: CategoryImage, var contentCount: Int, - val createdAt: String + val createdAt: String, + val openType: String, + val keywordType: String, ) fun Category.toCategoriesResponse(): CategoriesResponse { @@ -22,6 +24,8 @@ fun Category.toCategoriesResponse(): CategoriesResponse { categoryName = this.categoryName, categoryImage = this.categoryImage, contentCount = this.contentCount, - createdAt = this.createdAt.format(formatter) + createdAt = this.createdAt.format(formatter), + openType = this.openType.toString(), + keywordType = this.keyword.kor ) } diff --git a/domain/src/main/kotlin/com/pokit/category/dto/CategoryCommand.kt b/domain/src/main/kotlin/com/pokit/category/dto/CategoryCommand.kt index b517f21f..bdb8fff3 100644 --- a/domain/src/main/kotlin/com/pokit/category/dto/CategoryCommand.kt +++ b/domain/src/main/kotlin/com/pokit/category/dto/CategoryCommand.kt @@ -1,6 +1,11 @@ package com.pokit.category.dto -data class CategoryCommand ( +import com.pokit.category.model.OpenType +import com.pokit.user.model.InterestType + +data class CategoryCommand( val categoryName: String, val categoryImageId: Int, + val openType: OpenType = OpenType.PRIVATE, + val keywordType: InterestType = InterestType.DEFAULT, ) diff --git a/domain/src/main/kotlin/com/pokit/category/exception/CategoryErrorCode.kt b/domain/src/main/kotlin/com/pokit/category/exception/CategoryErrorCode.kt index 1714f76b..e3e58e3a 100644 --- a/domain/src/main/kotlin/com/pokit/category/exception/CategoryErrorCode.kt +++ b/domain/src/main/kotlin/com/pokit/category/exception/CategoryErrorCode.kt @@ -16,5 +16,6 @@ enum class CategoryErrorCode( NOT_FOUND_UNCATEGORIZED("사용자가 미분류 카테고리가 없습니다.(서버 에러)", "CA_008"), ALREADY_ACCEPTED("이미 초대를 수락한 포킷입니다.", "CA_009"), NEVER_ACCPTED("해당 유저가 포킷에 초대된 이력이 없습니다.", "CA_0010"), + INVALID_OPENTYPE("OpenType은 PUBLIC, PRIVATE중 하나여야 합니다.", "CA_0011"), } diff --git a/domain/src/main/kotlin/com/pokit/category/model/Category.kt b/domain/src/main/kotlin/com/pokit/category/model/Category.kt index f7a312f5..49fbd7fd 100644 --- a/domain/src/main/kotlin/com/pokit/category/model/Category.kt +++ b/domain/src/main/kotlin/com/pokit/category/model/Category.kt @@ -1,5 +1,7 @@ package com.pokit.category.model +import com.pokit.category.dto.CategoryCommand +import com.pokit.user.model.InterestType import java.time.LocalDateTime data class Category( @@ -12,10 +14,13 @@ data class Category( var openType: OpenType, var userCount: Int = 0, var isShared: Boolean = false, + var keyword: InterestType, ) { - fun update(categoryName: String, categoryImage: CategoryImage) { - this.categoryName = categoryName + fun update(command: CategoryCommand, categoryImage: CategoryImage) { + this.categoryName = command.categoryName this.categoryImage = categoryImage + this.openType = command.openType + this.keyword = command.keywordType } fun completeShare(): Category { diff --git a/domain/src/main/kotlin/com/pokit/category/model/OpenType.kt b/domain/src/main/kotlin/com/pokit/category/model/OpenType.kt index 292a0ae4..80dc5244 100644 --- a/domain/src/main/kotlin/com/pokit/category/model/OpenType.kt +++ b/domain/src/main/kotlin/com/pokit/category/model/OpenType.kt @@ -1,6 +1,18 @@ package com.pokit.category.model +import com.pokit.category.exception.CategoryErrorCode +import com.pokit.common.exception.ClientValidationException + enum class OpenType { PUBLIC, - PRIVATE, + PRIVATE + ; + + companion object { + fun of(input: String): OpenType { + return OpenType.entries + .firstOrNull { it.toString() == input } + ?: throw ClientValidationException(CategoryErrorCode.INVALID_OPENTYPE) + } + } } diff --git a/domain/src/main/kotlin/com/pokit/user/model/InterestType.kt b/domain/src/main/kotlin/com/pokit/user/model/InterestType.kt index f6eb2775..e398e947 100644 --- a/domain/src/main/kotlin/com/pokit/user/model/InterestType.kt +++ b/domain/src/main/kotlin/com/pokit/user/model/InterestType.kt @@ -6,6 +6,7 @@ import com.pokit.user.exception.UserErrorCode enum class InterestType( val kor: String, ) { + DEFAULT("default"), SPORTS("스포츠/레저"), OFFICE("문구/오피스"), FASHION("패션"),