diff --git a/taiga/projects/serializers.py b/taiga/projects/serializers.py index 95f05703..661aeece 100644 --- a/taiga/projects/serializers.py +++ b/taiga/projects/serializers.py @@ -344,6 +344,7 @@ class ProjectDetailSerializer(ProjectSerializer): roles = ProjectRoleSerializer(source="roles", many=True, read_only=True) members = serializers.SerializerMethodField(method_name="get_members") total_memberships = serializers.SerializerMethodField(method_name="get_total_memberships") + is_out_of_owner_limits = serializers.SerializerMethodField(method_name="get_is_out_of_owner_limits") def get_members(self, obj): qs = obj.memberships.filter(user__isnull=False) @@ -356,6 +357,9 @@ class ProjectDetailSerializer(ProjectSerializer): def get_total_memberships(self, obj): return services.get_total_project_memberships(obj) + def get_is_out_of_owner_limits(self, obj): + return services.check_if_project_is_out_of_owner_limits(obj) + class ProjectDetailAdminSerializer(ProjectDetailSerializer): is_private_extra_info = serializers.SerializerMethodField(method_name="get_is_private_extra_info") diff --git a/taiga/projects/services/__init__.py b/taiga/projects/services/__init__.py index d813423d..23d6334c 100644 --- a/taiga/projects/services/__init__.py +++ b/taiga/projects/services/__init__.py @@ -46,6 +46,7 @@ from .modules_config import get_modules_config from .projects import check_if_project_privacity_can_be_changed from .projects import check_if_project_can_be_created_or_updated from .projects import check_if_project_can_be_transfered +from .projects import check_if_project_is_out_of_owner_limits from .stats import get_stats_for_project_issues from .stats import get_stats_for_project diff --git a/taiga/projects/services/projects.py b/taiga/projects/services/projects.py index 306c585f..1ac6d2b7 100644 --- a/taiga/projects/services/projects.py +++ b/taiga/projects/services/projects.py @@ -124,3 +124,30 @@ def check_if_project_can_be_transfered(project, new_owner): return (False, error_memberships_exceeded) return (True, None) + + +def check_if_project_is_out_of_owner_limits(project): + """Return if the project fits on its owner limits. + + :param project: A project object. + + :return: bool + """ + if project.is_private: + current_memberships = project.memberships.count() + max_memberships = project.owner.max_memberships_private_projects + current_projects = project.owner.owned_projects.filter(is_private=True).count() + max_projects = project.owner.max_private_projects + else: + current_memberships = project.memberships.count() + max_memberships = project.owner.max_memberships_public_projects + current_projects = project.owner.owned_projects.filter(is_private=False).count() + max_projects = project.owner.max_public_projects + + if max_memberships is not None and current_memberships > max_memberships: + return True + + if max_projects is not None and current_projects > max_projects: + return True + + return False diff --git a/tests/integration/test_projects.py b/tests/integration/test_projects.py index 14a8c7f4..6111747b 100644 --- a/tests/integration/test_projects.py +++ b/tests/integration/test_projects.py @@ -1624,3 +1624,193 @@ def test_public_project_can_be_private_because_project_has_unlimited_members(cli project.owner.max_memberships_private_projects = None assert (check_if_project_privacity_can_be_changed(project) == {'can_be_updated': True, 'reason': None}) + + +#################################################################################### +# Test taiga.projects.services.projects.check_if_project_is_out_of_owner_limit +#################################################################################### + +from taiga.projects.services.projects import check_if_project_is_out_of_owner_limits + +def test_private_project_when_owner_doesnt_have_enought_slot_and_too_much_members(client): + project = f.create_project(is_private=True) + f.MembershipFactory(project=project, user=project.owner) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + + project.owner.max_private_projects = 0 + project.owner.max_memberships_private_projects = 3 + + assert check_if_project_is_out_of_owner_limits(project) == True + + +def test_private_project_when_owner_doesnt_have_enought_slot(client): + project = f.create_project(is_private=True) + f.MembershipFactory(project=project, user=project.owner) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + + project.owner.max_private_projects = 0 + project.owner.max_memberships_private_projects = 6 + + assert check_if_project_is_out_of_owner_limits(project) == True + + +def test_private_project_when_too_much_members(client): + project = f.create_project(is_private=True) + f.MembershipFactory(project=project, user=project.owner) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + + project.owner.max_private_projects = 2 + project.owner.max_memberships_private_projects = 3 + + assert check_if_project_is_out_of_owner_limits(project) == True + + +def test_private_project_when_owner_has_enought_slot_and_project_has_enought_members(client): + project = f.create_project(is_private=True) + f.MembershipFactory(project=project, user=project.owner) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + + project.owner.max_private_projects = 2 + project.owner.max_memberships_private_projects = 6 + + assert check_if_project_is_out_of_owner_limits(project) == False + + +def test_private_project_when_owner_has_unlimited_slot_and_project_has_unlimited_members(client): + project = f.create_project(is_private=True) + f.MembershipFactory(project=project, user=project.owner) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + + project.owner.max_private_projects = None + project.owner.max_memberships_private_projects = None + + assert check_if_project_is_out_of_owner_limits(project) == False + + +def test_private_project_when_owner_has_unlimited_slot(client): + project = f.create_project(is_private=True) + f.MembershipFactory(project=project, user=project.owner) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + + project.owner.max_private_projects = None + project.owner.max_memberships_private_projects = 6 + + assert check_if_project_is_out_of_owner_limits(project) == False + + +def test_private_project_when_project_has_unlimited_members(client): + project = f.create_project(is_private=True) + f.MembershipFactory(project=project, user=project.owner) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + + project.owner.max_private_projects = 2 + project.owner.max_memberships_private_projects = None + + assert check_if_project_is_out_of_owner_limits(project) == False + + +# public + +def test_public_project_when_owner_doesnt_have_enought_slot_and_too_much_members(client): + project = f.create_project(is_private=False) + f.MembershipFactory(project=project, user=project.owner) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + + project.owner.max_public_projects = 0 + project.owner.max_memberships_public_projects = 3 + + assert check_if_project_is_out_of_owner_limits(project) == True + + +def test_public_project_when_owner_doesnt_have_enought_slot(client): + project = f.create_project(is_private=False) + f.MembershipFactory(project=project, user=project.owner) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + + project.owner.max_public_projects = 0 + project.owner.max_memberships_public_projects = 6 + + assert check_if_project_is_out_of_owner_limits(project) == True + + +def test_public_project_when_too_much_members(client): + project = f.create_project(is_private=False) + f.MembershipFactory(project=project, user=project.owner) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + + project.owner.max_public_projects = 2 + project.owner.max_memberships_public_projects = 3 + + assert check_if_project_is_out_of_owner_limits(project) == True + + +def test_public_project_when_owner_has_enought_slot_and_project_has_enought_members(client): + project = f.create_project(is_private=False) + f.MembershipFactory(project=project, user=project.owner) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + + project.owner.max_public_projects = 2 + project.owner.max_memberships_public_projects = 6 + + assert check_if_project_is_out_of_owner_limits(project) == False + + +def test_public_project_when_owner_has_unlimited_slot_and_project_has_unlimited_members(client): + project = f.create_project(is_private=False) + f.MembershipFactory(project=project, user=project.owner) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + + project.owner.max_public_projects = None + project.owner.max_memberships_public_projects = None + + assert check_if_project_is_out_of_owner_limits(project) == False + + +def test_public_project_when_owner_has_unlimited_slot(client): + project = f.create_project(is_private=False) + f.MembershipFactory(project=project, user=project.owner) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + + project.owner.max_public_projects = None + project.owner.max_memberships_public_projects = 6 + + assert check_if_project_is_out_of_owner_limits(project) == False + + +def test_public_project_when_project_has_unlimited_members(client): + project = f.create_project(is_private=False) + f.MembershipFactory(project=project, user=project.owner) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + f.MembershipFactory(project=project) + + project.owner.max_public_projects = 2 + project.owner.max_memberships_public_projects = None + + assert check_if_project_is_out_of_owner_limits(project) == False