diff --git a/pkg/dal/errors.go b/pkg/dal/errors.go index a60f759da..5b5f4a830 100644 --- a/pkg/dal/errors.go +++ b/pkg/dal/errors.go @@ -14,6 +14,12 @@ func errConnectionNotFound(connectionID uint64) error { return fmt.Errorf("connection %d does not exist", connectionID) } +// Sensitivity level errors +// - remove +func errSensitivityLevelRemoveNotFound(sensitivityLevelID uint64) error { + return fmt.Errorf("cannot remove sensitivity level %d: sensitivity level does not exist", sensitivityLevelID) +} + // Connection errors // - create func errConnectionCreateMissingSensitivityLevel(connectionID, sensitivityLevelID uint64) error { diff --git a/pkg/dal/sensitivity_level.go b/pkg/dal/sensitivity_level.go index 2fb44a2a0..055ee42f0 100644 --- a/pkg/dal/sensitivity_level.go +++ b/pkg/dal/sensitivity_level.go @@ -1,5 +1,7 @@ package dal +import "sort" + type ( SensitivityLevel struct { Handle string @@ -32,6 +34,29 @@ func SensitivityLevelIndex(levels ...SensitivityLevel) *sensitivityLevelIndex { return out } +func (sli sensitivityLevelIndex) with(levels ...SensitivityLevel) *sensitivityLevelIndex { + slvls := append(sli.set, levels...) + sort.Sort(slvls) + + return SensitivityLevelIndex(slvls...) +} + +func (sli sensitivityLevelIndex) without(levels ...SensitivityLevel) *sensitivityLevelIndex { + nn := make(SensitivityLevelSet, 0, len(sli.set)) + + remIndex := SensitivityLevelIndex(levels...) + + for _, existing := range sli.set { + if !remIndex.includes(existing.ID) { + nn = append(nn, existing) + } + } + + sort.Sort(nn) + + return SensitivityLevelIndex(nn...) +} + func (sli sensitivityLevelIndex) includes(l uint64) (ok bool) { if l == 0 { return true @@ -69,10 +94,6 @@ func (sli sensitivityLevelIndex) isSubset(a, b uint64) (ok bool) { return lvlA <= lvlB } -func (ss SensitivityLevelSet) includes(l uint64) (ok bool) { - for _, s := range ss { - ok = ok || s.ID == l - } - - return -} +func (a SensitivityLevelSet) Len() int { return len(a) } +func (a SensitivityLevelSet) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a SensitivityLevelSet) Less(i, j int) bool { return a[i].Level < a[j].Level } diff --git a/pkg/dal/service.go b/pkg/dal/service.go index d370082d4..5c6bd423c 100644 --- a/pkg/dal/service.go +++ b/pkg/dal/service.go @@ -3,6 +3,8 @@ package dal import ( "context" "fmt" + "strconv" + "github.com/cortezaproject/corteza-server/pkg/dal/capabilities" "github.com/cortezaproject/corteza-server/pkg/expr" "github.com/cortezaproject/corteza-server/pkg/filter" @@ -13,14 +15,7 @@ type ( ConnectionWrap struct { connectionID uint64 - // @todo remove it and use value from connection meta - label string - - // @todo remove it and use value from connection meta - sensitivityLevel uint64 - - connection Connection - + connection Connection params ConnectionParams meta ConnectionMeta capabilities capabilities.Set @@ -60,7 +55,7 @@ type ( logger *zap.Logger inDev bool - sensitivityLevels sensitivityLevelIndex + sensitivityLevels *sensitivityLevelIndex connectionIssues dalIssueIndex modelIssues dalIssueIndex @@ -80,8 +75,9 @@ func SetGlobal(svc *service) { // It needs an established and working connection to the primary store func New(log *zap.Logger, inDev bool) (*service, error) { svc := &service{ - connections: make(map[uint64]*ConnectionWrap), - models: make(map[uint64]ModelSet), + connections: make(map[uint64]*ConnectionWrap), + models: make(map[uint64]ModelSet), + sensitivityLevels: SensitivityLevelIndex(), logger: log, inDev: inDev, @@ -115,66 +111,87 @@ func (svc *service) Drivers() (drivers []Driver) { return } -func (svc *service) ReloadSensitivityLevels(levels ...SensitivityLevel) (err error) { - svc.logger.Debug("reloading sensitivity levels", zap.Any("sensitivity levels", levels)) - newLevelIndex := svc.newSensitivityLevelIndex(levels) +func MakeSensitivityLevel(ID uint64, level int, handle string) SensitivityLevel { + return SensitivityLevel{ + ID: ID, + Level: level, + Handle: handle, + } +} + +func (svc *service) ReplaceSensitivityLevel(levels ...SensitivityLevel) (err error) { + var ( + log = svc.logger.Named("sensitivity level") + ) + + log.Debug("replacing levels", zap.Any("levels", levels)) + + if svc.sensitivityLevels == nil { + svc.sensitivityLevels = SensitivityLevelIndex() + } + nx := svc.sensitivityLevels + + for _, l := range levels { + log := log.With(zap.Uint64("ID", l.ID), zap.Int("level", l.Level), zap.String("handle", l.Handle)) + if nx.includes(l.ID) { + log.Debug("found existing") + } else { + log.Debug("adding new") + } + } + + nx = svc.sensitivityLevels.with(levels...) // Validate state after sensitivity level change - if err = svc.validateNewSensitivityLevels(newLevelIndex); err != nil { + log.Debug("validating new levels") + if err = svc.validateNewSensitivityLevels(nx); err != nil { return } - // Replace old ones - svc.sensitivityLevels = newLevelIndex + // Replace the old one + svc.sensitivityLevels = nx svc.logger.Debug("reloaded sensitivity levels") return } -func (svc *service) CreateSensitivityLevel(levels ...SensitivityLevel) (err error) { - svc.logger.Debug("creating sensitivity levels", zap.Any("sensitivity levels", levels)) - newIndex := svc.newAddedSensitivityLevelIndex(svc.sensitivityLevels, levels...) +func (svc *service) RemoveSensitivityLevel(levelIDs ...uint64) (err error) { + var ( + log = svc.logger.Named("sensitivity level") + ) + + log.Debug("removing levels", zap.Any("levels", levelIDs)) + + levels := make(SensitivityLevelSet, len(levelIDs)) + for i, lID := range levelIDs { + levels[i] = MakeSensitivityLevel(lID, i, strconv.FormatUint(lID, 10)) + } + + if svc.sensitivityLevels == nil { + svc.sensitivityLevels = SensitivityLevelIndex() + } + nx := svc.sensitivityLevels + + for _, l := range levels { + log := log.With(zap.Uint64("ID", l.ID)) + if !nx.includes(l.ID) { + log.Debug("sensitivity level not found") + return errSensitivityLevelRemoveNotFound(l.ID) + } + } + + nx = svc.sensitivityLevels.without(levels...) // Validate state after sensitivity level change - if err = svc.validateNewSensitivityLevels(newIndex); err != nil { + log.Debug("validating new levels") + if err = svc.validateNewSensitivityLevels(nx); err != nil { return } - // Replace old ones - svc.sensitivityLevels = newIndex - svc.logger.Debug("created sensitivity levels") - return -} - -func (svc *service) UpdateSensitivityLevel(levels ...SensitivityLevel) (err error) { - svc.logger.Debug("updating sensitivity levels", zap.Any("sensitivity levels", levels)) - newIndex := svc.newRemovedSensitivityLevelIndex(svc.sensitivityLevels, levels...) - newIndex = svc.newAddedSensitivityLevelIndex(newIndex, levels...) - - // Validate state after sensitivity level change - if err = svc.validateNewSensitivityLevels(newIndex); err != nil { - return - } - - // Replace old ones - svc.sensitivityLevels = newIndex - svc.logger.Debug("updated sensitivity levels") - return -} - -func (svc *service) DeleteSensitivityLevel(levels ...SensitivityLevel) (err error) { - svc.logger.Debug("deleting sensitivity levels", zap.Any("sensitivity levels", levels)) - newIndex := svc.newRemovedSensitivityLevelIndex(svc.sensitivityLevels, levels...) - - // Validate state after sensitivity level change - if err = svc.validateNewSensitivityLevels(newIndex); err != nil { - return - } - - // Replace old ones - svc.sensitivityLevels = newIndex - svc.logger.Debug("deleted sensitivity levels") + // Replace the old one + svc.sensitivityLevels = nx + svc.logger.Debug("removed sensitivity levels") return } @@ -189,12 +206,8 @@ func MakeConnection(ID uint64, conn Connection, p ConnectionParams, m Connection connectionID: ID, connection: conn, - params: p, - - meta: m, - sensitivityLevel: m.SensitivityLevel, - label: m.Label, - + params: p, + meta: m, capabilities: cap, } } @@ -228,7 +241,7 @@ func (svc *service) ReplaceConnection(ctx context.Context, cw *ConnectionWrap, i } else if svc.defConnID != ID { // default connection set but ID is different. // this does not make any sense - return fmt.Errorf("different ID for default connection detecte (old: %d, new: %d)", svc.defConnID, ID) + return fmt.Errorf("different ID for default connection detected (old: %d, new: %d)", svc.defConnID, ID) } } @@ -522,8 +535,8 @@ func (svc *service) CreateModel(ctx context.Context, models ...*Model) (err erro issues.addModelIssue(model.ConnectionID, model.ResourceID, errModelCreateMissingSensitivityLevel(model.ConnectionID, model.ResourceID, model.SensitivityLevel)) } else { // Only check if it is present - if !svc.sensitivityLevels.isSubset(model.SensitivityLevel, conn.sensitivityLevel) { - issues.addModelIssue(model.ConnectionID, model.ResourceID, errModelCreateGreaterSensitivityLevel(model.ConnectionID, model.ResourceID, model.SensitivityLevel, conn.sensitivityLevel)) + if !svc.sensitivityLevels.isSubset(model.SensitivityLevel, conn.meta.SensitivityLevel) { + issues.addModelIssue(model.ConnectionID, model.ResourceID, errModelCreateGreaterSensitivityLevel(model.ConnectionID, model.ResourceID, model.SensitivityLevel, conn.meta.SensitivityLevel)) } } // - attributes @@ -722,8 +735,8 @@ func (svc *service) UpdateModel(ctx context.Context, old *Model, new *Model) (er if !svc.sensitivityLevels.includes(new.SensitivityLevel) { issues.addModelIssue(new.ConnectionID, new.ResourceID, errModelUpdateMissingSensitivityLevel(new.ConnectionID, new.ResourceID, new.SensitivityLevel)) } else { - if !svc.sensitivityLevels.isSubset(new.SensitivityLevel, conn.sensitivityLevel) { - issues.addModelIssue(new.ConnectionID, new.ResourceID, errModelUpdateGreaterSensitivityLevel(new.ConnectionID, new.ResourceID, new.SensitivityLevel, conn.sensitivityLevel)) + if !svc.sensitivityLevels.isSubset(new.SensitivityLevel, conn.meta.SensitivityLevel) { + issues.addModelIssue(new.ConnectionID, new.ResourceID, errModelUpdateGreaterSensitivityLevel(new.ConnectionID, new.ResourceID, new.SensitivityLevel, conn.meta.SensitivityLevel)) } } @@ -988,66 +1001,7 @@ func (svc *service) getModelByFilter(mf ModelFilter) *Model { return svc.FindModelByResourceIdent(mf.ConnectionID, mf.ResourceType, mf.Resource) } -func (svc *service) newAddedSensitivityLevelIndex(sli sensitivityLevelIndex, add ...SensitivityLevel) (out sensitivityLevelIndex) { - newLevels := make(SensitivityLevelSet, 0, len(sli.set)+len(add)) - - var ( - i = 0 - j = 0 - ) - - for i < len(sli.set) { - for j < len(add) { - if sli.set[i].Level <= add[j].Level { - newLevels = append(newLevels, sli.set[i]) - i++ - } - if sli.set[i].Level > add[j].Level { - newLevels = append(newLevels, add[j]) - j++ - } - } - } - - if j < len(add)-1 { - newLevels = append(newLevels, add[j:]...) - } - - return svc.newSensitivityLevelIndex(newLevels) -} - -func (svc *service) newRemovedSensitivityLevelIndex(sli sensitivityLevelIndex, remove ...SensitivityLevel) (out sensitivityLevelIndex) { - newLevels := make(SensitivityLevelSet, 0, len(sli.set)+len(remove)) - - removeSet := SensitivityLevelSet(remove) - - for _, l := range sli.set { - if !removeSet.includes(l.ID) { - newLevels = append(newLevels, l) - } - } - - return svc.newSensitivityLevelIndex(newLevels) -} - -func (svc *service) newSensitivityLevelIndex(levels SensitivityLevelSet) (out sensitivityLevelIndex) { - out = sensitivityLevelIndex{ - byID: make(map[uint64]int), - byHandle: make(map[string]int), - set: make(SensitivityLevelSet, len(levels)), - } - - for i, l := range levels { - out.set[i] = l - - out.byID[l.ID] = i - out.byHandle[l.Handle] = i - } - - return -} - -func (svc *service) validateNewSensitivityLevels(levels sensitivityLevelIndex) (err error) { +func (svc *service) validateNewSensitivityLevels(levels *sensitivityLevelIndex) (err error) { err = func() (err error) { cIndex := make(map[uint64]*ConnectionWrap) @@ -1056,8 +1010,8 @@ func (svc *service) validateNewSensitivityLevels(levels sensitivityLevelIndex) ( c := _c cIndex[c.connectionID] = c - if !levels.includes(c.sensitivityLevel) { - return fmt.Errorf("connection sensitivity level missing %d", c.sensitivityLevel) + if !levels.includes(c.meta.SensitivityLevel) { + return fmt.Errorf("connection sensitivity level missing %d", c.meta.SensitivityLevel) } } @@ -1067,7 +1021,7 @@ func (svc *service) validateNewSensitivityLevels(levels sensitivityLevelIndex) ( if !levels.includes(m.SensitivityLevel) { return fmt.Errorf("model sensitivity level missing %d", m.SensitivityLevel) } - if !levels.isSubset(m.SensitivityLevel, cIndex[m.ConnectionID].sensitivityLevel) { + if !levels.isSubset(m.SensitivityLevel, cIndex[m.ConnectionID].meta.SensitivityLevel) { return fmt.Errorf("model sensitivity level missing %d", m.SensitivityLevel) } diff --git a/system/dalutils/sensitivity_level.go b/system/dalutils/sensitivity_level.go deleted file mode 100644 index 968867b24..000000000 --- a/system/dalutils/sensitivity_level.go +++ /dev/null @@ -1,83 +0,0 @@ -package dalutils - -import ( - "context" - "sort" - - "github.com/cortezaproject/corteza-server/pkg/dal" - "github.com/cortezaproject/corteza-server/pkg/filter" - "github.com/cortezaproject/corteza-server/store" - "github.com/cortezaproject/corteza-server/system/types" -) - -type ( - sensitivityLevelCreator interface { - CreateSensitivityLevel(levels ...dal.SensitivityLevel) (err error) - } - - sensitivityLevelUpdater interface { - UpdateSensitivityLevel(levels ...dal.SensitivityLevel) (err error) - } - - sensitivityLevelDeleter interface { - DeleteSensitivityLevel(levels ...dal.SensitivityLevel) (err error) - } - - sensitivityLevelReloader interface { - ReloadSensitivityLevels(levels ...dal.SensitivityLevel) (err error) - } -) - -func DalSensitivityLevelReload(ctx context.Context, s store.Storer, r sensitivityLevelReloader) (err error) { - ll, _, err := store.SearchDalSensitivityLevels(ctx, s, types.DalSensitivityLevelFilter{Deleted: filter.StateExcluded}) - if err != nil { - return - } - - // @todo temporary - ll = append(types.DalSensitivityLevelSet{{ - ID: 1, - Handle: "private", - Level: 1, - }}, ll...) - - sort.Sort(ll) - - levels := make(dal.SensitivityLevelSet, 0, len(ll)) - for _, l := range ll { - levels = append(levels, systemToPkgType(l)) - } - - return r.ReloadSensitivityLevels(levels...) -} - -func DalSensitivityLevelCreate(c sensitivityLevelCreator, levels ...*types.DalSensitivityLevel) (err error) { - return c.CreateSensitivityLevel(systemToPkgTypeSet(levels)...) -} - -func DalSensitivityLevelUpdate(u sensitivityLevelUpdater, levels ...*types.DalSensitivityLevel) (err error) { - return u.UpdateSensitivityLevel(systemToPkgTypeSet(levels)...) -} - -func DalSensitivityLevelDelete(d sensitivityLevelDeleter, levels ...*types.DalSensitivityLevel) (err error) { - return d.DeleteSensitivityLevel(systemToPkgTypeSet(levels)...) -} - -// // // // // // // // // // // // // // // // // // // // // // // // // -// Utils - -func systemToPkgType(level *types.DalSensitivityLevel) dal.SensitivityLevel { - return dal.SensitivityLevel{ - ID: level.ID, - Handle: level.Handle, - Level: level.Level, - } -} - -func systemToPkgTypeSet(levels types.DalSensitivityLevelSet) dal.SensitivityLevelSet { - out := make(dal.SensitivityLevelSet, 0, len(levels)) - for _, l := range levels { - out = append(out, systemToPkgType(l)) - } - return out -} diff --git a/system/service/dal_sensitivity_level.go b/system/service/dal_sensitivity_level.go index 98bc43b8e..fe8af7cb5 100644 --- a/system/service/dal_sensitivity_level.go +++ b/system/service/dal_sensitivity_level.go @@ -10,7 +10,6 @@ import ( "github.com/cortezaproject/corteza-server/pkg/dal" "github.com/cortezaproject/corteza-server/store" - "github.com/cortezaproject/corteza-server/system/dalutils" "github.com/cortezaproject/corteza-server/system/types" ) @@ -19,22 +18,20 @@ type ( actionlog actionlog.Recorder store store.Storer ac sensitivityLevelAccessController - dal dalSensitivityLevels + dal dalSensitivityLevelManager } sensitivityLevelAccessController interface { CanManageDalSensitivityLevel(context.Context) bool } - dalSensitivityLevels interface { - ReloadSensitivityLevels(levels ...dal.SensitivityLevel) (err error) - CreateSensitivityLevel(levels ...dal.SensitivityLevel) (err error) - UpdateSensitivityLevel(levels ...dal.SensitivityLevel) (err error) - DeleteSensitivityLevel(levels ...dal.SensitivityLevel) (err error) + dalSensitivityLevelManager interface { + ReplaceSensitivityLevel(levels ...dal.SensitivityLevel) (err error) + RemoveSensitivityLevel(levels ...uint64) (err error) } ) -func SensitivityLevel(ctx context.Context, dal dalSensitivityLevels) *dalSensitivityLevel { +func SensitivityLevel(ctx context.Context, dal dalSensitivityLevelManager) *dalSensitivityLevel { return &dalSensitivityLevel{ ac: DefaultAccessControl, actionlog: DefaultActionlog, @@ -95,7 +92,7 @@ func (svc *dalSensitivityLevel) Create(ctx context.Context, new *types.DalSensit q = new - return dalutils.DalSensitivityLevelCreate(svc.dal, new) + return dalSensitivityLevelReplace(ctx, svc.dal, new) }) return q, svc.recordAction(ctx, qProps, DalSensitivityLevelActionCreate, err) @@ -132,7 +129,7 @@ func (svc *dalSensitivityLevel) Update(ctx context.Context, upd *types.DalSensit q = upd - return dalutils.DalSensitivityLevelUpdate(svc.dal, upd) + return dalSensitivityLevelReplace(ctx, svc.dal, upd) }) return q, svc.recordAction(ctx, qProps, DalSensitivityLevelActionUpdate, err) @@ -184,10 +181,10 @@ func (svc *dalSensitivityLevel) DeleteByID(ctx context.Context, ID uint64) (err } } - if err = dalutils.DalSensitivityLevelUpdate(svc.dal, uu...); err != nil { + if err = dalSensitivityLevelReplace(ctx, svc.dal, uu...); err != nil { return err } - if err = dalutils.DalSensitivityLevelDelete(svc.dal, dd...); err != nil { + if err = dalSensitivityLevelRemove(ctx, svc.dal, dd...); err != nil { return err } return nil @@ -224,7 +221,7 @@ func (svc *dalSensitivityLevel) UndeleteByID(ctx context.Context, ID uint64) (er return } - return dalutils.DalSensitivityLevelCreate(svc.dal, q) + return dalSensitivityLevelReplace(ctx, svc.dal, q) }) return svc.recordAction(ctx, qProps, DalSensitivityLevelActionDelete, err) @@ -260,7 +257,7 @@ func (svc *dalSensitivityLevel) Search(ctx context.Context, filter types.DalSens } func (svc *dalSensitivityLevel) ReloadSensitivityLevels(ctx context.Context, s store.Storer) (err error) { - return dalutils.DalSensitivityLevelReload(ctx, s, svc.dal) + return dalSensitivityLevelReload(ctx, svc.store, svc.dal) } func (svc *dalSensitivityLevel) prepare(ctx context.Context, s store.Storer, sl *types.DalSensitivityLevel) (_ types.DalSensitivityLevelSet, err error) { @@ -334,3 +331,33 @@ func (svc *dalSensitivityLevel) prepare(ctx context.Context, s store.Storer, sl return set, err } + +func dalSensitivityLevelReload(ctx context.Context, s store.Storer, dsm dalSensitivityLevelManager) (err error) { + // Get all available sensitivityLevels + ll, _, err := store.SearchDalSensitivityLevels(ctx, s, types.DalSensitivityLevelFilter{}) + if err != nil { + return + } + + return dalSensitivityLevelReplace(ctx, dsm, ll...) +} + +func dalSensitivityLevelReplace(ctx context.Context, dsm dalSensitivityLevelManager, ll ...*types.DalSensitivityLevel) (err error) { + for _, l := range ll { + sl := dal.MakeSensitivityLevel(l.ID, l.Level, l.Handle) + if err = dsm.ReplaceSensitivityLevel(sl); err != nil { + return + } + } + + return nil +} + +func dalSensitivityLevelRemove(ctx context.Context, dsm dalSensitivityLevelManager, ll ...*types.DalSensitivityLevel) (err error) { + dd := make([]uint64, len(ll)) + for i, l := range ll { + dd[i] = l.ID + } + + return dsm.RemoveSensitivityLevel(dd...) +}