125 lines
3.5 KiB
Go
125 lines
3.5 KiB
Go
package rule
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
)
|
|
|
|
type PageQuery struct {
|
|
PageIndex int `form:"pageIndex"`
|
|
PageSize int `form:"pageSize"`
|
|
Name string `form:"name"`
|
|
Enabled *bool `form:"enabled"`
|
|
}
|
|
|
|
type Service struct{ DB *gorm.DB }
|
|
|
|
func NewService(db *gorm.DB) Service { return Service{DB: db} }
|
|
|
|
func (s Service) List(ctx context.Context, query PageQuery) ([]Rule, int64, error) {
|
|
page, size := pageValues(query.PageIndex, query.PageSize)
|
|
db := s.DB.WithContext(ctx).Model(&Rule{})
|
|
if name := strings.TrimSpace(query.Name); name != "" {
|
|
db = db.Where("name ILIKE ? OR code ILIKE ?", "%"+name+"%", "%"+name+"%")
|
|
}
|
|
if query.Enabled != nil {
|
|
db = db.Where("enabled = ?", *query.Enabled)
|
|
}
|
|
var count int64
|
|
if err := db.Count(&count).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
items := make([]Rule, 0)
|
|
err := db.Order("created_at DESC, id DESC").Offset((page - 1) * size).Limit(size).Find(&items).Error
|
|
return items, count, err
|
|
}
|
|
|
|
func (s Service) Create(ctx context.Context, input WriteInput, actorID int) (Rule, error) {
|
|
normalized, err := Normalize(input, true)
|
|
if err != nil {
|
|
return Rule{}, err
|
|
}
|
|
now := time.Now().UTC()
|
|
item := Rule{
|
|
ID: uuid.NewString(), Code: normalized.Code, Name: normalized.Name, Enabled: true,
|
|
EventType: normalized.EventType, MinimumSeverity: normalized.MinimumSeverity,
|
|
LocationContains: normalized.LocationContains, Version: 1,
|
|
CreatedBy: actorID, UpdatedBy: actorID, CreatedAt: now, UpdatedAt: now,
|
|
}
|
|
if err = s.DB.WithContext(ctx).Create(&item).Error; err != nil {
|
|
return Rule{}, err
|
|
}
|
|
return item, nil
|
|
}
|
|
|
|
func (s Service) Update(ctx context.Context, id string, input WriteInput, actorID int) (Rule, error) {
|
|
if _, err := uuid.Parse(id); err != nil {
|
|
return Rule{}, ErrNotFound
|
|
}
|
|
normalized, err := Normalize(input, false)
|
|
if err != nil {
|
|
return Rule{}, err
|
|
}
|
|
var item Rule
|
|
err = s.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&item, "id = ?", id).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return ErrNotFound
|
|
}
|
|
return err
|
|
}
|
|
updates := map[string]any{
|
|
"name": normalized.Name, "event_type": normalized.EventType,
|
|
"minimum_severity": normalized.MinimumSeverity, "location_contains": normalized.LocationContains,
|
|
"version": item.Version + 1, "updated_by": actorID, "updated_at": time.Now().UTC(),
|
|
}
|
|
if err := tx.Model(&item).Updates(updates).Error; err != nil {
|
|
return err
|
|
}
|
|
return tx.First(&item, "id = ?", id).Error
|
|
})
|
|
return item, err
|
|
}
|
|
|
|
func (s Service) SetEnabled(ctx context.Context, id string, enabled bool, actorID int) (Rule, error) {
|
|
if _, err := uuid.Parse(id); err != nil {
|
|
return Rule{}, ErrNotFound
|
|
}
|
|
var item Rule
|
|
err := s.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&item, "id = ?", id).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return ErrNotFound
|
|
}
|
|
return err
|
|
}
|
|
if item.Enabled == enabled {
|
|
return nil
|
|
}
|
|
if err := tx.Model(&item).Updates(map[string]any{
|
|
"enabled": enabled, "version": item.Version + 1,
|
|
"updated_by": actorID, "updated_at": time.Now().UTC(),
|
|
}).Error; err != nil {
|
|
return err
|
|
}
|
|
return tx.First(&item, "id = ?", id).Error
|
|
})
|
|
return item, err
|
|
}
|
|
|
|
func pageValues(page, size int) (int, int) {
|
|
if page < 1 {
|
|
page = 1
|
|
}
|
|
if size < 1 || size > 100 {
|
|
size = 20
|
|
}
|
|
return page, size
|
|
}
|