fix: auth flow fixed, add getOrCreate method for user

This commit is contained in:
AmirMahdi Qiasvand 2025-09-09 16:57:34 +03:30
parent 406b181576
commit 7d7f54261b
8 changed files with 65 additions and 16 deletions

View File

@ -73,7 +73,7 @@ func (h *AuthHandler) Authenticate(c *fiber.Ctx) error {
c.Context(), c.Context(),
req.PubKey, req.PubKey,
req.Signature, req.Signature,
// add chainID to cfg //TODO: add chainID to cfg
1, 1,
c.IP(), c.IP(),
c.Get("User-Agent"), c.Get("User-Agent"),
@ -90,3 +90,9 @@ func (h *AuthHandler) Authenticate(c *fiber.Ctx) error {
ExpiresAt: userToken.ExpiresAt, ExpiresAt: userToken.ExpiresAt,
}) })
} }
func (h *AuthHandler) HelloWorld(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"message": "Hello, World!",
})
}

View File

@ -4,6 +4,7 @@ import (
"backend/config" "backend/config"
"backend/docs" "backend/docs"
httpHandlers "backend/internal/api/http/handlers" httpHandlers "backend/internal/api/http/handlers"
"backend/internal/api/http/middlewares"
"backend/internal/app" "backend/internal/app"
"fmt" "fmt"
"log" "log"
@ -14,19 +15,27 @@ import (
) )
func Run(cfg config.Server, app *app.AppContainer) { func Run(cfg config.Server, app *app.AppContainer) {
router := fiber.New() fiberApp := fiber.New()
api := router.Group("/api") // Serve static files (HTML, CSS, JS)
fiberApp.Static("/", "./")
api := fiberApp.Group("/api")
// register routes here
registerPublicRoutes(api, app) registerPublicRoutes(api, app)
docs.SwaggerInfo.Host = "" docs.SwaggerInfo.Host = fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
docs.SwaggerInfo.Schemes = []string{}
docs.SwaggerInfo.BasePath = "/api" docs.SwaggerInfo.BasePath = "/api"
docs.SwaggerInfo.Schemes = []string{"http", "https"}
router.Get("/swagger/*", adaptor.HTTPHandler(httpSwagger.Handler())) api.Get("/swagger/*", adaptor.HTTPHandler(httpSwagger.Handler()))
log.Fatal(router.Listen(fmt.Sprintf("%s:%d", cfg.Host, cfg.Port))) api.Get("/hello", middlewares.JWTAuthMiddleware([]byte("Secret")), func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
log.Printf("Server starting on %s:%d", cfg.Host, cfg.Port)
log.Fatal(fiberApp.Listen(fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)))
} }
func registerPublicRoutes(router fiber.Router, app *app.AppContainer) { func registerPublicRoutes(router fiber.Router, app *app.AppContainer) {

View File

@ -4,6 +4,7 @@ import (
"backend/config" "backend/config"
"backend/internal/repository/cache" "backend/internal/repository/cache"
"backend/internal/repository/storage" "backend/internal/repository/storage"
"backend/internal/repository/storage/types"
"backend/internal/usecase" "backend/internal/usecase"
cachePackage "backend/pkg/cache" cachePackage "backend/pkg/cache"
"backend/pkg/postgres" "backend/pkg/postgres"
@ -32,6 +33,7 @@ func NewAppContainer(cfg config.Config) (*AppContainer, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to connect to database: %w", err) return nil, fmt.Errorf("failed to connect to database: %w", err)
} }
dbConn.AutoMigrate(&types.User{})
redis, err := cachePackage.NewRedis(cfg.Redis) redis, err := cachePackage.NewRedis(cfg.Redis)
if err != nil { if err != nil {

View File

@ -28,6 +28,7 @@ type UserRepo interface {
GetByID(ctx context.Context, id uuid.UUID) (*User, error) GetByID(ctx context.Context, id uuid.UUID) (*User, error)
GetByPhone(ctx context.Context, phone string) (*User, error) GetByPhone(ctx context.Context, phone string) (*User, error)
GetByPubKey(ctx context.Context, pubKey string) (*User, error) GetByPubKey(ctx context.Context, pubKey string) (*User, error)
GetOrCreateUserByPubKey(ctx context.Context, pubKey string) (*User, error)
Update(ctx context.Context, user *User) error Update(ctx context.Context, user *User) error
Delete(ctx context.Context, id uuid.UUID) error Delete(ctx context.Context, id uuid.UUID) error
} }

View File

@ -4,11 +4,19 @@ import (
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"gorm.io/gorm"
) )
type Base struct { type Base struct {
ID uuid.UUID ID uuid.UUID `gorm:"type:uuid;default:uuid_generate_v4();primaryKey"`
CreatedAt time.Time CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time
DeletedAt *time.Time DeletedAt *time.Time
} }
func (b *Base) BeforeCreate(tx *gorm.DB) (err error) {
if b.ID == uuid.Nil {
b.ID = uuid.New()
}
return
}

View File

@ -27,6 +27,7 @@ func CastUserToStorage(u domain.User) *User {
UpdatedAt: u.UpdatedAt, UpdatedAt: u.UpdatedAt,
DeletedAt: u.DeletedAt, DeletedAt: u.DeletedAt,
}, },
PubKey: u.PubKey,
Name: u.Name, Name: u.Name,
LastName: u.LastName, LastName: u.LastName,
Phone: u.PhoneNumber, Phone: u.PhoneNumber,
@ -40,6 +41,7 @@ func CastUserToStorage(u domain.User) *User {
func CastUserToDomain(u User) *domain.User { func CastUserToDomain(u User) *domain.User {
return &domain.User{ return &domain.User{
ID: u.ID, ID: u.ID,
PubKey: u.PubKey,
Name: u.Name, Name: u.Name,
LastName: u.LastName, LastName: u.LastName,
PhoneNumber: u.Phone, PhoneNumber: u.Phone,

View File

@ -20,8 +20,12 @@ func NewUserRepository(db *gorm.DB) domain.UserRepo {
} }
func (r *UserRepository) Create(ctx context.Context, user *domain.User) error { func (r *UserRepository) Create(ctx context.Context, user *domain.User) error {
var model types.User model := types.CastUserToStorage(*user)
return r.db.WithContext(ctx).Create(&model).Error if err := r.db.WithContext(ctx).Create(model).Error; err != nil {
return err
}
*user = *types.CastUserToDomain(*model)
return nil
} }
func (r *UserRepository) GetByID(ctx context.Context, id uuid.UUID) (*domain.User, error) { func (r *UserRepository) GetByID(ctx context.Context, id uuid.UUID) (*domain.User, error) {
@ -56,3 +60,22 @@ func (r *UserRepository) GetByPubKey(ctx context.Context, pubKey string) (*domai
} }
return types.CastUserToDomain(user), nil return types.CastUserToDomain(user), nil
} }
func (r *UserRepository) GetOrCreateUserByPubKey(ctx context.Context, pubKey string) (*domain.User, error) {
var user types.User
err := r.db.WithContext(ctx).First(&user, "pub_key = ?", pubKey).Error
if err == nil {
return types.CastUserToDomain(user), nil
}
if err != gorm.ErrRecordNotFound {
return nil, err
}
user = types.User{
PubKey: pubKey,
}
if err := r.db.WithContext(ctx).Create(&user).Error; err != nil {
return nil, err
}
return types.CastUserToDomain(user), nil
}

View File

@ -98,16 +98,14 @@ func (s *authService) Authenticate(ctx context.Context, pubKey string, signature
return nil, fmt.Errorf("failed to delete challenge: %w", err) return nil, fmt.Errorf("failed to delete challenge: %w", err)
} }
user, err := s.userRepo.GetByPubKey(ctx, pubKey) user, err := s.userRepo.GetOrCreateUserByPubKey(ctx, pubKey)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("failed to get or create user: %w", err)
}
if user == nil {
return nil, domain.ErrUserNotFound
} }
user.UpdateLastLogin() user.UpdateLastLogin()
if err := s.userRepo.Update(ctx, user); err != nil { if err := s.userRepo.Update(ctx, user); err != nil {
return nil, err return nil, fmt.Errorf("failed to update user: %w", err)
} }
expiresAt := time.Now().Add(time.Duration(s.cfg.TokenExpMinutes) * time.Minute) expiresAt := time.Now().Add(time.Duration(s.cfg.TokenExpMinutes) * time.Minute)