Skip to content

Commit

Permalink
Merge pull request #4 from opcruz/dev
Browse files Browse the repository at this point in the history
add signup services and some validations
  • Loading branch information
opcruz committed Apr 12, 2024
2 parents 8aa4f78 + 14e50ce commit fc078ab
Show file tree
Hide file tree
Showing 22 changed files with 217 additions and 29 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@ mvn spring-boot:run

5. Access the API:

[API testing](http://localhost:8080/ecommerce/swagger-ui/index.html)
- [API testing](http://localhost:8080/ecommerce/api/v1/swagger-ui/index.html)

4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.demo.sqlite.controllers;

import com.demo.sqlite.dtos.OrderResultDTO;
import com.demo.sqlite.dtos.OrderResultResponseDTO;
import com.demo.sqlite.models.Order;
import com.demo.sqlite.security.UserAuthenticateInfo;
import com.demo.sqlite.services.OrdersService;
Expand Down Expand Up @@ -31,8 +31,8 @@ public OrderController(@Autowired OrdersService orderService) {

@GetMapping(path = "/{order_id}/details")
@Operation(summary = "List orders", security = @SecurityRequirement(name = "bearerAuth"))
public @ResponseBody ResponseEntity<OrderResultDTO> orderDetails(@PathVariable(value = "order_id") Integer orderId,
Authentication auth) {
public @ResponseBody ResponseEntity<OrderResultResponseDTO> orderDetails(@PathVariable(value = "order_id") Integer orderId,
Authentication auth) {
int clientId = UserAuthenticateInfo.fromAuth(auth).getUserId();
return orderService.orderDetails(clientId, orderId)
.map(result -> ResponseEntity.ok().body(result))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.demo.sqlite.controllers;

import com.demo.sqlite.dtos.ShoppingCartResultDTO;
import com.demo.sqlite.dtos.ShoppingCartResultResponseDTO;
import com.demo.sqlite.exceptions.ValidationError;
import com.demo.sqlite.models.Order;
import com.demo.sqlite.models.ShoppingCart;
Expand Down Expand Up @@ -28,9 +28,9 @@ public ShoppingCartController(@Autowired ShoppingCartService shoppingCartService

@GetMapping
@Operation(summary = "List cart products", security = @SecurityRequirement(name = "bearerAuth"))
public @ResponseBody ResponseEntity<ShoppingCartResultDTO> getShoppingCart(Authentication auth) {
public @ResponseBody ResponseEntity<ShoppingCartResultResponseDTO> getShoppingCart(Authentication auth) {
int clientId = UserAuthenticateInfo.fromAuth(auth).getUserId();
ShoppingCartResultDTO shoppingCart = shoppingCartService.getShoppingCart(clientId);
ShoppingCartResultResponseDTO shoppingCart = shoppingCartService.getShoppingCart(clientId);
return ResponseEntity.ok().body(shoppingCart);
}

Expand Down
41 changes: 40 additions & 1 deletion src/main/java/com/demo/sqlite/controllers/UserController.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
package com.demo.sqlite.controllers;

import com.demo.sqlite.dtos.ClientSignupRequestDTO;
import com.demo.sqlite.dtos.EmployeeSignupRequestDTO;
import com.demo.sqlite.dtos.LoginRequestDTO;
import com.demo.sqlite.dtos.LoginResponseDTO;
import com.demo.sqlite.exceptions.ValidationError;
import com.demo.sqlite.models.Client;
import com.demo.sqlite.models.Employee;
import com.demo.sqlite.services.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@RestController
@RequestMapping(value = "/users")
public class UserController {
Expand All @@ -25,7 +32,7 @@ public UserController(@Autowired UserService userService) {
@PostMapping("/login")
@Operation(summary = "Login employees")
public @ResponseBody ResponseEntity<LoginResponseDTO> login(
@RequestBody LoginRequestDTO requestDTO,
@Valid @RequestBody LoginRequestDTO requestDTO,
@Parameter(
name = "role",
description = "Role of user",
Expand All @@ -44,4 +51,36 @@ public UserController(@Autowired UserService userService) {

}

@PostMapping("/client/signup")
@Operation(summary = "Signup new client")
public @ResponseBody ResponseEntity<Map<String, String>> signupClient(@Valid @RequestBody ClientSignupRequestDTO requestDTO) {
try {
Client newClient = userService.signupClient(requestDTO);
return ResponseEntity.status(HttpStatus.CREATED)
.body(Map.of(
"id", String.valueOf(newClient.getId()),
"name", newClient.getName(),
"email", newClient.getEmail()
));
} catch (ValidationError e) {
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY).body(Map.of("message", e.getMessage()));
}
}

@PostMapping("/employee/signup")
@Operation(summary = "Signup new employee")
public @ResponseBody ResponseEntity<Map<String, String>> signupEmployee(@Valid @RequestBody EmployeeSignupRequestDTO requestDTO) {
try {
Employee newEmployee = userService.signupEmployee(requestDTO);
return ResponseEntity.status(HttpStatus.CREATED)
.body(Map.of(
"id", String.valueOf(newEmployee.getId()),
"name", newEmployee.getName(),
"email", newEmployee.getEmail()
));
} catch (ValidationError e) {
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY).body(Map.of("message", e.getMessage()));
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.demo.sqlite.controllers;

import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class ValidationExceptionHandler {

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidationExceptions(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return ResponseEntity.badRequest().body(errors);
}

}
39 changes: 39 additions & 0 deletions src/main/java/com/demo/sqlite/dtos/ClientSignupRequestDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.demo.sqlite.dtos;

import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
@Schema(description = "Signup Client Request DTO")
public class ClientSignupRequestDTO {
@Schema(example = "Carlos")
@NotBlank(message = "Field 'name' is required")
private String name;
@Schema(example = "Cruz")
@NotBlank(message = "Field 'surnames' is required")
private String surnames;
@Schema(example = "Av. Principal 123")
@NotBlank(message = "Field 'direction' is required")
private String direction;
@Schema(example = "Jalisco")
@NotBlank(message = "Field 'state' is required")
private String state;
@Schema(example = "45000")
@NotBlank(message = "Field 'postal_code' is required")
private String postal_code;
@Schema(example = "3300000000")
@NotBlank(message = "Field 'phone' is required")
private String phone;
@Schema(example = "carlos@example.com")
@NotBlank(message = "Field 'email' is required")
@Email(message = "Field 'email' must be a valid email address")
private String email;
@Schema(example = "ok")
@NotBlank(message = "Field 'password' is required")
private String password;

}
27 changes: 27 additions & 0 deletions src/main/java/com/demo/sqlite/dtos/EmployeeSignupRequestDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.demo.sqlite.dtos;

import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
@Schema(description = "Signup Client Request DTO")
public class EmployeeSignupRequestDTO {
@Schema(example = "Felipe")
@NotBlank(message = "Field 'name' is required")
private String name;
@Schema(example = "Contreras")
@NotBlank(message = "Field 'surnames' is required")
private String surnames;
@Schema(example = "felipe@example.com")
@NotBlank(message = "Field 'email' is required")
@Email(message = "Field 'email' must be a valid email address")
private String email;
@Schema(example = "ok")
@NotBlank(message = "Field 'password' is required")
private String password;

}
3 changes: 3 additions & 0 deletions src/main/java/com/demo/sqlite/dtos/LoginRequestDTO.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@

import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
@Schema(description = "Login Request DTO")
public class LoginRequestDTO {
@Schema(example = "john@example.com")
@NotBlank(message = "Field 'email' is required")
String email;
@Schema(example = "ok")
@NotBlank(message = "Field 'password' is required")
String password;

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
@Builder
public class OrderResultDTO {
public class OrderResultResponseDTO {

private Integer id;
private String paymentMethod;
Expand Down
1 change: 0 additions & 1 deletion src/main/java/com/demo/sqlite/dtos/ProductCartDTO.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
public class ProductCartDTO {

private Integer cartId;

private Integer quantity;
private Stock stock;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
@Builder
public class ShoppingCartResultDTO {
public class ShoppingCartResultResponseDTO {

private Integer clientId;
private Double total;
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/com/demo/sqlite/models/Client.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.demo.sqlite.models;

import com.demo.sqlite.dtos.ClientSignupRequestDTO;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
Expand Down Expand Up @@ -27,4 +28,17 @@ public class Client {
private String email;
private String password_hash;

public static Client fromSignupDTO(ClientSignupRequestDTO clientSignupDTO, String passwordHash) {
return Client.builder()
.name(clientSignupDTO.getName())
.surnames(clientSignupDTO.getSurnames())
.direction(clientSignupDTO.getDirection())
.state(clientSignupDTO.getState())
.postal_code(clientSignupDTO.getPostal_code())
.phone(clientSignupDTO.getPhone())
.email(clientSignupDTO.getEmail())
.password_hash(passwordHash)
.build();
}

}
10 changes: 10 additions & 0 deletions src/main/java/com/demo/sqlite/models/Employee.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.demo.sqlite.models;

import com.demo.sqlite.dtos.EmployeeSignupRequestDTO;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
Expand All @@ -23,4 +24,13 @@ public class Employee {
private String email;
private String password_hash;

public static Employee fromSignupDTO(EmployeeSignupRequestDTO signupDTO, String passwordHash) {
return Employee.builder()
.name(signupDTO.getName())
.surnames(signupDTO.getSurnames())
.email(signupDTO.getEmail())
.password_hash(passwordHash)
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ public interface ClientRepository extends CrudRepository<Client, Integer> {
@Query(value = "SELECT u FROM clients u WHERE u.email = :email AND u.password_hash = :password_hash")
Optional<Client> findClientByEmailAndPassword(@Param("email") String email, @Param("password_hash") String passwordHash);

@Query(value = "SELECT u.id FROM clients u WHERE u.email = :email")
Optional<Integer> existEmail(@Param("email") String email);

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
@Query(value = "SELECT u FROM employees u WHERE u.email = :email AND u.password_hash = :password_hash")
Optional<Employee> findEmployeeByEmailAndPassword(@Param("email") String email, @Param("password_hash") String passwordHash);
@Query(value = "SELECT u.id FROM employees u WHERE u.email = :email")
Optional<Integer> existEmail(@Param("email") String email);

}
3 changes: 1 addition & 2 deletions src/main/java/com/demo/sqlite/security/JWTCoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
public class JWTCoder {

public static final String ISSUER = "ecommerce";
public static final long TIME_EXPIRATION = 600000;

public static final long TIME_EXPIRATION = 30 * 60 * 1000; // 30 minutes
public static final SecretKey SECRET_KEY = Jwts.SIG.HS256.key().build();


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.addFilterBefore(new JWTAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(d -> d.requestMatchers(HttpMethod.GET, "/").permitAll())
.authorizeHttpRequests(d -> d.requestMatchers(HttpMethod.POST, "/users/**").permitAll())
.authorizeHttpRequests(d -> d.requestMatchers(HttpMethod.GET, "/swagger-ui/**", "/v3/api-docs/**").permitAll())
.authorizeHttpRequests(d -> d.requestMatchers(HttpMethod.GET, "/swagger-ui/**", "/api-docs/**").permitAll())
.authorizeHttpRequests(d -> d.requestMatchers(HttpMethod.GET, "/lookup/**").permitAll())
.authorizeHttpRequests(d -> d.requestMatchers(HttpMethod.POST, "/stocks/**").hasRole(Roles.EMPLOYEE.getRole()))
.authorizeHttpRequests(d -> d.requestMatchers(HttpMethod.PUT, "/stocks/**").hasRole(Roles.EMPLOYEE.getRole()))
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/demo/sqlite/services/OrdersService.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.demo.sqlite.services;

import com.demo.sqlite.dtos.OrderResultDTO;
import com.demo.sqlite.dtos.OrderResultResponseDTO;
import com.demo.sqlite.dtos.ProductOrderDTO;
import com.demo.sqlite.models.Order;
import com.demo.sqlite.repositories.OrderDetailsRepository;
Expand All @@ -27,15 +27,15 @@ public List<Order> findByClientId(int clientId) {
return orderRepository.findByClientId(clientId);
}

public Optional<OrderResultDTO> orderDetails(int clientId, int orderId) {
public Optional<OrderResultResponseDTO> orderDetails(int clientId, int orderId) {
Optional<Order> order = orderRepository.findByIdAndClientId(clientId, orderId);
return order.map(value -> {
List<ProductOrderDTO> products = orderDetailsRepository.findByOrderId(value.getId());
double total =
products.stream()
.mapToDouble(product -> product.getPrice() * product.getQuantity())
.sum();
return OrderResultDTO.builder()
return OrderResultResponseDTO.builder()
.id(value.getId())
.paymentMethod(value.getPayment_method())
.total(total)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.demo.sqlite.dtos.ProductCartDTO;
import com.demo.sqlite.dtos.ShoppingCartJoined;
import com.demo.sqlite.dtos.ShoppingCartResultDTO;
import com.demo.sqlite.dtos.ShoppingCartResultResponseDTO;
import com.demo.sqlite.exceptions.ValidationError;
import com.demo.sqlite.models.Order;
import com.demo.sqlite.models.OrderDetails;
Expand Down Expand Up @@ -40,10 +40,10 @@ public ShoppingCartService(@Autowired StockRepository stockRepository,
this.orderDetailsRepository = orderDetailsRepository;
}

public ShoppingCartResultDTO getShoppingCart(int clientId) {
public ShoppingCartResultResponseDTO getShoppingCart(int clientId) {
Iterable<ShoppingCartJoined> shoppingCarts = shoppingCartRepository.filterByClientId(clientId);

ShoppingCartResultDTO.ShoppingCartResultDTOBuilder builder = ShoppingCartResultDTO.builder();
ShoppingCartResultResponseDTO.ShoppingCartResultResponseDTOBuilder builder = ShoppingCartResultResponseDTO.builder();
builder.clientId(clientId);

double total = 0.0;
Expand Down
Loading

0 comments on commit fc078ab

Please sign in to comment.