3
0
corteza/pkg/settings/service.go
2020-01-18 07:05:10 +01:00

178 lines
4.1 KiB
Go

package settings
import (
"context"
"strings"
"github.com/pkg/errors"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"github.com/cortezaproject/corteza-server/pkg/logger"
)
type (
service struct {
repository Repository
accessControl accessController
logger *zap.Logger
current interface{}
}
Service interface {
FindByPrefix(ctx context.Context, pp ...string) (vv ValueSet, err error)
BulkSet(ctx context.Context, vv ValueSet) (err error)
Set(ctx context.Context, v *Value) (err error)
Get(ctx context.Context, name string, ownedBy uint64) (out *Value, err error)
Delete(ctx context.Context, name string, ownedBy uint64) error
UpdateCurrent(ctx context.Context) error
}
accessController interface {
CanReadSettings(ctx context.Context) bool
CanManageSettings(ctx context.Context) bool
}
)
var (
ErrNoReadPermission = errors.New("not allowed to read settings")
ErrNoManagePermission = errors.New("not allowed to manage settings")
)
func NewService(r Repository, log *zap.Logger, ac accessController, current interface{}) *service {
svc := &service{
repository: r,
accessControl: ac,
logger: log.Named("settings"),
current: current,
}
return svc
}
func (svc service) log(ctx context.Context, fields ...zapcore.Field) *zap.Logger {
return logger.AddRequestID(ctx, svc.logger).With(fields...)
}
func (svc service) FindByPrefix(ctx context.Context, pp ...string) (ValueSet, error) {
if !svc.accessControl.CanReadSettings(ctx) {
return nil, ErrNoReadPermission
}
var (
f = Filter{
Prefix: strings.Join(pp, "."),
}
)
return svc.repository.With(ctx).Find(f)
}
func (svc service) Get(ctx context.Context, name string, ownedBy uint64) (out *Value, err error) {
if !svc.accessControl.CanReadSettings(ctx) {
return nil, ErrNoReadPermission
}
return svc.repository.With(ctx).Get(name, ownedBy)
}
func (svc service) UpdateCurrent(ctx context.Context) error {
if vv, err := svc.FindByPrefix(ctx); err != nil {
return err
} else {
return svc.updateCurrent(ctx, vv)
}
}
func (svc service) updateCurrent(ctx context.Context, vv ValueSet) (err error) {
// update current settings with new values
if err = vv.KV().Decode(svc.current); err != nil {
return
}
return
}
func (svc service) Set(ctx context.Context, v *Value) (err error) {
if !svc.accessControl.CanManageSettings(ctx) {
return ErrNoManagePermission
}
var current *Value
current, err = svc.repository.With(ctx).Get(v.Name, v.OwnedBy)
if err != nil || current.Eq(v) {
// Return on error or when there is nothing to update (same value)
return
}
err = svc.repository.With(ctx).Set(v)
if err != nil {
return
}
vv := ValueSet{v}
svc.logChange(ctx, vv)
return svc.updateCurrent(ctx, vv)
}
func (svc service) BulkSet(ctx context.Context, vv ValueSet) (err error) {
if !svc.accessControl.CanManageSettings(ctx) {
return ErrNoManagePermission
}
// Load current settings from repository
// and get changed values
var current ValueSet
if current, err = svc.FindByPrefix(ctx); err != nil {
return
} else {
vv = current.Changed(vv)
}
err = svc.repository.With(ctx).BulkSet(vv)
if err != nil {
return
}
svc.logChange(ctx, vv)
return svc.updateCurrent(ctx, vv)
}
func (svc service) logChange(ctx context.Context, vv ValueSet) {
for _, v := range vv {
svc.log(ctx,
zap.String("name", v.Name),
zap.Uint64("owned-by", v.OwnedBy),
zap.Stringer("value", v.Value)).Info("setting value updated")
}
}
func (svc service) Delete(ctx context.Context, name string, ownedBy uint64) (err error) {
if !svc.accessControl.CanManageSettings(ctx) {
return ErrNoManagePermission
}
var current *Value
current, err = svc.repository.With(ctx).Get(name, ownedBy)
if err != nil || current == nil {
// Return on error or when there is nothing to delete (there is no value)
return
}
err = svc.repository.With(ctx).Delete(name, ownedBy)
if err != nil {
return
}
vv := ValueSet{&Value{Name: name, OwnedBy: ownedBy}}
svc.log(ctx,
zap.String("name", name),
zap.Uint64("owned-by", ownedBy)).Info("setting value removed")
return svc.updateCurrent(ctx, vv)
}