diff --git a/settings/common.py b/settings/common.py index c1a60956..2b41d7d8 100644 --- a/settings/common.py +++ b/settings/common.py @@ -549,6 +549,8 @@ MAX_PUBLIC_PROJECTS_PER_USER = None # None == no limit MAX_MEMBERSHIPS_PRIVATE_PROJECTS = None # None == no limit MAX_MEMBERSHIPS_PUBLIC_PROJECTS = None # None == no limit +MAX_PENDING_MEMBERSHIPS = 30 # Max number of unconfirmed memberships in a project + from .sr import * diff --git a/taiga/projects/services/members.py b/taiga/projects/services/members.py index 3cd9b514..52c62eca 100644 --- a/taiga/projects/services/members.py +++ b/taiga/projects/services/members.py @@ -20,6 +20,7 @@ from taiga.base.exceptions import ValidationError from taiga.base.utils import db, text from taiga.users.models import User +from django.conf import settings from django.core.validators import validate_email from django.utils.translation import ugettext as _ @@ -143,4 +144,8 @@ def check_if_project_can_have_more_memberships(project, total_new_memberships): if max_memberships is not None and total_memberships > max_memberships: return False, error_members_exceeded + if project.memberships.filter(user=None).count() + total_new_memberships > settings.MAX_PENDING_MEMBERSHIPS: + error_pending_memberships_exceeded = _("You have reached the current limit of pending memberships") + return False, error_pending_memberships_exceeded + return True, None diff --git a/tests/integration/test_memberships.py b/tests/integration/test_memberships.py index b9c3dc95..16d642bf 100644 --- a/tests/integration/test_memberships.py +++ b/tests/integration/test_memberships.py @@ -657,3 +657,43 @@ def test_api_delete_membership_without_user(client): response = client.json.delete(url) assert response.status_code == 204 + + +def test_api_create_member_max_pending_memberships(client, settings): + settings.MAX_PENDING_MEMBERSHIPS = 2 + project = f.ProjectFactory() + john = f.UserFactory.create() + joseph = f.UserFactory.create() + tester = f.RoleFactory(project=project, name="Tester") + f.MembershipFactory(project=project, user=john, is_admin=True) + f.MembershipFactory(project=project, user=None) + f.MembershipFactory(project=project, user=None) + + url = reverse("memberships-list") + data = {"project": project.id, "role": tester.id, "username": joseph.email} + client.login(john) + response = client.json.post(url, json.dumps(data)) + assert response.status_code == 400 + assert "limit of pending memberships" in response.data["_error_message"] + + +def test_api_create_bulk_members_max_pending_memberships(client, settings): + settings.MAX_PENDING_MEMBERSHIPS = 2 + project = f.ProjectFactory() + john = f.UserFactory.create() + joseph = f.UserFactory.create() + tester = f.RoleFactory(project=project, name="Tester") + f.MembershipFactory(project=project, user=john, is_admin=True) + f.MembershipFactory(project=project, user=None) + f.MembershipFactory(project=project, user=None) + + url = reverse("memberships-bulk-create") + data = { + "project_id": project.id, + "bulk_memberships": [ + {"role_id": tester.id, "username": "testing@taiga.io"}, + ] + } + client.login(john) + response = client.json.post(url, json.dumps(data)) + assert response.status_code == 400