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
This commit is contained in:
@@ -20,6 +20,18 @@ const (
|
||||
ExportFormatXLSX = "xlsx"
|
||||
)
|
||||
|
||||
// Interfaces for dependency inversion (DIP) — service layer depends on these abstractions, not concrete types.
|
||||
type exportUserRepository interface {
|
||||
List(ctx context.Context, offset, limit int) ([]*domain.User, int64, error)
|
||||
AdvancedSearch(ctx context.Context, filter *repository.AdvancedFilter) ([]*domain.User, int64, error)
|
||||
ExistsByUsername(ctx context.Context, username string) (bool, error)
|
||||
Create(ctx context.Context, user *domain.User) error
|
||||
}
|
||||
|
||||
type exportRoleRepository interface {
|
||||
// Reserved for future use (role assignment during import)
|
||||
}
|
||||
|
||||
// ExportUsersRequest defines the supported export filters and output options.
|
||||
type ExportUsersRequest struct {
|
||||
Format string
|
||||
@@ -53,14 +65,14 @@ var defaultExportColumns = []exportColumn{
|
||||
|
||||
// ExportService 用户数据导入导出服务
|
||||
type ExportService struct {
|
||||
userRepo *repository.UserRepository
|
||||
roleRepo *repository.RoleRepository
|
||||
userRepo exportUserRepository
|
||||
roleRepo exportRoleRepository
|
||||
}
|
||||
|
||||
// NewExportService 创建导入导出服务
|
||||
func NewExportService(
|
||||
userRepo *repository.UserRepository,
|
||||
roleRepo *repository.RoleRepository,
|
||||
userRepo exportUserRepository,
|
||||
roleRepo exportRoleRepository,
|
||||
) *ExportService {
|
||||
return &ExportService{
|
||||
userRepo: userRepo,
|
||||
@@ -461,13 +473,13 @@ func parseCSVRecords(data []byte) ([][]string, error) {
|
||||
func parseXLSXRecords(data []byte) ([][]string, error) {
|
||||
file, err := excelize.OpenReader(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Excel 解析失败: %w", err)
|
||||
return nil, fmt.Errorf("excel parse failed: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
sheets := file.GetSheetList()
|
||||
if len(sheets) == 0 {
|
||||
return nil, fmt.Errorf("Excel 文件没有可用工作表")
|
||||
return nil, fmt.Errorf("excel file has no available sheets")
|
||||
}
|
||||
|
||||
rows, err := file.GetRows(sheets[0])
|
||||
|
||||
Reference in New Issue
Block a user