Skip to content

Commit

Permalink
Merge branch 'rhuandantas:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
victorts1991 authored Jul 7, 2024
2 parents f6cb699 + 7cae471 commit 8dfff3a
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 75 deletions.
28 changes: 14 additions & 14 deletions internal/adapters/http/handlers/cliente.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func NewCliente(cadastraClienteUC usecase.CadastrarClienteUseCase, pegaClientePo

func (h *Cliente) RegistraRotasCliente(server *echo.Echo) {
server.POST("/cliente", h.cadastra)
server.GET("/clientes/:cpf", h.pegaPorCpf, h.tokenJwt.VerifyToken)
server.GET("/clientes/:cpf", h.pegaPorCpf)
server.GET("/internal/clientes/:id", h.pegaPorID)
server.DELETE("/lgpd/clientes/delete", h.anonimizarClientLGPD)
}
Expand All @@ -43,11 +43,11 @@ func (h *Cliente) RegistraRotasCliente(server *echo.Echo) {
// @Accept json
// @Produce json
// @Param pedido body domain.ClienteRequest true "cria novo cliente"
// @Success 200 {object} domain.Cliente
// @Success 200 {object} domain.ClienteResponse
// @Router /cliente [post]
func (h *Cliente) cadastra(ctx echo.Context) error {
var (
cliente domain.Cliente
cliente domain.ClienteRequest
err error
)

Expand All @@ -74,13 +74,13 @@ func (h *Cliente) cadastra(ctx echo.Context) error {
// @Produce json
// @Param Authorization header string true "Insert your access token" default(Bearer <Add access token here>)
// @Param cpf path string true "cpf do cliente"
// @Success 200 {object} domain.Cliente
// @Success 200 {object} domain.ClienteResponse
// @Router /clientes/{cpf} [get]
func (h *Cliente) pegaPorCpf(ctx echo.Context) error {
cpf := ctx.Param("cpf")
c := &domain.Cliente{
Cpf: &cpf,

c := &domain.ClienteRequest{
Cpf: cpf,
}

if err := c.ValidateCPF(); err != nil {
Expand All @@ -99,7 +99,7 @@ func (h *Cliente) pegaPorCpf(ctx echo.Context) error {

ctx.Response().Header().Set("Authorization", token)

return ctx.JSON(http.StatusOK, cliente)
return ctx.JSON(http.StatusOK, domain.NewClienteResponse(cliente))
}

// pegaPorID godoc
Expand All @@ -109,7 +109,7 @@ func (h *Cliente) pegaPorCpf(ctx echo.Context) error {
// @Produce json
// @Param Authorization header string true "Insert your access token" default(Bearer <Add access token here>)
// @Param id path string true "id do cliente"
// @Success 200 {object} domain.Cliente
// @Success 200 {object} domain.ClienteResponse
// @Router /clientes/{id} [get]
func (h *Cliente) pegaPorID(ctx echo.Context) error {
id := ctx.Param("id")
Expand All @@ -126,7 +126,7 @@ func (h *Cliente) pegaPorID(ctx echo.Context) error {
return ctx.JSON(http.StatusOK, cliente)
}

func (h *Cliente) validateClienteBody(c *domain.Cliente) error {
func (h *Cliente) validateClienteBody(c *domain.ClienteRequest) error {
if err := h.validator.ValidateStruct(c); err != nil {
return err
}
Expand All @@ -144,14 +144,14 @@ func (h *Cliente) validateClienteBody(c *domain.Cliente) error {
// @Accept json
// @Produce json
// @Param pedido body domain.LGPDClienteRequest true "anonimiza os dados do cliente"
// @Success 200 {object} domain.Cliente
// @Success 200 {object} domain.ClienteResponse
// @Router /lgpd/clientes/delete [delete]
func (h *Cliente) anonimizarClientLGPD(ctx echo.Context) error {
var (
cliente domain.Cliente
cliente domain.ClienteRequest
err error
)

if err = ctx.Bind(&cliente); err != nil {
return serverErr.HandleError(ctx, serverErr.BadRequest.New(err.Error()))
}
Expand All @@ -164,7 +164,7 @@ func (h *Cliente) anonimizarClientLGPD(ctx echo.Context) error {
if err != nil {
return serverErr.HandleError(ctx, errorx.Cast(err))
}

return ctx.NoContent(http.StatusOK)

}
4 changes: 2 additions & 2 deletions internal/adapters/http/handlers/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ func (h *Login) RegistraRotasLogin(server *echo.Echo) {
// @Router /login/{cpf} [get]
func (h *Login) login(ctx echo.Context) error {
cpf := ctx.Param("cpf")
c := &domain.Cliente{
Cpf: &cpf,
c := &domain.ClienteRequest{
Cpf: cpf,
}

if err := c.ValidateCPF(); err != nil {
Expand Down
27 changes: 4 additions & 23 deletions internal/adapters/repository/cliente.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package repository
import (
"context"
"fiap-tech-challenge-api/internal/core/domain"
"github.com/joomcode/errorx"
db "github.com/rhuandantas/fiap-tech-challenge-commons/pkg/db/mysql"
_error "github.com/rhuandantas/fiap-tech-challenge-commons/pkg/errors"
"github.com/joomcode/errorx"
"xorm.io/xorm"
)

Expand All @@ -20,7 +20,6 @@ type ClienteRepo interface {
PesquisaPorCPF(ctx context.Context, cliente *domain.Cliente) (*domain.Cliente, error)
PesquisaPorId(ctx context.Context, id int64) (*domain.Cliente, error)
Anonimizar(ctx context.Context, cliente *domain.Cliente) error

}

func NewClienteRepo(connector db.DBConnector) ClienteRepo {
Expand Down Expand Up @@ -79,28 +78,10 @@ func (r *cliente) PesquisaPorId(ctx context.Context, id int64) (*domain.Cliente,
return &c, nil
}

func (r *cliente) Anonimizar(ctx context.Context, cliente *domain.Cliente) error {

newCliente := domain.Cliente{
Cpf: nil,
Nome: nil,
Email: nil,
Telefone: nil,
}

found, err := r.session.Context(ctx).Get(&cliente)
if err != nil {
return err
}

if !found {
return _error.NotFound.New("cliente não encontrado")
}

affected, err := r.session.Context(ctx).ID(&cliente.Id).Update(newCliente)
func (r *cliente) Anonimizar(ctx context.Context, cli *domain.Cliente) error {
_, err := r.session.Context(ctx).ID(cli.Id).Update(cli)
if err != nil {
return errorx.InternalError.New(err.Error())
}
_ = affected
return nil
}
}
73 changes: 54 additions & 19 deletions internal/core/domain/cliente.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package domain

import (
"bytes"
"database/sql"
"errors"
"fiap-tech-challenge-api/internal/core/commons"
"time"
Expand All @@ -16,23 +17,59 @@ type ClienteRequest struct {
Email string `json:"email" validate:"email"`
Telefone string `json:"telefone"`
}
type ClienteResponse struct {
Cpf string `json:"cpf" validate:"required" xorm:"unique"`
Nome string `json:"nome" validate:"required"`
Email string `json:"email" validate:"email"`
Telefone string `json:"telefone"`
CreatedAt time.Time `json:"created_at" xorm:"created"`
UpdatedAt time.Time `json:"updated_at" xorm:"updated"`
}

type LGPDClienteRequest struct {
Cpf string `json:"cpf" validate:"required" xorm:"unique"`
Cpf string `json:"cpf" validate:"required" xorm:"unique"`
}

type Cliente struct {
Id int64 `json:"id" xorm:"pk autoincr 'cliente_id'"`
Cpf *string `json:"cpf" xorm:"null unique"`
Nome *string `json:"nome" xorm:"null"`
Email *string `json:"email" xorm:"null"`
Telefone *string `json:"telefone" xorm:"null"`
CreatedAt time.Time `json:"created_at" xorm:"created"`
UpdatedAt time.Time `json:"updated_at" xorm:"updated"`
Id int64 `json:"id" xorm:"pk autoincr 'cliente_id'"`
Cpf sql.NullString `json:"cpf" xorm:"null"`
Nome sql.NullString `json:"nome" xorm:"null"`
Email sql.NullString `json:"email" xorm:"null"`
Telefone sql.NullString `json:"telefone" xorm:"null"`
CreatedAt time.Time `json:"created_at" xorm:"created"`
UpdatedAt time.Time `json:"updated_at" xorm:"updated"`
}

func NewClient(cli *ClienteRequest) *Cliente {
return &Cliente{
Cpf: setNullString(cli.Cpf),
Nome: setNullString(cli.Nome),
Email: setNullString(cli.Email),
Telefone: setNullString(cli.Telefone),
}
}

func (c *Cliente) ValidateCPF() error {
if !brdoc.IsCPF(DerefString(c.Cpf)) {
func NewClienteResponse(cli *Cliente) *ClienteResponse {
return &ClienteResponse{
Cpf: cli.Cpf.String,
Nome: cli.Nome.String,
Email: cli.Email.String,
Telefone: cli.Telefone.String,
CreatedAt: cli.CreatedAt,
UpdatedAt: cli.UpdatedAt,
}
}

func setNullString(str string) sql.NullString {
if str == "" {
return sql.NullString{}
}

return sql.NullString{String: str, Valid: true}
}

func (c *ClienteRequest) ValidateCPF() error {
if !brdoc.IsCPF(c.Cpf) {
return errors.New(commons.CpfInvalido)
}

Expand All @@ -42,22 +79,20 @@ func (c *Cliente) ValidateCPF() error {
}

func DerefString(s *string) string {
if s != nil {
return *s
}
if s != nil {
return *s
}

return ""
return ""
}


func (c *Cliente) limpaCaracteresEspeciais() {
func (c *ClienteRequest) limpaCaracteresEspeciais() {
buf := bytes.NewBufferString("")
for _, r := range DerefString(c.Cpf) {
for _, r := range c.Cpf {
if unicode.IsDigit(r) {
buf.WriteRune(r)
}
}

varAux := string(buf.String())
c.Cpf = &varAux
c.Cpf = buf.String()
}
19 changes: 16 additions & 3 deletions internal/core/usecase/cadastra_cliente.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package usecase

import (
"context"
"errors"
"fiap-tech-challenge-api/internal/adapters/repository"
"fiap-tech-challenge-api/internal/core/domain"
_error "github.com/rhuandantas/fiap-tech-challenge-commons/pkg/errors"
)

type CadastrarClienteUseCase interface {
Cadastra(ctx context.Context, cliente *domain.Cliente) (*domain.Cliente, error)
Cadastra(ctx context.Context, cliente *domain.ClienteRequest) (*domain.Cliente, error)
}

type cadastraClienteUC struct {
Expand All @@ -20,6 +22,17 @@ func NewCadastraCliente(clienteRepo repository.ClienteRepo) CadastrarClienteUseC
}
}

func (uc *cadastraClienteUC) Cadastra(ctx context.Context, cliente *domain.Cliente) (*domain.Cliente, error) {
return uc.clienteRepo.Insere(ctx, cliente)
func (uc *cadastraClienteUC) Cadastra(ctx context.Context, cliente *domain.ClienteRequest) (*domain.Cliente, error) {
found, err := uc.clienteRepo.PesquisaPorCPF(ctx, domain.NewClient(cliente))
if err != nil {
if errors.Is(err, _error.BadRequest.New("cliente não encontrado")) {
return nil, err
}
}

if found != nil {
return found, _error.BadRequest.New("cliente já existe")
}

return uc.clienteRepo.Insere(ctx, domain.NewClient(cliente))
}
15 changes: 11 additions & 4 deletions internal/core/usecase/cadastra_cliente_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package usecase

import (
"context"
"database/sql"
"errors"
"fiap-tech-challenge-api/internal/core/domain"
mock_repo "fiap-tech-challenge-api/test/mock/repository"
Expand All @@ -25,21 +26,27 @@ var _ = Describe("cadastra cliente use case testes", func() {
})

Context("cadastra cliente", func() {
clienteDTO := &domain.Cliente{
Id: 1,
clienteDTO := &domain.ClienteRequest{
Nome: "Mock",
Cpf: "20815919018",
Email: "[email protected]",
}
dto := &domain.Cliente{
Nome: sql.NullString{String: "Mock"},
Cpf: sql.NullString{String: "20815919018"},
Email: sql.NullString{String: "[email protected]"},
}
It("cadastra cliente com sucesso", func() {
repo.EXPECT().Insere(ctx, clienteDTO).Return(clienteDTO, nil)
repo.EXPECT().PesquisaPorCPF(gomock.Any(), gomock.Any()).Return(nil, nil)
repo.EXPECT().Insere(ctx, gomock.Any()).Return(dto, nil)
cli, err := cadastraCliente.Cadastra(ctx, clienteDTO)

gomega.Expect(err).To(gomega.BeNil())
gomega.Expect(cli).ToNot(gomega.BeNil())
})
It("falha ao cadastrar cliente", func() {
repo.EXPECT().Insere(ctx, clienteDTO).Return(nil, errors.New("mock error"))
repo.EXPECT().PesquisaPorCPF(gomock.Any(), gomock.Any()).Return(nil, nil)
repo.EXPECT().Insere(ctx, gomock.Any()).Return(nil, errors.New("mock error"))
cli, err := cadastraCliente.Cadastra(ctx, clienteDTO)

gomega.Expect(err.Error()).To(gomega.Equal("mock error"))
Expand Down
6 changes: 3 additions & 3 deletions internal/core/usecase/cliente_por_cpf.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

type PesquisarCliente interface {
PesquisaPorCPF(ctx context.Context, cliente *domain.Cliente) (*domain.Cliente, error)
PesquisaPorCPF(ctx context.Context, cliente *domain.ClienteRequest) (*domain.Cliente, error)
PesquisaPorID(ctx context.Context, id int64) (*domain.Cliente, error)
}

Expand All @@ -21,8 +21,8 @@ func NewPesquisarCliente(clienteRepo repository.ClienteRepo) PesquisarCliente {
}
}

func (uc *pesquisarClienteUC) PesquisaPorCPF(ctx context.Context, cliente *domain.Cliente) (*domain.Cliente, error) {
return uc.clienteRepo.PesquisaPorCPF(ctx, cliente)
func (uc *pesquisarClienteUC) PesquisaPorCPF(ctx context.Context, cliente *domain.ClienteRequest) (*domain.Cliente, error) {
return uc.clienteRepo.PesquisaPorCPF(ctx, domain.NewClient(cliente))
}
func (uc *pesquisarClienteUC) PesquisaPorID(ctx context.Context, id int64) (*domain.Cliente, error) {
return uc.clienteRepo.PesquisaPorId(ctx, id)
Expand Down
13 changes: 9 additions & 4 deletions internal/core/usecase/cliente_por_cpf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package usecase

import (
"context"
"database/sql"
"fiap-tech-challenge-api/internal/core/domain"
mock_repo "fiap-tech-challenge-api/test/mock/repository"

Expand All @@ -24,21 +25,25 @@ var _ = Describe("pesquisa cliente use case testes", func() {
})

Context("pesquisa cliente", func() {
clienteDTO := &domain.Cliente{
Id: 1,
clienteDTO := &domain.ClienteRequest{
Nome: "Mock",
Cpf: "20815919018",
Email: "[email protected]",
}
dto := &domain.Cliente{
Nome: sql.NullString{String: "Mock"},
Cpf: sql.NullString{String: "20815919018"},
Email: sql.NullString{String: "[email protected]"},
}
It("pesquisa por cpf com sucesso", func() {
repo.EXPECT().PesquisaPorCPF(ctx, clienteDTO).Return(clienteDTO, nil)
repo.EXPECT().PesquisaPorCPF(gomock.Any(), gomock.Any()).Return(dto, nil)
cli, err := pesquisaPorCpf.PesquisaPorCPF(ctx, clienteDTO)

gomega.Expect(err).To(gomega.BeNil())
gomega.Expect(cli).ToNot(gomega.BeNil())
})
It("pesquisa por id com sucesso", func() {
repo.EXPECT().PesquisaPorId(ctx, gomock.Any()).Return(clienteDTO, nil)
repo.EXPECT().PesquisaPorId(ctx, gomock.Any()).Return(dto, nil)
cli, err := pesquisaPorCpf.PesquisaPorID(ctx, 1)

gomega.Expect(err).To(gomega.BeNil())
Expand Down
Loading

0 comments on commit 8dfff3a

Please sign in to comment.