diff --git a/taiga/base/filters.py b/taiga/base/filters.py index f7ea91bb..12651e6f 100644 --- a/taiga/base/filters.py +++ b/taiga/base/filters.py @@ -250,6 +250,7 @@ class MembersFilterBackend(PermissionBasedFilterBackend): if request.user.is_authenticated() and request.user.is_superuser: qs = qs elif request.user.is_authenticated(): + Membership = apps.get_model('projects', 'Membership') memberships_qs = Membership.objects.filter(user=request.user) if project_id: memberships_qs = memberships_qs.filter(project_id=project_id) diff --git a/taiga/permissions/service.py b/taiga/permissions/service.py index 75376229..3ee86821 100644 --- a/taiga/permissions/service.py +++ b/taiga/permissions/service.py @@ -103,3 +103,12 @@ def get_user_project_permissions(user, project): anon_permissions = project.anon_permissions if project.anon_permissions is not None else [] return set(owner_permissions + members_permissions + public_permissions + anon_permissions) + + +def set_base_permissions_for_public_project(project): + """ + If a project is public anonymous and registered users should have at least visualization permissions + """ + anon_permissions = list(map(lambda perm: perm[0], ANON_PERMISSIONS)) + project.anon_permissions = list(set(project.anon_permissions + anon_permissions)) + project.public_permissions = list(set(project.public_permissions + anon_permissions)) diff --git a/taiga/projects/api.py b/taiga/projects/api.py index 0f17c668..3f64ba8e 100644 --- a/taiga/projects/api.py +++ b/taiga/projects/api.py @@ -36,6 +36,7 @@ from taiga.projects.mixins.on_destroy import MoveOnDestroyMixin from taiga.projects.userstories.models import UserStory from taiga.projects.tasks.models import Task from taiga.projects.issues.models import Issue +from taiga.permissions import service as permissions_service from . import serializers from . import models @@ -46,7 +47,6 @@ from .votes import serializers as votes_serializers from .votes import services as votes_service from .votes.utils import attach_votescount_to_queryset - ###################################################### ## Project ###################################################### @@ -176,6 +176,10 @@ class ProjectViewSet(ModelCrudViewSet): if not obj.id: obj.template = self.request.QUERY_PARAMS.get('template', None) + # Update anon permissions if the project is public + if obj.is_private == False: + permissions_service.set_base_permissions_for_public_project(obj) + super().pre_save(obj) def destroy(self, request, *args, **kwargs): diff --git a/tests/integration/test_projects.py b/tests/integration/test_projects.py index 29a1966f..f7c01b14 100644 --- a/tests/integration/test_projects.py +++ b/tests/integration/test_projects.py @@ -2,6 +2,7 @@ from django.core.urlresolvers import reverse from taiga.base.utils import json from taiga.projects.services import stats as stats_services from taiga.projects.history.services import take_snapshot +from taiga.permissions.permissions import ANON_PERMISSIONS from .. import factories as f @@ -235,3 +236,19 @@ def test_edit_membership_only_owner(client): response = client.json.patch(url, json.dumps(data)) assert response.status_code == 400 assert response.data["is_owner"][0] == "At least one of the user must be an active admin" + + +def test_anon_permissions_generation_when_making_project_public(client): + user = f.UserFactory.create() + project = f.ProjectFactory.create(is_private=True) + role = f.RoleFactory.create(project=project, permissions=["view_project", "modify_project"]) + membership = f.MembershipFactory.create(project=project, user=user, role=role, is_owner=True) + assert project.anon_permissions == [] + client.login(user) + url = reverse("projects-detail", kwargs={"pk": project.pk}) + data = {"is_private": False} + response = client.json.patch(url, json.dumps(data)) + assert response.status_code == 200 + anon_permissions = list(map(lambda perm: perm[0], ANON_PERMISSIONS)) + assert set(anon_permissions).issubset(set(response.data["anon_permissions"])) + assert set(anon_permissions).issubset(set(response.data["public_permissions"]))