Skip to content

Commit 391caf8

Browse files
authored
Merge pull request #116 from slid-todo/feature/todo-goals
feat : 목표별 할일 조회 시, 목표 기반으로 무한스크롤 하도록 변경
2 parents c3237e9 + 7731eaf commit 391caf8

File tree

9 files changed

+95
-41
lines changed

9 files changed

+95
-41
lines changed

.github/workflows/cd.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ jobs:
1313
- name: Checkout repository
1414
uses: actions/checkout@v2
1515

16+
- name: Set up JDK 17
17+
uses: actions/setup-java@v4
18+
with:
19+
java-version: '17'
20+
distribution: 'temurin'
21+
22+
- name: Setup Gradle
23+
uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582
24+
1625
- name: Add SSH host key
1726
run: |
1827
mkdir -p ~/.ssh
@@ -24,6 +33,17 @@ jobs:
2433
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/private_key.pem
2534
chmod 600 ~/.ssh/private_key.pem
2635
36+
- name: Build with Gradle
37+
run: ./gradlew build -x test
38+
39+
- name: Upload JAR to Remote Server
40+
run: |
41+
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/private_key.pem
42+
chmod 600 ~/.ssh/private_key.pem
43+
scp -i ~/.ssh/private_key.pem build/libs/todo-0.0.1-SNAPSHOT.jar ${{ secrets.USER }}@${{ secrets.HOST }}:${{ secrets.APP_DIR }}
44+
env:
45+
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
46+
2747
- name: Deploy to Remote Server
2848
run: |
2949
ssh -i ~/.ssh/private_key.pem ${{ secrets.USER }}@${{ secrets.HOST }} '

.github/workflows/ci.yml

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,4 @@ jobs:
2626
run: ./gradlew test
2727

2828
- name: Build with Gradle
29-
run: ./gradlew build -x test
30-
31-
- name: Add SSH host key
32-
run: |
33-
mkdir -p ~/.ssh
34-
ssh-keyscan -H ${{ secrets.HOST }} >> ~/.ssh/known_hosts
35-
chmod 644 ~/.ssh/known_hosts
36-
37-
- name: Upload JAR to Remote Server
38-
run: |
39-
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/private_key.pem
40-
chmod 600 ~/.ssh/private_key.pem
41-
scp -i ~/.ssh/private_key.pem build/libs/todo-0.0.1-SNAPSHOT.jar ${{ secrets.USER }}@${{ secrets.HOST }}:${{ secrets.APP_DIR }}
42-
env:
43-
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
29+
run: ./gradlew build -x test

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.codeit.todo.repository;
22

33
import com.codeit.todo.domain.Goal;
4+
import org.springframework.data.domain.Pageable;
5+
import org.springframework.data.domain.Slice;
46
import org.springframework.data.jpa.repository.JpaRepository;
57

68
import java.util.List;
@@ -10,4 +12,8 @@ public interface GoalRepository extends JpaRepository<Goal, Integer> {
1012
List<Goal> findByUser_UserId(int userId);
1113

1214
Optional<Goal> findByGoalIdAndUser_UserId(int goalId, int userId);
15+
16+
Slice<Goal> findByUser_UserId(int userId, Pageable pageable);
17+
18+
Slice<Goal> findByGoalIdAndUser_UserId(Integer goalId, int userId, Pageable pageable);
1319
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,8 @@ public interface TodoRepository extends JpaRepository<Todo, Integer> {
2020
Slice<Todo> findByGoal_GoalIdAndTodoIdLessThanOrderByTodoIdDesc(int goalId, Integer lastTodoId, Pageable pageable);
2121

2222
@Query("select t from Todo t where t.goal.goalId in :goalIds and :today between t.startDate and t.endDate")
23-
List<Todo> findTodosBetweenDates(@Param("goalIds") List<Integer> goalIds, @Param("today") LocalDate today);
23+
List<Todo> findTodosByGoalIdsBetweenDates(@Param("goalIds") List<Integer> goalIds, @Param("today") LocalDate today);
24+
25+
@Query("select t from Todo t where t.goal.goalId = :goalId and :today between t.startDate and t.endDate")
26+
List<Todo> findTodosByGoalIdBetweenDates(@Param("goalId") int goalId, @Param("today") LocalDate today);
2427
}

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package com.codeit.todo.service.todo;
22

3-
import com.codeit.todo.web.dto.request.todo.CreateTodoRequest;
4-
import com.codeit.todo.web.dto.request.todo.ReadTodoRequest;
5-
import com.codeit.todo.web.dto.request.todo.ReadTodoWithGoalRequest;
6-
import com.codeit.todo.web.dto.request.todo.UpdateTodoRequest;
3+
import com.codeit.todo.web.dto.request.todo.*;
74
import com.codeit.todo.web.dto.response.todo.*;
85
import org.springframework.data.domain.Slice;
96

@@ -15,7 +12,7 @@ public interface TodoService {
1512

1613
CreateTodoResponse saveTodo(int userId, CreateTodoRequest request);
1714

18-
List<ReadTodosWithGoalsResponse> findTodoListWithGoals(int userId, ReadTodoWithGoalRequest request);
15+
Slice<ReadTodosWithGoalsResponse> findTodoListWithGoals(int userId, ReadDashBoardTodoWithGoalRequest request);
1916

2017
Slice<ReadTodoWithGoalResponse> findTodoListWithGoal(int userId, int goalId, ReadTodoWithGoalRequest request);
2118

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

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,10 @@
1111
import com.codeit.todo.repository.TodoRepository;
1212
import com.codeit.todo.service.storage.StorageService;
1313
import com.codeit.todo.service.todo.TodoService;
14-
import com.codeit.todo.web.dto.request.todo.CreateTodoRequest;
15-
import com.codeit.todo.web.dto.request.todo.ReadTodoRequest;
16-
import com.codeit.todo.web.dto.request.todo.ReadTodoWithGoalRequest;
17-
import com.codeit.todo.web.dto.request.todo.UpdateTodoRequest;
14+
import com.codeit.todo.web.dto.request.todo.*;
1815
import com.codeit.todo.web.dto.response.complete.ReadCompleteResponse;
1916
import com.codeit.todo.web.dto.response.todo.*;
17+
import jakarta.validation.Valid;
2018
import lombok.RequiredArgsConstructor;
2119
import lombok.extern.slf4j.Slf4j;
2220
import org.springframework.data.domain.PageRequest;
@@ -108,19 +106,39 @@ public CreateTodoResponse saveTodo(int userId, CreateTodoRequest request) {
108106

109107
@Transactional(readOnly = true)
110108
@Override
111-
public List<ReadTodosWithGoalsResponse> findTodoListWithGoals(int userId, ReadTodoWithGoalRequest request) {
112-
List<Goal> goals = goalRepository.findByUser_UserId(userId);
109+
public Slice<ReadTodosWithGoalsResponse> findTodoListWithGoals(int userId, @Valid ReadDashBoardTodoWithGoalRequest request) {
110+
int pageSize = request.size();
111+
Pageable pageable = PageRequest.of(0, pageSize);
113112

114-
return goals.stream()
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+
}
119+
120+
List<ReadTodosWithGoalsResponse> responses = goals.getContent().stream()
115121
.map(goal -> {
116-
Pageable pageable = PageRequest.of(0, request.size());
117-
Slice<Todo> todos = todoRepository.findByGoal_GoalIdOrderByTodoIdDesc(goal.getGoalId(), pageable);
122+
List<Todo> todos = todoRepository.findTodosByGoalIdBetweenDates(goal.getGoalId(), LocalDate.now());
118123

119-
List<ReadTodosResponse> responses = getTodoResponses(todos);
124+
List<ReadTodosResponse> todosResponses = todos.stream()
125+
.map(todo -> {
126+
List<Complete> completes = completeRepository.findByTodo_TodoId(todo.getTodoId());
120127

121-
return ReadTodosWithGoalsResponse.from(goal, responses);
128+
List<ReadCompleteResponse> completeResponses = completes.stream()
129+
.map(ReadCompleteResponse::from)
130+
.toList();
122131

123-
}).toList();
132+
return ReadTodosResponse.from(todo, completeResponses);
133+
}).toList();
134+
135+
double goalProgress = calculateGoalProgress(todos);
136+
137+
return ReadTodosWithGoalsResponse.from(goal, todosResponses, goalProgress);
138+
})
139+
.toList();
140+
141+
return new SliceImpl<>(responses, pageable, goals.hasNext());
124142
}
125143

126144
@Transactional(readOnly = true)
@@ -234,7 +252,7 @@ private List<Todo> getTodayTodos(LocalDate today, int userId) {
234252
.map(Goal::getGoalId)
235253
.toList();
236254

237-
return todoRepository.findTodosBetweenDates(goalIds, today);
255+
return todoRepository.findTodosByGoalIdsBetweenDates(goalIds, today);
238256
}
239257

240258
private List<ReadTodosResponse> getTodoResponses(Slice<Todo> todos) {
@@ -249,4 +267,19 @@ private List<ReadTodosResponse> getTodoResponses(Slice<Todo> todos) {
249267
return ReadTodosResponse.from(todo, completeResponses);
250268
}).toList();
251269
}
270+
271+
private double calculateGoalProgress(List<Todo> todos) {
272+
long totalCompletes = 0;
273+
long completedCompletes = 0;
274+
275+
for (Todo todo : todos) {
276+
List<Complete> completes = completeRepository.findByTodo_TodoId(todo.getTodoId());
277+
totalCompletes += completes.size();
278+
completedCompletes += completes.stream()
279+
.filter(complete -> COMPLETE.equals(complete.getCompleteStatus()))
280+
.count();
281+
}
282+
283+
return totalCompletes > 0 ? (completedCompletes / (double) totalCompletes) * 100 : 0;
284+
}
252285
}

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@
22

33
import com.codeit.todo.repository.CustomUserDetails;
44
import com.codeit.todo.service.todo.TodoService;
5-
import com.codeit.todo.web.dto.request.todo.CreateTodoRequest;
6-
import com.codeit.todo.web.dto.request.todo.ReadTodoRequest;
7-
import com.codeit.todo.web.dto.request.todo.ReadTodoWithGoalRequest;
8-
import com.codeit.todo.web.dto.request.todo.UpdateTodoRequest;
5+
import com.codeit.todo.web.dto.request.todo.*;
96
import com.codeit.todo.web.dto.response.Response;
107
import com.codeit.todo.web.dto.response.goal.ReadGoalsResponse;
118
import com.codeit.todo.web.dto.response.todo.*;
@@ -51,8 +48,8 @@ public Response<Slice<ReadTodosResponse>> getTodoList(
5148
@ApiResponse(responseCode = "200", description = "조회 성공")
5249
})
5350
@GetMapping("/goals")
54-
public Response<List<ReadTodosWithGoalsResponse>> getTodoWithGoalList(
55-
@Valid @ModelAttribute ReadTodoWithGoalRequest request,
51+
public Response<Slice<ReadTodosWithGoalsResponse>> getTodoWithGoalList(
52+
@Valid @ModelAttribute ReadDashBoardTodoWithGoalRequest request,
5653
@AuthenticationPrincipal CustomUserDetails userDetails
5754
) {
5855
int userId = userDetails.getUserId();
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.codeit.todo.web.dto.request.todo;
2+
3+
import jakarta.validation.constraints.Min;
4+
5+
public record ReadDashBoardTodoWithGoalRequest(
6+
Integer lastGoalId,
7+
@Min(3)
8+
int size
9+
) {
10+
}

src/main/java/com/codeit/todo/web/dto/response/todo/ReadTodosWithGoalsResponse.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ public record ReadTodosWithGoalsResponse(
1010
int goalId,
1111
String goalTitle,
1212
String goalColor,
13+
double progress,
1314
List<ReadTodosResponse> todos
1415
) {
15-
public static ReadTodosWithGoalsResponse from(Goal goal, List<ReadTodosResponse> responses) {
16+
public static ReadTodosWithGoalsResponse from(Goal goal, List<ReadTodosResponse> responses, double goalProgress) {
1617
return ReadTodosWithGoalsResponse.builder()
1718
.goalId(goal.getGoalId())
1819
.goalTitle(goal.getGoalTitle())
1920
.goalColor(goal.getColor())
21+
.progress(goalProgress)
2022
.todos(responses)
2123
.build();
2224
}

0 commit comments

Comments
 (0)