package service import ( "context" "errors" "fmt" "time" "github.com/google/uuid" "github.com/muyuqingfeng/iloom/auth-service/internal/model" "github.com/muyuqingfeng/iloom/auth-service/internal/repository" "github.com/muyuqingfeng/iloom/shared/pkg/auth" sgrpc "github.com/muyuqingfeng/iloom/shared/pkg/grpc" ) var roleIDMap = map[string]string{ "purchaser": "r_010", "textile": "r_011", "washing": "r_012", } type AuthService struct { profileRepo *repository.ProfileRepo compRepo *repository.CompanyRepo memberRepo *repository.MemberRepo sysClient *sgrpc.SystemClient jwt *auth.JWTManager } func NewAuthService( profileRepo *repository.ProfileRepo, compRepo *repository.CompanyRepo, memberRepo *repository.MemberRepo, sysClient *sgrpc.SystemClient, jwt *auth.JWTManager, ) *AuthService { return &AuthService{ profileRepo: profileRepo, compRepo: compRepo, memberRepo: memberRepo, sysClient: sysClient, jwt: jwt, } } type RegisterRequest struct { Username string `json:"username"` Password string `json:"password"` CompanyName string `json:"company_name"` Role string `json:"role"` } type LoginResponse struct { AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token"` User *model.Profile `json:"user"` Company *model.Company `json:"company"` } type ProfileWithCompany struct { User *model.Profile `json:"user"` Company *model.Company `json:"company,omitempty"` } func (s *AuthService) Register(ctx context.Context, req RegisterRequest) (*LoginResponse, error) { roleID, ok := roleIDMap[req.Role] if !ok { return nil, errors.New("invalid role") } userID, err := s.sysClient.CreateUser(ctx, req.Username, req.Password, "", "", roleID) if err != nil { return nil, fmt.Errorf("create user: %w", err) } now := time.Now() companyID := uuid.New().String() company := &model.Company{ ID: companyID, Name: req.CompanyName, Role: req.Role, Status: 1, CreatedAt: now, } if err := s.compRepo.Create(ctx, company); err != nil { return nil, fmt.Errorf("create company: %w", err) } member := &model.CompanyMember{ ID: uuid.New().String(), CompanyID: companyID, UserID: userID, Role: "owner", IsMaster: true, CreatedAt: now, } if err := s.memberRepo.Create(ctx, member); err != nil { return nil, fmt.Errorf("create member: %w", err) } profile := &model.Profile{ ID: userID, Username: req.Username, CompanyID: companyID, CompanyName: req.CompanyName, Role: req.Role, IsMaster: true, CreatedAt: now, } return s.generateTokens(profile, company) } func (s *AuthService) Login(ctx context.Context, username, password string) (*LoginResponse, error) { result, err := s.sysClient.Login(ctx, username, password, "") if err != nil { return nil, errors.New("invalid credentials") } profile, err := s.profileRepo.GetWithCompany(ctx, result.UserID) if err != nil { return nil, fmt.Errorf("get profile: %w", err) } if profile == nil { profile = &model.Profile{ ID: result.UserID, Username: result.Username, RealName: result.RealName, Avatar: result.Avatar, } } var company *model.Company if profile.CompanyID != "" { company, err = s.compRepo.GetByID(ctx, profile.CompanyID) if err != nil { return nil, fmt.Errorf("get company: %w", err) } } return s.generateTokens(profile, company) } func (s *AuthService) RefreshToken(ctx context.Context, refreshToken string) (string, error) { userID, err := s.jwt.ParseRefreshToken(refreshToken) if err != nil { return "", fmt.Errorf("invalid refresh token: %w", err) } profile, err := s.profileRepo.GetWithCompany(ctx, userID) if err != nil { return "", fmt.Errorf("get user: %w", err) } if profile == nil { return "", errors.New("user not found") } claims := auth.Claims{ UserID: profile.ID, CompanyID: profile.CompanyID, Role: profile.Role, IsMaster: profile.IsMaster, Username: profile.Username, } return s.jwt.GenerateAccessToken(claims) } func (s *AuthService) GetMe(ctx context.Context, userID string) (*ProfileWithCompany, error) { profile, err := s.profileRepo.GetWithCompany(ctx, userID) if err != nil { return nil, fmt.Errorf("get profile: %w", err) } if profile == nil { return nil, errors.New("user not found") } result := &ProfileWithCompany{User: profile} if profile.CompanyID != "" { company, err := s.compRepo.GetByID(ctx, profile.CompanyID) if err != nil { return nil, fmt.Errorf("get company: %w", err) } result.Company = company } return result, nil } func (s *AuthService) generateTokens(profile *model.Profile, company *model.Company) (*LoginResponse, error) { role := profile.Role if role == "" && company != nil { role = company.Role } claims := auth.Claims{ UserID: profile.ID, CompanyID: profile.CompanyID, Role: role, IsMaster: profile.IsMaster, Username: profile.Username, } accessToken, err := s.jwt.GenerateAccessToken(claims) if err != nil { return nil, fmt.Errorf("generate access token: %w", err) } refreshToken, err := s.jwt.GenerateRefreshToken(profile.ID) if err != nil { return nil, fmt.Errorf("generate refresh token: %w", err) } return &LoginResponse{ AccessToken: accessToken, RefreshToken: refreshToken, User: profile, Company: company, }, nil }