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/docs/apis/http/webdav/_index.md b/docs/apis/http/webdav/_index.md
index b947d3e939..01371ff558 100644
--- a/docs/apis/http/webdav/_index.md
+++ b/docs/apis/http/webdav/_index.md
@@ -323,36 +323,49 @@ Available namespaces:
### Supported WebDAV Properties
-| Property | Desription | Example |
-|-----------------------------|----------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
-| `` | The latest modification time. | `Fri, 30 Dec 2022 14:22:43 GMT` |
-| `` | The file's etag. | `"c3a1ee4a0c28edc15b9635c3bf798013"` |
-| `` | The mime type of the file. | `image/jpeg` |
-| `` | Specifies the nature of the resource. | `` for a folder |
-| `` | The size if it is a file in bytes. | `5` bytes |
-| `` | Describes the active locks on a resource. | Detailed Example in [Locking]() |
-| `` | The globally unique ID of the resource. | `storage-1$27475553-7fb7-4689-b4cf-bbb635daff79!27475553-7fb7-4689-b4cf-bbb635daff79` |
-| `` | The globally unique ID of the resource. | `storage-1$27475553-7fb7-4689-b4cf-bbb635daff79!27475553-7fb7-4689-b4cf-bbb635daff79` |
-| `` | Direct URL to download a file from. | Not implemented. |
-| `` | The permissions a user has on the resource. | The value is a string containing letters for all available permissions. |
-| | | `S`: Shared |
-| | | `M`: Mounted |
-| | | `D`: Deletable |
-| | | `NV`: Updateable, Renameable, Moveable |
-| | | `W`: Updateable (file) |
-| | | `CK`: Creatable (folders only) |
-| | | `Z`: Deniable |
-| | | `P`: Trashbin Purgable |
-| `` | List of user specified tags. | `test` |
-| ` ` | The favorite state. | `0` for not favourited, `1` for favourited |
-| `` | The user id of the owner of a resource. Project spaces have no owner. | `einstein` |
-| `` | The display name of the owner of a resource. Project spaces have no owner. | `Albert Einstein` |
-| `` | List of share types. | `0` = User Share |
-| | | `1` = Group Share |
-| | | `2` = Public Link |
-| `` | | ``
`SHA1:1c68ea370b40c06fcaf7f26c8b1dba9d9caf5dea MD5:2205e48de5f93c784733ffcca841d2b5 ADLER32:058801ab`
`` |
-| | | Due to a bug in the very early development of ownCloud, this value is not an array, but a string separated by whitespaces. |
-| `` | Similar to `getcontentlength` but it also works for folders. | `10` bytes |
+| Property | Desription | Example |
+| ----------------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `` | The latest modification time. | `Fri, 30 Dec 2022 14:22:43 GMT` |
+| `` | The file's etag. | `"c3a1ee4a0c28edc15b9635c3bf798013"` |
+| `` | The mime type of the file. | `image/jpeg` |
+| `` | Specifies the nature of the resource. | `` for a folder |
+| `` | The size if it is a file in bytes. | `5` bytes |
+| `` | Describes the active locks on a resource. | Detailed Example in [Locking]() |
+| `` | The globally unique ID of the resource. | `storage-1$27475553-7fb7-4689-b4cf-bbb635daff79!27475553-7fb7-4689-b4cf-bbb635daff79` |
+| `` | The globally unique ID of the resource. | `storage-1$27475553-7fb7-4689-b4cf-bbb635daff79!27475553-7fb7-4689-b4cf-bbb635daff79` |
+| `` | Direct URL to download a file from. | Not implemented. |
+| `` | The permissions a user has on the resource. | The value is a string containing letters for all available permissions. |
+| | | `S`: Shared |
+| | | `M`: Mounted |
+| | | `D`: Deletable |
+| | | `NV`: Updateable, Renameable, Moveable |
+| | | `W`: Updateable (file) |
+| | | `CK`: Creatable (folders only) |
+| | | `Z`: Deniable |
+| | | `P`: Trashbin Purgable |
+| `` | List of user specified tags. | `test` |
+| ` ` | The favorite state. | `0` for not favourited, `1` for favourited |
+| `` | The user id of the owner of a resource. Project spaces have no owner. | `einstein` |
+| `` | The display name of the owner of a resource. Project spaces have no owner. | `Albert Einstein` |
+| `` | List of share types. | `0` = User Share |
+| | | `1` = Group Share |
+| | | `2` = Public Link |
+| `` | | ``
`SHA1:1c68ea370b40c06fcaf7f26c8b1dba9d9caf5dea MD5:2205e48de5f93c784733ffcca841d2b5 ADLER32:058801ab`
`` |
+| | | Due to a bug in the very early development of ownCloud, this value is not an array, but a string separated by whitespaces. |
+| `` | Similar to `getcontentlength` but it also works for folders. | `10` bytes |
+| `` | The ID of the share if the resource is part of such. | `storage-1$27475553-7fb7-4689-b4cf-bbb635daff79!27475553-7fb7-4689-b4cf-bbb635daff79` |
+| `` | The root path of the shared resource if the resource is part of such. | `/shared-folder` |
+| `` | The ID of the shared resource if the resource is part of such. | `storage-1$27475553-7fb7-4689-b4cf-bbb635daff79!27475553-7fb7-4689-b4cf-bbb635daff79` |
+| `` | The type of the resource if it's a public link. | `folder` |
+| `` | The share permissions of the resource if it's a public link. | `1` |
+| `` | The expiration date of the public link. | `Tue, 14 May 2024 12:44:29 GMT` |
+| `` | The date the public link was created. | `Tue, 14 May 2024 12:44:29 GMT` |
+| `` | The username of the user who created the public link. | `admin` |
+| `` | The original name of the resource before it was deleted. | `some-file.txt` |
+| `` | The original location of the resource before it was deleted. | `some-file.txt` |
+| `` | The date the resource was deleted. | `Tue, 14 May 2024 12:44:29 GMT` |
+| `` | Audio meta data if the resource contains such. | `MetallicaMetallicaEnter Sandman` |
+| `` | Location meta data if the resource contains such. | `51.504106-0.074575` |
### Request Headers
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..a5818f88db 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.GetRemoteItemId().GetStorageId(),
+ SpaceId: match.Entity.GetRemoteItemId().GetSpaceId(),
+ OpaqueId: match.Entity.GetRemoteItemId().GetOpaqueId(),
+ })))
}
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)))