Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

user delete endpoint #132

Merged
merged 7 commits into from
Jun 5, 2024
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
34 changes: 33 additions & 1 deletion api/controllers/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ func NewUserController(usecase *usecase.UserUsecase) *UserController {
}
}


func (uc *UserController) Insert(w http.ResponseWriter, r *http.Request) {
var userDto dto.UserInsertDto
err := json.NewDecoder(r.Body).Decode(&userDto)
Expand Down Expand Up @@ -133,3 +132,36 @@ func (uc *UserController) FindByID(w http.ResponseWriter, r *http.Request) {

w.WriteHeader(http.StatusOK)
}

func (uc *UserController) Delete(w http.ResponseWriter, r *http.Request) {
userIDFromTokenStr := r.Header.Get("UserId")
userIDFromToken, err := uniqueEntityId.ParseID(userIDFromTokenStr)
if err != nil {
logger.Error("[#UserController.Delete] Erro ao tentar receber o ID do token -> Erro: %v", err)
http.Error(w, "Erro ao converter a requisição ", http.StatusBadRequest)
return
}

IDStr := chi.URLParam(r, "id")
ID, err := uniqueEntityId.ParseID(IDStr)
if err != nil {
logger.Error("[#UserController.Delete] Erro ao tentar converter o body da requisição -> Erro: %v", err)
http.Error(w, "Erro ao converter a requisição ", http.StatusBadRequest)
return
}

if userIDFromToken != ID {
logger.Error("[#UserController.Delete] Erro ao tentar excluir outro usuário -> Erro: %v", err)
http.Error(w, "Usuário não autorizado a excluir este usuário", http.StatusUnauthorized)
return
}

err = uc.usecase.Delete(ID)
if err != nil {
logger.Error("[#UserController.Delete] Erro ao tentar deletar o usuário -> Erro: %v", err)
http.Error(w, "Erro ao tentar atualizar o usuário ", http.StatusBadRequest)
return
}

w.WriteHeader(http.StatusNoContent)
}
1 change: 1 addition & 0 deletions api/middlewares/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func AuthMiddleware(next http.Handler) http.Handler {
w.WriteHeader(401)
return
}
r.Header.Add("userId", userclaims.Id)
next.ServeHTTP(w, r)
})
}
44 changes: 26 additions & 18 deletions api/routes/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package routes

import (
"pet-dex-backend/v2/api/controllers"
"pet-dex-backend/v2/api/middlewares"

"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
Expand All @@ -19,29 +20,36 @@ func InitRoutes(controllers Controllers, c *chi.Mux) {
c.Route("/api", func(r chi.Router) {
r.Use(middleware.AllowContentType("application/json"))

r.Route("/pets", func(r chi.Router) {
r.Route("/breeds", func(r chi.Router) {
r.Get("/", controllers.BreedController.List)
r.Get("/{breedID}", controllers.BreedController.FindBreed)
r.Group(func(private chi.Router) {
private.Use(middlewares.AuthMiddleware)

private.Route("/pets", func(r chi.Router) {
r.Route("/breeds", func(r chi.Router) {
r.Get("/", controllers.BreedController.List)
})

r.Patch("/{petID}", controllers.PetController.Update)
r.Post("/", controllers.PetController.CreatePet)
})

r.Get("/breeds", controllers.BreedController.List)
r.Patch("/{petID}", controllers.PetController.Update)
r.Post("/", controllers.PetController.CreatePet)
})
private.Route("/ongs", func(r chi.Router) {
r.Post("/", controllers.OngController.Insert)
r.Get("/", controllers.OngController.List)
r.Get("/{ongID}", controllers.OngController.FindByID)
r.Patch("/{ongID}", controllers.OngController.Update)
})

r.Route("/ongs", func(r chi.Router) {
r.Post("/", controllers.OngController.Insert)
r.Get("/", controllers.OngController.List)
r.Get("/{ongID}", controllers.OngController.FindByID)
r.Patch("/{ongID}", controllers.OngController.Update)
private.Route("/user", func(r chi.Router) {
r.Get("/{id}/my-pets", controllers.PetController.ListUserPets)
r.Patch("/{id}", controllers.UserController.Update)
r.Get("/{id}", controllers.UserController.FindByID)
r.Delete("/{id}", controllers.UserController.Delete)
})
})

r.Route("/user", func(r chi.Router) {
r.Post("/token", controllers.UserController.GenerateToken)
r.Post("/", controllers.UserController.Insert)
r.Patch("/{id}", controllers.UserController.Update)
r.Get("/{id}", controllers.UserController.FindByID)
r.Group(func(public chi.Router) {
public.Post("/user", controllers.UserController.Insert)
public.Post("/user/token", controllers.UserController.GenerateToken)
})
})
}
22 changes: 20 additions & 2 deletions infra/db/user_repository.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package db

import (
"database/sql"
"fmt"
"pet-dex-backend/v2/entity"
"pet-dex-backend/v2/infra/config"
Expand All @@ -24,6 +25,13 @@ func NewUserRepository(dbconn *sqlx.DB) interfaces.UserRepository {
}

func (ur *UserRepository) Delete(id uniqueEntityId.ID) error {
_, err := ur.dbconnection.Exec("UPDATE users SET deleted_at = CURRENT_TIMESTAMP WHERE id = ?", id)

if err != nil {
ur.logger.Error("#UserRepository.Delete error: %w", err)
return fmt.Errorf("error on delete user")
}

return nil
}

Expand Down Expand Up @@ -156,8 +164,18 @@ func (ur *UserRepository) FindByID(ID uniqueEntityId.ID) (*entity.User, error) {
return &user, nil
}

func (ur *UserRepository) FindByEmail(email string) *entity.User {
return &entity.User{}
func (ur *UserRepository) FindByEmail(email string) (*entity.User, error) {
var user entity.User
err := ur.dbconnection.QueryRow("SELECT name, pass, email FROM users WHERE email = ?", email).Scan(&user.Name, &user.Pass, &user.Email)

if err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
return nil, fmt.Errorf("error retrieving user: %w", err)
}

return &user, nil
}

func (ur *UserRepository) List() (users []entity.User, err error) {
Expand Down
2 changes: 1 addition & 1 deletion interfaces/user_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type UserRepository interface {
Update(userID uniqueEntityId.ID, user entity.User) error
Delete(id uniqueEntityId.ID) error
FindByID(ID uniqueEntityId.ID) (*entity.User, error)
FindByEmail(email string) *entity.User
FindByEmail(email string) (*entity.User, error)
List() ([]entity.User, error)
AdressRepo
}
4 changes: 2 additions & 2 deletions mocks/pet-dex-backend/v2/interfaces/mock_UserRepository.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 17 additions & 1 deletion usecase/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package usecase

import (
"errors"
"fmt"
"pet-dex-backend/v2/entity"
"pet-dex-backend/v2/entity/dto"
"pet-dex-backend/v2/infra/config"
Expand Down Expand Up @@ -56,7 +57,11 @@ func (uc *UserUsecase) Save(userDto dto.UserInsertDto) error {
}

func (uc *UserUsecase) GenerateToken(loginDto *dto.UserLoginDto) (string, error) {
user := uc.repo.FindByEmail(loginDto.Email)
user, err := uc.repo.FindByEmail(loginDto.Email)
if err != nil {
return "", errors.New("invalid credentials")
}

if user.Name == "" {
return "", errors.New("invalid credentials")
}
Expand Down Expand Up @@ -106,3 +111,14 @@ func (uc *UserUsecase) FindByID(ID uniqueEntityId.ID) (*entity.User, error) {

return user, nil
}

func (uc *UserUsecase) Delete(userID uniqueEntityId.ID) error {
err := uc.repo.Delete(userID)

if err != nil {
uc.logger.Error(fmt.Errorf("#UserUsecase.Delete error: %w", err))
return err
}

return nil
}
50 changes: 50 additions & 0 deletions usecase/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,3 +259,53 @@ func TestErrorUpdate(t *testing.T) {
})
}
}

func TestDelete(t *testing.T) {
tcases := map[string]struct {
repo *mockInterfaces.MockUserRepository
inputID uniqueEntityId.ID
expectOutput error
}{
"success": {
repo: mockInterfaces.NewMockUserRepository(t),
inputID: uniqueEntityId.NewID(),
expectOutput: nil,
},
}

for name, tcase := range tcases {
t.Run(name, func(t *testing.T) {
tcase.repo.On("Delete", tcase.inputID).Return(tcase.expectOutput)

usecase := NewUserUsecase(tcase.repo, nil, nil)
err := usecase.Delete(tcase.inputID)

assert.Equal(t, tcase.expectOutput, err, "expected error mismatch")
})
}
}

func TestErrorDelete(t *testing.T) {
tcases := map[string]struct {
repo *mockInterfaces.MockUserRepository
inputID uniqueEntityId.ID
expectOutput error
}{
"errorDelete": {
repo: mockInterfaces.NewMockUserRepository(t),
inputID: uniqueEntityId.NewID(),
expectOutput: fmt.Errorf("error on delete user"),
},
}

for name, tcase := range tcases {
t.Run(name, func(t *testing.T) {
tcase.repo.On("Delete", tcase.inputID).Return(tcase.expectOutput)

usecase := NewUserUsecase(tcase.repo, nil, nil)
err := usecase.Delete(tcase.inputID)

assert.Equal(t, tcase.expectOutput, err, "expected error mismatch")
})
}
}
Loading