github.com/easysoft/zendata@v0.0.0-20240513203326-705bd5a7fd67/internal/server/service/instances.go (about)

     1  package serverService
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/easysoft/zendata/internal/pkg/domain"
    10  	"github.com/easysoft/zendata/internal/pkg/service"
    11  
    12  	consts "github.com/easysoft/zendata/internal/pkg/const"
    13  	"github.com/easysoft/zendata/internal/pkg/helper"
    14  	"github.com/easysoft/zendata/internal/pkg/model"
    15  	serverRepo "github.com/easysoft/zendata/internal/server/repo"
    16  	serverUtils "github.com/easysoft/zendata/internal/server/utils"
    17  	fileUtils "github.com/easysoft/zendata/pkg/utils/file"
    18  	"github.com/easysoft/zendata/pkg/utils/vari"
    19  	"gopkg.in/yaml.v3"
    20  	"gorm.io/gorm"
    21  )
    22  
    23  type InstancesService struct {
    24  	InstancesRepo  *serverRepo.InstancesRepo `inject:""`
    25  	ReferRepo      *serverRepo.ReferRepo     `inject:""`
    26  	ResService     *ResService               `inject:""`
    27  	SectionService *SectionService           `inject:""`
    28  	SectionRepo    *serverRepo.SectionRepo   `inject:""`
    29  
    30  	RangeService *service.RangeService `inject:""`
    31  }
    32  
    33  func (s *InstancesService) List(keywords string, page int) (list []*model.ZdInstances, total int) {
    34  	list, total, _ = s.InstancesRepo.List(strings.TrimSpace(keywords), page)
    35  	return
    36  }
    37  
    38  func (s *InstancesService) Get(id int) (instances model.ZdInstances, dirs []domain.Dir) {
    39  	instances, _ = s.InstancesRepo.Get(uint(id))
    40  
    41  	serverUtils.GetDirs(consts.ResDirYaml, &dirs)
    42  
    43  	return
    44  }
    45  
    46  func (s *InstancesService) Save(instances *model.ZdInstances) (err error) {
    47  	instances.Folder = serverUtils.DealWithPathSepRight(instances.Folder)
    48  	instances.Path = vari.WorkDir + instances.Folder + serverUtils.AddExt(instances.FileName, ".yaml")
    49  	instances.ReferName = helper.PathToName(instances.Path, consts.ResDirYaml, consts.ResTypeInstances)
    50  
    51  	if instances.ID == 0 {
    52  		err = s.Create(instances)
    53  	} else {
    54  		err = s.Update(instances)
    55  	}
    56  	s.updateYaml(instances.ID)
    57  
    58  	return
    59  }
    60  func (s *InstancesService) Create(instances *model.ZdInstances) (err error) {
    61  	err = s.InstancesRepo.Create(instances)
    62  
    63  	return
    64  }
    65  func (s *InstancesService) Update(instances *model.ZdInstances) (err error) {
    66  	var old model.ZdInstances
    67  	old, err = s.InstancesRepo.Get(instances.ID)
    68  	if err == gorm.ErrRecordNotFound {
    69  		return
    70  	}
    71  	if instances.Path != old.Path {
    72  		fileUtils.RemoveExist(old.Path)
    73  	}
    74  
    75  	err = s.InstancesRepo.Update(instances)
    76  
    77  	return
    78  }
    79  
    80  func (s *InstancesService) Remove(id int) (err error) {
    81  	var old model.ZdInstances
    82  	old, err = s.InstancesRepo.Get(uint(id))
    83  	if err == gorm.ErrRecordNotFound {
    84  		return
    85  	}
    86  
    87  	fileUtils.RemoveExist(old.Path)
    88  	err = s.InstancesRepo.Remove(uint(id))
    89  	return
    90  }
    91  
    92  func (s *InstancesService) updateYamlByItem(itemId uint) (err error) {
    93  	item, _ := s.InstancesRepo.GetItem(itemId)
    94  	return s.updateYaml(item.InstancesID)
    95  }
    96  func (s *InstancesService) updateYaml(id uint) (err error) {
    97  	var po model.ZdInstances
    98  	po, _ = s.InstancesRepo.Get(id)
    99  
   100  	s.genYaml(&po)
   101  	err = s.InstancesRepo.UpdateYaml(po)
   102  	fileUtils.WriteFile(po.Path, po.Yaml)
   103  
   104  	return
   105  }
   106  
   107  func (s *InstancesService) genYaml(instances *model.ZdInstances) (str string) {
   108  	//records, err := s.InstancesRepo.GetItems(instances.ID)
   109  	//if err != nil {
   110  	//	return
   111  	//}
   112  	//
   113  	//yamlObj := model.ResInstances{}
   114  	//s.InstancesRepo.GenInst(*instances, &yamlObj)
   115  	//
   116  	//for _, item := range records {
   117  	//	inst := instancesItemToResInstForExport(*item)
   118  	//
   119  	//	yamlObj.Instances = append(yamlObj.Instances, inst)
   120  	//}
   121  
   122  	root := s.GetItemTree(instances.ID)
   123  	for _, item := range root.Fields {
   124  		instances.Instances = append(instances.Instances, *item)
   125  	}
   126  	bytes, _ := yaml.Marshal(instances)
   127  	instances.Yaml = helper.ConvertYamlStringToMapFormat(bytes)
   128  
   129  	return
   130  }
   131  
   132  func (s *InstancesService) Sync(files []domain.ResFile) {
   133  	list := s.InstancesRepo.ListAll()
   134  
   135  	mp := map[string]*model.ZdInstances{}
   136  	for _, item := range list {
   137  		mp[item.Path] = item
   138  	}
   139  
   140  	for _, fi := range files {
   141  		_, found := mp[fi.Path]
   142  		if !found { // no record
   143  			s.SyncToDB(fi)
   144  		} else if fi.UpdatedAt.Unix() > mp[fi.Path].UpdatedAt.Unix() { // db is old
   145  			s.InstancesRepo.Remove(mp[fi.Path].ID)
   146  			s.SyncToDB(fi)
   147  		}
   148  	}
   149  
   150  	return
   151  }
   152  
   153  func (s *InstancesService) SyncToDB(fi domain.ResFile) (err error) {
   154  	content, _ := os.ReadFile(fi.Path)
   155  	yamlContent := helper.ReplaceSpecialChars(content)
   156  	po := model.ZdInstances{}
   157  	err = yaml.Unmarshal(yamlContent, &po)
   158  
   159  	po.Title = fi.Title
   160  	po.Desc = fi.Desc
   161  	po.Path = fi.Path
   162  	po.Folder = serverUtils.GetRelativePath(po.Path)
   163  	if strings.Index(po.Path, consts.ResDirYaml) > -1 {
   164  		po.ReferName = helper.PathToName(po.Path, consts.ResDirYaml, consts.ResTypeInstances)
   165  	} else {
   166  		po.ReferName = helper.PathToName(po.Path, consts.ResDirUsers, consts.ResTypeInstances)
   167  	}
   168  	po.FileName = fileUtils.GetFileName(po.Path)
   169  	po.Yaml = string(content)
   170  
   171  	s.InstancesRepo.Create(&po)
   172  
   173  	for i, item := range po.Instances {
   174  		item.Ord = i + 1
   175  		s.saveItemToDB(&item, po, fi.Path, 0, po.ID)
   176  	}
   177  
   178  	return
   179  }
   180  func (s *InstancesService) saveItemToDB(item *model.ZdInstancesItem, instances model.ZdInstances, currPath string, parentID, instancesID uint) {
   181  	if item.Froms != nil && len(item.Froms) > 0 {
   182  		for idx, from := range item.Froms {
   183  			if from.Field == "" {
   184  				from.Field = "from" + strconv.Itoa(idx+1)
   185  			}
   186  			s.saveItemToDB(from, instances, currPath, parentID, instancesID)
   187  		}
   188  
   189  		return
   190  	}
   191  
   192  	// update field
   193  	if item.Instance != "" { // instance node
   194  		item.Field = item.Instance
   195  	}
   196  
   197  	item.InstancesID = instancesID
   198  	item.ParentID = parentID
   199  	if item.From == "" && instances.From != "" {
   200  		item.From = instances.From
   201  	}
   202  	if item.Type == "" {
   203  		item.Type = consts.FieldTypeList
   204  	}
   205  	if item.Mode == "" {
   206  		item.Mode = consts.ModeParallel
   207  	}
   208  	item.Range = strings.TrimSpace(item.Range)
   209  
   210  	// save item
   211  	s.InstancesRepo.SaveItem(item)
   212  
   213  	// create refer
   214  	refer := model.ZdRefer{OwnerType: "instances", OwnerID: item.ID}
   215  
   216  	needToCreateSections := false
   217  	if item.Select != "" { // refer to excel
   218  		refer.Type = consts.ResTypeExcel
   219  
   220  		refer.ColName = item.Select
   221  		refer.Condition = item.Where
   222  		refer.Rand = item.Rand
   223  
   224  		_, sheet := fileUtils.ConvertResExcelPath(item.From, currPath)
   225  		refer.File = item.From
   226  		refer.Sheet = sheet
   227  
   228  	} else if item.Use != "" { // refer to ranges or instances, need to read yaml to get the type
   229  		rangeSections := s.RangeService.ParseRangeProperty(item.Use)
   230  		if len(rangeSections) > 0 { // only get the first one
   231  			rangeSection := rangeSections[0]
   232  			desc, _, count, countTag := s.RangeService.ParseRangeSection(rangeSection) // medium{2}
   233  			refer.ColName = desc
   234  			refer.Count = count
   235  			refer.CountTag = countTag
   236  		}
   237  
   238  		path := fileUtils.ConvertReferRangeToPath(item.From, currPath)
   239  		_, _, refer.Type = helper.ReadYamlInfo(path)
   240  		refer.File = item.From
   241  
   242  	} else if item.Config != "" { // refer to config
   243  		refer.Type = consts.ResTypeConfig
   244  
   245  		rangeSections := s.RangeService.ParseRangeProperty(item.Config) // dir/config.yaml
   246  		if len(rangeSections) > 0 {                                     // only get the first one
   247  			rangeSection := rangeSections[0]
   248  			desc, _, count, countTag := s.RangeService.ParseRangeSection(rangeSection)
   249  			refer.Count = count
   250  			refer.CountTag = countTag
   251  
   252  			path := fileUtils.ConvertReferRangeToPath(desc, currPath)
   253  			refer.File = GetRelatedPathWithResDir(path)
   254  		}
   255  
   256  	} else if item.Range != "" { // deal with yaml and text refer using range prop
   257  
   258  		rangeSections := s.RangeService.ParseRangeProperty(item.Range)
   259  		if len(rangeSections) > 0 { // only get the first one
   260  			rangeSection := rangeSections[0]
   261  			desc, step, count, countTag := s.RangeService.ParseRangeSection(rangeSection) // dir/users.txt:R{3}
   262  			if filepath.Ext(desc) == ".txt" || filepath.Ext(desc) == ".yaml" {
   263  				if filepath.Ext(desc) == ".txt" { // dir/users.txt:2
   264  					refer.Type = consts.ResTypeText
   265  
   266  					if strings.ToLower(step) == "r" {
   267  						refer.Rand = true
   268  					} else {
   269  						refer.Step, _ = strconv.Atoi(step)
   270  					}
   271  
   272  				} else if filepath.Ext(desc) == ".yaml" { // dir/content.yaml{3}
   273  					refer.Type = consts.ResTypeYaml
   274  
   275  					refer.Count = count
   276  					refer.CountTag = countTag
   277  				}
   278  
   279  				path := fileUtils.ConvertReferRangeToPath(desc, currPath)
   280  				refer.File = GetRelatedPathWithResDir(path)
   281  			} else { // like 1-9,a-z
   282  				needToCreateSections = true
   283  			}
   284  		}
   285  	}
   286  
   287  	// save refer
   288  	refer.OwnerID = item.ID
   289  	s.ReferRepo.Save(&refer)
   290  
   291  	// gen sections if needed
   292  	if needToCreateSections {
   293  		rangeSections := s.RangeService.ParseRangeProperty(item.Range)
   294  
   295  		for i, rangeSection := range rangeSections {
   296  			s.SectionService.SaveFieldSectionToDB(rangeSection, i, item.ID, "instances")
   297  		}
   298  	}
   299  
   300  	// deal with field's children
   301  	for i, child := range item.Fields {
   302  		child.Ord = i + 1
   303  		s.saveItemToDB(child, instances, currPath, item.ID, instancesID)
   304  	}
   305  }
   306  
   307  func NewInstancesService(instancesRepo *serverRepo.InstancesRepo, referRepo *serverRepo.ReferRepo,
   308  	sectionRepo *serverRepo.SectionRepo) *InstancesService {
   309  	return &InstancesService{InstancesRepo: instancesRepo, ReferRepo: referRepo, SectionRepo: sectionRepo}
   310  }