Skip to content

Feature/implement default quota for groups - #2858

Open
hefftich wants to merge 5 commits into
nextcloud:masterfrom
Dataport:feature/implement_default_Quota_for_Groups
Open

Feature/implement default quota for groups#2858
hefftich wants to merge 5 commits into
nextcloud:masterfrom
Dataport:feature/implement_default_Quota_for_Groups

Conversation

@hefftich

Copy link
Copy Markdown

Summary

We need a way for admins to set default quotas for team folder creation, based on group membership. This needs a group -> quota mapping in the Teams admin settings.

Admin settings --> Teams

  • In the Team settings, admins can add entries to a table, defining default quotas for groups.
  • When a user creates a new team, the highest quota of the groups, this user is a member of, gets applied to the new Team folder.
  • At least a line for "all" is always present in the table, which is applied at team creation, when the user isn't a member of any other quota group.
  • The three-dot menu lets admins delete any mapping, despite "all".
  • The quotas only get applied at team creation. An admin can alway change the quota of existing teams later on.
group | default quota | options -- | -- | -- all | 100 MB |   marketing | 2 GB | ... sales | 10 GB | ... engineering | 5 GB | ...

Examples

  • Bob is a member in the groups marketing and engineering. He creates a new team, which gets a quota of 5 GB.
  • Alice is not a member of any groups defined in this list. Her newly created team gets a quota of 100 MB.

TODO

  • ...

Checklist

AI (if applicable)

  • The content of this PR was partly or fully generated using AI
autocreation disabled banner

@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/teams/api.ts 0.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@tomek2k1 tomek2k1 moved this from Backlog to In progress in 👥 Teams Sep 2, 2026
@tomek2k1 tomek2k1 moved this from In progress to In review in 👥 Teams Sep 2, 2026
Comment thread appinfo/info.xml
Comment thread lib/ConfigLexicon.php Outdated
@hefftich
hefftich enabled auto-merge September 2, 2026 14:08
Comment thread appinfo/info.xml
Comment thread lib/ConfigLexicon.php Outdated
Comment thread src/teams/api.ts
Comment thread lib/Service/TeamFolderPolicy.php Outdated
Comment thread lib/ConfigLexicon.php Outdated
Comment thread lib/Controller/TeamFolderController.php
Comment thread lib/Controller/AdminController.php
Comment thread lib/Service/TeamFolderPolicy.php Outdated
@hefftich hefftich self-assigned this Sep 2, 2026
@hefftich
hefftich force-pushed the feature/implement_default_Quota_for_Groups branch 12 times, most recently from 761bc23 to 7d60718 Compare September 4, 2026 08:01
@hefftich

hefftich commented Sep 4, 2026

Copy link
Copy Markdown
Author

/backport to stable35

@jospoortvliet

Copy link
Copy Markdown
Member

Hi,

I did some testing. The Team specific quota - that should be GROUP specific, so this can be managed from LDAP.

We should also add an explanation text. Maybe:

"Choose the default quote assigned to a Team folder created by users based on group membership. The default quota for a new Team folder is always the highest from the default quotas assigned to any of the groups a user is member of."

The current teas-based implementation does largely work, but there is one issue.

What I tested:

I created a 'Sales Team', then assigned 2 users to it. Then, in admin settings for Teams, assigned that team a higher default quota:

teams admin overview 2

Then I let one of those users create a new team. This shows up correctly under Teamfolders in the Teamfolders (to be Groupfolders) app, with the higher default quota:

Screenshot 2026-09-06 at 19 09 22

(it is Sales Team EMEA, which got 5GB of storage quota, as intended).

But in the Teams app, the folder created by this user does not show:
Screenshot 2026-09-06 at 19 10 34

Choosing 'add' gives a error:
Screenshot 2026-09-06 at 19 11 00

... but I guess perhaps a specific branch of the groupfolders app has to be checked out for all this to properly work.

If so, disregard the broken part. We should of course still fix the team vs group thing.

@marcoambrosini

marcoambrosini commented Sep 7, 2026

Copy link
Copy Markdown
Member

that should be GROUP specific, so this can be managed from LDAP

@jospoortvliet I think we should also allow teams here, more flexible for everyone. But agree that we need groups

for example: if you already have a "management" team, it's useful to be able to use that for trusting the members with a higher quota, instead to having to recreate that to a group. What do you think?

@jospoortvliet

Copy link
Copy Markdown
Member

that should be GROUP specific, so this can be managed from LDAP

@jospoortvliet I think we should also allow teams here, more flexible for everyone. But agree that we need groups

for example: if you already have a "management" team, it's useful to be able to use that for trusting the members with a higher quota, instead to having to recreate that to a group. What do you think?

I don't think supporting teams is a problem - for small orgs it makes sense. Big orgs will likely want this in LDAP where other policies are handled, too, so groups would be the basis I think.

@hefftich

hefftich commented Sep 7, 2026

Copy link
Copy Markdown
Author

@jospoortvliet The issue in the 3rd screenshot is a bug in the groupfolders project.
i created a pr: nextcloud/groupfolders#5086

@Fin-c

Fin-c commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

@jospoortvliet I’ve fixed the bug relating to adding folders to existing teams that don’t yet have a team space #2890

@hefftich

hefftich commented Sep 7, 2026

Copy link
Copy Markdown
Author
BOTH

@jospoortvliet @marcoambrosini I implemented your suggestion. Teams and groups can now be selected.

@hefftich
hefftich force-pushed the feature/implement_default_Quota_for_Groups branch from 0f6c8e9 to 563e2bb Compare September 7, 2026 20:00
@jospoortvliet

Copy link
Copy Markdown
Member
BOTH @jospoortvliet @marcoambrosini I implemented your suggestion. Teams and groups can now be selected.

That works for me then. @alimmroth FYI

@hefftich
hefftich force-pushed the feature/implement_default_Quota_for_Groups branch 4 times, most recently from cb7a826 to ba69061 Compare September 9, 2026 08:42
@artonge

artonge commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

/compile amend /

@cristianscheid

Copy link
Copy Markdown
Member

/compile

@artonge

artonge commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Compile bot is failing because the PR comes from a fork.
Seems like I can compile something locally, but cannot push as you did not autorised repo admin to push to your branch.
So either you autorise me, or you try again compiling locally.

Co-authored-by: Copilot <copilot@github.com> GPT-5.6 Terra
Signed-off-by: Stefan Lender <Stefan.Lender@dataport.de>
Co-authored-by: Copilot <copilot@github.com> GPT-5.6 Terra

Signed-off-by: Stefan Lender <Stefan.Lender@dataport.de>
Signed-off-by: Stefan Lender <Stefan.Lender@dataport.de>
Signed-off-by: Stefan Lender <Stefan.Lender@dataport.de>
@tomek2k1
tomek2k1 force-pushed the feature/implement_default_Quota_for_Groups branch from 81742c7 to 9a61ea4 Compare September 11, 2026 09:24
@tomek2k1

tomek2k1 commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Compile bot is failing because the PR comes from a fork. Seems like I can compile something locally, but cannot push as you did not autorised repo admin to push to your branch. So either you autorise me, or you try again compiling locally.

I rebuilt it locally. It should be good now.

Signed-off-by: Louis Chmn <louis@chmn.me>
@artonge
artonge force-pushed the feature/implement_default_Quota_for_Groups branch from 8a1f00d to 467e24d Compare September 11, 2026 10:16
$matches = $override === null ? [] : [$override];
$owner = $circle->getOwner();
if (!$owner->isLocal()) {
return $matches === [] ? $fallback : ($matches[0] ?? $fallback);

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.

Isn't this simpler and the same?

Suggested change
return $matches === [] ? $fallback : ($matches[0] ?? $fallback);
return $quota;

Comment on lines +145 to +146
$override = $this->getTeamFolderQuota($circle);
$fallback = $this->getDefaultQuota();

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.

Suggested change
$override = $this->getTeamFolderQuota($circle);
$fallback = $this->getDefaultQuota();
$quota = $this->getTeamFolderQuota($circle) ?? $this->getDefaultQuota();

Comment on lines +154 to +165
foreach ($this->membershipRequest->getMemberships($owner->getSingleId()) as $membership) {
try {
$membershipCircle = $this->circleRequest->getCircle($membership->getCircleId());
} catch (CircleNotFoundException) {
continue;
}

$quota = $this->getTeamFolderQuota($membershipCircle);
if ($quota !== null) {
$matches[] = $quota;
}
}

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 means the quota for a unrelated team impacts the quota of the current team if the current user is part of both?
Is this really what we want?

* Resolve the highest configured team or group quota for the local team owner.
* Unlimited (0) takes precedence over every finite quota.
*/
public function getQuotaForCircle(Circle $circle): int {

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.

Probably a less complex version of it:

Suggested change
public function getQuotaForCircle(Circle $circle): int {
public function getQuotaForCircle(Circle $circle): int {
$quotas = [
$this->getTeamFolderQuota($circle) ?? $this->getDefaultQuota(),
...$this->getMatchingGroupQuotas($owner->getUserId()),
]);
if (in_array(0, $matches, true)) {
return 0;
}
return max(quotas);
}

}

/** @return list<int> */
private function getMatchingGroupQuotas(string $userId): array {

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.

Suggested change
private function getMatchingGroupQuotas(string $userId): array {
private function getGroupQuotaForUser(string $userId): array {

Comment thread lib/Search/LocalUsers.php

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 should either be properly addressed in another PR, or not be part of this PR.

$teamFolders = [];
foreach ($this->circleService->getAllCircles($probe) as $circle) {
$folder = $provider->getTeamFolder($circle->getSingleId());
$folder = $provider?->getTeamFolder($circle->getSingleId());

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.

Should be ok at this point

Suggested change
$folder = $provider?->getTeamFolder($circle->getSingleId());
$folder = $provider->getTeamFolder($circle->getSingleId());

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

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

7 participants