diff --git a/compose/service/record.go b/compose/service/record.go index d6345eb7b..9a46910ea 100644 --- a/compose/service/record.go +++ b/compose/service/record.go @@ -218,7 +218,12 @@ func defaultValidator(svc RecordService) recordValuesValidator { return false, nil } - r, _, err := svc.FindByID(ctx, f.NamespaceID, f.ModuleID, v.Ref) + var ( + referencedModuleID = f.Options.Uint64("moduleID") + + r, _, err = svc.FindByID(ctx, f.NamespaceID, referencedModuleID, v.Ref) + ) + return r != nil, err }) diff --git a/compose/service/record_test.go b/compose/service/record_test.go index 811653acd..a94ebb9b6 100644 --- a/compose/service/record_test.go +++ b/compose/service/record_test.go @@ -543,7 +543,16 @@ func TestRecord_refAccessControl(t *testing.T) { mod1 = &types.Module{ID: nextID(), NamespaceID: ns.ID, Name: "mod one", Config: modConf} mod2 = &types.Module{ID: nextID(), NamespaceID: ns.ID, Name: "mod two", Config: modConf} mod1strField = &types.ModuleField{ID: nextID(), NamespaceID: ns.ID, ModuleID: mod1.ID, Name: "str", Kind: "String"} - mod2refField = &types.ModuleField{ID: nextID(), NamespaceID: ns.ID, ModuleID: mod2.ID, Name: "ref", Kind: "Record"} + mod2refField = &types.ModuleField{ + ID: nextID(), + NamespaceID: ns.ID, + ModuleID: mod2.ID, + Name: "ref", + Kind: "Record", + Options: types.ModuleFieldOptions{ + "moduleID": mod1.ID, + }, + } testerRole = &sysTypes.Role{Name: "tester", ID: nextID()} diff --git a/compose/types/module_field_options.go b/compose/types/module_field_options.go index e47178aeb..526ec9151 100644 --- a/compose/types/module_field_options.go +++ b/compose/types/module_field_options.go @@ -105,6 +105,7 @@ func (opt ModuleFieldOptions) Int64Def(key string, def int64) int64 { // Uint64 returns option value for key casted to uint64 func (opt ModuleFieldOptions) Uint64(key string) uint64 { + if val, has := opt[key]; has { return cast.ToUint64(val) } diff --git a/tests/compose/record_batch_test.go b/tests/compose/record_batch_test.go index b9ea008f6..5e495b0e7 100644 --- a/tests/compose/record_batch_test.go +++ b/tests/compose/record_batch_test.go @@ -16,14 +16,26 @@ func TestBatchRecordCreate(t *testing.T) { h.clearRecords() ns := h.makeNamespace("batch testing namespace") - module := h.makeRecordModuleWithFieldsOnNs("record testing module", ns) - childModule := h.makeRecordModuleWithFieldsOnNs("record testing module child", ns) + parentModule := h.makeRecordModuleWithFieldsOnNs("record testing module", ns) + childModule := h.makeRecordModuleWithFieldsOnNs("record testing module child", ns, + &types.ModuleField{ + Name: "name", + }, + &types.ModuleField{ + Name: "parent_ref", + Kind: "Record", + Options: types.ModuleFieldOptions{ + "moduleID": strconv.FormatUint(parentModule.ID, 10), + }, + }, + ) + helpers.AllowMe(h, types.ModuleRbacResource(0, 0), "record.create") helpers.AllowMe(h, types.ModuleFieldRbacResource(0, 0, 0), "record.value.update") h.apiInit(). - Post(fmt.Sprintf("/namespace/%d/module/%d/record/", module.NamespaceID, module.ID)). - JSON(fmt.Sprintf(`{"values": [], "records": [{"refField": "another_record", "set": [{"moduleID": "%d", "values": []}]}]}`, childModule.ID)). + Post(fmt.Sprintf("/namespace/%d/module/%d/record/", parentModule.NamespaceID, parentModule.ID)). + JSON(fmt.Sprintf(`{"values": [], "records": [{"refField": "parent_ref", "set": [{"moduleID": "%d", "values": []}]}]}`, childModule.ID)). Expect(t). Status(http.StatusOK). Assert(helpers.AssertNoErrors). @@ -38,8 +50,8 @@ func TestBatchRecordUpdate(t *testing.T) { h.clearRecords() ns := h.makeNamespace("batch testing namespace") - module := h.makeRecordModuleWithFieldsOnNs("record testing module", ns) childModule := h.makeRecordModuleWithFieldsOnNs("record testing module child", ns) + module := h.makeRecordModuleWithFieldsOnNs("record testing module", ns) helpers.AllowMe(h, types.RecordRbacResource(0, 0, 0), "update") helpers.AllowMe(h, types.ModuleFieldRbacResource(0, 0, 0), "record.value.update") @@ -93,18 +105,29 @@ func TestBatchRecordMixed(t *testing.T) { h.clearRecords() ns := h.makeNamespace("batch testing namespace") - module := h.makeRecordModuleWithFieldsOnNs("record testing module", ns) - childModule := h.makeRecordModuleWithFieldsOnNs("record testing module child", ns) + parentModule := h.makeRecordModuleWithFieldsOnNs("record testing module", ns) + childModule := h.makeRecordModuleWithFieldsOnNs("record testing module child", ns, + &types.ModuleField{ + Name: "name", + }, + &types.ModuleField{ + Name: "parent_ref", + Kind: "Record", + Options: types.ModuleFieldOptions{ + "moduleID": strconv.FormatUint(parentModule.ID, 10), + }, + }, ) helpers.AllowMe(h, types.ModuleRbacResource(0, 0), "record.create") helpers.AllowMe(h, types.RecordRbacResource(0, 0, 0), "update", "delete") - record := h.makeRecord(module) - childRecord := h.makeRecord(childModule, &types.RecordValue{Name: "another_record", Value: strconv.FormatUint(record.ID, 10), Ref: record.ID}) + record := h.makeRecord(parentModule) + childRecord := h.makeRecord(childModule, &types.RecordValue{Name: "parent_ref", Value: strconv.FormatUint(record.ID, 10)}) h.apiInit(). - Post(fmt.Sprintf("/namespace/%d/module/%d/record/%d", module.NamespaceID, module.ID, record.ID)). + Debug(). + Post(fmt.Sprintf("/namespace/%d/module/%d/record/%d", parentModule.NamespaceID, parentModule.ID, record.ID)). Header("Accept", "application/json"). - JSON(fmt.Sprintf(`{"values": [{"name": "name", "value": "Some Name"}], "records": [{"refField": "another_record", "set": [{"moduleID": "%d", "values": [{"name": "name", "value": "Added Name"}]},{"moduleID": "%d", "recordID": "%d", "values": [{"name": "name", "value": "Another Name"}]}]}]}`, childModule.ID, childModule.ID, childRecord.ID)). + JSON(fmt.Sprintf(`{"values": [{"name": "name", "value": "Some Name"}], "records": [{"refField": "parent_ref", "set": [{"moduleID": "%d", "values": [{"name": "name", "value": "Added Name"}]},{"moduleID": "%d", "recordID": "%d", "values": [{"name": "name", "value": "Another Name"}]}]}]}`, childModule.ID, childModule.ID, childRecord.ID)). Expect(t). Status(http.StatusOK). Assert(helpers.AssertNoErrors). diff --git a/tests/compose/record_test.go b/tests/compose/record_test.go index 5a506a8bc..d4ea6d62d 100644 --- a/tests/compose/record_test.go +++ b/tests/compose/record_test.go @@ -682,7 +682,7 @@ func TestRecordUpdate_refUnchanged(t *testing.T) { Name: "ref", Kind: "Record", Options: types.ModuleFieldOptions{ - "moduleID": mRef.ID, + "moduleID": strconv.FormatUint(mRef.ID, 10), }, }, ) @@ -725,7 +725,7 @@ func TestRecordUpdate_refChanged(t *testing.T) { namespace := h.makeNamespace("record testing namespace") // mods - mRef := h.makeRecordModuleWithFieldsOnNs("record testing module", namespace) + mRef := h.makeRecordModuleWithFieldsOnNs("record testing module (ref)", namespace) module := h.makeRecordModuleWithFieldsOnNs("record testing module", namespace, &types.ModuleField{ Name: "name", @@ -735,7 +735,7 @@ func TestRecordUpdate_refChanged(t *testing.T) { Name: "ref", Kind: "Record", Options: types.ModuleFieldOptions{ - "moduleID": mRef.ID, + "moduleID": strconv.FormatUint(mRef.ID, 10), }, }, ) @@ -758,6 +758,7 @@ func TestRecordUpdate_refChanged(t *testing.T) { helpers.AllowMe(h, types.RecordRbacResource(0, 0, 0), "update") h.apiInit(). + Debug(). Post(fmt.Sprintf("/namespace/%d/module/%d/record/%d", module.NamespaceID, module.ID, record.ID)). JSON(fmt.Sprintf(`{"values": [{"name": "name", "value": "changed-val"}, {"name": "ref", "value": "%d"}]}`, rRef2.ID)). Header("Accept", "application/json").