From a36dee75afe2313fcfbc059cc8617363aba55a99 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Mon, 6 Apr 2026 19:49:38 -0600 Subject: [PATCH] expand User entity fields --- .../petshop/backend/dto/user/UserRequest.java | 67 +++++++++++---- .../backend/dto/user/UserResponse.java | 74 +++++++++++------ .../java/com/petshop/backend/entity/User.java | 83 ++++++++++++++----- .../petshop/backend/service/UserService.java | 38 +++++++-- 4 files changed, 191 insertions(+), 71 deletions(-) diff --git a/backend/src/main/java/com/petshop/backend/dto/user/UserRequest.java b/backend/src/main/java/com/petshop/backend/dto/user/UserRequest.java index 09a9036d..a6eb61cb 100644 --- a/backend/src/main/java/com/petshop/backend/dto/user/UserRequest.java +++ b/backend/src/main/java/com/petshop/backend/dto/user/UserRequest.java @@ -8,14 +8,20 @@ import jakarta.validation.constraints.Size; import java.util.Objects; public class UserRequest { - @NotBlank(message = "Username is required") @Size(min = 3, max = 50, message = "Username must be between 3 and 50 characters") private String username; @Size(min = 6, message = "Password must be at least 6 characters") private String password; - @NotBlank(message = "Full name is required") + @NotBlank(message = "First name is required") + @Size(max = 50) + private String firstName; + + @NotBlank(message = "Last name is required") + @Size(max = 50) + private String lastName; + private String fullName; @Email(message = "Invalid email format") @@ -27,6 +33,10 @@ public class UserRequest { @NotNull(message = "Role is required") private User.Role role; + private String staffRole; + + private Long primaryStoreId; + private Boolean active = true; public String getUsername() { @@ -45,6 +55,22 @@ public class UserRequest { this.password = password; } + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + public String getFullName() { return fullName; } @@ -77,6 +103,22 @@ public class UserRequest { this.role = role; } + public String getStaffRole() { + return staffRole; + } + + public void setStaffRole(String staffRole) { + this.staffRole = staffRole; + } + + public Long getPrimaryStoreId() { + return primaryStoreId; + } + + public void setPrimaryStoreId(Long primaryStoreId) { + this.primaryStoreId = primaryStoreId; + } + public Boolean getActive() { return active; } @@ -91,29 +133,20 @@ public class UserRequest { if (o == null || getClass() != o.getClass()) return false; UserRequest that = (UserRequest) o; return Objects.equals(username, that.username) && - Objects.equals(password, that.password) && - Objects.equals(fullName, that.fullName) && + Objects.equals(firstName, that.firstName) && + Objects.equals(lastName, that.lastName) && Objects.equals(email, that.email) && - Objects.equals(phone, that.phone) && - role == that.role && - Objects.equals(active, that.active); + role == that.role; } @Override public int hashCode() { - return Objects.hash(username, password, fullName, email, phone, role, active); + return Objects.hash(username, firstName, lastName, email, role); } @Override public String toString() { - return "UserRequest{" + - "username='" + username + '\'' + - ", password='" + password + '\'' + - ", fullName='" + fullName + '\'' + - ", email='" + email + '\'' + - ", phone='" + phone + '\'' + - ", role=" + role + - ", active=" + active + - '}'; + return "UserRequest{username='" + username + "', firstName='" + firstName + + "', lastName='" + lastName + "', role=" + role + '}'; } } diff --git a/backend/src/main/java/com/petshop/backend/dto/user/UserResponse.java b/backend/src/main/java/com/petshop/backend/dto/user/UserResponse.java index 9d7167c2..6c4d15b5 100644 --- a/backend/src/main/java/com/petshop/backend/dto/user/UserResponse.java +++ b/backend/src/main/java/com/petshop/backend/dto/user/UserResponse.java @@ -6,10 +6,15 @@ import java.util.Objects; public class UserResponse { private Long id; private String username; + private String firstName; + private String lastName; private String fullName; private String email; private String phone; private String role; + private String staffRole; + private Long primaryStoreId; + private Integer loyaltyPoints; private Boolean active; private LocalDateTime createdAt; private LocalDateTime updatedAt; @@ -17,18 +22,6 @@ public class UserResponse { public UserResponse() { } - public UserResponse(Long id, String username, String fullName, String email, String phone, String role, Boolean active, LocalDateTime createdAt, LocalDateTime updatedAt) { - this.id = id; - this.username = username; - this.fullName = fullName; - this.email = email; - this.phone = phone; - this.role = role; - this.active = active; - this.createdAt = createdAt; - this.updatedAt = updatedAt; - } - public Long getId() { return id; } @@ -45,6 +38,22 @@ public class UserResponse { this.username = username; } + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + public String getFullName() { return fullName; } @@ -77,6 +86,30 @@ public class UserResponse { this.role = role; } + public String getStaffRole() { + return staffRole; + } + + public void setStaffRole(String staffRole) { + this.staffRole = staffRole; + } + + public Long getPrimaryStoreId() { + return primaryStoreId; + } + + public void setPrimaryStoreId(Long primaryStoreId) { + this.primaryStoreId = primaryStoreId; + } + + public Integer getLoyaltyPoints() { + return loyaltyPoints; + } + + public void setLoyaltyPoints(Integer loyaltyPoints) { + this.loyaltyPoints = loyaltyPoints; + } + public Boolean getActive() { return active; } @@ -106,26 +139,17 @@ public class UserResponse { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; UserResponse that = (UserResponse) o; - return Objects.equals(id, that.id) && Objects.equals(username, that.username) && Objects.equals(fullName, that.fullName) && Objects.equals(email, that.email) && Objects.equals(phone, that.phone) && Objects.equals(role, that.role) && Objects.equals(active, that.active) && Objects.equals(createdAt, that.createdAt) && Objects.equals(updatedAt, that.updatedAt); + return Objects.equals(id, that.id); } @Override public int hashCode() { - return Objects.hash(id, username, fullName, email, phone, role, active, createdAt, updatedAt); + return Objects.hash(id); } @Override public String toString() { - return "UserResponse{" + - "id=" + id + - ", username='" + username + '\'' + - ", fullName='" + fullName + '\'' + - ", email='" + email + '\'' + - ", phone='" + phone + '\'' + - ", role='" + role + '\'' + - ", active=" + active + - ", createdAt=" + createdAt + - ", updatedAt=" + updatedAt + - '}'; + return "UserResponse{id=" + id + ", username='" + username + "', firstName='" + firstName + + "', lastName='" + lastName + "', role='" + role + "', active=" + active + '}'; } } diff --git a/backend/src/main/java/com/petshop/backend/entity/User.java b/backend/src/main/java/com/petshop/backend/entity/User.java index d13e2e68..97b8dfc5 100644 --- a/backend/src/main/java/com/petshop/backend/entity/User.java +++ b/backend/src/main/java/com/petshop/backend/entity/User.java @@ -16,15 +16,21 @@ public class User { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false, unique = true, length = 50) + @Column(unique = true, length = 50) private String username; - @Column(nullable = false) + @Column private String password; @Column(unique = true, length = 100) private String email; + @Column(nullable = false, length = 50) + private String firstName; + + @Column(nullable = false, length = 50) + private String lastName; + @Column(length = 100) private String fullName; @@ -38,6 +44,16 @@ public class User { @Column(nullable = false, length = 20, columnDefinition = "VARCHAR(20)") private Role role; + @Column(length = 50) + private String staffRole; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "primaryStoreId") + private StoreLocation primaryStore; + + @Column(nullable = false) + private Integer loyaltyPoints = 0; + @Column(nullable = false) private Boolean active = true; @@ -59,21 +75,6 @@ public class User { public User() { } - public User(Long id, String username, String password, String email, String fullName, String phone, String avatarUrl, Role role, Boolean active, Integer tokenVersion, LocalDateTime createdAt, LocalDateTime updatedAt) { - this.id = id; - this.username = username; - this.password = password; - this.email = email; - this.fullName = fullName; - this.phone = phone; - this.avatarUrl = avatarUrl; - this.role = role; - this.active = active; - this.tokenVersion = tokenVersion; - this.createdAt = createdAt; - this.updatedAt = updatedAt; - } - public Long getId() { return id; } @@ -106,6 +107,22 @@ public class User { this.email = email; } + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + public String getFullName() { return fullName; } @@ -138,6 +155,30 @@ public class User { this.role = role; } + public String getStaffRole() { + return staffRole; + } + + public void setStaffRole(String staffRole) { + this.staffRole = staffRole; + } + + public StoreLocation getPrimaryStore() { + return primaryStore; + } + + public void setPrimaryStore(StoreLocation primaryStore) { + this.primaryStore = primaryStore; + } + + public Integer getLoyaltyPoints() { + return loyaltyPoints; + } + + public void setLoyaltyPoints(Integer loyaltyPoints) { + this.loyaltyPoints = loyaltyPoints; + } + public Boolean getActive() { return active; } @@ -188,16 +229,12 @@ public class User { return "User{" + "id=" + id + ", username='" + username + '\'' + - ", password='" + password + '\'' + ", email='" + email + '\'' + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + ", fullName='" + fullName + '\'' + - ", phone='" + phone + '\'' + - ", avatarUrl='" + avatarUrl + '\'' + ", role=" + role + ", active=" + active + - ", tokenVersion=" + tokenVersion + - ", createdAt=" + createdAt + - ", updatedAt=" + updatedAt + '}'; } } diff --git a/backend/src/main/java/com/petshop/backend/service/UserService.java b/backend/src/main/java/com/petshop/backend/service/UserService.java index 3c219172..e3a17c5c 100644 --- a/backend/src/main/java/com/petshop/backend/service/UserService.java +++ b/backend/src/main/java/com/petshop/backend/service/UserService.java @@ -3,8 +3,10 @@ package com.petshop.backend.service; import com.petshop.backend.dto.common.BulkDeleteRequest; import com.petshop.backend.dto.user.UserRequest; import com.petshop.backend.dto.user.UserResponse; +import com.petshop.backend.entity.StoreLocation; import com.petshop.backend.entity.User; import com.petshop.backend.exception.ResourceNotFoundException; +import com.petshop.backend.repository.StoreRepository; import com.petshop.backend.repository.UserRepository; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -14,6 +16,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.server.ResponseStatusException; import java.util.Locale; +import java.util.Objects; import static org.springframework.http.HttpStatus.BAD_REQUEST; import static org.springframework.http.HttpStatus.CONFLICT; @@ -24,11 +27,13 @@ public class UserService { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; private final UserBusinessLinkageService userBusinessLinkageService; + private final StoreRepository storeRepository; - public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, UserBusinessLinkageService userBusinessLinkageService) { + public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder, UserBusinessLinkageService userBusinessLinkageService, StoreRepository storeRepository) { this.userRepository = userRepository; this.passwordEncoder = passwordEncoder; this.userBusinessLinkageService = userBusinessLinkageService; + this.storeRepository = storeRepository; } public Page getAllUsers(String query, String role, Pageable pageable) { @@ -56,12 +61,18 @@ public class UserService { @Transactional public UserResponse createUser(UserRequest request) { User user = new User(); - user.setUsername(request.getUsername()); - user.setPassword(passwordEncoder.encode(request.getPassword())); + user.setUsername(trimToNull(request.getUsername())); + if (request.getPassword() != null && !request.getPassword().trim().isEmpty()) { + user.setPassword(passwordEncoder.encode(request.getPassword())); + } + user.setFirstName(request.getFirstName()); + user.setLastName(request.getLastName()); user.setFullName(request.getFullName()); user.setEmail(request.getEmail()); user.setPhone(trimToNull(request.getPhone())); user.setRole(request.getRole()); + user.setStaffRole(trimToNull(request.getStaffRole())); + user.setPrimaryStore(resolveStore(request.getPrimaryStoreId())); user.setActive(request.getActive() != null ? request.getActive() : true); validateUniquePhone(user.getPhone(), null); @@ -79,23 +90,27 @@ public class UserService { .orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + id)); boolean invalidateToken = - !user.getUsername().equals(request.getUsername()) + !Objects.equals(user.getUsername(), request.getUsername()) || user.getRole() != request.getRole() || !user.getActive().equals(request.getActive() != null ? request.getActive() : true); - user.setUsername(request.getUsername()); + user.setUsername(trimToNull(request.getUsername())); if (request.getPassword() != null && !request.getPassword().trim().isEmpty()) { user.setPassword(passwordEncoder.encode(request.getPassword())); invalidateToken = true; } + user.setFirstName(request.getFirstName()); + user.setLastName(request.getLastName()); user.setFullName(request.getFullName()); user.setEmail(request.getEmail()); String phone = trimToNull(request.getPhone()); - if (!java.util.Objects.equals(user.getPhone(), phone)) { + if (!Objects.equals(user.getPhone(), phone)) { validateUniquePhone(phone, user.getId()); } user.setPhone(phone); user.setRole(request.getRole()); + user.setStaffRole(trimToNull(request.getStaffRole())); + user.setPrimaryStore(resolveStore(request.getPrimaryStoreId())); user.setActive(request.getActive() != null ? request.getActive() : true); if (invalidateToken) { user.setTokenVersion(user.getTokenVersion() + 1); @@ -123,16 +138,27 @@ public class UserService { UserResponse response = new UserResponse(); response.setId(user.getId()); response.setUsername(user.getUsername()); + response.setFirstName(user.getFirstName()); + response.setLastName(user.getLastName()); response.setFullName(user.getFullName()); response.setEmail(user.getEmail()); response.setPhone(user.getPhone()); response.setRole(user.getRole().toString()); + response.setStaffRole(user.getStaffRole()); + response.setPrimaryStoreId(user.getPrimaryStore() != null ? user.getPrimaryStore().getStoreId() : null); + response.setLoyaltyPoints(user.getLoyaltyPoints()); response.setActive(user.getActive()); response.setCreatedAt(user.getCreatedAt()); response.setUpdatedAt(user.getUpdatedAt()); return response; } + private StoreLocation resolveStore(Long storeId) { + if (storeId == null) return null; + return storeRepository.findById(storeId) + .orElseThrow(() -> new ResourceNotFoundException("Store not found with id: " + storeId)); + } + private void validateUniquePhone(String phone, Long currentUserId) { if (phone == null || phone.isBlank()) { return;