Skip to content

Commit

Permalink
fix: create service for post 4
Browse files Browse the repository at this point in the history
  • Loading branch information
wiliamvj committed Dec 19, 2023
1 parent 54dc662 commit 58bc79a
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 35 deletions.
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ POSTGRES_PASSWORD="golang_api_users"
POSTGRES_HOST="localhost"
POSTGRES_PORT="5432"
DATABASE_URL="postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=disable"

VIA_CEP_URL="https://viacep.com.br/ws"
42 changes: 42 additions & 0 deletions api/viacep/viacep.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package viacep

import (
"encoding/json"
"fmt"
"net/http"

"github.com/wiliamvj/api-users-golang/config/env"
)

type ViaCepResponse struct {
CEP string `json:"cep"`
Logradouro string `json:"logradouro"`
Complemento string `json:"complemento"`
Bairro string `json:"bairro"`
Localidade string `json:"localidade"`
UF string `json:"uf"`
IBGE string `json:"ibge"`
GIA string `json:"gia"`
DDD string `json:"ddd"`
SIAFI string `json:"siafi"`
}

func GetCep(cep string) (*ViaCepResponse, error) {
url := fmt.Sprintf("%s/%s/json", env.Env.ViaCepURL, cep)
var viaCepResponse ViaCepResponse

resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()

err = json.NewDecoder(resp.Body).Decode(&viaCepResponse)
if err != nil {
return nil, err
}
if viaCepResponse.CEP == "" {
return nil, fmt.Errorf("cep not found")
}
return &viaCepResponse, nil
}
1 change: 1 addition & 0 deletions config/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type config struct {
GoEnv string `mapstructure:"GO_ENV"`
GoPort string `mapstructure:"GO_PORT"`
DatabaseURL string `mapstructure:"DATABASE_URL"`
ViaCepURL string `mapstructure:"VIA_CEP_URL"`
}

func LoadingConfig(path string) (*config, error) {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/spf13/viper v1.17.0
github.com/swaggo/http-swagger v1.3.4
github.com/swaggo/swag v1.8.1
golang.org/x/crypto v0.13.0
)

require (
Expand Down Expand Up @@ -39,7 +40,6 @@ require (
github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/crypto v0.13.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.15.0 // indirect
golang.org/x/sys v0.12.0 // indirect
Expand Down
6 changes: 4 additions & 2 deletions http_client.http
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ content-type: application/json
{
"name": "John Doe",
"email": "[email protected]",
"password": "12345678@"
"password": "12345678@",
"cep": "77132243"
}

###
Expand All @@ -17,7 +18,8 @@ content-type: application/json

{
"name": "John Doe",
"email": "[email protected]"
"email": "[email protected]",
"cep": "00000000"
}

###
Expand Down
2 changes: 2 additions & 0 deletions internal/dto/user_dto.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ type CreateUserDto struct {
Name string `json:"name" validate:"required,min=3,max=30"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8,max=30,containsany=!@#$%*"`
CEP string `json:"cep" validate:"required,min=8,max=8"`
}

type UpdateUserDto struct {
Name string `json:"name" validate:"omitempty,min=3,max=30"`
Email string `json:"email" validate:"omitempty,email"`
CEP string `json:"cep" validate:"omitempty,min=8,max=8"`
}

type UpdateUserPasswordDto struct {
Expand Down
22 changes: 16 additions & 6 deletions internal/entity/user_entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,20 @@ package entity
import "time"

type UserEntity struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Password string `json:"password,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Password string `json:"password,omitempty"`
Address UserAddress `json:"address,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}

type UserAddress struct {
CEP string `json:"cep"`
IBGE string `json:"ibge"`
UF string `json:"uf"`
City string `json:"city"`
Complement string `json:"complement,omitempty"`
Street string `json:"street"`
}
44 changes: 28 additions & 16 deletions internal/handler/userhandler/user_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,28 @@ func (h *handler) CreateUser(w http.ResponseWriter, r *http.Request) {
}
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
slog.Error("error to decode body", "err", err, slog.String("package", "handler_user"))
slog.Error("error to decode body", "err", err, slog.String("package", "userhandler"))
w.WriteHeader(http.StatusBadRequest)
msg := httperr.NewBadRequestError("error to decode body")
json.NewEncoder(w).Encode(msg)
return
}
httpErr := validation.ValidateHttpData(req)
if httpErr != nil {
slog.Error(fmt.Sprintf("error to validate data: %v", httpErr), slog.String("package", "handler_user"))
slog.Error(fmt.Sprintf("error to validate data: %v", httpErr), slog.String("package", "userhandler"))
w.WriteHeader(httpErr.Code)
json.NewEncoder(w).Encode(httpErr)
return
}
err = h.service.CreateUser(r.Context(), req)
if err != nil {
slog.Error(fmt.Sprintf("error to create user: %v", err), slog.String("package", "handler_user"))
slog.Error(fmt.Sprintf("error to create user: %v", err), slog.String("package", "userhandler"))
if err.Error() == "cep not found" {
w.WriteHeader(http.StatusNotFound)
msg := httperr.NewNotFoundError("cep not found")
json.NewEncoder(w).Encode(msg)
return
}
w.WriteHeader(http.StatusInternalServerError)
msg := httperr.NewBadRequestError("error to create user")
json.NewEncoder(w).Encode(msg)
Expand Down Expand Up @@ -85,7 +91,7 @@ func (h *handler) UpdateUser(w http.ResponseWriter, r *http.Request) {
}
_, err := uuid.Parse(id)
if err != nil {
slog.Error(fmt.Sprintf("error to parse id: %v", err), slog.String("package", "handler_user"))
slog.Error(fmt.Sprintf("error to parse id: %v", err), slog.String("package", "userhandler"))
w.WriteHeader(http.StatusBadRequest)
msg := httperr.NewBadRequestError("error to parse id")
json.NewEncoder(w).Encode(msg)
Expand All @@ -100,28 +106,34 @@ func (h *handler) UpdateUser(w http.ResponseWriter, r *http.Request) {
}
err = json.NewDecoder(r.Body).Decode(&req)
if err != nil {
slog.Error("error to decode body", "err", err, slog.String("package", "handler_user"))
slog.Error("error to decode body", "err", err, slog.String("package", "userhandler"))
w.WriteHeader(http.StatusBadRequest)
msg := httperr.NewBadRequestError("error to decode body")
json.NewEncoder(w).Encode(msg)
return
}
httpErr := validation.ValidateHttpData(req)
if httpErr != nil {
slog.Error(fmt.Sprintf("error to validate data: %v", httpErr), slog.String("package", "handler_user"))
slog.Error(fmt.Sprintf("error to validate data: %v", httpErr), slog.String("package", "userhandler"))
w.WriteHeader(httpErr.Code)
json.NewEncoder(w).Encode(httpErr)
return
}
err = h.service.UpdateUser(r.Context(), req, id)
if err != nil {
slog.Error(fmt.Sprintf("error to update user: %v", err), slog.String("package", "handler_user"))
slog.Error(fmt.Sprintf("error to update user: %v", err), slog.String("package", "userhandler"))
if err.Error() == "user not found" {
w.WriteHeader(http.StatusNotFound)
msg := httperr.NewNotFoundError("user not found")
json.NewEncoder(w).Encode(msg)
return
}
if err.Error() == "cep not found" {
w.WriteHeader(http.StatusNotFound)
msg := httperr.NewNotFoundError("cep not found")
json.NewEncoder(w).Encode(msg)
return
}
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(err)
return
Expand Down Expand Up @@ -152,15 +164,15 @@ func (h *handler) GetUserByID(w http.ResponseWriter, r *http.Request) {
}
_, err := uuid.Parse(id)
if err != nil {
slog.Error(fmt.Sprintf("error to parse id: %v", err), slog.String("package", "handler_user"))
slog.Error(fmt.Sprintf("error to parse id: %v", err), slog.String("package", "userhandler"))
w.WriteHeader(http.StatusBadRequest)
msg := httperr.NewBadRequestError("error to parse id")
json.NewEncoder(w).Encode(msg)
return
}
res, err := h.service.GetUserByID(r.Context(), id)
if err != nil {
slog.Error(fmt.Sprintf("error to get user: %v", err), slog.String("package", "handler_user"))
slog.Error(fmt.Sprintf("error to get user: %v", err), slog.String("package", "userhandler"))
if err.Error() == "user not found" {
w.WriteHeader(http.StatusNotFound)
msg := httperr.NewNotFoundError("user not found")
Expand Down Expand Up @@ -201,15 +213,15 @@ func (h *handler) DeleteUser(w http.ResponseWriter, r *http.Request) {
}
_, err := uuid.Parse(id)
if err != nil {
slog.Error(fmt.Sprintf("error to parse id: %v", err), slog.String("package", "handler_user"))
slog.Error(fmt.Sprintf("error to parse id: %v", err), slog.String("package", "userhandler"))
w.WriteHeader(http.StatusBadRequest)
msg := httperr.NewBadRequestError("error to parse id")
json.NewEncoder(w).Encode(msg)
return
}
err = h.service.DeleteUser(r.Context(), id)
if err != nil {
slog.Error(fmt.Sprintf("error to delete user: %v", err), slog.String("package", "handler_user"))
slog.Error(fmt.Sprintf("error to delete user: %v", err), slog.String("package", "userhandler"))
if err.Error() == "user not found" {
w.WriteHeader(http.StatusNotFound)
msg := httperr.NewNotFoundError("user not found")
Expand Down Expand Up @@ -239,7 +251,7 @@ func (h *handler) DeleteUser(w http.ResponseWriter, r *http.Request) {
func (h *handler) FindManyUsers(w http.ResponseWriter, r *http.Request) {
res, err := h.service.FindManyUsers(r.Context())
if err != nil {
slog.Error(fmt.Sprintf("error to find many users: %v", err), slog.String("package", "handler_user"))
slog.Error(fmt.Sprintf("error to find many users: %v", err), slog.String("package", "userhandler"))
w.WriteHeader(http.StatusInternalServerError)
msg := httperr.NewBadRequestError("error to find many users")
json.NewEncoder(w).Encode(msg)
Expand Down Expand Up @@ -276,7 +288,7 @@ func (h *handler) UpdateUserPassword(w http.ResponseWriter, r *http.Request) {
}
_, err := uuid.Parse(id)
if err != nil {
slog.Error(fmt.Sprintf("error to parse id: %v", err), slog.String("package", "handler_user"))
slog.Error(fmt.Sprintf("error to parse id: %v", err), slog.String("package", "userhandler"))
w.WriteHeader(http.StatusBadRequest)
msg := httperr.NewBadRequestError("error to parse id")
json.NewEncoder(w).Encode(msg)
Expand All @@ -291,22 +303,22 @@ func (h *handler) UpdateUserPassword(w http.ResponseWriter, r *http.Request) {
}
err = json.NewDecoder(r.Body).Decode(&req)
if err != nil {
slog.Error("error to decode body", "err", err, slog.String("package", "handler_user"))
slog.Error("error to decode body", "err", err, slog.String("package", "userhandler"))
w.WriteHeader(http.StatusBadRequest)
msg := httperr.NewBadRequestError("error to decode body")
json.NewEncoder(w).Encode(msg)
return
}
httpErr := validation.ValidateHttpData(req)
if httpErr != nil {
slog.Error(fmt.Sprintf("error to validate data: %v", httpErr), slog.String("package", "handler_user"))
slog.Error(fmt.Sprintf("error to validate data: %v", httpErr), slog.String("package", "userhandler"))
w.WriteHeader(httpErr.Code)
json.NewEncoder(w).Encode(httpErr)
return
}
err = h.service.UpdateUserPassword(r.Context(), &req, id)
if err != nil {
slog.Error(fmt.Sprintf("error to update user password: %v", err), slog.String("package", "handler_user"))
slog.Error(fmt.Sprintf("error to update user password: %v", err), slog.String("package", "userhandler"))
if err.Error() == "user not found" {
w.WriteHeader(http.StatusNotFound)
msg := httperr.NewNotFoundError("user not found")
Expand Down
48 changes: 38 additions & 10 deletions internal/service/userservice/user_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/google/uuid"
"github.com/wiliamvj/api-users-golang/api/viacep"
"github.com/wiliamvj/api-users-golang/internal/dto"
"github.com/wiliamvj/api-users-golang/internal/entity"
"github.com/wiliamvj/api-users-golang/internal/handler/response"
Expand All @@ -23,16 +24,29 @@ func (s *service) CreateUser(ctx context.Context, u dto.CreateUserDto) error {
slog.Error("user already exists", slog.String("package", "userservice"))
return errors.New("user already exists")
}
passwordEncrypted, err := bcrypt.GenerateFromPassword([]byte(u.Password), 31)
passwordEncrypted, err := bcrypt.GenerateFromPassword([]byte(u.Password), 12)
if err != nil {
slog.Error("error to encrypt password", "err", err, slog.String("package", "userservice"))
return errors.New("error to encrypt password")
}
cep, err := viacep.GetCep(u.CEP)
if err != nil {
slog.Error("error to get cep", "err", err, slog.String("package", "userservice"))
return err
}
newUser := entity.UserEntity{
ID: uuid.New().String(),
Name: u.Name,
Email: u.Email,
Password: string(passwordEncrypted),
ID: uuid.New().String(),
Name: u.Name,
Email: u.Email,
Password: string(passwordEncrypted),
Address: entity.UserAddress{
CEP: cep.CEP,
IBGE: cep.IBGE,
UF: cep.UF,
City: cep.Localidade,
Complement: cep.Complemento,
Street: cep.Logradouro,
},
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
Expand All @@ -54,6 +68,7 @@ func (s *service) UpdateUser(ctx context.Context, u dto.UpdateUserDto, id string
slog.Error("user not found", slog.String("package", "userservice"))
return errors.New("user already exists")
}
var updateUser entity.UserEntity
if u.Email != "" {
verifyUserEmail, err := s.repo.FindUserByEmail(ctx, u.Email)
if err != nil {
Expand All @@ -64,13 +79,26 @@ func (s *service) UpdateUser(ctx context.Context, u dto.UpdateUserDto, id string
slog.Error("user already exists", slog.String("package", "userservice"))
return errors.New("user already exists")
}
updateUser.Email = u.Email
}
updateUser := entity.UserEntity{
ID: id,
Name: u.Name,
Email: u.Email,
UpdatedAt: time.Now(),
if u.CEP != "" {
cep, err := viacep.GetCep(u.CEP)
if err != nil {
slog.Error("error to get cep", "err", err, slog.String("package", "userservice"))
return err
}
updateUser.Address = entity.UserAddress{
CEP: cep.CEP,
IBGE: cep.IBGE,
UF: cep.UF,
City: cep.Localidade,
Complement: cep.Complemento,
Street: cep.Logradouro,
}
}
updateUser.ID = id
updateUser.Name = u.Name
updateUser.UpdatedAt = time.Now()
err = s.repo.UpdateUser(ctx, &updateUser)
if err != nil {
slog.Error("error to update user", "err", err, slog.String("package", "userservice"))
Expand Down

0 comments on commit 58bc79a

Please sign in to comment.