2023-11-01 23:21:12 +03:00
|
|
|
package service
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/hex"
|
|
|
|
"errors"
|
|
|
|
"net/mail"
|
|
|
|
|
|
|
|
normalizer "github.com/dimuska139/go-email-normalizer"
|
2024-01-06 08:44:26 +03:00
|
|
|
"github.com/google/uuid"
|
2023-11-01 23:21:12 +03:00
|
|
|
"github.com/labstack/echo-contrib/session"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
|
|
|
"gitrepo.ru/neonxp/nquest/pkg/models"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
ErrInvalidUsername = errors.New("invalid username")
|
|
|
|
ErrInvalidPassword = errors.New("invalid password")
|
|
|
|
ErrInvalidEmail = errors.New("invalid email")
|
|
|
|
ErrDiffferentPassword = errors.New("different password")
|
|
|
|
ErrDuplicateUser = errors.New("duplicate user")
|
|
|
|
ErrIvalidUserOrPassword = errors.New("invalid user or password")
|
|
|
|
)
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
DB *gorm.DB
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewUser returns new User.
|
|
|
|
func NewUser(db *gorm.DB) *User {
|
|
|
|
return &User{
|
|
|
|
DB: db,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *User) Register(ctx context.Context, username, email, password, password2 string) (*models.User, error) {
|
|
|
|
if len(username) < 3 || len(username) > 36 {
|
|
|
|
return nil, ErrInvalidUsername
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(password) < 8 {
|
|
|
|
return nil, ErrInvalidPassword
|
|
|
|
}
|
|
|
|
|
|
|
|
if password != password2 {
|
|
|
|
return nil, ErrDiffferentPassword
|
|
|
|
}
|
|
|
|
|
|
|
|
if !isValidEmail(email) {
|
|
|
|
return nil, ErrInvalidEmail
|
|
|
|
}
|
|
|
|
|
|
|
|
hashed, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
u := &models.User{
|
2024-01-06 08:44:26 +03:00
|
|
|
Model: models.Model{
|
|
|
|
ID: uuid.New(),
|
|
|
|
},
|
2023-11-01 23:21:12 +03:00
|
|
|
Username: username,
|
|
|
|
Email: normalizer.NewNormalizer().Normalize(email),
|
|
|
|
Password: hex.EncodeToString(hashed),
|
|
|
|
}
|
|
|
|
|
|
|
|
err = s.DB.WithContext(ctx).Create(u).Error
|
|
|
|
switch {
|
|
|
|
case errors.Is(err, models.ErrEmptyPassword):
|
|
|
|
return nil, ErrInvalidPassword
|
|
|
|
case errors.Is(err, gorm.ErrDuplicatedKey):
|
|
|
|
return nil, ErrDuplicateUser
|
|
|
|
case err != nil:
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return u, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *User) Login(ctx context.Context, email, password string) (*models.User, error) {
|
|
|
|
u := new(models.User)
|
|
|
|
nemail := normalizer.NewNormalizer().Normalize(email)
|
|
|
|
err := s.DB.
|
|
|
|
WithContext(ctx).
|
|
|
|
Where("email = ?", nemail).
|
|
|
|
First(u).
|
|
|
|
Error
|
|
|
|
if err != nil {
|
|
|
|
return nil, ErrIvalidUserOrPassword
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := hex.DecodeString(u.Password)
|
|
|
|
if err != nil {
|
|
|
|
return nil, ErrIvalidUserOrPassword
|
|
|
|
}
|
|
|
|
if err := bcrypt.CompareHashAndPassword(b, []byte(password)); err != nil {
|
|
|
|
return nil, ErrIvalidUserOrPassword
|
|
|
|
}
|
|
|
|
|
|
|
|
return u, nil
|
|
|
|
}
|
|
|
|
|
2024-01-06 08:44:26 +03:00
|
|
|
func (s *User) GetUserByID(ctx context.Context, userID uuid.UUID) (*models.User, error) {
|
2023-11-01 23:21:12 +03:00
|
|
|
u := new(models.User)
|
|
|
|
|
2024-01-05 03:50:33 +03:00
|
|
|
return u, s.DB.WithContext(ctx).
|
2024-01-06 08:44:26 +03:00
|
|
|
Preload("Games", `Finish = true`).
|
2024-01-05 03:50:33 +03:00
|
|
|
Preload("Games.Game").
|
|
|
|
First(u, userID).Error
|
2023-11-01 23:21:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *User) GetUser(c echo.Context) *models.User {
|
|
|
|
sess, err := session.Get("session", c)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-01-06 08:44:26 +03:00
|
|
|
userID, ok := sess.Values["userID"].(string)
|
2023-11-01 23:21:12 +03:00
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
2024-01-06 08:44:26 +03:00
|
|
|
uid, err := uuid.Parse(userID)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
2023-11-01 23:21:12 +03:00
|
|
|
|
2024-01-06 08:44:26 +03:00
|
|
|
user, err := s.GetUserByID(c.Request().Context(), uid)
|
2023-11-01 23:21:12 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return user
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *User) Update(ctx context.Context, user *models.User) error {
|
|
|
|
return s.DB.WithContext(ctx).Session(&gorm.Session{FullSaveAssociations: true}).Save(user).Error
|
|
|
|
}
|
|
|
|
|
|
|
|
func isValidEmail(email string) bool {
|
|
|
|
_, err := mail.ParseAddress(email)
|
|
|
|
return err == nil
|
|
|
|
}
|