Skip to content

Commit

Permalink
[Feat] Shoot 생성 API 구현, 상태 변경 수정 (#64)
Browse files Browse the repository at this point in the history
* feat : shootStatus 변경 수정

* feat : shootStatus 구현

* feat : Shoot 생성, 태그 추출 구현

* feat : ShootStatusService 분리

* feat : ShootRepository 정리

* feat : figmaService 수정
  • Loading branch information
cowboysj authored Nov 19, 2024
1 parent e4803c8 commit f8c3b42
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 37 deletions.
2 changes: 2 additions & 0 deletions src/main/java/gigedi/dev/domain/auth/dao/FigmaRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ public interface FigmaRepository extends JpaRepository<Figma, Long> {
Optional<Figma> findByFigmaIdAndDeletedAtIsNull(Long figmaId);

Optional<Figma> findByFigmaUserIdAndDeletedAtIsNull(String figmaUserId);

Optional<Figma> findByFigmaName(String name);
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ public Figma getFigmaByFigmaId(String figmaId) {
.orElseThrow(() -> new CustomException(ErrorCode.FIGMA_NOT_CONNECTED));
}

public Figma findByTag(String tag) {
return figmaRepository
.findByFigmaName(tag)
.orElseThrow(() -> new CustomException(ErrorCode.FIGMA_USER_INFO_NOT_FOUND));
}

@Transactional(readOnly = true)
public List<Figma> getFigmaListByMember(Member member) {
return figmaRepository.findByMemberAndDeletedAtIsNull(member);
Expand Down
13 changes: 12 additions & 1 deletion src/main/java/gigedi/dev/domain/shoot/api/ShootController.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@
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 gigedi.dev.domain.shoot.application.ShootService;
import gigedi.dev.domain.shoot.application.ShootStatusService;
import gigedi.dev.domain.shoot.dto.request.CreateShootRequest;
import gigedi.dev.domain.shoot.dto.request.UpdateShootStatusRequest;
import gigedi.dev.domain.shoot.dto.response.GetShootResponse;
import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -23,6 +26,7 @@
@RequiredArgsConstructor
public class ShootController {
private final ShootService shootService;
private final ShootStatusService shootStatusService;

@Operation(summary = "Block 별 Shoot 조회 API", description = "Block 별 Shoot을 조회하는 API")
@GetMapping("/{blockId}")
Expand All @@ -36,10 +40,17 @@ public void deleteShoot(@PathVariable Long shootId) {
shootService.deleteShoot(shootId);
}

@Operation(summary = "Shoot 생성 API", description = "Shoot을 생성하는 API")
@PostMapping("/{blockId}")
public GetShootResponse createShoot(
@PathVariable Long blockId, @RequestBody CreateShootRequest request) {
return shootService.createShoot(blockId, request.content());
}

@Operation(summary = "Shoot 상태 변경 API", description = "Shoot의 상태(yet, doing, done)를 변경하는 API")
@PatchMapping("/status/{shootId}")
public GetShootResponse updateShootStatus(
@PathVariable Long shootId, @RequestBody UpdateShootStatusRequest request) {
return shootService.updateShootStatus(shootId, request.status());
return shootStatusService.updateShootStatus(shootId, request.status());
}
}
62 changes: 32 additions & 30 deletions src/main/java/gigedi/dev/domain/shoot/application/ShootService.java
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
package gigedi.dev.domain.shoot.application;

import java.util.EnumSet;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import gigedi.dev.domain.auth.domain.Figma;
import gigedi.dev.domain.block.application.BlockService;
import gigedi.dev.domain.block.domain.Block;
import gigedi.dev.domain.shoot.dao.ShootRepository;
import gigedi.dev.domain.shoot.dao.ShootStatusRepository;
import gigedi.dev.domain.shoot.domain.Shoot;
import gigedi.dev.domain.shoot.domain.ShootStatus;
import gigedi.dev.domain.shoot.domain.Status;
import gigedi.dev.domain.shoot.dto.response.GetShootResponse;
import gigedi.dev.global.error.exception.CustomException;
import gigedi.dev.global.error.exception.ErrorCode;
import gigedi.dev.global.util.FigmaUtil;
import gigedi.dev.global.util.ShootUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
public class ShootService {
private final ShootRepository shootRepository;
private final ShootStatusRepository shootStatusRepository;
private final ShootStatusService shootStatusService;
private final FigmaUtil figmaUtil;
private final BlockService blockService;
private final ShootTagService shootTagService;

@Transactional(readOnly = true)
public List<GetShootResponse> getShoot(Long blockId) {
Expand All @@ -40,7 +46,29 @@ public List<GetShootResponse> getShoot(Long blockId) {
.toList();
}

private List<GetShootResponse.User> getUsersByStatus(Shoot shoot, Status status) {
@Transactional
public void deleteShoot(Long shootId) {
Shoot shoot = findValidShoot(shootId);
shoot.deleteShoot();
}

@Transactional
public GetShootResponse createShoot(Long blockId, String content) {
Block block = blockService.getBlockById(blockId);
final Figma figma = figmaUtil.getCurrentFigma();
Shoot shoot = Shoot.createShoot(content, figma, block);
shootRepository.save(shoot);
processTags(content, shoot);

return GetShootResponse.of(shoot, null, null, null);
}

private void processTags(String content, Shoot shoot) {
List<String> tags = ShootUtil.extractTags(content);
shootTagService.createShootTags(shoot, tags);
}

public List<GetShootResponse.User> getUsersByStatus(Shoot shoot, Status status) {
return shootStatusRepository
.findByShoot_ShootIdAndStatus(shoot.getShootId(), status)
.stream()
Expand All @@ -55,32 +83,6 @@ private List<GetShootResponse.User> getUsersByStatus(Shoot shoot, Status status)
.collect(Collectors.toList());
}

@Transactional
public void deleteShoot(Long shootId) {
Shoot shoot = findValidShoot(shootId);
shoot.deleteShoot();
}

@Transactional
public GetShootResponse updateShootStatus(Long shootId, Status newStatus) {
validateStatus(newStatus);
Shoot shoot = findValidShoot(shootId);
ShootStatus shootStatus = shootStatusService.getShootStatusByShootId(shoot.getShootId());
shootStatus.updateStatus(newStatus);
return GetShootResponse.of(
shoot,
getUsersByStatus(shoot, Status.YET),
getUsersByStatus(shoot, Status.DOING),
getUsersByStatus(shoot, Status.DONE));
}

private void validateStatus(Status status) {
if (status == null || !EnumSet.allOf(Status.class).contains(status)) {
throw new CustomException(ErrorCode.INVALID_STATUS);
}
}

@Transactional
public Shoot findValidShoot(Long shootId) {
return shootRepository
.findByShootIdAndDeletedAtIsNull(shootId)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,56 @@
package gigedi.dev.domain.shoot.application;

import jakarta.transaction.Transactional;
import java.util.EnumSet;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import gigedi.dev.domain.auth.domain.Figma;
import gigedi.dev.domain.shoot.dao.ShootStatusRepository;
import gigedi.dev.domain.shoot.domain.Shoot;
import gigedi.dev.domain.shoot.domain.ShootStatus;
import gigedi.dev.domain.shoot.domain.Status;
import gigedi.dev.domain.shoot.dto.response.GetShootResponse;
import gigedi.dev.global.error.exception.CustomException;
import gigedi.dev.global.error.exception.ErrorCode;
import gigedi.dev.global.util.FigmaUtil;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class ShootStatusService {
private final ShootStatusRepository shootStatusRepository;
private final FigmaUtil figmaUtil;
private final ShootService shootService;

@Transactional
public ShootStatus getShootStatusByShootId(Long shootId) {
return shootStatusRepository
.findByShoot_ShootId(shootId)
.orElseThrow(() -> new CustomException(ErrorCode.SHOOT_STATUS_NOT_FOUND));
public GetShootResponse updateShootStatus(Long shootId, Status newStatus) {
final Figma figma = figmaUtil.getCurrentFigma();
validateStatus(newStatus);
Shoot shoot = shootService.findValidShoot(shootId);
ShootStatus shootStatus =
shootStatusRepository
.findByShoot_ShootIdAndFigma_FigmaId(shootId, figma.getFigmaId())
.orElseGet(
() -> {
ShootStatus newShootStatus =
ShootStatus.createShootStatus(newStatus, figma, shoot);
return shootStatusRepository.save(newShootStatus);
});

if (shootStatus.getStatus() != newStatus) {
shootStatus.updateStatus(newStatus);
}
return GetShootResponse.of(
shoot,
shootService.getUsersByStatus(shoot, Status.YET),
shootService.getUsersByStatus(shoot, Status.DOING),
shootService.getUsersByStatus(shoot, Status.DONE));
}

private void validateStatus(Status status) {
if (status == null || !EnumSet.allOf(Status.class).contains(status)) {
throw new CustomException(ErrorCode.INVALID_STATUS);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package gigedi.dev.domain.shoot.application;

import java.util.List;

import org.springframework.stereotype.Service;

import gigedi.dev.domain.auth.domain.Figma;
import gigedi.dev.domain.figma.application.FigmaService;
import gigedi.dev.domain.shoot.dao.ShootTagRepository;
import gigedi.dev.domain.shoot.domain.Shoot;
import gigedi.dev.domain.shoot.domain.ShootTag;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class ShootTagService {
private final ShootTagRepository shootTagRepository;
private final FigmaService figmaService;

public void createShootTags(Shoot shoot, List<String> tags) {
tags.forEach(
tag -> {
Figma figma = figmaService.findByTag(tag);
if (figma != null) {
ShootTag shootTag = ShootTag.createShootTag(shoot, figma);
shootTagRepository.save(shootTag);
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@
public interface ShootStatusRepository extends JpaRepository<ShootStatus, Long> {
List<ShootStatus> findByShoot_ShootIdAndStatus(Long shootId, Status status);

Optional<ShootStatus> findByShoot_ShootId(Long shootId);
Optional<ShootStatus> findByShoot_ShootIdAndFigma_FigmaId(Long shootId, Long figmaId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package gigedi.dev.domain.shoot.dao;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import gigedi.dev.domain.shoot.domain.ShootTag;

@Repository
public interface ShootTagRepository extends JpaRepository<ShootTag, Long> {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package gigedi.dev.domain.shoot.dto.request;

public record CreateShootRequest(String content) {}
22 changes: 22 additions & 0 deletions src/main/java/gigedi/dev/global/util/ShootUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package gigedi.dev.global.util;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class ShootUtil {
private static final String SPACE_DELIMITER = "\\s+";
private static final String TAG_PREFIX = "@";

public static List<String> extractTags(String content) {

if (content == null || content.isEmpty()) {
return Collections.emptyList();
}
return Arrays.stream(content.split(SPACE_DELIMITER))
.filter(word -> word.startsWith(TAG_PREFIX))
.map(word -> word.substring(1))
.collect(Collectors.toList());
}
}

0 comments on commit f8c3b42

Please sign in to comment.