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

RAC-462 feat : wish 분리 및 신청서 API #327

Merged
merged 19 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
@@ -1,6 +1,7 @@
package com.postgraduate.admin.application.mapper;

import com.postgraduate.admin.application.dto.res.*;
import com.postgraduate.domain.member.user.domain.entity.constant.Status;
import com.postgraduate.domain.mentoring.domain.entity.Mentoring;
import com.postgraduate.domain.payment.domain.entity.Payment;
import com.postgraduate.domain.salary.domain.entity.Salary;
Expand All @@ -9,8 +10,6 @@
import com.postgraduate.domain.member.senior.domain.entity.Senior;
import com.postgraduate.domain.member.user.application.utils.UserUtils;
import com.postgraduate.domain.member.user.domain.entity.User;
import com.postgraduate.domain.member.user.domain.entity.constant.Role;
import com.postgraduate.domain.member.user.domain.entity.Wish;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -42,19 +41,17 @@ public CertificationDetailsResponse mapToCertificationInfo(Senior senior) {
);
}

public UserInfo mapToUserInfo(Wish wish) {
User user = wish.getUser();
Boolean isSenior = user.getRole() == Role.SENIOR;
public UserInfo mapToUserInfo(User user) {
return new UserInfo(
user.getUserId(),
user.getNickName(),
user.getPhoneNumber(),
user.getCreatedAt(),
user.getMarketingReceive(),
wish.getMatchingReceive(),
wish.getWishId(),
wish.getStatus(),
isSenior
false,
1L, // todo : wish 삭제에 따른 변경 필요
Status.MATCHED,
false
);
}

Expand All @@ -69,7 +66,7 @@ public SeniorInfo mapToSeniorInfo(Salary salary) {
senior.getStatus(),
salary.getTotalAmount(),
user.getMarketingReceive(),
user.isJunior()
false //todo : wish 삭제에 따른 선배에서 후배 판단 조건 삭제 or 수정 필요
);
}

Expand Down Expand Up @@ -242,17 +239,4 @@ private static MentoringWithPaymentResponse getMentoringWithPaymentResponse(Ment
SHORT.getCharge()
);
}

public WishResponse mapToWishResponse(Wish wish) {
User user = wish.getUser();
return new WishResponse(
wish.getWishId(),
user.getNickName(),
user.getPhoneNumber(),
user.getCreatedAt(),
user.getMarketingReceive(),
wish.getMatchingReceive(),
wish.getMajor(),
wish.getField());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import com.postgraduate.admin.application.mapper.AdminMapper;
import com.postgraduate.admin.domain.service.AdminUserService;
import com.postgraduate.domain.member.user.domain.entity.User;
import com.postgraduate.domain.member.user.domain.entity.Wish;
import com.postgraduate.global.bizppurio.application.dto.req.JuniorMatchingSuccessRequest;
import com.postgraduate.global.bizppurio.application.usecase.BizppurioJuniorMessage;
import lombok.RequiredArgsConstructor;
Expand All @@ -31,16 +30,15 @@ public User login(Login loginForm) {

@Transactional(readOnly = true)
public List<UserInfo> userInfos() {
List<Wish> all = adminUserService.allJunior();
List<User> all = adminUserService.allJunior();
return all.stream()
.map(adminMapper::mapToUserInfo)
.toList();
}

@Transactional(readOnly = true)
public WishResponse wishInfo(Long userId) {
User user = adminUserService.userByUserId(userId);
return adminMapper.mapToWishResponse(user.getWish());
return null; //todo : wish 변경에 따른 수정 필요
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

⚠️ Potential issue

Critical: Null return in wishInfo() causes runtime risk in active endpoint

The method is actively used in the /user/matching/{userId} endpoint where its result is directly added to the model. Returning null will cause issues when the template tries to access wishInfo attributes.

  • AdminWithThymeLeafController.userMatching() adds the null response to model without null checking
  • Template "userWish" likely expects valid WishResponse data

Immediate action required to prevent runtime errors. Either:

  1. Implement proper error handling in the controller
  2. Complete the TODO implementation in AdminUserUseCase
  3. If the feature is temporarily disabled, return an empty but valid WishResponse object
🔗 Analysis chain

Critical: Replace null return with proper error handling.

Returning null with a TODO comment is problematic as it can lead to NullPointerException in consuming code. Consider these alternatives:

  1. Throw an UnsupportedOperationException with a clear message if the feature is temporarily disabled
  2. Return an Optional
  3. If the feature is no longer needed, remove the method entirely

Here's a suggested improvement:

-    public WishResponse wishInfo(Long userId) {
-        return null; //todo : wish 변경에 따른 수정 필요
-    }
+    public WishResponse wishInfo(Long userId) {
+        throw new UnsupportedOperationException("Wish functionality is currently being restructured");
+    }

Let's check if this method is still being used:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for calls to wishInfo method
rg -l "wishInfo\(" --type java

Length of output: 195


Script:

#!/bin/bash
# Check how wishInfo is being used in the controller
rg "wishInfo" -A 5 -B 5 src/main/java/com/postgraduate/admin/presentation/AdminWithThymeLeafController.java

Length of output: 536

}

public void wishDone(Long wishId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.postgraduate.admin.domain.repository;

import com.postgraduate.domain.member.user.domain.entity.User;
import com.postgraduate.domain.member.user.domain.entity.Wish;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
Expand All @@ -16,19 +15,12 @@
public class AdminUserRepository {
private final JPAQueryFactory queryFactory;

public List<Wish> findAllJunior() {
return queryFactory.select(user.wish)
.from(user)
.where(user.wish.isNotNull())
public List<User> findAllJunior() {
return queryFactory.selectFrom(user)
// .where(user.role.eq(Role.USER))
.fetch();
}

public Optional<User> findUserByWishId(Long wishId) {
return Optional.ofNullable(queryFactory.selectFrom(user)
.where(user.wish.wishId.eq(wishId))
.fetchOne());
}

public Optional<User> findUserByUserId(Long userId) {
return Optional.ofNullable(queryFactory.selectFrom(user)
.where(user.userId.eq(userId))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import com.postgraduate.admin.domain.repository.AdminUserRepository;
import com.postgraduate.domain.member.user.domain.entity.User;
import com.postgraduate.domain.member.user.exception.UserNotFoundException;
import com.postgraduate.domain.member.user.domain.entity.Wish;
import com.postgraduate.domain.member.user.exception.WishNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

Expand All @@ -15,14 +13,12 @@
public class AdminUserService {
private final AdminUserRepository adminUserRepository;

public List<Wish> allJunior() {
public List<User> allJunior() {
return adminUserRepository.findAllJunior();
}

public void updateWishDone(Long wishId) {
User user = adminUserRepository.findUserByWishId(wishId)
.orElseThrow(WishNotFoundException::new);
user.updateWishDone();
//todo : wish삭제에 따른 수정 필요
}
Comment on lines 20 to 22
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

⚠️ Potential issue

Implement updateWishDone method properly - it's actively being used

The method is actively called from AdminUserUseCase.wishDone(), so it cannot be removed. The current empty implementation with just a TODO comment is dangerous as it silently does nothing when called.

  • Implement proper functionality in AdminUserService.updateWishDone() method
  • If the wish functionality is being separated/removed, throw an appropriate exception until the transition is complete

Example implementation:

public void updateWishDone(Long wishId) {
    throw new UnsupportedOperationException("This operation needs to be implemented - wish deletion functionality pending");
}
🔗 Analysis chain

Remove or properly implement the updateWishDone method

The current implementation with just a TODO comment is problematic:

  1. It creates a "zombie" method that does nothing but can still be called
  2. The TODO comment is vague and doesn't provide clear direction
  3. Keeping unused methods increases technical debt

Either:

  1. Remove this method entirely if it's no longer needed:
-    public void updateWishDone(Long wishId) {
-         //todo : wish삭제에 따른 수정 필요
-    }
  1. Or throw an appropriate exception until properly implemented:
     public void updateWishDone(Long wishId) {
-         //todo : wish삭제에 따른 수정 필요
+         throw new UnsupportedOperationException("This operation is no longer supported due to wish functionality separation");
     }

Let's verify if this method is still being called anywhere:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining calls to updateWishDone
rg -l "updateWishDone" --type java

Length of output: 187


Script:

#!/bin/bash
# Let's check how updateWishDone is being used in AdminUserUseCase.java
rg "updateWishDone" src/main/java/com/postgraduate/admin/application/usecase/AdminUserUseCase.java -A 3 -B 3

Length of output: 277


public User userByUserId(Long userId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,18 @@ public void launchSalaryJob() throws JobInstanceAlreadyCompleteException, JobExe
.addLocalDateTime("date", LocalDateTime.now())
.toJobParameters();
jobLauncher.run(salaryJob, jobParameters);
checkSalaryJobSuccess(jobParameters);
checkSalaryJobSuccess();
}

public void launchSalaryJobWithAdmin() throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException {
JobParameters jobParameters = new JobParametersBuilder()
.addLocalDateTime("date", LocalDateTime.now())
.toJobParameters();
jobLauncher.run(salaryJobWithAdmin, jobParameters);
checkSalaryJobSuccess(jobParameters);
checkSalaryJobSuccess();
}

private void checkSalaryJobSuccess(JobParameters jobParameters) throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException {
private void checkSalaryJobSuccess() throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException {
int retries = 0;
boolean success = false;
int seniorSize = seniorGetService.allSeniorId()
Expand All @@ -90,6 +90,9 @@ private void checkSalaryJobSuccess(JobParameters jobParameters) throws JobExecut
Thread.currentThread().interrupt(); //스레드 상태 복원
log.error("Thread Interrupt 발생");
}
JobParameters jobParameters = new JobParametersBuilder()
.addLocalDateTime("date", LocalDateTime.now())
.toJobParameters();
jobLauncher.run(salaryJobWithAdmin, jobParameters);
Comment on lines +93 to 96
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Improve error handling and job tracking

The creation of new JobParameters on each retry makes it difficult to correlate related job executions. Additionally, the job execution exceptions are not properly handled.

-            JobParameters jobParameters = new JobParametersBuilder()
-                    .addLocalDateTime("date", LocalDateTime.now())
-                    .toJobParameters();
-            jobLauncher.run(salaryJobWithAdmin, jobParameters);
+            JobParameters jobParameters = new JobParametersBuilder()
+                    .addLocalDateTime("date", LocalDateTime.now())
+                    .addString("retryAttempt", String.valueOf(retries))
+                    .addString("originalJobId", originalJobId)  // Add correlation ID
+                    .toJobParameters();
+            try {
+                jobLauncher.run(salaryJobWithAdmin, jobParameters);
+            } catch (JobExecutionException e) {
+                log.error("Failed to execute salary job on retry {}: {}", retries, e.getMessage());
+                throw e;
+            }

Committable suggestion skipped: line range outside the PR's diff.

retries++;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import java.util.List;

import static com.postgraduate.domain.member.senior.application.mapper.SeniorMapper.*;
import static com.postgraduate.domain.member.user.domain.entity.constant.Role.SENIOR;

@Service
@Transactional
Expand All @@ -25,7 +24,7 @@ public class SeniorInfoUseCase {
private final SeniorUpdateService seniorUpdateService;

public SeniorDetailResponse getSeniorDetail(User user, Long seniorId) {
if (user != null && user.getRole() == SENIOR)
if (user != null && user.isSenior())
return checkIsMine(user, seniorId);
return getResponse(seniorId, false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,4 @@ public SeniorMyPageUserAccountResponse getSeniorMyPageUserAccount(User user) {
String accountNumber = encryptorUtils.decryptData(account.getAccountNumber());
return mapToMyPageUserAccount(senior, account, accountNumber);
}

public SeniorPossibleResponse checkUser(User user) {
if (!user.isJunior())
return new SeniorPossibleResponse(FALSE, user.getSocialId());
return new SeniorPossibleResponse(TRUE, user.getSocialId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,4 @@ public ResponseEntity<ResponseDto<AllSeniorSearchResponse>> getFieldSenior(@Requ
AllSeniorSearchResponse searchSenior = seniorInfoUseCase.getFieldSenior(field, postgradu, page);
return ResponseEntity.ok(create(SeniorResponseCode.SENIOR_FIND.getCode(), SeniorResponseMessage.GET_SENIOR_LIST_INFO.getMessage(), searchSenior));
}

@GetMapping("/me/role")
@Operation(summary = "후배 전환시 가능 여부 확인 | 토큰 필요", description = "true-가능, false-불가능")
public ResponseEntity<ResponseDto<SeniorPossibleResponse>> checkRole(@AuthenticationPrincipal User user) {
SeniorPossibleResponse possibleResponse = seniorMyPageUseCase.checkUser(user);
return ResponseEntity.ok(create(SeniorResponseCode.SENIOR_FIND.getCode(), SeniorResponseMessage.GET_USER_CHECK.getMessage(), possibleResponse));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@

import com.postgraduate.domain.member.user.application.dto.res.UserInfoResponse;
import com.postgraduate.domain.member.user.application.dto.res.UserMyPageResponse;
import com.postgraduate.domain.member.user.domain.entity.MemberRole;
import com.postgraduate.domain.member.user.domain.entity.constant.Role;
import com.postgraduate.domain.member.user.domain.entity.constant.Status;
import com.postgraduate.domain.member.user.domain.entity.Wish;
import com.postgraduate.global.auth.login.application.dto.req.SeniorSignUpRequest;
import com.postgraduate.global.auth.login.application.dto.req.SignUpRequest;
import com.postgraduate.domain.member.user.domain.entity.User;
import com.postgraduate.global.auth.login.application.dto.req.UserChangeRequest;

public class UserMapper {

Expand Down Expand Up @@ -48,29 +46,13 @@ public static User mapToUser(SeniorSignUpRequest request, String profile) {
.phoneNumber(request.phoneNumber())
.marketingReceive(request.marketingReceive())
.profile(profile)
.role(Role.SENIOR)
.build();
}

public static Wish mapToWish(User user, SignUpRequest request) {
Status matchingStatus = request.matchingReceive() ? Status.WAITING : Status.REJECTED;
return Wish.builder()
public static MemberRole mapToRole(Role role, User user) {
return MemberRole.builder()
.role(role)
Comment on lines +52 to +54
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add null checks for role and user parameters

To prevent potential NullPointerExceptions, consider adding null checks for the role and user parameters before passing them to MemberRole.builder().

Apply this diff to add null checks:

 public static MemberRole mapToRole(Role role, User user) {
+    if (role == null || user == null) {
+        throw new IllegalArgumentException("Role and User must not be null");
+    }
     return MemberRole.builder()
             .role(role)
             .user(user)
             .build();
 }
📝 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
public static MemberRole mapToRole(Role role, User user) {
return MemberRole.builder()
.role(role)
public static MemberRole mapToRole(Role role, User user) {
if (role == null || user == null) {
throw new IllegalArgumentException("Role and User must not be null");
}
return MemberRole.builder()
.role(role)

.user(user)
.major(request.major())
.field(request.field())
.matchingReceive(request.matchingReceive())
.status(matchingStatus)
.build();
}

public static Wish mapToWish(User user, UserChangeRequest request) {
Status matchingStatus = request.matchingReceive() ? Status.WAITING : Status.REJECTED;
return Wish.builder()
.user(user)
.major(request.major())
.field(request.field())
.matchingReceive(request.matchingReceive())
.status(matchingStatus)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.postgraduate.domain.member.user.application.dto.res.UserPossibleResponse;
import com.postgraduate.domain.member.user.application.mapper.UserMapper;
import com.postgraduate.domain.member.user.domain.entity.User;
import com.postgraduate.domain.member.user.domain.entity.constant.Role;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

Expand All @@ -21,8 +20,7 @@ public UserInfoResponse getUserOriginInfo(User user) {
}

public UserPossibleResponse checkSenior(User user) {
Role role = user.getRole();
if (role.equals(Role.SENIOR))
if (user.isSenior())
return new UserPossibleResponse(true, user.getSocialId());
return new UserPossibleResponse(false, user.getSocialId());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class UserUtils {

@PostConstruct
public void init() {
archiveUser = new User(-100L, -100L, null, "알수없음", "탈퇴한회원", profile, 0, null, false, null, null, false, false, null);
archiveUser = new User(-100L, -100L, null, "알수없음", "탈퇴한회원", profile, 0, null, false, null, null, false, false);
}

public User getArchiveUser() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.postgraduate.domain.member.user.domain.entity;

import com.postgraduate.domain.member.user.domain.entity.constant.Role;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class MemberRole {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long roleId;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Role role;
Comment on lines +20 to +22
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add validation to ensure role is never null

While the column is marked as non-nullable in the database, the entity should validate this at the application level. Consider adding Bean Validation annotations.

 @Enumerated(EnumType.STRING)
 @Column(nullable = false)
+@NotNull(message = "Role cannot be null")
 private Role role;
📝 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
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Role role;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
@NotNull(message = "Role cannot be null")
private Role role;


@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
Comment on lines +24 to +26
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Add index and foreign key constraint to improve query performance

The suggestion to add an index and explicit foreign key constraint is valid as:

  1. The entity has a many-to-one relationship that would benefit from an indexed foreign key
  2. There are no existing indexes on the user_id column
  3. The foreign key constraint is not explicitly named

Regarding the transactional context concern:

  • The services using MemberRole don't show explicit @transactional annotations
  • Given that this is a JPA entity with lazy loading, transactions should be properly managed

Recommended changes:

  • Add index and named foreign key as suggested in the original review
  • Ensure @transactional is added to service methods that access the User entity through MemberRole
🔗 Analysis chain

Consider adding an index on the user_id foreign key

The many-to-one relationship would benefit from an index on the foreign key column for better query performance, especially when querying roles by user.

 @ManyToOne(fetch = FetchType.LAZY)
-@JoinColumn(name = "user_id")
+@JoinColumn(name = "user_id", foreignKey = @ForeignKey(name = "fk_member_role_user"))
+@Index(name = "idx_member_role_user_id")
 private User user;

Also, be cautious with lazy loading. Ensure that the user field is always accessed within a transactional context to prevent LazyInitializationException.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if @Transactional is properly used in services accessing MemberRole
ast-grep --pattern 'class $_ {
  $$$
  @Transactional
  $$$
  public $_ $_($$$) {
    $$$
    memberRole.getUser()
    $$$
  }
  $$$
}'

Length of output: 137


Script:

#!/bin/bash
# Let's first check for any references to MemberRole.getUser()
rg "memberRole.*getUser" -A 3

# Check for service classes that use MemberRole
rg "class.*Service.*\{" -A 5 | rg -B 5 "MemberRole"

# Check if there's any @Index annotation already on MemberRole
rg "@Index" src/main/java/com/postgraduate/domain/member/user/domain/entity/MemberRole.java

# Check for existing foreign key constraints in MemberRole
rg "@ForeignKey|@JoinColumn" src/main/java/com/postgraduate/domain/member/user/domain/entity/MemberRole.java

Length of output: 2361


Script:

#!/bin/bash
# Let's check for @Transactional annotations in services that use MemberRole
rg "@Transactional" src/main/java/com/postgraduate/domain/member/user/domain/service/UserDeleteService.java
rg "@Transactional" src/main/java/com/postgraduate/domain/member/user/domain/service/UserUpdateService.java
rg "@Transactional" src/main/java/com/postgraduate/domain/member/user/domain/service/UserSaveService.java

# Check if there are any existing indexes in the entity
rg "Table|Index" src/main/java/com/postgraduate/domain/member/user/domain/entity/MemberRole.java

# Let's see the full MemberRole entity class to understand its structure
cat src/main/java/com/postgraduate/domain/member/user/domain/entity/MemberRole.java

Length of output: 1146

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.hibernate.annotations.*;

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

import static java.time.LocalDate.now;
Expand Down Expand Up @@ -46,10 +47,9 @@ public class User {
@Column(nullable = false)
private int point;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
@Builder.Default
private Role role = Role.USER;
private List<MemberRole> roles = new ArrayList<>();
Comment on lines +50 to +52
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider using FetchType.LAZY for roles to improve performance

Currently, the roles relationship is defined with FetchType.EAGER, which can lead to performance issues due to unnecessary loading of roles when a User entity is fetched. Switching to FetchType.LAZY ensures that role data is loaded only when explicitly accessed.

Apply this diff to change the fetch type:

-    @OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
+    @OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
📝 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
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
@Builder.Default
private Role role = Role.USER;
private List<MemberRole> roles = new ArrayList<>();
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
@Builder.Default
private List<MemberRole> roles = new ArrayList<>();


@Column(nullable = false)
private Boolean marketingReceive;
Expand All @@ -69,23 +69,29 @@ public class User {
@Builder.Default
private boolean isDelete = false;

@OneToOne(mappedBy = "user")
private Wish wish;

public void addWish(Wish wish) {
this.wish = wish;
public boolean isJunior() {
return roles.stream()
.map(MemberRole::getRole)
.toList()
.contains(Role.USER);
}

public void updateWishDone() {
this.wish.updateDone();
public boolean isSenior() {
return roles.stream()
.map(MemberRole::getRole)
.toList()
.contains(Role.SENIOR);
}

public boolean isJunior() {
return this.wish != null;
public boolean isAdmin() {
return roles.stream()
.map(MemberRole::getRole)
.toList()
.contains(Role.ADMIN);
}

public void updateRole(Role role) {
this.role = role;
public void updateRole(MemberRole memberRole) {
roles.add(memberRole);
Comment on lines +93 to +94
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Ensure idempotent role updates in updateRole()

Adding roles without checking for existing entries might introduce duplicates, especially if roles remains a List. Consider checking for the existence of the role before adding it.

Apply this diff:

     public void updateRole(MemberRole memberRole) {
-        roles.add(memberRole);
+        if (!roles.contains(memberRole)) {
+            roles.add(memberRole);
+        }
     }

Note: If you've converted roles to a Set, this check becomes unnecessary due to the nature of sets preventing duplicates. Ensure that the MemberRole class properly overrides equals and hashCode methods to function correctly in a Set.

📝 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
public void updateRole(MemberRole memberRole) {
roles.add(memberRole);
public void updateRole(MemberRole memberRole) {
if (!roles.contains(memberRole)) {
roles.add(memberRole);
}

}

public void updateInfo(String profile, String nickName, String phoneNumber) {
Expand Down Expand Up @@ -143,8 +149,4 @@ public boolean isHardDelete() {
)
);
}

public boolean isSenior() {
return this.role.equals(Role.SENIOR);
}
}
Loading
Loading