Skip to content

Commit 382a2ec

Browse files
authored
Merge pull request #122 from slid-todo/feature/goal-detail
feat: 종료된 할일 포함해 모든 목표, 할일, 인증 가져오기
2 parents b10c30a + 0550834 commit 382a2ec

File tree

10 files changed

+127
-34
lines changed

10 files changed

+127
-34
lines changed

src/main/java/com/codeit/todo/repository/TodoRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ public interface TodoRepository extends JpaRepository<Todo, Integer> {
2424

2525
@Query("select t from Todo t where t.goal.goalId = :goalId and :today between t.startDate and t.endDate")
2626
List<Todo> findTodosByGoalIdBetweenDates(@Param("goalId") int goalId, @Param("today") LocalDate today);
27+
28+
List<Todo> findByGoal_GoalId(int goalId);
2729
}

src/main/java/com/codeit/todo/service/goal/GoalService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package com.codeit.todo.service.goal;
22

3+
import com.codeit.todo.web.dto.request.todo.ReadTodoCompleteWithGoalRequest;
34
import com.codeit.todo.web.dto.response.goal.DeleteGoalResponse;
45
import com.codeit.todo.web.dto.request.goal.UpdateGoalRequest;
56
import com.codeit.todo.web.dto.request.goal.CreateGoalRequest;
67
import com.codeit.todo.web.dto.response.goal.CreateGoalResponse;
78
import com.codeit.todo.web.dto.response.goal.ReadGoalsResponse;
89
import com.codeit.todo.web.dto.response.goal.UpdateGoalResponse;
10+
import com.codeit.todo.web.dto.response.todo.ReadTodosWithGoalsResponse;
11+
import org.springframework.data.domain.Slice;
912

1013
import java.util.List;
1114

@@ -20,4 +23,5 @@ public interface GoalService {
2023
DeleteGoalResponse deleteGoal(int userId, int goalId);
2124

2225

26+
Slice<ReadTodosWithGoalsResponse> findAllGoals(int userId, ReadTodoCompleteWithGoalRequest request);
2327
}

src/main/java/com/codeit/todo/service/goal/impl/GoalServiceImpl.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,34 @@
44
import com.codeit.todo.common.exception.goal.GoalNotFoundException;
55
import com.codeit.todo.common.exception.user.UserNotFoundException;
66
import com.codeit.todo.domain.Goal;
7+
import com.codeit.todo.domain.Todo;
78
import com.codeit.todo.domain.User;
9+
import com.codeit.todo.repository.CompleteRepository;
810
import com.codeit.todo.repository.GoalRepository;
11+
import com.codeit.todo.repository.TodoRepository;
912
import com.codeit.todo.repository.UserRepository;
1013
import com.codeit.todo.service.goal.GoalService;
14+
import com.codeit.todo.service.todo.impl.TodoServiceImpl;
15+
import com.codeit.todo.web.dto.request.todo.ReadTodoCompleteWithGoalRequest;
1116
import com.codeit.todo.web.dto.response.goal.DeleteGoalResponse;
1217
import com.codeit.todo.web.dto.request.goal.UpdateGoalRequest;
1318
import com.codeit.todo.web.dto.request.goal.CreateGoalRequest;
1419
import com.codeit.todo.web.dto.response.goal.CreateGoalResponse;
1520
import com.codeit.todo.web.dto.response.goal.ReadGoalsResponse;
1621
import com.codeit.todo.web.dto.response.goal.UpdateGoalResponse;
22+
import com.codeit.todo.web.dto.response.todo.ReadTodosResponse;
23+
import com.codeit.todo.web.dto.response.todo.ReadTodosWithGoalsResponse;
1724
import lombok.RequiredArgsConstructor;
25+
import org.springframework.data.domain.PageRequest;
26+
import org.springframework.data.domain.Pageable;
27+
import org.springframework.data.domain.Slice;
28+
import org.springframework.data.domain.SliceImpl;
1829
import org.springframework.stereotype.Service;
1930
import org.springframework.transaction.annotation.Transactional;
2031

32+
import java.util.ArrayList;
2133
import java.util.List;
34+
import java.util.Objects;
2235
import java.util.Random;
2336
import java.util.stream.Collectors;
2437

@@ -28,6 +41,8 @@ public class GoalServiceImpl implements GoalService {
2841

2942
private final UserRepository userRepository;
3043
private final GoalRepository goalRepository;
44+
private final TodoRepository todoRepository;
45+
private final TodoServiceImpl todoServiceImpl;
3146

3247

3348
@Override
@@ -67,6 +82,7 @@ public CreateGoalResponse saveGoal(int userId, CreateGoalRequest request) {
6782
return CreateGoalResponse.fromEntity(savedGoal);
6883
}
6984

85+
@Transactional
7086
@Override
7187
public UpdateGoalResponse updateGoal(int userId, int goalId, UpdateGoalRequest request) {
7288
Goal goal = goalRepository.findByGoalIdAndUser_UserId(goalId, userId)
@@ -86,4 +102,50 @@ public DeleteGoalResponse deleteGoal(int userId, int goalId) {
86102
goalRepository.delete(goal);
87103
return new DeleteGoalResponse(goalId);
88104
}
105+
106+
@Transactional(readOnly = true)
107+
@Override
108+
public Slice<ReadTodosWithGoalsResponse> findAllGoals(int userId, ReadTodoCompleteWithGoalRequest request) {
109+
int pageSize = request.size();
110+
Pageable pageable = PageRequest.of(0, pageSize);
111+
112+
Slice<Goal> goals = todoServiceImpl.getGoalsPagination(userId, request, pageable);
113+
114+
List<ReadTodosWithGoalsResponse> goalsResponses = goals.stream()
115+
.map(goal -> {
116+
List<Todo> todos = todoRepository.findByGoal_GoalId(goal.getGoalId());
117+
118+
List<ReadTodosResponse> todosResponses = todoServiceImpl.makeTodosResponses(todos);
119+
120+
double goalProgress = todoServiceImpl.calculateGoalProgress(todos);
121+
122+
return ReadTodosWithGoalsResponse.from(goal, todosResponses, goalProgress);
123+
}).toList();
124+
125+
List<ReadTodosWithGoalsResponse> sortedGoalsResponses = sortAllGoals(goalsResponses);
126+
127+
return new SliceImpl<>(sortedGoalsResponses, pageable, goals.hasNext());
128+
}
129+
130+
private List<ReadTodosWithGoalsResponse> sortAllGoals(List<ReadTodosWithGoalsResponse> goalsResponses){
131+
List<ReadTodosWithGoalsResponse> sortedGoalsResponses = new ArrayList<>();
132+
133+
//todo status "진행"
134+
List<ReadTodosWithGoalsResponse> goalsWithPriority = goalsResponses.stream()
135+
.filter( goalResponse -> goalResponse.todos().stream()
136+
.anyMatch(todo -> "진행".equals(todo.todoStatus())))
137+
.toList();
138+
139+
//todo status not "진행"
140+
List<ReadTodosWithGoalsResponse> goalsWithoutPriority = goalsResponses.stream()
141+
.filter( goalResponse -> goalResponse.todos().stream()
142+
.noneMatch(todo -> "진행".equals(todo.todoStatus())))
143+
.toList();
144+
//combine two lists
145+
sortedGoalsResponses.addAll(goalsWithPriority);
146+
sortedGoalsResponses.addAll(goalsWithoutPriority);
147+
148+
return sortedGoalsResponses;
149+
150+
}
89151
}

src/main/java/com/codeit/todo/service/todo/TodoService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public interface TodoService {
1212

1313
CreateTodoResponse saveTodo(int userId, CreateTodoRequest request);
1414

15-
Slice<ReadTodosWithGoalsResponse> findTodoListWithGoals(int userId, ReadDashBoardTodoWithGoalRequest request);
15+
Slice<ReadTodosWithGoalsResponse> findTodoListWithGoals(int userId, ReadTodoCompleteWithGoalRequest request);
1616

1717
Slice<ReadTodoWithGoalResponse> findTodoListWithGoal(int userId, int goalId, ReadTodoWithGoalRequest request);
1818

src/main/java/com/codeit/todo/service/todo/impl/TodoServiceImpl.java

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -106,31 +106,17 @@ public CreateTodoResponse saveTodo(int userId, CreateTodoRequest request) {
106106

107107
@Transactional(readOnly = true)
108108
@Override
109-
public Slice<ReadTodosWithGoalsResponse> findTodoListWithGoals(int userId, @Valid ReadDashBoardTodoWithGoalRequest request) {
109+
public Slice<ReadTodosWithGoalsResponse> findTodoListWithGoals(int userId, @Valid ReadTodoCompleteWithGoalRequest request) {
110110
int pageSize = request.size();
111111
Pageable pageable = PageRequest.of(0, pageSize);
112112

113-
Slice<Goal> goals;
114-
if (Objects.isNull(request.lastGoalId()) || request.lastGoalId() <= 0) {
115-
goals = goalRepository.findByUser_UserId(userId, pageable);
116-
} else {
117-
goals = goalRepository.findByGoalIdAndUser_UserId(request.lastGoalId(), userId, pageable);
118-
}
113+
Slice<Goal> goals = getGoalsPagination(userId, request, pageable);
119114

120115
List<ReadTodosWithGoalsResponse> responses = goals.getContent().stream()
121116
.map(goal -> {
122117
List<Todo> todos = todoRepository.findTodosByGoalIdBetweenDates(goal.getGoalId(), LocalDate.now());
123118

124-
List<ReadTodosResponse> todosResponses = todos.stream()
125-
.map(todo -> {
126-
List<Complete> completes = completeRepository.findByTodo_TodoId(todo.getTodoId());
127-
128-
List<ReadCompleteResponse> completeResponses = completes.stream()
129-
.map(ReadCompleteResponse::from)
130-
.toList();
131-
132-
return ReadTodosResponse.from(todo, completeResponses);
133-
}).toList();
119+
List<ReadTodosResponse> todosResponses = makeTodosResponses(todos);
134120

135121
double goalProgress = calculateGoalProgress(todos);
136122

@@ -268,7 +254,7 @@ private List<ReadTodosResponse> getTodoResponses(Slice<Todo> todos) {
268254
}).toList();
269255
}
270256

271-
private double calculateGoalProgress(List<Todo> todos) {
257+
public double calculateGoalProgress(List<Todo> todos) {
272258
long totalCompletes = 0;
273259
long completedCompletes = 0;
274260

@@ -282,4 +268,30 @@ private double calculateGoalProgress(List<Todo> todos) {
282268

283269
return totalCompletes > 0 ? (completedCompletes / (double) totalCompletes) * 100 : 0;
284270
}
271+
272+
public List<ReadTodosResponse> makeTodosResponses(List<Todo> todos){
273+
List<ReadTodosResponse> todosResponses = todos.stream()
274+
.map(todo -> {
275+
List<Complete> completes = completeRepository.findByTodo_TodoId(todo.getTodoId());
276+
277+
List<ReadCompleteResponse> completeResponses = completes.stream()
278+
.map(ReadCompleteResponse::from)
279+
.toList();
280+
281+
return ReadTodosResponse.from(todo, completeResponses);
282+
}).toList();
283+
284+
return todosResponses;
285+
}
286+
287+
public Slice<Goal> getGoalsPagination(int userId, ReadTodoCompleteWithGoalRequest request, Pageable pageable){
288+
Slice<Goal> goals;
289+
if (Objects.isNull(request.lastGoalId()) || request.lastGoalId() <= 0) {
290+
goals = goalRepository.findByUser_UserId(userId, pageable);
291+
} else {
292+
goals = goalRepository.findByGoalIdAndUser_UserId(request.lastGoalId(), userId, pageable);
293+
}
294+
295+
return goals;
296+
}
285297
}

src/main/java/com/codeit/todo/service/user/impl/UserServiceImpl.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.springframework.security.core.context.SecurityContextHolder;
2323
import org.springframework.security.crypto.password.PasswordEncoder;
2424
import org.springframework.stereotype.Service;
25+
import org.springframework.transaction.annotation.Transactional;
2526

2627
import java.security.SignatureException;
2728
import java.time.LocalDateTime;
@@ -40,6 +41,7 @@ public class UserServiceImpl implements UserService {
4041

4142
private static final int BAD_REQUEST = 400;
4243

44+
@Transactional
4345
@Override
4446
public SignUpResponse signUpUser(SignUpRequest request) {
4547
//기존에 있는 이메일인지 확인
@@ -94,6 +96,7 @@ public ReadUserResponse findUserInfo(int userId) {
9496
return ReadUserResponse.from(user);
9597
}
9698

99+
@Transactional
97100
@Override
98101
public UpdatePictureResponse updateProfilePicture(int userId, UpdatePictureRequest pictureRequest) {
99102
User user = getUser(userId);

src/main/java/com/codeit/todo/web/controller/AuthController.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,15 @@
66
import com.codeit.todo.web.dto.request.auth.LoginRequest;
77
import com.codeit.todo.web.dto.request.auth.SignUpRequest;
88
import com.codeit.todo.web.dto.request.auth.UpdatePictureRequest;
9-
import com.codeit.todo.web.dto.request.complete.UpdateCompleteRequest;
109
import com.codeit.todo.web.dto.response.Response;
11-
import com.codeit.todo.web.dto.response.auth.ReadUserResponse;
1210
import com.codeit.todo.web.dto.response.auth.UpdatePictureResponse;
13-
import com.codeit.todo.web.dto.response.complete.UpdateCompleteResponse;
1411
import io.swagger.v3.oas.annotations.Operation;
1512
import io.swagger.v3.oas.annotations.responses.ApiResponse;
1613
import io.swagger.v3.oas.annotations.responses.ApiResponses;
17-
import jakarta.servlet.http.Cookie;
1814
import jakarta.servlet.http.HttpServletResponse;
1915
import lombok.RequiredArgsConstructor;
20-
import org.springframework.http.HttpHeaders;
21-
import org.springframework.http.ResponseCookie;
2216
import org.springframework.http.ResponseEntity;
2317
import org.springframework.security.core.annotation.AuthenticationPrincipal;
24-
import org.springframework.transaction.annotation.Transactional;
2518
import org.springframework.web.bind.annotation.*;
2619

2720
@RestController
@@ -33,7 +26,7 @@ public class AuthController {
3326
private final JwtTokenProvider jwtTokenProvider;
3427

3528

36-
@Transactional
29+
3730
@Operation(summary = "회원가입", description = "이름, 이메일, 비밀번호로 회원가입")
3831
@ApiResponses(value = {
3932
@ApiResponse(responseCode = "200", description = "회원가입 성공")
@@ -66,7 +59,7 @@ public Response getUserInfo(@AuthenticationPrincipal CustomUserDetails customUse
6659
return Response.ok( userService.findUserInfo(userId) );
6760
}
6861

69-
@Transactional
62+
7063
@Operation(
7164
summary = "프로필 사진 수정",
7265
description = "유저가 원하는 사진을 골라 프로필 사진을 수정"

src/main/java/com/codeit/todo/web/controller/GoalController.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,20 @@
44
import com.codeit.todo.service.goal.GoalService;
55
import com.codeit.todo.web.dto.request.goal.CreateGoalRequest;
66
import com.codeit.todo.web.dto.request.goal.UpdateGoalRequest;
7+
import com.codeit.todo.web.dto.request.todo.ReadTodoCompleteWithGoalRequest;
78
import com.codeit.todo.web.dto.response.Response;
89
import com.codeit.todo.web.dto.response.goal.DeleteGoalResponse;
910
import com.codeit.todo.web.dto.response.goal.CreateGoalResponse;
1011
import com.codeit.todo.web.dto.response.goal.ReadGoalsResponse;
1112
import com.codeit.todo.web.dto.response.goal.UpdateGoalResponse;
13+
import com.codeit.todo.web.dto.response.todo.ReadTodosWithGoalsResponse;
1214
import io.swagger.v3.oas.annotations.Operation;
1315
import io.swagger.v3.oas.annotations.responses.ApiResponse;
1416
import io.swagger.v3.oas.annotations.responses.ApiResponses;
1517
import jakarta.validation.Valid;
1618
import lombok.RequiredArgsConstructor;
19+
import org.springframework.data.domain.Slice;
1720
import org.springframework.security.core.annotation.AuthenticationPrincipal;
18-
import org.springframework.transaction.annotation.Transactional;
1921
import org.springframework.web.bind.annotation.*;
2022

2123
import java.util.List;
@@ -52,7 +54,7 @@ public Response<CreateGoalResponse> createGoal(
5254
}
5355

5456

55-
@Transactional
57+
5658
@Operation(summary = "목표 수정",
5759
description = "기존 목표 제목 수정 API, 수정된 목표의 ID 반환")
5860
@ApiResponses(value = {
@@ -68,7 +70,7 @@ public Response<UpdateGoalResponse> updateGoal(
6870
return Response.ok(goalService.updateGoal(userId, goalId, request));
6971
}
7072

71-
@Transactional
73+
7274
@Operation(summary = "목표 삭제",
7375
description = "목표 삭제 API, 삭제된 목표의 ID 반환")
7476
@ApiResponses(value = {
@@ -83,4 +85,20 @@ public Response<DeleteGoalResponse> deleteGoal(
8385
return Response.ok(goalService.deleteGoal(userId, goalId));
8486
}
8587

88+
@Operation(
89+
summary = "목표와 할 일, 인증 상세조회",
90+
description = "종료된 할 일 또는 인증도 포함해서 목표, 할 일, 인증을 모두 불러옵니다."
91+
)
92+
@ApiResponses(value = {
93+
@ApiResponse(responseCode = "200", description = "조회 성공")
94+
})
95+
@GetMapping("/all")
96+
public Response<Slice<ReadTodosWithGoalsResponse>> getGoalsDetail(
97+
@AuthenticationPrincipal CustomUserDetails userDetails,
98+
@Valid @ModelAttribute ReadTodoCompleteWithGoalRequest request
99+
) {
100+
int userId = userDetails.getUserId();
101+
return Response.ok(goalService.findAllGoals(userId, request));
102+
}
103+
86104
}

src/main/java/com/codeit/todo/web/controller/TodoController.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import com.codeit.todo.service.todo.TodoService;
55
import com.codeit.todo.web.dto.request.todo.*;
66
import com.codeit.todo.web.dto.response.Response;
7-
import com.codeit.todo.web.dto.response.goal.ReadGoalsResponse;
87
import com.codeit.todo.web.dto.response.todo.*;
98
import io.swagger.v3.oas.annotations.Operation;
109
import io.swagger.v3.oas.annotations.responses.ApiResponse;
@@ -49,7 +48,7 @@ public Response<Slice<ReadTodosResponse>> getTodoList(
4948
})
5049
@GetMapping("/goals")
5150
public Response<Slice<ReadTodosWithGoalsResponse>> getTodoWithGoalList(
52-
@Valid @ModelAttribute ReadDashBoardTodoWithGoalRequest request,
51+
@Valid @ModelAttribute ReadTodoCompleteWithGoalRequest request,
5352
@AuthenticationPrincipal CustomUserDetails userDetails
5453
) {
5554
int userId = userDetails.getUserId();

src/main/java/com/codeit/todo/web/dto/request/todo/ReadDashBoardTodoWithGoalRequest.java renamed to src/main/java/com/codeit/todo/web/dto/request/todo/ReadTodoCompleteWithGoalRequest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import jakarta.validation.constraints.Min;
44

5-
public record ReadDashBoardTodoWithGoalRequest(
5+
public record ReadTodoCompleteWithGoalRequest(
66
Integer lastGoalId,
77
@Min(3)
88
int size

0 commit comments

Comments
 (0)