From 413a83808a5c1836270928707faa6bcd75b5dffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Wed, 11 May 2016 20:50:19 +0200 Subject: [PATCH] US #4186: Permission to add comments --- CHANGELOG.md | 7 +- taiga/permissions/choices.py | 5 +- taiga/permissions/permissions.py | 37 + .../fixtures/initial_project_templates.json | 84 +- taiga/projects/issues/permissions.py | 5 +- .../migrations/0041_auto_20160519_1058.py | 21 + .../migrations/0042_auto_20160525_0911.py | 67 ++ taiga/projects/tasks/permissions.py | 6 +- taiga/projects/userstories/permissions.py | 6 +- taiga/projects/wiki/permissions.py | 6 +- .../migrations/0019_auto_20160519_1058.py | 21 + .../migrations/0020_auto_20160525_1229.py | 48 ++ .../test_issues_resources.py | 532 ++++++++---- .../test_tasks_resources.py | 466 +++++++---- .../test_userstories_resources.py | 380 ++++++--- .../test_wiki_resources.py | 786 ++++++++++++------ 16 files changed, 1720 insertions(+), 757 deletions(-) create mode 100644 taiga/projects/migrations/0041_auto_20160519_1058.py create mode 100644 taiga/projects/migrations/0042_auto_20160525_0911.py create mode 100644 taiga/users/migrations/0019_auto_20160519_1058.py create mode 100644 taiga/users/migrations/0020_auto_20160525_1229.py diff --git a/CHANGELOG.md b/CHANGELOG.md index eca3114a..97b090ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,13 @@ # Changelog # ## 2.2.0 ??? (unreleased) + ### Features -- [API] edit comment endpoint: comment owners and project admins can edit existing comments +- 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) diff --git a/taiga/permissions/choices.py b/taiga/permissions/choices.py index bfd7192e..f617da97 100644 --- a/taiga/permissions/choices.py +++ b/taiga/permissions/choices.py @@ -27,7 +27,6 @@ ANON_PERMISSIONS = [ ('view_wiki_pages', _('View wiki pages')), ('view_wiki_links', _('View wiki links')), ] - MEMBERS_PERMISSIONS = [ ('view_project', _('View project')), # Milestone permissions @@ -39,21 +38,25 @@ MEMBERS_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')), diff --git a/taiga/permissions/permissions.py b/taiga/permissions/permissions.py index 4e563522..c2b7699a 100644 --- a/taiga/permissions/permissions.py +++ b/taiga/permissions/permissions.py @@ -51,3 +51,40 @@ class IsObjectOwner(PermissionComponent): 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 diff --git a/taiga/projects/fixtures/initial_project_templates.json b/taiga/projects/fixtures/initial_project_templates.json index 46d369a5..54e73bd0 100644 --- a/taiga/projects/fixtures/initial_project_templates.json +++ b/taiga/projects/fixtures/initial_project_templates.json @@ -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\"]}]" + } } ] diff --git a/taiga/projects/issues/permissions.py b/taiga/projects/issues/permissions.py index 791848f9..ea823fcc 100644 --- a/taiga/projects/issues/permissions.py +++ b/taiga/projects/issues/permissions.py @@ -19,6 +19,7 @@ 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() diff --git a/taiga/projects/migrations/0041_auto_20160519_1058.py b/taiga/projects/migrations/0041_auto_20160519_1058.py new file mode 100644 index 00000000..c4b0a2fd --- /dev/null +++ b/taiga/projects/migrations/0041_auto_20160519_1058.py @@ -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'), + ), + ] diff --git a/taiga/projects/migrations/0042_auto_20160525_0911.py b/taiga/projects/migrations/0042_auto_20160525_0911.py new file mode 100644 index 00000000..0652df06 --- /dev/null +++ b/taiga/projects/migrations/0042_auto_20160525_0911.py @@ -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") + ) + ] diff --git a/taiga/projects/tasks/permissions.py b/taiga/projects/tasks/permissions.py index 566fc79c..8dfafc41 100644 --- a/taiga/projects/tasks/permissions.py +++ b/taiga/projects/tasks/permissions.py @@ -18,14 +18,16 @@ 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): enought_perms = IsProjectAdmin() | IsSuperUser() 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() diff --git a/taiga/projects/userstories/permissions.py b/taiga/projects/userstories/permissions.py index 11aa5b73..c91ef2a7 100644 --- a/taiga/projects/userstories/permissions.py +++ b/taiga/projects/userstories/permissions.py @@ -18,14 +18,16 @@ 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() diff --git a/taiga/projects/wiki/permissions.py b/taiga/projects/wiki/permissions.py index d85d56ea..e60458c7 100644 --- a/taiga/projects/wiki/permissions.py +++ b/taiga/projects/wiki/permissions.py @@ -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() diff --git a/taiga/users/migrations/0019_auto_20160519_1058.py b/taiga/users/migrations/0019_auto_20160519_1058.py new file mode 100644 index 00000000..69780084 --- /dev/null +++ b/taiga/users/migrations/0019_auto_20160519_1058.py @@ -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'), + ), + ] diff --git a/taiga/users/migrations/0020_auto_20160525_1229.py b/taiga/users/migrations/0020_auto_20160525_1229.py new file mode 100644 index 00000000..765eb3e1 --- /dev/null +++ b/taiga/users/migrations/0020_auto_20160525_1229.py @@ -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") + ) + ] diff --git a/tests/integration/resources_permissions/test_issues_resources.py b/tests/integration/resources_permissions/test_issues_resources.py index bb532473..536b4422 100644 --- a/tests/integration/resources_permissions/test_issues_resources.py +++ b/tests/integration/resources_permissions/test_issues_resources.py @@ -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,139 +502,7 @@ def test_issue_update_with_project_change(client): issue.save() -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}) - 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, - ] - - 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_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, 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_patch(client, data): +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}) @@ -473,7 +534,110 @@ def test_issue_patch(client, data): assert results == [401, 403, 403, 451, 451] -def test_issue_bulk_create(client, data): +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}) + 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, + ] + + 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_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() @@ -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] diff --git a/tests/integration/resources_permissions/test_tasks_resources.py b/tests/integration/resources_permissions/test_tasks_resources.py index aff81389..63a1d63e 100644 --- a/tests/integration/resources_permissions/test_tasks_resources.py +++ b/tests/integration/resources_permissions/test_tasks_resources.py @@ -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] diff --git a/tests/integration/resources_permissions/test_userstories_resources.py b/tests/integration/resources_permissions/test_userstories_resources.py index 4da7b081..cb5f78ff 100644 --- a/tests/integration/resources_permissions/test_userstories_resources.py +++ b/tests/integration/resources_permissions/test_userstories_resources.py @@ -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}) @@ -201,7 +259,92 @@ def test_user_story_update(client, 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,87 +439,7 @@ def test_user_story_update_with_project_change(client): us.save() -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}) - 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, - ] - 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_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, 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_patch(client, data): +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}) @@ -408,6 +471,109 @@ def test_user_story_patch(client, data): 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}) + 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, + ] + 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_user_story_action_bulk_create(client, data): url = reverse('userstories-bulk-create') @@ -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] diff --git a/tests/integration/resources_permissions/test_wiki_resources.py b/tests/integration/resources_permissions/test_wiki_resources.py index aaee4e53..e981aa75 100644 --- a/tests/integration/resources_permissions/test_wiki_resources.py +++ b/tests/integration/resources_permissions/test_wiki_resources.py @@ -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, 403, 403, 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_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,6 +145,30 @@ def test_wiki_page_list(client, data): assert response.status_code == 200 +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_create(client, data): url = reverse('wiki-list') @@ -270,7 +212,8 @@ def test_wiki_page_create(client, data): 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_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}) @@ -285,68 +228,36 @@ def test_wiki_page_patch(client, data): ] 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] + 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] - 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] + 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] - 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] + 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] - 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] + 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_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) - 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_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_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, @@ -357,35 +268,278 @@ 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, 403, 403, 200, 200] + 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_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_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_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["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_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["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_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_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, 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_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] + 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]