From d40a643fbf015fd6baa1d6e3369c2fcdfcf85454 Mon Sep 17 00:00:00 2001 From: Jannik Stehle Date: Tue, 7 May 2024 15:06:33 +0200 Subject: [PATCH] feat: add remote item id to search report responses Adds the remote item id to search `REPORT` responses for shared resources and resources that are part of such. This id represents the id of the original resource that has been shared (= the remote item) and is needed for clients to correctly resolve their locations. --- .../add-remote-item-id-to-webdav-report.md | 6 +++ .../gen/ocis/messages/search/v0/search.pb.go | 53 ++++++++++++------- .../services/search/v0/search.swagger.json | 3 ++ .../ocis/messages/search/v0/search.proto | 1 + services/search/pkg/search/service.go | 7 +++ services/search/pkg/search/service_test.go | 12 +++++ services/webdav/pkg/service/v0/search.go | 5 ++ 7 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 changelog/unreleased/add-remote-item-id-to-webdav-report.md diff --git a/changelog/unreleased/add-remote-item-id-to-webdav-report.md b/changelog/unreleased/add-remote-item-id-to-webdav-report.md new file mode 100644 index 0000000000..1542f7ce2c --- /dev/null +++ b/changelog/unreleased/add-remote-item-id-to-webdav-report.md @@ -0,0 +1,6 @@ +Enhancement: Add remote item id to WebDAV report responses + +The remote item id has been added to WebDAV `REPORT` responses. + +https://github.com/owncloud/ocis/issues/9094 +https://github.com/owncloud/ocis/pull/9095 diff --git a/protogen/gen/ocis/messages/search/v0/search.pb.go b/protogen/gen/ocis/messages/search/v0/search.pb.go index 0349d3e177..0cca4f065a 100644 --- a/protogen/gen/ocis/messages/search/v0/search.pb.go +++ b/protogen/gen/ocis/messages/search/v0/search.pb.go @@ -390,6 +390,7 @@ type Entity struct { Highlights string `protobuf:"bytes,14,opt,name=highlights,proto3" json:"highlights,omitempty"` Audio *Audio `protobuf:"bytes,15,opt,name=audio,proto3" json:"audio,omitempty"` Location *GeoCoordinates `protobuf:"bytes,16,opt,name=location,proto3" json:"location,omitempty"` + RemoteItemId *ResourceID `protobuf:"bytes,17,opt,name=remote_item_id,json=remoteItemId,proto3" json:"remote_item_id,omitempty"` } func (x *Entity) Reset() { @@ -536,6 +537,13 @@ func (x *Entity) GetLocation() *GeoCoordinates { return nil } +func (x *Entity) GetRemoteItemId() *ResourceID { + if x != nil { + return x.RemoteItemId + } + return nil +} + type Match struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -669,8 +677,8 @@ var file_ocis_messages_search_v0_search_proto_rawDesc = []byte{ 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x48, 0x02, 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x61, 0x6c, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, - 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x22, 0xfd, - 0x04, 0x0a, 0x06, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x34, 0x0a, 0x03, 0x72, 0x65, 0x66, + 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x22, 0xc8, + 0x05, 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, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x03, 0x72, 0x65, 0x66, 0x12, @@ -709,18 +717,22 @@ var file_ocis_messages_search_v0_search_proto_rawDesc = []byte{ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 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, 0x47, 0x65, 0x6f, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, - 0x61, 0x74, 0x65, 0x73, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 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, 0x74, 0x65, 0x73, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x49, + 0x0a, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, + 0x18, 0x11, 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, 0x0c, 0x72, 0x65, 0x6d, + 0x6f, 0x74, 0x65, 0x49, 0x74, 0x65, 0x6d, 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 ( @@ -753,12 +765,13 @@ var file_ocis_messages_search_v0_search_proto_depIdxs = []int32{ 0, // 4: ocis.messages.search.v0.Entity.parent_id:type_name -> ocis.messages.search.v0.ResourceID 2, // 5: ocis.messages.search.v0.Entity.audio:type_name -> ocis.messages.search.v0.Audio 3, // 6: ocis.messages.search.v0.Entity.location:type_name -> ocis.messages.search.v0.GeoCoordinates - 4, // 7: ocis.messages.search.v0.Match.entity:type_name -> ocis.messages.search.v0.Entity - 8, // [8:8] is the sub-list for method output_type - 8, // [8:8] is the sub-list for method input_type - 8, // [8:8] is the sub-list for extension type_name - 8, // [8:8] is the sub-list for extension extendee - 0, // [0:8] is the sub-list for field type_name + 0, // 7: ocis.messages.search.v0.Entity.remote_item_id:type_name -> ocis.messages.search.v0.ResourceID + 4, // 8: ocis.messages.search.v0.Match.entity:type_name -> ocis.messages.search.v0.Entity + 9, // [9:9] is the sub-list for method output_type + 9, // [9:9] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { file_ocis_messages_search_v0_search_proto_init() } diff --git a/protogen/gen/ocis/services/search/v0/search.swagger.json b/protogen/gen/ocis/services/search/v0/search.swagger.json index d84ac28f33..98a0c0e356 100644 --- a/protogen/gen/ocis/services/search/v0/search.swagger.json +++ b/protogen/gen/ocis/services/search/v0/search.swagger.json @@ -273,6 +273,9 @@ }, "location": { "$ref": "#/definitions/v0GeoCoordinates" + }, + "remoteItemId": { + "$ref": "#/definitions/v0ResourceID" } } }, diff --git a/protogen/proto/ocis/messages/search/v0/search.proto b/protogen/proto/ocis/messages/search/v0/search.proto index 84b2b9c250..eab871217d 100644 --- a/protogen/proto/ocis/messages/search/v0/search.proto +++ b/protogen/proto/ocis/messages/search/v0/search.proto @@ -59,6 +59,7 @@ message Entity { string highlights = 14; Audio audio = 15; GeoCoordinates location = 16; + ResourceID remote_item_id = 17; } message Match { diff --git a/services/search/pkg/search/service.go b/services/search/pkg/search/service.go index 40184a741a..2a473d8cbf 100644 --- a/services/search/pkg/search/service.go +++ b/services/search/pkg/search/service.go @@ -278,6 +278,7 @@ func (s *Service) searchIndex(ctx context.Context, req *searchsvc.SearchRequest, mountpointRootID *searchmsg.ResourceID rootName string permissions *provider.ResourcePermissions + remoteItemId *searchmsg.ResourceID ) mountpointPrefix := "" searchPathPrefix := req.Ref.GetPath() @@ -329,6 +330,11 @@ func (s *Service) searchIndex(ctx context.Context, req *searchsvc.SearchRequest, } rootName = space.GetRootInfo().GetPath() permissions = space.GetRootInfo().GetPermissionSet() + remoteItemId = &searchmsg.ResourceID{ + StorageId: space.GetRootInfo().GetId().GetStorageId(), + SpaceId: space.GetRootInfo().GetId().GetSpaceId(), + OpaqueId: space.GetRootInfo().GetId().GetOpaqueId(), + } s.logger.Debug().Interface("grantSpace", space).Interface("mountpointRootId", mountpointRootID).Msg("searching a grant") case _spaceTypePersonal, _spaceTypeProject: permissions = space.GetRootInfo().GetPermissionSet() @@ -365,6 +371,7 @@ func (s *Service) searchIndex(ctx context.Context, req *searchsvc.SearchRequest, match.Entity.Ref.ResourceId = mountpointRootID } match.Entity.ShareRootName = rootName + match.Entity.RemoteItemId = remoteItemId isShared := match.GetEntity().GetRef().GetResourceId().GetSpaceId() == utils.ShareStorageSpaceID isMountpoint := isShared && match.GetEntity().GetRef().GetPath() == "." diff --git a/services/search/pkg/search/service_test.go b/services/search/pkg/search/service_test.go index d54b8d5adb..57a89b3ecc 100644 --- a/services/search/pkg/search/service_test.go +++ b/services/search/pkg/search/service_test.go @@ -281,6 +281,13 @@ var _ = Describe("Searchprovider", func() { Id: &sprovider.StorageSpaceId{OpaqueId: "storageproviderid$spaceid!otherspacegrant"}, Root: &sprovider.ResourceId{StorageId: "storageproviderid", SpaceId: "spaceid", OpaqueId: "otherspacegrant"}, Name: "grantspace", + RootInfo: &sprovider.ResourceInfo{ + Id: &sprovider.ResourceId{ + StorageId: "storageid", + SpaceId: "spaceid", + OpaqueId: "opaqueid", + }, + }, } mountpointSpace = &sprovider.StorageSpace{ SpaceType: "mountpoint", @@ -345,6 +352,11 @@ var _ = Describe("Searchprovider", func() { Expect(match.Entity.Name).To(Equal("Shared.pdf")) Expect(match.Entity.Ref.ResourceId.OpaqueId).To(Equal(mountpointSpace.Root.OpaqueId)) Expect(match.Entity.Ref.Path).To(Equal("./to/Shared.pdf")) + Expect(match.Entity.RemoteItemId).To(Equal(&searchmsg.ResourceID{ + StorageId: grantSpace.RootInfo.Id.StorageId, + SpaceId: grantSpace.RootInfo.Id.SpaceId, + OpaqueId: grantSpace.RootInfo.Id.OpaqueId, + })) }) Context("when searching both spaces", func() { diff --git a/services/webdav/pkg/service/v0/search.go b/services/webdav/pkg/service/v0/search.go index 94c2efbb5c..cf67032f27 100644 --- a/services/webdav/pkg/service/v0/search.go +++ b/services/webdav/pkg/service/v0/search.go @@ -185,6 +185,11 @@ func matchToPropResponse(ctx context.Context, match *searchmsg.Match) (*propfind 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)) + propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:remote-item-id", storagespace.FormatResourceID(provider.ResourceId{ + StorageId: match.Entity.RemoteItemId.StorageId, + SpaceId: match.Entity.RemoteItemId.SpaceId, + OpaqueId: match.Entity.RemoteItemId.OpaqueId, + }))) } propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:name", match.Entity.Name)) propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("d:getlastmodified", match.Entity.LastModifiedTime.AsTime().Format(time.RFC3339)))