diff --git a/settings/common.py b/settings/common.py index 87d0d904..6fd60c83 100644 --- a/settings/common.py +++ b/settings/common.py @@ -533,6 +533,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 8c9bf265..1f91e215 100644 --- a/taiga/projects/services/members.py +++ b/taiga/projects/services/members.py @@ -17,6 +17,8 @@ # along with this program. If not, see . from taiga.base.utils import db, text + +from django.conf import settings from django.utils.translation import ugettext as _ from .. import models @@ -116,7 +118,7 @@ def check_if_project_can_have_more_memberships(project, total_new_memberships): """ if project.owner is None: return False, _("Project without owner") - + if project.is_private: total_memberships = project.memberships.count() + total_new_memberships max_memberships = project.owner.max_memberships_private_projects @@ -129,4 +131,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 70d3d198..ce49f1f0 100644 --- a/tests/integration/test_memberships.py +++ b/tests/integration/test_memberships.py @@ -560,3 +560,44 @@ 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, "email": 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, "email": "testing@taiga.io"}, + ] + } + 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"]