diff --git a/api/controllers/user.go b/api/controllers/user.go index 6ddc96c5..f191266e 100644 --- a/api/controllers/user.go +++ b/api/controllers/user.go @@ -7,6 +7,7 @@ import ( "pet-dex-backend/v2/infra/config" "pet-dex-backend/v2/pkg/uniqueEntityId" "pet-dex-backend/v2/usecase" + "strconv" "github.com/go-chi/chi/v5" ) @@ -238,3 +239,40 @@ func (uc *UserController) ChangePassword(w http.ResponseWriter, r *http.Request) w.WriteHeader(http.StatusOK) } + +func (uc *UserController) RetrieveUserList(w http.ResponseWriter, r *http.Request) { + page := 1 + limit := 10 + search := "" + + if p := r.URL.Query().Get("page"); p != "" { + if pInt, err := strconv.Atoi(p); err == nil { + page = pInt + } + } + if l := r.URL.Query().Get("limit"); l != "" { + if lInt, err := strconv.Atoi(l); err == nil { + limit = lInt + } + } + if s := r.URL.Query().Get("search"); s != "" { + search = s + } + + input := dto.NewUserListInput(page, limit, search) + + user, err := uc.usecase.RetrieveUserList(input) + + if err != nil { + logger.Error("error on user controller: ", err) + http.Error(w, err.Error(), http.StatusInternalServerError) + } + + if err = json.NewEncoder(w).Encode(&user); err != nil { + logger.Error("error on user controller: ", err) + http.Error(w, "Failed to encode user", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusOK) +} diff --git a/api/routes/routes.go b/api/routes/routes.go index 393c183a..066b170a 100644 --- a/api/routes/routes.go +++ b/api/routes/routes.go @@ -40,6 +40,7 @@ func InitRoutes(controllers Controllers, c *chi.Mux) { }) 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) @@ -52,6 +53,7 @@ func InitRoutes(controllers Controllers, c *chi.Mux) { r.Group(func(public chi.Router) { public.Post("/user", controllers.UserController.Insert) + public.Get("/user", controllers.UserController.RetrieveUserList) public.Post("/user/token", controllers.UserController.GenerateToken) public.Get("/pets/", controllers.PetController.ListAllPets) }) diff --git a/entity/dto/user_list.dto.go b/entity/dto/user_list.dto.go new file mode 100644 index 00000000..238319fc --- /dev/null +++ b/entity/dto/user_list.dto.go @@ -0,0 +1,40 @@ +package dto + +import ( + "pet-dex-backend/v2/pkg/uniqueEntityId" + "time" +) + + + +type UserListInput struct { + Page int + Limit int + Search string +} + + +type UserList struct { + ID uniqueEntityId.ID `json:"id" db:"id"` + Name string `json:"name" db:"name"` + Type string `json:"type" db:"type"` + Document string `json:"document" db:"document"` + AvatarURL string `json:"avatar_url" db:"avatarUrl"` + Email string `json:"email" db:"email"` + Phone string `json:"phone" db:"phone"` + Birthdate *time.Time `json:"birthdate"` + PushNotificationsEnabled *bool `json:"pushNotificationsEnabled" db:"pushNotificationsEnabled"` +} + +type UserListOutput struct { + Users []UserList `json:"users"` + Total int `json:"total"` +} + +func NewUserListInput(page, limit int, search string) *UserListInput { + return &UserListInput{ + Page: page, + Limit: limit, + Search: search, + } +} diff --git a/infra/db/user_repository.go b/infra/db/user_repository.go index 407634cd..f03fabe7 100644 --- a/infra/db/user_repository.go +++ b/infra/db/user_repository.go @@ -1,8 +1,10 @@ package db import ( + "errors" "fmt" "pet-dex-backend/v2/entity" + "pet-dex-backend/v2/entity/dto" "pet-dex-backend/v2/infra/config" "pet-dex-backend/v2/interfaces" "pet-dex-backend/v2/pkg/uniqueEntityId" @@ -193,10 +195,6 @@ func (ur *UserRepository) FindByEmail(email string) (*entity.User, error) { return &user, nil } -func (ur *UserRepository) List() (users []entity.User, err error) { - return nil, nil -} - func (ur *UserRepository) ChangePassword(userId uniqueEntityId.ID, newPassword string) error { query := "UPDATE users SET pass = ?," @@ -222,3 +220,62 @@ func (ur *UserRepository) ChangePassword(userId uniqueEntityId.ID, newPassword s return nil } + + +func (ur *UserRepository) List(input *dto.UserListInput) (output *dto.UserListOutput, err error) { + var users []dto.UserList + query := `SELECT + u.id, + u.name, + u.type, + u.document, + u.email, + u.phone, + u.birthdate, + u.pushNotificationsEnabled + FROM users u` + var args []interface{} + if input.Search != "" { + query += " WHERE u.name LIKE ?" + args = append(args, "%"+input.Search+"%") + } + + offset := (input.Page - 1) * input.Limit + query += fmt.Sprintf(" LIMIT %d OFFSET %d", input.Limit, offset) + + rows, err := ur.dbconnection.Queryx(query, args...) + if err != nil { + ur.logger.Error("error retrieving user list: ", err) + return nil, errors.New("error retrieving user list") + } + defer rows.Close() + + for rows.Next() { + var user dto.UserList + if err := rows.StructScan(&user); err != nil { + ur.logger.Error("error scanning user: ", err) + return nil, errors.New("error retrieving users") + } + users = append(users, user) + } + + var total int + countQuery := `SELECT COUNT(*) FROM users` + if input.Search != "" { + countQuery += " WHERE name LIKE ?" + err = ur.dbconnection.Get(&total, countQuery, "%"+input.Search+"%") + } else { + err = ur.dbconnection.Get(&total, countQuery) + } + + if err != nil { + ur.logger.Error("error counting users: ", err) + return nil, errors.New("error counting users") + } + + return &dto.UserListOutput{ + Users: users, + Total: total, + }, nil +} + diff --git a/interfaces/user_repository.go b/interfaces/user_repository.go index 17afe681..886bef37 100644 --- a/interfaces/user_repository.go +++ b/interfaces/user_repository.go @@ -2,6 +2,7 @@ package interfaces import ( "pet-dex-backend/v2/entity" + "pet-dex-backend/v2/entity/dto" "pet-dex-backend/v2/pkg/uniqueEntityId" ) @@ -11,7 +12,7 @@ type UserRepository interface { Delete(id uniqueEntityId.ID) error FindByID(ID uniqueEntityId.ID) (*entity.User, error) FindByEmail(email string) (*entity.User, error) - List() ([]entity.User, error) + List(*dto.UserListInput) (*dto.UserListOutput, error) ChangePassword(userId uniqueEntityId.ID, newPassword string) error AdressRepo } diff --git a/usecase/user.go b/usecase/user.go index 01c5c1da..744a45ed 100644 --- a/usecase/user.go +++ b/usecase/user.go @@ -178,3 +178,15 @@ func (uc *UserUsecase) UpdatePushNotificationSettings(userID uniqueEntityId.ID, return nil } + + +func (uc *UserUsecase) RetrieveUserList(input *dto.UserListInput) (*dto.UserListOutput, error) { + output, err := uc.repo.List(input) + + if err != nil { + uc.logger.Error("error listing users", err) + return nil, errors.New("error retrieving users") + } + + return output, nil +} \ No newline at end of file