From e97f7fbc8bf7fc5dff0afe9e5e760746194905d0 Mon Sep 17 00:00:00 2001 From: Victor Toupitzen Specian Date: Sat, 15 Jun 2024 17:30:49 -0300 Subject: [PATCH] add /lgpd/clientes/delete endpoint --- internal/adapters/http/handlers/cliente.go | 39 ++++++++++++++++++++-- internal/adapters/http/handlers/login.go | 2 +- internal/adapters/repository/cliente.go | 30 ++++++++++++++++- internal/core/domain/cliente.go | 28 ++++++++++++---- internal/core/usecase/lgpd.go | 26 +++++++++++++++ wire.go | 1 + wire_gen.go | 3 +- 7 files changed, 117 insertions(+), 12 deletions(-) create mode 100644 internal/core/usecase/lgpd.go diff --git a/internal/adapters/http/handlers/cliente.go b/internal/adapters/http/handlers/cliente.go index c13edba..1a1e87f 100644 --- a/internal/adapters/http/handlers/cliente.go +++ b/internal/adapters/http/handlers/cliente.go @@ -15,14 +15,16 @@ import ( type Cliente struct { cadastraClienteUC usecase.CadastrarClienteUseCase pegaClienteUC usecase.PesquisarCliente + lgpd usecase.LGPD validator util.Validator tokenJwt auth.Token } -func NewCliente(cadastraClienteUC usecase.CadastrarClienteUseCase, pegaClientePorCPFUC usecase.PesquisarCliente, validator util.Validator, tokenJwt auth.Token) *Cliente { +func NewCliente(cadastraClienteUC usecase.CadastrarClienteUseCase, pegaClientePorCPFUC usecase.PesquisarCliente, lgpd usecase.LGPD, validator util.Validator, tokenJwt auth.Token) *Cliente { return &Cliente{ cadastraClienteUC: cadastraClienteUC, pegaClienteUC: pegaClientePorCPFUC, + lgpd: lgpd, validator: validator, tokenJwt: tokenJwt, } @@ -32,6 +34,7 @@ func (h *Cliente) RegistraRotasCliente(server *echo.Echo) { server.POST("/cliente", h.cadastra) server.GET("/clientes/:cpf", h.pegaPorCpf, h.tokenJwt.VerifyToken) server.GET("/internal/clientes/:id", h.pegaPorID) + server.DELETE("/lgpd/clientes/delete", h.anonimizarClientLGPD) } // cadastra godoc @@ -75,8 +78,9 @@ func (h *Cliente) cadastra(ctx echo.Context) error { // @Router /clientes/{cpf} [get] func (h *Cliente) pegaPorCpf(ctx echo.Context) error { cpf := ctx.Param("cpf") + c := &domain.Cliente{ - Cpf: cpf, + Cpf: &cpf, } if err := c.ValidateCPF(); err != nil { @@ -133,3 +137,34 @@ func (h *Cliente) validateClienteBody(c *domain.Cliente) error { return nil } + +// delete godoc +// @Summary deleta um cliente +// @Tags Cliente +// @Accept json +// @Produce json +// @Param pedido body domain.LGPDClienteRequest true "anonimiza os dados do cliente" +// @Success 200 {object} domain.Cliente +// @Router /lgpd/clientes/delete [delete] +func (h *Cliente) anonimizarClientLGPD(ctx echo.Context) error { + var ( + cliente domain.Cliente + err error + ) + + if err = ctx.Bind(&cliente); err != nil { + return serverErr.HandleError(ctx, serverErr.BadRequest.New(err.Error())) + } + + if err := cliente.ValidateCPF(); err != nil { + return serverErr.HandleError(ctx, serverErr.BadRequest.New(err.Error())) + } + + err = h.lgpd.Anonimizar(ctx.Request().Context(), &cliente) + if err != nil { + return serverErr.HandleError(ctx, errorx.Cast(err)) + } + + return ctx.NoContent(http.StatusOK) + +} diff --git a/internal/adapters/http/handlers/login.go b/internal/adapters/http/handlers/login.go index d39cd35..9922d0c 100644 --- a/internal/adapters/http/handlers/login.go +++ b/internal/adapters/http/handlers/login.go @@ -36,7 +36,7 @@ func (h *Login) RegistraRotasLogin(server *echo.Echo) { func (h *Login) login(ctx echo.Context) error { cpf := ctx.Param("cpf") c := &domain.Cliente{ - Cpf: cpf, + Cpf: &cpf, } if err := c.ValidateCPF(); err != nil { diff --git a/internal/adapters/repository/cliente.go b/internal/adapters/repository/cliente.go index 5cbced1..8b6c3e4 100644 --- a/internal/adapters/repository/cliente.go +++ b/internal/adapters/repository/cliente.go @@ -5,7 +5,7 @@ import ( "fiap-tech-challenge-api/internal/core/domain" 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" ) @@ -19,6 +19,8 @@ type ClienteRepo interface { Insere(ctx context.Context, cliente *domain.Cliente) (*domain.Cliente, error) 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 { @@ -76,3 +78,29 @@ 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) + if err != nil { + return errorx.InternalError.New(err.Error()) + } + _ = affected + return nil +} \ No newline at end of file diff --git a/internal/core/domain/cliente.go b/internal/core/domain/cliente.go index 4462eb7..2b729fb 100644 --- a/internal/core/domain/cliente.go +++ b/internal/core/domain/cliente.go @@ -17,18 +17,22 @@ type ClienteRequest struct { Telefone string `json:"telefone"` } +type LGPDClienteRequest struct { + Cpf string `json:"cpf" validate:"required" xorm:"unique"` +} + type Cliente struct { Id int64 `json:"id" xorm:"pk autoincr 'cliente_id'"` - Cpf string `json:"cpf" validate:"required" xorm:"unique"` - Nome string `json:"nome" validate:"required"` - Email string `json:"email" validate:"email"` - Telefone string `json:"telefone"` + 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"` } func (c *Cliente) ValidateCPF() error { - if !brdoc.IsCPF(c.Cpf) { + if !brdoc.IsCPF(DerefString(c.Cpf)) { return errors.New(commons.CpfInvalido) } @@ -37,13 +41,23 @@ func (c *Cliente) ValidateCPF() error { return nil } +func DerefString(s *string) string { + if s != nil { + return *s + } + + return "" +} + + func (c *Cliente) limpaCaracteresEspeciais() { buf := bytes.NewBufferString("") - for _, r := range c.Cpf { + for _, r := range DerefString(c.Cpf) { if unicode.IsDigit(r) { buf.WriteRune(r) } } - c.Cpf = buf.String() + varAux := string(buf.String()) + c.Cpf = &varAux } diff --git a/internal/core/usecase/lgpd.go b/internal/core/usecase/lgpd.go new file mode 100644 index 0000000..035819d --- /dev/null +++ b/internal/core/usecase/lgpd.go @@ -0,0 +1,26 @@ +package usecase + +import ( + "context" + "fiap-tech-challenge-api/internal/adapters/repository" + "fiap-tech-challenge-api/internal/core/domain" +) + +type LGPD interface { + Anonimizar(ctx context.Context, cliente *domain.Cliente) error +} + +type anonimizarClienteUC struct { + clienteRepo repository.ClienteRepo +} + +func NewLGPD(clienteRepo repository.ClienteRepo) LGPD { + return &anonimizarClienteUC{ + clienteRepo: clienteRepo, + } +} + + +func (uc *anonimizarClienteUC) Anonimizar(ctx context.Context, cliente *domain.Cliente) error { + return uc.clienteRepo.Anonimizar(ctx, cliente) +} diff --git a/wire.go b/wire.go index 7ae625d..2ff232f 100644 --- a/wire.go +++ b/wire.go @@ -22,6 +22,7 @@ func InitializeWebServer() (*http.Server, error) { repository.NewProdutoRepo, auth.NewJwtToken, usecase.NewCadastraCliente, + usecase.NewLGPD, usecase.NewPesquisarCliente, usecase.NewCadastraProduto, usecase.NewPegaProdutoPorCategoria, diff --git a/wire_gen.go b/wire_gen.go index 6bc1c37..7d5c1ee 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -24,9 +24,10 @@ func InitializeWebServer() (*http.Server, error) { clienteRepo := repository2.NewClienteRepo(dbConnector) cadastrarClienteUseCase := usecase.NewCadastraCliente(clienteRepo) pesquisarClientePorCPF := usecase.NewPesquisarCliente(clienteRepo) + lgpd := usecase.NewLGPD(clienteRepo) validator := util.NewCustomValidator() token := auth.NewJwtToken() - cliente := handlers.NewCliente(cadastrarClienteUseCase, pesquisarClientePorCPF, validator, token) + cliente := handlers.NewCliente(cadastrarClienteUseCase, pesquisarClientePorCPF, lgpd, validator, token) produtoRepo := repository2.NewProdutoRepo(dbConnector) cadastrarProduto := usecase.NewCadastraProduto(produtoRepo) pegarProdutoPorCategoria := usecase.NewPegaProdutoPorCategoria(produtoRepo)