Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pet 100 feat : Todo 달성률 조회 API #59

Merged
merged 3 commits into from
Sep 16, 2023
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
Expand Up @@ -21,7 +21,7 @@ public enum Error {
// Todo
TODO_TEAM_NOT_FOUND("Todo 팀을 찾을 수 없습니다.", 3000),
NOT_REGISTER_USER("Todo 팀에 등록되지 않은 사용자입니다.", 3001),

REGISTER_NOT_FOUND("등록된 팀을 찾을 수 없습니다.", 3002),

// Image
FILE_EXTENTION_ERROR("잘못된 형식의 파일입니다.", 4001),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.pawith.todoapplication.dto.response;

import lombok.Getter;

@Getter
public class TodoProgressResponse {

private final Integer progress;

public TodoProgressResponse(Integer progress) {
this.progress = progress;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.pawith.todoapplication.service;

import com.pawith.commonmodule.annotation.ApplicationService;
import com.pawith.todoapplication.dto.response.TodoProgressResponse;
import com.pawith.tododomain.entity.Category;
import com.pawith.tododomain.entity.Register;
import com.pawith.tododomain.service.CategoryQueryService;
import com.pawith.tododomain.service.RegisterQueryService;
import com.pawith.tododomain.service.TodoQueryService;
import com.pawith.tododomain.service.TodoTeamQueryService;
import com.pawith.usermodule.entity.User;
import com.pawith.usermodule.utils.UserUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

@ApplicationService
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class TodoRateGetUseCase {

private final TodoQueryService todoQueryService;
private final TodoTeamQueryService todoTeamQueryService;
private final RegisterQueryService registerQueryService;
private final CategoryQueryService categoryQueryService;

public TodoProgressResponse getTodoProgress(Long todoTeamId) {
if(todoTeamId == null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이렇게 null값을 받는것보다는 가입된 패밀리 id랑 이름만 반환하는 api 제공해주고
그 다음에 사용자가 선택하면 null값이 안들어올것같은데 어떻게 생각해?

final User user = UserUtils.getAccessUser();
final Register register = registerQueryService.findRecentRegisterByUserId(user.getId());
todoTeamQueryService.findTodoTeamById(register.getTodoTeam().getId());
}
List<Category> categoryList = categoryQueryService.findCategoryListByTodoTeamId(todoTeamId);
Long totalTodoCount = categoryList.stream()
.mapToLong(category -> todoQueryService.countTodoByCategoryIdAndCreatedAt(category.getId(), LocalDateTime.now()))
.sum();
Long doneTodoCount = categoryList.stream()
.mapToLong(category -> todoQueryService.countTodoByCategoryIdAndCreatedAtAndStatus(category.getId(), LocalDateTime.now(), "COMPLETE"))
.sum();
int result = (int)((double)doneTodoCount/totalTodoCount*100);
return new TodoProgressResponse(result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.pawith.tododomain.exception;

import com.pawith.commonmodule.exception.Error;

public class RegisterNotFoundException extends TodoException{
public RegisterNotFoundException(Error error) {
super(error);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
import com.pawith.tododomain.entity.Category;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface CategoryRepository extends JpaRepository<Category, Long> {
List<Category> findAllByTodoTeamId(Long todoTeamId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ public interface RegisterRepository extends JpaRepository<Register, Long> {
Slice<Register> findAllByUserId(Long userId, Pageable pageable);

Optional<Register> findByTodoTeamIdAndUserId(Long todoTeamId, Long userId);

Optional<Register> findTopByUserIdOrderByCreatedAtDesc(Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,10 @@
import com.pawith.tododomain.entity.Todo;
import org.springframework.data.jpa.repository.JpaRepository;

import java.time.LocalDateTime;

public interface TodoRepository extends JpaRepository<Todo, Long> {
Long countByCategoryIdAndCreatedAt(Long categoryId, LocalDateTime createdAt);

Long countByCategoryIdAndCreatedAtAndTodoStatus(Long categoryId, LocalDateTime createdAt, String status);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.pawith.tododomain.service;

import com.pawith.commonmodule.annotation.DomainService;
import com.pawith.tododomain.entity.Category;
import com.pawith.tododomain.repository.CategoryRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@DomainService
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class CategoryQueryService {

private final CategoryRepository categoryRepository;

public List<Category> findCategoryListByTodoTeamId(Long todoTeamId) {
return categoryRepository.findAllByTodoTeamId(todoTeamId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.pawith.commonmodule.exception.Error;
import com.pawith.tododomain.entity.Register;
import com.pawith.tododomain.exception.NotRegisterUserException;
import com.pawith.tododomain.exception.RegisterNotFoundException;
import com.pawith.tododomain.repository.RegisterRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
Expand All @@ -24,4 +25,9 @@ public Register findRegisterByTodoTeamIdAndUserId(Long todoTeamId, Long userId)
return registerRepository.findByTodoTeamIdAndUserId(todoTeamId, userId)
.orElseThrow(() -> new NotRegisterUserException(Error.NOT_REGISTER_USER));
}

public Register findRecentRegisterByUserId(Long userId) {
return registerRepository.findTopByUserIdOrderByCreatedAtDesc(userId)
.orElseThrow(() -> new RegisterNotFoundException(Error.REGISTER_NOT_FOUND));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 (() -> new NotRegisterUserException(Error.NOT_REGISTER_USER)) 로 통일할 수 있을것같은데 어떻게 생각해?

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.pawith.tododomain.service;

import com.pawith.commonmodule.annotation.DomainService;
import com.pawith.tododomain.repository.TodoRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

@DomainService
@RequiredArgsConstructor
@Transactional
public class TodoQueryService {

private final TodoRepository todoRepository;

public Long countTodoByCategoryIdAndCreatedAt(Long categoryId, LocalDateTime createdAt) {
return todoRepository.countByCategoryIdAndCreatedAt(categoryId, createdAt);
}

public Long countTodoByCategoryIdAndCreatedAtAndStatus(Long categoryId, LocalDateTime createdAt, String status) {
return todoRepository.countByCategoryIdAndCreatedAtAndTodoStatus(categoryId, createdAt, status);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,9 @@ operation::todo-team-controller-test/get-todo-teams[snippets='http-request,reque

operation::register-controller-test/unregister-todo-team[snippets='http-request,path-parameters,request-headers,http-response']


[[Todo-API-Todo-달성률]]
=== Todo 달성률 (홈 화면)

operation::todo-home-controller-test/get-todo-progress[snippets='http-request,path-parameters,request-headers,http-response']

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.pawith.todopresentation;

import com.pawith.todoapplication.dto.response.TodoProgressResponse;
import com.pawith.todoapplication.service.TodoRateGetUseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/todo/home")
public class TodoHomeController {

private final TodoRateGetUseCase todoRateGetUseCase;

@GetMapping("/progress/{teamId}")
public TodoProgressResponse getTodoProgress(@PathVariable Long teamId) { return todoRateGetUseCase.getTodoProgress(teamId);}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.pawith.todopresentation;

import com.navercorp.fixturemonkey.FixtureMonkey;
import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector;
import com.pawith.commonmodule.BaseRestDocsTest;
import com.pawith.todoapplication.dto.response.TodoProgressResponse;
import com.pawith.todoapplication.service.TodoRateGetUseCase;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;

import static org.mockito.BDDMockito.given;
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@Slf4j
@WebMvcTest(TodoHomeController.class)
@DisplayName("RegisterController 테스트")
public class TodoHomeControllerTest extends BaseRestDocsTest {

@MockBean
private TodoRateGetUseCase todoRateGetUseCase;

private static final String TODO_HOME_REQUEST_URL = "/todo/home";

@Test
@DisplayName("Todo 달성률을 가져오는 테스트")
void getTodoProgress() throws Exception{
//given
final TodoProgressResponse testTodoProgress = getFixtureMonkey().giveMeOne(TodoProgressResponse.class);
final Long testTeamId = getFixtureMonkey().giveMeOne(Long.class);
given(todoRateGetUseCase.getTodoProgress(testTeamId)).willReturn(testTodoProgress);
MockHttpServletRequestBuilder request = get(TODO_HOME_REQUEST_URL + "/progress/{teamId}", testTeamId)
.header("Authorization", "Bearer accessToken");
//when
ResultActions result = mvc.perform(request);
//then
result.andExpect(status().isOk())
.andDo(resultHandler.document(
requestHeaders(
headerWithName("Authorization").description("access 토큰")
),
pathParameters(
parameterWithName("teamId").description("TodoTeam의 Id. 홈 화면 처음 들어올때는 null 상태로 보내야함")
),
responseFields(
fieldWithPath("progress").description("달성률")
)
));
}

private FixtureMonkey getFixtureMonkey() {
return FixtureMonkey.builder()
.defaultNotNull(true)
.objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)
.build();
}
}