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,104 @@
package starlight.adapter.backoffice.expert.webapi;

import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
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 starlight.adapter.backoffice.expert.webapi.dto.request.BackofficeExpertActiveStatusUpdateRequest;
import starlight.adapter.backoffice.expert.webapi.dto.request.BackofficeExpertCreateRequest;
import starlight.adapter.backoffice.expert.webapi.dto.request.BackofficeExpertProfileImageUpdateRequest;
import starlight.adapter.backoffice.expert.webapi.dto.request.BackofficeExpertUpdateRequest;
import starlight.adapter.backoffice.expert.webapi.dto.response.BackofficeExpertCreateResponse;
import starlight.adapter.backoffice.expert.webapi.dto.response.BackofficeExpertDetailResponse;
import starlight.adapter.backoffice.expert.webapi.dto.response.BackofficeExpertListResponse;
import starlight.adapter.backoffice.expert.webapi.swagger.BackofficeExpertApiDoc;
import starlight.application.backoffice.expert.provided.BackofficeExpertCommandUseCase;
import starlight.application.backoffice.expert.provided.BackofficeExpertQueryUseCase;
import starlight.application.backoffice.expert.provided.dto.input.BackofficeExpertActiveStatusUpdateInput;
import starlight.application.backoffice.expert.provided.dto.input.BackofficeExpertProfileImageUpdateInput;
import starlight.shared.apiPayload.response.ApiResponse;

import java.util.List;

@RestController
@RequiredArgsConstructor
@SecurityRequirement(name = "backofficeSession")
@RequestMapping("/v1/backoffice/experts")
public class BackofficeExpertController implements BackofficeExpertApiDoc {

private final BackofficeExpertQueryUseCase backofficeExpertQuery;
private final BackofficeExpertCommandUseCase backofficeExpertCommand;

@GetMapping
public ApiResponse<List<BackofficeExpertListResponse>> searchAll() {
return ApiResponse.success(BackofficeExpertListResponse.fromAll(
backofficeExpertQuery.searchAll()
));
}

@PostMapping
public ApiResponse<BackofficeExpertCreateResponse> create(
@Valid @RequestBody BackofficeExpertCreateRequest request
) {
return ApiResponse.success(BackofficeExpertCreateResponse.from(
backofficeExpertCommand.createExpert(request.toInput())
));
}

@GetMapping("/{expertId}")
public ApiResponse<BackofficeExpertDetailResponse> detail(
@PathVariable Long expertId
) {
return ApiResponse.success(BackofficeExpertDetailResponse.from(
backofficeExpertQuery.findById(expertId)
));
}

@PatchMapping("/{expertId}/active-status")
public ApiResponse<?> updateActiveStatus(
@PathVariable Long expertId,
@Valid @RequestBody BackofficeExpertActiveStatusUpdateRequest request
) {
backofficeExpertCommand.updateActiveStatus(
BackofficeExpertActiveStatusUpdateInput.of(expertId, request.activeStatus())
);

return ApiResponse.success();
}

@PatchMapping("/{expertId}")
public ApiResponse<?> update(
@PathVariable Long expertId,
@Valid @RequestBody BackofficeExpertUpdateRequest request
) {
backofficeExpertCommand.updateExpert(request.toInput(expertId));
return ApiResponse.success();
}

@DeleteMapping("/{expertId}")
public ApiResponse<?> delete(
@PathVariable Long expertId
) {
backofficeExpertCommand.deleteExpert(expertId);
return ApiResponse.success();
}

@PatchMapping("/{expertId}/profile-image")
public ApiResponse<?> updateProfileImage(
@PathVariable Long expertId,
@Valid @RequestBody BackofficeExpertProfileImageUpdateRequest request
) {
backofficeExpertCommand.updateProfileImage(
BackofficeExpertProfileImageUpdateInput.of(expertId, request.profileImageUrl())
);
return ApiResponse.success();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package starlight.adapter.backoffice.expert.webapi.dto.request;

import jakarta.validation.constraints.NotNull;
import starlight.domain.expert.enumerate.ExpertActiveStatus;

public record BackofficeExpertActiveStatusUpdateRequest(
@NotNull ExpertActiveStatus activeStatus
) { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package starlight.adapter.backoffice.expert.webapi.dto.request;

import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

import java.time.LocalDateTime;

public record BackofficeExpertCareerUpdateRequest(
Long id,
@NotNull @Min(0) Integer orderIndex,
@NotBlank String careerTitle,
String careerExplanation,
@NotNull LocalDateTime careerStartedAt,
@NotNull LocalDateTime careerEndedAt
) {
@AssertTrue(message = "경력 시작일은 종료일보다 늦을 수 없습니다.")
public boolean isValidPeriod() {
if (careerStartedAt == null || careerEndedAt == null) {
return true;
}
return !careerStartedAt.isAfter(careerEndedAt);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package starlight.adapter.backoffice.expert.webapi.dto.request;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import starlight.application.backoffice.expert.provided.dto.input.BackofficeExpertCreateInput;
import starlight.domain.expert.enumerate.TagCategory;

import java.util.List;

public record BackofficeExpertCreateRequest(
@NotBlank String name,
@Email @NotBlank String email,
String oneLineIntroduction,
List<String> tags,
List<TagCategory> categories
) {
public BackofficeExpertCreateInput toInput() {
return BackofficeExpertCreateInput.of(
name,
email,
oneLineIntroduction,
tags,
categories
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package starlight.adapter.backoffice.expert.webapi.dto.request;

import jakarta.validation.constraints.NotBlank;

public record BackofficeExpertProfileImageUpdateRequest(
@NotBlank String profileImageUrl
) { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package starlight.adapter.backoffice.expert.webapi.dto.request;

import jakarta.validation.Valid;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import starlight.application.backoffice.expert.provided.dto.input.BackofficeExpertCareerUpdateInput;
import starlight.application.backoffice.expert.provided.dto.input.BackofficeExpertUpdateInput;
import starlight.domain.expert.enumerate.TagCategory;

import java.util.List;

public record BackofficeExpertUpdateRequest(
@NotBlank String name,
@Email @NotBlank String email,
String oneLineIntroduction,
String detailedIntroduction,
Long workedPeriod,
Integer mentoringPriceWon,
List<String> tags,
List<TagCategory> categories,
@Valid List<BackofficeExpertCareerUpdateRequest> careers
) {
public BackofficeExpertUpdateInput toInput(Long expertId) {
List<BackofficeExpertCareerUpdateInput> careerInputs = careers == null
? null
: careers.stream()
.map(career -> new BackofficeExpertCareerUpdateInput(
career.id(),
career.orderIndex(),
career.careerTitle(),
career.careerExplanation(),
career.careerStartedAt(),
career.careerEndedAt()
))
.toList();

return BackofficeExpertUpdateInput.of(
expertId,
name,
email,
oneLineIntroduction,
detailedIntroduction,
workedPeriod,
mentoringPriceWon,
tags,
categories,
careerInputs
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package starlight.adapter.backoffice.expert.webapi.dto.response;

import starlight.application.expert.provided.dto.ExpertCareerResult;

import java.time.LocalDateTime;

public record BackofficeExpertCareerResponse(
Long id,
Integer orderIndex,
String careerTitle,
String careerExplanation,
LocalDateTime careerStartedAt,
LocalDateTime careerEndedAt
) {
public static BackofficeExpertCareerResponse from(ExpertCareerResult result) {
return new BackofficeExpertCareerResponse(
result.id(),
result.orderIndex(),
result.careerTitle(),
result.careerExplanation(),
result.careerStartedAt(),
result.careerEndedAt()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package starlight.adapter.backoffice.expert.webapi.dto.response;

import starlight.application.backoffice.expert.provided.dto.result.BackofficeExpertCreateResult;

public record BackofficeExpertCreateResponse(
Long id
) {
public static BackofficeExpertCreateResponse from(BackofficeExpertCreateResult result) {
return new BackofficeExpertCreateResponse(result.id());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package starlight.adapter.backoffice.expert.webapi.dto.response;

import starlight.application.backoffice.expert.provided.dto.result.BackofficeExpertDetailResult;

import java.util.List;

public record BackofficeExpertDetailResponse(
Long id,
Long applicationCount,
String name,
String oneLineIntroduction,
String detailedIntroduction,
String profileImageUrl,
Long workedPeriod,
String email,
Integer mentoringPriceWon,
String activeStatus,
List<BackofficeExpertCareerResponse> careers,
List<String> tags,
List<String> categories
) {
public static BackofficeExpertDetailResponse from(BackofficeExpertDetailResult result) {
List<BackofficeExpertCareerResponse> careers = result.careers().stream()
.map(BackofficeExpertCareerResponse::from)
.toList();

return new BackofficeExpertDetailResponse(
result.id(),
result.applicationCount(),
result.name(),
result.oneLineIntroduction(),
result.detailedIntroduction(),
result.profileImageUrl(),
result.workedPeriod(),
result.email(),
result.mentoringPriceWon(),
result.activeStatus().name(),
careers,
result.tags(),
result.categories()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package starlight.adapter.backoffice.expert.webapi.dto.response;

import starlight.application.backoffice.expert.provided.dto.result.BackofficeExpertDetailResult;
import starlight.application.expert.provided.dto.ExpertCareerResult;

import java.util.List;

public record BackofficeExpertListResponse(
Long id,
String name,
String oneLineIntroduction,
String profileImageUrl,
Long workedPeriod,
String email,
String activeStatus,
List<BackofficeExpertCareerSummaryResponse> careers,
List<String> tags,
List<String> categories
) {
private static final int MAX_CAREERS = 3;

public static BackofficeExpertListResponse from(BackofficeExpertDetailResult result) {
List<BackofficeExpertCareerSummaryResponse> careers = result.careers().stream()
.limit(MAX_CAREERS)
.map(BackofficeExpertCareerSummaryResponse::from)
.toList();

return new BackofficeExpertListResponse(
result.id(),
result.name(),
result.oneLineIntroduction(),
result.profileImageUrl(),
result.workedPeriod(),
result.email(),
result.activeStatus().name(),
careers,
result.tags(),
result.categories()
);
}

public static List<BackofficeExpertListResponse> fromAll(List<BackofficeExpertDetailResult> results) {
return results.stream()
.map(BackofficeExpertListResponse::from)
.toList();
}

public record BackofficeExpertCareerSummaryResponse(
Integer orderIndex,
String careerTitle
) {
public static BackofficeExpertCareerSummaryResponse from(ExpertCareerResult result) {
return new BackofficeExpertCareerSummaryResponse(
result.orderIndex(),
result.careerTitle()
);
}
}
}
Loading