Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<dependency>
<groupId>com.github.Podzilla</groupId>
<artifactId>podzilla-utils-lib</artifactId>
<version>v1.1.5</version>
<version>v1.1.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down Expand Up @@ -107,6 +107,10 @@
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -43,7 +44,7 @@ public AuthenticationController(
description = "User logged in successfully"
)
public ResponseEntity<?> login(
@RequestBody final LoginRequest loginRequest,
@Valid @RequestBody final LoginRequest loginRequest,
final HttpServletResponse response) {
String email = authenticationService.login(loginRequest, response);
LOGGER.info("User {} logged in", email);
Expand All @@ -62,7 +63,7 @@ public ResponseEntity<?> login(
description = "User registered successfully"
)
public ResponseEntity<?> registerUser(
@RequestBody final SignupRequest signupRequest) {
@Valid @RequestBody final SignupRequest signupRequest) {
authenticationService.registerAccount(signupRequest);
LOGGER.info("User {} registered", signupRequest.getEmail());
return new ResponseEntity<>("Account registered.",
Expand Down
28 changes: 19 additions & 9 deletions src/main/java/com/podzilla/auth/controller/UserController.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package com.podzilla.auth.controller;

import com.podzilla.auth.dto.UpdateRequest;
import com.podzilla.auth.dto.UserDetailsRequest;
import com.podzilla.auth.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.UUID;

@RestController
@RequestMapping("/user")
public class UserController {
Expand All @@ -27,14 +27,24 @@ public UserController(final UserService userService) {
this.userService = userService;
}

@PutMapping("/update/{userId}")
@PutMapping("/update")
@Operation(summary = "Update user name",
description = "Allows user to update their name.")
@ApiResponse(responseCode = "200",
description = "User profile updated successfully")
public void updateProfile(@PathVariable final UUID userId,
@Valid @RequestBody final String name) {
LOGGER.debug("Received updateProfile request for userId={}", userId);
userService.updateUserProfile(userId, name);
public void updateProfile(@Valid @RequestBody final UpdateRequest
updateRequest) {
LOGGER.debug("Received updateProfile request");
userService.updateUserProfile(updateRequest);
}

@GetMapping("/details")
@Operation(summary = "Get user details",
description = "Fetches the details of the current user.")
@ApiResponse(responseCode = "200",
description = "User details fetched successfully")
public UserDetailsRequest getUserDetails() {
LOGGER.debug("Received getUserDetails request");
return userService.getUserDetails();
}
}
3 changes: 3 additions & 0 deletions src/main/java/com/podzilla/auth/dto/CustomUserDetails.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Set;
import java.util.UUID;

@JsonIgnoreProperties(ignoreUnknown = true)
@Builder
Expand All @@ -21,6 +22,8 @@ public class CustomUserDetails implements UserDetails {

private String username;

private UUID id;

@JsonIgnore
private String password;

Expand Down
7 changes: 7 additions & 0 deletions src/main/java/com/podzilla/auth/dto/LoginRequest.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package com.podzilla.auth.dto;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

@Data
public class LoginRequest {

@Email
@NotBlank(message = "Email is required")
private String email;

@NotBlank(message = "Password is required")
private String password;
}
16 changes: 16 additions & 0 deletions src/main/java/com/podzilla/auth/dto/SignupRequest.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
package com.podzilla.auth.dto;

import com.podzilla.mq.events.DeliveryAddress;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

@Data
public class SignupRequest {
@NotBlank(message = "Name is required")
private String name;

@Email
@NotBlank(message = "Email is required")
private String email;

@NotBlank(message = "Password is required")
private String password;

@NotBlank(message = "Mobile number is required")
private String mobileNumber;

@Valid
private DeliveryAddress address;
}
19 changes: 19 additions & 0 deletions src/main/java/com/podzilla/auth/dto/UpdateRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.podzilla.auth.dto;

import com.podzilla.mq.events.DeliveryAddress;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

@Data
public class UpdateRequest {

@NotBlank(message = "Name is required")
private String name;

@Valid
private DeliveryAddress address;

@NotBlank(message = "Mobile Number is required")
private String mobileNumber;
}
12 changes: 12 additions & 0 deletions src/main/java/com/podzilla/auth/dto/UserDetailsRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.podzilla.auth.dto;

import com.podzilla.mq.events.DeliveryAddress;
import lombok.Builder;

@Builder
public class UserDetailsRequest {
private String email;
private String name;
private String mobileNumber;
private DeliveryAddress address;
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,41 @@
package com.podzilla.auth.exception;

import io.micrometer.common.lang.NonNull;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

@Override // Good practice to use @Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
final MethodArgumentNotValidException ex,
@NonNull final HttpHeaders headers,
@NonNull final HttpStatusCode status,
@NonNull final WebRequest request) {

StringBuilder errorMessage = new StringBuilder("Validation failed: ");
for (FieldError error : ex.getBindingResult().getFieldErrors()) {
errorMessage.append(error.getField()).append(": ")
.append(error.getDefaultMessage()).append("; ");
}

ErrorResponse errorResponse = new ErrorResponse(
errorMessage.toString(), (HttpStatus) status);

return new ResponseEntity<>(errorResponse, status);

}

@ExceptionHandler(AccessDeniedException.class)
public ResponseEntity<ErrorResponse> handleAccessDeniedException(
Expand Down
46 changes: 46 additions & 0 deletions src/main/java/com/podzilla/auth/model/Address.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.podzilla.auth.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Getter;

import java.util.UUID;

@Entity
@Table(name = "addresses")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class Address {

@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;

@OneToOne(optional = false)
@JoinColumn(name = "user_id", nullable = false)
@JsonIgnore
private User user;

private String street;

private String city;

private String state;

private String country;

private String postalCode;
}
12 changes: 8 additions & 4 deletions src/main/java/com/podzilla/auth/model/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import jakarta.persistence.FetchType;

Expand All @@ -18,7 +19,6 @@
import java.util.UUID;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
Expand All @@ -37,17 +37,21 @@ public class User {
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;

@NotBlank(message = "Name is required")
private String name;

@NotBlank(message = "Email is required")
@Email
@Column(unique = true)
private String email;

@NotBlank(message = "Password is required")
private String password;

@Column(unique = true)
private String mobileNumber;

@OneToOne(mappedBy = "user", cascade = CascadeType.ALL,
orphanRemoval = true)
private Address address;

@Builder.Default
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "users_roles",
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/podzilla/auth/repository/AddressRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.podzilla.auth.repository;

import com.podzilla.auth.model.Address;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;
import java.util.UUID;

public interface AddressRepository extends JpaRepository<Address, UUID> {
Optional<Address> findByUserId(UUID userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@
public interface UserRepository extends JpaRepository<User, UUID> {
Optional<User> findByEmail(String email);
Boolean existsByEmail(String email);
Boolean existsByMobileNumber(String mobileNumber);
}
1 change: 1 addition & 0 deletions src/main/java/com/podzilla/auth/service/AdminService.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public static UserDetails getUserDetails(final User user) {

return CustomUserDetails.builder()
.username(user.getEmail())
.id(user.getId())
.password(user.getPassword())
.enabled(user.getEnabled())
.authorities(authorities)
Expand Down
Loading