Files
user-system/internal/service/auth_capabilities.go
long-agent 09beb173cc feat: complete production readiness improvements
- Fix DIP violations in service layer (device, stats, auth middleware)
- Add ReplaceUserRoles interface method for transaction safety
- Implement Magic Bytes validation for avatar uploads
- Standardize OAuth error handling with ErrOAuthProviderNotSupported
- Use crypto/rand for JWT secret generation instead of weak fixed key
- Apply code formatting with gofumpt and goimports
- Fix staticcheck issues (S1024, S1008, ST1005)
- Add comprehensive quality and functional test reports
- Achieve 36.3% test coverage (up from 16.3%)
- All E2E, integration, and business logic tests passing
2026-04-12 16:15:32 +08:00

96 lines
2.7 KiB
Go

package service
import (
"context"
"errors"
"log"
"github.com/user-management-system/internal/auth"
"github.com/user-management-system/internal/domain"
"gorm.io/gorm"
)
const adminRoleCode = "admin"
type AuthCapabilities struct {
Password bool `json:"password"`
EmailActivation bool `json:"email_activation"`
EmailCode bool `json:"email_code"`
SMSCode bool `json:"sms_code"`
PasswordReset bool `json:"password_reset"`
AdminBootstrapRequired bool `json:"admin_bootstrap_required"`
OAuthProviders []auth.OAuthProviderInfo `json:"oauth_providers"`
}
func (s *AuthService) SupportsEmailActivation() bool {
return s != nil && s.emailActivationSvc != nil
}
func (s *AuthService) SupportsEmailCodeLogin() bool {
return s != nil && s.emailCodeSvc != nil
}
func (s *AuthService) SupportsSMSCodeLogin() bool {
return s != nil && s.smsCodeSvc != nil
}
func (s *AuthService) GetAuthCapabilities(ctx context.Context) AuthCapabilities {
if ctx == nil {
ctx = context.Background()
}
return AuthCapabilities{
Password: true,
EmailActivation: s.SupportsEmailActivation(),
EmailCode: s.SupportsEmailCodeLogin(),
SMSCode: s.SupportsSMSCodeLogin(),
AdminBootstrapRequired: s.IsAdminBootstrapRequired(ctx),
OAuthProviders: s.GetEnabledOAuthProviders(),
}
}
func (s *AuthService) IsAdminBootstrapRequired(ctx context.Context) bool {
if s == nil || s.userRepo == nil || s.roleRepo == nil || s.userRoleRepo == nil {
return false
}
if ctx == nil {
ctx = context.Background()
}
adminRole, err := s.roleRepo.GetByCode(ctx, adminRoleCode)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return true
}
log.Printf("auth: resolve auth capabilities failed while loading admin role: %v", err)
return false
}
userIDs, err := s.userRoleRepo.GetUserIDByRoleID(ctx, adminRole.ID)
if err != nil {
log.Printf("auth: resolve auth capabilities failed while loading admin users: role_id=%d err=%v", adminRole.ID, err)
return false
}
if len(userIDs) == 0 {
return true
}
hadUnexpectedLookupError := false
for _, userID := range userIDs {
user, err := s.userRepo.GetByID(ctx, userID)
if err != nil {
if isUserNotFoundError(err) {
continue
}
hadUnexpectedLookupError = true
log.Printf("auth: resolve auth capabilities failed while loading admin user: user_id=%d err=%v", userID, err)
continue
}
if user != nil && user.Status == domain.UserStatusActive {
return false
}
}
return !hadUnexpectedLookupError
}