github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/db/template.go (about)

     1  // This file is part of the Smart Home
     2  // Program complex distribution https://github.com/e154/smart-home
     3  // Copyright (C) 2016-2023, Filippov Alex
     4  //
     5  // This library is free software: you can redistribute it and/or
     6  // modify it under the terms of the GNU Lesser General Public
     7  // License as published by the Free Software Foundation; either
     8  // version 3 of the License, or (at your option) any later version.
     9  //
    10  // This library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13  // Library General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public
    16  // License along with this library.  If not, see
    17  // <https://www.gnu.org/licenses/>.
    18  
    19  package db
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"time"
    25  
    26  	"github.com/e154/smart-home/common/apperr"
    27  
    28  	"github.com/pkg/errors"
    29  	"gorm.io/gorm"
    30  )
    31  
    32  // Templates ...
    33  type Templates struct {
    34  	Db *gorm.DB
    35  }
    36  
    37  // TemplateTree ...
    38  type TemplateTree struct {
    39  	Name        string          `json:"name"`
    40  	Description string          `json:"description"`
    41  	Status      string          `json:"status"`
    42  	Nodes       []*TemplateTree `json:"nodes"`
    43  }
    44  
    45  // Template ...
    46  type Template struct {
    47  	Name        string `gorm:"primary_key"`
    48  	Description string
    49  	Content     string
    50  	Status      string
    51  	Type        string
    52  	ParentName  *string   `gorm:"column:parent"`
    53  	CreatedAt   time.Time `gorm:"<-:create"`
    54  	UpdatedAt   time.Time
    55  }
    56  
    57  // TableName ...
    58  func (d *Template) TableName() string {
    59  	return "templates"
    60  }
    61  
    62  // UpdateOrCreate ...
    63  func (n Templates) UpdateOrCreate(ctx context.Context, tpl *Template) (err error) {
    64  
    65  	if err = n.Db.WithContext(ctx).Create(tpl).Error; err != nil {
    66  		if err = n.Update(ctx, tpl); err != nil {
    67  			err = errors.Wrap(apperr.ErrTemplateUpdate, err.Error())
    68  			return
    69  		}
    70  	}
    71  
    72  	return
    73  }
    74  
    75  // Create ...
    76  func (n Templates) Create(ctx context.Context, tpl *Template) (err error) {
    77  	if err = n.Db.WithContext(ctx).Create(tpl).Error; err != nil {
    78  		err = errors.Wrap(apperr.ErrTemplateAdd, err.Error())
    79  	}
    80  	return
    81  }
    82  
    83  // GetByName ...
    84  func (n Templates) GetByName(ctx context.Context, name, itemType string) (*Template, error) {
    85  
    86  	tpl := &Template{}
    87  	err := n.Db.WithContext(ctx).Model(tpl).
    88  		Where("name = ? and type = ?", name, itemType).
    89  		First(&tpl).Error
    90  
    91  	if err != nil {
    92  		if errors.Is(err, gorm.ErrRecordNotFound) {
    93  			err = errors.Wrap(apperr.ErrTemplateNotFound, fmt.Sprintf("name \"%s\"", name))
    94  			return nil, err
    95  		}
    96  		err = errors.Wrap(apperr.ErrTemplateGet, err.Error())
    97  	}
    98  
    99  	return tpl, nil
   100  }
   101  
   102  // GetItemsSortedList ...
   103  func (n Templates) GetItemsSortedList(ctx context.Context) (count int64, newItems []string, err error) {
   104  
   105  	items := make([]*Template, 0)
   106  	err = n.Db.WithContext(ctx).Model(&Template{}).
   107  		Where("type = 'item' and status = 'active'").
   108  		Find(&items).
   109  		Error
   110  
   111  	if err != nil {
   112  		err = errors.Wrap(apperr.ErrTemplateList, err.Error())
   113  		return
   114  	}
   115  
   116  	newItems = make([]string, 0)
   117  
   118  	treeGetEndPoints := func(i []*Template, t *[]string) {
   119  		for _, v := range i {
   120  			var exist bool
   121  			for _, k := range i {
   122  				if k.ParentName == &v.Name {
   123  					exist = true
   124  					break
   125  				}
   126  			}
   127  
   128  			if !exist {
   129  				*t = append(*t, v.Name)
   130  			}
   131  		}
   132  	}
   133  	treeGetEndPoints(items, &newItems)
   134  	count = int64(len(newItems))
   135  
   136  	return
   137  }
   138  
   139  // Update ...
   140  func (n Templates) Update(ctx context.Context, m *Template) error {
   141  	err := n.Db.WithContext(ctx).Model(&Template{Name: m.Name}).Updates(map[string]interface{}{
   142  		"name":        m.Name,
   143  		"description": m.Description,
   144  		"status":      m.Status,
   145  		"type":        m.Type,
   146  		"content":     m.Content,
   147  		"parent":      m.ParentName,
   148  	}).Error
   149  
   150  	if err != nil {
   151  		err = errors.Wrap(apperr.ErrTemplateUpdate, err.Error())
   152  	}
   153  	return nil
   154  }
   155  
   156  // UpdateStatus ...
   157  func (n Templates) UpdateStatus(ctx context.Context, m *Template) error {
   158  	err := n.Db.WithContext(ctx).Model(&Template{Name: m.Name}).Updates(map[string]interface{}{
   159  		"status": m.Status,
   160  	}).Error
   161  
   162  	if err != nil {
   163  		err = errors.Wrap(apperr.ErrTemplateUpdate, err.Error())
   164  	}
   165  	return nil
   166  }
   167  
   168  // Delete ...
   169  func (n Templates) Delete(ctx context.Context, name string) (err error) {
   170  	if err = n.Db.WithContext(ctx).Delete(&Template{Name: name}).Error; err != nil {
   171  		err = errors.Wrap(apperr.ErrTemplateDelete, err.Error())
   172  	}
   173  	return
   174  }
   175  
   176  // GetItemsTree ...
   177  func (n Templates) GetItemsTree(ctx context.Context) (tree []*TemplateTree, err error) {
   178  
   179  	var items []*Template
   180  	if items, err = n.GetList(ctx, "item"); err != nil {
   181  		err = errors.Wrap(apperr.ErrTemplateGet, err.Error())
   182  		return
   183  	}
   184  
   185  	tree = make([]*TemplateTree, 0)
   186  	for _, item := range items {
   187  		if item.ParentName == nil {
   188  			branch := &TemplateTree{
   189  				Description: item.Description,
   190  				Name:        item.Name,
   191  				Nodes:       make([]*TemplateTree, 0),
   192  				Status:      item.Status,
   193  			}
   194  			n.renderTreeRecursive(ctx, items, branch, branch.Name)
   195  			tree = append(tree, branch)
   196  		}
   197  	}
   198  
   199  	return
   200  }
   201  
   202  // GetList ...
   203  func (n Templates) GetList(ctx context.Context, templateType string) ([]*Template, error) {
   204  	items := make([]*Template, 0)
   205  	err := n.Db.WithContext(ctx).Model(&Template{}).
   206  		Where("type = ?", templateType).
   207  		Find(&items).
   208  		Error
   209  
   210  	if err != nil {
   211  		err = errors.Wrap(apperr.ErrTemplateGet, err.Error())
   212  	}
   213  
   214  	return items, nil
   215  }
   216  
   217  // Search ...
   218  func (n *Templates) Search(ctx context.Context, query string, limit, offset int) (items []*Template, total int64, err error) {
   219  
   220  	q := n.Db.WithContext(ctx).Model(&Template{}).
   221  		Where("name LIKE ?", "%"+query+"%").
   222  		Where("type = 'template'")
   223  
   224  	if err = q.Count(&total).Error; err != nil {
   225  		err = errors.Wrap(apperr.ErrTemplateSearch, err.Error())
   226  		return
   227  	}
   228  
   229  	q = q.
   230  		Limit(limit).
   231  		Offset(offset).
   232  		Order("name ASC")
   233  
   234  	items = make([]*Template, 0)
   235  	if err = q.Find(&items).Error; err != nil {
   236  		err = errors.Wrap(apperr.ErrTemplateSearch, err.Error())
   237  	}
   238  
   239  	return
   240  }
   241  
   242  func (n Templates) renderTreeRecursive(ctx context.Context, i []*Template, t *TemplateTree, c string) {
   243  
   244  	for _, item := range i {
   245  		if item.ParentName != nil && *item.ParentName == c {
   246  			tree := &TemplateTree{}
   247  			tree.Name = item.Name
   248  			tree.Description = item.Description
   249  			tree.Nodes = make([]*TemplateTree, 0) // fix - nodes: null
   250  			tree.Status = item.Status
   251  			t.Nodes = append(t.Nodes, tree)
   252  			n.renderTreeRecursive(ctx, i, tree, item.Name)
   253  		}
   254  	}
   255  }
   256  
   257  // UpdateItemsTree ...
   258  func (n Templates) UpdateItemsTree(ctx context.Context, tree []*TemplateTree, parent string) error {
   259  
   260  	for _, v := range tree {
   261  		if parent != "" {
   262  			go n.emailItemParentUpdate(ctx, v.Name, parent)
   263  		}
   264  
   265  		err := n.Db.WithContext(ctx).Model(&Template{Name: v.Name}).Updates(map[string]interface{}{
   266  			"parent": nil,
   267  		}).Error
   268  		if err != nil {
   269  			err = errors.Wrap(apperr.ErrTemplateUpdate, err.Error())
   270  		}
   271  
   272  		if len(v.Nodes) == 0 {
   273  			continue
   274  		}
   275  
   276  		n.updateTreeRecursive(ctx, v.Nodes, v.Name)
   277  	}
   278  
   279  	return nil
   280  }
   281  
   282  func (n Templates) emailItemParentUpdate(ctx context.Context, name, parent string) {
   283  
   284  	_ = n.Db.WithContext(ctx).Model(&Template{}).
   285  		Where("name = ?", name).
   286  		Updates(map[string]interface{}{
   287  			"parent": parent,
   288  		}).Error
   289  }
   290  
   291  func (n Templates) updateTreeRecursive(ctx context.Context, t []*TemplateTree, parent string) {
   292  
   293  	for _, v := range t {
   294  		if parent != "" {
   295  			go n.emailItemParentUpdate(ctx, v.Name, parent)
   296  		}
   297  		n.updateTreeRecursive(ctx, v.Nodes, v.Name)
   298  	}
   299  
   300  }