Fix compose integration tests
This commit is contained in:
@@ -89,8 +89,6 @@ func (ctrl *Record) List(ctx context.Context, r *request.RecordList) (interface{
|
||||
return nil, err
|
||||
}
|
||||
|
||||
panic("refactor page filter")
|
||||
|
||||
if m, err = ctrl.module.With(ctx).FindByID(r.NamespaceID, r.ModuleID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ func (svc chart) Find(filter types.ChartFilter) (set types.ChartSet, f types.Cha
|
||||
}
|
||||
|
||||
err = func() error {
|
||||
if ns, err := loadNamespace(svc.ctx, svc.store, f.NamespaceID); err != nil {
|
||||
if ns, err := loadNamespace(svc.ctx, svc.store, filter.NamespaceID); err != nil {
|
||||
return err
|
||||
} else {
|
||||
aProps.setNamespace(ns)
|
||||
@@ -256,7 +256,7 @@ func (svc chart) handleUpdate(upd *types.Chart) chartUpdateHandler {
|
||||
|
||||
func (svc chart) handleDelete(ctx context.Context, ns *types.Namespace, c *types.Chart) (bool, error) {
|
||||
if !svc.ac.CanDeleteChart(ctx, c) {
|
||||
return false, ChartErrNotAllowedToUndelete()
|
||||
return false, ChartErrNotAllowedToDelete()
|
||||
}
|
||||
|
||||
if c.DeletedAt != nil {
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
func TestCharts(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
s, err = sqlite.NewInMemory(ctx)
|
||||
s, err = sqlite.ConnectInMemory(ctx)
|
||||
|
||||
namespaceID = id.Next()
|
||||
ns *types.Namespace
|
||||
|
||||
+69
-45
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/actionlog"
|
||||
"github.com/cortezaproject/corteza-server/pkg/eventbus"
|
||||
"github.com/cortezaproject/corteza-server/pkg/filter"
|
||||
"github.com/cortezaproject/corteza-server/pkg/handle"
|
||||
"github.com/cortezaproject/corteza-server/pkg/id"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
@@ -82,7 +83,7 @@ func (svc module) Find(filter types.ModuleFilter) (set types.ModuleSet, f types.
|
||||
}
|
||||
|
||||
err = func() error {
|
||||
if ns, err := loadNamespace(svc.ctx, svc.store, f.NamespaceID); err != nil {
|
||||
if ns, err := loadNamespace(svc.ctx, svc.store, filter.NamespaceID); err != nil {
|
||||
return err
|
||||
} else {
|
||||
aProps.setNamespace(ns)
|
||||
@@ -156,13 +157,13 @@ func (svc module) FindByAny(namespaceID uint64, identifier interface{}) (m *type
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (svc module) Create(new *types.Module) (m *types.Module, err error) {
|
||||
func (svc module) Create(new *types.Module) (*types.Module, error) {
|
||||
var (
|
||||
ns *types.Namespace
|
||||
aProps = &moduleActionProps{changed: new}
|
||||
)
|
||||
|
||||
err = store.Tx(svc.ctx, svc.store, func(ctx context.Context, s store.Storable) error {
|
||||
err := store.Tx(svc.ctx, svc.store, func(ctx context.Context, s store.Storable) (err error) {
|
||||
if !handle.IsValid(new.Handle) {
|
||||
return ModuleErrInvalidHandle()
|
||||
}
|
||||
@@ -191,25 +192,27 @@ func (svc module) Create(new *types.Module) (m *types.Module, err error) {
|
||||
new.UpdatedAt = nil
|
||||
new.DeletedAt = nil
|
||||
|
||||
m.Fields.Walk(func(f *types.ModuleField) error {
|
||||
f.ModuleID = new.ID
|
||||
f.CreatedAt = *nowPtr()
|
||||
f.UpdatedAt = nil
|
||||
f.DeletedAt = nil
|
||||
return nil
|
||||
})
|
||||
if new.Fields != nil {
|
||||
_ = new.Fields.Walk(func(f *types.ModuleField) error {
|
||||
f.ModuleID = new.ID
|
||||
f.CreatedAt = *nowPtr()
|
||||
f.UpdatedAt = nil
|
||||
f.DeletedAt = nil
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
aProps.setModule(m)
|
||||
aProps.setModule(new)
|
||||
|
||||
if err = store.CreateComposeModule(ctx, s, new); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = store.CreateComposeModuleField(ctx, s, m.Fields...); err != nil {
|
||||
if err = store.CreateComposeModuleField(ctx, s, new.Fields...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_ = svc.eventbus.WaitFor(ctx, event.ModuleAfterCreate(m, nil, ns))
|
||||
_ = svc.eventbus.WaitFor(ctx, event.ModuleAfterCreate(new, nil, ns))
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -272,10 +275,15 @@ func (svc module) updater(namespaceID, moduleID uint64, action func(...*moduleAc
|
||||
if fieldsChanged {
|
||||
var (
|
||||
hasRecords bool
|
||||
// @todo
|
||||
//store.SearchComposeRecords()
|
||||
set types.RecordSet
|
||||
)
|
||||
|
||||
if set, _, err = store.SearchComposeRecords(ctx, s, m, types.RecordFilter{Paging: filter.Paging{Limit: 1}}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hasRecords = len(set) > 0
|
||||
|
||||
if err = updateModuleFields(ctx, s, m, m.Fields, hasRecords); err != nil {
|
||||
|
||||
}
|
||||
@@ -340,7 +348,7 @@ func (svc module) uniqueCheck(m *types.Module) (err error) {
|
||||
}
|
||||
|
||||
func (svc module) handleUpdate(upd *types.Module) moduleUpdateHandler {
|
||||
return func(ctx context.Context, ns *types.Namespace, m *types.Module) (bool, bool, error) {
|
||||
return func(ctx context.Context, ns *types.Namespace, m *types.Module) (mch bool, fch bool, err error) {
|
||||
if isStale(upd.UpdatedAt, m.UpdatedAt, m.CreatedAt) {
|
||||
return false, false, ModuleErrStaleData()
|
||||
}
|
||||
@@ -349,7 +357,7 @@ func (svc module) handleUpdate(upd *types.Module) moduleUpdateHandler {
|
||||
return false, false, ModuleErrInvalidHandle()
|
||||
}
|
||||
|
||||
if err := svc.uniqueCheck(upd); err != nil {
|
||||
if err = svc.uniqueCheck(upd); err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
|
||||
@@ -357,31 +365,39 @@ func (svc module) handleUpdate(upd *types.Module) moduleUpdateHandler {
|
||||
return false, false, ModuleErrNotAllowedToUpdate()
|
||||
}
|
||||
|
||||
m.Name = upd.Name
|
||||
m.Handle = upd.Handle
|
||||
m.Meta = upd.Meta
|
||||
m.Fields = upd.Fields
|
||||
m.UpdatedAt = nowPtr()
|
||||
if m.Name != upd.Name {
|
||||
mch = true
|
||||
m.Name = upd.Name
|
||||
}
|
||||
|
||||
// @todo
|
||||
// select 1 record to see how fields can be updated
|
||||
//var rf = types.RecordFilter{}
|
||||
//rf.Limit = 1
|
||||
//if _, rf, err = svc.recordRepo.Find(m, rf); err != nil {
|
||||
// return err
|
||||
//}
|
||||
//
|
||||
//if err = svc.moduleRepo.UpdateFields(m.ID, m.Fields, rf.Count > 0); err != nil {
|
||||
// return err
|
||||
//}
|
||||
if m.Handle != upd.Handle {
|
||||
mch = true
|
||||
m.Handle = upd.Handle
|
||||
}
|
||||
|
||||
return true, false, nil
|
||||
if m.Meta.String() != upd.Meta.String() {
|
||||
mch = true
|
||||
m.Meta = upd.Meta
|
||||
}
|
||||
|
||||
// @todo make field-change detection more optimal
|
||||
if len(upd.Fields) > 0 {
|
||||
fch = true
|
||||
m.Fields = upd.Fields
|
||||
}
|
||||
|
||||
if mch {
|
||||
m.UpdatedAt = nowPtr()
|
||||
}
|
||||
|
||||
// for now, we assume that
|
||||
return mch, fch, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (svc module) handleDelete(ctx context.Context, ns *types.Namespace, m *types.Module) (bool, bool, error) {
|
||||
if !svc.ac.CanDeleteModule(ctx, m) {
|
||||
return false, false, ModuleErrNotAllowedToUndelete()
|
||||
return false, false, ModuleErrNotAllowedToDelete()
|
||||
}
|
||||
|
||||
if m.DeletedAt != nil {
|
||||
@@ -410,8 +426,8 @@ func (svc module) handleUndelete(ctx context.Context, ns *types.Namespace, m *ty
|
||||
// updates module fields
|
||||
// expecting to receive all module fields, as it deletes the rest
|
||||
// also, sort order of the fields is also important as this fn stores and updates field's place as send
|
||||
func updateModuleFields(ctx context.Context, s store.Storable, m *types.Module, ff types.ModuleFieldSet, hasRecords bool) error {
|
||||
for _, f := range ff {
|
||||
func updateModuleFields(ctx context.Context, s store.Storable, m *types.Module, newFields types.ModuleFieldSet, hasRecords bool) (err error) {
|
||||
for _, f := range newFields {
|
||||
// Set module ID to all new fields
|
||||
if f.ModuleID == 0 {
|
||||
f.ModuleID = m.ID
|
||||
@@ -423,29 +439,28 @@ func updateModuleFields(ctx context.Context, s store.Storable, m *types.Module,
|
||||
}
|
||||
}
|
||||
|
||||
eff, _, err := store.SearchComposeModuleFields(ctx, s, types.ModuleFieldFilter{ModuleID: []uint64{m.ID}})
|
||||
if err != nil {
|
||||
return err
|
||||
if err = loadModuleFields(ctx, s, m); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, ef := range eff {
|
||||
f := ff.FindByID(ef.ID)
|
||||
for _, ef := range m.Fields {
|
||||
f := newFields.FindByID(ef.ID)
|
||||
if f != nil || f.DeletedAt == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
ef.DeletedAt = nowPtr()
|
||||
err = store.PartialComposeModuleFieldUpdate(ctx, s, []string{"deleted_at"}, ef)
|
||||
err = store.UpdateComposeModuleField(ctx, s, ef)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for idx, f := range ff {
|
||||
for idx, f := range newFields {
|
||||
f.Place = idx
|
||||
f.DeletedAt = nil
|
||||
|
||||
if e := eff.FindByID(f.ID); e != nil {
|
||||
if e := m.Fields.FindByID(f.ID); e != nil {
|
||||
f.CreatedAt = e.CreatedAt
|
||||
|
||||
// We do not have any other code in place that would handle changes of field name and kind, so we need
|
||||
@@ -474,6 +489,10 @@ func updateModuleFields(ctx context.Context, s store.Storable, m *types.Module,
|
||||
}
|
||||
|
||||
func loadModuleFields(ctx context.Context, s store.Storable, mm ...*types.Module) (err error) {
|
||||
if len(mm) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
ff types.ModuleFieldSet
|
||||
mff = types.ModuleFieldFilter{ModuleID: types.ModuleSet(mm).IDs()}
|
||||
@@ -491,6 +510,7 @@ func loadModuleFields(ctx context.Context, s store.Storable, mm ...*types.Module
|
||||
return
|
||||
}
|
||||
|
||||
// loads record module with fields and namespace
|
||||
func loadModuleWithNamespace(ctx context.Context, s store.Storable, namespaceID, moduleID uint64) (ns *types.Namespace, m *types.Module, err error) {
|
||||
if moduleID == 0 {
|
||||
return nil, nil, ModuleErrInvalidID()
|
||||
@@ -521,6 +541,10 @@ func loadModule(ctx context.Context, s store.Storable, moduleID uint64) (m *type
|
||||
err = ModuleErrNotFound()
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
err = loadModuleFields(ctx, s, m)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -301,7 +301,7 @@ func (svc namespace) handleUpdate(upd *types.Namespace) namespaceUpdateHandler {
|
||||
|
||||
func (svc namespace) handleDelete(ctx context.Context, ns *types.Namespace) (bool, error) {
|
||||
if !svc.ac.CanDeleteNamespace(ctx, ns) {
|
||||
return false, NamespaceErrNotAllowedToUndelete()
|
||||
return false, NamespaceErrNotAllowedToDelete()
|
||||
}
|
||||
|
||||
if ns.DeletedAt != nil {
|
||||
|
||||
@@ -52,6 +52,7 @@ func Page() PageService {
|
||||
return (&page{
|
||||
ac: DefaultAccessControl,
|
||||
eventbus: eventbus.Service(),
|
||||
store: DefaultNgStore,
|
||||
}).With(context.Background())
|
||||
}
|
||||
|
||||
@@ -61,7 +62,7 @@ func (svc page) With(ctx context.Context) PageService {
|
||||
actionlog: DefaultActionlog,
|
||||
ac: svc.ac,
|
||||
eventbus: svc.eventbus,
|
||||
store: DefaultNgStore,
|
||||
store: svc.store,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +119,7 @@ func (svc page) search(filter types.PageFilter) (set types.PageSet, f types.Page
|
||||
filter.Check = checkPage(svc.ctx, svc.ac)
|
||||
|
||||
err = func() error {
|
||||
if ns, err := loadNamespace(svc.ctx, svc.store, f.NamespaceID); err != nil {
|
||||
if ns, err := loadNamespace(svc.ctx, svc.store, filter.NamespaceID); err != nil {
|
||||
return err
|
||||
} else {
|
||||
aProps.setNamespace(ns)
|
||||
@@ -416,7 +417,7 @@ func (svc page) handleUpdate(upd *types.Page) pageUpdateHandler {
|
||||
|
||||
func (svc page) handleDelete(ctx context.Context, ns *types.Namespace, m *types.Page) (bool, error) {
|
||||
if !svc.ac.CanDeletePage(ctx, m) {
|
||||
return false, PageErrNotAllowedToUndelete()
|
||||
return false, PageErrNotAllowedToDelete()
|
||||
}
|
||||
|
||||
if m.DeletedAt != nil {
|
||||
|
||||
+23
-101
@@ -57,6 +57,11 @@ type (
|
||||
UserRefChecker(fn values.ReferenceChecker)
|
||||
}
|
||||
|
||||
recordValueAccessController interface {
|
||||
CanReadRecordValue(context.Context, *types.ModuleField) bool
|
||||
CanUpdateRecordValue(context.Context, *types.ModuleField) bool
|
||||
}
|
||||
|
||||
recordAccessController interface {
|
||||
CanCreateRecord(context.Context, *types.Module) bool
|
||||
CanReadNamespace(context.Context, *types.Namespace) bool
|
||||
@@ -64,8 +69,8 @@ type (
|
||||
CanReadRecord(context.Context, *types.Module) bool
|
||||
CanUpdateRecord(context.Context, *types.Module) bool
|
||||
CanDeleteRecord(context.Context, *types.Module) bool
|
||||
CanReadRecordValue(context.Context, *types.ModuleField) bool
|
||||
CanUpdateRecordValue(context.Context, *types.ModuleField) bool
|
||||
|
||||
recordValueAccessController
|
||||
}
|
||||
|
||||
RecordService interface {
|
||||
@@ -131,6 +136,7 @@ func Record() RecordService {
|
||||
ac: DefaultAccessControl,
|
||||
eventbus: eventbus.Service(),
|
||||
optEmitEvents: true,
|
||||
store: DefaultNgStore,
|
||||
}).With(context.Background())
|
||||
}
|
||||
|
||||
@@ -219,9 +225,7 @@ func (svc record) lookup(namespaceID, moduleID uint64, lookup func(*types.Module
|
||||
return RecordErrNotAllowedToRead()
|
||||
}
|
||||
|
||||
if err = svc.preloadValues(m, r); err != nil {
|
||||
return err
|
||||
}
|
||||
trimUnreadableRecordFields(svc.ctx, svc.ac, m, r)
|
||||
|
||||
return nil
|
||||
}()
|
||||
@@ -236,58 +240,6 @@ func (svc record) FindByID(namespaceID, moduleID, recordID uint64) (r *types.Rec
|
||||
})
|
||||
}
|
||||
|
||||
//func (svc record) loadModuleWithNamespace(namespaceID, moduleID uint64) (m *types.Module, err error) {
|
||||
// return m, func() error {
|
||||
// if namespaceID == 0 {
|
||||
// return RecordErrInvalidNamespaceID()
|
||||
// }
|
||||
//
|
||||
// if moduleID == 0 {
|
||||
// return RecordErrInvalidModuleID()
|
||||
// }
|
||||
//
|
||||
// if m, err = svc.moduleRepo.FindByID(namespaceID, moduleID); err != nil {
|
||||
// if repository.ErrModuleNotFound.Eq(err) {
|
||||
// return RecordErrModuleNotFoundModule()
|
||||
// }
|
||||
//
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// if !svc.ac.CanReadModule(svc.ctx, m) {
|
||||
// return RecordErrNotAllowedToReadModule()
|
||||
// }
|
||||
//
|
||||
// if m.Fields, err = svc.moduleRepo.FindFields(m.ID); err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// return nil
|
||||
// }()
|
||||
//}
|
||||
//
|
||||
//func (svc record) loadNamespace(namespaceID uint64) (ns *types.Namespace, err error) {
|
||||
// return ns, func() error {
|
||||
// if namespaceID == 0 {
|
||||
// return RecordErrInvalidNamespaceID()
|
||||
// }
|
||||
//
|
||||
// if ns, err = svc.nsRepo.FindByID(namespaceID); err != nil {
|
||||
// if repository.ErrNamespaceNotFound.Eq(err) {
|
||||
// return RecordErrNamespaceNotFound()
|
||||
// }
|
||||
//
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// if !svc.ac.CanReadNamespace(svc.ctx, ns) {
|
||||
// return RecordErrNotAllowedToReadNamespace()
|
||||
// }
|
||||
//
|
||||
// return err
|
||||
// }()
|
||||
//}
|
||||
|
||||
// Report generates report for a given module using metrics, dimensions and filter
|
||||
func (svc record) Report(namespaceID, moduleID uint64, metrics, dimensions, filter string) (out interface{}, err error) {
|
||||
var (
|
||||
@@ -327,9 +279,7 @@ func (svc record) Find(filter types.RecordFilter) (set types.RecordSet, f types.
|
||||
return err
|
||||
}
|
||||
|
||||
if err = svc.preloadValues(m, set...); err != nil {
|
||||
return err
|
||||
}
|
||||
trimUnreadableRecordFields(svc.ctx, svc.ac, m, set...)
|
||||
|
||||
return nil
|
||||
}()
|
||||
@@ -409,10 +359,6 @@ func (svc record) Export(f types.RecordFilter, enc Encoder) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = svc.preloadValues(m, set...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return set.Walk(enc.Record)
|
||||
}()
|
||||
|
||||
@@ -644,11 +590,6 @@ func (svc record) update(upd *types.Record) (rec *types.Record, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Preload old record values so we can send it together with event
|
||||
if err = svc.preloadValues(m, old); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
rve *types.RecordValueErrorSet
|
||||
)
|
||||
@@ -858,11 +799,6 @@ func (svc record) delete(namespaceID, moduleID, recordID uint64) (del *types.Rec
|
||||
}
|
||||
|
||||
if svc.optEmitEvents {
|
||||
// Preload old record values so we can send it together with event
|
||||
if err = svc.preloadValues(m, del); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Calling before-record-delete scripts
|
||||
if err = svc.eventbus.WaitFor(svc.ctx, event.RecordBeforeDelete(nil, del, m, ns, nil)); err != nil {
|
||||
return nil, err
|
||||
@@ -1211,10 +1147,6 @@ func (svc record) Iterator(f types.RecordFilter, fn eventbus.HandlerFn, action s
|
||||
return err
|
||||
}
|
||||
|
||||
if err = svc.preloadValues(m, set...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, rec := range set {
|
||||
recordableAction := RecordActionIteratorIteration
|
||||
|
||||
@@ -1363,31 +1295,21 @@ func (svc record) generalValueSetValidation(m *types.Module, vv types.RecordValu
|
||||
return
|
||||
}
|
||||
|
||||
func (svc record) preloadValues(m *types.Module, rr ...*types.Record) error {
|
||||
panic("refactor")
|
||||
//if rvs, err := svc.recordRepo.LoadValues(svc.readableFields(m), types.RecordSet(rr).IDs()); err != nil {
|
||||
// return err
|
||||
//} else {
|
||||
// return types.RecordSet(rr).Walk(func(r *types.Record) error {
|
||||
// r.Values = svc.formatter.Run(m, rvs.FilterByRecordID(r.ID))
|
||||
// return nil
|
||||
// })
|
||||
//}
|
||||
}
|
||||
// checks record-value-read access permissions for all module fields and removes unreadable fields from all records
|
||||
func trimUnreadableRecordFields(ctx context.Context, ac recordValueAccessController, m *types.Module, rr ...*types.Record) {
|
||||
var (
|
||||
readableFields = map[string]bool{}
|
||||
)
|
||||
|
||||
// readableFields creates a slice of module fields that current user has permission to read
|
||||
func (svc record) readableFields(m *types.Module) []string {
|
||||
ff := make([]string, 0)
|
||||
for _, f := range m.Fields {
|
||||
readableFields[f.Name] = ac.CanReadRecordValue(ctx, f)
|
||||
}
|
||||
|
||||
_ = m.Fields.Walk(func(f *types.ModuleField) error {
|
||||
if svc.ac.CanReadRecordValue(svc.ctx, f) {
|
||||
ff = append(ff, f.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return ff
|
||||
for _, r := range rr {
|
||||
r.Values, _ = r.Values.Filter(func(v *types.RecordValue) (bool, error) {
|
||||
return readableFields[v.Name], nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// loadRecordCombo Loads namespace, module and record
|
||||
|
||||
Reference in New Issue
Block a user