Skip to content

Commit e75a0a4

Browse files
Vincent Petryrullzer
authored andcommitted
Make share target consistent when grouping group share with user share
In some situations, a group share is created before a user share, and the recipient renamed the received share before the latter is created. In this situation, the "file_target" was already modified and the second created share must align to the already renamed share. To achieve this, the MountProvider now groups only by "item_source" value and sorts by share time. This makes it so that the least recent share is selected as super-share and its "file_target" value is then adjusted in all grouped shares. This fixes the issue where this situation would have different "file_target" values resulting in two shared folders appearing instead of one.
1 parent 56e9f7c commit e75a0a4

2 files changed

Lines changed: 55 additions & 12 deletions

File tree

apps/files_sharing/lib/MountProvider.php

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public function getMountsForUser(IUser $user, IStorageFactory $storageFactory) {
7575
return $share->getPermissions() > 0 && $share->getShareOwner() !== $user->getUID();
7676
});
7777

78-
$superShares = $this->buildSuperShares($shares);
78+
$superShares = $this->buildSuperShares($shares, $user);
7979

8080
$mounts = [];
8181
foreach ($superShares as $share) {
@@ -116,17 +116,22 @@ private function groupShares(array $shares) {
116116
if (!isset($tmp[$share->getNodeId()])) {
117117
$tmp[$share->getNodeId()] = [];
118118
}
119-
$tmp[$share->getNodeId()][$share->getTarget()][] = $share;
119+
$tmp[$share->getNodeId()][] = $share;
120120
}
121121

122122
$result = [];
123-
foreach ($tmp as $tmp2) {
124-
foreach ($tmp2 as $item) {
125-
$result[] = $item;
126-
}
123+
// sort by stime, the super share will be based on the least recent share
124+
foreach ($tmp as &$tmp2) {
125+
@usort($tmp2, function($a, $b) {
126+
if ($a->getShareTime() < $b->getShareTime()) {
127+
return -1;
128+
}
129+
return 1;
130+
});
131+
$result[] = $tmp2;
127132
}
128133

129-
return $result;
134+
return array_values($result);
130135
}
131136

132137
/**
@@ -136,9 +141,10 @@ private function groupShares(array $shares) {
136141
* of all shares within the group.
137142
*
138143
* @param \OCP\Share\IShare[] $allShares
144+
* @param \OCP\IUser $user user
139145
* @return array Tuple of [superShare, groupedShares]
140146
*/
141-
private function buildSuperShares(array $allShares) {
147+
private function buildSuperShares(array $allShares, \OCP\IUser $user) {
142148
$result = [];
143149

144150
$groupedShares = $this->groupShares($allShares);
@@ -161,6 +167,11 @@ private function buildSuperShares(array $allShares) {
161167
$permissions = 0;
162168
foreach ($shares as $share) {
163169
$permissions |= $share->getPermissions();
170+
if ($share->getTarget() !== $superShare->getTarget()) {
171+
// adjust target, for database consistency
172+
$share->setTarget($superShare->getTarget());
173+
$this->shareManager->moveShare($share, $user->getUID());
174+
}
164175
}
165176

166177
$superShare->setPermissions($permissions);

apps/files_sharing/tests/MountProviderTest.php

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@ private function makeMockShare($id, $nodeId, $owner = 'user2', $target = null, $
8585
$share->expects($this->any())
8686
->method('getNodeId')
8787
->will($this->returnValue($nodeId));
88+
$share->expects($this->any())
89+
->method('getShareTime')
90+
->will($this->returnValue(
91+
// compute share time based on id, simulating share order
92+
new \DateTime('@' . (1469193980 + 1000 * $id))
93+
));
8894
return $share;
8995
}
9096

@@ -101,9 +107,9 @@ public function testExcludeShares() {
101107
$this->makeMockShare(2, 100, 'user2', '/share2', 31),
102108
];
103109
$groupShares = [
104-
$this->makeMockShare(3, 100, 'user2', '/share2', 0),
105-
$this->makeMockShare(4, 100, 'user2', '/share4', 31),
106-
$this->makeMockShare(5, 100, 'user1', '/share4', 31),
110+
$this->makeMockShare(3, 100, 'user2', '/share2', 0),
111+
$this->makeMockShare(4, 101, 'user2', '/share4', 31),
112+
$this->makeMockShare(5, 100, 'user1', '/share4', 31),
107113
];
108114
$this->user->expects($this->any())
109115
->method('getUID')
@@ -134,7 +140,7 @@ public function testExcludeShares() {
134140
$mountedShare2 = $mounts[1]->getShare();
135141
$this->assertEquals('4', $mountedShare2->getId());
136142
$this->assertEquals('user2', $mountedShare2->getShareOwner());
137-
$this->assertEquals(100, $mountedShare2->getNodeId());
143+
$this->assertEquals(101, $mountedShare2->getNodeId());
138144
$this->assertEquals('/share4', $mountedShare2->getTarget());
139145
$this->assertEquals(31, $mountedShare2->getPermissions());
140146
}
@@ -229,6 +235,32 @@ public function mergeSharesDataProvider() {
229235
// no received share since "user1" opted out
230236
],
231237
],
238+
// #7: share as outsider with "group1" and "user1" where recipient renamed in between
239+
[
240+
[
241+
[1, 100, 'user2', '/share2-renamed', 31],
242+
],
243+
[
244+
[2, 100, 'user2', '/share2', 31],
245+
],
246+
[
247+
// use target of least recent share
248+
['1', 100, 'user2', '/share2-renamed', 31],
249+
],
250+
],
251+
// #8: share as outsider with "group1" and "user1" where recipient renamed in between
252+
[
253+
[
254+
[2, 100, 'user2', '/share2', 31],
255+
],
256+
[
257+
[1, 100, 'user2', '/share2-renamed', 31],
258+
],
259+
[
260+
// use target of least recent share
261+
['1', 100, 'user2', '/share2-renamed', 31],
262+
],
263+
],
232264
];
233265
}
234266

0 commit comments

Comments
 (0)