Skip to content

Commit

Permalink
Merge pull request #79 from Train0303/feature/workspace
Browse files Browse the repository at this point in the history
워크스페이스 API 구현
  • Loading branch information
ikyeong authored Oct 5, 2023
2 parents 7506e17 + 92f7941 commit f54eb54
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
@RequiredArgsConstructor
@Getter
public enum WorkspaceExceptionStatus implements BaseExceptionStatus {
WORKSPACE_NOT_FOUND("존재하지 않는 워크스페이스 입니다.", 404),
WORKSPACE_FORBIDDEN("접근 권한이 없는 사용자 입니다.", 403),
WORKSPACE_DUPLICATED("같은 이름의 워크스페이스가 존재합니다.", 400);

private final String message;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.kakao.linknamu.workspace.controller;

import com.kakao.linknamu._core.security.CustomUserDetails;
import com.kakao.linknamu._core.util.ApiUtils;
import com.kakao.linknamu.workspace.dto.WorkspaceCreateRequestDto;
import com.kakao.linknamu.workspace.dto.WorkspaceUpdateRequestDto;
import com.kakao.linknamu.workspace.service.WorkspaceDeleteService;
import com.kakao.linknamu.workspace.service.WorkspaceReadService;
import com.kakao.linknamu.workspace.service.WorkspaceSaveService;
import com.kakao.linknamu.workspace.service.WorkspaceUpdateService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/workspace")
public class WorkspaceController {
private final WorkspaceReadService workspaceReadService;
private final WorkspaceSaveService workspaceSaveService;
private final WorkspaceUpdateService workspaceUpdateService;
private final WorkspaceDeleteService workspaceDeleteService;

@GetMapping("/list")
public ResponseEntity<?> getWorkspaceList(@AuthenticationPrincipal CustomUserDetails userDetails) {
// 워크스페이스 리스트 조회 서비스 코드
return ResponseEntity.ok(ApiUtils.success(workspaceReadService.getWorkspaceList(userDetails.getUser())));
}

@PostMapping("/create")
public ResponseEntity<?> createWorkspace(@RequestBody @Valid WorkspaceCreateRequestDto requestDto,
@AuthenticationPrincipal CustomUserDetails userDetails) {
// 워크스페이스 생성 서비스 코드
workspaceSaveService.createWorkspace(requestDto.workspaceName(), userDetails.getUser());
return ResponseEntity.ok(ApiUtils.success(null));
}

@PostMapping("/update/{workspace_id}")
public ResponseEntity<?> updateWorkspace(@PathVariable("workspace_id") Long workspaceId,
@RequestBody @Valid WorkspaceUpdateRequestDto requestDto,
@AuthenticationPrincipal CustomUserDetails userDetails) {
// 워크스페이스 수정 서비스 코드
workspaceUpdateService.updateWorkspace(workspaceId, requestDto, userDetails.getUser());
return ResponseEntity.ok(ApiUtils.success(null));
}

@PostMapping("/delete/{workspace_id}")
public ResponseEntity<?> deleteWorkspace(@PathVariable("workspace_id") Long workspaceId,
@AuthenticationPrincipal CustomUserDetails userDetails) {
// 워크스페이스 삭제 서비스 코드
workspaceDeleteService.deleteWorkspace(workspaceId, userDetails.getUser());
return ResponseEntity.ok(ApiUtils.success(null));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.kakao.linknamu.workspace.dto;

import jakarta.validation.constraints.NotBlank;

public record WorkspaceCreateRequestDto(
@NotBlank String workspaceName
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.kakao.linknamu.workspace.dto;

import com.kakao.linknamu.category.entity.Category;
import com.kakao.linknamu.workspace.entity.Workspace;
import lombok.Builder;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public record WorkspaceGetResponseDto(
Long workspaceId,
String workspaceName,
List<CategoryResponseDto> categoryList
) {
record CategoryResponseDto(
Long categoryId,
String categoryName
){}


@Builder
public WorkspaceGetResponseDto {
}


public static WorkspaceGetResponseDto of(Workspace workspace) {
return WorkspaceGetResponseDto.builder()
.workspaceId(workspace.getId())
.workspaceName(workspace.getWorkspaceName())
.categoryList(workspace.getCategorySet().stream()
.sorted(Comparator.comparing(Category::getCategoryId))
.map((c) -> new CategoryResponseDto(c.getCategoryId(), c.getCategoryName()))
.toList())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.kakao.linknamu.workspace.dto;

import jakarta.validation.constraints.NotBlank;

public record WorkspaceUpdateRequestDto(
@NotBlank String workspaceName
) {
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package com.kakao.linknamu.workspace.entity;

import com.kakao.linknamu._core.util.AuditingEntity;
import com.kakao.linknamu.category.entity.Category;
import com.kakao.linknamu.user.entity.User;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;

import java.util.Objects;
import java.util.*;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@ToString(exclude = {"user"})
@ToString(callSuper = true, exclude = {"user", "categoryList"})
@DynamicUpdate
@Table(
name = "workspace_tb",
uniqueConstraints = {
Expand All @@ -24,7 +28,7 @@
)
}
)
public class Workspace {
public class Workspace extends AuditingEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="workspace_id")
private Long id;
Expand All @@ -37,13 +41,20 @@ public class Workspace {
@Column(length = 50, name = "workspace_name", nullable = false)
private String workspaceName;

@OneToMany(mappedBy = "workspace")
private Set<Category> categorySet = new HashSet<>();

@Builder
public Workspace(Long id, User user, String workspaceName) {
this.id = id;
this.user = user;
this.workspaceName = workspaceName;
}

public void renameWorkspace(String workspaceName) {
this.workspaceName = workspaceName;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,9 @@ public interface WorkspaceJPARepository extends JpaRepository<Workspace, Long> {

@Query(value = "select w from Workspace w where w.user.userId=:userId and w.workspaceName =:workspaceName")
Optional<Workspace> findByUserIdAndWorkspaceName(@Param("userId") Long userId, @Param("workspaceName") String workspaceName);

@Query(value = "select distinct w from Workspace w " +
"join fetch w.categorySet c " +
"where w.user.userId =:userId")
List<Workspace> findAllByUserIdFetchJoinCategory(@Param("userId") Long userId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.kakao.linknamu.workspace.service;

import com.kakao.linknamu._core.exception.Exception403;
import com.kakao.linknamu._core.exception.Exception404;
import com.kakao.linknamu.user.entity.User;
import com.kakao.linknamu.workspace.WorkspaceExceptionStatus;
import com.kakao.linknamu.workspace.entity.Workspace;
import com.kakao.linknamu.workspace.repository.WorkspaceJPARepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional
public class WorkspaceDeleteService {
private final WorkspaceJPARepository workspaceJPARepository;

public void deleteWorkspace(Long workspaceId, User user) {
Workspace workspace = workspaceJPARepository.findById(workspaceId).orElseThrow(
() -> new Exception404(WorkspaceExceptionStatus.WORKSPACE_NOT_FOUND));

validationCheck(workspace.getUser().getUserId(), user.getUserId());

workspaceJPARepository.delete(workspace);
}

private void validationCheck(Long writerId, Long requesterId) {
if (!writerId.equals(requesterId)) throw new Exception403(WorkspaceExceptionStatus.WORKSPACE_FORBIDDEN);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.kakao.linknamu.workspace.service;

import com.kakao.linknamu.category.entity.Category;
import com.kakao.linknamu.category.service.CategoryService;
import com.kakao.linknamu.user.entity.User;
import com.kakao.linknamu.workspace.dto.WorkspaceGetResponseDto;
import com.kakao.linknamu.workspace.entity.Workspace;
import com.kakao.linknamu.workspace.repository.WorkspaceJPARepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Comparator;
import java.util.List;
import java.util.TreeMap;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class WorkspaceReadService {
private final WorkspaceJPARepository workspaceJPARepository;

public List<WorkspaceGetResponseDto> getWorkspaceList(User user) {
List<Workspace> workspaceList = workspaceJPARepository.findAllByUserIdFetchJoinCategory(user.getUserId());
if (workspaceList.isEmpty()) return List.of();

return workspaceList.stream()
.map(WorkspaceGetResponseDto::of)
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.kakao.linknamu.workspace.service;

import com.kakao.linknamu._core.exception.Exception403;
import com.kakao.linknamu._core.exception.Exception404;
import com.kakao.linknamu.user.entity.User;
import com.kakao.linknamu.workspace.WorkspaceExceptionStatus;
import com.kakao.linknamu.workspace.dto.WorkspaceUpdateRequestDto;
import com.kakao.linknamu.workspace.entity.Workspace;
import com.kakao.linknamu.workspace.repository.WorkspaceJPARepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional
public class WorkspaceUpdateService {
private final WorkspaceJPARepository workspaceJPARepository;

public void updateWorkspace(Long workspaceId, WorkspaceUpdateRequestDto requestDto, User user) {
Workspace workspace = workspaceJPARepository.findById(workspaceId).orElseThrow(
() -> new Exception404(WorkspaceExceptionStatus.WORKSPACE_NOT_FOUND));

validationCheck(workspace.getUser().getUserId(), user.getUserId());

// 만약 수정하고자하는 이름이 같다면 DB에 Update할 이유가 없다.
if (requestDto.workspaceName().equals(workspace.getWorkspaceName())) return;

workspace.renameWorkspace(requestDto.workspaceName());
}

private void validationCheck(Long writerId, Long requesterId) {
if (!writerId.equals(requesterId)) throw new Exception403(WorkspaceExceptionStatus.WORKSPACE_FORBIDDEN);
}
}

0 comments on commit f54eb54

Please sign in to comment.