Merge pull request #680 from taigaio/issue/4032/change_privacity_validation_error
Fix issue #4032: Wrong validation when change the project privacityremotes/origin/issue/4795/notification_even_they_are_disabled
commit
28efb6dd68
|
@ -94,7 +94,7 @@ class ProjectImporterViewSet(mixins.ImportThrottlingPolicyMixin, CreateModelMixi
|
|||
is_private = data.get('is_private', False)
|
||||
(enough_slots, not_enough_slots_error) = users_service.has_available_slot_for_project(
|
||||
self.request.user,
|
||||
project=Project(is_private=is_private, id=None)
|
||||
Project(is_private=is_private, id=None)
|
||||
)
|
||||
if not enough_slots:
|
||||
raise exc.NotEnoughSlotsForProject(is_private, 1, not_enough_slots_error)
|
||||
|
@ -115,11 +115,11 @@ class ProjectImporterViewSet(mixins.ImportThrottlingPolicyMixin, CreateModelMixi
|
|||
|
||||
# Create memberships
|
||||
if "memberships" in data:
|
||||
members = len(data['memberships'])
|
||||
members = len([m for m in data.get("memberships", []) if m.get("email", None) != data["owner"]])
|
||||
(enough_slots, not_enough_slots_error) = users_service.has_available_slot_for_project(
|
||||
self.request.user,
|
||||
project=Project(is_private=is_private, id=None),
|
||||
members=max(members, 1)
|
||||
Project(is_private=is_private, id=None),
|
||||
members
|
||||
)
|
||||
if not enough_slots:
|
||||
raise exc.NotEnoughSlotsForProject(is_private, max(members, 1), not_enough_slots_error)
|
||||
|
@ -223,16 +223,18 @@ class ProjectImporterViewSet(mixins.ImportThrottlingPolicyMixin, CreateModelMixi
|
|||
except Exception:
|
||||
raise exc.WrongArguments(_("Invalid dump format"))
|
||||
|
||||
user = request.user
|
||||
slug = dump.get('slug', None)
|
||||
if slug is not None and Project.objects.filter(slug=slug).exists():
|
||||
del dump['slug']
|
||||
|
||||
members = len(dump.get("memberships", []))
|
||||
user = request.user
|
||||
dump['owner'] = user.email
|
||||
|
||||
members = len([m for m in dump.get("memberships", []) if m.get("email", None) != dump["owner"]])
|
||||
(enough_slots, not_enough_slots_error) = users_service.has_available_slot_for_project(
|
||||
user,
|
||||
project=Project(is_private=is_private, id=None),
|
||||
members=max(members, 1)
|
||||
Project(is_private=is_private, id=None),
|
||||
members
|
||||
)
|
||||
if not enough_slots:
|
||||
raise exc.NotEnoughSlotsForProject(is_private, max(members, 1), not_enough_slots_error)
|
||||
|
|
|
@ -91,11 +91,11 @@ def store_tags_colors(project, data):
|
|||
def dict_to_project(data, owner=None):
|
||||
if owner:
|
||||
data["owner"] = owner.email
|
||||
members = len(data.get("memberships", []))
|
||||
members = len([m for m in data.get("memberships", []) if m.get("email", None) != data["owner"]])
|
||||
(enough_slots, not_enough_slots_error) = users_service.has_available_slot_for_project(
|
||||
owner,
|
||||
project=Project(is_private=data.get("is_private", False), id=None),
|
||||
members=members
|
||||
Project(is_private=data.get("is_private", False), id=None),
|
||||
members
|
||||
)
|
||||
if not enough_slots:
|
||||
raise TaigaImportError(not_enough_slots_error)
|
||||
|
|
|
@ -380,8 +380,7 @@ class ProjectViewSet(LikedResourceMixin, HistoryResourceMixin,
|
|||
|
||||
(enough_slots, not_enough_slots_error) = users_service.has_available_slot_for_project(
|
||||
request.user,
|
||||
project=project,
|
||||
members=0
|
||||
project,
|
||||
)
|
||||
if not enough_slots:
|
||||
members = project.memberships.count()
|
||||
|
@ -419,16 +418,17 @@ class ProjectViewSet(LikedResourceMixin, HistoryResourceMixin,
|
|||
permissions_service.set_base_permissions_for_project(obj)
|
||||
|
||||
def pre_save(self, obj):
|
||||
user = self.request.user
|
||||
(enough_slots, not_enough_slots_error) = users_service.has_available_slot_for_project(user, project=obj)
|
||||
members = max(obj.memberships.count(), 1)
|
||||
if not enough_slots:
|
||||
raise exc.NotEnoughSlotsForProject(obj.is_private, members, not_enough_slots_error)
|
||||
|
||||
if not obj.id:
|
||||
obj.owner = user
|
||||
obj.owner = self.request.user
|
||||
obj.template = self.request.QUERY_PARAMS.get('template', None)
|
||||
|
||||
# Validate if the owner have enought slots to create or update the project
|
||||
# TODO: Move to the ProjectAdminSerializer
|
||||
(enough_slots, not_enough_slots_error) = users_service.has_available_slot_for_project(obj.owner, obj)
|
||||
if not enough_slots:
|
||||
members = max(obj.memberships.count(), 1)
|
||||
raise exc.NotEnoughSlotsForProject(obj.is_private, members, not_enough_slots_error)
|
||||
|
||||
self._set_base_permissions(obj)
|
||||
super().pre_save(obj)
|
||||
|
||||
|
@ -635,8 +635,8 @@ class MembershipViewSet(BlockedByProjectMixin, ModelCrudViewSet):
|
|||
members = len(data["bulk_memberships"])
|
||||
(enough_slots, not_enough_slots_error) = users_service.has_available_slot_for_project(
|
||||
project.owner,
|
||||
project=project,
|
||||
members=members
|
||||
project,
|
||||
members
|
||||
)
|
||||
if not enough_slots:
|
||||
raise exc.NotEnoughSlotsForProject(project.is_private, members, not_enough_slots_error)
|
||||
|
@ -672,8 +672,8 @@ class MembershipViewSet(BlockedByProjectMixin, ModelCrudViewSet):
|
|||
members = 1
|
||||
(enough_slots, not_enough_slots_error) = users_service.has_available_slot_for_project(
|
||||
self.request.user,
|
||||
project=obj.project,
|
||||
members=members
|
||||
obj.project,
|
||||
members
|
||||
)
|
||||
if not enough_slots:
|
||||
raise exc.NotEnoughSlotsForProject(obj.project.is_private, members, not_enough_slots_error)
|
||||
|
|
|
@ -575,41 +575,60 @@ def get_voted_list(for_user, from_user, type=None, q=None):
|
|||
]
|
||||
|
||||
|
||||
def has_available_slot_for_project(user, project, members=1):
|
||||
def has_available_slot_for_project(user, project, new_members=0):
|
||||
# TODO: Refactor: Create one service for every type of action and move to project services
|
||||
#
|
||||
# - has_available_slot_to_create_new_project()
|
||||
# - has_available_slot_to_update_this_project()
|
||||
# - has_available_slot_to_transfer_this_project()
|
||||
# - has_available_slot_to_import_this_project()
|
||||
# - has_available_slot_to_add_members_to_this_project()
|
||||
|
||||
(enough, error) = _has_available_slot_for_project_type(user, project)
|
||||
if not enough:
|
||||
return (enough, error)
|
||||
return _has_available_slot_for_project_members(user, project, members)
|
||||
return _has_available_slot_for_project_members(user, project, new_members)
|
||||
|
||||
|
||||
def _has_available_slot_for_project_type(user, project):
|
||||
if project.is_private:
|
||||
if user.max_private_projects is None:
|
||||
return (True, None)
|
||||
elif user.owned_projects.filter(is_private=True).exclude(id=project.id).count() < user.max_private_projects:
|
||||
|
||||
current_private_projects = user.owned_projects.filter(is_private=True).exclude(id=project.id).count()
|
||||
if current_private_projects < user.max_private_projects:
|
||||
return (True, None)
|
||||
|
||||
return (False, _("You can't have more private projects"))
|
||||
|
||||
else:
|
||||
if user.max_public_projects is None:
|
||||
return (True, None)
|
||||
elif user.owned_projects.filter(is_private=False).exclude(id=project.id).count() < user.max_public_projects:
|
||||
|
||||
current_public_project = user.owned_projects.filter(is_private=False).exclude(id=project.id).count()
|
||||
if current_public_project < user.max_public_projects:
|
||||
return (True, None)
|
||||
|
||||
return (False, _("You can't have more public projects"))
|
||||
|
||||
|
||||
|
||||
def _has_available_slot_for_project_members(user, project, members):
|
||||
current_memberships = project.memberships.count()
|
||||
def _has_available_slot_for_project_members(user, project, new_members):
|
||||
current_memberships = max(project.memberships.count(), 1)
|
||||
|
||||
if project.is_private:
|
||||
if user.max_memberships_private_projects is None:
|
||||
return (True, None)
|
||||
elif current_memberships + members <= user.max_memberships_private_projects:
|
||||
|
||||
if current_memberships + new_members <= user.max_memberships_private_projects:
|
||||
return (True, None)
|
||||
|
||||
return (False, _("You have reached your current limit of memberships for private projects"))
|
||||
|
||||
else:
|
||||
if user.max_memberships_public_projects is None:
|
||||
return (True, None)
|
||||
elif current_memberships + members <= user.max_memberships_public_projects:
|
||||
|
||||
if current_memberships + new_members <= user.max_memberships_public_projects:
|
||||
return (True, None)
|
||||
|
||||
return (False, _("You have reached your current limit of memberships for public projects"))
|
||||
|
|
|
@ -1501,3 +1501,87 @@ def test_valid_dump_import_without_slug(client):
|
|||
|
||||
response = client.post(url, {'dump': data})
|
||||
assert response.status_code == 201
|
||||
|
||||
|
||||
def test_valid_dump_import_with_the_limit_of_membership_whit_you_for_private_project(client):
|
||||
user = f.UserFactory.create(max_memberships_private_projects=5)
|
||||
client.login(user)
|
||||
|
||||
url = reverse("importer-load-dump")
|
||||
|
||||
data = ContentFile(bytes(json.dumps({
|
||||
"slug": "private-project-with-memberships-limit-with-you",
|
||||
"name": "Valid project",
|
||||
"description": "Valid project desc",
|
||||
"is_private": True,
|
||||
"memberships": [
|
||||
{
|
||||
"email": user.email,
|
||||
"role": "Role",
|
||||
},
|
||||
{
|
||||
"email": "test2@test.com",
|
||||
"role": "Role",
|
||||
},
|
||||
{
|
||||
"email": "test3@test.com",
|
||||
"role": "Role",
|
||||
},
|
||||
{
|
||||
"email": "test4@test.com",
|
||||
"role": "Role",
|
||||
},
|
||||
{
|
||||
"email": "test5@test.com",
|
||||
"role": "Role",
|
||||
},
|
||||
],
|
||||
"roles": [{"name": "Role"}]
|
||||
}), "utf-8"))
|
||||
data.name = "test"
|
||||
|
||||
response = client.post(url, {'dump': data})
|
||||
assert response.status_code == 201
|
||||
assert Project.objects.filter(slug="private-project-with-memberships-limit-with-you").count() == 1
|
||||
|
||||
|
||||
def test_valid_dump_import_with_the_limit_of_membership_whit_you_for_public_project(client):
|
||||
user = f.UserFactory.create(max_memberships_public_projects=5)
|
||||
client.login(user)
|
||||
|
||||
url = reverse("importer-load-dump")
|
||||
|
||||
data = ContentFile(bytes(json.dumps({
|
||||
"slug": "public-project-with-memberships-limit-with-you",
|
||||
"name": "Valid project",
|
||||
"description": "Valid project desc",
|
||||
"is_private": False,
|
||||
"memberships": [
|
||||
{
|
||||
"email": user.email,
|
||||
"role": "Role",
|
||||
},
|
||||
{
|
||||
"email": "test2@test.com",
|
||||
"role": "Role",
|
||||
},
|
||||
{
|
||||
"email": "test3@test.com",
|
||||
"role": "Role",
|
||||
},
|
||||
{
|
||||
"email": "test4@test.com",
|
||||
"role": "Role",
|
||||
},
|
||||
{
|
||||
"email": "test5@test.com",
|
||||
"role": "Role",
|
||||
},
|
||||
],
|
||||
"roles": [{"name": "Role"}]
|
||||
}), "utf-8"))
|
||||
data.name = "test"
|
||||
|
||||
response = client.post(url, {'dump': data})
|
||||
assert response.status_code == 201
|
||||
assert Project.objects.filter(slug="public-project-with-memberships-limit-with-you").count() == 1
|
||||
|
|
Loading…
Reference in New Issue