From 38e5198cc9443fb1d6c1c67a99d7c5dfafee6f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Mon, 23 May 2016 14:57:52 +0200 Subject: [PATCH] Minor refactor over permissions module --- ...rate_fixtures_initial_project_templates.sh | 6 ++ taiga/base/api/permissions.py | 33 ++------ taiga/permissions/choices.py | 72 ++++++++++++++++ taiga/permissions/permissions.py | 83 +++++++------------ taiga/permissions/{service.py => services.py} | 9 +- taiga/projects/api.py | 12 +-- taiga/projects/history/permissions.py | 2 +- taiga/projects/issues/permissions.py | 14 +--- .../management/commands/sample_data.py | 2 +- taiga/projects/models.py | 11 ++- taiga/projects/notifications/services.py | 2 +- taiga/projects/permissions.py | 25 +++--- taiga/projects/references/api.py | 2 +- taiga/projects/serializers.py | 4 +- taiga/projects/signals.py | 1 - taiga/projects/tasks/permissions.py | 5 +- taiga/projects/userstories/api.py | 1 - taiga/projects/userstories/permissions.py | 7 +- taiga/searches/api.py | 2 +- taiga/timeline/permissions.py | 8 +- taiga/users/models.py | 2 +- taiga/webhooks/permissions.py | 2 +- tests/factories.py | 2 +- .../test_attachment_resources.py | 2 +- .../test_history_resources.py | 2 +- .../test_issues_custom_attributes_resource.py | 2 +- .../test_issues_resources.py | 2 +- .../test_milestones_resources.py | 2 +- .../test_modules_resources.py | 2 +- .../test_projects_choices_resources.py | 2 +- .../test_projects_resource.py | 2 +- .../test_resolver_resources.py | 2 +- .../test_search_resources.py | 2 +- .../test_tasks_custom_attributes_resource.py | 2 +- .../test_tasks_resources.py | 2 +- .../test_timelines_resources.py | 2 +- ..._userstories_custom_attributes_resource.py | 2 +- .../test_userstories_resources.py | 2 +- .../test_wiki_resources.py | 2 +- tests/integration/test_notifications.py | 2 +- tests/integration/test_permissions.py | 36 ++++---- tests/integration/test_projects.py | 2 +- tests/integration/test_searches.py | 2 +- tests/integration/test_users.py | 2 +- tests/integration/test_watch_projects.py | 2 +- tests/unit/test_permissions.py | 26 ------ 46 files changed, 205 insertions(+), 206 deletions(-) create mode 100755 scripts/generate_fixtures_initial_project_templates.sh create mode 100644 taiga/permissions/choices.py rename taiga/permissions/{service.py => services.py} (96%) delete mode 100644 tests/unit/test_permissions.py diff --git a/scripts/generate_fixtures_initial_project_templates.sh b/scripts/generate_fixtures_initial_project_templates.sh new file mode 100755 index 00000000..d0201489 --- /dev/null +++ b/scripts/generate_fixtures_initial_project_templates.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +python ./manage.py dumpdata --format json \ + --indent 4 \ + --output './taiga/projects/fixtures/initial_project_templates.json' \ + 'projects.ProjectTemplate' diff --git a/taiga/base/api/permissions.py b/taiga/base/api/permissions.py index 62b40619..19b366fc 100644 --- a/taiga/base/api/permissions.py +++ b/taiga/base/api/permissions.py @@ -20,11 +20,12 @@ import abc from functools import reduce from taiga.base.utils import sequence as sq -from taiga.permissions.service import user_has_perm, is_project_admin +from taiga.permissions.services import user_has_perm, is_project_admin from django.apps import apps from django.utils.translation import ugettext as _ + ###################################################################### # Base permissiones definition ###################################################################### @@ -179,33 +180,6 @@ class HasProjectPerm(PermissionComponent): return user_has_perm(request.user, self.project_perm, obj) -class HasProjectParamAndPerm(PermissionComponent): - def __init__(self, perm, *components): - self.project_perm = perm - super().__init__(*components) - - def check_permissions(self, request, view, obj=None): - Project = apps.get_model('projects', 'Project') - project_id = request.QUERY_PARAMS.get("project", None) - try: - project = Project.objects.get(pk=project_id) - except Project.DoesNotExist: - return False - return user_has_perm(request.user, self.project_perm, project) - - -class HasMandatoryParam(PermissionComponent): - def __init__(self, param, *components): - self.mandatory_param = param - super().__init__(*components) - - def check_permissions(self, request, view, obj=None): - param = request.GET.get(self.mandatory_param, None) - if param: - return True - return False - - class IsProjectAdmin(PermissionComponent): def check_permissions(self, request, view, obj=None): return is_project_admin(request.user, obj) @@ -213,6 +187,9 @@ class IsProjectAdmin(PermissionComponent): class IsObjectOwner(PermissionComponent): def check_permissions(self, request, view, obj=None): + if obj.owner is None: + return False + return obj.owner == request.user diff --git a/taiga/permissions/choices.py b/taiga/permissions/choices.py new file mode 100644 index 00000000..bfd7192e --- /dev/null +++ b/taiga/permissions/choices.py @@ -0,0 +1,72 @@ +# Copyright (C) 2014-2016 Andrey Antukh +# Copyright (C) 2014-2016 Jesús Espino +# Copyright (C) 2014-2016 David Barragán +# Copyright (C) 2014-2016 Alejandro Alonso +# Copyright (C) 2014-2016 Anler Hernández +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from django.utils.translation import ugettext_lazy as _ + +ANON_PERMISSIONS = [ + ('view_project', _('View project')), + ('view_milestones', _('View milestones')), + ('view_us', _('View user stories')), + ('view_tasks', _('View tasks')), + ('view_issues', _('View issues')), + ('view_wiki_pages', _('View wiki pages')), + ('view_wiki_links', _('View wiki links')), +] + +MEMBERS_PERMISSIONS = [ + ('view_project', _('View project')), + # Milestone permissions + ('view_milestones', _('View milestones')), + ('add_milestone', _('Add milestone')), + ('modify_milestone', _('Modify milestone')), + ('delete_milestone', _('Delete milestone')), + # US permissions + ('view_us', _('View user story')), + ('add_us', _('Add user story')), + ('modify_us', _('Modify user story')), + ('delete_us', _('Delete user story')), + # Task permissions + ('view_tasks', _('View tasks')), + ('add_task', _('Add task')), + ('modify_task', _('Modify task')), + ('delete_task', _('Delete task')), + # Issue permissions + ('view_issues', _('View issues')), + ('add_issue', _('Add issue')), + ('modify_issue', _('Modify issue')), + ('delete_issue', _('Delete issue')), + # Wiki page permissions + ('view_wiki_pages', _('View wiki pages')), + ('add_wiki_page', _('Add wiki page')), + ('modify_wiki_page', _('Modify wiki page')), + ('delete_wiki_page', _('Delete wiki page')), + # Wiki link permissions + ('view_wiki_links', _('View wiki links')), + ('add_wiki_link', _('Add wiki link')), + ('modify_wiki_link', _('Modify wiki link')), + ('delete_wiki_link', _('Delete wiki link')), +] + +ADMINS_PERMISSIONS = [ + ('modify_project', _('Modify project')), + ('delete_project', _('Delete project')), + ('add_member', _('Add member')), + ('remove_member', _('Remove member')), + ('admin_project_values', _('Admin project values')), + ('admin_roles', _('Admin roles')), +] diff --git a/taiga/permissions/permissions.py b/taiga/permissions/permissions.py index 61c0b683..4e563522 100644 --- a/taiga/permissions/permissions.py +++ b/taiga/permissions/permissions.py @@ -16,57 +16,38 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from django.utils.translation import ugettext_lazy as _ +from django.apps import apps -ANON_PERMISSIONS = [ - ('view_project', _('View project')), - ('view_milestones', _('View milestones')), - ('view_us', _('View user stories')), - ('view_tasks', _('View tasks')), - ('view_issues', _('View issues')), - ('view_wiki_pages', _('View wiki pages')), - ('view_wiki_links', _('View wiki links')), -] +from taiga.base.api.permissions import PermissionComponent -MEMBERS_PERMISSIONS = [ - ('view_project', _('View project')), - # Milestone permissions - ('view_milestones', _('View milestones')), - ('add_milestone', _('Add milestone')), - ('modify_milestone', _('Modify milestone')), - ('delete_milestone', _('Delete milestone')), - # US permissions - ('view_us', _('View user story')), - ('add_us', _('Add user story')), - ('modify_us', _('Modify user story')), - ('delete_us', _('Delete user story')), - # Task permissions - ('view_tasks', _('View tasks')), - ('add_task', _('Add task')), - ('modify_task', _('Modify task')), - ('delete_task', _('Delete task')), - # Issue permissions - ('view_issues', _('View issues')), - ('add_issue', _('Add issue')), - ('modify_issue', _('Modify issue')), - ('delete_issue', _('Delete issue')), - # Wiki page permissions - ('view_wiki_pages', _('View wiki pages')), - ('add_wiki_page', _('Add wiki page')), - ('modify_wiki_page', _('Modify wiki page')), - ('delete_wiki_page', _('Delete wiki page')), - # Wiki link permissions - ('view_wiki_links', _('View wiki links')), - ('add_wiki_link', _('Add wiki link')), - ('modify_wiki_link', _('Modify wiki link')), - ('delete_wiki_link', _('Delete wiki link')), -] +from . import services -ADMINS_PERMISSIONS = [ - ('modify_project', _('Modify project')), - ('add_member', _('Add member')), - ('remove_member', _('Remove member')), - ('delete_project', _('Delete project')), - ('admin_project_values', _('Admin project values')), - ('admin_roles', _('Admin roles')), -] + +###################################################################### +# Generic perms +###################################################################### + +class HasProjectPerm(PermissionComponent): + def __init__(self, perm, *components): + self.project_perm = perm + super().__init__(*components) + + def check_permissions(self, request, view, obj=None): + return services.user_has_perm(request.user, self.project_perm, obj) + + +class IsObjectOwner(PermissionComponent): + def check_permissions(self, request, view, obj=None): + if obj.owner is None: + return False + + return obj.owner == request.user + + +###################################################################### +# Project Perms +###################################################################### + +class IsProjectAdmin(PermissionComponent): + def check_permissions(self, request, view, obj=None): + return services.is_project_admin(request.user, obj) diff --git a/taiga/permissions/service.py b/taiga/permissions/services.py similarity index 96% rename from taiga/permissions/service.py rename to taiga/permissions/services.py index 02922574..9ed1e8c3 100644 --- a/taiga/permissions/service.py +++ b/taiga/permissions/services.py @@ -16,10 +16,11 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from .permissions import ADMINS_PERMISSIONS, MEMBERS_PERMISSIONS, ANON_PERMISSIONS +from .choices import ADMINS_PERMISSIONS, MEMBERS_PERMISSIONS, ANON_PERMISSIONS from django.apps import apps + def _get_user_project_membership(user, project, cache="user"): """ cache param determines how memberships are calculated trying to reuse the existing data @@ -83,10 +84,6 @@ def user_has_perm(user, perm, obj=None, cache="user"): return perm in get_user_project_permissions(user, project, cache=cache) -def role_has_perm(role, perm): - return perm in role.permissions - - def _get_membership_permissions(membership): if membership and membership.role and membership.role.permissions: return membership.role.permissions @@ -97,7 +94,7 @@ def get_user_project_permissions(user, project, cache="user"): """ cache param determines how memberships are calculated trying to reuse the existing data in cache - """ + """ membership = _get_user_project_membership(user, project, cache=cache) if user.is_superuser: admins_permissions = list(map(lambda perm: perm[0], ADMINS_PERMISSIONS)) diff --git a/taiga/projects/api.py b/taiga/projects/api.py index a7c3aa61..17684fd3 100644 --- a/taiga/projects/api.py +++ b/taiga/projects/api.py @@ -51,8 +51,8 @@ from taiga.projects.userstories.models import UserStory, RolePoints from taiga.projects.tasks.models import Task from taiga.projects.issues.models import Issue from taiga.projects.likes.mixins.viewsets import LikedResourceMixin, FansViewSetMixin -from taiga.permissions import service as permissions_service -from taiga.users import services as users_service +from taiga.permissions import services as permissions_services +from taiga.users import services as users_services from . import filters as project_filters from . import models @@ -147,7 +147,7 @@ class ProjectViewSet(LikedResourceMixin, HistoryResourceMixin, else: project = self.get_object() - if permissions_service.is_project_admin(self.request.user, project): + if permissions_services.is_project_admin(self.request.user, project): serializer_class = self.admin_serializer_class return serializer_class @@ -415,7 +415,7 @@ class ProjectViewSet(LikedResourceMixin, HistoryResourceMixin, update_permissions = True if update_permissions: - permissions_service.set_base_permissions_for_project(obj) + permissions_services.set_base_permissions_for_project(obj) def pre_save(self, obj): if not obj.id: @@ -603,12 +603,12 @@ class MembershipViewSet(BlockedByProjectMixin, ModelCrudViewSet): use_admin_serializer = True if self.action == "retrieve": - use_admin_serializer = permissions_service.is_project_admin(self.request.user, self.object.project) + use_admin_serializer = permissions_services.is_project_admin(self.request.user, self.object.project) project_id = self.request.QUERY_PARAMS.get("project", None) if self.action == "list" and project_id is not None: project = get_object_or_404(models.Project, pk=project_id) - use_admin_serializer = permissions_service.is_project_admin(self.request.user, project) + use_admin_serializer = permissions_services.is_project_admin(self.request.user, project) if use_admin_serializer: return self.admin_serializer_class diff --git a/taiga/projects/history/permissions.py b/taiga/projects/history/permissions.py index fdce68cd..54fc59f1 100644 --- a/taiga/projects/history/permissions.py +++ b/taiga/projects/history/permissions.py @@ -19,7 +19,7 @@ from taiga.base.api.permissions import (TaigaResourcePermission, HasProjectPerm, IsProjectAdmin, AllowAny, IsObjectOwner, PermissionComponent) -from taiga.permissions.service import is_project_admin +from taiga.permissions.services import is_project_admin from taiga.projects.history.services import get_model_from_key, get_pk_from_key diff --git a/taiga/projects/issues/permissions.py b/taiga/projects/issues/permissions.py index 291dede7..791848f9 100644 --- a/taiga/projects/issues/permissions.py +++ b/taiga/projects/issues/permissions.py @@ -16,9 +16,9 @@ # along with this program. If not, see . -from taiga.base.api.permissions import (TaigaResourcePermission, HasProjectPerm, - IsProjectAdmin, PermissionComponent, - AllowAny, IsAuthenticated, IsSuperUser) +from taiga.base.api.permissions import TaigaResourcePermission, AllowAny, IsAuthenticated, IsSuperUser +from taiga.permissions.permissions import HasProjectPerm, IsProjectAdmin + class IssuePermission(TaigaResourcePermission): @@ -40,14 +40,6 @@ class IssuePermission(TaigaResourcePermission): unwatch_perms = IsAuthenticated() & HasProjectPerm('view_issues') -class HasIssueIdUrlParam(PermissionComponent): - def check_permissions(self, request, view, obj=None): - param = view.kwargs.get('issue_id', None) - if param: - return True - return False - - class IssueVotersPermission(TaigaResourcePermission): enought_perms = IsProjectAdmin() | IsSuperUser() global_perms = None diff --git a/taiga/projects/management/commands/sample_data.py b/taiga/projects/management/commands/sample_data.py index f5c7b6ea..be43df8c 100644 --- a/taiga/projects/management/commands/sample_data.py +++ b/taiga/projects/management/commands/sample_data.py @@ -29,7 +29,7 @@ from django.contrib.contenttypes.models import ContentType from sampledatahelper.helper import SampleDataHelper from taiga.users.models import * -from taiga.permissions.permissions import ANON_PERMISSIONS +from taiga.permissions.choices import ANON_PERMISSIONS from taiga.projects.choices import BLOCKED_BY_STAFF from taiga.projects.models import * from taiga.projects.milestones.models import * diff --git a/taiga/projects/models.py b/taiga/projects/models.py index cd38c35b..506c2736 100644 --- a/taiga/projects/models.py +++ b/taiga/projects/models.py @@ -40,7 +40,7 @@ from taiga.base.utils.sequence import arithmetic_progression from taiga.base.utils.slug import slugify_uniquely from taiga.base.utils.slug import slugify_uniquely_for_queryset -from taiga.permissions.permissions import ANON_PERMISSIONS, MEMBERS_PERMISSIONS +from taiga.permissions.choices import ANON_PERMISSIONS, MEMBERS_PERMISSIONS from taiga.projects.notifications.choices import NotifyLevel from taiga.projects.notifications.services import ( @@ -366,7 +366,8 @@ class Project(ProjectDefaults, TaggedMixin, models.Model): @cached_property def cached_memberships(self): - return {m.user.id: m for m in self.memberships.exclude(user__isnull=True).select_related("user", "project", "role")} + return {m.user.id: m for m in self.memberships.exclude(user__isnull=True) + .select_related("user", "project", "role")} def cached_memberships_for_user(self, user): return self.cached_memberships.get(user.id, None) @@ -966,9 +967,11 @@ class ProjectTemplate(models.Model): project=project) if self.priorities: - project.default_priority = Priority.objects.get(name=self.default_options["priority"], project=project) + project.default_priority = Priority.objects.get(name=self.default_options["priority"], + project=project) if self.severities: - project.default_severity = Severity.objects.get(name=self.default_options["severity"], project=project) + project.default_severity = Severity.objects.get(name=self.default_options["severity"], + project=project) return project diff --git a/taiga/projects/notifications/services.py b/taiga/projects/notifications/services.py index 22d518cb..27e4b5ae 100644 --- a/taiga/projects/notifications/services.py +++ b/taiga/projects/notifications/services.py @@ -35,7 +35,7 @@ from taiga.projects.history.choices import HistoryType from taiga.projects.history.services import (make_key_from_model_object, get_last_snapshot_for_key, get_model_from_key) -from taiga.permissions.service import user_has_perm +from taiga.permissions.services import user_has_perm from .models import HistoryChangeNotification, Watched diff --git a/taiga/projects/permissions.py b/taiga/projects/permissions.py index de65cd69..ba4f3260 100644 --- a/taiga/projects/permissions.py +++ b/taiga/projects/permissions.py @@ -18,18 +18,21 @@ from django.utils.translation import ugettext as _ from taiga.base.api.permissions import TaigaResourcePermission -from taiga.base.api.permissions import HasProjectPerm from taiga.base.api.permissions import IsAuthenticated -from taiga.base.api.permissions import IsProjectAdmin from taiga.base.api.permissions import AllowAny from taiga.base.api.permissions import IsSuperUser +from taiga.base.api.permissions import IsObjectOwner from taiga.base.api.permissions import PermissionComponent from taiga.base import exceptions as exc -from taiga.projects.models import Membership +from taiga.permissions.permissions import HasProjectPerm +from taiga.permissions.permissions import IsProjectAdmin + +from . import models from . import services + class CanLeaveProject(PermissionComponent): def check_permissions(self, request, view, obj=None): if not obj or not request.user.is_authenticated(): @@ -37,20 +40,12 @@ class CanLeaveProject(PermissionComponent): try: if not services.can_user_leave_project(request.user, obj): - raise exc.PermissionDenied(_("You can't leave the project if you are the owner or there are no more admins")) + raise exc.PermissionDenied(_("You can't leave the project if you are the owner or there are " + "no more admins")) return True - except Membership.DoesNotExist: + except models.Membership.DoesNotExist: return False -class IsMainOwner(PermissionComponent): - def check_permissions(self, request, view, obj=None): - if not obj or not request.user.is_authenticated(): - return False - - if obj.owner is None: - return False - - return obj.owner == request.user class ProjectPermission(TaigaResourcePermission): retrieve_perms = HasProjectPerm('view_project') @@ -79,7 +74,7 @@ class ProjectPermission(TaigaResourcePermission): leave_perms = CanLeaveProject() transfer_validate_token_perms = IsAuthenticated() & HasProjectPerm('view_project') transfer_request_perms = IsProjectAdmin() - transfer_start_perms = IsMainOwner() + transfer_start_perms = IsObjectOwner() transfer_reject_perms = IsAuthenticated() & HasProjectPerm('view_project') transfer_accept_perms = IsAuthenticated() & HasProjectPerm('view_project') diff --git a/taiga/projects/references/api.py b/taiga/projects/references/api.py index 028d4642..0775bc72 100644 --- a/taiga/projects/references/api.py +++ b/taiga/projects/references/api.py @@ -21,7 +21,7 @@ from taiga.base import exceptions as exc from taiga.base import response from taiga.base.api import viewsets from taiga.base.api.utils import get_object_or_404 -from taiga.permissions.service import user_has_perm +from taiga.permissions.services import user_has_perm from .serializers import ResolverSerializer from . import permissions diff --git a/taiga/projects/serializers.py b/taiga/projects/serializers.py index 661aeece..7096919a 100644 --- a/taiga/projects/serializers.py +++ b/taiga/projects/serializers.py @@ -32,8 +32,8 @@ from taiga.users.serializers import UserBasicInfoSerializer from taiga.users.serializers import ProjectRoleSerializer from taiga.users.validators import RoleExistsValidator -from taiga.permissions.service import get_user_project_permissions -from taiga.permissions.service import is_project_admin, is_project_owner +from taiga.permissions.services import get_user_project_permissions +from taiga.permissions.services import is_project_admin, is_project_owner from taiga.projects.mixins.serializers import ValidateDuplicatedNameInProjectMixin from . import models diff --git a/taiga/projects/signals.py b/taiga/projects/signals.py index 51ff6485..32da1176 100644 --- a/taiga/projects/signals.py +++ b/taiga/projects/signals.py @@ -67,7 +67,6 @@ def project_post_save(sender, instance, created, **kwargs): if instance._importing: return - template = getattr(instance, "creation_template", None) if template is None: ProjectTemplate = apps.get_model("projects", "ProjectTemplate") diff --git a/taiga/projects/tasks/permissions.py b/taiga/projects/tasks/permissions.py index 9e189f10..566fc79c 100644 --- a/taiga/projects/tasks/permissions.py +++ b/taiga/projects/tasks/permissions.py @@ -15,9 +15,8 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from taiga.base.api.permissions import (TaigaResourcePermission, HasProjectPerm, - IsAuthenticated, IsProjectAdmin, AllowAny, - IsSuperUser) +from taiga.base.api.permissions import TaigaResourcePermission, AllowAny, IsAuthenticated, IsSuperUser +from taiga.permissions.permissions import HasProjectPerm, IsProjectAdmin class TaskPermission(TaigaResourcePermission): diff --git a/taiga/projects/userstories/api.py b/taiga/projects/userstories/api.py index 815560c1..745268cd 100644 --- a/taiga/projects/userstories/api.py +++ b/taiga/projects/userstories/api.py @@ -112,7 +112,6 @@ class UserStoryViewSet(OCCResourceMixin, VotedResourceMixin, HistoryResourceMixi return super().update(request, *args, **kwargs) - def get_queryset(self): qs = super().get_queryset() qs = qs.prefetch_related("role_points", diff --git a/taiga/projects/userstories/permissions.py b/taiga/projects/userstories/permissions.py index 326c99fe..11aa5b73 100644 --- a/taiga/projects/userstories/permissions.py +++ b/taiga/projects/userstories/permissions.py @@ -15,12 +15,13 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from taiga.base.api.permissions import (TaigaResourcePermission, HasProjectPerm, - IsAuthenticated, IsProjectAdmin, - AllowAny, IsSuperUser) +from taiga.base.api.permissions import TaigaResourcePermission, AllowAny, IsAuthenticated, IsSuperUser +from taiga.permissions.permissions import HasProjectPerm, IsProjectAdmin class UserStoryPermission(TaigaResourcePermission): + enought_perms = IsProjectAdmin() | IsSuperUser() + global_perms = None retrieve_perms = HasProjectPerm('view_us') create_perms = HasProjectPerm('add_us_to_project') | HasProjectPerm('add_us') update_perms = HasProjectPerm('modify_us') diff --git a/taiga/searches/api.py b/taiga/searches/api.py index be8a0e9a..f10554a8 100644 --- a/taiga/searches/api.py +++ b/taiga/searches/api.py @@ -21,7 +21,7 @@ from taiga.base.api import viewsets from taiga.base import response from taiga.base.api.utils import get_object_or_404 -from taiga.permissions.service import user_has_perm +from taiga.permissions.services import user_has_perm from . import services from . import serializers diff --git a/taiga/timeline/permissions.py b/taiga/timeline/permissions.py index b71530ed..f2753869 100644 --- a/taiga/timeline/permissions.py +++ b/taiga/timeline/permissions.py @@ -15,13 +15,17 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from taiga.base.api.permissions import (TaigaResourcePermission, HasProjectPerm, - AllowAny) +from taiga.base.api.permissions import TaigaResourcePermission, AllowAny, IsSuperUser +from taiga.permissions.permissions import HasProjectPerm, IsProjectAdmin class UserTimelinePermission(TaigaResourcePermission): + enought_perms = IsSuperUser() + global_perms = None retrieve_perms = AllowAny() class ProjectTimelinePermission(TaigaResourcePermission): + enought_perms = IsProjectAdmin() | IsSuperUser() + global_perms = None retrieve_perms = HasProjectPerm('view_project') diff --git a/taiga/users/models.py b/taiga/users/models.py index a0a9048b..c1cf4a3b 100644 --- a/taiga/users/models.py +++ b/taiga/users/models.py @@ -38,7 +38,7 @@ from djorm_pgarray.fields import TextArrayField from taiga.auth.tokens import get_token_for_user from taiga.base.utils.slug import slugify_uniquely from taiga.base.utils.files import get_file_path -from taiga.permissions.permissions import MEMBERS_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS from taiga.projects.choices import BLOCKED_BY_OWNER_LEAVING from taiga.projects.notifications.choices import NotifyLevel diff --git a/taiga/webhooks/permissions.py b/taiga/webhooks/permissions.py index bc1cae61..82ca5bd7 100644 --- a/taiga/webhooks/permissions.py +++ b/taiga/webhooks/permissions.py @@ -18,7 +18,7 @@ from taiga.base.api.permissions import (TaigaResourcePermission, IsProjectAdmin, AllowAny, PermissionComponent) -from taiga.permissions.service import is_project_admin +from taiga.permissions.services import is_project_admin class IsWebhookProjectAdmin(PermissionComponent): diff --git a/tests/factories.py b/tests/factories.py index 252ce47a..2f1ddccc 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -26,7 +26,7 @@ from .utils import DUMMY_BMP_DATA import factory -from taiga.permissions.permissions import MEMBERS_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS diff --git a/tests/integration/resources_permissions/test_attachment_resources.py b/tests/integration/resources_permissions/test_attachment_resources.py index c48a7e3a..357b13a7 100644 --- a/tests/integration/resources_permissions/test_attachment_resources.py +++ b/tests/integration/resources_permissions/test_attachment_resources.py @@ -4,7 +4,7 @@ from django.test.client import MULTIPART_CONTENT from taiga.base.utils import json -from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS from taiga.projects import choices as project_choices from taiga.projects.attachments.serializers import AttachmentSerializer diff --git a/tests/integration/resources_permissions/test_history_resources.py b/tests/integration/resources_permissions/test_history_resources.py index 9d39b9d7..62ba4e77 100644 --- a/tests/integration/resources_permissions/test_history_resources.py +++ b/tests/integration/resources_permissions/test_history_resources.py @@ -2,7 +2,7 @@ from django.core.urlresolvers import reverse from django.utils import timezone from taiga.base.utils import json -from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS from taiga.projects.history.models import HistoryEntry from taiga.projects.history.choices import HistoryType from taiga.projects.history.services import make_key_from_model_object diff --git a/tests/integration/resources_permissions/test_issues_custom_attributes_resource.py b/tests/integration/resources_permissions/test_issues_custom_attributes_resource.py index 718172df..60b57eed 100644 --- a/tests/integration/resources_permissions/test_issues_custom_attributes_resource.py +++ b/tests/integration/resources_permissions/test_issues_custom_attributes_resource.py @@ -21,7 +21,7 @@ from django.core.urlresolvers import reverse from taiga.base.utils import json from taiga.projects import choices as project_choices from taiga.projects.custom_attributes import serializers -from taiga.permissions.permissions import (MEMBERS_PERMISSIONS, +from taiga.permissions.choices import (MEMBERS_PERMISSIONS, ANON_PERMISSIONS) from tests import factories as f diff --git a/tests/integration/resources_permissions/test_issues_resources.py b/tests/integration/resources_permissions/test_issues_resources.py index 4cf3e2a1..bb532473 100644 --- a/tests/integration/resources_permissions/test_issues_resources.py +++ b/tests/integration/resources_permissions/test_issues_resources.py @@ -4,7 +4,7 @@ from django.core.urlresolvers import reverse from taiga.projects import choices as project_choices from taiga.projects.issues.serializers import IssueSerializer -from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS from taiga.base.utils import json from tests import factories as f diff --git a/tests/integration/resources_permissions/test_milestones_resources.py b/tests/integration/resources_permissions/test_milestones_resources.py index c42c0580..56f072f4 100644 --- a/tests/integration/resources_permissions/test_milestones_resources.py +++ b/tests/integration/resources_permissions/test_milestones_resources.py @@ -6,7 +6,7 @@ from taiga.projects import choices as project_choices from taiga.projects.milestones.serializers import MilestoneSerializer from taiga.projects.milestones.models import Milestone from taiga.projects.notifications.services import add_watcher -from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS from tests import factories as f from tests.utils import helper_test_http_method, disconnect_signals, reconnect_signals diff --git a/tests/integration/resources_permissions/test_modules_resources.py b/tests/integration/resources_permissions/test_modules_resources.py index 27269458..fc1de642 100644 --- a/tests/integration/resources_permissions/test_modules_resources.py +++ b/tests/integration/resources_permissions/test_modules_resources.py @@ -2,7 +2,7 @@ import uuid from django.core.urlresolvers import reverse -from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS from taiga.base.utils import json from tests import factories as f diff --git a/tests/integration/resources_permissions/test_projects_choices_resources.py b/tests/integration/resources_permissions/test_projects_choices_resources.py index 207889f9..c26e51b5 100644 --- a/tests/integration/resources_permissions/test_projects_choices_resources.py +++ b/tests/integration/resources_permissions/test_projects_choices_resources.py @@ -4,7 +4,7 @@ from taiga.base.utils import json from taiga.projects import choices as project_choices from taiga.projects import serializers from taiga.users.serializers import RoleSerializer -from taiga.permissions.permissions import MEMBERS_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS from tests import factories as f from tests.utils import helper_test_http_method diff --git a/tests/integration/resources_permissions/test_projects_resource.py b/tests/integration/resources_permissions/test_projects_resource.py index 9bcd7a9f..a2ec130e 100644 --- a/tests/integration/resources_permissions/test_projects_resource.py +++ b/tests/integration/resources_permissions/test_projects_resource.py @@ -4,7 +4,7 @@ from django.apps import apps from taiga.base.utils import json from taiga.projects import choices as project_choices from taiga.projects.serializers import ProjectDetailSerializer -from taiga.permissions.permissions import MEMBERS_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS from tests import factories as f from tests.utils import helper_test_http_method, helper_test_http_method_and_count diff --git a/tests/integration/resources_permissions/test_resolver_resources.py b/tests/integration/resources_permissions/test_resolver_resources.py index 6858d976..c8634c46 100644 --- a/tests/integration/resources_permissions/test_resolver_resources.py +++ b/tests/integration/resources_permissions/test_resolver_resources.py @@ -1,6 +1,6 @@ from django.core.urlresolvers import reverse -from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS from tests import factories as f from tests.utils import helper_test_http_method, disconnect_signals, reconnect_signals diff --git a/tests/integration/resources_permissions/test_search_resources.py b/tests/integration/resources_permissions/test_search_resources.py index 783818d3..d72e7bc2 100644 --- a/tests/integration/resources_permissions/test_search_resources.py +++ b/tests/integration/resources_permissions/test_search_resources.py @@ -1,6 +1,6 @@ from django.core.urlresolvers import reverse -from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS from tests import factories as f from tests.utils import helper_test_http_method_and_keys, disconnect_signals, reconnect_signals diff --git a/tests/integration/resources_permissions/test_tasks_custom_attributes_resource.py b/tests/integration/resources_permissions/test_tasks_custom_attributes_resource.py index 44509354..2262a222 100644 --- a/tests/integration/resources_permissions/test_tasks_custom_attributes_resource.py +++ b/tests/integration/resources_permissions/test_tasks_custom_attributes_resource.py @@ -21,7 +21,7 @@ from django.core.urlresolvers import reverse from taiga.base.utils import json from taiga.projects import choices as project_choices from taiga.projects.custom_attributes import serializers -from taiga.permissions.permissions import (MEMBERS_PERMISSIONS, +from taiga.permissions.choices import (MEMBERS_PERMISSIONS, ANON_PERMISSIONS) from tests import factories as f diff --git a/tests/integration/resources_permissions/test_tasks_resources.py b/tests/integration/resources_permissions/test_tasks_resources.py index 274f7a0c..aff81389 100644 --- a/tests/integration/resources_permissions/test_tasks_resources.py +++ b/tests/integration/resources_permissions/test_tasks_resources.py @@ -5,7 +5,7 @@ from django.core.urlresolvers import reverse from taiga.base.utils import json from taiga.projects import choices as project_choices from taiga.projects.tasks.serializers import TaskSerializer -from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS from taiga.projects.occ import OCCResourceMixin from tests import factories as f diff --git a/tests/integration/resources_permissions/test_timelines_resources.py b/tests/integration/resources_permissions/test_timelines_resources.py index ffc4e41d..ed68f67b 100644 --- a/tests/integration/resources_permissions/test_timelines_resources.py +++ b/tests/integration/resources_permissions/test_timelines_resources.py @@ -1,6 +1,6 @@ from django.core.urlresolvers import reverse -from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS from tests import factories as f from tests.utils import helper_test_http_method, disconnect_signals, reconnect_signals diff --git a/tests/integration/resources_permissions/test_userstories_custom_attributes_resource.py b/tests/integration/resources_permissions/test_userstories_custom_attributes_resource.py index 030060f3..64e7324a 100644 --- a/tests/integration/resources_permissions/test_userstories_custom_attributes_resource.py +++ b/tests/integration/resources_permissions/test_userstories_custom_attributes_resource.py @@ -21,7 +21,7 @@ from django.core.urlresolvers import reverse from taiga.base.utils import json from taiga.projects import choices as project_choices from taiga.projects.custom_attributes import serializers -from taiga.permissions.permissions import (MEMBERS_PERMISSIONS, +from taiga.permissions.choices import (MEMBERS_PERMISSIONS, ANON_PERMISSIONS) diff --git a/tests/integration/resources_permissions/test_userstories_resources.py b/tests/integration/resources_permissions/test_userstories_resources.py index 0daadad5..4da7b081 100644 --- a/tests/integration/resources_permissions/test_userstories_resources.py +++ b/tests/integration/resources_permissions/test_userstories_resources.py @@ -5,7 +5,7 @@ from django.core.urlresolvers import reverse from taiga.base.utils import json from taiga.projects import choices as project_choices from taiga.projects.userstories.serializers import UserStorySerializer -from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS from taiga.projects.occ import OCCResourceMixin from tests import factories as f diff --git a/tests/integration/resources_permissions/test_wiki_resources.py b/tests/integration/resources_permissions/test_wiki_resources.py index ed76e769..aaee4e53 100644 --- a/tests/integration/resources_permissions/test_wiki_resources.py +++ b/tests/integration/resources_permissions/test_wiki_resources.py @@ -1,7 +1,7 @@ from django.core.urlresolvers import reverse from taiga.base.utils import json -from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS from taiga.projects import choices as project_choices from taiga.projects.notifications.services import add_watcher from taiga.projects.occ import OCCResourceMixin diff --git a/tests/integration/test_notifications.py b/tests/integration/test_notifications.py index bb2cdfd8..4d341086 100644 --- a/tests/integration/test_notifications.py +++ b/tests/integration/test_notifications.py @@ -41,7 +41,7 @@ from taiga.projects.history.services import take_snapshot from taiga.projects.issues.serializers import IssueSerializer from taiga.projects.userstories.serializers import UserStorySerializer from taiga.projects.tasks.serializers import TaskSerializer -from taiga.permissions.permissions import MEMBERS_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS pytestmark = pytest.mark.django_db diff --git a/tests/integration/test_permissions.py b/tests/integration/test_permissions.py index ddcf9e34..7ec25929 100644 --- a/tests/integration/test_permissions.py +++ b/tests/integration/test_permissions.py @@ -1,6 +1,6 @@ import pytest -from taiga.permissions import service, permissions +from taiga.permissions import services, choices from django.contrib.auth.models import AnonymousUser from .. import factories @@ -15,15 +15,15 @@ def test_get_user_project_role(): role = factories.RoleFactory() membership = factories.MembershipFactory(user=user1, project=project, role=role) - assert service._get_user_project_membership(user1, project) == membership - assert service._get_user_project_membership(user2, project) is None + assert services._get_user_project_membership(user1, project) == membership + assert services._get_user_project_membership(user2, project) is None def test_anon_get_user_project_permissions(): project = factories.ProjectFactory() project.anon_permissions = ["test1"] project.public_permissions = ["test2"] - assert service.get_user_project_permissions(AnonymousUser(), project) == set(["test1"]) + assert services.get_user_project_permissions(AnonymousUser(), project) == set(["test1"]) def test_user_get_user_project_permissions_on_public_project(): @@ -31,7 +31,7 @@ def test_user_get_user_project_permissions_on_public_project(): project = factories.ProjectFactory() project.anon_permissions = ["test1"] project.public_permissions = ["test2"] - assert service.get_user_project_permissions(user1, project) == set(["test1", "test2"]) + assert services.get_user_project_permissions(user1, project) == set(["test1", "test2"]) def test_user_get_user_project_permissions_on_private_project(): @@ -40,7 +40,7 @@ def test_user_get_user_project_permissions_on_private_project(): project.anon_permissions = ["test1"] project.public_permissions = ["test2"] project.is_private = True - assert service.get_user_project_permissions(user1, project) == set(["test1", "test2"]) + assert services.get_user_project_permissions(user1, project) == set(["test1", "test2"]) def test_owner_get_user_project_permissions(): @@ -55,7 +55,7 @@ def test_owner_get_user_project_permissions(): expected_perms = set( ["test1", "test2", "view_us"] ) - assert service.get_user_project_permissions(user1, project) == expected_perms + assert services.get_user_project_permissions(user1, project) == expected_perms def test_owner_member_get_user_project_permissions(): @@ -68,10 +68,10 @@ def test_owner_member_get_user_project_permissions(): expected_perms = set( ["test1", "test2", "test3"] + - [x[0] for x in permissions.ADMINS_PERMISSIONS] + - [x[0] for x in permissions.MEMBERS_PERMISSIONS] + [x[0] for x in choices.ADMINS_PERMISSIONS] + + [x[0] for x in choices.MEMBERS_PERMISSIONS] ) - assert service.get_user_project_permissions(user1, project) == expected_perms + assert services.get_user_project_permissions(user1, project) == expected_perms def test_member_get_user_project_permissions(): @@ -82,22 +82,22 @@ def test_member_get_user_project_permissions(): role = factories.RoleFactory(permissions=["test3"]) factories.MembershipFactory(user=user1, project=project, role=role) - assert service.get_user_project_permissions(user1, project) == set(["test1", "test2", "test3"]) + assert services.get_user_project_permissions(user1, project) == set(["test1", "test2", "test3"]) def test_anon_user_has_perm(): project = factories.ProjectFactory() project.anon_permissions = ["test"] - assert service.user_has_perm(AnonymousUser(), "test", project) is True - assert service.user_has_perm(AnonymousUser(), "fail", project) is False + assert services.user_has_perm(AnonymousUser(), "test", project) is True + assert services.user_has_perm(AnonymousUser(), "fail", project) is False def test_authenticated_user_has_perm_on_project(): user1 = factories.UserFactory() project = factories.ProjectFactory() project.public_permissions = ["test"] - assert service.user_has_perm(user1, "test", project) is True - assert service.user_has_perm(user1, "fail", project) is False + assert services.user_has_perm(user1, "test", project) is True + assert services.user_has_perm(user1, "fail", project) is False def test_authenticated_user_has_perm_on_project_related_object(): @@ -106,10 +106,10 @@ def test_authenticated_user_has_perm_on_project_related_object(): project.public_permissions = ["test"] us = factories.UserStoryFactory(project=project) - assert service.user_has_perm(user1, "test", us) is True - assert service.user_has_perm(user1, "fail", us) is False + assert services.user_has_perm(user1, "test", us) is True + assert services.user_has_perm(user1, "fail", us) is False def test_authenticated_user_has_perm_on_invalid_object(): user1 = factories.UserFactory() - assert service.user_has_perm(user1, "test", user1) is False + assert services.user_has_perm(user1, "test", user1) is False diff --git a/tests/integration/test_projects.py b/tests/integration/test_projects.py index 6111747b..28a0dbe3 100644 --- a/tests/integration/test_projects.py +++ b/tests/integration/test_projects.py @@ -7,7 +7,7 @@ from django.core import signing 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 taiga.permissions.choices import ANON_PERMISSIONS from taiga.projects.models import Project from .. import factories as f diff --git a/tests/integration/test_searches.py b/tests/integration/test_searches.py index 334ad405..30c3247b 100644 --- a/tests/integration/test_searches.py +++ b/tests/integration/test_searches.py @@ -22,7 +22,7 @@ from django.core.urlresolvers import reverse from .. import factories as f -from taiga.permissions.permissions import MEMBERS_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS from tests.utils import disconnect_signals, reconnect_signals diff --git a/tests/integration/test_users.py b/tests/integration/test_users.py index 7ca9b867..be48c553 100644 --- a/tests/integration/test_users.py +++ b/tests/integration/test_users.py @@ -14,7 +14,7 @@ from taiga.base.utils.thumbnails import get_thumbnail_url from taiga.users import models from taiga.users.serializers import LikedObjectSerializer, VotedObjectSerializer from taiga.auth.tokens import get_token_for_user -from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS from taiga.projects import choices as project_choices from taiga.users.services import get_watched_list, get_voted_list, get_liked_list from taiga.projects.notifications.choices import NotifyLevel diff --git a/tests/integration/test_watch_projects.py b/tests/integration/test_watch_projects.py index 6c4f7d41..5a77f086 100644 --- a/tests/integration/test_watch_projects.py +++ b/tests/integration/test_watch_projects.py @@ -20,7 +20,7 @@ import pytest import json from django.core.urlresolvers import reverse -from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS +from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS from .. import factories as f diff --git a/tests/unit/test_permissions.py b/tests/unit/test_permissions.py deleted file mode 100644 index 5ef7a93d..00000000 --- a/tests/unit/test_permissions.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (C) 2014-2016 Andrey Antukh -# Copyright (C) 2014-2016 Jesús Espino -# Copyright (C) 2014-2016 David Barragán -# Copyright (C) 2014-2016 Alejandro Alonso -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -from taiga.permissions import service -from taiga.users.models import Role - - -def test_role_has_perm(): - role = Role() - role.permissions = ["test"] - assert service.role_has_perm(role, "test") - assert service.role_has_perm(role, "false") is False