This commit is contained in:
aespin 2024-05-02 14:13:44 +02:00
parent e808ec3139
commit 62b232a418
8 changed files with 346 additions and 5 deletions

3
go.mod
View File

@ -6,6 +6,7 @@ require (
git.espin.casa/albert/cml04-eventer v0.0.0-20240312060131-787bef88f992
git.espin.casa/albert/logger v0.0.0-20240312060442-59b35e5c6996
github.com/zc2638/swag v1.5.1
golang.org/x/crypto v0.22.0
gorm.io/driver/mysql v1.5.6
gorm.io/gorm v1.25.9
)
@ -20,5 +21,5 @@ require (
github.com/nsqio/go-nsq v1.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
golang.org/x/sys v0.19.0 // indirect
)

5
go.sum
View File

@ -39,8 +39,11 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/zc2638/swag v1.5.1 h1:T/PyvMTXOxCRIakSpD7Ed4uICW4PM16JdPsS+3dJbKU=
github.com/zc2638/swag v1.5.1/go.mod h1:AjyTDUHzZZ4mctSNLEZVD5jWQHFGDJlaCR5XjDm46aE=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -15,6 +15,51 @@ type LoggingService struct {
next service.IService
}
// ValidarUsuario implements service.IService.
func (svc *LoggingService) ValidarUsuario(ctx context.Context, req types.ValidarUsuarioReq) (res types.ValidarUsuarioRes, err error) {
defer func(start time.Time) {
logFields := logger.LogFields{
"took": time.Since(start),
}
if err != nil {
svc.log.Error("validate user failed", err, logFields)
} else {
svc.log.Info("validate user success", logFields)
}
}(time.Now())
return svc.next.ValidarUsuario(ctx, req)
}
// CreateUsuario implements service.IService.
func (svc *LoggingService) CreateUsuario(ctx context.Context, req types.CreateUsuarioReq) (res types.CreateUsuarioRes, err error) {
defer func(start time.Time) {
logFields := logger.LogFields{
"took": time.Since(start),
}
if err != nil {
svc.log.Error("create usuario failed", err, logFields)
} else {
svc.log.Info("create usuario success", logFields)
}
}(time.Now())
return svc.next.CreateUsuario(ctx, req)
}
// GetUsuario implements service.IService.
func (svc *LoggingService) GetUsuario(ctx context.Context, req types.GetUsuarioReq) (res types.GetUsuarioRes, err error) {
defer func(start time.Time) {
logFields := logger.LogFields{
"took": time.Since(start),
}
if err != nil {
svc.log.Error("get medicion failed", err, logFields)
} else {
svc.log.Info("get medicion success", logFields)
}
}(time.Now())
return svc.next.GetUsuario(ctx, req)
}
// GetMedicion implements service.IService.
func (svc *LoggingService) GetMedicion(ctx context.Context, req types.GetMedicionReq) (res types.GetMedicionRes, err error) {
defer func(start time.Time) {

View File

@ -2,7 +2,6 @@ package server
import (
"encoding/json"
"fmt"
"net/http"
"path"
"time"
@ -89,11 +88,121 @@ func PostMedicionesEndPoint(svc service.IService) *swag.Endpoint {
)
}
func GetUserEndPoint(svc service.IService) *swag.Endpoint {
return endpoint.New(http.MethodPost, "/user",
endpoint.BodyR(types.GetUsuarioReq{}),
endpoint.Response(http.StatusOK, "ok", endpoint.SchemaResponseOption(types.GetUsuarioRes{})),
endpoint.Summary("Get user based on email primary key"),
endpoint.Description("Get user based on email primary key"),
endpoint.Handler(GetUserHandler(svc)),
)
}
func CreateUserEndPoint(svc service.IService) *swag.Endpoint {
return endpoint.New(http.MethodPost, "/user/create",
endpoint.BodyR(types.CreateUsuarioReq{}),
endpoint.Response(http.StatusOK, "ok", endpoint.SchemaResponseOption(types.CreateUsuarioRes{})),
endpoint.Summary("Create a new user"),
endpoint.Description("Create a new user"),
endpoint.Handler(CreateUserHandler(svc)),
)
}
func ValidateUserEndPoint(svc service.IService) *swag.Endpoint {
return endpoint.New(http.MethodPost, "/user/validate",
endpoint.BodyR(types.ValidarUsuarioReq{}),
endpoint.Response(http.StatusOK, "ok", endpoint.SchemaResponseOption(types.ValidarUsuarioRes{})),
endpoint.Summary("User validation"),
endpoint.Description("User validation"),
endpoint.Handler(ValidateUserHandler(svc)),
)
}
func ValidateUserHandler(svc service.IService) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// request body holder
req := types.ValidarUsuarioReq{}
// decode json body request
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "body json decoding failed", http.StatusBadRequest)
return
}
//
res, err := svc.ValidarUsuario(r.Context(), req)
if err != nil {
http.Error(w, "validate user failed", http.StatusInternalServerError)
return
}
// set content type header
w.Header().Set("Content-Type", "application/json")
// response
w.WriteHeader(http.StatusOK)
// write response
if err := json.NewEncoder(w).Encode(&res); err != nil {
http.Error(w, "encode response failed", http.StatusInternalServerError)
return
}
})
}
func GetUserHandler(svc service.IService) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// request body holder
req := types.GetUsuarioReq{}
// decode json body request
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "body json decoding failed", http.StatusBadRequest)
return
}
// get user from database
res, err := svc.GetUsuario(r.Context(), req)
if err != nil {
http.Error(w, "get user failed", http.StatusInternalServerError)
return
}
// set content type header
w.Header().Set("Content-Type", "application/json")
// response
w.WriteHeader(http.StatusOK)
// write response
if err := json.NewEncoder(w).Encode(&res); err != nil {
http.Error(w, "encode response failed", http.StatusInternalServerError)
return
}
})
}
func CreateUserHandler(svc service.IService) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// request body holder
req := types.CreateUsuarioReq{}
// decode json body request
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "body json decoding failed", http.StatusBadRequest)
return
}
// create user service call
res, err := svc.CreateUsuario(r.Context(), req)
if err != nil {
http.Error(w, "create user failed", http.StatusInternalServerError)
return
}
// set content type header
w.Header().Set("Content-Type", "application/json")
// response
w.WriteHeader(http.StatusOK)
// write response
if err := json.NewEncoder(w).Encode(&res); err != nil {
http.Error(w, "encode response failed", http.StatusInternalServerError)
return
}
})
}
func PostMedicionesHandler(svc service.IService) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// request body holder
req := types.PostMedicionesReq{}
fmt.Printf("mediciones req: %+v\n", req)
// decode json body request
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "body json decoding failed", http.StatusBadRequest)
@ -326,6 +435,9 @@ func NewServer(url string, svc service.IService) *Server {
PostMedicionesEndPoint(svc),
GetMedicionesEndPoint(svc),
GetMedicionEndPoint(svc),
GetUserEndPoint(svc),
CreateUserEndPoint(svc),
ValidateUserEndPoint(svc),
)
return &Server{
api: api,

View File

@ -4,12 +4,16 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"os"
"regexp"
"time"
cml04eventer "git.espin.casa/albert/cml04-eventer"
"git.espin.casa/albert/cml04-mediciones-service/internal/storage"
"git.espin.casa/albert/cml04-mediciones-service/internal/types"
"golang.org/x/crypto/bcrypt"
)
type IService interface {
@ -24,6 +28,10 @@ type IService interface {
GetMedicion(ctx context.Context, req types.GetMedicionReq) (types.GetMedicionRes, error)
GetMediciones(ctx context.Context, req types.GetMedicionesReq) (types.GetMedicionesRes, error)
PostMediciones(ctx context.Context, req types.PostMedicionesReq) (types.PostMedicionesRes, error)
// Ususarios
GetUsuario(ctx context.Context, req types.GetUsuarioReq) (types.GetUsuarioRes, error)
CreateUsuario(ctx context.Context, req types.CreateUsuarioReq) (types.CreateUsuarioRes, error)
ValidarUsuario(ctx context.Context, req types.ValidarUsuarioReq) (types.ValidarUsuarioRes, error)
/* NSQ */
ProcessEvent(ctx context.Context, event *cml04eventer.Event) error
CreateProductionOrder(ctx context.Context, po *types.OrdenFabricacion) error
@ -34,6 +42,82 @@ type service struct {
file *os.File
}
// ValidarUsuario implements IService.
func (s *service) ValidarUsuario(ctx context.Context, req types.ValidarUsuarioReq) (types.ValidarUsuarioRes, error) {
// get user from database
user, err := s.storage.GetUser(ctx, req.Email)
if err != nil {
return types.ValidarUsuarioRes{}, err
}
// password from request
pass := req.Pass
// hash from database
hash := user.Password
// compare hash and pass
if err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(pass)); err != nil {
return types.ValidarUsuarioRes{}, err
}
return types.ValidarUsuarioRes{
Message: "user validated success",
TimeStamp: time.Now().UTC().Format(time.RFC3339),
}, nil
}
func checkEmail(email string) bool {
// regular expression for validate email
regex := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`
// compile regular expression
pattern := regexp.MustCompile(regex)
// check if string match pattern
return pattern.MatchString(email)
}
func encryptPass(pass string) (string, error) {
res, err := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost)
if err != nil {
return "", err
}
return string(res), nil
}
// CreateUsuario implements IService.
func (s *service) CreateUsuario(ctx context.Context, req types.CreateUsuarioReq) (types.CreateUsuarioRes, error) {
// user var holder
user := req.Usuario
// encrypt user pass
pass, err := encryptPass(user.Password)
if err != nil {
return types.CreateUsuarioRes{}, err
}
// assign hash based on password
user.Password = pass
// check if email is correct
if !checkEmail(user.Email) {
return types.CreateUsuarioRes{}, errors.New("email format is not correct")
}
// create user
if err := s.storage.CreateUser(ctx, user); err != nil {
return types.CreateUsuarioRes{}, err
}
// done
return types.CreateUsuarioRes{
Message: fmt.Sprintf("create user: %s success", user.Email),
TimeStamp: time.Now().UTC().Format(time.RFC3339),
}, nil
}
// GetUsuario implements IService.
func (s *service) GetUsuario(ctx context.Context, req types.GetUsuarioReq) (types.GetUsuarioRes, error) {
user, err := s.storage.GetUser(ctx, req.Email)
if err != nil {
return types.GetUsuarioRes{}, err
}
return types.GetUsuarioRes{
Usuario: user,
TimeStamp: time.Now().Format(time.RFC3339),
}, nil
}
// GetMedicion implements IService.
func (s *service) GetMedicion(ctx context.Context, req types.GetMedicionReq) (types.GetMedicionRes, error) {
medicion, err := s.storage.GetMedicion(ctx, req.MedicionID)

View File

@ -18,6 +18,8 @@ type IStorage interface {
PostMediciones(ctx context.Context, medicion *types.Mediciones) error
GetMediciones(ctx context.Context, pono int) ([]types.Mediciones, error)
GetMedicion(ctx context.Context, id uint64) (*types.Mediciones, error)
CreateUser(ctx context.Context, user *types.Usuario) error
GetUser(ctx context.Context, email string) (*types.Usuario, error)
}
type StorageConfig struct {
@ -32,6 +34,20 @@ type storage struct {
db *gorm.DB
}
// CreateUSer implements IStorage.
func (s *storage) CreateUser(ctx context.Context, user *types.Usuario) error {
return s.db.Create(user).Error
}
// GetUser implements IStorage.
func (s *storage) GetUser(ctx context.Context, email string) (*types.Usuario, error) {
user := &types.Usuario{}
if err := s.db.Where("email", email).Find(user).Error; err != nil {
return nil, err
}
return user, nil
}
// GetMedicion implements IStorage.
func (s *storage) GetMedicion(ctx context.Context, id uint64) (*types.Mediciones, error) {
medicion := &types.Mediciones{}
@ -110,6 +126,7 @@ func AutoMigrate(db *gorm.DB) error {
&types.Tolerancia{},
&types.OrdenFabricacion{},
&types.Mediciones{},
&types.Usuario{},
)
}

View File

@ -39,7 +39,7 @@ type AnchuraAlas struct {
}
type Mediciones struct {
MedicionID uint64 `gorm:"primaryKey"`
MedicionID uint64 `gorm:"primaryKey;autoIncrement:true"`
POrderNo int `gorm:"index"`
Observaciones string
Colada string
@ -51,6 +51,11 @@ type Mediciones struct {
AnchuraAlas AnchuraAlas `gorm:"embedded;embeddedPrefix:anchura_alas_"`
AsimetriaAlma AsimetriaAlma `gorm:"embedded;embeddedPrefix:asimetria_alma_"`
Firmada bool
Operador string
Enraye bool
MarcaCelsa bool
Turno string
IDBarra string
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`

View File

@ -0,0 +1,74 @@
package types
import (
"time"
"gorm.io/gorm"
)
type Rol uint8
const (
Admin Rol = iota + 1
Operador
JefeTurno
)
type Usuario struct {
Email string `gorm:"primaryKey"`
Password string
Enabled bool
Rol Rol
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
func (u *Usuario) TableName() string {
return "usuarios"
}
type GetUsuarioReq struct {
Sender string
Email string
TimeStamp string
}
type GetUsuarioRes struct {
Usuario *Usuario
TimeStamp string
}
type CreateUsuarioReq struct {
Sender string
Usuario *Usuario
TimeStamp string
}
type CreateUsuarioRes struct {
Message string
TimeStamp string
}
type ValidarUsuarioReq struct {
Sender string
Email string
Pass string
TimeStamp string
}
type ValidarUsuarioRes struct {
Message string
TimeStamp string
}
func (u *Usuario) BeforeCreate(tx *gorm.DB) (err error) {
u.CreatedAt = time.Now()
u.UpdatedAt = time.Now()
return
}
func (u *Usuario) BeforeUpdate(tx *gorm.DB) (err error) {
u.UpdatedAt = time.Now()
return
}