Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
mrow4a committed Mar 7, 2017
1 parent 24620f5 commit 331b82e
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 133 deletions.
56 changes: 39 additions & 17 deletions apps/dav/lib/Connector/Sabre/SharesPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,30 @@ public function initialize(\Sabre\DAV\Server $server) {
}

/**
* Update cachedShareTypes for specific nodeIDs
* Converts IShare[] to int[][] hash map
*
* @param IShare[] array containing shares
* @param int[][] array containing hash map nodeIds->shareTypes $initShareTypes[$currentNodeID][$currentShareType]
*/
private function convertToHashMap($allShares, $initShareTypes) {
// Use some already preinitialized hash map which may contain some values e.g. empty arrays
$shareTypes = $initShareTypes;

foreach ($allShares as $share) {
$currentNodeID = $share->getNodeId();
$currentShareType = $share->getShareType();
$shareTypes[$currentNodeID][$currentShareType] = true;
}

return $shareTypes;
}

/**
* Get all shares for specific nodeIDs
*
* @param int[] array of folder/file nodeIDs
*/
private function getNodesShareTypes($nodeIDs) {
private function getSharesForNodeIds($nodeIDs) {
$requestedShareTypes = [
\OCP\Share::SHARE_TYPE_USER,
\OCP\Share::SHARE_TYPE_GROUP,
Expand All @@ -122,13 +141,8 @@ private function getNodesShareTypes($nodeIDs) {
$requestedShareTypes,
$nodeIDs
);

// Cache obtained share types
foreach ($allShares as $share) {
$currentNodeID = $share->getNodeId();
$currentShareType = $share->getShareType();
$this->cachedShareTypes[$currentNodeID][$currentShareType] = true;
}

return $allShares;
}

/**
Expand Down Expand Up @@ -157,8 +171,10 @@ public function handleGetProperties(
$folderNodeID = intval($folderNode->getId());
$nodeIdsArray = [$folderNodeID];

// Initialize share types array for this node in case there would be no shares for this node
$initShareTypes[$folderNodeID] = [];

// Get IDs for all children of the parent folder
$this->cachedShareTypes[$folderNodeID] = [];
foreach ($children as $childNode) {
// Ensure that they are of File or Folder type
if (!($childNode instanceof \OCP\Files\File) &&
Expand All @@ -169,24 +185,30 @@ public function handleGetProperties(
// Put node ID into an array and initialize cache for it
$nodeId = intval($childNode->getId());
array_push($nodeIdsArray, $nodeId);
$this->cachedShareTypes[$nodeId] = [];

// Initialize share types array for this node in case there would be no shares for this node
$initShareTypes[$nodeId] = [];
}

// Cache share-types obtaining them from DB
$this->getNodesShareTypes($nodeIdsArray);
// Get all shares for specified nodes obtaining them from DB
$returnedShares = $this->getSharesForNodeIds($nodeIdsArray);

// Convert to hash map and cache so that $propFind->handle() can use it
$this->cachedShareTypes = $this->convertToHashMap($returnedShares, $initShareTypes);
}

$propFind->handle(self::SHARETYPES_PROPERTYNAME, function() use ($sabreNode) {
$shareTypesHash = [];
if (isset($this->cachedShareTypes[$sabreNode->getId()])) {
// Share types in cache for this node
$shareTypesHash = $this->cachedShareTypes[$sabreNode->getId()];
} else {
// Share types for this node not in cache, obtain if any
$nodeId = $this->userFolder->get($sabreNode->getPath())->getId();
$this->cachedShareTypes[$nodeId] = [];
$this->getNodesShareTypes([$nodeId]);
$shareTypesHash = $this->cachedShareTypes[$nodeId];
$returnedShares = $this->getSharesForNodeIds([$nodeId]);

// Initialize share types for this node and obtain share types hash if any
$initShareTypes[$nodeId] = [];
$shareTypesHash = $this->convertToHashMap($returnedShares, $initShareTypes)[$nodeId];
}
$shareTypes = array_keys($shareTypesHash);

Expand Down
74 changes: 39 additions & 35 deletions apps/federatedfilesharing/lib/FederatedShareProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -566,50 +566,54 @@ public function deleteFromSelf(IShare $share, $recipient) {
* @inheritdoc
*/
public function getAllSharesBy($userId, $shareTypes, $nodeIDs, $reshares) {
// In federates sharing currently we have only one share_type_remote
$shares = [];
$qb = $this->dbConnection->getQueryBuilder();
$qb->select('*')
->from('share');

$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)));
$nodeIdsChunks = array_chunk($nodeIDs, 100);
foreach ($nodeIdsChunks as $nodeIdsChunk) {
// In federates sharing currently we have only one share_type_remote
$qb->select('*')
->from('share');

/**
* Reshares for this user are shares where they are the owner.
*/
if ($reshares === false) {
//Special case for old shares created via the web UI
$or1 = $qb->expr()->andX(
$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
$qb->expr()->isNull('uid_initiator')
);
$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)));

$qb->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
$or1
)
);
} else {
$qb->andWhere(
$qb->expr()->orX(
/**
* Reshares for this user are shares where they are the owner.
*/
if ($reshares === false) {
//Special case for old shares created via the web UI
$or1 = $qb->expr()->andX(
$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
)
);
}
$qb->expr()->isNull('uid_initiator')
);

$qb->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)),
$or1
)
);
} else {
$qb->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
)
);
}

$qb->andWhere($qb->expr()->in('file_source', $qb->createParameter('file_source_ids')));
$qb->setParameter('file_source_ids', $nodeIDs, IQueryBuilder::PARAM_INT_ARRAY);
$qb->andWhere($qb->expr()->in('file_source', $qb->createParameter('file_source_ids')));
$qb->setParameter('file_source_ids', $nodeIdsChunk, IQueryBuilder::PARAM_INT_ARRAY);

$qb->orderBy('id');
$qb->orderBy('id');

$cursor = $qb->execute();
$shares = [];
while($data = $cursor->fetch()) {
$shares[] = $this->createShareObject($data);
$cursor = $qb->execute();
while($data = $cursor->fetch()) {
$shares[] = $this->createShareObject($data);
}
$cursor->closeCursor();
}
$cursor->closeCursor();


return $shares;
}

Expand Down
13 changes: 12 additions & 1 deletion apps/federatedfilesharing/tests/FederatedShareProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -529,9 +529,20 @@ public function testGetAllSharedByWithReshares() {
->setNode($node);
$this->provider->create($share2);

for($i = 0; $i < 200; $i++) {
$receiver = strval($i)."[email protected]";
$share2 = $this->shareManager->newShare();
$share2->setSharedWith(strval($receiver))
->setSharedBy('sharedBy')
->setShareOwner('shareOwner')
->setPermissions(19)
->setNode($node);
$this->provider->create($share2);
}

$shares = $this->provider->getAllSharesBy('shareOwner', [\OCP\Share::SHARE_TYPE_REMOTE], [$node->getId()], true);

$this->assertCount(2, $shares);
$this->assertCount(202, $shares);
}

public function testGetSharedBy() {
Expand Down
70 changes: 37 additions & 33 deletions lib/private/Share20/DefaultShareProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -463,48 +463,52 @@ public function move(\OCP\Share\IShare $share, $recipient) {
* @inheritdoc
*/
public function getAllSharesBy($userId, $shareTypes, $nodeIDs, $reshares) {
$shares = [];
$qb = $this->dbConn->getQueryBuilder();
$qb->select('*')
->from('share')
->andWhere($qb->expr()->orX(
$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
));

$orX = $qb->expr()->orX();
$nodeIdsChunks = array_chunk($nodeIDs, 100);
foreach ($nodeIdsChunks as $nodeIdsChunk) {
$qb->select('*')
->from('share')
->andWhere($qb->expr()->orX(
$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
));

foreach ($shareTypes as $shareType) {
$orX->add($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType)));
}
$orX = $qb->expr()->orX();

$qb->andWhere($orX);
foreach ($shareTypes as $shareType) {
$orX->add($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType)));
}

/**
* Reshares for this user are shares where they are the owner.
*/
if ($reshares === false) {
$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
} else {
$qb->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
)
);
}
$qb->andWhere($orX);

$qb->andWhere($qb->expr()->in('file_source', $qb->createParameter('file_source_ids')));
$qb->setParameter('file_source_ids', $nodeIDs, IQueryBuilder::PARAM_INT_ARRAY);
/**
* Reshares for this user are shares where they are the owner.
*/
if ($reshares === false) {
$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
} else {
$qb->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
)
);
}

$qb->orderBy('id');
$qb->andWhere($qb->expr()->in('file_source', $qb->createParameter('file_source_ids')));
$qb->setParameter('file_source_ids', $nodeIdsChunk, IQueryBuilder::PARAM_INT_ARRAY);

$cursor = $qb->execute();
$shares = [];
while($data = $cursor->fetch()) {
$shares[] = $this->createShare($data);
}
$cursor->closeCursor();
$qb->orderBy('id');

$cursor = $qb->execute();
while($data = $cursor->fetch()) {
$shares[] = $this->createShare($data);
}
$cursor->closeCursor();
}

return $shares;
}

Expand Down
40 changes: 14 additions & 26 deletions lib/private/Share20/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -900,40 +900,28 @@ public function getAllSharesBy($userId, $shareTypes, $nodeIDs, $reshares = false
array_push($providerIdMap[$providerId], $shareType);
}

$today = new \DateTime();
foreach ($providerIdMap as $providerId => $shareTypeArray) {
// Get provider from cache
$provider = $this->factory->getProvider($providerId);

// Batch Node IDs into chunks of 100 and get all shares for these nodes
$batchNodeIDs = array_chunk($nodeIDs, 100);
foreach ($batchNodeIDs as $nodeIDsChunk) {
$queriedShares = $provider->getAllSharesBy($userId, $shareTypeArray, $nodeIDsChunk, $reshares);
foreach ($queriedShares as $queriedShare){
array_push($shares, $queriedShare);
}
}

}

// Ensure to delete expired shares. Please note that here $node is obligatory and we will receive only shares belonging to one node
$shares2 = [];
$today = new \DateTime();
foreach ($shares as $share) {
// Check if the share is expired and if so delete it
if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK && $share->getExpirationDate() !== null &&
$share->getExpirationDate() <= $today
) {
try {
$this->deleteShare($share);
} catch (NotFoundException $e) {
//Ignore since this basically means the share is deleted
$queriedShares = $provider->getAllSharesBy($userId, $shareTypeArray, $nodeIDs, $reshares);
foreach ($queriedShares as $queriedShare){
if ($queriedShare->getShareType() === \OCP\Share::SHARE_TYPE_LINK && $queriedShare->getExpirationDate() !== null &&
$queriedShare->getExpirationDate() <= $today
) {
try {
$this->deleteShare($queriedShare);
} catch (NotFoundException $e) {
//Ignore since this basically means the share is deleted
}
continue;
}
continue;
array_push($shares, $queriedShare);
}
$shares2[] = $share;
}

return $shares2;
return $shares;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/public/Share/IManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public function deleteFromSelf(IShare $share, $recipientId);
public function moveShare(IShare $share, $recipientId);

/**
* Get shares shared by (initiated) by the provided user.
* Get all shares shared by (initiated) by the provided user for specific node IDs.
*
* @param string $userId
* @param int[] $shareTypes
Expand Down
18 changes: 17 additions & 1 deletion tests/lib/Share20/DefaultShareProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1225,13 +1225,29 @@ public function testGetAllSharesByNodes() {
]);
$this->assertEquals(1, $qb->execute());

for($i = 0; $i < 200; $i++) {
$receiver = strval($i)."sharedWith";
$qb->insert('share')
->values([
'share_type' => $qb->expr()->literal(Share::SHARE_TYPE_USER),
'share_with' => $qb->expr()->literal($receiver),
'uid_owner' => $qb->expr()->literal('shareOwner'),
'uid_initiator' => $qb->expr()->literal('sharedBy'),
'item_type' => $qb->expr()->literal('file'),
'file_source' => $qb->expr()->literal(42),
'file_target' => $qb->expr()->literal('myTarget'),
'permissions' => $qb->expr()->literal(13),
]);
$this->assertEquals(1, $qb->execute());
}

$file = $this->createMock(File::class);
$file->method('getId')->willReturn(42);
$this->rootFolder->method('getUserFolder')->with('shareOwner')->will($this->returnSelf());
$this->rootFolder->method('getById')->with(42)->willReturn([$file]);

$share = $this->provider->getAllSharesBy('sharedBy', [Share::SHARE_TYPE_USER], [$file->getId()], false);
$this->assertCount(1, $share);
$this->assertCount(201, $share);

/** @var Share\IShare $share */
$share = $share[0];
Expand Down
Loading

0 comments on commit 331b82e

Please sign in to comment.