Skip to content

Only share to users and groups when necessary#389

Merged
lukasdotcom merged 2 commits intomainfrom
better-sharing
Mar 16, 2026
Merged

Only share to users and groups when necessary#389
lukasdotcom merged 2 commits intomainfrom
better-sharing

Conversation

@lukasdotcom
Copy link
Copy Markdown
Member

Different method than #52 that gets all users that have access to a file first and then updates the shares based on that. Thanks @SystemKeeper

Signed-off-by: Lukas Schaefer <lukas@lschaefer.xyz>
Comment on lines +579 to +587
$success = true;
foreach ($groupMembersThatNeedAccess as $groupMemberId) {
if (!$this->utilsService->createShare($node, IShare::TYPE_USER, $groupMemberId, $fileOwner, $label)) {
$success = false;
}
}
if ($success) {
$createdShares[] = $approver;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not make sense to me. If one group member fails, all are failed?
But I also checked, the return value of shareWithApprovers is never used, can we get rid of it entirely?

Copy link
Copy Markdown
Member Author

@lukasdotcom lukasdotcom Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just removed createdShares as it is not needed anyway

Copy link
Copy Markdown
Member

@julien-nc julien-nc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If some people already have access, we don't create a group share but user shares. But then, if a user is added to the "approver" group, this user won't have access to the file that they are allowed to approve.

Not sure how to deal with that limitation but it's worth mentioning it in the README. Wdyt?

@lukasdotcom
Copy link
Copy Markdown
Member Author

If some people already have access, we don't create a group share but user shares. But then, if a user is added to the "approver" group, this user won't have access to the file that they are allowed to approve.

Not sure how to deal with that limitation but it's worth mentioning it in the README. Wdyt?

It seems like a lot of users wanted the behavior with sharing with individuals instead when it makes sense, but mentioning it in the README is a good idea.

@lukasdotcom lukasdotcom force-pushed the better-sharing branch 3 times, most recently from 9ab7288 to 698cbcd Compare March 13, 2026 17:17
…overs

Signed-off-by: Lukas Schaefer <lukas@lschaefer.xyz>
@SystemKeeper
Copy link
Copy Markdown
Contributor

I agree, mentioning it in the README totally makes sense.

I can't really judge how the app is used, I totally can see use cases that would require one or the other. Besides listening on group changes and checking access, the only other idea would be to still create a group share and for those who already have access, to leave the share (if I understand it correctly for that USERGROUP share permission is set to 0). That would prevent double shares and new users would still gain access (which then could be result in a double share for that new user).

Is it better? No idea.

@julien-nc julien-nc self-requested a review March 13, 2026 17:24
Copy link
Copy Markdown
Member

@julien-nc julien-nc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lgtm 👍

@SystemKeeper
Copy link
Copy Markdown
Contributor

Did the following test:

  • Have a group with 100 users
  • Group has access to the files via groupfolders

Before this PR on the first (createShares = true) request
2872 queries done

After this PR on the first (createShares = true) request
160 queries done

The second request (createShares = false) is still quite heavy, I think this is coming from

public function sendRequestNotification(int $fileId, array $rule, string $requestUserId, bool $checkAccess): void {
// find users involved in rules matching tags
$rulesUserIds = [];
$thisRuleUserIds = $this->getRuleAuthorizedUserIds($rule, 'approvers');
foreach ($thisRuleUserIds as $userId) {
if (!in_array($userId, $rulesUserIds, true)) {
$rulesUserIds[] = $userId;
}
}
// create activity (which deals with access checks)
$this->activityManager->triggerEvent(
ActivityManager::APPROVAL_OBJECT_NODE, $fileId,
ActivityManager::SUBJECT_MANUALLY_REQUESTED,
['users' => $thisRuleUserIds, 'who' => $requestUserId]
);
$paramsByUser = [];
$root = $this->root;
if ($checkAccess) {
// only notify users having access to the file
foreach ($rulesUserIds as $userId) {
$userFolder = $root->getUserFolder($userId);
$node = $userFolder->getFirstNodeById($fileId);
if ($node !== null) {
$path = $userFolder->getRelativePath($node->getPath());
$type = $node->getType() === FileInfo::TYPE_FILE
? 'file'
: 'folder';
$paramsByUser[$userId] = [
'type' => $type,
'fileId' => $fileId,
'fileName' => $node->getName(),
'relativePath' => $path,
];
}
}
} else {
// we don't check if users have access to the file because they might not have yet (share is not effective yet)
// => notify every approver
foreach ($rulesUserIds as $userId) {
$node = $root->getFirstNodeById($fileId);
if ($node !== null) {
// we don't know the path in user storage
$path = '';
$type = $node->getType() === FileInfo::TYPE_FILE
? 'file'
: 'folder';
$paramsByUser[$userId] = [
'type' => $type,
'fileId' => $fileId,
'fileName' => $node->getName(),
'relativePath' => $path,
];
}
}
}

Maybe we could do a similar thing there.

Otherwise from what I can judge, looks good to me.

@lukasdotcom
Copy link
Copy Markdown
Member Author

Did the following test:

* Have a group with 100 users

* Group has access to the files via groupfolders

Before this PR on the first (createShares = true) request 2872 queries done

After this PR on the first (createShares = true) request 160 queries done

The second request (createShares = false) is still quite heavy, I think this is coming from

public function sendRequestNotification(int $fileId, array $rule, string $requestUserId, bool $checkAccess): void {
// find users involved in rules matching tags
$rulesUserIds = [];
$thisRuleUserIds = $this->getRuleAuthorizedUserIds($rule, 'approvers');
foreach ($thisRuleUserIds as $userId) {
if (!in_array($userId, $rulesUserIds, true)) {
$rulesUserIds[] = $userId;
}
}
// create activity (which deals with access checks)
$this->activityManager->triggerEvent(
ActivityManager::APPROVAL_OBJECT_NODE, $fileId,
ActivityManager::SUBJECT_MANUALLY_REQUESTED,
['users' => $thisRuleUserIds, 'who' => $requestUserId]
);
$paramsByUser = [];
$root = $this->root;
if ($checkAccess) {
// only notify users having access to the file
foreach ($rulesUserIds as $userId) {
$userFolder = $root->getUserFolder($userId);
$node = $userFolder->getFirstNodeById($fileId);
if ($node !== null) {
$path = $userFolder->getRelativePath($node->getPath());
$type = $node->getType() === FileInfo::TYPE_FILE
? 'file'
: 'folder';
$paramsByUser[$userId] = [
'type' => $type,
'fileId' => $fileId,
'fileName' => $node->getName(),
'relativePath' => $path,
];
}
}
} else {
// we don't check if users have access to the file because they might not have yet (share is not effective yet)
// => notify every approver
foreach ($rulesUserIds as $userId) {
$node = $root->getFirstNodeById($fileId);
if ($node !== null) {
// we don't know the path in user storage
$path = '';
$type = $node->getType() === FileInfo::TYPE_FILE
? 'file'
: 'folder';
$paramsByUser[$userId] = [
'type' => $type,
'fileId' => $fileId,
'fileName' => $node->getName(),
'relativePath' => $path,
];
}
}
}

Maybe we could do a similar thing there.

Otherwise from what I can judge, looks good to me.

Did the following test:

* Have a group with 100 users

* Group has access to the files via groupfolders

Before this PR on the first (createShares = true) request 2872 queries done

After this PR on the first (createShares = true) request 160 queries done

The second request (createShares = false) is still quite heavy, I think this is coming from

public function sendRequestNotification(int $fileId, array $rule, string $requestUserId, bool $checkAccess): void {
// find users involved in rules matching tags
$rulesUserIds = [];
$thisRuleUserIds = $this->getRuleAuthorizedUserIds($rule, 'approvers');
foreach ($thisRuleUserIds as $userId) {
if (!in_array($userId, $rulesUserIds, true)) {
$rulesUserIds[] = $userId;
}
}
// create activity (which deals with access checks)
$this->activityManager->triggerEvent(
ActivityManager::APPROVAL_OBJECT_NODE, $fileId,
ActivityManager::SUBJECT_MANUALLY_REQUESTED,
['users' => $thisRuleUserIds, 'who' => $requestUserId]
);
$paramsByUser = [];
$root = $this->root;
if ($checkAccess) {
// only notify users having access to the file
foreach ($rulesUserIds as $userId) {
$userFolder = $root->getUserFolder($userId);
$node = $userFolder->getFirstNodeById($fileId);
if ($node !== null) {
$path = $userFolder->getRelativePath($node->getPath());
$type = $node->getType() === FileInfo::TYPE_FILE
? 'file'
: 'folder';
$paramsByUser[$userId] = [
'type' => $type,
'fileId' => $fileId,
'fileName' => $node->getName(),
'relativePath' => $path,
];
}
}
} else {
// we don't check if users have access to the file because they might not have yet (share is not effective yet)
// => notify every approver
foreach ($rulesUserIds as $userId) {
$node = $root->getFirstNodeById($fileId);
if ($node !== null) {
// we don't know the path in user storage
$path = '';
$type = $node->getType() === FileInfo::TYPE_FILE
? 'file'
: 'folder';
$paramsByUser[$userId] = [
'type' => $type,
'fileId' => $fileId,
'fileName' => $node->getName(),
'relativePath' => $path,
];
}
}
}

Maybe we could do a similar thing there.

Otherwise from what I can judge, looks good to me.

I'll look at that in a new pr.

@lukasdotcom lukasdotcom merged commit 7238f9d into main Mar 16, 2026
41 checks passed
@lukasdotcom lukasdotcom deleted the better-sharing branch March 16, 2026 14:45
@lukasdotcom
Copy link
Copy Markdown
Member Author

/backport to stable32

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants