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
@@ -0,0 +1,54 @@
package com.pinback.api.category.controller;

import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.pinback.api.category.dto.request.CreateCategoryRequestV3;
import com.pinback.api.category.dto.request.UpdateCategoryRequestV3;
import com.pinback.application.category.dto.response.CreateCategoryResponseV3;
import com.pinback.application.category.dto.response.UpdateCategoryResponseV3;
import com.pinback.application.category.port.in.CreateCategoryPort;
import com.pinback.application.category.port.in.UpdateCategoryPort;
import com.pinback.domain.user.entity.User;
import com.pinback.shared.annotation.CurrentUser;
import com.pinback.shared.dto.ResponseDto;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping("/api/v3/categories")
@RequiredArgsConstructor
@Tag(name = "CategoryV3", description = "카테고리 관리 API V3")
public class CategoryControllerV3 {
private final CreateCategoryPort createCategoryPort;
private final UpdateCategoryPort updateCategoryPort;

@Operation(summary = "카테고리 생성 V3", description = "공개여부 설정을 추가하여 새로운 카테고리를 생성합니다")
@PostMapping
public ResponseDto<CreateCategoryResponseV3> createCategoryV3(
@Parameter(hidden = true) @CurrentUser User user,
@Valid @RequestBody CreateCategoryRequestV3 request
) {
CreateCategoryResponseV3 response = createCategoryPort.createCategoryV3(user, request.toCommand());
return ResponseDto.ok(response);
}

@Operation(summary = "카테고리 수정 V3", description = "공개여부 설정을 추가하여 카테고리 정보를 수정합니다")
@PatchMapping("/{categoryId}")
public ResponseDto<UpdateCategoryResponseV3> updateCategoryV3(
@Parameter(hidden = true) @CurrentUser User user,
@Parameter(description = "카테고리 ID") @PathVariable Long categoryId,
@Valid @RequestBody UpdateCategoryRequestV3 request
) {
UpdateCategoryResponseV3 response = updateCategoryPort.updateCategoryV3(user, categoryId, request.toCommand());
return ResponseDto.ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.pinback.api.category.dto.request;

import com.pinback.application.category.dto.command.CreateCategoryCommandV3;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

@Schema(description = "카테고리 생성 요청 V3")
public record CreateCategoryRequestV3(
@Schema(description = "카테고리 이름", example = "개발")
@NotBlank(message = "카테고리 이름은 필수입니다")
@Size(max = 50, message = "카테고리 이름은 50자 이하로 입력해주세요")
String categoryName,
@Schema(description = "카테고리 공개여부", example = "true")
Boolean isPublic
) {
public CreateCategoryCommandV3 toCommand() {
return new CreateCategoryCommandV3(categoryName, isPublic);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.pinback.api.category.dto.request;

import com.pinback.application.category.dto.command.UpdateCategoryCommandV3;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

@Schema(description = "카테고리 수정 요청 V3")
public record UpdateCategoryRequestV3(
@Schema(description = "카테고리 이름", example = "수정된 개발")
@NotBlank(message = "카테고리 이름은 필수입니다")
@Size(max = 50, message = "카테고리 이름은 50자 이하로 입력해주세요")
String categoryName,
@Schema(description = "카테고리 공개여부", example = "false")
Boolean isPublic
) {
public UpdateCategoryCommandV3 toCommand() {
return new UpdateCategoryCommandV3(categoryName, isPublic);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.pinback.application.category.dto.command;

public record CreateCategoryCommandV3(
String categoryName,
Boolean isPublic
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.pinback.application.category.dto.command;

public record UpdateCategoryCommandV3(
String categoryName,
Boolean isPublic
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.pinback.application.category.dto.response;

import com.pinback.domain.category.enums.CategoryColor;

public record CreateCategoryResponseV3(
Long categoryId,
String categoryName,
String categoryColor,
Boolean isPublic
) {
public static CreateCategoryResponseV3 of(Long categoryId, String categoryName, CategoryColor categoryColor) {
return new CreateCategoryResponseV3(categoryId, categoryName, categoryColor.toString(), false);
}

public static CreateCategoryResponseV3 of(Long categoryId, String categoryName, CategoryColor categoryColor,
boolean isPublic) {
return new CreateCategoryResponseV3(categoryId, categoryName, categoryColor.toString(), isPublic);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.pinback.application.category.dto.response;

import com.pinback.domain.category.entity.Category;

public record UpdateCategoryResponseV3(
long categoryId,
String categoryName,
Boolean isPublic
) {
public static UpdateCategoryResponseV3 from(Category category) {
return new UpdateCategoryResponseV3(category.getId(), category.getName(), category.getIsPublic());
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package com.pinback.application.category.port.in;

import com.pinback.application.category.dto.command.CreateCategoryCommand;
import com.pinback.application.category.dto.command.CreateCategoryCommandV3;
import com.pinback.application.category.dto.response.CreateCategoryResponse;
import com.pinback.application.category.dto.response.CreateCategoryResponseV3;
import com.pinback.domain.user.entity.User;

public interface CreateCategoryPort {
CreateCategoryResponse createCategory(User user, CreateCategoryCommand command);

CreateCategoryResponseV3 createCategoryV3(User user, CreateCategoryCommandV3 command);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package com.pinback.application.category.port.in;

import com.pinback.application.category.dto.command.UpdateCategoryCommand;
import com.pinback.application.category.dto.command.UpdateCategoryCommandV3;
import com.pinback.application.category.dto.response.UpdateCategoryResponse;
import com.pinback.application.category.dto.response.UpdateCategoryResponseV3;
import com.pinback.domain.user.entity.User;

public interface UpdateCategoryPort {
UpdateCategoryResponse updateCategory(User user, Long categoryId, UpdateCategoryCommand command);

UpdateCategoryResponseV3 updateCategoryV3(User user, Long categoryId, UpdateCategoryCommandV3 command);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import org.springframework.transaction.annotation.Transactional;

import com.pinback.application.category.dto.command.CreateCategoryCommand;
import com.pinback.application.category.dto.command.CreateCategoryCommandV3;
import com.pinback.application.category.dto.response.CreateCategoryResponse;
import com.pinback.application.category.dto.response.CreateCategoryResponseV3;
import com.pinback.application.category.port.in.CreateCategoryPort;
import com.pinback.application.category.port.out.CategoryColorServicePort;
import com.pinback.application.category.port.out.CategoryGetServicePort;
Expand Down Expand Up @@ -44,6 +46,26 @@ public CreateCategoryResponse createCategory(User user, CreateCategoryCommand co
}
}

@Override
public CreateCategoryResponseV3 createCategoryV3(User user, CreateCategoryCommandV3 command) {
validateCategoryCreationV3(user, command);

CategoryColor availableColor = getNextAvailableColor(user);
try {
Category category = Category.createWithIsPublic(command.categoryName(), user, availableColor,
command.isPublic());
Category savedCategory = categorySaveService.save(category);
return CreateCategoryResponseV3.of(
savedCategory.getId(),
savedCategory.getName(),
savedCategory.getColor(),
savedCategory.getIsPublic()
);
} catch (CategoryNameLengthOverException e) {
throw new CategoryNameLengthOverException();
}
}

private void validateCategoryCreation(User user, CreateCategoryCommand command) {
if (categoryGetService.countCategoriesByUser(user) >= 10) {
throw new CategoryLimitOverException();
Expand All @@ -61,4 +83,13 @@ private CategoryColor getNextAvailableColor(User user) {
.findFirst()
.orElse(CategoryColor.COLOR1);
}

private void validateCategoryCreationV3(User user, CreateCategoryCommandV3 command) {
if (categoryGetService.countCategoriesByUser(user) >= 10) {
throw new CategoryLimitOverException();
}
if (categoryGetService.checkExistsByCategoryNameAndUser(command.categoryName(), user)) {
throw new CategoryAlreadyExistException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import org.springframework.transaction.annotation.Transactional;

import com.pinback.application.category.dto.command.UpdateCategoryCommand;
import com.pinback.application.category.dto.command.UpdateCategoryCommandV3;
import com.pinback.application.category.dto.response.UpdateCategoryResponse;
import com.pinback.application.category.dto.response.UpdateCategoryResponseV3;
import com.pinback.application.category.port.in.UpdateCategoryPort;
import com.pinback.application.category.port.out.CategoryGetServicePort;
import com.pinback.domain.category.entity.Category;
Expand All @@ -31,4 +33,17 @@ public UpdateCategoryResponse updateCategory(User user, Long categoryId, UpdateC

return UpdateCategoryResponse.from(category);
}

@Override
public UpdateCategoryResponseV3 updateCategoryV3(User user, Long categoryId, UpdateCategoryCommandV3 command) {
Category category = categoryGetService.getCategoryAndUser(categoryId, user);
try {
category.updateName(command.categoryName());
} catch (CategoryNameLengthOverException e) {
throw new CategoryNameLengthOverException();
}
category.updateIsPublic(command.isPublic());

return UpdateCategoryResponseV3.from(category);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ public class Category extends BaseEntity {
@Enumerated(EnumType.STRING)
private CategoryColor color;

@Column(name = "is_public", nullable = false)
private Boolean isPublic;

public static Category create(String name, User user, CategoryColor color) {
validateName(name);
return Category.builder()
Expand All @@ -62,6 +65,16 @@ public static Category create(String name, User user, CategoryColor color) {
.build();
}

public static Category createWithIsPublic(String name, User user, CategoryColor color, Boolean isPublic) {
validateName(name);
return Category.builder()
.name(name)
.user(user)
.color(color)
.isPublic(isPublic)
.build();
}

private static void validateName(String name) {
int characterCount = TextUtil.countGraphemeClusters(name);
if (characterCount > 300) {
Expand All @@ -77,4 +90,8 @@ public void updateName(String name) {
public boolean isOwnedBy(User user) {
return this.user.equals(user);
}

public void updateIsPublic(Boolean isPublic) {
this.isPublic = isPublic;
}
}
Loading