Skip to content

Commit

Permalink
feat: cadastro de produto para usuário logado
Browse files Browse the repository at this point in the history
  • Loading branch information
almeidawilliam committed Apr 28, 2021
1 parent 812e9c2 commit 04c9929
Show file tree
Hide file tree
Showing 9 changed files with 315 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package br.com.zupacademy.william.ecommerce.produto;

import br.com.zupacademy.william.ecommerce.categoria.Categoria;
import br.com.zupacademy.william.ecommerce.produto.caracteristica.ProdutoCaracteristica;
import br.com.zupacademy.william.ecommerce.usuario.Usuario;
import io.jsonwebtoken.lang.Assert;
import org.hibernate.annotations.CreationTimestamp;

import javax.persistence.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Set;

@Entity
public class Produto {

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

private String nome;
private BigDecimal valor;
private int quantidadeDisponivel;
private String descricao;

@OneToMany(cascade = CascadeType.ALL)
private Set<ProdutoCaracteristica> caracteristicas;

@ManyToOne
@JoinColumn(name = "id_categoria")
private Categoria categoria;

@ManyToOne
@JoinColumn(name = "id_usuario")
private Usuario donoDoProduto;

@CreationTimestamp
private LocalDateTime instanteCriacao = LocalDateTime.now();

public Produto(String nome, BigDecimal valor, int quantidadeDisponivel, String descricao,
Set<ProdutoCaracteristica> caracteristicas, Categoria categoria, Usuario donoDoProduto) {
this.nome = nome;
this.valor = valor;
this.quantidadeDisponivel = quantidadeDisponivel;
this.descricao = descricao;
this.caracteristicas = caracteristicas;
this.categoria = categoria;
this.donoDoProduto = donoDoProduto;

Assert.isTrue(this.caracteristicas.size() >= 3, "É necessário ao menos 3 características para um produto");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package br.com.zupacademy.william.ecommerce.produto;

import br.com.zupacademy.william.ecommerce.categoria.Categoria;
import br.com.zupacademy.william.ecommerce.categoria.CategoriaRepository;
import br.com.zupacademy.william.ecommerce.usuario.Usuario;
import br.com.zupacademy.william.ecommerce.validation.ProibeCaracteristicaComNomeIgualValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;

import javax.persistence.EntityNotFoundException;
import javax.validation.Valid;
import java.util.Optional;

@RestController
@RequestMapping("/produtos")
public class ProdutoController {

@Autowired
private ProdutoRepository produtoRepository;

@Autowired
private CategoriaRepository categoriaRepository;

@InitBinder
public void init(WebDataBinder webDataBinder) {
webDataBinder.addValidators(new ProibeCaracteristicaComNomeIgualValidator());
}

@PostMapping
public ResponseEntity criar(@RequestBody @Valid ProdutoInputDto produtoInputDto,
@AuthenticationPrincipal Usuario usuarioLogado) {
Optional<Categoria> possivelCategoria = categoriaRepository.findById(produtoInputDto.getIdCategoria());

if (possivelCategoria.isEmpty()) {
throw new EntityNotFoundException(String.format("Não existe uma categoria com id %d", produtoInputDto.getIdCategoria()));
}

Produto novoProduto = produtoInputDto.toModel(possivelCategoria.get(), usuarioLogado);
produtoRepository.save(novoProduto);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package br.com.zupacademy.william.ecommerce.produto;

import br.com.zupacademy.william.ecommerce.categoria.Categoria;
import br.com.zupacademy.william.ecommerce.produto.caracteristica.ProdutoCaracteristica;
import br.com.zupacademy.william.ecommerce.produto.caracteristica.ProdutoCaracteristicaInputDto;
import br.com.zupacademy.william.ecommerce.usuario.Usuario;
import br.com.zupacademy.william.ecommerce.validation.annotation.ExistsId;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.Length;

import javax.validation.Valid;
import javax.validation.constraints.*;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class ProdutoInputDto {

@NotBlank
private String nome;

@NotNull
@Positive
private BigDecimal valor;

@NotNull
@PositiveOrZero
@JsonProperty("quantidade_disponivel")
private int quantidadeDisponivel;

@NotBlank
@Length(max = 1000)
private String descricao;

@Size(min = 3, max = 100)
@Valid
private List<ProdutoCaracteristicaInputDto> caracteristicas;

@ExistsId(domainClass = Categoria.class, fieldName = "id")
@JsonProperty("id_categoria")
private Long idCategoria;

public ProdutoInputDto(String nome, BigDecimal valor, int quantidadeDisponivel, String descricao, List<ProdutoCaracteristicaInputDto> produtoCaracteristicasInputDto, Long idCategoria) {
this.nome = nome;
this.valor = valor;
this.quantidadeDisponivel = quantidadeDisponivel;
this.descricao = descricao;
this.caracteristicas = produtoCaracteristicasInputDto;
this.idCategoria = idCategoria;
}

public Produto toModel(Categoria categoriaDoProduto, Usuario donoDoProduto) {
Set<ProdutoCaracteristica> crodutoCaracteristicas = new HashSet<>();

if (!this.caracteristicas.isEmpty()) {
crodutoCaracteristicas.addAll(this.caracteristicas.stream()
.map(ProdutoCaracteristicaInputDto::toModel)
.collect(Collectors.toList()));
}

return new Produto(
this.nome,
this.valor,
this.quantidadeDisponivel,
this.descricao,
crodutoCaracteristicas,
categoriaDoProduto,
donoDoProduto);
}

public Long getIdCategoria() {
return idCategoria;
}

public List<ProdutoCaracteristicaInputDto> getCaracteristicas() {
return caracteristicas;
}

public boolean temCaracteristicasRepetidas() {
List<String> caracteristicasDepoisDoDistinct = this.caracteristicas.stream()
.map(ProdutoCaracteristicaInputDto::getNome)
.distinct()
.collect(Collectors.toList());

return (caracteristicasDepoisDoDistinct.size() != this.caracteristicas.size());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package br.com.zupacademy.william.ecommerce.produto;

import org.springframework.data.jpa.repository.JpaRepository;

public interface ProdutoRepository extends JpaRepository<Produto, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package br.com.zupacademy.william.ecommerce.produto.caracteristica;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.util.Objects;

@Entity
public class ProdutoCaracteristica {

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

private String nome;
private String descricao;

public ProdutoCaracteristica(String nome, String descricao) {
this.nome = nome;
this.descricao = descricao;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProdutoCaracteristica that = (ProdutoCaracteristica) o;
return nome.equals(that.nome);
}

@Override
public int hashCode() {
return Objects.hash(nome);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package br.com.zupacademy.william.ecommerce.produto.caracteristica;

import javax.validation.constraints.NotBlank;

public class ProdutoCaracteristicaInputDto {

@NotBlank
private String nome;

@NotBlank
private String descricao;

public ProdutoCaracteristicaInputDto(String nome, String descricao) {
this.nome = nome;
this.descricao = descricao;
}

public ProdutoCaracteristica toModel() {
return new ProdutoCaracteristica(this.nome, this.descricao);
}



public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}

public String getDescricao() {
return descricao;
}

public void setDescricao(String descricao) {
this.descricao = descricao;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ protected void configure(HttpSecurity http) throws Exception {
.antMatchers(HttpMethod.GET, "/categorias/*").permitAll()
.antMatchers(HttpMethod.POST, "/usuarios").permitAll()
.antMatchers(HttpMethod.POST, "/auth").permitAll()
.anyRequest().authenticated()
.antMatchers(HttpMethod.POST, "/produtos").permitAll()
.anyRequest().permitAll()
//h2-console
.and().headers().frameOptions().disable()
.and().csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package br.com.zupacademy.william.ecommerce.validation;

import br.com.zupacademy.william.ecommerce.produto.ProdutoInputDto;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

public class ProibeCaracteristicaComNomeIgualValidator implements Validator {

@Override
public boolean supports(Class<?> aClass) {
return ProdutoInputDto.class.isAssignableFrom(aClass);
}

@Override
public void validate(Object target, Errors errors) {
if (errors.hasErrors()) {
return;
}

ProdutoInputDto request = (ProdutoInputDto) target;
boolean temCaracteristicasRepetidas = request.temCaracteristicasRepetidas();

if (temCaracteristicasRepetidas) {
errors.rejectValue("caracteristicas", null, "Características repetidas não são aceitas");
}
}
}
20 changes: 17 additions & 3 deletions src/main/resources/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ NotBlank={0} é obrigatório(a)
Email={0} deve ser um e-mail válido
UniqueValue={0} já existe no banco de dados
ExistsId={0} não existe no banco de dados
Length={0} deve ter o tamanho entre {2} e {1}

Length={0} deve ter o tamanho entre {2} e {1} caracteres
Positive={0} deve ser maior que 0
PositiveOrZero={0} deve ser maior ou igual a 0
Size={0} deve ser de tamanho entre {2} e {1}

#UsuarioInputDto
usuarioInputDto.login=Login do usuário
Expand All @@ -14,4 +16,16 @@ categoriaInputDto.nome=Nome da categoria

#LoginForm
loginForm.login=Login do usuário
loginForm.senha=Senha do usuário
loginForm.senha=Senha do usuário

#ProdutoInputDto
produtoInputDto.nome=Nome do produto
produtoInputDto.valor=Valor do produto
produtoInputDto.quantidadeDisponivel=Quantidade disponível do produto
produtoInputDto.descricao=Descrição do produto
produtoInputDto.idCategoria=Categoria do produto
#produtoInputDto.caracteristicas=Características do produto

#ProdutoCaracteristicaInputDto
produtoCaracteristicaInputDto.nome=Nome da característica
produtoCaracteristicaInputDto.descricao=Descrição da característica

0 comments on commit 04c9929

Please sign in to comment.