222 lines
7.1 KiB
Go
222 lines
7.1 KiB
Go
|
|
package utils
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"bubble/types"
|
|||
|
|
"fmt"
|
|||
|
|
"github.com/charmbracelet/bubbles/textinput"
|
|||
|
|
"github.com/expr-lang/expr"
|
|||
|
|
"github.com/sirupsen/logrus"
|
|||
|
|
"os/exec"
|
|||
|
|
"reflect"
|
|||
|
|
"regexp"
|
|||
|
|
"strconv"
|
|||
|
|
"strings"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// userRE - с начала строки, делит все по знаку двоеточия, берется первые 3 группы, пример user_name:x:1000:
|
|||
|
|
var userRE = regexp.MustCompile(`^([^:]+):[^:]*:([0-9]+):`)
|
|||
|
|
|
|||
|
|
// ComputeValue вычисляет значение для поля compute.
|
|||
|
|
func ComputeValue(computeExpr string, app *types.PackageApplication) (interface{}, error) {
|
|||
|
|
if computeExpr == "" {
|
|||
|
|
return nil, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
env := ParamsForCompute(app)
|
|||
|
|
options := append([]expr.Option{
|
|||
|
|
expr.Env(env),
|
|||
|
|
expr.AsKind(reflect.String), // по умолчанию строка, если не указано иное
|
|||
|
|
expr.AllowUndefinedVariables(),
|
|||
|
|
}, DefineExprCustomFunctions()...)
|
|||
|
|
|
|||
|
|
program, err := expr.Compile(computeExpr, options...)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, fmt.Errorf("ошибка компиляции compute: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
result, err := expr.Run(program, env)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, fmt.Errorf("ошибка выполнения compute: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Recompute производит перерасчет всех полей
|
|||
|
|
func Recompute(app *types.PackageApplication) {
|
|||
|
|
for i := range app.Sections {
|
|||
|
|
section := &app.Sections[i]
|
|||
|
|
for j := range section.Fields {
|
|||
|
|
field := §ion.Fields[j]
|
|||
|
|
if field.FieldType == "compute" && field.Compute != "" {
|
|||
|
|
value, err := ComputeValue(field.Compute, app)
|
|||
|
|
if err != nil {
|
|||
|
|
value = fmt.Sprintf("Ошибка вычисления: %v", err)
|
|||
|
|
}
|
|||
|
|
field.Variable.Value = value
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CheckCondition проверяет равно ли переданное условие
|
|||
|
|
func CheckCondition(condition string, app *types.PackageApplication) bool {
|
|||
|
|
if condition == "" {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
result, err := expr.Eval(condition, ParamsForCondition(app))
|
|||
|
|
|
|||
|
|
if err != nil {
|
|||
|
|
logrus.Errorf("Ошибка в условии '%s': %v", condition, err)
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
boolResult, ok := result.(bool)
|
|||
|
|
if !ok {
|
|||
|
|
logrus.Warnf("Условие '%s' не вернуло bool, а %T: %v", condition, result, result)
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return boolResult
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// IsParent проверяет, является ли указанная переменная условием для поля или секции
|
|||
|
|
func IsParent(variableName string, sections []types.Section) bool {
|
|||
|
|
for _, section := range sections {
|
|||
|
|
for _, parent := range section.Parent {
|
|||
|
|
if parent == variableName {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
for _, field := range section.Fields {
|
|||
|
|
for _, parent := range field.Parent {
|
|||
|
|
if parent == variableName {
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// IsMultiField проверяет переменную на использование несколькими полями.
|
|||
|
|
func IsMultiField(variableName string, applicationSections []types.Section) bool {
|
|||
|
|
var count int
|
|||
|
|
for _, section := range applicationSections {
|
|||
|
|
for _, field := range section.Fields {
|
|||
|
|
if field.Name == variableName {
|
|||
|
|
count++
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return count > 1
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// SpecialValueHandle получаем необычные значения полей
|
|||
|
|
func SpecialValueHandle(special string) interface{} {
|
|||
|
|
specialValue := strings.Split(special, "code:")[1]
|
|||
|
|
switch specialValue {
|
|||
|
|
case "users":
|
|||
|
|
return GetSystemUsers()
|
|||
|
|
}
|
|||
|
|
return true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetSystemUsers получение списка обычных пользователей в системе
|
|||
|
|
func GetSystemUsers() []string {
|
|||
|
|
//результат выполнения команды читающей файл passwd
|
|||
|
|
output, _ := exec.Command("getent", "passwd").Output()
|
|||
|
|
//массив строк разделенных новой строкой
|
|||
|
|
lines := strings.Split(string(output), "\n")
|
|||
|
|
var users []string
|
|||
|
|
for _, line := range lines {
|
|||
|
|
//линия совпадает с регулярным выражением
|
|||
|
|
if matches := userRE.FindStringSubmatch(line); len(matches) == 3 {
|
|||
|
|
//идентификатор больше или равен 1000, uid обычного пользователя в системе
|
|||
|
|
if uid, _ := strconv.Atoi(matches[2]); uid >= 1000 {
|
|||
|
|
users = append(users, matches[1])
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return users
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateCheckField создает функцию типа types.BoolValidateFunc для проверки значения bool полей
|
|||
|
|
func ValidateCheckField(fieldName, variableName string, validations []types.FieldValidate, app *types.PackageApplication) types.BoolValidateFunc {
|
|||
|
|
if len(validations) == 0 {
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
return func(checked bool) error {
|
|||
|
|
env := ParamsForCompute(app)
|
|||
|
|
env[variableName] = checked
|
|||
|
|
options := append([]expr.Option{
|
|||
|
|
expr.Env(env),
|
|||
|
|
expr.AllowUndefinedVariables(),
|
|||
|
|
}, DefineExprCustomFunctions()...)
|
|||
|
|
for _, validate := range validations {
|
|||
|
|
program, err := expr.Compile(validate.Rule, options...)
|
|||
|
|
prefix := fmt.Sprintf("Валидация поля %s,", fieldName)
|
|||
|
|
if err != nil {
|
|||
|
|
msg := fmt.Errorf("ошибка компиляции правила: %s, err: %v", validate.Rule, err)
|
|||
|
|
logrus.Errorf("%s %v", prefix, msg)
|
|||
|
|
return msg
|
|||
|
|
}
|
|||
|
|
result, err := expr.Run(program, env)
|
|||
|
|
if err != nil {
|
|||
|
|
msg := fmt.Errorf("ошибка выполнения правила: %s, err: %v", validate.Rule, err)
|
|||
|
|
logrus.Errorf("%s %v", prefix, msg)
|
|||
|
|
return msg
|
|||
|
|
}
|
|||
|
|
if boolValue, ok := result.(bool); ok && !boolValue {
|
|||
|
|
return fmt.Errorf("%s", validate.Message)
|
|||
|
|
} else if !ok {
|
|||
|
|
msg := fmt.Errorf("возвращаемое значение правила: %s не булево", validate.Rule)
|
|||
|
|
logrus.Errorf("%s %v", prefix, msg)
|
|||
|
|
return msg
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ValidateField создает функцию типа textinput.ValidateFunc для проверки значения text полей
|
|||
|
|
func ValidateField(fieldName, variableName string, validations []types.FieldValidate, app *types.PackageApplication) textinput.ValidateFunc {
|
|||
|
|
if len(validations) == 0 {
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
return func(text string) error {
|
|||
|
|
env := ParamsForCompute(app)
|
|||
|
|
env[variableName] = text
|
|||
|
|
options := append([]expr.Option{
|
|||
|
|
expr.Env(env),
|
|||
|
|
expr.AllowUndefinedVariables(),
|
|||
|
|
}, DefineExprCustomFunctions()...)
|
|||
|
|
for _, validate := range validations {
|
|||
|
|
program, err := expr.Compile(validate.Rule, options...)
|
|||
|
|
prefix := fmt.Sprintf("Валидация поля %s,", fieldName)
|
|||
|
|
if err != nil {
|
|||
|
|
msg := fmt.Errorf("ошибка компиляции правила: %s, err: %v", validate.Rule, err)
|
|||
|
|
logrus.Errorf("%s %v", prefix, msg)
|
|||
|
|
return msg
|
|||
|
|
}
|
|||
|
|
result, err := expr.Run(program, env)
|
|||
|
|
if err != nil {
|
|||
|
|
msg := fmt.Errorf("ошибка выполнения правила: %s, err: %v", validate.Rule, err)
|
|||
|
|
logrus.Errorf("%s %v", prefix, msg)
|
|||
|
|
return msg
|
|||
|
|
}
|
|||
|
|
if boolValue, ok := result.(bool); ok && !boolValue {
|
|||
|
|
return fmt.Errorf("%s", validate.Message)
|
|||
|
|
} else if !ok {
|
|||
|
|
msg := fmt.Errorf("возвращаемое значение правила: %s не булево", validate.Rule)
|
|||
|
|
logrus.Errorf("%s %v", prefix, msg)
|
|||
|
|
return msg
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
}
|