mirror of
				https://github.com/veops/oneterm.git
				synced 2025-11-01 03:12:39 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			204 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package service
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 
 | |
| 	"gorm.io/gorm"
 | |
| 
 | |
| 	"github.com/gin-gonic/gin"
 | |
| 	"github.com/veops/oneterm/internal/model"
 | |
| 	"github.com/veops/oneterm/internal/repository"
 | |
| 	dbpkg "github.com/veops/oneterm/pkg/db"
 | |
| )
 | |
| 
 | |
| // CommandTemplateService handles business logic for command templates
 | |
| type CommandTemplateService struct {
 | |
| 	repo repository.ICommandTemplateRepository
 | |
| }
 | |
| 
 | |
| // NewCommandTemplateService creates a new command template service
 | |
| func NewCommandTemplateService() *CommandTemplateService {
 | |
| 	repo := repository.NewCommandTemplateRepository(dbpkg.DB)
 | |
| 	return &CommandTemplateService{
 | |
| 		repo: repo,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // BuildQuery builds the base query for command templates
 | |
| func (s *CommandTemplateService) BuildQuery(ctx *gin.Context) (*gorm.DB, error) {
 | |
| 	db := dbpkg.DB.Model(model.DefaultCommandTemplate)
 | |
| 
 | |
| 	// Apply search filter
 | |
| 	if search := ctx.Query("search"); search != "" {
 | |
| 		db = db.Where("name LIKE ? OR description LIKE ?", "%"+search+"%", "%"+search+"%")
 | |
| 	}
 | |
| 
 | |
| 	// Apply category filter
 | |
| 	if category := ctx.Query("category"); category != "" {
 | |
| 		db = db.Where("category = ?", category)
 | |
| 	}
 | |
| 
 | |
| 	// Apply builtin filter
 | |
| 	if builtinStr := ctx.Query("builtin"); builtinStr != "" {
 | |
| 		builtin := builtinStr == "true"
 | |
| 		db = db.Where("is_builtin = ?", builtin)
 | |
| 	}
 | |
| 
 | |
| 	return db, nil
 | |
| }
 | |
| 
 | |
| // CreateCommandTemplate creates a new command template
 | |
| func (s *CommandTemplateService) CreateCommandTemplate(ctx context.Context, template *model.CommandTemplate) error {
 | |
| 	// Validate the template
 | |
| 	if err := s.ValidateCommandTemplate(template); err != nil {
 | |
| 		return fmt.Errorf("validation failed: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	// Check for duplicate names
 | |
| 	existing, err := s.repo.GetByName(ctx, template.Name)
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("failed to check existing template: %w", err)
 | |
| 	}
 | |
| 	if existing != nil {
 | |
| 		return errors.New("template with this name already exists")
 | |
| 	}
 | |
| 
 | |
| 	// Set default values
 | |
| 	template.IsBuiltin = false
 | |
| 
 | |
| 	return s.repo.Create(ctx, template)
 | |
| }
 | |
| 
 | |
| // GetCommandTemplate retrieves a command template by ID
 | |
| func (s *CommandTemplateService) GetCommandTemplate(ctx context.Context, id int) (*model.CommandTemplate, error) {
 | |
| 	return s.repo.GetByID(ctx, id)
 | |
| }
 | |
| 
 | |
| // GetCommandTemplateByName retrieves a command template by name
 | |
| func (s *CommandTemplateService) GetCommandTemplateByName(ctx context.Context, name string) (*model.CommandTemplate, error) {
 | |
| 	return s.repo.GetByName(ctx, name)
 | |
| }
 | |
| 
 | |
| // ListCommandTemplates retrieves command templates with pagination and filters
 | |
| func (s *CommandTemplateService) ListCommandTemplates(ctx context.Context, offset, limit int, category string, builtin *bool) ([]*model.CommandTemplate, int64, error) {
 | |
| 	return s.repo.List(ctx, offset, limit, category, builtin)
 | |
| }
 | |
| 
 | |
| // UpdateCommandTemplate updates an existing command template
 | |
| func (s *CommandTemplateService) UpdateCommandTemplate(ctx context.Context, template *model.CommandTemplate) error {
 | |
| 	// Validate the template
 | |
| 	if err := s.ValidateCommandTemplate(template); err != nil {
 | |
| 		return fmt.Errorf("validation failed: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	// Check if template exists
 | |
| 	existing, err := s.repo.GetByID(ctx, template.Id)
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("failed to get existing template: %w", err)
 | |
| 	}
 | |
| 	if existing == nil {
 | |
| 		return errors.New("command template not found")
 | |
| 	}
 | |
| 
 | |
| 	// Don't allow changing built-in status
 | |
| 	template.IsBuiltin = existing.IsBuiltin
 | |
| 
 | |
| 	return s.repo.Update(ctx, template)
 | |
| }
 | |
| 
 | |
| // DeleteCommandTemplate deletes a command template
 | |
| func (s *CommandTemplateService) DeleteCommandTemplate(ctx context.Context, id int) error {
 | |
| 	return s.repo.Delete(ctx, id)
 | |
| }
 | |
| 
 | |
| // GetBuiltInTemplates retrieves all built-in command templates
 | |
| func (s *CommandTemplateService) GetBuiltInTemplates(ctx context.Context) ([]*model.CommandTemplate, error) {
 | |
| 	return s.repo.GetBuiltInTemplates(ctx)
 | |
| }
 | |
| 
 | |
| // ValidateCommandTemplate validates a command template
 | |
| func (s *CommandTemplateService) ValidateCommandTemplate(template *model.CommandTemplate) error {
 | |
| 	if template.Name == "" {
 | |
| 		return errors.New("template name is required")
 | |
| 	}
 | |
| 
 | |
| 	if len(template.Name) > 128 {
 | |
| 		return errors.New("template name too long (max 128 characters)")
 | |
| 	}
 | |
| 
 | |
| 	if template.Category == "" {
 | |
| 		return errors.New("template category is required")
 | |
| 	}
 | |
| 
 | |
| 	// Validate category
 | |
| 	validCategories := []string{"security", "system", "database", "network", "file", "developer", "custom"}
 | |
| 	categoryValid := false
 | |
| 	for _, cat := range validCategories {
 | |
| 		if string(template.Category) == cat {
 | |
| 			categoryValid = true
 | |
| 			break
 | |
| 		}
 | |
| 	}
 | |
| 	if !categoryValid {
 | |
| 		return fmt.Errorf("invalid category: %s. Valid categories: %v", template.Category, validCategories)
 | |
| 	}
 | |
| 
 | |
| 	// Validate command IDs if provided
 | |
| 	if len(template.CmdIds) > 0 {
 | |
| 		if err := s.validateCommandIds(template.CmdIds); err != nil {
 | |
| 			return fmt.Errorf("invalid command IDs: %w", err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // validateCommandIds validates that all command IDs exist
 | |
| func (s *CommandTemplateService) validateCommandIds(cmdIds model.Slice[int]) error {
 | |
| 	if len(cmdIds) == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	// Convert model.Slice[int] to []int for SQL query
 | |
| 	ids := make([]int, len(cmdIds))
 | |
| 	copy(ids, cmdIds)
 | |
| 
 | |
| 	// Check if all command IDs exist
 | |
| 	var count int64
 | |
| 	err := dbpkg.DB.Model(&model.Command{}).Where("id IN ?", ids).Count(&count).Error
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("failed to validate command IDs: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	if int(count) != len(cmdIds) {
 | |
| 		return errors.New("some command IDs do not exist")
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // GetTemplateCommands retrieves all commands for a template
 | |
| func (s *CommandTemplateService) GetTemplateCommands(ctx context.Context, templateId int) ([]*model.Command, error) {
 | |
| 	template, err := s.repo.GetByID(ctx, templateId)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	if template == nil {
 | |
| 		return nil, errors.New("command template not found")
 | |
| 	}
 | |
| 
 | |
| 	if len(template.CmdIds) == 0 {
 | |
| 		return []*model.Command{}, nil
 | |
| 	}
 | |
| 
 | |
| 	// Convert model.Slice[int] to []int for SQL query
 | |
| 	ids := make([]int, len(template.CmdIds))
 | |
| 	copy(ids, template.CmdIds)
 | |
| 
 | |
| 	var commands []*model.Command
 | |
| 	err = dbpkg.DB.WithContext(ctx).Where("id IN ?", ids).Find(&commands).Error
 | |
| 	return commands, err
 | |
| }
 | 
