feature/core-service-auth #1
@@ -74,11 +74,25 @@ type RegisterRequest struct {
|
|||||||
OrganizationType string `json:"organization_type"`
|
OrganizationType string `json:"organization_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserResponse ответ с информацией о пользователе
|
||||||
|
type UserResponse struct {
|
||||||
|
ID uuid.UUID `json:"id"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Role string `json:"role"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrganizationResponse ответ с информацией об организации
|
||||||
|
type OrganizationResponse struct {
|
||||||
|
ID uuid.UUID `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
// LoginResponse ответ на аутентификацию
|
// LoginResponse ответ на аутентификацию
|
||||||
type LoginResponse struct {
|
type LoginResponse struct {
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
User User `json:"user"`
|
User UserResponse `json:"user"`
|
||||||
ExpiresAt time.Time `json:"expires_at"`
|
Organization OrganizationResponse `json:"organization"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateLocationRequest запрос на создание места хранения
|
// CreateLocationRequest запрос на создание места хранения
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package repository
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"erp-mvp/core-service/internal/models"
|
"erp-mvp/core-service/internal/models"
|
||||||
@@ -29,7 +30,13 @@ func (r *organizationRepository) Create(ctx context.Context, org *models.Organiz
|
|||||||
VALUES ($1, $2, $3, $4, $5)
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
`
|
`
|
||||||
|
|
||||||
_, err := r.db.ExecContext(ctx, query, org.ID, org.Name, org.Type, org.Settings, org.CreatedAt)
|
// Конвертируем JSON в строку
|
||||||
|
settingsJSON, err := json.Marshal(org.Settings)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to marshal settings: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.db.ExecContext(ctx, query, org.ID, org.Name, org.Type, string(settingsJSON), org.CreatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create organization: %w", err)
|
return fmt.Errorf("failed to create organization: %w", err)
|
||||||
}
|
}
|
||||||
@@ -44,12 +51,13 @@ func (r *organizationRepository) GetByID(ctx context.Context, id uuid.UUID) (*mo
|
|||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
|
var settingsJSON []byte
|
||||||
org := &models.Organization{}
|
org := &models.Organization{}
|
||||||
err := r.db.QueryRowContext(ctx, query, id).Scan(
|
err := r.db.QueryRowContext(ctx, query, id).Scan(
|
||||||
&org.ID,
|
&org.ID,
|
||||||
&org.Name,
|
&org.Name,
|
||||||
&org.Type,
|
&org.Type,
|
||||||
&org.Settings,
|
&settingsJSON,
|
||||||
&org.CreatedAt,
|
&org.CreatedAt,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -60,6 +68,16 @@ func (r *organizationRepository) GetByID(ctx context.Context, id uuid.UUID) (*mo
|
|||||||
return nil, fmt.Errorf("failed to get organization: %w", err)
|
return nil, fmt.Errorf("failed to get organization: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Конвертируем JSON строку в map
|
||||||
|
if len(settingsJSON) > 0 {
|
||||||
|
err = json.Unmarshal(settingsJSON, &org.Settings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to unmarshal settings: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
org.Settings = make(models.JSON)
|
||||||
|
}
|
||||||
|
|
||||||
return org, nil
|
return org, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +88,13 @@ func (r *organizationRepository) Update(ctx context.Context, org *models.Organiz
|
|||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
result, err := r.db.ExecContext(ctx, query, org.ID, org.Name, org.Type, org.Settings)
|
// Конвертируем JSON в строку
|
||||||
|
settingsJSON, err := json.Marshal(org.Settings)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to marshal settings: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := r.db.ExecContext(ctx, query, org.ID, org.Name, org.Type, string(settingsJSON))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to update organization: %w", err)
|
return fmt.Errorf("failed to update organization: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import (
|
|||||||
"erp-mvp/core-service/internal/auth"
|
"erp-mvp/core-service/internal/auth"
|
||||||
"erp-mvp/core-service/internal/models"
|
"erp-mvp/core-service/internal/models"
|
||||||
"erp-mvp/core-service/internal/repository"
|
"erp-mvp/core-service/internal/repository"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AuthService interface {
|
type AuthService interface {
|
||||||
@@ -19,6 +21,7 @@ type authService struct {
|
|||||||
orgRepo repository.OrganizationRepository
|
orgRepo repository.OrganizationRepository
|
||||||
userRepo repository.UserRepository
|
userRepo repository.UserRepository
|
||||||
jwtService *auth.JWTService
|
jwtService *auth.JWTService
|
||||||
|
logger *logrus.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAuthService(orgRepo repository.OrganizationRepository, userRepo repository.UserRepository, jwtService *auth.JWTService) AuthService {
|
func NewAuthService(orgRepo repository.OrganizationRepository, userRepo repository.UserRepository, jwtService *auth.JWTService) AuthService {
|
||||||
@@ -26,37 +29,46 @@ func NewAuthService(orgRepo repository.OrganizationRepository, userRepo reposito
|
|||||||
orgRepo: orgRepo,
|
orgRepo: orgRepo,
|
||||||
userRepo: userRepo,
|
userRepo: userRepo,
|
||||||
jwtService: jwtService,
|
jwtService: jwtService,
|
||||||
|
logger: logrus.New(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *authService) Register(ctx context.Context, req *models.RegisterRequest) (*models.LoginResponse, error) {
|
func (s *authService) Register(ctx context.Context, req *models.RegisterRequest) (*models.LoginResponse, error) {
|
||||||
|
s.logger.Info("Starting registration process")
|
||||||
|
|
||||||
// Проверяем, что пользователь с таким email не существует
|
// Проверяем, что пользователь с таким email не существует
|
||||||
existingUser, err := s.userRepo.GetByEmail(ctx, req.UserEmail)
|
existingUser, err := s.userRepo.GetByEmail(ctx, req.UserEmail)
|
||||||
if err == nil && existingUser != nil {
|
if err == nil && existingUser != nil {
|
||||||
|
s.logger.Error("User with this email already exists")
|
||||||
return nil, &ValidationError{Message: "User with this email already exists"}
|
return nil, &ValidationError{Message: "User with this email already exists"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Создаём организацию
|
// Создаем организацию
|
||||||
orgID := uuid.New()
|
orgID := uuid.New()
|
||||||
org := &models.Organization{
|
org := &models.Organization{
|
||||||
ID: orgID,
|
ID: orgID,
|
||||||
Name: req.OrganizationName,
|
Name: req.OrganizationName,
|
||||||
Type: req.OrganizationType,
|
Type: req.OrganizationType,
|
||||||
Settings: models.JSON{},
|
Settings: models.JSON{"created_at": time.Now().Unix()},
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.logger.Info("Creating organization with ID: ", orgID)
|
||||||
if err := s.orgRepo.Create(ctx, org); err != nil {
|
if err := s.orgRepo.Create(ctx, org); err != nil {
|
||||||
|
s.logger.Error("Failed to create organization: ", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
s.logger.Info("Organization created successfully")
|
||||||
|
|
||||||
// Хешируем пароль
|
// Хешируем пароль
|
||||||
passwordHash, err := auth.HashPassword(req.UserPassword)
|
passwordHash, err := auth.HashPassword(req.UserPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to hash password: ", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
s.logger.Info("Password hashed successfully")
|
||||||
|
|
||||||
// Создаём пользователя
|
// Создаем пользователя
|
||||||
userID := uuid.New()
|
userID := uuid.New()
|
||||||
user := &models.User{
|
user := &models.User{
|
||||||
ID: userID,
|
ID: userID,
|
||||||
@@ -66,20 +78,33 @@ func (s *authService) Register(ctx context.Context, req *models.RegisterRequest)
|
|||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.logger.Info("Creating user with ID: ", userID)
|
||||||
if err := s.userRepo.Create(ctx, user, passwordHash); err != nil {
|
if err := s.userRepo.Create(ctx, user, passwordHash); err != nil {
|
||||||
|
s.logger.Error("Failed to create user: ", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
s.logger.Info("User created successfully")
|
||||||
|
|
||||||
// Генерируем JWT токен
|
// Генерируем JWT токен
|
||||||
token, err := s.jwtService.GenerateToken(user.ID, org.ID, user.Email, user.Role)
|
token, err := s.jwtService.GenerateToken(user.ID, org.ID, user.Email, user.Role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to generate token: ", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
s.logger.Info("JWT token generated successfully")
|
||||||
|
|
||||||
return &models.LoginResponse{
|
return &models.LoginResponse{
|
||||||
Token: token,
|
Token: token,
|
||||||
User: *user,
|
User: models.UserResponse{
|
||||||
ExpiresAt: time.Now().Add(24 * time.Hour), // TTL из конфигурации
|
ID: user.ID,
|
||||||
|
Email: user.Email,
|
||||||
|
Role: user.Role,
|
||||||
|
},
|
||||||
|
Organization: models.OrganizationResponse{
|
||||||
|
ID: org.ID,
|
||||||
|
Name: org.Name,
|
||||||
|
Type: org.Type,
|
||||||
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,10 +126,24 @@ func (s *authService) Login(ctx context.Context, req *models.LoginRequest) (*mod
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Получаем организацию для ответа
|
||||||
|
org, err := s.orgRepo.GetByID(ctx, user.OrganizationID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &models.LoginResponse{
|
return &models.LoginResponse{
|
||||||
Token: token,
|
Token: token,
|
||||||
User: *user,
|
User: models.UserResponse{
|
||||||
ExpiresAt: time.Now().Add(24 * time.Hour), // TTL из конфигурации
|
ID: user.ID,
|
||||||
|
Email: user.Email,
|
||||||
|
Role: user.Role,
|
||||||
|
},
|
||||||
|
Organization: models.OrganizationResponse{
|
||||||
|
ID: org.ID,
|
||||||
|
Name: org.Name,
|
||||||
|
Type: org.Type,
|
||||||
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user