diff --git a/Makefile b/Makefile index fe9987362..b4038cfa4 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,7 @@ OCIS_MODULES = \ services/ocdav \ services/ocs \ services/proxy \ + services/search \ services/settings \ services/sharing \ services/storage-system \ diff --git a/changelog/unreleased/report-parentid.md b/changelog/unreleased/report-parentid.md new file mode 100644 index 000000000..6b710fe55 --- /dev/null +++ b/changelog/unreleased/report-parentid.md @@ -0,0 +1,6 @@ +Enhancement: report parent id + +We now index and return the parent id of a resource in search REPORTs. + +https://github.com/owncloud/ocis/pull/4757 +https://github.com/owncloud/ocis/issues/4727 \ No newline at end of file diff --git a/protogen/gen/ocis/messages/search/v0/search.pb.go b/protogen/gen/ocis/messages/search/v0/search.pb.go index 215de6eef..b8f62574b 100644 --- a/protogen/gen/ocis/messages/search/v0/search.pb.go +++ b/protogen/gen/ocis/messages/search/v0/search.pb.go @@ -155,6 +155,7 @@ type Entity struct { Type uint64 `protobuf:"varint,9,opt,name=type,proto3" json:"type,omitempty"` Deleted bool `protobuf:"varint,10,opt,name=deleted,proto3" json:"deleted,omitempty"` ShareRootName string `protobuf:"bytes,11,opt,name=shareRootName,proto3" json:"shareRootName,omitempty"` + ParentId *ResourceID `protobuf:"bytes,12,opt,name=parent_id,json=parentId,proto3" json:"parent_id,omitempty"` } func (x *Entity) Reset() { @@ -266,6 +267,13 @@ func (x *Entity) GetShareRootName() string { return "" } +func (x *Entity) GetParentId() *ResourceID { + if x != nil { + return x.ParentId + } + return nil +} + type Match struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -344,7 +352,7 @@ var file_ocis_messages_search_v0_search_proto_rawDesc = []byte{ 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x44, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x8c, 0x03, 0x0a, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0xce, 0x03, 0x0a, 0x06, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x34, 0x0a, 0x03, 0x72, 0x65, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x52, @@ -369,17 +377,22 @@ var file_ocis_messages_search_v0_search_proto_rawDesc = []byte{ 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x68, 0x61, 0x72, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x68, - 0x61, 0x72, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x56, 0x0a, 0x05, 0x4d, - 0x61, 0x74, 0x63, 0x68, 0x12, 0x37, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x45, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, - 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x73, 0x63, - 0x6f, 0x72, 0x65, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x6f, 0x63, 0x69, 0x73, 0x2f, - 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x65, 0x6e, 0x2f, - 0x6f, 0x63, 0x69, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2f, 0x73, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x2f, 0x76, 0x30, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x72, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x40, 0x0a, 0x09, 0x70, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, + 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x73, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x49, 0x44, 0x52, 0x08, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x56, 0x0a, + 0x05, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x37, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, + 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, + 0x73, 0x63, 0x6f, 0x72, 0x65, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x6f, 0x63, 0x69, + 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x65, + 0x6e, 0x2f, 0x6f, 0x63, 0x69, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2f, + 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x76, 0x30, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -407,12 +420,13 @@ var file_ocis_messages_search_v0_search_proto_depIdxs = []int32{ 1, // 1: ocis.messages.search.v0.Entity.ref:type_name -> ocis.messages.search.v0.Reference 0, // 2: ocis.messages.search.v0.Entity.id:type_name -> ocis.messages.search.v0.ResourceID 4, // 3: ocis.messages.search.v0.Entity.last_modified_time:type_name -> google.protobuf.Timestamp - 2, // 4: ocis.messages.search.v0.Match.entity:type_name -> ocis.messages.search.v0.Entity - 5, // [5:5] is the sub-list for method output_type - 5, // [5:5] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 0, // 4: ocis.messages.search.v0.Entity.parent_id:type_name -> ocis.messages.search.v0.ResourceID + 2, // 5: ocis.messages.search.v0.Match.entity:type_name -> ocis.messages.search.v0.Entity + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_ocis_messages_search_v0_search_proto_init() } diff --git a/protogen/gen/ocis/messages/settings/v0/settings.pb.go b/protogen/gen/ocis/messages/settings/v0/settings.pb.go index 8e08272ef..b30e14dc3 100644 --- a/protogen/gen/ocis/messages/settings/v0/settings.pb.go +++ b/protogen/gen/ocis/messages/settings/v0/settings.pb.go @@ -589,6 +589,7 @@ type Setting struct { DisplayName string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` // Types that are assignable to Value: + // // *Setting_IntValue // *Setting_StringValue // *Setting_BoolValue @@ -1193,6 +1194,7 @@ type Value struct { AccountUuid string `protobuf:"bytes,4,opt,name=account_uuid,json=accountUuid,proto3" json:"account_uuid,omitempty"` Resource *Resource `protobuf:"bytes,5,opt,name=resource,proto3" json:"resource,omitempty"` // Types that are assignable to Value: + // // *Value_BoolValue // *Value_IntValue // *Value_StringValue @@ -1383,6 +1385,7 @@ type ListOptionValue struct { unknownFields protoimpl.UnknownFields // Types that are assignable to Option: + // // *ListOptionValue_StringValue // *ListOptionValue_IntValue Option isListOptionValue_Option `protobuf_oneof:"option"` diff --git a/protogen/gen/ocis/services/search/v0/search.swagger.json b/protogen/gen/ocis/services/search/v0/search.swagger.json index 0901be95f..2ba276bda 100644 --- a/protogen/gen/ocis/services/search/v0/search.swagger.json +++ b/protogen/gen/ocis/services/search/v0/search.swagger.json @@ -195,6 +195,9 @@ }, "shareRootName": { "type": "string" + }, + "parentId": { + "$ref": "#/definitions/v0ResourceID" } } }, diff --git a/protogen/gen/ocis/services/thumbnails/v0/thumbnails.pb.go b/protogen/gen/ocis/services/thumbnails/v0/thumbnails.pb.go index 9d0293e6f..29930a15b 100644 --- a/protogen/gen/ocis/services/thumbnails/v0/thumbnails.pb.go +++ b/protogen/gen/ocis/services/thumbnails/v0/thumbnails.pb.go @@ -37,6 +37,7 @@ type GetThumbnailRequest struct { // The height of the thumbnail Height int32 `protobuf:"varint,4,opt,name=height,proto3" json:"height,omitempty"` // Types that are assignable to Source: + // // *GetThumbnailRequest_WebdavSource // *GetThumbnailRequest_Cs3Source Source isGetThumbnailRequest_Source `protobuf_oneof:"source"` diff --git a/protogen/proto/ocis/messages/search/v0/search.proto b/protogen/proto/ocis/messages/search/v0/search.proto index 85e50c04b..8fc5d9e7a 100644 --- a/protogen/proto/ocis/messages/search/v0/search.proto +++ b/protogen/proto/ocis/messages/search/v0/search.proto @@ -29,6 +29,7 @@ message Entity { uint64 type = 9; bool deleted = 10; string shareRootName = 11; + ResourceID parent_id = 12; } message Match { diff --git a/services/search/Makefile b/services/search/Makefile index 032a972be..f8a3b5a8c 100644 --- a/services/search/Makefile +++ b/services/search/Makefile @@ -24,7 +24,9 @@ docs-generate: config-docs-generate include ../../.make/generate.mk .PHONY: ci-go-generate -ci-go-generate: # CI runs ci-node-generate automatically before this target +ci-go-generate: $(MOCKERY) # CI runs ci-node-generate automatically before this target + $(MOCKERY) --dir pkg/search --output pkg/search/mocks --case underscore --name IndexClient + $(MOCKERY) --dir pkg/search --output pkg/search/mocks --case underscore --name ProviderClient .PHONY: ci-node-generate ci-node-generate: diff --git a/services/search/pkg/search/index/index.go b/services/search/pkg/search/index/index.go index 271557e6f..f822841b0 100644 --- a/services/search/pkg/search/index/index.go +++ b/services/search/pkg/search/index/index.go @@ -44,9 +44,10 @@ import ( ) type indexDocument struct { - RootID string - Path string - ID string + RootID string + Path string + ID string + ParentID string Name string Size uint64 @@ -170,7 +171,7 @@ func (i *Index) Purge(id *sprovider.ResourceId) error { } // Move update the path of an entry and all its children -func (i *Index) Move(id *sprovider.ResourceId, fullPath string) error { +func (i *Index) Move(id, newParentID *sprovider.ResourceId, fullPath string) error { bleveId := idToBleveId(id) doc, err := i.getEntity(bleveId) if err != nil { @@ -182,6 +183,7 @@ func (i *Index) Move(id *sprovider.ResourceId, fullPath string) error { doc, err = i.updateEntity(bleveId, func(doc *indexDocument) { doc.Path = newName doc.Name = path.Base(newName) + doc.ParentID = idToBleveId(newParentID) }) if err != nil { return err @@ -284,6 +286,7 @@ func toEntity(ref *sprovider.Reference, ri *sprovider.ResourceInfo) *indexDocume RootID: idToBleveId(ref.ResourceId), Path: ref.Path, ID: idToBleveId(ri.Id), + ParentID: idToBleveId(ri.ParentId), Name: ri.Path, Size: ri.Size, MimeType: ri.MimeType, @@ -303,6 +306,7 @@ func fieldsToEntity(fields map[string]interface{}) *indexDocument { RootID: fields["RootID"].(string), Path: fields["Path"].(string), ID: fields["ID"].(string), + ParentID: fields["ParentID"].(string), Name: fields["Name"].(string), Size: uint64(fields["Size"].(float64)), Mtime: fields["Mtime"].(string), @@ -338,6 +342,13 @@ func fromDocumentMatch(hit *search.DocumentMatch) (*searchmsg.Match, error) { Deleted: hit.Fields["Deleted"].(bool), }, } + if hit.Fields["ParentID"] != nil && hit.Fields["ParentID"] != "" { + parentID, err := storagespace.ParseID(hit.Fields["ParentID"].(string)) + if err != nil { + return nil, err + } + match.Entity.ParentId = resourceIDtoSearchID(parentID) + } if mtime, err := time.Parse(time.RFC3339, hit.Fields["Mtime"].(string)); err == nil { match.Entity.LastModifiedTime = ×tamppb.Timestamp{Seconds: mtime.Unix(), Nanos: int32(mtime.Nanosecond())} diff --git a/services/search/pkg/search/index/index_test.go b/services/search/pkg/search/index/index_test.go index 7391d18a2..1708b7668 100644 --- a/services/search/pkg/search/index/index_test.go +++ b/services/search/pkg/search/index/index_test.go @@ -38,6 +38,11 @@ var _ = Describe("Index", func() { SpaceId: "spaceid", OpaqueId: "parentopaqueid", }, + ParentId: &sprovider.ResourceId{ + StorageId: "provider-1", + SpaceId: "spaceid", + OpaqueId: "myopaqueid", + }, Path: "sub d!r", Size: 12345, Type: sprovider.ResourceType_RESOURCE_TYPE_CONTAINER, @@ -370,20 +375,48 @@ var _ = Describe("Index", func() { }) Describe("Move", func() { - It("moves the parent and its child resources", func() { + It("renames the parent and its child resources", func() { err := i.Add(parentRef, parentRi) Expect(err).ToNot(HaveOccurred()) err = i.Add(childRef, childRi) Expect(err).ToNot(HaveOccurred()) parentRi.Path = "newname" - err = i.Move(parentRi.Id, "./somewhere/else/newname") + err = i.Move(parentRi.Id, parentRi.ParentId, "./my/newname") Expect(err).ToNot(HaveOccurred()) assertDocCount(rootId, `sub\ d!r`, 0) matches := assertDocCount(rootId, "Name:child.pdf", 1) + Expect(matches[0].Entity.ParentId.OpaqueId).To(Equal("parentopaqueid")) + Expect(matches[0].Entity.Ref.Path).To(Equal("./my/newname/child.pdf")) + }) + + It("moves the parent and its child resources", func() { + err := i.Add(parentRef, parentRi) + Expect(err).ToNot(HaveOccurred()) + err = i.Add(childRef, childRi) + Expect(err).ToNot(HaveOccurred()) + + parentRi.Path = " " + parentRi.ParentId = &sprovider.ResourceId{ + StorageId: "provider-1", + SpaceId: "spaceid", + OpaqueId: "somewhereopaqueid", + } + err = i.Move(parentRi.Id, parentRi.ParentId, "./somewhere/else/newname") + Expect(err).ToNot(HaveOccurred()) + + assertDocCount(rootId, `sub\ d!r`, 0) + + matches := assertDocCount(rootId, "Name:child.pdf", 1) + Expect(matches[0].Entity.ParentId.OpaqueId).To(Equal("parentopaqueid")) Expect(matches[0].Entity.Ref.Path).To(Equal("./somewhere/else/newname/child.pdf")) + + matches = assertDocCount(rootId, `newname`, 1) + Expect(matches[0].Entity.ParentId.OpaqueId).To(Equal("somewhereopaqueid")) + Expect(matches[0].Entity.Ref.Path).To(Equal("./somewhere/else/newname")) + }) }) }) diff --git a/services/search/pkg/search/index/mocks/BleveIndex.go b/services/search/pkg/search/index/mocks/BleveIndex.go deleted file mode 100644 index 1bb4f1b28..000000000 --- a/services/search/pkg/search/index/mocks/BleveIndex.go +++ /dev/null @@ -1,415 +0,0 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. - -package mocks - -import ( - context "context" - - bleve "github.com/blevesearch/bleve/v2" - - index "github.com/blevesearch/bleve_index_api" - - mapping "github.com/blevesearch/bleve/v2/mapping" - - mock "github.com/stretchr/testify/mock" -) - -// BleveIndex is an autogenerated mock type for the BleveIndex type -type BleveIndex struct { - mock.Mock -} - -// Advanced provides a mock function with given fields: -func (_m *BleveIndex) Advanced() (index.Index, error) { - ret := _m.Called() - - var r0 index.Index - if rf, ok := ret.Get(0).(func() index.Index); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(index.Index) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Batch provides a mock function with given fields: b -func (_m *BleveIndex) Batch(b *bleve.Batch) error { - ret := _m.Called(b) - - var r0 error - if rf, ok := ret.Get(0).(func(*bleve.Batch) error); ok { - r0 = rf(b) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Close provides a mock function with given fields: -func (_m *BleveIndex) Close() error { - ret := _m.Called() - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Delete provides a mock function with given fields: id -func (_m *BleveIndex) Delete(id string) error { - ret := _m.Called(id) - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(id) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// DeleteInternal provides a mock function with given fields: key -func (_m *BleveIndex) DeleteInternal(key []byte) error { - ret := _m.Called(key) - - var r0 error - if rf, ok := ret.Get(0).(func([]byte) error); ok { - r0 = rf(key) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// DocCount provides a mock function with given fields: -func (_m *BleveIndex) DocCount() (uint64, error) { - ret := _m.Called() - - var r0 uint64 - if rf, ok := ret.Get(0).(func() uint64); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint64) - } - - var r1 error - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Document provides a mock function with given fields: id -func (_m *BleveIndex) Document(id string) (index.Document, error) { - ret := _m.Called(id) - - var r0 index.Document - if rf, ok := ret.Get(0).(func(string) index.Document); ok { - r0 = rf(id) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(index.Document) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(id) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FieldDict provides a mock function with given fields: field -func (_m *BleveIndex) FieldDict(field string) (index.FieldDict, error) { - ret := _m.Called(field) - - var r0 index.FieldDict - if rf, ok := ret.Get(0).(func(string) index.FieldDict); ok { - r0 = rf(field) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(index.FieldDict) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(field) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FieldDictPrefix provides a mock function with given fields: field, termPrefix -func (_m *BleveIndex) FieldDictPrefix(field string, termPrefix []byte) (index.FieldDict, error) { - ret := _m.Called(field, termPrefix) - - var r0 index.FieldDict - if rf, ok := ret.Get(0).(func(string, []byte) index.FieldDict); ok { - r0 = rf(field, termPrefix) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(index.FieldDict) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(string, []byte) error); ok { - r1 = rf(field, termPrefix) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// FieldDictRange provides a mock function with given fields: field, startTerm, endTerm -func (_m *BleveIndex) FieldDictRange(field string, startTerm []byte, endTerm []byte) (index.FieldDict, error) { - ret := _m.Called(field, startTerm, endTerm) - - var r0 index.FieldDict - if rf, ok := ret.Get(0).(func(string, []byte, []byte) index.FieldDict); ok { - r0 = rf(field, startTerm, endTerm) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(index.FieldDict) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(string, []byte, []byte) error); ok { - r1 = rf(field, startTerm, endTerm) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Fields provides a mock function with given fields: -func (_m *BleveIndex) Fields() ([]string, error) { - ret := _m.Called() - - var r0 []string - if rf, ok := ret.Get(0).(func() []string); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]string) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// GetInternal provides a mock function with given fields: key -func (_m *BleveIndex) GetInternal(key []byte) ([]byte, error) { - ret := _m.Called(key) - - var r0 []byte - if rf, ok := ret.Get(0).(func([]byte) []byte); ok { - r0 = rf(key) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func([]byte) error); ok { - r1 = rf(key) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// Index provides a mock function with given fields: id, data -func (_m *BleveIndex) Index(id string, data interface{}) error { - ret := _m.Called(id, data) - - var r0 error - if rf, ok := ret.Get(0).(func(string, interface{}) error); ok { - r0 = rf(id, data) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Mapping provides a mock function with given fields: -func (_m *BleveIndex) Mapping() mapping.IndexMapping { - ret := _m.Called() - - var r0 mapping.IndexMapping - if rf, ok := ret.Get(0).(func() mapping.IndexMapping); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(mapping.IndexMapping) - } - } - - return r0 -} - -// Name provides a mock function with given fields: -func (_m *BleveIndex) Name() string { - ret := _m.Called() - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// NewBatch provides a mock function with given fields: -func (_m *BleveIndex) NewBatch() *bleve.Batch { - ret := _m.Called() - - var r0 *bleve.Batch - if rf, ok := ret.Get(0).(func() *bleve.Batch); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*bleve.Batch) - } - } - - return r0 -} - -// Search provides a mock function with given fields: req -func (_m *BleveIndex) Search(req *bleve.SearchRequest) (*bleve.SearchResult, error) { - ret := _m.Called(req) - - var r0 *bleve.SearchResult - if rf, ok := ret.Get(0).(func(*bleve.SearchRequest) *bleve.SearchResult); ok { - r0 = rf(req) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*bleve.SearchResult) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(*bleve.SearchRequest) error); ok { - r1 = rf(req) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SearchInContext provides a mock function with given fields: ctx, req -func (_m *BleveIndex) SearchInContext(ctx context.Context, req *bleve.SearchRequest) (*bleve.SearchResult, error) { - ret := _m.Called(ctx, req) - - var r0 *bleve.SearchResult - if rf, ok := ret.Get(0).(func(context.Context, *bleve.SearchRequest) *bleve.SearchResult); ok { - r0 = rf(ctx, req) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*bleve.SearchResult) - } - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, *bleve.SearchRequest) error); ok { - r1 = rf(ctx, req) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// SetInternal provides a mock function with given fields: key, val -func (_m *BleveIndex) SetInternal(key []byte, val []byte) error { - ret := _m.Called(key, val) - - var r0 error - if rf, ok := ret.Get(0).(func([]byte, []byte) error); ok { - r0 = rf(key, val) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// SetName provides a mock function with given fields: _a0 -func (_m *BleveIndex) SetName(_a0 string) { - _m.Called(_a0) -} - -// Stats provides a mock function with given fields: -func (_m *BleveIndex) Stats() *bleve.IndexStat { - ret := _m.Called() - - var r0 *bleve.IndexStat - if rf, ok := ret.Get(0).(func() *bleve.IndexStat); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*bleve.IndexStat) - } - } - - return r0 -} - -// StatsMap provides a mock function with given fields: -func (_m *BleveIndex) StatsMap() map[string]interface{} { - ret := _m.Called() - - var r0 map[string]interface{} - if rf, ok := ret.Get(0).(func() map[string]interface{}); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]interface{}) - } - } - - return r0 -} diff --git a/services/search/pkg/search/mocks/IndexClient.go b/services/search/pkg/search/mocks/index_client.go similarity index 85% rename from services/search/pkg/search/mocks/IndexClient.go rename to services/search/pkg/search/mocks/index_client.go index d2286517a..a4d171ccd 100644 --- a/services/search/pkg/search/mocks/IndexClient.go +++ b/services/search/pkg/search/mocks/index_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.10.4. DO NOT EDIT. package mocks @@ -65,13 +65,13 @@ func (_m *IndexClient) DocCount() (uint64, error) { return r0, r1 } -// Move provides a mock function with given fields: id, fullPath -func (_m *IndexClient) Move(id *providerv1beta1.ResourceId, fullPath string) error { - ret := _m.Called(id, fullPath) +// Move provides a mock function with given fields: id, parentID, fullPath +func (_m *IndexClient) Move(id *providerv1beta1.ResourceId, parentID *providerv1beta1.ResourceId, fullPath string) error { + ret := _m.Called(id, parentID, fullPath) var r0 error - if rf, ok := ret.Get(0).(func(*providerv1beta1.ResourceId, string) error); ok { - r0 = rf(id, fullPath) + if rf, ok := ret.Get(0).(func(*providerv1beta1.ResourceId, *providerv1beta1.ResourceId, string) error); ok { + r0 = rf(id, parentID, fullPath) } else { r0 = ret.Error(0) } diff --git a/services/search/pkg/search/mocks/ProviderClient.go b/services/search/pkg/search/mocks/provider_client.go similarity index 96% rename from services/search/pkg/search/mocks/ProviderClient.go rename to services/search/pkg/search/mocks/provider_client.go index 7435e78cb..69827f7c1 100644 --- a/services/search/pkg/search/mocks/ProviderClient.go +++ b/services/search/pkg/search/mocks/provider_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.10.4. DO NOT EDIT. package mocks diff --git a/services/search/pkg/search/provider/events.go b/services/search/pkg/search/provider/events.go index af62c7841..c3c7ab7d1 100644 --- a/services/search/pkg/search/provider/events.go +++ b/services/search/pkg/search/provider/events.go @@ -99,7 +99,7 @@ func (p *Provider) handleEvent(ev interface{}) { return } - err = p.indexClient.Move(statRes.Info.Id, gpRes.Path) + err = p.indexClient.Move(statRes.GetInfo().GetId(), statRes.GetInfo().GetParentId(), gpRes.Path) if err != nil { p.logger.Error().Err(err).Msg("failed to move the changed resource in the index") } diff --git a/services/search/pkg/search/provider/events_test.go b/services/search/pkg/search/provider/events_test.go index 7ee7f45f2..1917b7326 100644 --- a/services/search/pkg/search/provider/events_test.go +++ b/services/search/pkg/search/provider/events_test.go @@ -188,7 +188,7 @@ var _ = Describe("Searchprovider", func() { }, nil) indexClient.On("Move", mock.MatchedBy(func(id *sprovider.ResourceId) bool { return id.OpaqueId == ri.Id.OpaqueId - }), "./new/path.pdf").Return(nil).Run(func(args mock.Arguments) { + }), mock.Anything, "./new/path.pdf").Return(nil).Run(func(args mock.Arguments) { called = true }) ref.Path = "./new/path.pdf" diff --git a/services/search/pkg/search/search.go b/services/search/pkg/search/search.go index 0a8bedd26..acbbbd9c4 100644 --- a/services/search/pkg/search/search.go +++ b/services/search/pkg/search/search.go @@ -38,7 +38,7 @@ type ProviderClient interface { type IndexClient interface { Search(ctx context.Context, req *searchsvc.SearchIndexRequest) (*searchsvc.SearchIndexResponse, error) Add(ref *providerv1beta1.Reference, ri *providerv1beta1.ResourceInfo) error - Move(id *providerv1beta1.ResourceId, fullPath string) error + Move(id, parentID *providerv1beta1.ResourceId, fullPath string) error Delete(id *providerv1beta1.ResourceId) error Restore(id *providerv1beta1.ResourceId) error Purge(id *providerv1beta1.ResourceId) error diff --git a/services/webdav/pkg/service/v0/search.go b/services/webdav/pkg/service/v0/search.go index 55a6758fe..6c5a3d66c 100644 --- a/services/webdav/pkg/service/v0/search.go +++ b/services/webdav/pkg/service/v0/search.go @@ -171,6 +171,13 @@ func matchToPropResponse(ctx context.Context, match *searchmsg.Match) (*propfind SpaceId: match.Entity.Id.SpaceId, OpaqueId: match.Entity.Id.OpaqueId, }))) + if match.Entity.ParentId != nil { + propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:file-parent", storagespace.FormatResourceID(provider.ResourceId{ + StorageId: match.Entity.ParentId.StorageId, + SpaceId: match.Entity.ParentId.SpaceId, + OpaqueId: match.Entity.ParentId.OpaqueId, + }))) + } if match.Entity.Ref.ResourceId.StorageId == utils.ShareStorageProviderID { propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:shareid", match.Entity.Ref.ResourceId.OpaqueId)) propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:shareroot", match.Entity.ShareRootName))