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

[FEAT] 선택한 경로로 출발하기 및 이동 중 관련 기능 구현 #58

Open
wants to merge 27 commits into
base: develop
Choose a base branch
from

Conversation

codrin2
Copy link
Member

@codrin2 codrin2 commented Feb 7, 2025

Issue Number

#53

As-Is

출발하기 및 이동 중 관련 기능을 구현합니다.

To-Be

  • 선택한 경로로 출발하기 API 구현
    • 오늘 할 일 복제하여 경로별 할 일로 생성
  • 사용자 이동 중 데이터 조회 API 구현
    • 이동 가능 시간, 경로 별 할일 데이터 반환
    • Querydsl을 통한 fetch join으로 N+1 문제 처리
  • 이동 중 취소 API 구현

Check List

  • 테스트가 전부 통과되었나요?
  • 모든 commit이 push 되었나요?
  • merge할 branch를 확인했나요?
  • Assignee를 지정했나요?
  • Label을 지정했나요?

Test Screenshot

(Optional) Additional Description

Summary by CodeRabbit

  • New Features
    • Launched plan management endpoints to create, view recent, and delete plans.
    • Enhanced error messaging with new notifications for invalid member statuses, missing plans, and unsupported traffic types.
  • Refactor
    • Improved route search responses and refined data structures to include associated task details.
    • Adjusted security configuration to support additional endpoints.
  • Chore
    • Reorganized internal structures and package layouts for better consistency across plan and route management.

@codrin2 codrin2 added feat 새로운 기능 구현 BE 백엔드 작업 labels Feb 7, 2025
@codrin2 codrin2 added this to the [BE] 2차 스프린트 milestone Feb 7, 2025
@codrin2 codrin2 requested a review from khw7385 February 7, 2025 16:14
@codrin2 codrin2 self-assigned this Feb 7, 2025
Copy link

coderabbitai bot commented Feb 7, 2025

Walkthrough

This pull request updates the backend by expanding interceptor path patterns, modifying error code definitions, and introducing several new features. It adds REST controllers and services for managing plans that include creating, retrieving, and deleting operations. Domain models are updated by removing and adding fields, and new DTOs are introduced to better structure request and response data. Additionally, custom repository interfaces and exception classes are added to support new business logic, and modifications in the todo entity improve data consistency.

Changes

File(s) Change Summary
backend/.../WebConfig.java
backend/.../TokenInterceptor.java
Updated interceptor configuration by adding new path pattern /plans/** and minor formatting adjustments.
backend/.../ErrorCode.java
backend/.../TrafficType.java
Modified error codes: added INVALID_MEMBER_STATUS, PLAN_NOT_FOUND, INVALID_TRAFFIC_TYPE and removed unused ones; added string-to-enum conversion helper in TrafficType.
backend/.../PlanController.java
backend/.../PlanService.java
backend/.../RouteController.java
backend/.../RouteService.java
Introduced new REST controller and service classes for plan management with corresponding endpoint methods and DTO type updates.
backend/.../Path.java
backend/.../Plan.java
Revised domain models: in Path, removed congestionLevel, added todos and a factory method; in Plan, added a list of paths and a factory method createPlan.
backend/.../PlanSaveRequest.java
backend/.../PlanRecentResponse.java
backend/.../RouteSearchResponse.java
backend/.../OdsayRouteApiResponse.java
Added new request and response DTO records; reorganized package structure for response DTOs.
backend/.../InvalidMemberStatusException.java
backend/.../InvalidTrafficTypeException.java
backend/.../PlanNotFoundException.java
Introduced new exception classes to handle specific error conditions related to plan operations and traffic type validation.
backend/.../CustomPathRepository.java
backend/.../CustomPathRepositoryImpl.java
backend/.../PathRepository.java
Added a custom repository interface and its implementation for querying paths with associated todos, and extended the PathRepository accordingly.
backend/.../Todo.java
backend/.../TodoType.java
Enhanced the Todo entity with a many-to-one relation to Path and a new copyOf method; updated TodoType by adding IN_PROGRESS and rearranging constants.

Sequence Diagram(s)

sequenceDiagram
    participant PC as PlanController
    participant PS as PlanService
    participant PR as Repository
    participant DM as Domain Model
    PC->>PS: savePlan(memberId, PlanSaveRequest)
    PS->>PR: Validate member and persist plan data
    PR-->>PS: Persisted plan and paths
    PS->>DM: Create plan using factory methods (createPlan & createPath)
    PS-->>PC: Return response (201 Created)
Loading

Possibly related issues

Possibly related PRs

Suggested reviewers

  • khw7385

Poem

Hoppin’ through changes with a bounce in my stride,
New paths and plans now side-by-side.
I’ve tucked todos in a cozy little row,
Error codes refined, letting clarity flow.
A tiny code rabbit sings a joyful tune,
Celebrating each update under a bright, coding moon.
🐰✨

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (12)
backend/src/main/java/com/dubu/backend/plan/infra/repository/CustomPathRepositoryImpl.java (1)

19-25: LGTM! Well-implemented QueryDSL query with fetch join.

The implementation effectively uses QueryDSL to solve the N+1 problem by using fetch join.

Consider these improvements for handling large datasets:

  1. Add pagination support to prevent memory issues with large result sets
  2. Consider using distinct to prevent cartesian product issues with the collection fetch join
  3. For very large datasets, you might want to batch the fetch join to avoid the cartesian product problem:
public List<Path> findByPlanWithTodosOrderByPathOrder(Plan plan) {
    List<Path> paths = queryFactory
            .selectFrom(path)
            .where(path.plan.eq(plan))
            .orderBy(path.pathOrder.asc())
            .fetch();

    return queryFactory
            .selectFrom(path)
            .leftJoin(path.todos, todo).fetchJoin()
            .where(path.in(paths))
            .orderBy(path.pathOrder.asc())
            .fetch();
}
backend/src/main/java/com/dubu/backend/plan/application/RouteService.java (3)

35-35: Consider enhancing error handling for the API response.

While the code changes look good, consider adding error handling for potential null values in the API response, especially when accessing nested objects like apiPath.info().

Add null checks or use Optional to handle potential null values:

 private RouteSearchResponse convertApiPathToRoute(OdsayRouteApiResponse.Path apiPath, boolean isRecentlyUsed) {
-    OdsayRouteApiResponse.Info info = apiPath.info();
+    OdsayRouteApiResponse.Info info = Optional.ofNullable(apiPath.info())
+        .orElseThrow(() -> new IllegalArgumentException("Route info cannot be null"));

     int totalTime = info.totalTime();
     int totalSectionTime = 0;

Also applies to: 43-43, 46-46, 112-131


95-97: Replace magic numbers with constants for traffic types.

Using magic numbers (1, 2, 3) for traffic types reduces code readability and maintainability. Consider creating an enum for traffic types.

Create a TrafficType enum:

public enum TrafficType {
    SUBWAY(1),
    BUS(2),
    WALK(3),
    UNKNOWN(-1);

    private final int code;

    TrafficType(int code) {
        this.code = code;
    }

    public static TrafficType fromCode(int code) {
        return Arrays.stream(values())
            .filter(type -> type.code == code)
            .findFirst()
            .orElse(UNKNOWN);
    }
}

Then update the code:

-    int tType = subPath.trafficType();
-    String trafficType = switch (tType) {
-        case 1 -> "SUBWAY";
-        case 2 -> "BUS";
-        case 3 -> "WALK";
-        default -> "UNKNOWN";
-    };
+    TrafficType trafficType = TrafficType.fromCode(subPath.trafficType());
+    String trafficTypeStr = trafficType.name();

Also applies to: 135-140


149-162: Simplify nested conditions using early returns.

The nested conditions in convertApiSubPathToPathDto can be simplified for better readability.

Consider refactoring to:

-    if (subPath.lane() != null && !subPath.lane().isEmpty()) {
-        OdsayRouteApiResponse.Lane lane = subPath.lane().get(0);
-        if ("SUBWAY".equals(trafficType)) {
-            subwayName = lane.name();
-            subwayCode = lane.subwayCode();
-            startName = subPath.startName() + "역";
-            endName = subPath.endName() + "역";
-        } else if ("BUS".equals(trafficType)) {
-            busNumber = lane.busNo();
-            busCode = lane.busID();
-            startName = subPath.startName();
-            endName = subPath.endName();
-        }
-    }
+    if (subPath.lane() == null || subPath.lane().isEmpty()) {
+        return buildPath(trafficType, subPath, null, null, null, null, null, null);
+    }
+
+    OdsayRouteApiResponse.Lane lane = subPath.lane().get(0);
+    if ("SUBWAY".equals(trafficType)) {
+        return buildPath(
+            trafficType,
+            subPath,
+            lane.name(),
+            lane.subwayCode(),
+            null,
+            null,
+            subPath.startName() + "역",
+            subPath.endName() + "역"
+        );
+    }
+
+    if ("BUS".equals(trafficType)) {
+        return buildPath(
+            trafficType,
+            subPath,
+            null,
+            null,
+            lane.busNo(),
+            lane.busID(),
+            subPath.startName(),
+            subPath.endName()
+        );
+    }

Add a helper method:

private RouteSearchResponse.Path buildPath(
    String trafficType,
    OdsayRouteApiResponse.SubPath subPath,
    String subwayName,
    Integer subwayCode,
    String busNumber,
    Integer busCode,
    String startName,
    String endName
) {
    return new RouteSearchResponse.Path(
        trafficType,
        subPath.sectionTime(),
        subwayName,
        subwayCode,
        busNumber,
        busCode,
        startName,
        endName
    );
}
backend/src/main/java/com/dubu/backend/plan/dto/request/PlanSaveRequest.java (1)

5-16: Consider adding input validation for plan fields.
Though Java records are concise, you might want to ensure that values like 'totalSectionTime' or 'sectionTime' are non-null and non-negative. Bean Validation (e.g., @NotNull, @positive) can help gracefully handle invalid requests before they reach your service layer.

backend/src/main/java/com/dubu/backend/plan/exception/PlanNotFoundException.java (1)

8-16: Include details about the missing plan for easier troubleshooting.
Currently, the exception only returns a generic message. Consider adding a constructor that accepts the missing plan’s ID for better clarity in logs and user feedback.

Example:

public class PlanNotFoundException extends NotFoundException {
-   public PlanNotFoundException() {
+   public PlanNotFoundException(Long planId) {
       super(PLAN_NOT_FOUND.getMessage() + " Plan ID: " + planId);
   }
   ...
}
backend/src/main/java/com/dubu/backend/todo/entity/TodoType.java (1)

4-4: LGTM! Consider adding documentation for the new state.

The addition of IN_PROGRESS state aligns well with the travel functionality requirements. Consider adding Javadoc comments to document the purpose and usage of each enum value, especially the new IN_PROGRESS state.

 public enum TodoType {
+    /** Task scheduled for execution */
     SCHEDULED,
+    /** Task saved for later */
     SAVE,
+    /** Recommended task */
     RECOMMEND,
+    /** Task currently in progress during travel */
     IN_PROGRESS,
+    /** Completed task */
     DONE;

Also applies to: 11-11

backend/src/main/java/com/dubu/backend/plan/domain/enums/TrafficType.java (1)

10-15: Add null check to prevent NullPointerException.

The implementation looks good, but consider adding a null check to prevent NullPointerException.

 public static TrafficType from(String value) {
+    if (value == null) {
+        throw new InvalidTrafficTypeException("null");
+    }
     return Arrays.stream(TrafficType.values())
             .filter(type -> type.name().equalsIgnoreCase(value))
             .findFirst()
             .orElseThrow(() -> new InvalidTrafficTypeException(value));
 }
backend/src/main/java/com/dubu/backend/plan/exception/InvalidMemberStatusException.java (1)

7-16: Add serialVersionUID for serializable exception.

The exception implementation looks good. Consider adding serialVersionUID as it extends Exception (which is Serializable).

 public class InvalidMemberStatusException extends BadRequestException {
+    private static final long serialVersionUID = 1L;
+
     public InvalidMemberStatusException(String memberStatus) {
         super(INVALID_MEMBER_STATUS.getMessage().formatted(memberStatus));
     }
backend/src/main/java/com/dubu/backend/plan/api/PlanController.java (2)

17-24: Add request validation.

Consider adding @Valid annotation to validate the request body and define validation constraints in PlanSaveRequest.


35-42: Use path variable for planId.

Consider using @PathVariable instead of @RequestParam for planId as it represents a resource identifier:

-    @DeleteMapping
-    public void deletePlan(
-            @RequestAttribute("memberId") Long memberId,
-            @RequestParam("planId") Long planId
-    ){
+    @DeleteMapping("/{planId}")
+    public void deletePlan(
+            @RequestAttribute("memberId") Long memberId,
+            @PathVariable Long planId
+    ){
backend/src/main/java/com/dubu/backend/todo/entity/Todo.java (1)

41-43: Consider adding cascade type for Path relationship.

The @ManyToOne relationship with Path should specify a cascade type to ensure proper relationship management.

Apply this diff to add cascade type:

-    @ManyToOne(fetch = FetchType.LAZY)
+    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between feddf4f and 9cc43be.

📒 Files selected for processing (24)
  • backend/src/main/java/com/dubu/backend/global/config/WebConfig.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/global/exception/ErrorCode.java (2 hunks)
  • backend/src/main/java/com/dubu/backend/global/interceptor/TokenInterceptor.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/plan/api/PlanController.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/plan/api/RouteController.java (2 hunks)
  • backend/src/main/java/com/dubu/backend/plan/application/PlanService.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/plan/application/RouteService.java (4 hunks)
  • backend/src/main/java/com/dubu/backend/plan/domain/Path.java (3 hunks)
  • backend/src/main/java/com/dubu/backend/plan/domain/Plan.java (2 hunks)
  • backend/src/main/java/com/dubu/backend/plan/domain/enums/CongestionLevel.java (0 hunks)
  • backend/src/main/java/com/dubu/backend/plan/domain/enums/TrafficType.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/plan/dto/request/PlanSaveRequest.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/plan/dto/response/OdsayRouteApiResponse.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/plan/dto/response/PlanRecentResponse.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/plan/dto/response/RouteSearchResponse.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/plan/exception/InvalidMemberStatusException.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/plan/exception/InvalidTrafficTypeException.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/plan/exception/PlanNotFoundException.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/plan/infra/client/OdsayApiClient.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/plan/infra/repository/CustomPathRepository.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/plan/infra/repository/CustomPathRepositoryImpl.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/plan/infra/repository/PathRepository.java (1 hunks)
  • backend/src/main/java/com/dubu/backend/todo/entity/Todo.java (3 hunks)
  • backend/src/main/java/com/dubu/backend/todo/entity/TodoType.java (1 hunks)
💤 Files with no reviewable changes (1)
  • backend/src/main/java/com/dubu/backend/plan/domain/enums/CongestionLevel.java
✅ Files skipped from review due to trivial changes (4)
  • backend/src/main/java/com/dubu/backend/global/interceptor/TokenInterceptor.java
  • backend/src/main/java/com/dubu/backend/plan/dto/response/OdsayRouteApiResponse.java
  • backend/src/main/java/com/dubu/backend/plan/dto/response/RouteSearchResponse.java
  • backend/src/main/java/com/dubu/backend/plan/infra/client/OdsayApiClient.java
🔇 Additional comments (14)
backend/src/main/java/com/dubu/backend/plan/infra/repository/CustomPathRepository.java (1)

8-10: LGTM! Well-structured custom repository interface.

The interface follows Spring Data JPA best practices with a clear, descriptive method name that indicates its functionality.

backend/src/main/java/com/dubu/backend/plan/infra/repository/PathRepository.java (1)

8-8: LGTM! Good use of repository composition.

The interface properly extends both JpaRepository and CustomPathRepository, following Spring Data JPA best practices for combining standard and custom repository functionality.

backend/src/main/java/com/dubu/backend/plan/application/RouteService.java (1)

8-9: LGTM! Good use of read-only transactions.

The @Transactional(readOnly = true) annotation is appropriately used for this service class as it primarily contains search operations. This helps optimize performance by avoiding unnecessary transaction overhead.

Also applies to: 15-15, 21-21

backend/src/main/java/com/dubu/backend/plan/application/PlanService.java (2)

43-45: Clarify the logic behind restricting plan creation to STATUS.STOP.
Currently, the check only permits plan creation if the member’s status is STOP. This might be inverted depending on your business requirements (e.g., you may want to prohibit plan creation if the member is STOP). Please verify that this condition accurately reflects the intended business rule.

Would you like a verification script to review related code handling the STOP status and confirm consistency across the codebase?


62-69: Handle potential zero-length paths to avoid IndexOutOfBounds exceptions.
When assigning paths via round-robin, calling 'paths.get(i % paths.size())' will throw an exception if 'paths' is empty. Consider validating that 'paths' is not empty before iterating through 'existingTodos'.

backend/src/main/java/com/dubu/backend/plan/exception/InvalidTrafficTypeException.java (1)

7-16: LGTM! Well-structured exception handling.

The exception class is well-implemented with proper message formatting and error code handling.

backend/src/main/java/com/dubu/backend/plan/domain/Plan.java (2)

26-27: LGTM! Well-defined JPA relationship.

The one-to-many relationship with Path entities is properly configured with appropriate cascade and orphan removal settings.


32-37: LGTM! Well-structured factory method.

The static factory method follows best practices by:

  • Using the builder pattern
  • Encapsulating object creation logic
  • Having clear parameter names
backend/src/main/java/com/dubu/backend/global/config/WebConfig.java (1)

41-41: LGTM! Proper security configuration.

The path pattern for plans is correctly added to the token interceptor configuration.

backend/src/main/java/com/dubu/backend/plan/domain/Path.java (3)

31-32: LGTM! Well-defined JPA relationship.

The one-to-many relationship with Todo entities is properly configured with appropriate cascade and orphan removal settings.


50-59: LGTM! Well-structured factory method.

The static factory method follows best practices by:

  • Using the builder pattern
  • Properly mapping request data to entity fields
  • Having clear parameter names

1-60: Verify impact of removing congestionLevel field.

The congestionLevel field has been removed. Please ensure that:

  1. All references to this field in the codebase are updated
  2. Any frontend code depending on this field is modified
  3. Database migration scripts are created
backend/src/main/java/com/dubu/backend/global/exception/ErrorCode.java (1)

34-36: LGTM! Error codes align with new features.

The new error codes are well-organized and provide clear error messages for the journey-related features.

Also applies to: 44-49

backend/src/main/java/com/dubu/backend/plan/api/RouteController.java (1)

6-6: LGTM! Type updates are consistent across the controller.

The changes consistently update the response type from RouteSearchResponseDto to RouteSearchResponse across imports, method signature, and implementation.

Since this changes the API response type, please ensure that:

  1. The API documentation (if any) has been updated
  2. The clients consuming this endpoint have been notified of the change

Also applies to: 19-19, 26-26

Comment on lines +87 to +93
@Transactional
public void removePlan(Long memberId, Long planId) {
memberRepository.findById(memberId)
.orElseThrow(() -> new MemberNotFoundException(memberId));

planRepository.deleteById(planId);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Enforce plan ownership checks when deleting a plan.
The current logic only verifies that the member exists but not that the plan belongs to the member. This could allow a member to delete another user’s plan unintentionally.

Below is an example code diff to ensure the plan is bound to the correct member:

 @Transactional
 public void removePlan(Long memberId, Long planId) {
    memberRepository.findById(memberId)
        .orElseThrow(() -> new MemberNotFoundException(memberId));

+   Plan plan = planRepository.findById(planId)
+       .orElseThrow(() -> new PlanNotFoundException());
+   if (!plan.getMember().getId().equals(memberId)) {
+       throw new PlanNotFoundException(); // or any relevant unauthorized exception
+   }

-   planRepository.deleteById(planId);
+   planRepository.delete(plan);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Transactional
public void removePlan(Long memberId, Long planId) {
memberRepository.findById(memberId)
.orElseThrow(() -> new MemberNotFoundException(memberId));
planRepository.deleteById(planId);
}
@Transactional
public void removePlan(Long memberId, Long planId) {
memberRepository.findById(memberId)
.orElseThrow(() -> new MemberNotFoundException(memberId));
Plan plan = planRepository.findById(planId)
.orElseThrow(() -> new PlanNotFoundException());
if (!plan.getMember().getId().equals(memberId)) {
throw new PlanNotFoundException(); // or any relevant unauthorized exception
}
planRepository.delete(plan);
}

) {
public static PathTodoResponse from(Todo todo) {
return new PathTodoResponse(
todo.getType() == TodoType.DONE,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect todo status check.

The current implementation assumes TodoType.DONE is the only state to check for completion status. This might not handle all possible todo states correctly.

Apply this diff to fix the todo status check:

-                    todo.getType() == TodoType.DONE,
+                    todo.getType() == TodoType.DONE || todo.getType() == TodoType.IN_PROGRESS,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
todo.getType() == TodoType.DONE,
todo.getType() == TodoType.DONE || todo.getType() == TodoType.IN_PROGRESS,

Comment on lines +42 to +43
path.getTrafficType() == TrafficType.SUBWAY ? path.getPlan().getId().intValue() : null,
path.getTrafficType() == TrafficType.BUS ? path.getStartName() : null,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect traffic type handling logic.

The current implementation has logical issues in handling traffic types:

  1. Using plan.getId() as subway code is incorrect
  2. Using startName as bus number is incorrect

Apply this diff to fix the traffic type handling:

-                    path.getTrafficType() == TrafficType.SUBWAY ? path.getPlan().getId().intValue() : null,
-                    path.getTrafficType() == TrafficType.BUS ? path.getStartName() : null,
+                    path.getTrafficType() == TrafficType.SUBWAY ? path.getSubwayCode() : null,
+                    path.getTrafficType() == TrafficType.BUS ? path.getBusNumber() : null,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
path.getTrafficType() == TrafficType.SUBWAY ? path.getPlan().getId().intValue() : null,
path.getTrafficType() == TrafficType.BUS ? path.getStartName() : null,
path.getTrafficType() == TrafficType.SUBWAY ? path.getSubwayCode() : null,
path.getTrafficType() == TrafficType.BUS ? path.getBusNumber() : null,

Comment on lines +70 to +79
public static Todo copyOf(Todo originalTodo, Path assignedPath) {
return Todo.builder()
.title(originalTodo.getTitle())
.type(TodoType.IN_PROGRESS)
.difficulty(originalTodo.getDifficulty())
.memo(originalTodo.getMemo())
.path(assignedPath)
.category(originalTodo.getCategory())
.build();
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add member field initialization in copyOf method.

The copyOf method doesn't initialize the member field, which could lead to data inconsistency.

Apply this diff to fix member initialization:

     public static Todo copyOf(Todo originalTodo, Path assignedPath) {
         return Todo.builder()
                 .title(originalTodo.getTitle())
                 .type(TodoType.IN_PROGRESS)
                 .difficulty(originalTodo.getDifficulty())
                 .memo(originalTodo.getMemo())
                 .path(assignedPath)
                 .category(originalTodo.getCategory())
+                .member(originalTodo.getMember())
                 .build();
     }

Copy link
Collaborator

@khw7385 khw7385 left a comment

Choose a reason for hiding this comment

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

수고하셨습니다!! 승인하겠습니다!!


newTodos.add(clonedTodo);
}
todoRepository.saveAll(newTodos);
Copy link
Collaborator

Choose a reason for hiding this comment

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

todo 를 하나씩 저장하는 것이 아닌 한 번에 저장하는 것이 좋았습니다!!

memberRepository.findById(memberId)
.orElseThrow(() -> new MemberNotFoundException(memberId));

planRepository.deleteById(planId);
Copy link
Collaborator

Choose a reason for hiding this comment

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

deleteById 로 해당 plan 의 존재 여부를 확인하지 않고 바로 삭제하는 것이 좋네요!! 배워갑니다!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BE 백엔드 작업 feat 새로운 기능 구현
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[FEAT] 선택한 경로로 출발하기 및 이동중 데이터 조회 기능 구현
2 participants