|
19 | 19 | use OCA\Files_Sharing\SharedStorage; |
20 | 20 | use OCA\ShareByMail\ShareByMailProvider; |
21 | 21 | use OCP\Constants; |
| 22 | +use OCP\DB\QueryBuilder\IQueryBuilder; |
22 | 23 | use OCP\EventDispatcher\Event; |
23 | 24 | use OCP\EventDispatcher\IEventDispatcher; |
24 | 25 | use OCP\Files\File; |
|
32 | 33 | use OCP\IAppConfig; |
33 | 34 | use OCP\IConfig; |
34 | 35 | use OCP\IDateTimeZone; |
| 36 | +use OCP\IDBConnection; |
35 | 37 | use OCP\IGroupManager; |
36 | 38 | use OCP\IL10N; |
37 | 39 | use OCP\IUser; |
@@ -90,6 +92,7 @@ public function __construct( |
90 | 92 | private ShareDisableChecker $shareDisableChecker, |
91 | 93 | private IDateTimeZone $dateTimeZone, |
92 | 94 | private IAppConfig $appConfig, |
| 95 | + private IDBConnection $connection, |
93 | 96 | ) { |
94 | 97 | $this->l = $this->l10nFactory->get('lib'); |
95 | 98 | // The constructor of LegacyHooks registers the listeners of share events |
@@ -1039,35 +1042,76 @@ protected function promoteReshares(IShare $share): void { |
1039 | 1042 | IShare::TYPE_EMAIL, |
1040 | 1043 | ]; |
1041 | 1044 |
|
1042 | | - foreach ($userIds as $userId) { |
1043 | | - foreach ($shareTypes as $shareType) { |
| 1045 | + // Figure out which users has some shares with which providers |
| 1046 | + $qb = $this->connection->getQueryBuilder(); |
| 1047 | + $qb->select('uid_initiator', 'share_type', 'uid_owner', 'file_source') |
| 1048 | + ->from('share') |
| 1049 | + ->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY))) |
| 1050 | + ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($shareTypes, IQueryBuilder::PARAM_INT_ARRAY))) |
| 1051 | + ->andWhere( |
| 1052 | + $qb->expr()->orX( |
| 1053 | + $qb->expr()->in('uid_initiator', $qb->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)), |
| 1054 | + // Special case for old shares created via the web UI |
| 1055 | + $qb->expr()->andX( |
| 1056 | + $qb->expr()->in('uid_owner', $qb->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)), |
| 1057 | + $qb->expr()->isNull('uid_initiator') |
| 1058 | + ) |
| 1059 | + ) |
| 1060 | + ); |
| 1061 | + |
| 1062 | + if (!$node instanceof Folder) { |
| 1063 | + $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId(), IQueryBuilder::PARAM_INT))); |
| 1064 | + } |
| 1065 | + |
| 1066 | + $qb->orderBy('id'); |
| 1067 | + |
| 1068 | + $cursor = $qb->executeQuery(); |
| 1069 | + /** @var array<string, list<array{IShare::TYPE_*, Node}>> $rawShare */ |
| 1070 | + $rawShares = []; |
| 1071 | + while ($data = $cursor->fetch()) { |
| 1072 | + if (!isset($rawShares[$data['uid_initiator']])) { |
| 1073 | + $rawShares[$data['uid_initiator']] = []; |
| 1074 | + } |
| 1075 | + if (!in_array($data['share_type'], $rawShares[$data['uid_initiator']], true)) { |
| 1076 | + if ($node instanceof Folder) { |
| 1077 | + if ($data['file_source'] === null || $data['uid_owner'] === null) { |
| 1078 | + /* Ignore share of non-existing node */ |
| 1079 | + continue; |
| 1080 | + } |
| 1081 | + |
| 1082 | + // for federated shares the owner can be a remote user, in this |
| 1083 | + // case we use the initiator |
| 1084 | + if ($this->userManager->userExists($data['uid_owner'])) { |
| 1085 | + $userFolder = $this->rootFolder->getUserFolder($data['uid_owner']); |
| 1086 | + } else { |
| 1087 | + $userFolder = $this->rootFolder->getUserFolder($data['uid_initiator']); |
| 1088 | + } |
| 1089 | + $sharedNode = $userFolder->getFirstNodeById((int)$data['file_source']); |
| 1090 | + if (!$sharedNode) { |
| 1091 | + continue; |
| 1092 | + } |
| 1093 | + if ($node->getRelativePath($sharedNode->getPath()) !== null) { |
| 1094 | + $rawShares[$data['uid_initiator']][] = [(int)$data['share_type'], $sharedNode]; |
| 1095 | + } |
| 1096 | + } elseif ($node instanceof File) { |
| 1097 | + $rawShares[$data['uid_initiator']][] = [(int)$data['share_type'], $node]; |
| 1098 | + } |
| 1099 | + } |
| 1100 | + } |
| 1101 | + $cursor->closeCursor(); |
| 1102 | + |
| 1103 | + foreach ($rawShares as $userId => $shareInfos) { |
| 1104 | + foreach ($shareInfos as $shareInfo) { |
| 1105 | + [$shareType, $sharedNode] = $shareInfo; |
1044 | 1106 | try { |
1045 | 1107 | $provider = $this->factory->getProviderForType($shareType); |
1046 | | - } catch (ProviderException $e) { |
| 1108 | + } catch (ProviderException) { |
1047 | 1109 | continue; |
1048 | 1110 | } |
1049 | 1111 |
|
1050 | | - if ($node instanceof Folder) { |
1051 | | - /* We need to get all shares by this user to get subshares */ |
1052 | | - $shares = $provider->getSharesBy($userId, $shareType, null, false, -1, 0); |
1053 | | - |
1054 | | - foreach ($shares as $share) { |
1055 | | - try { |
1056 | | - $path = $share->getNode()->getPath(); |
1057 | | - } catch (NotFoundException) { |
1058 | | - /* Ignore share of non-existing node */ |
1059 | | - continue; |
1060 | | - } |
1061 | | - if ($node->getRelativePath($path) !== null) { |
1062 | | - /* If relative path is not null it means the shared node is the same or in a subfolder */ |
1063 | | - $reshareRecords[] = $share; |
1064 | | - } |
1065 | | - } |
1066 | | - } else { |
1067 | | - $shares = $provider->getSharesBy($userId, $shareType, $node, false, -1, 0); |
1068 | | - foreach ($shares as $child) { |
1069 | | - $reshareRecords[] = $child; |
1070 | | - } |
| 1112 | + $shares = $provider->getSharesBy($userId, $shareType, $sharedNode, false, -1, 0); |
| 1113 | + foreach ($shares as $child) { |
| 1114 | + $reshareRecords[] = $child; |
1071 | 1115 | } |
1072 | 1116 | } |
1073 | 1117 | } |
|
0 commit comments