From 54fe5ba79c0240127fc3c106af6bf9892708c033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Hermida?= Date: Fri, 21 Sep 2018 14:26:38 +0200 Subject: [PATCH] Validate user settings homepage --- taiga/projects/settings/api.py | 2 ++ taiga/projects/settings/serializers.py | 22 ++----------- taiga/projects/settings/utils.py | 23 +++++++++++++ taiga/projects/settings/validators.py | 38 ++++++++++++++++++++++ tests/integration/test_project_settings.py | 32 +++++++++++++++++- 5 files changed, 96 insertions(+), 21 deletions(-) create mode 100644 taiga/projects/settings/utils.py create mode 100644 taiga/projects/settings/validators.py diff --git a/taiga/projects/settings/api.py b/taiga/projects/settings/api.py index 6ff89e17..4aabed59 100644 --- a/taiga/projects/settings/api.py +++ b/taiga/projects/settings/api.py @@ -28,11 +28,13 @@ from . import models from . import permissions from . import serializers from . import services +from . import validators class UserProjectSettingsViewSet(ModelCrudViewSet): serializer_class = serializers.UserProjectSettingsSerializer permission_classes = (permissions.UserProjectSettingsPermission,) + validator_class = validators.UserProjectSettingsValidator def _build_user_project_settings(self): projects = Project.objects.filter( diff --git a/taiga/projects/settings/serializers.py b/taiga/projects/settings/serializers.py index dd10cbf7..f5539038 100644 --- a/taiga/projects/settings/serializers.py +++ b/taiga/projects/settings/serializers.py @@ -17,11 +17,10 @@ # along with this program. If not, see . from taiga.base.api import serializers -from taiga.permissions.services import is_project_admin, user_has_perm from . import models -from taiga.projects.settings.choices import Section +from taiga.projects.settings.utils import get_allowed_sections class UserProjectSettingsSerializer(serializers.ModelSerializer): @@ -36,21 +35,4 @@ class UserProjectSettingsSerializer(serializers.ModelSerializer): return obj.project.name def get_allowed_sections(self, obj): - sections = [Section.timeline, Section.search, Section.team] - active_modules = {'epics': 'view_epics', 'backlog': 'view_us', - 'kanban': 'view_us', 'wiki': 'view_wiki_pages', - 'issues': 'view_issues'} - - for key in active_modules: - module_name = "is_{}_activated".format(key) - if getattr(obj.project, module_name) and \ - user_has_perm(obj.user, active_modules[key], obj.project): - sections.append(getattr(Section, key)) - - if obj.project.videoconferences: - sections.append(Section.meetup) - - if is_project_admin(obj.user, obj.project): - sections.append(Section.admin) - - return sections + return get_allowed_sections(obj) diff --git a/taiga/projects/settings/utils.py b/taiga/projects/settings/utils.py new file mode 100644 index 00000000..03560eb6 --- /dev/null +++ b/taiga/projects/settings/utils.py @@ -0,0 +1,23 @@ +from taiga.permissions.services import is_project_admin, user_has_perm +from taiga.projects.settings.choices import Section + + +def get_allowed_sections(obj): + sections = [Section.timeline, Section.search, Section.team] + active_modules = {'epics': 'view_epics', 'backlog': 'view_us', + 'kanban': 'view_us', 'wiki': 'view_wiki_pages', + 'issues': 'view_issues'} + + for key in active_modules: + module_name = "is_{}_activated".format(key) + if getattr(obj.project, module_name) and \ + user_has_perm(obj.user, active_modules[key], obj.project): + sections.append(getattr(Section, key)) + + if obj.project.videoconferences: + sections.append(Section.meetup) + + if is_project_admin(obj.user, obj.project): + sections.append(Section.admin) + + return sections diff --git a/taiga/projects/settings/validators.py b/taiga/projects/settings/validators.py new file mode 100644 index 00000000..ff7206fc --- /dev/null +++ b/taiga/projects/settings/validators.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2014-2017 Andrey Antukh +# Copyright (C) 2014-2017 Jesús Espino +# Copyright (C) 2014-2017 David Barragán +# Copyright (C) 2014-2017 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 django.utils.translation import ugettext as _ + +from taiga.base.api import validators +from taiga.base.exceptions import ValidationError +from taiga.projects.settings.utils import get_allowed_sections + +from . import models + + +class UserProjectSettingsValidator(validators.ModelValidator): + + class Meta: + model = models.UserProjectSettings + read_only_fields = ('id', 'created_at', 'modified_at', 'project', + 'user') + + def validate_homepage(self, attrs, source): + if attrs[source] not in get_allowed_sections(self.object): + msg = _("You don't have access to this section") + raise ValidationError(msg) + return attrs diff --git a/tests/integration/test_project_settings.py b/tests/integration/test_project_settings.py index fa288326..4ebad339 100644 --- a/tests/integration/test_project_settings.py +++ b/tests/integration/test_project_settings.py @@ -1,3 +1,5 @@ +import json + import pytest from django.apps import apps @@ -34,7 +36,7 @@ def test_create_retrieve_home_page_setting(): assert setting.homepage == Section.timeline -def test_retrieve_home_page_setting_with_allowed_sections(client): +def test_retrieve_homepage_setting_with_allowed_sections(client): # Default template has next configuration: # "is_epics_activated": false, # "is_backlog_activated": true, @@ -66,3 +68,31 @@ def test_retrieve_home_page_setting_with_allowed_sections(client): assert Section.epics not in response.data[0].get("allowed_sections") assert Section.issues not in response.data[0].get("allowed_sections") + + +def test_avoid_patch_homepage_setting_with_not_allowed_section(client): + # Default template has next configuration: + # "is_epics_activated": false, + # "is_backlog_activated": true, + # "is_kanban_activated": false, + # "is_wiki_activated": true, + # "is_issues_activated": true, + # "videoconferences": null, + user = f.UserFactory.create() + project = f.ProjectFactory.create(owner=user) + membership = f.MembershipFactory.create(user=user, project=project, + is_admin=False) + membership.role.permissions = ["view_us", "view_wiki_pages"] + membership.role.save() + + setting = services.create_user_project_settings_if_not_exists(project, + project.owner) + + url = reverse("user-project-settings-detail", args=[setting.pk]) + + client.login(project.owner) + response = client.json.patch(url, data=json.dumps({"homepage": Section.backlog})) + assert response.status_code == 200 + + response = client.json.patch(url, data=json.dumps({"homepage": Section.issues})) + assert response.status_code == 400