Merge pull request #729 from taigaio/us/4186-2929/add_and_edit_comment_permission

US #4186 #2929: Add and edit comment permission
remotes/origin/issue/4795/notification_even_they_are_disabled
David Barragán Merino 2016-05-26 11:02:09 +02:00
commit 43fafd1f57
60 changed files with 3142 additions and 1156 deletions

View File

@ -1,5 +1,14 @@
# Changelog #
## 2.2.0 ??? (unreleased)
### Features
- Now comment owners and project admins can edit existing comments with the history Entry endpoint.
- Add a new permissions to allow add comments instead of use the existent modify permission for this purpose.
### Misc
- Lots of small and not so small bugfixes.
## 2.1.0 Ursus Americanus (2016-05-03)

View File

@ -0,0 +1,6 @@
#!/bin/bash
python ./manage.py dumpdata --format json \
--indent 4 \
--output './taiga/projects/fixtures/initial_project_templates.json' \
'projects.ProjectTemplate'

View File

@ -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

View File

@ -0,0 +1,75 @@
# Copyright (C) 2014-2016 Andrey Antukh <niwi@niwi.nz>
# Copyright (C) 2014-2016 Jesús Espino <jespinog@gmail.com>
# Copyright (C) 2014-2016 David Barragán <bameda@dbarragan.com>
# Copyright (C) 2014-2016 Alejandro Alonso <alejandro.alonso@kaleidos.net>
# Copyright (C) 2014-2016 Anler Hernández <hello@anler.me>
# 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 <http://www.gnu.org/licenses/>.
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')),
('comment_us', _('Comment user story')),
('delete_us', _('Delete user story')),
# Task permissions
('view_tasks', _('View tasks')),
('add_task', _('Add task')),
('modify_task', _('Modify task')),
('comment_task', _('Comment task')),
('delete_task', _('Delete task')),
# Issue permissions
('view_issues', _('View issues')),
('add_issue', _('Add issue')),
('modify_issue', _('Modify issue')),
('comment_issue', _('Comment 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')),
('comment_wiki_page', _('Comment 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')),
]

View File

@ -16,77 +16,75 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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
USER_PERMISSIONS = [
('view_project', _('View project')),
('view_milestones', _('View milestones')),
('view_us', _('View user stories')),
('view_issues', _('View issues')),
('view_tasks', _('View tasks')),
('view_wiki_pages', _('View wiki pages')),
('view_wiki_links', _('View wiki links')),
('request_membership', _('Request membership')),
('add_us_to_project', _('Add user story to project')),
('add_comments_to_us', _('Add comments to user stories')),
('add_comments_to_task', _('Add comments to tasks')),
('add_issue', _('Add issues')),
('add_comments_to_issue', _('Add comments to issues')),
('add_wiki_page', _('Add wiki page')),
('modify_wiki_page', _('Modify wiki page')),
('add_wiki_link', _('Add wiki link')),
('modify_wiki_link', _('Modify wiki link')),
]
from . import services
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')),
('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)
######################################################################
# Common perms for stories, tasks and issues
######################################################################
class CommentAndOrUpdatePerm(PermissionComponent):
def __init__(self, update_perm, comment_perm, *components):
self.update_perm = update_perm
self.comment_perm = comment_perm
super().__init__(*components)
def check_permissions(self, request, view, obj=None):
if not obj:
return False
project_id = request.DATA.get('project', None)
if project_id and obj.project_id != project_id:
project = apps.get_model("projects", "Project").objects.get(pk=project_id)
else:
project = obj.project
data_keys = request.DATA.keys()
if (not services.user_has_perm(request.user, self.comment_perm, project) and
"comment" in data_keys):
# User can't comment but there is a comment in the request
#raise exc.PermissionDenied(_("You don't have permissions to comment this."))
return False
if (not services.user_has_perm(request.user, self.update_perm, project) and
len(data_keys - "comment")):
# User can't update but there is a change in the request
#raise exc.PermissionDenied(_("You don't have permissions to update this."))
return False
return True

View File

@ -16,10 +16,11 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .permissions import ADMINS_PERMISSIONS, MEMBERS_PERMISSIONS, ANON_PERMISSIONS, USER_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
@ -102,7 +99,7 @@ def get_user_project_permissions(user, project, cache="user"):
if user.is_superuser:
admins_permissions = list(map(lambda perm: perm[0], ADMINS_PERMISSIONS))
members_permissions = list(map(lambda perm: perm[0], MEMBERS_PERMISSIONS))
public_permissions = list(map(lambda perm: perm[0], USER_PERMISSIONS))
public_permissions = []
anon_permissions = list(map(lambda perm: perm[0], ANON_PERMISSIONS))
elif membership:
if membership.is_admin:

View File

@ -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

View File

@ -1,56 +1,56 @@
[
{
"model": "projects.projecttemplate",
"pk": 1,
"fields": {
"is_issues_activated": true,
"task_statuses": "[{\"color\": \"#999999\", \"order\": 1, \"is_closed\": false, \"name\": \"New\", \"slug\": \"new\"}, {\"color\": \"#ff9900\", \"order\": 2, \"is_closed\": false, \"name\": \"In progress\", \"slug\": \"in-progress\"}, {\"color\": \"#ffcc00\", \"order\": 3, \"is_closed\": true, \"name\": \"Ready for test\", \"slug\": \"ready-for-test\"}, {\"color\": \"#669900\", \"order\": 4, \"is_closed\": true, \"name\": \"Closed\", \"slug\": \"closed\"}, {\"color\": \"#999999\", \"order\": 5, \"is_closed\": false, \"name\": \"Needs Info\", \"slug\": \"needs-info\"}]",
"is_backlog_activated": true,
"modified_date": "2014-07-25T10:02:46.479Z",
"us_statuses": "[{\"color\": \"#999999\", \"order\": 1, \"is_closed\": false, \"is_archived\": false, \"wip_limit\": null, \"name\": \"New\", \"slug\": \"new\"}, {\"color\": \"#ff8a84\", \"order\": 2, \"is_closed\": false, \"is_archived\": false, \"wip_limit\": null, \"name\": \"Ready\", \"slug\": \"ready\"}, {\"color\": \"#ff9900\", \"order\": 3, \"is_closed\": false, \"is_archived\": false, \"wip_limit\": null, \"name\": \"In progress\", \"slug\": \"in-progress\"}, {\"color\": \"#fcc000\", \"order\": 4, \"is_closed\": false, \"is_archived\": false, \"wip_limit\": null, \"name\": \"Ready for test\", \"slug\": \"ready-for-test\"}, {\"color\": \"#669900\", \"order\": 5, \"is_closed\": true, \"is_archived\": false, \"wip_limit\": null, \"name\": \"Done\", \"slug\": \"done\"}, {\"color\": \"#5c3566\", \"order\": 6, \"is_closed\": true, \"is_archived\": true, \"wip_limit\": null, \"name\": \"Archived\", \"slug\": \"archived\"}]",
"is_wiki_activated": true,
"roles": "[{\"order\": 10, \"slug\": \"ux\", \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"], \"name\": \"UX\", \"computable\": true}, {\"order\": 20, \"slug\": \"design\", \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"], \"name\": \"Design\", \"computable\": true}, {\"order\": 30, \"slug\": \"front\", \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"], \"name\": \"Front\", \"computable\": true}, {\"order\": 40, \"slug\": \"back\", \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"], \"name\": \"Back\", \"computable\": true}, {\"order\": 50, \"slug\": \"product-owner\", \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"], \"name\": \"Product Owner\", \"computable\": false}, {\"order\": 60, \"slug\": \"stakeholder\", \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"view_milestones\", \"view_project\", \"view_tasks\", \"view_us\", \"modify_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"], \"name\": \"Stakeholder\", \"computable\": false}]",
"points": "[{\"value\": null, \"order\": 1, \"name\": \"?\"}, {\"value\": 0.0, \"order\": 2, \"name\": \"0\"}, {\"value\": 0.5, \"order\": 3, \"name\": \"1/2\"}, {\"value\": 1.0, \"order\": 4, \"name\": \"1\"}, {\"value\": 2.0, \"order\": 5, \"name\": \"2\"}, {\"value\": 3.0, \"order\": 6, \"name\": \"3\"}, {\"value\": 5.0, \"order\": 7, \"name\": \"5\"}, {\"value\": 8.0, \"order\": 8, \"name\": \"8\"}, {\"value\": 10.0, \"order\": 9, \"name\": \"10\"}, {\"value\": 13.0, \"order\": 10, \"name\": \"13\"}, {\"value\": 20.0, \"order\": 11, \"name\": \"20\"}, {\"value\": 40.0, \"order\": 12, \"name\": \"40\"}]",
"severities": "[{\"color\": \"#666666\", \"order\": 1, \"name\": \"Wishlist\"}, {\"color\": \"#669933\", \"order\": 2, \"name\": \"Minor\"}, {\"color\": \"#0000FF\", \"order\": 3, \"name\": \"Normal\"}, {\"color\": \"#FFA500\", \"order\": 4, \"name\": \"Important\"}, {\"color\": \"#CC0000\", \"order\": 5, \"name\": \"Critical\"}]",
"is_kanban_activated": false,
"priorities": "[{\"color\": \"#666666\", \"order\": 1, \"name\": \"Low\"}, {\"color\": \"#669933\", \"order\": 3, \"name\": \"Normal\"}, {\"color\": \"#CC0000\", \"order\": 5, \"name\": \"High\"}]",
"created_date": "2014-04-22T14:48:43.596Z",
"default_options": "{\"us_status\": \"New\", \"task_status\": \"New\", \"priority\": \"Normal\", \"issue_type\": \"Bug\", \"severity\": \"Normal\", \"points\": \"?\", \"issue_status\": \"New\"}",
"name": "Scrum",
"slug": "scrum",
"videoconferences_extra_data": "",
"issue_statuses": "[{\"color\": \"#8C2318\", \"order\": 1, \"is_closed\": false, \"name\": \"New\", \"slug\": \"new\"}, {\"color\": \"#5E8C6A\", \"order\": 2, \"is_closed\": false, \"name\": \"In progress\", \"slug\": \"in-progress\"}, {\"color\": \"#88A65E\", \"order\": 3, \"is_closed\": true, \"name\": \"Ready for test\", \"slug\": \"ready-for-test\"}, {\"color\": \"#BFB35A\", \"order\": 4, \"is_closed\": true, \"name\": \"Closed\", \"slug\": \"closed\"}, {\"color\": \"#89BAB4\", \"order\": 5, \"is_closed\": false, \"name\": \"Needs Info\", \"slug\": \"needs-info\"}, {\"color\": \"#CC0000\", \"order\": 6, \"is_closed\": true, \"name\": \"Rejected\", \"slug\": \"rejected\"}, {\"color\": \"#666666\", \"order\": 7, \"is_closed\": false, \"name\": \"Postponed\", \"slug\": \"posponed\"}]",
"default_owner_role": "product-owner",
"issue_types": "[{\"color\": \"#89BAB4\", \"order\": 1, \"name\": \"Bug\"}, {\"color\": \"#ba89a8\", \"order\": 2, \"name\": \"Question\"}, {\"color\": \"#89a8ba\", \"order\": 3, \"name\": \"Enhancement\"}]",
"videoconferences": null,
"description": "The agile product backlog in Scrum is a prioritized features list, containing short descriptions of all functionality desired in the product. When applying Scrum, it's not necessary to start a project with a lengthy, upfront effort to document all requirements. The Scrum product backlog is then allowed to grow and change as more is learned about the product and its customers",
"name": "Scrum"
},
"pk": 1
"created_date": "2014-04-22T14:48:43.596Z",
"modified_date": "2014-07-25T10:02:46.479Z",
"default_owner_role": "product-owner",
"is_backlog_activated": true,
"is_kanban_activated": false,
"is_wiki_activated": true,
"is_issues_activated": true,
"videoconferences": null,
"videoconferences_extra_data": "",
"default_options": "{\"severity\": \"Normal\", \"priority\": \"Normal\", \"task_status\": \"New\", \"points\": \"?\", \"us_status\": \"New\", \"issue_type\": \"Bug\", \"issue_status\": \"New\"}",
"us_statuses": "[{\"is_archived\": false, \"slug\": \"new\", \"is_closed\": false, \"wip_limit\": null, \"order\": 1, \"name\": \"New\", \"color\": \"#999999\"}, {\"is_archived\": false, \"slug\": \"ready\", \"is_closed\": false, \"wip_limit\": null, \"order\": 2, \"name\": \"Ready\", \"color\": \"#ff8a84\"}, {\"is_archived\": false, \"slug\": \"in-progress\", \"is_closed\": false, \"wip_limit\": null, \"order\": 3, \"name\": \"In progress\", \"color\": \"#ff9900\"}, {\"is_archived\": false, \"slug\": \"ready-for-test\", \"is_closed\": false, \"wip_limit\": null, \"order\": 4, \"name\": \"Ready for test\", \"color\": \"#fcc000\"}, {\"is_archived\": false, \"slug\": \"done\", \"is_closed\": true, \"wip_limit\": null, \"order\": 5, \"name\": \"Done\", \"color\": \"#669900\"}, {\"is_archived\": true, \"slug\": \"archived\", \"is_closed\": true, \"wip_limit\": null, \"order\": 6, \"name\": \"Archived\", \"color\": \"#5c3566\"}]",
"points": "[{\"order\": 1, \"name\": \"?\", \"value\": null}, {\"order\": 2, \"name\": \"0\", \"value\": 0.0}, {\"order\": 3, \"name\": \"1/2\", \"value\": 0.5}, {\"order\": 4, \"name\": \"1\", \"value\": 1.0}, {\"order\": 5, \"name\": \"2\", \"value\": 2.0}, {\"order\": 6, \"name\": \"3\", \"value\": 3.0}, {\"order\": 7, \"name\": \"5\", \"value\": 5.0}, {\"order\": 8, \"name\": \"8\", \"value\": 8.0}, {\"order\": 9, \"name\": \"10\", \"value\": 10.0}, {\"order\": 10, \"name\": \"13\", \"value\": 13.0}, {\"order\": 11, \"name\": \"20\", \"value\": 20.0}, {\"order\": 12, \"name\": \"40\", \"value\": 40.0}]",
"task_statuses": "[{\"order\": 1, \"name\": \"New\", \"slug\": \"new\", \"color\": \"#999999\", \"is_closed\": false}, {\"order\": 2, \"name\": \"In progress\", \"slug\": \"in-progress\", \"color\": \"#ff9900\", \"is_closed\": false}, {\"order\": 3, \"name\": \"Ready for test\", \"slug\": \"ready-for-test\", \"color\": \"#ffcc00\", \"is_closed\": true}, {\"order\": 4, \"name\": \"Closed\", \"slug\": \"closed\", \"color\": \"#669900\", \"is_closed\": true}, {\"order\": 5, \"name\": \"Needs Info\", \"slug\": \"needs-info\", \"color\": \"#999999\", \"is_closed\": false}]",
"issue_statuses": "[{\"order\": 1, \"name\": \"New\", \"slug\": \"new\", \"color\": \"#8C2318\", \"is_closed\": false}, {\"order\": 2, \"name\": \"In progress\", \"slug\": \"in-progress\", \"color\": \"#5E8C6A\", \"is_closed\": false}, {\"order\": 3, \"name\": \"Ready for test\", \"slug\": \"ready-for-test\", \"color\": \"#88A65E\", \"is_closed\": true}, {\"order\": 4, \"name\": \"Closed\", \"slug\": \"closed\", \"color\": \"#BFB35A\", \"is_closed\": true}, {\"order\": 5, \"name\": \"Needs Info\", \"slug\": \"needs-info\", \"color\": \"#89BAB4\", \"is_closed\": false}, {\"order\": 6, \"name\": \"Rejected\", \"slug\": \"rejected\", \"color\": \"#CC0000\", \"is_closed\": true}, {\"order\": 7, \"name\": \"Postponed\", \"slug\": \"posponed\", \"color\": \"#666666\", \"is_closed\": false}]",
"issue_types": "[{\"order\": 1, \"name\": \"Bug\", \"color\": \"#89BAB4\"}, {\"order\": 2, \"name\": \"Question\", \"color\": \"#ba89a8\"}, {\"order\": 3, \"name\": \"Enhancement\", \"color\": \"#89a8ba\"}]",
"priorities": "[{\"order\": 1, \"name\": \"Low\", \"color\": \"#666666\"}, {\"order\": 3, \"name\": \"Normal\", \"color\": \"#669933\"}, {\"order\": 5, \"name\": \"High\", \"color\": \"#CC0000\"}]",
"severities": "[{\"order\": 1, \"name\": \"Wishlist\", \"color\": \"#666666\"}, {\"order\": 2, \"name\": \"Minor\", \"color\": \"#669933\"}, {\"order\": 3, \"name\": \"Normal\", \"color\": \"#0000FF\"}, {\"order\": 4, \"name\": \"Important\", \"color\": \"#FFA500\"}, {\"order\": 5, \"name\": \"Critical\", \"color\": \"#CC0000\"}]",
"roles": "[{\"order\": 10, \"name\": \"UX\", \"slug\": \"ux\", \"computable\": true, \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"]}, {\"order\": 20, \"name\": \"Design\", \"slug\": \"design\", \"computable\": true, \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"]}, {\"order\": 30, \"name\": \"Front\", \"slug\": \"front\", \"computable\": true, \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"]}, {\"order\": 40, \"name\": \"Back\", \"slug\": \"back\", \"computable\": true, \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"]}, {\"order\": 50, \"name\": \"Product Owner\", \"slug\": \"product-owner\", \"computable\": false, \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"]}, {\"order\": 60, \"name\": \"Stakeholder\", \"slug\": \"stakeholder\", \"computable\": false, \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"view_milestones\", \"view_project\", \"view_tasks\", \"view_us\", \"modify_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"]}]"
}
},
{
"model": "projects.projecttemplate",
"pk": 2,
"fields": {
"is_issues_activated": false,
"task_statuses": "[{\"color\": \"#999999\", \"order\": 1, \"is_closed\": false, \"name\": \"New\", \"slug\": \"new\"}, {\"color\": \"#729fcf\", \"order\": 2, \"is_closed\": false, \"name\": \"In progress\", \"slug\": \"in-progress\"}, {\"color\": \"#f57900\", \"order\": 3, \"is_closed\": true, \"name\": \"Ready for test\", \"slug\": \"ready-for-test\"}, {\"color\": \"#4e9a06\", \"order\": 4, \"is_closed\": true, \"name\": \"Closed\", \"slug\": \"closed\"}, {\"color\": \"#cc0000\", \"order\": 5, \"is_closed\": false, \"name\": \"Needs Info\", \"slug\": \"needs-info\"}]",
"is_backlog_activated": false,
"modified_date": "2014-07-25T13:11:42.754Z",
"us_statuses": "[{\"wip_limit\": null, \"order\": 1, \"is_closed\": false, \"is_archived\": false, \"color\": \"#999999\", \"name\": \"New\", \"slug\": \"new\"}, {\"wip_limit\": null, \"order\": 2, \"is_closed\": false, \"is_archived\": false, \"color\": \"#f57900\", \"name\": \"Ready\", \"slug\": \"ready\"}, {\"wip_limit\": null, \"order\": 3, \"is_closed\": false, \"is_archived\": false, \"color\": \"#729fcf\", \"name\": \"In progress\", \"slug\": \"in-progress\"}, {\"wip_limit\": null, \"order\": 4, \"is_closed\": false, \"is_archived\": false, \"color\": \"#4e9a06\", \"name\": \"Ready for test\", \"slug\": \"ready-for-test\"}, {\"wip_limit\": null, \"order\": 5, \"is_closed\": true, \"is_archived\": false, \"color\": \"#cc0000\", \"name\": \"Done\", \"slug\": \"done\"}, {\"wip_limit\": null, \"order\": 6, \"is_closed\": true, \"is_archived\": true, \"color\": \"#5c3566\", \"name\": \"Archived\", \"slug\": \"archived\"}]",
"is_wiki_activated": false,
"roles": "[{\"order\": 10, \"slug\": \"ux\", \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"], \"name\": \"UX\", \"computable\": true}, {\"order\": 20, \"slug\": \"design\", \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"], \"name\": \"Design\", \"computable\": true}, {\"order\": 30, \"slug\": \"front\", \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"], \"name\": \"Front\", \"computable\": true}, {\"order\": 40, \"slug\": \"back\", \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"], \"name\": \"Back\", \"computable\": true}, {\"order\": 50, \"slug\": \"product-owner\", \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"], \"name\": \"Product Owner\", \"computable\": false}, {\"order\": 60, \"slug\": \"stakeholder\", \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"view_milestones\", \"view_project\", \"view_tasks\", \"view_us\", \"modify_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"], \"name\": \"Stakeholder\", \"computable\": false}]",
"points": "[{\"value\": null, \"name\": \"?\", \"order\": 1}, {\"value\": 0.0, \"name\": \"0\", \"order\": 2}, {\"value\": 0.5, \"name\": \"1/2\", \"order\": 3}, {\"value\": 1.0, \"name\": \"1\", \"order\": 4}, {\"value\": 2.0, \"name\": \"2\", \"order\": 5}, {\"value\": 3.0, \"name\": \"3\", \"order\": 6}, {\"value\": 5.0, \"name\": \"5\", \"order\": 7}, {\"value\": 8.0, \"name\": \"8\", \"order\": 8}, {\"value\": 10.0, \"name\": \"10\", \"order\": 9}, {\"value\": 13.0, \"name\": \"13\", \"order\": 10}, {\"value\": 20.0, \"name\": \"20\", \"order\": 11}, {\"value\": 40.0, \"name\": \"40\", \"order\": 12}]",
"severities": "[{\"color\": \"#999999\", \"order\": 1, \"name\": \"Wishlist\"}, {\"color\": \"#729fcf\", \"order\": 2, \"name\": \"Minor\"}, {\"color\": \"#4e9a06\", \"order\": 3, \"name\": \"Normal\"}, {\"color\": \"#f57900\", \"order\": 4, \"name\": \"Important\"}, {\"color\": \"#CC0000\", \"order\": 5, \"name\": \"Critical\"}]",
"is_kanban_activated": true,
"priorities": "[{\"color\": \"#999999\", \"order\": 1, \"name\": \"Low\"}, {\"color\": \"#4e9a06\", \"order\": 3, \"name\": \"Normal\"}, {\"color\": \"#CC0000\", \"order\": 5, \"name\": \"High\"}]",
"created_date": "2014-04-22T14:50:19.738Z",
"default_options": "{\"us_status\": \"New\", \"task_status\": \"New\", \"priority\": \"Normal\", \"issue_type\": \"Bug\", \"severity\": \"Normal\", \"points\": \"?\", \"issue_status\": \"New\"}",
"name": "Kanban",
"slug": "kanban",
"videoconferences_extra_data": "",
"issue_statuses": "[{\"color\": \"#999999\", \"order\": 1, \"is_closed\": false, \"name\": \"New\", \"slug\": \"new\"}, {\"color\": \"#729fcf\", \"order\": 2, \"is_closed\": false, \"name\": \"In progress\", \"slug\": \"in-progress\"}, {\"color\": \"#f57900\", \"order\": 3, \"is_closed\": true, \"name\": \"Ready for test\", \"slug\": \"ready-for-test\"}, {\"color\": \"#4e9a06\", \"order\": 4, \"is_closed\": true, \"name\": \"Closed\", \"slug\": \"closed\"}, {\"color\": \"#cc0000\", \"order\": 5, \"is_closed\": false, \"name\": \"Needs Info\", \"slug\": \"needs-info\"}, {\"color\": \"#d3d7cf\", \"order\": 6, \"is_closed\": true, \"name\": \"Rejected\", \"slug\": \"rejected\"}, {\"color\": \"#75507b\", \"order\": 7, \"is_closed\": false, \"name\": \"Postponed\", \"slug\": \"posponed\"}]",
"default_owner_role": "product-owner",
"issue_types": "[{\"color\": \"#cc0000\", \"order\": 1, \"name\": \"Bug\"}, {\"color\": \"#729fcf\", \"order\": 2, \"name\": \"Question\"}, {\"color\": \"#4e9a06\", \"order\": 3, \"name\": \"Enhancement\"}]",
"videoconferences": null,
"description": "Kanban is a method for managing knowledge work with an emphasis on just-in-time delivery while not overloading the team members. In this approach, the process, from definition of a task to its delivery to the customer, is displayed for participants to see and team members pull work from a queue.",
"name": "Kanban"
},
"pk": 2
"created_date": "2014-04-22T14:50:19.738Z",
"modified_date": "2014-07-25T13:11:42.754Z",
"default_owner_role": "product-owner",
"is_backlog_activated": false,
"is_kanban_activated": true,
"is_wiki_activated": false,
"is_issues_activated": false,
"videoconferences": null,
"videoconferences_extra_data": "",
"default_options": "{\"severity\": \"Normal\", \"priority\": \"Normal\", \"task_status\": \"New\", \"points\": \"?\", \"us_status\": \"New\", \"issue_type\": \"Bug\", \"issue_status\": \"New\"}",
"us_statuses": "[{\"is_archived\": false, \"slug\": \"new\", \"is_closed\": false, \"wip_limit\": null, \"order\": 1, \"name\": \"New\", \"color\": \"#999999\"}, {\"is_archived\": false, \"slug\": \"ready\", \"is_closed\": false, \"wip_limit\": null, \"order\": 2, \"name\": \"Ready\", \"color\": \"#f57900\"}, {\"is_archived\": false, \"slug\": \"in-progress\", \"is_closed\": false, \"wip_limit\": null, \"order\": 3, \"name\": \"In progress\", \"color\": \"#729fcf\"}, {\"is_archived\": false, \"slug\": \"ready-for-test\", \"is_closed\": false, \"wip_limit\": null, \"order\": 4, \"name\": \"Ready for test\", \"color\": \"#4e9a06\"}, {\"is_archived\": false, \"slug\": \"done\", \"is_closed\": true, \"wip_limit\": null, \"order\": 5, \"name\": \"Done\", \"color\": \"#cc0000\"}, {\"is_archived\": true, \"slug\": \"archived\", \"is_closed\": true, \"wip_limit\": null, \"order\": 6, \"name\": \"Archived\", \"color\": \"#5c3566\"}]",
"points": "[{\"order\": 1, \"name\": \"?\", \"value\": null}, {\"order\": 2, \"name\": \"0\", \"value\": 0.0}, {\"order\": 3, \"name\": \"1/2\", \"value\": 0.5}, {\"order\": 4, \"name\": \"1\", \"value\": 1.0}, {\"order\": 5, \"name\": \"2\", \"value\": 2.0}, {\"order\": 6, \"name\": \"3\", \"value\": 3.0}, {\"order\": 7, \"name\": \"5\", \"value\": 5.0}, {\"order\": 8, \"name\": \"8\", \"value\": 8.0}, {\"order\": 9, \"name\": \"10\", \"value\": 10.0}, {\"order\": 10, \"name\": \"13\", \"value\": 13.0}, {\"order\": 11, \"name\": \"20\", \"value\": 20.0}, {\"order\": 12, \"name\": \"40\", \"value\": 40.0}]",
"task_statuses": "[{\"order\": 1, \"name\": \"New\", \"slug\": \"new\", \"color\": \"#999999\", \"is_closed\": false}, {\"order\": 2, \"name\": \"In progress\", \"slug\": \"in-progress\", \"color\": \"#729fcf\", \"is_closed\": false}, {\"order\": 3, \"name\": \"Ready for test\", \"slug\": \"ready-for-test\", \"color\": \"#f57900\", \"is_closed\": true}, {\"order\": 4, \"name\": \"Closed\", \"slug\": \"closed\", \"color\": \"#4e9a06\", \"is_closed\": true}, {\"order\": 5, \"name\": \"Needs Info\", \"slug\": \"needs-info\", \"color\": \"#cc0000\", \"is_closed\": false}]",
"issue_statuses": "[{\"order\": 1, \"name\": \"New\", \"slug\": \"new\", \"color\": \"#999999\", \"is_closed\": false}, {\"order\": 2, \"name\": \"In progress\", \"slug\": \"in-progress\", \"color\": \"#729fcf\", \"is_closed\": false}, {\"order\": 3, \"name\": \"Ready for test\", \"slug\": \"ready-for-test\", \"color\": \"#f57900\", \"is_closed\": true}, {\"order\": 4, \"name\": \"Closed\", \"slug\": \"closed\", \"color\": \"#4e9a06\", \"is_closed\": true}, {\"order\": 5, \"name\": \"Needs Info\", \"slug\": \"needs-info\", \"color\": \"#cc0000\", \"is_closed\": false}, {\"order\": 6, \"name\": \"Rejected\", \"slug\": \"rejected\", \"color\": \"#d3d7cf\", \"is_closed\": true}, {\"order\": 7, \"name\": \"Postponed\", \"slug\": \"posponed\", \"color\": \"#75507b\", \"is_closed\": false}]",
"issue_types": "[{\"order\": 1, \"name\": \"Bug\", \"color\": \"#cc0000\"}, {\"order\": 2, \"name\": \"Question\", \"color\": \"#729fcf\"}, {\"order\": 3, \"name\": \"Enhancement\", \"color\": \"#4e9a06\"}]",
"priorities": "[{\"order\": 1, \"name\": \"Low\", \"color\": \"#999999\"}, {\"order\": 3, \"name\": \"Normal\", \"color\": \"#4e9a06\"}, {\"order\": 5, \"name\": \"High\", \"color\": \"#CC0000\"}]",
"severities": "[{\"order\": 1, \"name\": \"Wishlist\", \"color\": \"#999999\"}, {\"order\": 2, \"name\": \"Minor\", \"color\": \"#729fcf\"}, {\"order\": 3, \"name\": \"Normal\", \"color\": \"#4e9a06\"}, {\"order\": 4, \"name\": \"Important\", \"color\": \"#f57900\"}, {\"order\": 5, \"name\": \"Critical\", \"color\": \"#CC0000\"}]",
"roles": "[{\"order\": 10, \"name\": \"UX\", \"slug\": \"ux\", \"computable\": true, \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"]}, {\"order\": 20, \"name\": \"Design\", \"slug\": \"design\", \"computable\": true, \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"]}, {\"order\": 30, \"name\": \"Front\", \"slug\": \"front\", \"computable\": true, \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"]}, {\"order\": 40, \"name\": \"Back\", \"slug\": \"back\", \"computable\": true, \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"]}, {\"order\": 50, \"name\": \"Product Owner\", \"slug\": \"product-owner\", \"computable\": false, \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"add_milestone\", \"modify_milestone\", \"delete_milestone\", \"view_milestones\", \"view_project\", \"add_task\", \"modify_task\", \"delete_task\", \"view_tasks\", \"add_us\", \"modify_us\", \"delete_us\", \"view_us\", \"add_wiki_page\", \"modify_wiki_page\", \"delete_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"]}, {\"order\": 60, \"name\": \"Stakeholder\", \"slug\": \"stakeholder\", \"computable\": false, \"permissions\": [\"add_issue\", \"modify_issue\", \"delete_issue\", \"view_issues\", \"view_milestones\", \"view_project\", \"view_tasks\", \"view_us\", \"modify_wiki_page\", \"view_wiki_pages\", \"add_wiki_link\", \"delete_wiki_link\", \"view_wiki_links\"]}]"
}
}
]

View File

@ -23,6 +23,7 @@ from taiga.base import response
from taiga.base.decorators import detail_route
from taiga.base.api import ReadOnlyListViewSet
from taiga.base.api.utils import get_object_or_404
from taiga.mdrender.service import render as mdrender
from . import permissions
from . import serializers
@ -56,42 +57,93 @@ class HistoryViewSet(ReadOnlyListViewSet):
return response.Ok(serializer.data)
@detail_route(methods=['get'])
def comment_versions(self, request, pk):
obj = self.get_object()
history_entry_id = request.QUERY_PARAMS.get('id', None)
history_entry = services.get_history_queryset_by_model_instance(obj).filter(id=history_entry_id).first()
self.check_permissions(request, 'comment_versions', history_entry)
if history_entry is None:
return response.NotFound()
history_entry.attach_user_info_to_comment_versions()
return response.Ok(history_entry.comment_versions)
@detail_route(methods=['post'])
def edit_comment(self, request, pk):
obj = self.get_object()
history_entry_id = request.QUERY_PARAMS.get('id', None)
history_entry = services.get_history_queryset_by_model_instance(obj).filter(id=history_entry_id).first()
obj = services.get_instance_from_key(history_entry.key)
comment = request.DATA.get("comment", None)
self.check_permissions(request, 'edit_comment', history_entry)
if history_entry is None:
return response.NotFound()
if comment is None:
return response.BadRequest({"error": _("comment is required")})
if history_entry.delete_comment_date or history_entry.delete_comment_user:
return response.BadRequest({"error": _("deleted comments can't be edited")})
# comment_versions can be None if there are no historic versions of the comment
comment_versions = history_entry.comment_versions or []
comment_versions.append({
"date": history_entry.created_at,
"comment": history_entry.comment,
"comment_html": history_entry.comment_html,
"user": {
"id": request.user.pk,
}
})
history_entry.edit_comment_date = timezone.now()
history_entry.comment = comment
history_entry.comment_html = mdrender(obj.project, comment)
history_entry.comment_versions = comment_versions
history_entry.save()
return response.Ok()
@detail_route(methods=['post'])
def delete_comment(self, request, pk):
obj = self.get_object()
comment_id = request.QUERY_PARAMS.get('id', None)
comment = services.get_history_queryset_by_model_instance(obj).filter(id=comment_id).first()
history_entry_id = request.QUERY_PARAMS.get('id', None)
history_entry = services.get_history_queryset_by_model_instance(obj).filter(id=history_entry_id).first()
self.check_permissions(request, 'delete_comment', comment)
self.check_permissions(request, 'delete_comment', history_entry)
if comment is None:
if history_entry is None:
return response.NotFound()
if comment.delete_comment_date or comment.delete_comment_user:
if history_entry.delete_comment_date or history_entry.delete_comment_user:
return response.BadRequest({"error": _("Comment already deleted")})
comment.delete_comment_date = timezone.now()
comment.delete_comment_user = {"pk": request.user.pk, "name": request.user.get_full_name()}
comment.save()
history_entry.delete_comment_date = timezone.now()
history_entry.delete_comment_user = {"pk": request.user.pk, "name": request.user.get_full_name()}
history_entry.save()
return response.Ok()
@detail_route(methods=['post'])
def undelete_comment(self, request, pk):
obj = self.get_object()
comment_id = request.QUERY_PARAMS.get('id', None)
comment = services.get_history_queryset_by_model_instance(obj).filter(id=comment_id).first()
history_entry_id = request.QUERY_PARAMS.get('id', None)
history_entry = services.get_history_queryset_by_model_instance(obj).filter(id=history_entry_id).first()
self.check_permissions(request, 'undelete_comment', comment)
self.check_permissions(request, 'undelete_comment', history_entry)
if comment is None:
if history_entry is None:
return response.NotFound()
if not comment.delete_comment_date and not comment.delete_comment_user:
if not history_entry.delete_comment_date and not history_entry.delete_comment_user:
return response.BadRequest({"error": _("Comment not deleted")})
comment.delete_comment_date = None
comment.delete_comment_user = None
comment.save()
history_entry.delete_comment_date = None
history_entry.delete_comment_user = None
history_entry.save()
return response.Ok()
# Just for restframework! Because it raises

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.2 on 2016-05-12 11:10
from __future__ import unicode_literals
from django.db import migrations, models
import django_pgjson.fields
class Migration(migrations.Migration):
dependencies = [
('history', '0008_auto_20150508_1028'),
]
operations = [
migrations.AddField(
model_name='historyentry',
name='comment_versions',
field=django_pgjson.fields.JsonField(blank=True, default=None, null=True),
),
migrations.AddField(
model_name='historyentry',
name='edit_comment_date',
field=models.DateTimeField(blank=True, default=None, null=True),
),
]

View File

@ -67,6 +67,10 @@ class HistoryEntry(models.Model):
delete_comment_date = models.DateTimeField(null=True, blank=True, default=None)
delete_comment_user = JsonField(null=True, blank=True, default=None)
# Historic version of comments
comment_versions = JsonField(null=True, blank=True, default=None)
edit_comment_date = models.DateTimeField(null=True, blank=True, default=None)
# Flag for mark some history entries as
# hidden. Hidden history entries are important
# for save but not important to preview.
@ -111,6 +115,20 @@ class HistoryEntry(models.Model):
self._owner = owner
self._prefetched_owner = True
def attach_user_info_to_comment_versions(self):
if not self.comment_versions:
return
from taiga.users.serializers import UserSerializer
user_ids = [v["user"]["id"] for v in self.comment_versions if "user" in v and "id" in v["user"]]
users_by_id = {u.id: u for u in get_user_model().objects.filter(id__in=user_ids)}
for version in self.comment_versions:
user = users_by_id.get(version["user"]["id"], None)
if user:
version["user"] = UserSerializer(user).data
@cached_property
def values_diff(self):
result = {}

View File

@ -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
@ -33,32 +33,41 @@ class IsCommentOwner(PermissionComponent):
return obj.user and obj.user.get("pk", "not-pk") == request.user.pk
class IsCommentProjectOwner(PermissionComponent):
class IsCommentProjectAdmin(PermissionComponent):
def check_permissions(self, request, view, obj=None):
model = get_model_from_key(obj.key)
pk = get_pk_from_key(obj.key)
project = model.objects.get(pk=pk)
return is_project_admin(request.user, project)
class UserStoryHistoryPermission(TaigaResourcePermission):
retrieve_perms = HasProjectPerm('view_project')
delete_comment_perms = IsCommentProjectOwner() | IsCommentOwner()
undelete_comment_perms = IsCommentProjectOwner() | IsCommentDeleter()
edit_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
delete_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
undelete_comment_perms = IsCommentProjectAdmin() | IsCommentDeleter()
comment_versions_perms = IsCommentProjectAdmin() | IsCommentOwner()
class TaskHistoryPermission(TaigaResourcePermission):
retrieve_perms = HasProjectPerm('view_project')
delete_comment_perms = IsCommentProjectOwner() | IsCommentOwner()
undelete_comment_perms = IsCommentProjectOwner() | IsCommentDeleter()
edit_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
delete_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
undelete_comment_perms = IsCommentProjectAdmin() | IsCommentDeleter()
comment_versions_perms = IsCommentProjectAdmin() | IsCommentOwner()
class IssueHistoryPermission(TaigaResourcePermission):
retrieve_perms = HasProjectPerm('view_project')
delete_comment_perms = IsCommentProjectOwner() | IsCommentOwner()
undelete_comment_perms = IsCommentProjectOwner() | IsCommentDeleter()
edit_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
delete_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
undelete_comment_perms = IsCommentProjectAdmin() | IsCommentDeleter()
comment_versions_perms = IsCommentProjectAdmin() | IsCommentOwner()
class WikiHistoryPermission(TaigaResourcePermission):
retrieve_perms = HasProjectPerm('view_project')
delete_comment_perms = IsCommentProjectOwner() | IsCommentOwner()
undelete_comment_perms = IsCommentProjectOwner() | IsCommentDeleter()
edit_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
delete_comment_perms = IsCommentProjectAdmin() | IsCommentOwner()
undelete_comment_perms = IsCommentProjectAdmin() | IsCommentDeleter()
comment_versions_perms = IsCommentProjectAdmin() | IsCommentOwner()

View File

@ -33,9 +33,11 @@ class HistoryEntrySerializer(serializers.ModelSerializer):
values_diff = I18NJsonField(i18n_fields=HISTORY_ENTRY_I18N_FIELDS)
user = serializers.SerializerMethodField("get_user")
delete_comment_user = JsonField()
comment_versions = JsonField()
class Meta:
model = models.HistoryEntry
exclude = ("comment_versions",)
def get_user(self, entry):
user = {"pk": None, "username": None, "name": None, "photo": None, "is_active": False}

View File

@ -91,6 +91,20 @@ def get_pk_from_key(key:str) -> object:
return pk
def get_instance_from_key(key:str) -> object:
"""
Get instance from key
"""
model = get_model_from_key(key)
pk = get_pk_from_key(key)
try:
obj = model.objects.get(pk=pk)
return obj
except model.DoesNotExist:
# Catch simultaneous DELETE request
return None
def register_values_implementation(typename:str, fn=None):
"""
Register values implementation for specified typename.

View File

@ -16,9 +16,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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
from taiga.permissions.permissions import CommentAndOrUpdatePerm
class IssuePermission(TaigaResourcePermission):
@ -26,8 +27,8 @@ class IssuePermission(TaigaResourcePermission):
global_perms = None
retrieve_perms = HasProjectPerm('view_issues')
create_perms = HasProjectPerm('add_issue')
update_perms = HasProjectPerm('modify_issue')
partial_update_perms = HasProjectPerm('modify_issue')
update_perms = CommentAndOrUpdatePerm('modify_issue', 'comment_issue')
partial_update_perms = CommentAndOrUpdatePerm('modify_issue', 'comment_issue')
destroy_perms = HasProjectPerm('delete_issue')
list_perms = AllowAny()
filters_data_perms = AllowAny()
@ -40,14 +41,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

View File

@ -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 *

View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.2 on 2016-05-19 10:58
from __future__ import unicode_literals
from django.db import migrations
import djorm_pgarray.fields
class Migration(migrations.Migration):
dependencies = [
('projects', '0040_remove_memberships_of_cancelled_users_acounts'),
]
operations = [
migrations.AlterField(
model_name='project',
name='public_permissions',
field=djorm_pgarray.fields.TextArrayField(choices=[('view_project', 'View project'), ('view_milestones', 'View milestones'), ('add_milestone', 'Add milestone'), ('modify_milestone', 'Modify milestone'), ('delete_milestone', 'Delete milestone'), ('view_us', 'View user story'), ('add_us', 'Add user story'), ('modify_us', 'Modify user story'), ('comment_us', 'Comment user story'), ('delete_us', 'Delete user story'), ('view_tasks', 'View tasks'), ('add_task', 'Add task'), ('modify_task', 'Modify task'), ('comment_task', 'Comment task'), ('delete_task', 'Delete task'), ('view_issues', 'View issues'), ('add_issue', 'Add issue'), ('modify_issue', 'Modify issue'), ('comment_issue', 'Comment issue'), ('delete_issue', 'Delete issue'), ('view_wiki_pages', 'View wiki pages'), ('add_wiki_page', 'Add wiki page'), ('modify_wiki_page', 'Modify wiki page'), ('comment_wiki_page', 'Comment wiki page'), ('delete_wiki_page', 'Delete wiki page'), ('view_wiki_links', 'View wiki links'), ('add_wiki_link', 'Add wiki link'), ('modify_wiki_link', 'Modify wiki link'), ('delete_wiki_link', 'Delete wiki link')], dbtype='text', default=[], verbose_name='user permissions'),
),
]

View File

@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.2 on 2016-05-25 09:11
from __future__ import unicode_literals
from django.db import migrations
UPDATE_PROJECTS_ANON_PERMISSIONS_SQL = """
UPDATE projects_project
SET
ANON_PERMISSIONS = array_append(ANON_PERMISSIONS, '{comment_permission}')
WHERE
'{base_permission}' = ANY(ANON_PERMISSIONS)
AND
NOT '{comment_permission}' = ANY(ANON_PERMISSIONS)
"""
UPDATE_PROJECTS_PUBLIC_PERMISSIONS_SQL = """
UPDATE projects_project
SET
PUBLIC_PERMISSIONS = array_append(PUBLIC_PERMISSIONS, '{comment_permission}')
WHERE
'{base_permission}' = ANY(PUBLIC_PERMISSIONS)
AND
NOT '{comment_permission}' = ANY(PUBLIC_PERMISSIONS)
"""
class Migration(migrations.Migration):
dependencies = [
('projects', '0041_auto_20160519_1058'),
]
operations = [
# user stories
migrations.RunSQL(UPDATE_PROJECTS_ANON_PERMISSIONS_SQL.format(
base_permission="modify_us",
comment_permission="comment_us")
),
migrations.RunSQL(UPDATE_PROJECTS_PUBLIC_PERMISSIONS_SQL.format(
base_permission="modify_us",
comment_permission="comment_us")
),
# tasks
migrations.RunSQL(UPDATE_PROJECTS_ANON_PERMISSIONS_SQL.format(
base_permission="modify_task",
comment_permission="comment_task")
),
migrations.RunSQL(UPDATE_PROJECTS_PUBLIC_PERMISSIONS_SQL.format(
base_permission="modify_task",
comment_permission="comment_task")
),
# issues
migrations.RunSQL(UPDATE_PROJECTS_ANON_PERMISSIONS_SQL.format(
base_permission="modify_issue",
comment_permission="comment_issue")
),
migrations.RunSQL(UPDATE_PROJECTS_PUBLIC_PERMISSIONS_SQL.format(
base_permission="modify_issue",
comment_permission="comment_issue")
)
]

View File

@ -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

View File

@ -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

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -15,9 +15,10 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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
from taiga.permissions.permissions import CommentAndOrUpdatePerm
class TaskPermission(TaigaResourcePermission):
@ -25,8 +26,8 @@ class TaskPermission(TaigaResourcePermission):
global_perms = None
retrieve_perms = HasProjectPerm('view_tasks')
create_perms = HasProjectPerm('add_task')
update_perms = HasProjectPerm('modify_task')
partial_update_perms = HasProjectPerm('modify_task')
update_perms = CommentAndOrUpdatePerm('modify_task', 'comment_task')
partial_update_perms = CommentAndOrUpdatePerm('modify_task', 'comment_task')
destroy_perms = HasProjectPerm('delete_task')
list_perms = AllowAny()
csv_perms = AllowAny()

View File

@ -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",

View File

@ -15,16 +15,19 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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
from taiga.permissions.permissions import CommentAndOrUpdatePerm
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')
partial_update_perms = HasProjectPerm('modify_us')
update_perms = CommentAndOrUpdatePerm('modify_us', 'comment_us')
partial_update_perms = CommentAndOrUpdatePerm('modify_us', 'comment_us')
destroy_perms = HasProjectPerm('delete_us')
list_perms = AllowAny()
filters_data_perms = AllowAny()

View File

@ -19,6 +19,8 @@ from taiga.base.api.permissions import (TaigaResourcePermission, HasProjectPerm,
IsAuthenticated, IsProjectAdmin, AllowAny,
IsSuperUser)
from taiga.permissions.permissions import CommentAndOrUpdatePerm
class WikiPagePermission(TaigaResourcePermission):
enought_perms = IsProjectAdmin() | IsSuperUser()
@ -26,8 +28,8 @@ class WikiPagePermission(TaigaResourcePermission):
retrieve_perms = HasProjectPerm('view_wiki_pages')
by_slug_perms = HasProjectPerm('view_wiki_pages')
create_perms = HasProjectPerm('add_wiki_page')
update_perms = HasProjectPerm('modify_wiki_page')
partial_update_perms = HasProjectPerm('modify_wiki_page')
update_perms = CommentAndOrUpdatePerm('modify_wiki_page', 'comment_wiki_page')
partial_update_perms = CommentAndOrUpdatePerm('modify_wiki_page', 'comment_wiki_page')
destroy_perms = HasProjectPerm('delete_wiki_page')
list_perms = AllowAny()
render_perms = AllowAny()

View File

@ -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

View File

@ -15,13 +15,17 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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')

View File

@ -44,7 +44,6 @@ def _clean_description_fields(values_diff):
def on_new_history_entry(sender, instance, created, **kwargs):
if instance._importing:
return
@ -81,6 +80,10 @@ def on_new_history_entry(sender, instance, created, **kwargs):
if instance.delete_comment_date:
extra_data["comment_deleted"] = True
# Detect edited comment
if instance.comment_versions is not None and len(instance.comment_versions)>0:
extra_data["comment_edited"] = True
created_datetime = instance.created_at
_push_to_timelines(project, user, obj, event_type, created_datetime, extra_data=extra_data)

View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.2 on 2016-05-19 10:58
from __future__ import unicode_literals
from django.db import migrations
import djorm_pgarray.fields
class Migration(migrations.Migration):
dependencies = [
('users', '0018_remove_vote_issues_in_roles_permissions_field'),
]
operations = [
migrations.AlterField(
model_name='role',
name='permissions',
field=djorm_pgarray.fields.TextArrayField(choices=[('view_project', 'View project'), ('view_milestones', 'View milestones'), ('add_milestone', 'Add milestone'), ('modify_milestone', 'Modify milestone'), ('delete_milestone', 'Delete milestone'), ('view_us', 'View user story'), ('add_us', 'Add user story'), ('modify_us', 'Modify user story'), ('comment_us', 'Comment user story'), ('delete_us', 'Delete user story'), ('view_tasks', 'View tasks'), ('add_task', 'Add task'), ('modify_task', 'Modify task'), ('comment_task', 'Comment task'), ('delete_task', 'Delete task'), ('view_issues', 'View issues'), ('add_issue', 'Add issue'), ('modify_issue', 'Modify issue'), ('comment_issue', 'Comment issue'), ('delete_issue', 'Delete issue'), ('view_wiki_pages', 'View wiki pages'), ('add_wiki_page', 'Add wiki page'), ('modify_wiki_page', 'Modify wiki page'), ('comment_wiki_page', 'Comment wiki page'), ('delete_wiki_page', 'Delete wiki page'), ('view_wiki_links', 'View wiki links'), ('add_wiki_link', 'Add wiki link'), ('modify_wiki_link', 'Modify wiki link'), ('delete_wiki_link', 'Delete wiki link')], dbtype='text', default=[], verbose_name='permissions'),
),
]

View File

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.2 on 2016-05-25 12:29
from __future__ import unicode_literals
from django.db import migrations
UPDATE_ROLES_PERMISSIONS_SQL = """
UPDATE users_role
SET
PERMISSIONS = array_append(PERMISSIONS, '{comment_permission}')
WHERE
'{base_permission}' = ANY(PERMISSIONS)
AND
NOT '{comment_permission}' = ANY(PERMISSIONS)
"""
class Migration(migrations.Migration):
dependencies = [
('users', '0019_auto_20160519_1058'),
]
operations = [
# user stories
migrations.RunSQL(UPDATE_ROLES_PERMISSIONS_SQL.format(
base_permission="modify_us",
comment_permission="comment_us")
),
# tasks
migrations.RunSQL(UPDATE_ROLES_PERMISSIONS_SQL.format(
base_permission="modify_task",
comment_permission="comment_task")
),
# issues
migrations.RunSQL(UPDATE_ROLES_PERMISSIONS_SQL.format(
base_permission="modify_issue",
comment_permission="comment_issue")
),
# issues
migrations.RunSQL(UPDATE_ROLES_PERMISSIONS_SQL.format(
base_permission="modify_issue",
comment_permission="comment_issue")
)
]

View File

@ -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

View File

@ -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):

View File

@ -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

View File

@ -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, USER_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
@ -38,11 +38,11 @@ def data():
m.public_project = f.ProjectFactory(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project1 = f.ProjectFactory(is_private=True,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project2 = f.ProjectFactory(is_private=True,
anon_permissions=[],
@ -491,9 +491,9 @@ def test_wiki_attachment_patch(client, data, data_wiki):
attachment_data = json.dumps(attachment_data)
results = helper_test_http_method(client, 'patch', public_url, attachment_data, users)
assert results == [401, 200, 200, 200, 200]
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'patch', private_url1, attachment_data, users)
assert results == [401, 200, 200, 200, 200]
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'patch', private_url2, attachment_data, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'patch', blocked_url, attachment_data, users)
@ -583,9 +583,9 @@ def test_wiki_attachment_delete(client, data, data_wiki):
]
results = helper_test_http_method(client, 'delete', public_url, None, [None, data.registered_user])
assert results == [401, 204]
assert results == [401, 403]
results = helper_test_http_method(client, 'delete', private_url1, None, [None, data.registered_user])
assert results == [401, 204]
assert results == [401, 403]
results = helper_test_http_method(client, 'delete', private_url2, None, users)
assert results == [401, 403, 403, 204]
results = helper_test_http_method(client, 'delete', blocked_url, None, users)
@ -721,7 +721,7 @@ def test_wiki_attachment_create(client, data, data_wiki):
content_type=MULTIPART_CONTENT,
after_each_request=_after_each_request_hook)
assert results == [401, 201, 201, 201, 201]
assert results == [401, 403, 403, 201, 201]
attachment_data = {"description": "test",
"object_id": data_wiki.blocked_wiki_attachment.object_id,

View File

@ -1,6 +1,11 @@
from django.core.urlresolvers import reverse
from django.utils import timezone
from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS, USER_PERMISSIONS
from taiga.base.utils import json
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
from tests import factories as f
from tests.utils import helper_test_http_method, disconnect_signals, reconnect_signals
@ -21,19 +26,19 @@ def teardown_module(module):
def data():
m = type("Models", (object,), {})
m.registered_user = f.UserFactory.create()
m.project_member_with_perms = f.UserFactory.create()
m.project_member_without_perms = f.UserFactory.create()
m.project_owner = f.UserFactory.create()
m.other_user = f.UserFactory.create()
m.registered_user = f.UserFactory.create(full_name="registered_user")
m.project_member_with_perms = f.UserFactory.create(full_name="project_member_with_perms")
m.project_member_without_perms = f.UserFactory.create(full_name="project_member_without_perms")
m.project_owner = f.UserFactory.create(full_name="project_owner")
m.other_user = f.UserFactory.create(full_name="other_user")
m.public_project = f.ProjectFactory(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project1 = f.ProjectFactory(is_private=True,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project2 = f.ProjectFactory(is_private=True,
anon_permissions=[],
@ -76,39 +81,33 @@ def data():
return m
#########################################################
## User stories
#########################################################
@pytest.fixture
def data_us(data):
m = type("Models", (object,), {})
m.public_user_story = f.UserStoryFactory(project=data.public_project, ref=1)
m.public_history_entry = f.HistoryEntryFactory.create(type=HistoryType.change,
comment="testing public",
key=make_key_from_model_object(m.public_user_story),
diff={},
user={"pk": data.project_member_with_perms.pk})
m.private_user_story1 = f.UserStoryFactory(project=data.private_project1, ref=5)
m.private_history_entry1 = f.HistoryEntryFactory.create(type=HistoryType.change,
comment="testing 1",
key=make_key_from_model_object(m.private_user_story1),
diff={},
user={"pk": data.project_member_with_perms.pk})
m.private_user_story2 = f.UserStoryFactory(project=data.private_project2, ref=9)
return m
@pytest.fixture
def data_task(data):
m = type("Models", (object,), {})
m.public_task = f.TaskFactory(project=data.public_project, ref=2)
m.private_task1 = f.TaskFactory(project=data.private_project1, ref=6)
m.private_task2 = f.TaskFactory(project=data.private_project2, ref=10)
return m
@pytest.fixture
def data_issue(data):
m = type("Models", (object,), {})
m.public_issue = f.IssueFactory(project=data.public_project, ref=3)
m.private_issue1 = f.IssueFactory(project=data.private_project1, ref=7)
m.private_issue2 = f.IssueFactory(project=data.private_project2, ref=11)
return m
@pytest.fixture
def data_wiki(data):
m = type("Models", (object,), {})
m.public_wiki = f.WikiPageFactory(project=data.public_project, slug=4)
m.private_wiki1 = f.WikiPageFactory(project=data.private_project1, slug=8)
m.private_wiki2 = f.WikiPageFactory(project=data.private_project2, slug=12)
m.private_history_entry2 = f.HistoryEntryFactory.create(type=HistoryType.change,
comment="testing 2",
key=make_key_from_model_object(m.private_user_story2),
diff={},
user={"pk": data.project_member_with_perms.pk})
return m
@ -133,6 +132,222 @@ def test_user_story_history_retrieve(client, data, data_us):
assert results == [401, 403, 403, 200, 200]
def test_user_story_action_edit_comment(client, data, data_us):
public_url = "{}?id={}".format(
reverse('userstory-history-edit-comment', kwargs={"pk": data_us.public_user_story.pk}),
data_us.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('userstory-history-edit-comment', kwargs={"pk": data_us.private_user_story1.pk}),
data_us.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('userstory-history-edit-comment', kwargs={"pk": data_us.private_user_story2.pk}),
data_us.private_history_entry2.id
)
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
data = json.dumps({"comment": "testing update comment"})
results = helper_test_http_method(client, 'post', public_url, data, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'post', private_url1, data, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'post', private_url2, data, users)
assert results == [401, 403, 403, 200, 200]
def test_user_story_action_delete_comment(client, data, data_us):
public_url = "{}?id={}".format(
reverse('userstory-history-delete-comment', kwargs={"pk": data_us.public_user_story.pk}),
data_us.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('userstory-history-delete-comment', kwargs={"pk": data_us.private_user_story1.pk}),
data_us.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('userstory-history-delete-comment', kwargs={"pk": data_us.private_user_story2.pk}),
data_us.private_history_entry2.id
)
users_and_statuses = [
(None, 401),
(data.registered_user, 403),
(data.project_member_without_perms, 403),
(data.project_member_with_perms, 200),
(data.project_owner, 200),
]
for user, status_code in users_and_statuses:
data_us.public_history_entry.delete_comment_date = None
data_us.public_history_entry.delete_comment_user = None
data_us.public_history_entry.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(public_url)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_us.private_history_entry1.delete_comment_date = None
data_us.private_history_entry1.delete_comment_user = None
data_us.private_history_entry1.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url1)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_us.private_history_entry2.delete_comment_date = None
data_us.private_history_entry2.delete_comment_user = None
data_us.private_history_entry2.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url2)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
def test_user_story_action_undelete_comment(client, data, data_us):
public_url = "{}?id={}".format(
reverse('userstory-history-undelete-comment', kwargs={"pk": data_us.public_user_story.pk}),
data_us.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('userstory-history-undelete-comment', kwargs={"pk": data_us.private_user_story1.pk}),
data_us.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('userstory-history-undelete-comment', kwargs={"pk": data_us.private_user_story2.pk}),
data_us.private_history_entry2.id
)
users_and_statuses = [
(None, 401),
(data.registered_user, 403),
(data.project_member_without_perms, 403),
(data.project_member_with_perms, 200),
(data.project_owner, 200),
]
for user, status_code in users_and_statuses:
data_us.public_history_entry.delete_comment_date = timezone.now()
data_us.public_history_entry.delete_comment_user = {"pk": data.project_member_with_perms.pk}
data_us.public_history_entry.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(public_url)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_us.private_history_entry1.delete_comment_date = timezone.now()
data_us.private_history_entry1.delete_comment_user = {"pk": data.project_member_with_perms.pk}
data_us.private_history_entry1.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url1)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_us.private_history_entry2.delete_comment_date = timezone.now()
data_us.private_history_entry2.delete_comment_user = {"pk": data.project_member_with_perms.pk}
data_us.private_history_entry2.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url2)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
def test_user_story_action_comment_versions(client, data, data_us):
public_url = "{}?id={}".format(
reverse('userstory-history-comment-versions', kwargs={"pk": data_us.public_user_story.pk}),
data_us.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('userstory-history-comment-versions', kwargs={"pk": data_us.private_user_story1.pk}),
data_us.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('userstory-history-comment-versions', kwargs={"pk": data_us.private_user_story2.pk}),
data_us.private_history_entry2.id
)
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner,
]
results = helper_test_http_method(client, 'get', public_url, None, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'get', private_url1, None, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'get', private_url2, None, users)
assert results == [401, 403, 403, 200, 200]
#########################################################
## Tasks
#########################################################
@pytest.fixture
def data_task(data):
m = type("Models", (object,), {})
m.public_task = f.TaskFactory(project=data.public_project, ref=2)
m.public_history_entry = f.HistoryEntryFactory.create(type=HistoryType.change,
comment="testing public",
key=make_key_from_model_object(m.public_task),
diff={},
user={"pk": data.project_member_with_perms.pk})
m.private_task1 = f.TaskFactory(project=data.private_project1, ref=6)
m.private_history_entry1 = f.HistoryEntryFactory.create(type=HistoryType.change,
comment="testing 1",
key=make_key_from_model_object(m.private_task1),
diff={},
user={"pk": data.project_member_with_perms.pk})
m.private_task2 = f.TaskFactory(project=data.private_project2, ref=10)
m.private_history_entry2 = f.HistoryEntryFactory.create(type=HistoryType.change,
comment="testing 2",
key=make_key_from_model_object(m.private_task2),
diff={},
user={"pk": data.project_member_with_perms.pk})
return m
def test_task_history_retrieve(client, data, data_task):
public_url = reverse('task-history-detail', kwargs={"pk": data_task.public_task.pk})
private_url1 = reverse('task-history-detail', kwargs={"pk": data_task.private_task1.pk})
@ -154,6 +369,222 @@ def test_task_history_retrieve(client, data, data_task):
assert results == [401, 403, 403, 200, 200]
def test_task_action_edit_comment(client, data, data_task):
public_url = "{}?id={}".format(
reverse('task-history-edit-comment', kwargs={"pk": data_task.public_task.pk}),
data_task.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('task-history-edit-comment', kwargs={"pk": data_task.private_task1.pk}),
data_task.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('task-history-edit-comment', kwargs={"pk": data_task.private_task2.pk}),
data_task.private_history_entry2.id
)
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
data = json.dumps({"comment": "testing update comment"})
results = helper_test_http_method(client, 'post', public_url, data, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'post', private_url1, data, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'post', private_url2, data, users)
assert results == [401, 403, 403, 200, 200]
def test_task_action_delete_comment(client, data, data_task):
public_url = "{}?id={}".format(
reverse('task-history-delete-comment', kwargs={"pk": data_task.public_task.pk}),
data_task.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('task-history-delete-comment', kwargs={"pk": data_task.private_task1.pk}),
data_task.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('task-history-delete-comment', kwargs={"pk": data_task.private_task2.pk}),
data_task.private_history_entry2.id
)
users_and_statuses = [
(None, 401),
(data.registered_user, 403),
(data.project_member_without_perms, 403),
(data.project_member_with_perms, 200),
(data.project_owner, 200),
]
for user, status_code in users_and_statuses:
data_task.public_history_entry.delete_comment_date = None
data_task.public_history_entry.delete_comment_user = None
data_task.public_history_entry.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(public_url)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_task.private_history_entry1.delete_comment_date = None
data_task.private_history_entry1.delete_comment_user = None
data_task.private_history_entry1.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url1)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_task.private_history_entry2.delete_comment_date = None
data_task.private_history_entry2.delete_comment_user = None
data_task.private_history_entry2.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url2)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
def test_task_action_undelete_comment(client, data, data_task):
public_url = "{}?id={}".format(
reverse('task-history-undelete-comment', kwargs={"pk": data_task.public_task.pk}),
data_task.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('task-history-undelete-comment', kwargs={"pk": data_task.private_task1.pk}),
data_task.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('task-history-undelete-comment', kwargs={"pk": data_task.private_task2.pk}),
data_task.private_history_entry2.id
)
users_and_statuses = [
(None, 401),
(data.registered_user, 403),
(data.project_member_without_perms, 403),
(data.project_member_with_perms, 200),
(data.project_owner, 200),
]
for user, status_code in users_and_statuses:
data_task.public_history_entry.delete_comment_date = timezone.now()
data_task.public_history_entry.delete_comment_user = {"pk": data.project_member_with_perms.pk}
data_task.public_history_entry.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(public_url)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_task.private_history_entry1.delete_comment_date = timezone.now()
data_task.private_history_entry1.delete_comment_user = {"pk": data.project_member_with_perms.pk}
data_task.private_history_entry1.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url1)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_task.private_history_entry2.delete_comment_date = timezone.now()
data_task.private_history_entry2.delete_comment_user = {"pk": data.project_member_with_perms.pk}
data_task.private_history_entry2.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url2)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
def test_task_action_comment_versions(client, data, data_task):
public_url = "{}?id={}".format(
reverse('task-history-comment-versions', kwargs={"pk": data_task.public_task.pk}),
data_task.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('task-history-comment-versions', kwargs={"pk": data_task.private_task1.pk}),
data_task.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('task-history-comment-versions', kwargs={"pk": data_task.private_task2.pk}),
data_task.private_history_entry2.id
)
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner,
]
results = helper_test_http_method(client, 'get', public_url, None, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'get', private_url1, None, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'get', private_url2, None, users)
assert results == [401, 403, 403, 200, 200]
#########################################################
## Issues
#########################################################
@pytest.fixture
def data_issue(data):
m = type("Models", (object,), {})
m.public_issue = f.IssueFactory(project=data.public_project, ref=3)
m.public_history_entry = f.HistoryEntryFactory.create(type=HistoryType.change,
comment="testing public",
key=make_key_from_model_object(m.public_issue),
diff={},
user={"pk": data.project_member_with_perms.pk})
m.private_issue1 = f.IssueFactory(project=data.private_project1, ref=7)
m.private_history_entry1 = f.HistoryEntryFactory.create(type=HistoryType.change,
comment="testing 1",
key=make_key_from_model_object(m.private_issue1),
diff={},
user={"pk": data.project_member_with_perms.pk})
m.private_issue2 = f.IssueFactory(project=data.private_project2, ref=11)
m.private_history_entry2 = f.HistoryEntryFactory.create(type=HistoryType.change,
comment="testing 2",
key=make_key_from_model_object(m.private_issue2),
diff={},
user={"pk": data.project_member_with_perms.pk})
return m
def test_issue_history_retrieve(client, data, data_issue):
public_url = reverse('issue-history-detail', kwargs={"pk": data_issue.public_issue.pk})
private_url1 = reverse('issue-history-detail', kwargs={"pk": data_issue.private_issue1.pk})
@ -175,6 +606,222 @@ def test_issue_history_retrieve(client, data, data_issue):
assert results == [401, 403, 403, 200, 200]
def test_issue_action_edit_comment(client, data, data_issue):
public_url = "{}?id={}".format(
reverse('issue-history-edit-comment', kwargs={"pk": data_issue.public_issue.pk}),
data_issue.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('issue-history-edit-comment', kwargs={"pk": data_issue.private_issue1.pk}),
data_issue.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('issue-history-edit-comment', kwargs={"pk": data_issue.private_issue2.pk}),
data_issue.private_history_entry2.id
)
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
data = json.dumps({"comment": "testing update comment"})
results = helper_test_http_method(client, 'post', public_url, data, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'post', private_url1, data, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'post', private_url2, data, users)
assert results == [401, 403, 403, 200, 200]
def test_issue_action_delete_comment(client, data, data_issue):
public_url = "{}?id={}".format(
reverse('issue-history-delete-comment', kwargs={"pk": data_issue.public_issue.pk}),
data_issue.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('issue-history-delete-comment', kwargs={"pk": data_issue.private_issue1.pk}),
data_issue.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('issue-history-delete-comment', kwargs={"pk": data_issue.private_issue2.pk}),
data_issue.private_history_entry2.id
)
users_and_statuses = [
(None, 401),
(data.registered_user, 403),
(data.project_member_without_perms, 403),
(data.project_member_with_perms, 200),
(data.project_owner, 200),
]
for user, status_code in users_and_statuses:
data_issue.public_history_entry.delete_comment_date = None
data_issue.public_history_entry.delete_comment_user = None
data_issue.public_history_entry.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(public_url)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_issue.private_history_entry1.delete_comment_date = None
data_issue.private_history_entry1.delete_comment_user = None
data_issue.private_history_entry1.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url1)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_issue.private_history_entry2.delete_comment_date = None
data_issue.private_history_entry2.delete_comment_user = None
data_issue.private_history_entry2.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url2)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
def test_issue_action_undelete_comment(client, data, data_issue):
public_url = "{}?id={}".format(
reverse('issue-history-undelete-comment', kwargs={"pk": data_issue.public_issue.pk}),
data_issue.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('issue-history-undelete-comment', kwargs={"pk": data_issue.private_issue1.pk}),
data_issue.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('issue-history-undelete-comment', kwargs={"pk": data_issue.private_issue2.pk}),
data_issue.private_history_entry2.id
)
users_and_statuses = [
(None, 401),
(data.registered_user, 403),
(data.project_member_without_perms, 403),
(data.project_member_with_perms, 200),
(data.project_owner, 200),
]
for user, status_code in users_and_statuses:
data_issue.public_history_entry.delete_comment_date = timezone.now()
data_issue.public_history_entry.delete_comment_user = {"pk": data.project_member_with_perms.pk}
data_issue.public_history_entry.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(public_url)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_issue.private_history_entry1.delete_comment_date = timezone.now()
data_issue.private_history_entry1.delete_comment_user = {"pk": data.project_member_with_perms.pk}
data_issue.private_history_entry1.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url1)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_issue.private_history_entry2.delete_comment_date = timezone.now()
data_issue.private_history_entry2.delete_comment_user = {"pk": data.project_member_with_perms.pk}
data_issue.private_history_entry2.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url2)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
def test_issue_action_comment_versions(client, data, data_issue):
public_url = "{}?id={}".format(
reverse('issue-history-comment-versions', kwargs={"pk": data_issue.public_issue.pk}),
data_issue.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('issue-history-comment-versions', kwargs={"pk": data_issue.private_issue1.pk}),
data_issue.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('issue-history-comment-versions', kwargs={"pk": data_issue.private_issue2.pk}),
data_issue.private_history_entry2.id
)
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner,
]
results = helper_test_http_method(client, 'get', public_url, None, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'get', private_url1, None, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'get', private_url2, None, users)
assert results == [401, 403, 403, 200, 200]
#########################################################
## Wiki pages
#########################################################
@pytest.fixture
def data_wiki(data):
m = type("Models", (object,), {})
m.public_wiki = f.WikiPageFactory(project=data.public_project, slug=4)
m.public_history_entry = f.HistoryEntryFactory.create(type=HistoryType.change,
comment="testing public",
key=make_key_from_model_object(m.public_wiki),
diff={},
user={"pk": data.project_member_with_perms.pk})
m.private_wiki1 = f.WikiPageFactory(project=data.private_project1, slug=8)
m.private_history_entry1 = f.HistoryEntryFactory.create(type=HistoryType.change,
comment="testing 1",
key=make_key_from_model_object(m.private_wiki1),
diff={},
user={"pk": data.project_member_with_perms.pk})
m.private_wiki2 = f.WikiPageFactory(project=data.private_project2, slug=12)
m.private_history_entry2 = f.HistoryEntryFactory.create(type=HistoryType.change,
comment="testing 2",
key=make_key_from_model_object(m.private_wiki2),
diff={},
user={"pk": data.project_member_with_perms.pk})
return m
def test_wiki_history_retrieve(client, data, data_wiki):
public_url = reverse('wiki-history-detail', kwargs={"pk": data_wiki.public_wiki.pk})
private_url1 = reverse('wiki-history-detail', kwargs={"pk": data_wiki.private_wiki1.pk})
@ -194,3 +841,189 @@ def test_wiki_history_retrieve(client, data, data_wiki):
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', private_url2, None, users)
assert results == [401, 403, 403, 200, 200]
def test_wiki_action_edit_comment(client, data, data_wiki):
public_url = "{}?id={}".format(
reverse('wiki-history-edit-comment', kwargs={"pk": data_wiki.public_wiki.pk}),
data_wiki.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('wiki-history-edit-comment', kwargs={"pk": data_wiki.private_wiki1.pk}),
data_wiki.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('wiki-history-edit-comment', kwargs={"pk": data_wiki.private_wiki2.pk}),
data_wiki.private_history_entry2.id
)
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
data = json.dumps({"comment": "testing update comment"})
results = helper_test_http_method(client, 'post', public_url, data, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'post', private_url1, data, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'post', private_url2, data, users)
assert results == [401, 403, 403, 200, 200]
def test_wiki_action_delete_comment(client, data, data_wiki):
public_url = "{}?id={}".format(
reverse('wiki-history-delete-comment', kwargs={"pk": data_wiki.public_wiki.pk}),
data_wiki.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('wiki-history-delete-comment', kwargs={"pk": data_wiki.private_wiki1.pk}),
data_wiki.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('wiki-history-delete-comment', kwargs={"pk": data_wiki.private_wiki2.pk}),
data_wiki.private_history_entry2.id
)
users_and_statuses = [
(None, 401),
(data.registered_user, 403),
(data.project_member_without_perms, 403),
(data.project_member_with_perms, 200),
(data.project_owner, 200),
]
for user, status_code in users_and_statuses:
data_wiki.public_history_entry.delete_comment_date = None
data_wiki.public_history_entry.delete_comment_user = None
data_wiki.public_history_entry.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(public_url)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_wiki.private_history_entry1.delete_comment_date = None
data_wiki.private_history_entry1.delete_comment_user = None
data_wiki.private_history_entry1.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url1)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_wiki.private_history_entry2.delete_comment_date = None
data_wiki.private_history_entry2.delete_comment_user = None
data_wiki.private_history_entry2.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url2)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
def test_wiki_action_undelete_comment(client, data, data_wiki):
public_url = "{}?id={}".format(
reverse('wiki-history-undelete-comment', kwargs={"pk": data_wiki.public_wiki.pk}),
data_wiki.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('wiki-history-undelete-comment', kwargs={"pk": data_wiki.private_wiki1.pk}),
data_wiki.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('wiki-history-undelete-comment', kwargs={"pk": data_wiki.private_wiki2.pk}),
data_wiki.private_history_entry2.id
)
users_and_statuses = [
(None, 401),
(data.registered_user, 403),
(data.project_member_without_perms, 403),
(data.project_member_with_perms, 200),
(data.project_owner, 200),
]
for user, status_code in users_and_statuses:
data_wiki.public_history_entry.delete_comment_date = timezone.now()
data_wiki.public_history_entry.delete_comment_user = {"pk": data.project_member_with_perms.pk}
data_wiki.public_history_entry.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(public_url)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_wiki.private_history_entry1.delete_comment_date = timezone.now()
data_wiki.private_history_entry1.delete_comment_user = {"pk": data.project_member_with_perms.pk}
data_wiki.private_history_entry1.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url1)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
for user, status_code in users_and_statuses:
data_wiki.private_history_entry2.delete_comment_date = timezone.now()
data_wiki.private_history_entry2.delete_comment_user = {"pk": data.project_member_with_perms.pk}
data_wiki.private_history_entry2.save()
if user:
client.login(user)
else:
client.logout()
response = client.json.post(private_url2)
error_mesage = "{} != {} for {}".format(response.status_code, status_code, user)
assert response.status_code == status_code, error_mesage
def test_wiki_action_comment_versions(client, data, data_wiki):
public_url = "{}?id={}".format(
reverse('wiki-history-comment-versions', kwargs={"pk": data_wiki.public_wiki.pk}),
data_wiki.public_history_entry.id
)
private_url1 = "{}?id={}".format(
reverse('wiki-history-comment-versions', kwargs={"pk": data_wiki.private_wiki1.pk}),
data_wiki.private_history_entry1.id
)
private_url2 = "{}?id={}".format(
reverse('wiki-history-comment-versions', kwargs={"pk": data_wiki.private_wiki2.pk}),
data_wiki.private_history_entry2.id
)
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner,
]
results = helper_test_http_method(client, 'get', public_url, None, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'get', private_url1, None, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'get', private_url2, None, users)
assert results == [401, 403, 403, 200, 200]

View File

@ -21,8 +21,8 @@ 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,
ANON_PERMISSIONS, USER_PERMISSIONS)
from taiga.permissions.choices import (MEMBERS_PERMISSIONS,
ANON_PERMISSIONS)
from tests import factories as f
from tests.utils import helper_test_http_method
@ -43,11 +43,11 @@ def data():
m.public_project = f.ProjectFactory(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project1 = f.ProjectFactory(is_private=True,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project2 = f.ProjectFactory(is_private=True,
anon_permissions=[],

View File

@ -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, USER_PERMISSIONS
from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS
from taiga.base.utils import json
from tests import factories as f
@ -39,12 +39,12 @@ def data():
m.public_project = f.ProjectFactory(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner,
issues_csv_uuid=uuid.uuid4().hex)
m.private_project1 = f.ProjectFactory(is_private=True,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner,
issues_csv_uuid=uuid.uuid4().hex)
m.private_project2 = f.ProjectFactory(is_private=True,
@ -132,6 +132,55 @@ def data():
return m
def test_issue_list(client, data):
url = reverse('issues-list')
response = client.get(url)
issues_data = json.loads(response.content.decode('utf-8'))
assert len(issues_data) == 2
assert response.status_code == 200
client.login(data.registered_user)
response = client.get(url)
issues_data = json.loads(response.content.decode('utf-8'))
assert len(issues_data) == 2
assert response.status_code == 200
client.login(data.project_member_with_perms)
response = client.get(url)
issues_data = json.loads(response.content.decode('utf-8'))
assert len(issues_data) == 4
assert response.status_code == 200
client.login(data.project_owner)
response = client.get(url)
issues_data = json.loads(response.content.decode('utf-8'))
assert len(issues_data) == 4
assert response.status_code == 200
def test_issue_list_filter_by_project_ok(client, data):
url = "{}?project={}".format(reverse("issues-list"), data.public_project.pk)
client.login(data.project_owner)
response = client.get(url)
assert response.status_code == 200
assert len(response.data) == 1
def test_issue_list_filter_by_project_error(client, data):
url = "{}?project={}".format(reverse("issues-list"), "-ERROR-")
client.login(data.project_owner)
response = client.get(url)
assert response.status_code == 400
def test_issue_retrieve(client, data):
public_url = reverse('issues-detail', kwargs={"pk": data.public_issue.pk})
private_url1 = reverse('issues-detail', kwargs={"pk": data.private_issue1.pk})
@ -156,7 +205,67 @@ def test_issue_retrieve(client, data):
assert results == [401, 403, 403, 200, 200]
def test_issue_update(client, data):
def test_issue_create(client, data):
url = reverse('issues-list')
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
create_data = json.dumps({
"subject": "test",
"ref": 1,
"project": data.public_project.pk,
"severity": data.public_project.severities.all()[0].pk,
"priority": data.public_project.priorities.all()[0].pk,
"status": data.public_project.issue_statuses.all()[0].pk,
"type": data.public_project.issue_types.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"subject": "test",
"ref": 2,
"project": data.private_project1.pk,
"severity": data.private_project1.severities.all()[0].pk,
"priority": data.private_project1.priorities.all()[0].pk,
"status": data.private_project1.issue_statuses.all()[0].pk,
"type": data.private_project1.issue_types.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"subject": "test",
"ref": 3,
"project": data.private_project2.pk,
"severity": data.private_project2.severities.all()[0].pk,
"priority": data.private_project2.priorities.all()[0].pk,
"status": data.private_project2.issue_statuses.all()[0].pk,
"type": data.private_project2.issue_types.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"subject": "test",
"ref": 3,
"project": data.blocked_project.pk,
"severity": data.blocked_project.severities.all()[0].pk,
"priority": data.blocked_project.priorities.all()[0].pk,
"status": data.blocked_project.issue_statuses.all()[0].pk,
"type": data.blocked_project.issue_types.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 451, 451]
def test_issue_put_update(client, data):
public_url = reverse('issues-detail', kwargs={"pk": data.public_issue.pk})
private_url1 = reverse('issues-detail', kwargs={"pk": data.private_issue1.pk})
private_url2 = reverse('issues-detail', kwargs={"pk": data.private_issue2.pk})
@ -171,32 +280,116 @@ def test_issue_update(client, data):
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
issue_data = IssueSerializer(data.public_issue).data
issue_data["subject"] = "test"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', public_url, issue_data, users)
assert results == [401, 403, 403, 200, 200]
issue_data = IssueSerializer(data.public_issue).data
issue_data["subject"] = "test"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', public_url, issue_data, users)
assert results == [401, 403, 403, 200, 200]
issue_data = IssueSerializer(data.private_issue1).data
issue_data["subject"] = "test"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', private_url1, issue_data, users)
assert results == [401, 403, 403, 200, 200]
issue_data = IssueSerializer(data.private_issue1).data
issue_data["subject"] = "test"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', private_url1, issue_data, users)
assert results == [401, 403, 403, 200, 200]
issue_data = IssueSerializer(data.private_issue2).data
issue_data["subject"] = "test"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', private_url2, issue_data, users)
assert results == [401, 403, 403, 200, 200]
issue_data = IssueSerializer(data.private_issue2).data
issue_data["subject"] = "test"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', private_url2, issue_data, users)
assert results == [401, 403, 403, 200, 200]
issue_data = IssueSerializer(data.blocked_issue).data
issue_data["subject"] = "test"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', blocked_url, issue_data, users)
assert results == [401, 403, 403, 451, 451]
issue_data = IssueSerializer(data.blocked_issue).data
issue_data["subject"] = "test"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', blocked_url, issue_data, users)
assert results == [401, 403, 403, 451, 451]
def test_issue_update_with_project_change(client):
def test_issue_put_comment(client, data):
public_url = reverse('issues-detail', kwargs={"pk": data.public_issue.pk})
private_url1 = reverse('issues-detail', kwargs={"pk": data.private_issue1.pk})
private_url2 = reverse('issues-detail', kwargs={"pk": data.private_issue2.pk})
blocked_url = reverse('issues-detail', kwargs={"pk": data.blocked_issue.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
issue_data = IssueSerializer(data.public_issue).data
issue_data["comment"] = "test comment"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', public_url, issue_data, users)
assert results == [401, 403, 403, 200, 200]
issue_data = IssueSerializer(data.private_issue1).data
issue_data["comment"] = "test comment"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', private_url1, issue_data, users)
assert results == [401, 403, 403, 200, 200]
issue_data = IssueSerializer(data.private_issue2).data
issue_data["comment"] = "test comment"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', private_url2, issue_data, users)
assert results == [401, 403, 403, 200, 200]
issue_data = IssueSerializer(data.blocked_issue).data
issue_data["comment"] = "test comment"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', blocked_url, issue_data, users)
assert results == [401, 403, 403, 451, 451]
def test_issue_put_update_and_comment(client, data):
public_url = reverse('issues-detail', kwargs={"pk": data.public_issue.pk})
private_url1 = reverse('issues-detail', kwargs={"pk": data.private_issue1.pk})
private_url2 = reverse('issues-detail', kwargs={"pk": data.private_issue2.pk})
blocked_url = reverse('issues-detail', kwargs={"pk": data.blocked_issue.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
issue_data = IssueSerializer(data.public_issue).data
issue_data["subject"] = "test"
issue_data["comment"] = "test comment"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', public_url, issue_data, users)
assert results == [401, 403, 403, 200, 200]
issue_data = IssueSerializer(data.private_issue1).data
issue_data["subject"] = "test"
issue_data["comment"] = "test comment"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', private_url1, issue_data, users)
assert results == [401, 403, 403, 200, 200]
issue_data = IssueSerializer(data.private_issue2).data
issue_data["subject"] = "test"
issue_data["comment"] = "test comment"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', private_url2, issue_data, users)
assert results == [401, 403, 403, 200, 200]
issue_data = IssueSerializer(data.blocked_issue).data
issue_data["subject"] = "test"
issue_data["comment"] = "test comment"
issue_data = json.dumps(issue_data)
results = helper_test_http_method(client, 'put', blocked_url, issue_data, users)
assert results == [401, 403, 403, 451, 451]
def test_issue_put_update_with_project_change(client):
user1 = f.UserFactory.create()
user2 = f.UserFactory.create()
user3 = f.UserFactory.create()
@ -309,6 +502,118 @@ def test_issue_update_with_project_change(client):
issue.save()
def test_issue_patch_update(client, data):
public_url = reverse('issues-detail', kwargs={"pk": data.public_issue.pk})
private_url1 = reverse('issues-detail', kwargs={"pk": data.private_issue1.pk})
private_url2 = reverse('issues-detail', kwargs={"pk": data.private_issue2.pk})
blocked_url = reverse('issues-detail', kwargs={"pk": data.blocked_issue.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({"subject": "test", "version": data.public_issue.version})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"subject": "test", "version": data.private_issue1.version})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"subject": "test", "version": data.private_issue2.version})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"subject": "test", "version": data.blocked_issue.version})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
def test_issue_patch_comment(client, data):
public_url = reverse('issues-detail', kwargs={"pk": data.public_issue.pk})
private_url1 = reverse('issues-detail', kwargs={"pk": data.private_issue1.pk})
private_url2 = reverse('issues-detail', kwargs={"pk": data.private_issue2.pk})
blocked_url = reverse('issues-detail', kwargs={"pk": data.blocked_issue.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({"comment": "test comment", "version": data.public_issue.version})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"comment": "test comment", "version": data.private_issue1.version})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"comment": "test comment", "version": data.private_issue2.version})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"comment": "test comment", "version": data.blocked_issue.version})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
def test_issue_patch_update_and_comment(client, data):
public_url = reverse('issues-detail', kwargs={"pk": data.public_issue.pk})
private_url1 = reverse('issues-detail', kwargs={"pk": data.private_issue1.pk})
private_url2 = reverse('issues-detail', kwargs={"pk": data.private_issue2.pk})
blocked_url = reverse('issues-detail', kwargs={"pk": data.blocked_issue.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({
"subject": "test",
"comment": "test comment",
"version": data.public_issue.version
})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({
"subject": "test",
"comment": "test comment",
"version": data.private_issue1.version
})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({
"subject": "test",
"comment": "test comment",
"version": data.private_issue2.version
})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({
"subject": "test",
"comment": "test comment",
"version": data.blocked_issue.version
})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
def test_issue_delete(client, data):
public_url = reverse('issues-detail', kwargs={"pk": data.public_issue.pk})
private_url1 = reverse('issues-detail', kwargs={"pk": data.private_issue1.pk})
@ -332,148 +637,7 @@ def test_issue_delete(client, data):
assert results == [401, 403, 403, 451]
def test_issue_list(client, data):
url = reverse('issues-list')
response = client.get(url)
issues_data = json.loads(response.content.decode('utf-8'))
assert len(issues_data) == 2
assert response.status_code == 200
client.login(data.registered_user)
response = client.get(url)
issues_data = json.loads(response.content.decode('utf-8'))
assert len(issues_data) == 2
assert response.status_code == 200
client.login(data.project_member_with_perms)
response = client.get(url)
issues_data = json.loads(response.content.decode('utf-8'))
assert len(issues_data) == 4
assert response.status_code == 200
client.login(data.project_owner)
response = client.get(url)
issues_data = json.loads(response.content.decode('utf-8'))
assert len(issues_data) == 4
assert response.status_code == 200
def test_issue_list_filter_by_project_ok(client, data):
url = "{}?project={}".format(reverse("issues-list"), data.public_project.pk)
client.login(data.project_owner)
response = client.get(url)
assert response.status_code == 200
assert len(response.data) == 1
def test_issue_list_filter_by_project_error(client, data):
url = "{}?project={}".format(reverse("issues-list"), "-ERROR-")
client.login(data.project_owner)
response = client.get(url)
assert response.status_code == 400
def test_issue_create(client, data):
url = reverse('issues-list')
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
create_data = json.dumps({
"subject": "test",
"ref": 1,
"project": data.public_project.pk,
"severity": data.public_project.severities.all()[0].pk,
"priority": data.public_project.priorities.all()[0].pk,
"status": data.public_project.issue_statuses.all()[0].pk,
"type": data.public_project.issue_types.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 201, 201, 201, 201]
create_data = json.dumps({
"subject": "test",
"ref": 2,
"project": data.private_project1.pk,
"severity": data.private_project1.severities.all()[0].pk,
"priority": data.private_project1.priorities.all()[0].pk,
"status": data.private_project1.issue_statuses.all()[0].pk,
"type": data.private_project1.issue_types.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 201, 201, 201, 201]
create_data = json.dumps({
"subject": "test",
"ref": 3,
"project": data.private_project2.pk,
"severity": data.private_project2.severities.all()[0].pk,
"priority": data.private_project2.priorities.all()[0].pk,
"status": data.private_project2.issue_statuses.all()[0].pk,
"type": data.private_project2.issue_types.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"subject": "test",
"ref": 3,
"project": data.blocked_project.pk,
"severity": data.blocked_project.severities.all()[0].pk,
"priority": data.blocked_project.priorities.all()[0].pk,
"status": data.blocked_project.issue_statuses.all()[0].pk,
"type": data.blocked_project.issue_types.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 451, 451]
def test_issue_patch(client, data):
public_url = reverse('issues-detail', kwargs={"pk": data.public_issue.pk})
private_url1 = reverse('issues-detail', kwargs={"pk": data.private_issue1.pk})
private_url2 = reverse('issues-detail', kwargs={"pk": data.private_issue2.pk})
blocked_url = reverse('issues-detail', kwargs={"pk": data.blocked_issue.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({"subject": "test", "version": data.public_issue.version})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"subject": "test", "version": data.private_issue1.version})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"subject": "test", "version": data.private_issue2.version})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"subject": "test", "version": data.blocked_issue.version})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
def test_issue_bulk_create(client, data):
def test_issue_action_bulk_create(client, data):
data.public_issue.project.default_issue_status = f.IssueStatusFactory()
data.public_issue.project.default_issue_type = f.IssueTypeFactory()
data.public_issue.project.default_priority = f.PriorityFactory()
@ -511,12 +675,12 @@ def test_issue_bulk_create(client, data):
bulk_data = json.dumps({"bulk_issues": "test1\ntest2",
"project_id": data.public_issue.project.pk})
results = helper_test_http_method(client, 'post', url, bulk_data, users)
assert results == [401, 200, 200, 200, 200]
assert results == [401, 403, 403, 200, 200]
bulk_data = json.dumps({"bulk_issues": "test1\ntest2",
"project_id": data.private_issue1.project.pk})
results = helper_test_http_method(client, 'post', url, bulk_data, users)
assert results == [401, 200, 200, 200, 200]
assert results == [401, 403, 403, 200, 200]
bulk_data = json.dumps({"bulk_issues": "test1\ntest2",
"project_id": data.private_issue2.project.pk})
@ -633,34 +797,6 @@ def test_issue_voters_retrieve(client, data):
assert results == [401, 403, 403, 200, 200]
def test_issues_csv(client, data):
url = reverse('issues-csv')
csv_public_uuid = data.public_project.issues_csv_uuid
csv_private1_uuid = data.private_project1.issues_csv_uuid
csv_private2_uuid = data.private_project2.issues_csv_uuid
csv_blocked_uuid = data.blocked_project.issues_csv_uuid
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_public_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_private1_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_private2_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_blocked_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
def test_issue_action_watch(client, data):
public_url = reverse('issues-watch', kwargs={"pk": data.public_issue.pk})
private_url1 = reverse('issues-watch', kwargs={"pk": data.private_issue1.pk})
@ -762,3 +898,31 @@ def test_issue_watchers_retrieve(client, data):
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'get', blocked_url, None, users)
assert results == [401, 403, 403, 200, 200]
def test_issues_csv(client, data):
url = reverse('issues-csv')
csv_public_uuid = data.public_project.issues_csv_uuid
csv_private1_uuid = data.private_project1.issues_csv_uuid
csv_private2_uuid = data.private_project2.issues_csv_uuid
csv_blocked_uuid = data.blocked_project.issues_csv_uuid
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_public_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_private1_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_private2_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_blocked_uuid), None, users)
assert results == [200, 200, 200, 200, 200]

View File

@ -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, USER_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
@ -35,11 +35,11 @@ def data():
m.public_project = f.ProjectFactory(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project1 = f.ProjectFactory(is_private=True,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project2 = f.ProjectFactory(is_private=True,
anon_permissions=[],

View File

@ -2,7 +2,7 @@ import uuid
from django.core.urlresolvers import reverse
from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS, USER_PERMISSIONS
from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS
from taiga.base.utils import json
from tests import factories as f
@ -38,11 +38,11 @@ def data():
m.public_project = f.ProjectFactory(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project1 = f.ProjectFactory(is_private=True,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project2 = f.ProjectFactory(is_private=True,
anon_permissions=[],

View File

@ -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

View File

@ -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

View File

@ -1,6 +1,6 @@
from django.core.urlresolvers import reverse
from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS, USER_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
@ -29,12 +29,12 @@ def data():
m.public_project = f.ProjectFactory(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner,
slug="public")
m.private_project1 = f.ProjectFactory(is_private=True,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner,
slug="private1")
m.private_project2 = f.ProjectFactory(is_private=True,

View File

@ -1,6 +1,6 @@
from django.core.urlresolvers import reverse
from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS, USER_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
@ -29,11 +29,11 @@ def data():
m.public_project = f.ProjectFactory(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project1 = f.ProjectFactory(is_private=True,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project2 = f.ProjectFactory(is_private=True,
anon_permissions=[],

View File

@ -21,8 +21,8 @@ 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,
ANON_PERMISSIONS, USER_PERMISSIONS)
from taiga.permissions.choices import (MEMBERS_PERMISSIONS,
ANON_PERMISSIONS)
from tests import factories as f
from tests.utils import helper_test_http_method
@ -43,11 +43,11 @@ def data():
m.public_project = f.ProjectFactory(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project1 = f.ProjectFactory(is_private=True,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project2 = f.ProjectFactory(is_private=True,
anon_permissions=[],

View File

@ -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, USER_PERMISSIONS
from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS
from taiga.projects.occ import OCCResourceMixin
from tests import factories as f
@ -39,12 +39,12 @@ def data():
m.public_project = f.ProjectFactory(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner,
tasks_csv_uuid=uuid.uuid4().hex)
m.private_project1 = f.ProjectFactory(is_private=True,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner,
tasks_csv_uuid=uuid.uuid4().hex)
m.private_project2 = f.ProjectFactory(is_private=True,
@ -142,6 +142,36 @@ def data():
return m
def test_task_list(client, data):
url = reverse('tasks-list')
response = client.get(url)
tasks_data = json.loads(response.content.decode('utf-8'))
assert len(tasks_data) == 2
assert response.status_code == 200
client.login(data.registered_user)
response = client.get(url)
tasks_data = json.loads(response.content.decode('utf-8'))
assert len(tasks_data) == 2
assert response.status_code == 200
client.login(data.project_member_with_perms)
response = client.get(url)
tasks_data = json.loads(response.content.decode('utf-8'))
assert len(tasks_data) == 4
assert response.status_code == 200
client.login(data.project_owner)
response = client.get(url)
tasks_data = json.loads(response.content.decode('utf-8'))
assert len(tasks_data) == 4
assert response.status_code == 200
def test_task_retrieve(client, data):
public_url = reverse('tasks-detail', kwargs={"pk": data.public_task.pk})
private_url1 = reverse('tasks-detail', kwargs={"pk": data.private_task1.pk})
@ -166,7 +196,55 @@ def test_task_retrieve(client, data):
assert results == [401, 403, 403, 200, 200]
def test_task_update(client, data):
def test_task_create(client, data):
url = reverse('tasks-list')
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
create_data = json.dumps({
"subject": "test",
"ref": 1,
"project": data.public_project.pk,
"status": data.public_project.task_statuses.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"subject": "test",
"ref": 2,
"project": data.private_project1.pk,
"status": data.private_project1.task_statuses.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"subject": "test",
"ref": 3,
"project": data.private_project2.pk,
"status": data.private_project2.task_statuses.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"subject": "test",
"ref": 3,
"project": data.blocked_project.pk,
"status": data.blocked_project.task_statuses.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 451, 451]
def test_task_put_update(client, data):
public_url = reverse('tasks-detail', kwargs={"pk": data.public_task.pk})
private_url1 = reverse('tasks-detail', kwargs={"pk": data.private_task1.pk})
private_url2 = reverse('tasks-detail', kwargs={"pk": data.private_task2.pk})
@ -181,32 +259,116 @@ def test_task_update(client, data):
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
task_data = TaskSerializer(data.public_task).data
task_data["subject"] = "test"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', public_url, task_data, users)
assert results == [401, 403, 403, 200, 200]
task_data = TaskSerializer(data.public_task).data
task_data["subject"] = "test"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', public_url, task_data, users)
assert results == [401, 403, 403, 200, 200]
task_data = TaskSerializer(data.private_task1).data
task_data["subject"] = "test"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', private_url1, task_data, users)
assert results == [401, 403, 403, 200, 200]
task_data = TaskSerializer(data.private_task1).data
task_data["subject"] = "test"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', private_url1, task_data, users)
assert results == [401, 403, 403, 200, 200]
task_data = TaskSerializer(data.private_task2).data
task_data["subject"] = "test"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', private_url2, task_data, users)
assert results == [401, 403, 403, 200, 200]
task_data = TaskSerializer(data.private_task2).data
task_data["subject"] = "test"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', private_url2, task_data, users)
assert results == [401, 403, 403, 200, 200]
task_data = TaskSerializer(data.blocked_task).data
task_data["subject"] = "test"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', blocked_url, task_data, users)
assert results == [401, 403, 403, 451, 451]
task_data = TaskSerializer(data.blocked_task).data
task_data["subject"] = "test"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', blocked_url, task_data, users)
assert results == [401, 403, 403, 451, 451]
def test_task_update_with_project_change(client):
def test_task_put_comment(client, data):
public_url = reverse('tasks-detail', kwargs={"pk": data.public_task.pk})
private_url1 = reverse('tasks-detail', kwargs={"pk": data.private_task1.pk})
private_url2 = reverse('tasks-detail', kwargs={"pk": data.private_task2.pk})
blocked_url = reverse('tasks-detail', kwargs={"pk": data.blocked_task.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
task_data = TaskSerializer(data.public_task).data
task_data["comment"] = "test comment"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', public_url, task_data, users)
assert results == [401, 403, 403, 200, 200]
task_data = TaskSerializer(data.private_task1).data
task_data["comment"] = "test comment"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', private_url1, task_data, users)
assert results == [401, 403, 403, 200, 200]
task_data = TaskSerializer(data.private_task2).data
task_data["comment"] = "test comment"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', private_url2, task_data, users)
assert results == [401, 403, 403, 200, 200]
task_data = TaskSerializer(data.blocked_task).data
task_data["comment"] = "test comment"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', blocked_url, task_data, users)
assert results == [401, 403, 403, 451, 451]
def test_task_put_update_and_comment(client, data):
public_url = reverse('tasks-detail', kwargs={"pk": data.public_task.pk})
private_url1 = reverse('tasks-detail', kwargs={"pk": data.private_task1.pk})
private_url2 = reverse('tasks-detail', kwargs={"pk": data.private_task2.pk})
blocked_url = reverse('tasks-detail', kwargs={"pk": data.blocked_task.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
task_data = TaskSerializer(data.public_task).data
task_data["subject"] = "test"
task_data["comment"] = "test comment"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', public_url, task_data, users)
assert results == [401, 403, 403, 200, 200]
task_data = TaskSerializer(data.private_task1).data
task_data["subject"] = "test"
task_data["comment"] = "test comment"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', private_url1, task_data, users)
assert results == [401, 403, 403, 200, 200]
task_data = TaskSerializer(data.private_task2).data
task_data["subject"] = "test"
task_data["comment"] = "test comment"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', private_url2, task_data, users)
assert results == [401, 403, 403, 200, 200]
task_data = TaskSerializer(data.blocked_task).data
task_data["subject"] = "test"
task_data["comment"] = "test comment"
task_data = json.dumps(task_data)
results = helper_test_http_method(client, 'put', blocked_url, task_data, users)
assert results == [401, 403, 403, 451, 451]
def test_task_put_update_with_project_change(client):
user1 = f.UserFactory.create()
user2 = f.UserFactory.create()
user3 = f.UserFactory.create()
@ -301,107 +463,7 @@ def test_task_update_with_project_change(client):
task.save()
def test_task_delete(client, data):
public_url = reverse('tasks-detail', kwargs={"pk": data.public_task.pk})
private_url1 = reverse('tasks-detail', kwargs={"pk": data.private_task1.pk})
private_url2 = reverse('tasks-detail', kwargs={"pk": data.private_task2.pk})
blocked_url = reverse('tasks-detail', kwargs={"pk": data.blocked_task.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
]
results = helper_test_http_method(client, 'delete', public_url, None, users)
assert results == [401, 403, 403, 204]
results = helper_test_http_method(client, 'delete', private_url1, None, users)
assert results == [401, 403, 403, 204]
results = helper_test_http_method(client, 'delete', private_url2, None, users)
assert results == [401, 403, 403, 204]
results = helper_test_http_method(client, 'delete', blocked_url, None, users)
assert results == [401, 403, 403, 451]
def test_task_list(client, data):
url = reverse('tasks-list')
response = client.get(url)
tasks_data = json.loads(response.content.decode('utf-8'))
assert len(tasks_data) == 2
assert response.status_code == 200
client.login(data.registered_user)
response = client.get(url)
tasks_data = json.loads(response.content.decode('utf-8'))
assert len(tasks_data) == 2
assert response.status_code == 200
client.login(data.project_member_with_perms)
response = client.get(url)
tasks_data = json.loads(response.content.decode('utf-8'))
assert len(tasks_data) == 4
assert response.status_code == 200
client.login(data.project_owner)
response = client.get(url)
tasks_data = json.loads(response.content.decode('utf-8'))
assert len(tasks_data) == 4
assert response.status_code == 200
def test_task_create(client, data):
url = reverse('tasks-list')
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
create_data = json.dumps({
"subject": "test",
"ref": 1,
"project": data.public_project.pk,
"status": data.public_project.task_statuses.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"subject": "test",
"ref": 2,
"project": data.private_project1.pk,
"status": data.private_project1.task_statuses.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"subject": "test",
"ref": 3,
"project": data.private_project2.pk,
"status": data.private_project2.task_statuses.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"subject": "test",
"ref": 3,
"project": data.blocked_project.pk,
"status": data.blocked_project.task_statuses.all()[0].pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 451, 451]
def test_task_patch(client, data):
def test_task_patch_update(client, data):
public_url = reverse('tasks-detail', kwargs={"pk": data.public_task.pk})
private_url1 = reverse('tasks-detail', kwargs={"pk": data.private_task1.pk})
private_url2 = reverse('tasks-detail', kwargs={"pk": data.private_task2.pk})
@ -433,6 +495,108 @@ def test_task_patch(client, data):
assert results == [401, 403, 403, 451, 451]
def test_task_patch_comment(client, data):
public_url = reverse('tasks-detail', kwargs={"pk": data.public_task.pk})
private_url1 = reverse('tasks-detail', kwargs={"pk": data.private_task1.pk})
private_url2 = reverse('tasks-detail', kwargs={"pk": data.private_task2.pk})
blocked_url = reverse('tasks-detail', kwargs={"pk": data.blocked_task.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({"comment": "test comment", "version": data.public_task.version})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"comment": "test comment", "version": data.private_task1.version})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"comment": "test comment", "version": data.private_task2.version})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"comment": "test comment", "version": data.blocked_task.version})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
def test_task_patch_update_and_comment(client, data):
public_url = reverse('tasks-detail', kwargs={"pk": data.public_task.pk})
private_url1 = reverse('tasks-detail', kwargs={"pk": data.private_task1.pk})
private_url2 = reverse('tasks-detail', kwargs={"pk": data.private_task2.pk})
blocked_url = reverse('tasks-detail', kwargs={"pk": data.blocked_task.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({
"subject": "test",
"comment": "test comment",
"version": data.public_task.version
})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({
"subject": "test",
"comment": "test comment",
"version": data.private_task1.version
})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({
"subject": "test",
"comment": "test comment",
"version": data.private_task2.version
})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({
"subject": "test",
"comment": "test comment",
"version": data.blocked_task.version
})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
def test_task_delete(client, data):
public_url = reverse('tasks-detail', kwargs={"pk": data.public_task.pk})
private_url1 = reverse('tasks-detail', kwargs={"pk": data.private_task1.pk})
private_url2 = reverse('tasks-detail', kwargs={"pk": data.private_task2.pk})
blocked_url = reverse('tasks-detail', kwargs={"pk": data.blocked_task.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
]
results = helper_test_http_method(client, 'delete', public_url, None, users)
assert results == [401, 403, 403, 204]
results = helper_test_http_method(client, 'delete', private_url1, None, users)
assert results == [401, 403, 403, 204]
results = helper_test_http_method(client, 'delete', private_url2, None, users)
assert results == [401, 403, 403, 204]
results = helper_test_http_method(client, 'delete', blocked_url, None, users)
assert results == [401, 403, 403, 451]
def test_task_action_bulk_create(client, data):
url = reverse('tasks-bulk-create')
@ -586,34 +750,6 @@ def test_task_voters_retrieve(client, data):
assert results == [401, 403, 403, 200, 200]
def test_tasks_csv(client, data):
url = reverse('tasks-csv')
csv_public_uuid = data.public_project.tasks_csv_uuid
csv_private1_uuid = data.private_project1.tasks_csv_uuid
csv_private2_uuid = data.private_project1.tasks_csv_uuid
csv_blocked_uuid = data.blocked_project.tasks_csv_uuid
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_public_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_private1_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_private2_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_blocked_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
def test_task_action_watch(client, data):
public_url = reverse('tasks-watch', kwargs={"pk": data.public_task.pk})
private_url1 = reverse('tasks-watch', kwargs={"pk": data.private_task1.pk})
@ -716,3 +852,31 @@ def test_task_watchers_retrieve(client, data):
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'get', blocked_url, None, users)
assert results == [401, 403, 403, 200, 200]
def test_tasks_csv(client, data):
url = reverse('tasks-csv')
csv_public_uuid = data.public_project.tasks_csv_uuid
csv_private1_uuid = data.private_project1.tasks_csv_uuid
csv_private2_uuid = data.private_project1.tasks_csv_uuid
csv_blocked_uuid = data.blocked_project.tasks_csv_uuid
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_public_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_private1_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_private2_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_blocked_uuid), None, users)
assert results == [200, 200, 200, 200, 200]

View File

@ -1,6 +1,6 @@
from django.core.urlresolvers import reverse
from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS, USER_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
@ -29,11 +29,11 @@ def data():
m.public_project = f.ProjectFactory(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project1 = f.ProjectFactory(is_private=True,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project2 = f.ProjectFactory(is_private=True,
anon_permissions=[],

View File

@ -21,8 +21,8 @@ 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,
ANON_PERMISSIONS, USER_PERMISSIONS)
from taiga.permissions.choices import (MEMBERS_PERMISSIONS,
ANON_PERMISSIONS)
from tests import factories as f
@ -44,11 +44,11 @@ def data():
m.public_project = f.ProjectFactory(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project1 = f.ProjectFactory(is_private=True,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project2 = f.ProjectFactory(is_private=True,
anon_permissions=[],

View File

@ -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, USER_PERMISSIONS
from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS
from taiga.projects.occ import OCCResourceMixin
from tests import factories as f
@ -39,12 +39,12 @@ def data():
m.public_project = f.ProjectFactory(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner,
userstories_csv_uuid=uuid.uuid4().hex)
m.private_project1 = f.ProjectFactory(is_private=True,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner,
userstories_csv_uuid=uuid.uuid4().hex)
m.private_project2 = f.ProjectFactory(is_private=True,
@ -138,6 +138,36 @@ def data():
return m
def test_user_story_list(client, data):
url = reverse('userstories-list')
response = client.get(url)
userstories_data = json.loads(response.content.decode('utf-8'))
assert len(userstories_data) == 2
assert response.status_code == 200
client.login(data.registered_user)
response = client.get(url)
userstories_data = json.loads(response.content.decode('utf-8'))
assert len(userstories_data) == 2
assert response.status_code == 200
client.login(data.project_member_with_perms)
response = client.get(url)
userstories_data = json.loads(response.content.decode('utf-8'))
assert len(userstories_data) == 4
assert response.status_code == 200
client.login(data.project_owner)
response = client.get(url)
userstories_data = json.loads(response.content.decode('utf-8'))
assert len(userstories_data) == 4
assert response.status_code == 200
def test_user_story_retrieve(client, data):
public_url = reverse('userstories-detail', kwargs={"pk": data.public_user_story.pk})
private_url1 = reverse('userstories-detail', kwargs={"pk": data.private_user_story1.pk})
@ -162,7 +192,35 @@ def test_user_story_retrieve(client, data):
assert results == [401, 403, 403, 200, 200]
def test_user_story_update(client, data):
def test_user_story_create(client, data):
url = reverse('userstories-list')
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
create_data = json.dumps({"subject": "test", "ref": 1, "project": data.public_project.pk})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({"subject": "test", "ref": 2, "project": data.private_project1.pk})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({"subject": "test", "ref": 3, "project": data.private_project2.pk})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({"subject": "test", "ref": 4, "project": data.blocked_project.pk})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 451, 451]
def test_user_story_put_update(client, data):
public_url = reverse('userstories-detail', kwargs={"pk": data.public_user_story.pk})
private_url1 = reverse('userstories-detail', kwargs={"pk": data.private_user_story1.pk})
private_url2 = reverse('userstories-detail', kwargs={"pk": data.private_user_story2.pk})
@ -177,31 +235,116 @@ def test_user_story_update(client, data):
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
user_story_data = UserStorySerializer(data.public_user_story).data
user_story_data["subject"] = "test"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', public_url, user_story_data, users)
assert results == [401, 403, 403, 200, 200]
user_story_data = UserStorySerializer(data.public_user_story).data
user_story_data["subject"] = "test"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', public_url, user_story_data, users)
assert results == [401, 403, 403, 200, 200]
user_story_data = UserStorySerializer(data.private_user_story1).data
user_story_data["subject"] = "test"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', private_url1, user_story_data, users)
assert results == [401, 403, 403, 200, 200]
user_story_data = UserStorySerializer(data.private_user_story1).data
user_story_data["subject"] = "test"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', private_url1, user_story_data, users)
assert results == [401, 403, 403, 200, 200]
user_story_data = UserStorySerializer(data.private_user_story2).data
user_story_data["subject"] = "test"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', private_url2, user_story_data, users)
assert results == [401, 403, 403, 200, 200]
user_story_data = UserStorySerializer(data.private_user_story2).data
user_story_data["subject"] = "test"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', private_url2, user_story_data, users)
assert results == [401, 403, 403, 200, 200]
user_story_data = UserStorySerializer(data.blocked_user_story).data
user_story_data["subject"] = "test"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', blocked_url, user_story_data, users)
assert results == [401, 403, 403, 451, 451]
user_story_data = UserStorySerializer(data.blocked_user_story).data
user_story_data["subject"] = "test"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', blocked_url, user_story_data, users)
assert results == [401, 403, 403, 451, 451]
def test_user_story_update_with_project_change(client):
def test_user_story_put_comment(client, data):
public_url = reverse('userstories-detail', kwargs={"pk": data.public_user_story.pk})
private_url1 = reverse('userstories-detail', kwargs={"pk": data.private_user_story1.pk})
private_url2 = reverse('userstories-detail', kwargs={"pk": data.private_user_story2.pk})
blocked_url = reverse('userstories-detail', kwargs={"pk": data.blocked_user_story.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
user_story_data = UserStorySerializer(data.public_user_story).data
user_story_data["comment"] = "test comment"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', public_url, user_story_data, users)
assert results == [401, 403, 403, 200, 200]
user_story_data = UserStorySerializer(data.private_user_story1).data
user_story_data["comment"] = "test comment"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', private_url1, user_story_data, users)
assert results == [401, 403, 403, 200, 200]
user_story_data = UserStorySerializer(data.private_user_story2).data
user_story_data["comment"] = "test comment"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', private_url2, user_story_data, users)
assert results == [401, 403, 403, 200, 200]
user_story_data = UserStorySerializer(data.blocked_user_story).data
user_story_data["comment"] = "test comment"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', blocked_url, user_story_data, users)
assert results == [401, 403, 403, 451, 451]
def test_user_story_put_update_and_comment(client, data):
public_url = reverse('userstories-detail', kwargs={"pk": data.public_user_story.pk})
private_url1 = reverse('userstories-detail', kwargs={"pk": data.private_user_story1.pk})
private_url2 = reverse('userstories-detail', kwargs={"pk": data.private_user_story2.pk})
blocked_url = reverse('userstories-detail', kwargs={"pk": data.blocked_user_story.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
user_story_data = UserStorySerializer(data.public_user_story).data
user_story_data["subject"] = "test"
user_story_data["comment"] = "test comment"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', public_url, user_story_data, users)
assert results == [401, 403, 403, 200, 200]
user_story_data = UserStorySerializer(data.private_user_story1).data
user_story_data["subject"] = "test"
user_story_data["comment"] = "test comment"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', private_url1, user_story_data, users)
assert results == [401, 403, 403, 200, 200]
user_story_data = UserStorySerializer(data.private_user_story2).data
user_story_data["subject"] = "test"
user_story_data["comment"] = "test comment"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', private_url2, user_story_data, users)
assert results == [401, 403, 403, 200, 200]
user_story_data = UserStorySerializer(data.blocked_user_story).data
user_story_data["subject"] = "test"
user_story_data["comment"] = "test comment"
user_story_data = json.dumps(user_story_data)
results = helper_test_http_method(client, 'put', blocked_url, user_story_data, users)
assert results == [401, 403, 403, 451, 451]
def test_user_story_put_update_with_project_change(client):
user1 = f.UserFactory.create()
user2 = f.UserFactory.create()
user3 = f.UserFactory.create()
@ -296,6 +439,118 @@ def test_user_story_update_with_project_change(client):
us.save()
def test_user_story_patch_update(client, data):
public_url = reverse('userstories-detail', kwargs={"pk": data.public_user_story.pk})
private_url1 = reverse('userstories-detail', kwargs={"pk": data.private_user_story1.pk})
private_url2 = reverse('userstories-detail', kwargs={"pk": data.private_user_story2.pk})
blocked_url = reverse('userstories-detail', kwargs={"pk": data.blocked_user_story.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({"subject": "test", "version": data.public_user_story.version})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"subject": "test", "version": data.private_user_story1.version})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"subject": "test", "version": data.private_user_story2.version})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"subject": "test", "version": data.blocked_user_story.version})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
def test_user_story_patch_comment(client, data):
public_url = reverse('userstories-detail', kwargs={"pk": data.public_user_story.pk})
private_url1 = reverse('userstories-detail', kwargs={"pk": data.private_user_story1.pk})
private_url2 = reverse('userstories-detail', kwargs={"pk": data.private_user_story2.pk})
blocked_url = reverse('userstories-detail', kwargs={"pk": data.blocked_user_story.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({"comment": "test comment", "version": data.public_user_story.version})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"comment": "test comment", "version": data.private_user_story1.version})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"comment": "test comment", "version": data.private_user_story2.version})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"comment": "test comment", "version": data.blocked_user_story.version})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
def test_user_story_patch_update_and_comment(client, data):
public_url = reverse('userstories-detail', kwargs={"pk": data.public_user_story.pk})
private_url1 = reverse('userstories-detail', kwargs={"pk": data.private_user_story1.pk})
private_url2 = reverse('userstories-detail', kwargs={"pk": data.private_user_story2.pk})
blocked_url = reverse('userstories-detail', kwargs={"pk": data.blocked_user_story.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({
"subject": "test",
"comment": "test comment",
"version": data.public_user_story.version
})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({
"subject": "test",
"comment": "test comment",
"version": data.private_user_story1.version
})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({
"subject": "test",
"comment": "test comment",
"version": data.private_user_story2.version
})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({
"subject": "test",
"comment": "test comment",
"version": data.blocked_user_story.version
})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
def test_user_story_delete(client, data):
public_url = reverse('userstories-detail', kwargs={"pk": data.public_user_story.pk})
private_url1 = reverse('userstories-detail', kwargs={"pk": data.private_user_story1.pk})
@ -318,95 +573,6 @@ def test_user_story_delete(client, data):
assert results == [401, 403, 403, 451]
def test_user_story_list(client, data):
url = reverse('userstories-list')
response = client.get(url)
userstories_data = json.loads(response.content.decode('utf-8'))
assert len(userstories_data) == 2
assert response.status_code == 200
client.login(data.registered_user)
response = client.get(url)
userstories_data = json.loads(response.content.decode('utf-8'))
assert len(userstories_data) == 2
assert response.status_code == 200
client.login(data.project_member_with_perms)
response = client.get(url)
userstories_data = json.loads(response.content.decode('utf-8'))
assert len(userstories_data) == 4
assert response.status_code == 200
client.login(data.project_owner)
response = client.get(url)
userstories_data = json.loads(response.content.decode('utf-8'))
assert len(userstories_data) == 4
assert response.status_code == 200
def test_user_story_create(client, data):
url = reverse('userstories-list')
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
create_data = json.dumps({"subject": "test", "ref": 1, "project": data.public_project.pk})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 201, 201, 201, 201]
create_data = json.dumps({"subject": "test", "ref": 2, "project": data.private_project1.pk})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 201, 201, 201, 201]
create_data = json.dumps({"subject": "test", "ref": 3, "project": data.private_project2.pk})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({"subject": "test", "ref": 4, "project": data.blocked_project.pk})
results = helper_test_http_method(client, 'post', url, create_data, users)
assert results == [401, 403, 403, 451, 451]
def test_user_story_patch(client, data):
public_url = reverse('userstories-detail', kwargs={"pk": data.public_user_story.pk})
private_url1 = reverse('userstories-detail', kwargs={"pk": data.private_user_story1.pk})
private_url2 = reverse('userstories-detail', kwargs={"pk": data.private_user_story2.pk})
blocked_url = reverse('userstories-detail', kwargs={"pk": data.blocked_user_story.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({"subject": "test", "version": data.public_user_story.version})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"subject": "test", "version": data.private_user_story1.version})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"subject": "test", "version": data.private_user_story2.version})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"subject": "test", "version": data.blocked_user_story.version})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
def test_user_story_action_bulk_create(client, data):
url = reverse('userstories-bulk-create')
@ -421,11 +587,11 @@ def test_user_story_action_bulk_create(client, data):
bulk_data = json.dumps({"bulk_stories": "test1\ntest2", "project_id": data.public_user_story.project.pk})
results = helper_test_http_method(client, 'post', url, bulk_data, users)
assert results == [401, 200, 200, 200, 200]
assert results == [401, 403, 403, 200, 200]
bulk_data = json.dumps({"bulk_stories": "test1\ntest2", "project_id": data.private_user_story1.project.pk})
results = helper_test_http_method(client, 'post', url, bulk_data, users)
assert results == [401, 200, 200, 200, 200]
assert results == [401, 403, 403, 200, 200]
bulk_data = json.dumps({"bulk_stories": "test1\ntest2", "project_id": data.private_user_story2.project.pk})
results = helper_test_http_method(client, 'post', url, bulk_data, users)
@ -580,30 +746,6 @@ def test_user_story_voters_retrieve(client, data):
assert results == [401, 403, 403, 200, 200]
def test_user_stories_csv(client, data):
url = reverse('userstories-csv')
csv_public_uuid = data.public_project.userstories_csv_uuid
csv_private1_uuid = data.private_project1.userstories_csv_uuid
csv_private2_uuid = data.private_project1.userstories_csv_uuid
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_public_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_private1_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_private2_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
def test_user_story_action_watch(client, data):
public_url = reverse('userstories-watch', kwargs={"pk": data.public_user_story.pk})
private_url1 = reverse('userstories-watch', kwargs={"pk": data.private_user_story1.pk})
@ -706,3 +848,27 @@ def test_userstory_watchers_retrieve(client, data):
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'get', blocked_url, None, users)
assert results == [401, 403, 403, 200, 200]
def test_user_stories_action_csv(client, data):
url = reverse('userstories-csv')
csv_public_uuid = data.public_project.userstories_csv_uuid
csv_private1_uuid = data.private_project1.userstories_csv_uuid
csv_private2_uuid = data.private_project1.userstories_csv_uuid
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_public_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_private1_uuid), None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', "{}?uuid={}".format(url, csv_private2_uuid), None, users)
assert results == [200, 200, 200, 200, 200]

View File

@ -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, USER_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
@ -37,11 +37,11 @@ def data():
m.public_project = f.ProjectFactory(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project1 = f.ProjectFactory(is_private=True,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
owner=m.project_owner)
m.private_project2 = f.ProjectFactory(is_private=True,
anon_permissions=[],
@ -111,91 +111,9 @@ def data():
return m
def test_wiki_page_retrieve(client, data):
public_url = reverse('wiki-detail', kwargs={"pk": data.public_wiki_page.pk})
private_url1 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page1.pk})
private_url2 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page2.pk})
blocked_url = reverse('wiki-detail', kwargs={"pk": data.blocked_wiki_page.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
results = helper_test_http_method(client, 'get', public_url, None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', private_url1, None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', private_url2, None, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'get', blocked_url, None, users)
assert results == [401, 403, 403, 200, 200]
def test_wiki_page_update(client, data):
public_url = reverse('wiki-detail', kwargs={"pk": data.public_wiki_page.pk})
private_url1 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page1.pk})
private_url2 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page2.pk})
blocked_url = reverse('wiki-detail', kwargs={"pk": data.blocked_wiki_page.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
wiki_page_data = WikiPageSerializer(data.public_wiki_page).data
wiki_page_data["content"] = "test"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', public_url, wiki_page_data, users)
assert results == [401, 200, 200, 200, 200]
wiki_page_data = WikiPageSerializer(data.private_wiki_page1).data
wiki_page_data["content"] = "test"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', private_url1, wiki_page_data, users)
assert results == [401, 200, 200, 200, 200]
wiki_page_data = WikiPageSerializer(data.private_wiki_page2).data
wiki_page_data["content"] = "test"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', private_url2, wiki_page_data, users)
assert results == [401, 403, 403, 200, 200]
wiki_page_data = WikiPageSerializer(data.blocked_wiki_page).data
wiki_page_data["content"] = "test"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', blocked_url, wiki_page_data, users)
assert results == [401, 403, 403, 451, 451]
def test_wiki_page_delete(client, data):
public_url = reverse('wiki-detail', kwargs={"pk": data.public_wiki_page.pk})
private_url1 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page1.pk})
private_url2 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page2.pk})
blocked_url = reverse('wiki-detail', kwargs={"pk": data.blocked_wiki_page.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
]
results = helper_test_http_method(client, 'delete', public_url, None, users)
assert results == [401, 403, 403, 204]
results = helper_test_http_method(client, 'delete', private_url1, None, users)
assert results == [401, 403, 403, 204]
results = helper_test_http_method(client, 'delete', private_url2, None, users)
assert results == [401, 403, 403, 204]
results = helper_test_http_method(client, 'delete', blocked_url, None, users)
assert results == [401, 403, 403, 451]
##############################################
## WIKI PAGES
##############################################
def test_wiki_page_list(client, data):
url = reverse('wiki-list')
@ -227,50 +145,7 @@ def test_wiki_page_list(client, data):
assert response.status_code == 200
def test_wiki_page_create(client, data):
url = reverse('wiki-list')
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
create_data = json.dumps({
"content": "test",
"slug": "test",
"project": data.public_project.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiPage.objects.all().delete())
assert results == [401, 201, 201, 201, 201]
create_data = json.dumps({
"content": "test",
"slug": "test",
"project": data.private_project1.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiPage.objects.all().delete())
assert results == [401, 201, 201, 201, 201]
create_data = json.dumps({
"content": "test",
"slug": "test",
"project": data.private_project2.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiPage.objects.all().delete())
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"content": "test",
"slug": "test",
"project": data.blocked_project.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiPage.objects.all().delete())
assert results == [401, 403, 403, 451, 451]
def test_wiki_page_patch(client, data):
def test_wiki_page_retrieve(client, data):
public_url = reverse('wiki-detail', kwargs={"pk": data.public_wiki_page.pk})
private_url1 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page1.pk})
private_url2 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page2.pk})
@ -284,54 +159,6 @@ def test_wiki_page_patch(client, data):
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({"content": "test", "version": data.public_wiki_page.version})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 200, 200, 200, 200]
patch_data = json.dumps({"content": "test", "version": data.private_wiki_page2.version})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 200, 200, 200, 200]
patch_data = json.dumps({"content": "test", "version": data.private_wiki_page2.version})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"content": "test", "version": data.blocked_wiki_page.version})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
def test_wiki_page_action_render(client, data):
url = reverse('wiki-render')
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
post_data = json.dumps({"content": "test", "project_id": data.public_project.pk})
results = helper_test_http_method(client, 'post', url, post_data, users)
assert results == [200, 200, 200, 200, 200]
def test_wiki_link_retrieve(client, data):
public_url = reverse('wiki-links-detail', kwargs={"pk": data.public_wiki_link.pk})
private_url1 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link1.pk})
private_url2 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link2.pk})
blocked_url = reverse('wiki-links-detail', kwargs={"pk": data.blocked_wiki_link.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
results = helper_test_http_method(client, 'get', public_url, None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', private_url1, None, users)
@ -342,11 +169,55 @@ def test_wiki_link_retrieve(client, data):
assert results == [401, 403, 403, 200, 200]
def test_wiki_link_update(client, data):
public_url = reverse('wiki-links-detail', kwargs={"pk": data.public_wiki_link.pk})
private_url1 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link1.pk})
private_url2 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link2.pk})
blocked_url = reverse('wiki-links-detail', kwargs={"pk": data.blocked_wiki_link.pk})
def test_wiki_page_create(client, data):
url = reverse('wiki-list')
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
create_data = json.dumps({
"content": "test",
"slug": "test",
"project": data.public_project.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiPage.objects.all().delete())
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"content": "test",
"slug": "test",
"project": data.private_project1.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiPage.objects.all().delete())
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"content": "test",
"slug": "test",
"project": data.private_project2.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiPage.objects.all().delete())
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"content": "test",
"slug": "test",
"project": data.blocked_project.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiPage.objects.all().delete())
assert results == [401, 403, 403, 451, 451]
def test_wiki_page_put_update(client, data):
public_url = reverse('wiki-detail', kwargs={"pk": data.public_wiki_page.pk})
private_url1 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page1.pk})
private_url2 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page2.pk})
blocked_url = reverse('wiki-detail', kwargs={"pk": data.blocked_wiki_page.pk})
users = [
None,
@ -357,35 +228,318 @@ def test_wiki_link_update(client, data):
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
wiki_link_data = WikiLinkSerializer(data.public_wiki_link).data
wiki_link_data["title"] = "test"
wiki_link_data = json.dumps(wiki_link_data)
results = helper_test_http_method(client, 'put', public_url, wiki_link_data, users)
assert results == [401, 200, 200, 200, 200]
wiki_page_data = WikiPageSerializer(data.public_wiki_page).data
wiki_page_data["content"] = "test"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', public_url, wiki_page_data, users)
assert results == [401, 403, 403, 200, 200]
wiki_link_data = WikiLinkSerializer(data.private_wiki_link1).data
wiki_link_data["title"] = "test"
wiki_link_data = json.dumps(wiki_link_data)
results = helper_test_http_method(client, 'put', private_url1, wiki_link_data, users)
assert results == [401, 200, 200, 200, 200]
wiki_page_data = WikiPageSerializer(data.private_wiki_page1).data
wiki_page_data["content"] = "test"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', private_url1, wiki_page_data, users)
assert results == [401, 403, 403, 200, 200]
wiki_link_data = WikiLinkSerializer(data.private_wiki_link2).data
wiki_link_data["title"] = "test"
wiki_link_data = json.dumps(wiki_link_data)
results = helper_test_http_method(client, 'put', private_url2, wiki_link_data, users)
assert results == [401, 403, 403, 200, 200]
wiki_page_data = WikiPageSerializer(data.private_wiki_page2).data
wiki_page_data["content"] = "test"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', private_url2, wiki_page_data, users)
assert results == [401, 403, 403, 200, 200]
wiki_link_data = WikiLinkSerializer(data.blocked_wiki_link).data
wiki_link_data["title"] = "test"
wiki_link_data = json.dumps(wiki_link_data)
results = helper_test_http_method(client, 'put', blocked_url, wiki_link_data, users)
assert results == [401, 403, 403, 451, 451]
wiki_page_data = WikiPageSerializer(data.blocked_wiki_page).data
wiki_page_data["content"] = "test"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', blocked_url, wiki_page_data, users)
assert results == [401, 403, 403, 451, 451]
def test_wiki_link_delete(client, data):
public_url = reverse('wiki-links-detail', kwargs={"pk": data.public_wiki_link.pk})
private_url1 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link1.pk})
private_url2 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link2.pk})
blocked_url = reverse('wiki-links-detail', kwargs={"pk": data.blocked_wiki_link.pk})
def test_wiki_page_put_comment(client, data):
public_url = reverse('wiki-detail', kwargs={"pk": data.public_wiki_page.pk})
private_url1 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page1.pk})
private_url2 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page2.pk})
blocked_url = reverse('wiki-detail', kwargs={"pk": data.blocked_wiki_page.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
wiki_page_data = WikiPageSerializer(data.public_wiki_page).data
wiki_page_data["comment"] = "test comment"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', public_url, wiki_page_data, users)
assert results == [401, 403, 403, 200, 200]
wiki_page_data = WikiPageSerializer(data.private_wiki_page1).data
wiki_page_data["comment"] = "test comment"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', private_url1, wiki_page_data, users)
assert results == [401, 403, 403, 200, 200]
wiki_page_data = WikiPageSerializer(data.private_wiki_page2).data
wiki_page_data["comment"] = "test comment"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', private_url2, wiki_page_data, users)
assert results == [401, 403, 403, 200, 200]
wiki_page_data = WikiPageSerializer(data.blocked_wiki_page).data
wiki_page_data["comment"] = "test comment"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', blocked_url, wiki_page_data, users)
assert results == [401, 403, 403, 451, 451]
def test_wiki_page_put_update_and_comment(client, data):
public_url = reverse('wiki-detail', kwargs={"pk": data.public_wiki_page.pk})
private_url1 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page1.pk})
private_url2 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page2.pk})
blocked_url = reverse('wiki-detail', kwargs={"pk": data.blocked_wiki_page.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
wiki_page_data = WikiPageSerializer(data.public_wiki_page).data
wiki_page_data["slug"] = "test"
wiki_page_data["comment"] = "test comment"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', public_url, wiki_page_data, users)
assert results == [401, 403, 403, 200, 200]
wiki_page_data = WikiPageSerializer(data.private_wiki_page1).data
wiki_page_data["slug"] = "test"
wiki_page_data["comment"] = "test comment"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', private_url1, wiki_page_data, users)
assert results == [401, 403, 403, 200, 200]
wiki_page_data = WikiPageSerializer(data.private_wiki_page2).data
wiki_page_data["slug"] = "test"
wiki_page_data["comment"] = "test comment"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', private_url2, wiki_page_data, users)
assert results == [401, 403, 403, 200, 200]
wiki_page_data = WikiPageSerializer(data.blocked_wiki_page).data
wiki_page_data["slug"] = "test"
wiki_page_data["comment"] = "test comment"
wiki_page_data = json.dumps(wiki_page_data)
results = helper_test_http_method(client, 'put', blocked_url, wiki_page_data, users)
assert results == [401, 403, 403, 451, 451]
def test_wiki_page_put_update_with_project_change(client):
user1 = f.UserFactory.create()
user2 = f.UserFactory.create()
user3 = f.UserFactory.create()
user4 = f.UserFactory.create()
project1 = f.ProjectFactory()
project2 = f.ProjectFactory()
membership1 = f.MembershipFactory(project=project1,
user=user1,
role__project=project1,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
membership2 = f.MembershipFactory(project=project2,
user=user1,
role__project=project2,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
membership3 = f.MembershipFactory(project=project1,
user=user2,
role__project=project1,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
membership4 = f.MembershipFactory(project=project2,
user=user3,
role__project=project2,
role__permissions=list(map(lambda x: x[0], MEMBERS_PERMISSIONS)))
wiki_page = f.WikiPageFactory.create(project=project1)
url = reverse('wiki-detail', kwargs={"pk": wiki_page.pk})
# Test user with permissions in both projects
client.login(user1)
wiki_page_data = WikiPageSerializer(wiki_page).data
wiki_page_data["project"] = project2.id
wiki_page_data = json.dumps(wiki_page_data)
response = client.put(url, data=wiki_page_data, content_type="application/json")
assert response.status_code == 200
wiki_page.project = project1
wiki_page.save()
# Test user with permissions in only origin project
client.login(user2)
wiki_page_data = WikiPageSerializer(wiki_page).data
wiki_page_data["project"] = project2.id
wiki_page_data = json.dumps(wiki_page_data)
response = client.put(url, data=wiki_page_data, content_type="application/json")
assert response.status_code == 403
wiki_page.project = project1
wiki_page.save()
# Test user with permissions in only destionation project
client.login(user3)
wiki_page_data = WikiPageSerializer(wiki_page).data
wiki_page_data["project"] = project2.id
wiki_page_data = json.dumps(wiki_page_data)
response = client.put(url, data=wiki_page_data, content_type="application/json")
assert response.status_code == 403
wiki_page.project = project1
wiki_page.save()
# Test user without permissions in the projects
client.login(user4)
wiki_page_data = WikiPageSerializer(wiki_page).data
wiki_page_data["project"] = project2.id
wiki_page_data = json.dumps(wiki_page_data)
response = client.put(url, data=wiki_page_data, content_type="application/json")
assert response.status_code == 403
wiki_page.project = project1
wiki_page.save()
def test_wiki_page_patch_update(client, data):
public_url = reverse('wiki-detail', kwargs={"pk": data.public_wiki_page.pk})
private_url1 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page1.pk})
private_url2 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page2.pk})
blocked_url = reverse('wiki-detail', kwargs={"pk": data.blocked_wiki_page.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({"content": "test", "version": data.public_wiki_page.version})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"content": "test", "version": data.private_wiki_page2.version})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"content": "test", "version": data.private_wiki_page2.version})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"content": "test", "version": data.blocked_wiki_page.version})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
def test_wiki_page_patch_comment(client, data):
public_url = reverse('wiki-detail', kwargs={"pk": data.public_wiki_page.pk})
private_url1 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page1.pk})
private_url2 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page2.pk})
blocked_url = reverse('wiki-detail', kwargs={"pk": data.blocked_wiki_page.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({"comment": "test comment", "version": data.public_wiki_page.version})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"comment": "test comment", "version": data.private_wiki_page2.version})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"comment": "test comment", "version": data.private_wiki_page2.version})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"comment": "test comment", "version": data.blocked_wiki_page.version})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
def test_wiki_page_patch_update_and_comment(client, data):
public_url = reverse('wiki-detail', kwargs={"pk": data.public_wiki_page.pk})
private_url1 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page1.pk})
private_url2 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page2.pk})
blocked_url = reverse('wiki-detail', kwargs={"pk": data.blocked_wiki_page.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({
"content": "test",
"comment": "test comment",
"version": data.public_wiki_page.version
})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({
"content": "test",
"comment": "test comment",
"version": data.private_wiki_page2.version
})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({
"content": "test",
"comment": "test comment",
"version": data.private_wiki_page2.version
})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({
"content": "test",
"comment": "test comment",
"version": data.blocked_wiki_page.version
})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
def test_wiki_page_delete(client, data):
public_url = reverse('wiki-detail', kwargs={"pk": data.public_wiki_page.pk})
private_url1 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page1.pk})
private_url2 = reverse('wiki-detail', kwargs={"pk": data.private_wiki_page2.pk})
blocked_url = reverse('wiki-detail', kwargs={"pk": data.blocked_wiki_page.pk})
users = [
None,
@ -403,38 +557,8 @@ def test_wiki_link_delete(client, data):
assert results == [401, 403, 403, 451]
def test_wiki_link_list(client, data):
url = reverse('wiki-links-list')
response = client.get(url)
wiki_links_data = json.loads(response.content.decode('utf-8'))
assert len(wiki_links_data) == 2
assert response.status_code == 200
client.login(data.registered_user)
response = client.get(url)
wiki_links_data = json.loads(response.content.decode('utf-8'))
assert len(wiki_links_data) == 2
assert response.status_code == 200
client.login(data.project_member_with_perms)
response = client.get(url)
wiki_links_data = json.loads(response.content.decode('utf-8'))
assert len(wiki_links_data) == 4
assert response.status_code == 200
client.login(data.project_owner)
response = client.get(url)
wiki_links_data = json.loads(response.content.decode('utf-8'))
assert len(wiki_links_data) == 4
assert response.status_code == 200
def test_wiki_link_create(client, data):
url = reverse('wiki-links-list')
def test_wiki_page_action_render(client, data):
url = reverse('wiki-render')
users = [
None,
@ -444,69 +568,9 @@ def test_wiki_link_create(client, data):
data.project_owner
]
create_data = json.dumps({
"title": "test",
"href": "test",
"project": data.public_project.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiLink.objects.all().delete())
assert results == [401, 201, 201, 201, 201]
create_data = json.dumps({
"title": "test",
"href": "test",
"project": data.private_project1.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiLink.objects.all().delete())
assert results == [401, 201, 201, 201, 201]
create_data = json.dumps({
"title": "test",
"href": "test",
"project": data.private_project2.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiLink.objects.all().delete())
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"title": "test",
"href": "test",
"project": data.blocked_project.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiLink.objects.all().delete())
assert results == [401, 403, 403, 451, 451]
def test_wiki_link_patch(client, data):
public_url = reverse('wiki-links-detail', kwargs={"pk": data.public_wiki_link.pk})
private_url1 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link1.pk})
private_url2 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link2.pk})
blocked_url = reverse('wiki-links-detail', kwargs={"pk": data.blocked_wiki_link.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({"title": "test"})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 200, 200, 200, 200]
patch_data = json.dumps({"title": "test"})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 200, 200, 200, 200]
patch_data = json.dumps({"title": "test"})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"title": "test"})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
post_data = json.dumps({"content": "test", "project_id": data.public_project.pk})
results = helper_test_http_method(client, 'post', url, post_data, users)
assert results == [200, 200, 200, 200, 200]
def test_wikipage_action_watch(client, data):
@ -610,3 +674,199 @@ def test_wikipage_watchers_retrieve(client, data):
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'get', blocked_url, None, users)
assert results == [401, 403, 403, 200, 200]
##############################################
## WIKI LINKS
##############################################
def test_wiki_link_list(client, data):
url = reverse('wiki-links-list')
response = client.get(url)
wiki_links_data = json.loads(response.content.decode('utf-8'))
assert len(wiki_links_data) == 2
assert response.status_code == 200
client.login(data.registered_user)
response = client.get(url)
wiki_links_data = json.loads(response.content.decode('utf-8'))
assert len(wiki_links_data) == 2
assert response.status_code == 200
client.login(data.project_member_with_perms)
response = client.get(url)
wiki_links_data = json.loads(response.content.decode('utf-8'))
assert len(wiki_links_data) == 4
assert response.status_code == 200
client.login(data.project_owner)
response = client.get(url)
wiki_links_data = json.loads(response.content.decode('utf-8'))
assert len(wiki_links_data) == 4
assert response.status_code == 200
def test_wiki_link_retrieve(client, data):
public_url = reverse('wiki-links-detail', kwargs={"pk": data.public_wiki_link.pk})
private_url1 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link1.pk})
private_url2 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link2.pk})
blocked_url = reverse('wiki-links-detail', kwargs={"pk": data.blocked_wiki_link.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
results = helper_test_http_method(client, 'get', public_url, None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', private_url1, None, users)
assert results == [200, 200, 200, 200, 200]
results = helper_test_http_method(client, 'get', private_url2, None, users)
assert results == [401, 403, 403, 200, 200]
results = helper_test_http_method(client, 'get', blocked_url, None, users)
assert results == [401, 403, 403, 200, 200]
def test_wiki_link_create(client, data):
url = reverse('wiki-links-list')
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
create_data = json.dumps({
"title": "test",
"href": "test",
"project": data.public_project.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiLink.objects.all().delete())
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"title": "test",
"href": "test",
"project": data.private_project1.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiLink.objects.all().delete())
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"title": "test",
"href": "test",
"project": data.private_project2.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiLink.objects.all().delete())
assert results == [401, 403, 403, 201, 201]
create_data = json.dumps({
"title": "test",
"href": "test",
"project": data.blocked_project.pk,
})
results = helper_test_http_method(client, 'post', url, create_data, users, lambda: WikiLink.objects.all().delete())
assert results == [401, 403, 403, 451, 451]
def test_wiki_link_update(client, data):
public_url = reverse('wiki-links-detail', kwargs={"pk": data.public_wiki_link.pk})
private_url1 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link1.pk})
private_url2 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link2.pk})
blocked_url = reverse('wiki-links-detail', kwargs={"pk": data.blocked_wiki_link.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
wiki_link_data = WikiLinkSerializer(data.public_wiki_link).data
wiki_link_data["title"] = "test"
wiki_link_data = json.dumps(wiki_link_data)
results = helper_test_http_method(client, 'put', public_url, wiki_link_data, users)
assert results == [401, 403, 403, 200, 200]
wiki_link_data = WikiLinkSerializer(data.private_wiki_link1).data
wiki_link_data["title"] = "test"
wiki_link_data = json.dumps(wiki_link_data)
results = helper_test_http_method(client, 'put', private_url1, wiki_link_data, users)
assert results == [401, 403, 403, 200, 200]
wiki_link_data = WikiLinkSerializer(data.private_wiki_link2).data
wiki_link_data["title"] = "test"
wiki_link_data = json.dumps(wiki_link_data)
results = helper_test_http_method(client, 'put', private_url2, wiki_link_data, users)
assert results == [401, 403, 403, 200, 200]
wiki_link_data = WikiLinkSerializer(data.blocked_wiki_link).data
wiki_link_data["title"] = "test"
wiki_link_data = json.dumps(wiki_link_data)
results = helper_test_http_method(client, 'put', blocked_url, wiki_link_data, users)
assert results == [401, 403, 403, 451, 451]
def test_wiki_link_patch(client, data):
public_url = reverse('wiki-links-detail', kwargs={"pk": data.public_wiki_link.pk})
private_url1 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link1.pk})
private_url2 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link2.pk})
blocked_url = reverse('wiki-links-detail', kwargs={"pk": data.blocked_wiki_link.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
data.project_owner
]
with mock.patch.object(OCCResourceMixin, "_validate_and_update_version"):
patch_data = json.dumps({"title": "test"})
results = helper_test_http_method(client, 'patch', public_url, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"title": "test"})
results = helper_test_http_method(client, 'patch', private_url1, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"title": "test"})
results = helper_test_http_method(client, 'patch', private_url2, patch_data, users)
assert results == [401, 403, 403, 200, 200]
patch_data = json.dumps({"title": "test"})
results = helper_test_http_method(client, 'patch', blocked_url, patch_data, users)
assert results == [401, 403, 403, 451, 451]
def test_wiki_link_delete(client, data):
public_url = reverse('wiki-links-detail', kwargs={"pk": data.public_wiki_link.pk})
private_url1 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link1.pk})
private_url2 = reverse('wiki-links-detail', kwargs={"pk": data.private_wiki_link2.pk})
blocked_url = reverse('wiki-links-detail', kwargs={"pk": data.blocked_wiki_link.pk})
users = [
None,
data.registered_user,
data.project_member_without_perms,
data.project_member_with_perms,
]
results = helper_test_http_method(client, 'delete', public_url, None, users)
assert results == [401, 403, 403, 204]
results = helper_test_http_method(client, 'delete', private_url1, None, users)
assert results == [401, 403, 403, 204]
results = helper_test_http_method(client, 'delete', private_url2, None, users)
assert results == [401, 403, 403, 204]
results = helper_test_http_method(client, 'delete', blocked_url, None, users)
assert results == [401, 403, 403, 451]

View File

@ -17,6 +17,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pytest
import datetime
from unittest.mock import patch
from django.core.urlresolvers import reverse
@ -235,3 +237,84 @@ def test_delete_comment_by_project_owner(client):
url = "%s?id=%s" % (url, history_entry.id)
response = client.post(url, content_type="application/json")
assert 200 == response.status_code, response.status_code
def test_edit_comment(client):
project = f.create_project()
us = f.create_userstory(project=project)
f.MembershipFactory.create(project=project, user=project.owner, is_admin=True)
key = make_key_from_model_object(us)
history_entry = f.HistoryEntryFactory.create(type=HistoryType.change,
comment="testing",
key=key,
diff={},
user={"pk": project.owner.id})
history_entry_created_at = history_entry.created_at
assert history_entry.comment_versions == None
assert history_entry.edit_comment_date == None
client.login(project.owner)
url = reverse("userstory-history-edit-comment", args=(us.id,))
url = "%s?id=%s" % (url, history_entry.id)
data = json.dumps({"comment": "testing update comment"})
response = client.post(url, data, content_type="application/json")
assert 200 == response.status_code, response.status_code
history_entry = HistoryEntry.objects.get(id=history_entry.id)
assert len(history_entry.comment_versions) == 1
assert history_entry.comment == "testing update comment"
assert history_entry.comment_versions[0]["comment"] == "testing"
assert history_entry.edit_comment_date != None
assert history_entry.comment_versions[0]["user"]["id"] == project.owner.id
def test_get_comment_versions(client):
project = f.create_project()
us = f.create_userstory(project=project)
f.MembershipFactory.create(project=project, user=project.owner, is_admin=True)
key = make_key_from_model_object(us)
history_entry = f.HistoryEntryFactory.create(
type=HistoryType.change,
comment="testing",
key=key,
diff={},
user={"pk": project.owner.id},
edit_comment_date=datetime.datetime.now(),
comment_versions = [{
"comment_html": "<p>test</p>",
"date": "2016-05-09T09:34:27.221Z",
"comment": "test",
"user": {
"id": project.owner.id,
}}])
client.login(project.owner)
url = reverse("userstory-history-comment-versions", args=(us.id,))
url = "%s?id=%s" % (url, history_entry.id)
response = client.get(url, content_type="application/json")
assert 200 == response.status_code, response.status_code
assert response.data[0]["user"]["username"] == project.owner.username
def test_get_comment_versions_from_history_entry_without_comment(client):
project = f.create_project()
us = f.create_userstory(project=project)
f.MembershipFactory.create(project=project, user=project.owner, is_admin=True)
key = make_key_from_model_object(us)
history_entry = f.HistoryEntryFactory.create(
type=HistoryType.change,
key=key,
diff={},
user={"pk": project.owner.id})
client.login(project.owner)
url = reverse("userstory-history-comment-versions", args=(us.id,))
url = "%s?id=%s" % (url, history_entry.id)
response = client.get(url, content_type="application/json")
assert 200 == response.status_code, response.status_code
assert response.data == None

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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, USER_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
@ -340,7 +340,7 @@ def test_list_contacts_no_projects(client):
def test_list_contacts_public_projects(client):
project = f.ProjectFactory.create(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)))
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)))
user_1 = f.UserFactory.create()
user_2 = f.UserFactory.create()

View File

@ -20,7 +20,7 @@ import pytest
import json
from django.core.urlresolvers import reverse
from taiga.permissions.permissions import MEMBERS_PERMISSIONS, ANON_PERMISSIONS, USER_PERMISSIONS
from taiga.permissions.choices import MEMBERS_PERMISSIONS, ANON_PERMISSIONS
from .. import factories as f
@ -129,7 +129,7 @@ def test_get_project_is_watcher(client):
user = f.UserFactory.create()
project = f.ProjectFactory.create(is_private=False,
anon_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)),
public_permissions=list(map(lambda x: x[0], USER_PERMISSIONS)))
public_permissions=list(map(lambda x: x[0], ANON_PERMISSIONS)))
url_detail = reverse("projects-detail", args=(project.id,))
url_watch = reverse("projects-watch", args=(project.id,))

View File

@ -1,26 +0,0 @@
# Copyright (C) 2014-2016 Andrey Antukh <niwi@niwi.nz>
# Copyright (C) 2014-2016 Jesús Espino <jespinog@gmail.com>
# Copyright (C) 2014-2016 David Barragán <bameda@dbarragan.com>
# Copyright (C) 2014-2016 Alejandro Alonso <alejandro.alonso@kaleidos.net>
# 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 <http://www.gnu.org/licenses/>.
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