Repository: owncloud/ocis
Pull request #4752 (2022-10-07 06:23:08)

Bump google.golang.org/grpc from 1.49.0 to 1.50.0
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.49.0 to 1.50.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/grpc/grpc-go/releases">google.golang.org/grpc's releases</a>.</em></p>
<blockquote>
<h2>Release 1.50.0</h2>
<h1>Behavior Changes</h1>
<ul>
<li>client: use proper &quot;@&quot; semantics for connecting to abstract unix sockets. (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5678">#5678</a>)
<ul>
<li>This is technically a bug fix; the result is that the address was including a trailing NULL byte, which it should not have.  This may break users creating the socket in Go by prefixing a NULL instead of an &quot;@&quot;, though, so calling it out as a behavior change.</li>
</ul>
<ul>
<li>Special Thanks: <a href="https://github.com/jachor"><code>@​jachor</code></a></li>
</ul>
</li>
</ul>
<h1>New Features</h1>
<ul>
<li>metadata: add experimental <code>ValueFromIncomingContext</code> to more efficiently retrieve a single value (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5596">#5596</a>)
<ul>
<li>Special Thanks: <a href="https://github.com/horpto"><code>@​horpto</code></a></li>
</ul>
</li>
<li>stats: provide peer information in <code>HandleConn</code> context (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5589">#5589</a>)
<ul>
<li>Special Thanks: <a href="https://github.com/feihu-stripe"><code>@​feihu-stripe</code></a></li>
</ul>
</li>
<li>xds: add support for Outlier Detection, enabled by default (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5435">#5435</a>, <a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5673">#5673</a>)</li>
</ul>
<h1>Bug Fixes</h1>
<ul>
<li>client: fix deadlock in transport caused by GOAWAY racing with stream creation (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5652">#5652</a>)
<ul>
<li>This should only occur with an HTTP/2 server that does not follow best practices of an advisory GOAWAY (not a grpc-go server).</li>
</ul>
</li>
<li>xds/xdsclient: fix a bug which was causing routes with <code>cluster_specifier_plugin</code> set to be NACKed when GRPC_EXPERIMENTAL_XDS_RLS_LB was off (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5670">#5670</a>)</li>
<li>xds/xdsclient: NACK cluster resource if <code>config_source_specifier</code> in <code>lrs_server</code> is not <code>self</code> (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5613">#5613</a>)</li>
<li>xds/ringhash: fix a bug which sometimes prevents the LB policy from retrying connection attempts (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5601">#5601</a>)</li>
<li>xds/ringhash: do nothing when asked to exit <code>IDLE</code> instead of falling back on the default channel behavior of connecting to all addresses (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5614">#5614</a>)</li>
<li>xds/rls: fix a bug which was causing the channel to be stuck in <code>IDLE</code> (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5656">#5656</a>)</li>
<li>alts: fix a bug which was setting <code>WaitForReady</code> on handshaker service RPCs, thereby delaying fallback when required (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5620">#5620</a>)</li>
<li>gcp/observability: fix End() to cleanup global state correctly (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5623">#5623</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/grpc/grpc-go/commit/c1d7d7acc3d14788d07ded8be9cd74c136084294"><code>c1d7d7a</code></a> Change version to 1.50.0 (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5685">#5685</a>)</li>
<li><a href="https://github.com/grpc/grpc-go/commit/1451c62ccdce325a1f2fdbcc90db89518a36dc06"><code>1451c62</code></a> internal/transport: optimize grpc-message encoding/decoding (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5654">#5654</a>)</li>
<li><a href="https://github.com/grpc/grpc-go/commit/be4b63b1fcab082f7e19b540abfbbaf13958addd"><code>be4b63b</code></a> test: minor test cleanup (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5679">#5679</a>)</li>
<li><a href="https://github.com/grpc/grpc-go/commit/d83070ec0d9043f713b6a63e1963c593b447208c"><code>d83070e</code></a> Changed Outlier Detection Env Var to default true (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5673">#5673</a>)</li>
<li><a href="https://github.com/grpc/grpc-go/commit/54521b22e01f52e6e112b33bbca8b2255915dd40"><code>54521b2</code></a> client: remove trailing null from unix abstract socket address (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5678">#5678</a>)</li>
<li><a href="https://github.com/grpc/grpc-go/commit/36e481079b224e01fc3134ba7f1b2717f0c4d4ef"><code>36e4810</code></a> orca: cleanup old code, and get grpc package to use new code (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5627">#5627</a>)</li>
<li><a href="https://github.com/grpc/grpc-go/commit/e8866a83edf51f5a5dcd8097c6d4fe4cdef49cdd"><code>e8866a8</code></a> build: harden GitHub Workflow permissions (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5660">#5660</a>)</li>
<li><a href="https://github.com/grpc/grpc-go/commit/8458251c6b35036b90788223f67fc9e4396cd32c"><code>8458251</code></a> xdsclient: ignore routes with cluster_specifier_plugin when GRPC_EXPERIMENTAL...</li>
<li><a href="https://github.com/grpc/grpc-go/commit/a238cebacde409d423d0116523523deb9fe0bdc7"><code>a238ceb</code></a> xDS: Outlier Detection Env Var not hardcoded to false (<a href="https://github-redirect.dependabot.com/grpc/grpc-go/issues/5664">#5664</a>)</li>
<li><a href="https://github.com/grpc/grpc-go/commit/b1d7f56b81b7902d871111b82dec6ba45f854ede"><code>b1d7f56</code></a> transport: Fix deadlock in transport caused by GOAWAY race with new stream cr...</li>
<li>Additional commits viewable in <a href="https://github.com/grpc/grpc-go/compare/v1.49.0...v1.50.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=google.golang.org/grpc&package-manager=go_modules&previous-version=1.49.0&new-version=1.50.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

update-docs[bot]: Thanks for opening this pull request! The maintainers of this repository would appreciate it if you would create a [changelog](https://github.com/owncloud/ocis/blob/master/changelog/README.md) item based on your changes.

sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=4752)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=4752&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=4752&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=4752&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=4752&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=4752&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=4752&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=4752&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=4752&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=4752&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=4752&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=4752&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=4752&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=4752&metric=coverage&view=list) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=4752&metric=duplicated_lines_density&view=list) No Duplication information



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cba085f859d..d3ab1160c93 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,6 +26,7 @@ The following sections list the changes for unreleased.
 * Enhancement - Add support for REPORT requests to /dav/spaces URLs: [#4661](https://github.com/owncloud/ocis/pull/4661)
 * Enhancement - Allow to configure applications in Web: [#4578](https://github.com/owncloud/ocis/pull/4578)
 * Enhancement - Restrict admins from self-removal: [#3713](https://github.com/owncloud/ocis/issues/3713)
+* Enhancement - Report parent id: [#4757](https://github.com/owncloud/ocis/pull/4757)
 * Enhancement - Add thumbnails support for tiff and bmp files: [#4634](https://github.com/owncloud/ocis/pull/4634)
 * Enhancement - Update reva: [#4588](https://github.com/owncloud/ocis/pull/4588)
 * Enhancement - Make it possible to configure a WOPI folderurl: [#4716](https://github.com/owncloud/ocis/pull/4716)
@@ -184,6 +185,13 @@ The following sections list the changes for unreleased.
 
    https://github.com/owncloud/ocis/issues/3713
 
+* Enhancement - Report parent id: [#4757](https://github.com/owncloud/ocis/pull/4757)
+
+   We now index and return the parent id of a resource in search REPORTs.
+
+   https://github.com/owncloud/ocis/issues/4727
+   https://github.com/owncloud/ocis/pull/4757
+
 * Enhancement - Add thumbnails support for tiff and bmp files: [#4634](https://github.com/owncloud/ocis/pull/4634)
 
    Support generating thumbnails for tiff and bmp files in the thumbnails service.
diff --git a/Makefile b/Makefile
index fe998736262..b4038cfa476 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 00000000000..6b710fe5503
--- /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/go.mod b/go.mod
index ceb177ec22f..1ccaa09fcc2 100644
--- a/go.mod
+++ b/go.mod
@@ -69,7 +69,6 @@ require (
 	go.etcd.io/bbolt v1.3.6
 	go.etcd.io/etcd/client/v3 v3.5.5
 	go.opencensus.io v0.23.0
-	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.36.1
 	go.opentelemetry.io/otel v1.10.0
 	go.opentelemetry.io/otel/exporters/jaeger v1.10.0
 	go.opentelemetry.io/otel/sdk v1.10.0
@@ -82,7 +81,7 @@ require (
 	golang.org/x/term v0.0.0-20220722155259-a9ba230a4035
 	golang.org/x/text v0.3.7
 	google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006
-	google.golang.org/grpc v1.49.0
+	google.golang.org/grpc v1.50.0
 	google.golang.org/protobuf v1.28.1
 	gopkg.in/yaml.v2 v2.4.0
 	gotest.tools/v3 v3.3.0
@@ -98,7 +97,6 @@ require (
 	github.com/Masterminds/sprig v2.22.0+incompatible // indirect
 	github.com/Microsoft/go-winio v0.5.2 // indirect
 	github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895 // indirect
-	github.com/ReneKroon/ttlcache/v2 v2.11.0 // indirect
 	github.com/RoaringBitmap/roaring v0.9.4 // indirect
 	github.com/acomagu/bufpipe v1.0.3 // indirect
 	github.com/ajg/form v1.5.1 // indirect
@@ -270,6 +268,7 @@ require (
 	github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
 	go.etcd.io/etcd/api/v3 v3.5.5 // indirect
 	go.etcd.io/etcd/client/pkg/v3 v3.5.5 // indirect
+	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.36.1 // indirect
 	go.opentelemetry.io/otel/internal/metric v0.27.0 // indirect
 	go.opentelemetry.io/otel/metric v0.27.0 // indirect
 	go.uber.org/atomic v1.10.0 // indirect
diff --git a/go.sum b/go.sum
index 96dab7ffd06..6ee6787b99f 100644
--- a/go.sum
+++ b/go.sum
@@ -115,8 +115,6 @@ github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895 h1:NsReiLpErI
 github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8=
 github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
-github.com/ReneKroon/ttlcache/v2 v2.11.0 h1:OvlcYFYi941SBN3v9dsDcC2N8vRxyHcCmJb3Vl4QMoM=
-github.com/ReneKroon/ttlcache/v2 v2.11.0/go.mod h1:mBxvsNY+BT8qLLd6CuAJubbKo6r0jh3nb5et22bbfGY=
 github.com/RoaringBitmap/roaring v0.9.4 h1:ckvZSX5gwCRaJYBNe7syNawCU5oruY9gQmjXlp4riwo=
 github.com/RoaringBitmap/roaring v0.9.4/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA=
 github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
@@ -297,8 +295,6 @@ github.com/crewjam/saml v0.4.6 h1:XCUFPkQSJLvzyl4cW9OvpWUbRf0gE7VUpU8ZnilbeM4=
 github.com/crewjam/saml v0.4.6/go.mod h1:ZBOXnNPFzB3CgOkRm7Nd6IVdkG+l/wF+0ZXLqD96t1A=
 github.com/cs3org/go-cs3apis v0.0.0-20220929083235-bb0b1a236d6c h1:b+YTmOGlf43mnF8MzO0fsy8/Ho8JLu44Iq5Y0fKLJMM=
 github.com/cs3org/go-cs3apis v0.0.0-20220929083235-bb0b1a236d6c/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
-github.com/cs3org/reva/v2 v2.10.1-0.20221004120309-40430d529c4e h1:nVkgLcPZeIxxprEs1HNOnvQWZnjlKzGjpAKPa34q3QU=
-github.com/cs3org/reva/v2 v2.10.1-0.20221004120309-40430d529c4e/go.mod h1:3KJAxMKj8RMkCE//Zr/CTuLloRt7HpUVYmj3DD6S3Vo=
 github.com/cs3org/reva/v2 v2.10.1-0.20221006145249-70bf0e95ec00 h1:cmXDi1Uv/96k8lv7/mWShKIMd4cvOqmhtbrXtVxz+uM=
 github.com/cs3org/reva/v2 v2.10.1-0.20221006145249-70bf0e95ec00/go.mod h1:UQVMlPZtcoPXLZSJ4ZRTruzn6PlRVmpEantwf1wGknU=
 github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI=
@@ -1900,8 +1896,9 @@ google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu
 google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
 google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
 google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw=
 google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
+google.golang.org/grpc v1.50.0 h1:fPVVDxY9w++VjTZsYvXWqEf9Rqar/e+9zYfxKK+W+YU=
+google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
 google.golang.org/grpc/examples v0.0.0-20211102180624-670c133e568e h1:m7aQHHqd0q89mRwhwS9Bx2rjyl/hsFAeta+uGrHsQaU=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
diff --git a/protogen/gen/ocis/messages/search/v0/search.pb.go b/protogen/gen/ocis/messages/search/v0/search.pb.go
index 215de6eef1c..b8f62574bf2 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 8e08272ef01..b30e14dc3dc 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 0901be95f8a..2ba276bda0f 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 9d0293e6fb5..29930a15bc7 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 85e50c04b5a..8fc5d9e7aa2 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 032a972be33..f8a3b5a8c01 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 271557e6ff9..f822841b087 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 = &timestamppb.Timestamp{Seconds: mtime.Unix(), Nanos: int32(mtime.Nanosecond())}
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 1bb4f1b28d3..00000000000
--- 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 d2286517a43..a4d171ccdbb 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 7435e78cba3..69827f7c1d1 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 af62c78410e..c3c7ab7d14b 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/search.go b/services/search/pkg/search/search.go
index 0a8bedd2662..acbbbd9c45f 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 55a6758fe92..6c5a3d66cbd 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))


Test patch:
diff --git a/services/search/pkg/search/index/index_test.go b/services/search/pkg/search/index/index_test.go
index 7391d18a2e2..1708b766842 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/provider/events_test.go b/services/search/pkg/search/provider/events_test.go
index 7ee7f45f2a7..1917b732697 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"