From bed01cbdd981fa509b80749d0af3bc21cf843b19 Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Wed, 6 Sep 2023 17:18:07 +0200 Subject: [PATCH 01/10] fix user account update signals triggering (#1274) --- CHANGELOG.rst | 10 ++++++++++ docs/source/conf.py | 2 +- docs/source/major_changes.rst | 9 +++++++++ projectroles/apps.py | 3 +++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 34c78cdd..a2b53f22 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,16 @@ Changelog for the **SODAR Core** Django app package. Loosely follows the `Keep a Changelog `_ guidelines. +Unreleased +========== + +Fixed +----- + +- **Projectroles** + - User account update signals not triggered on login (#1274) + + v0.13.1 (2023-08-30) ==================== diff --git a/docs/source/conf.py b/docs/source/conf.py index dd3bedc0..8e677798 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -29,7 +29,7 @@ # The short X.Y version version = '0.13' # The full version, including alpha/beta/rc tags -release = '0.13.1' +release = '0.13.2-WIP' # -- General configuration --------------------------------------------------- diff --git a/docs/source/major_changes.rst b/docs/source/major_changes.rst index 93e94d77..2e4b0cd4 100644 --- a/docs/source/major_changes.rst +++ b/docs/source/major_changes.rst @@ -10,6 +10,15 @@ older SODAR Core version. For a complete list of changes in current and previous releases, see the :ref:`full changelog`. +v0.13.2 (WIP) +************* + +Release Highlights +================== + +- General bug fixes and minor updates + + v0.13.1 (2023-08-30) ******************** diff --git a/projectroles/apps.py b/projectroles/apps.py index 106c3a31..3118ab5d 100644 --- a/projectroles/apps.py +++ b/projectroles/apps.py @@ -3,3 +3,6 @@ class ProjectrolesConfig(AppConfig): name = 'projectroles' + + def ready(self): + import projectroles.signals # noqa From a47e9e2c877c2f89a53ea6595f1a29fb3ad79a5f Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Thu, 7 Sep 2023 10:45:52 +0200 Subject: [PATCH 02/10] add APIProjectContextMixin queryset override (#1273) --- CHANGELOG.rst | 7 ++++++ docs/source/major_changes.rst | 1 + projectroles/views_api.py | 46 +++++++++++++++++++++++------------ 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a2b53f22..70dbeb99 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,13 @@ Changelog for the **SODAR Core** Django app package. Loosely follows the Unreleased ========== +Added +----- + +- **Projectroles** + - ``queryset_project_field`` override in ``APIProjectContextMixin`` (#1273) + + Fixed ----- diff --git a/docs/source/major_changes.rst b/docs/source/major_changes.rst index 2e4b0cd4..3f7c2b2e 100644 --- a/docs/source/major_changes.rst +++ b/docs/source/major_changes.rst @@ -16,6 +16,7 @@ v0.13.2 (WIP) Release Highlights ================== +- Add REST API project context queryset field override - General bug fixes and minor updates diff --git a/projectroles/views_api.py b/projectroles/views_api.py index c5b7ce27..2b576794 100644 --- a/projectroles/views_api.py +++ b/projectroles/views_api.py @@ -118,14 +118,15 @@ class SODARAPIProjectPermission(ProjectAccessMixin, BasePermission): single permission_required attribute. Also works with Knox token based views. - This must be used in the permission_classes attribute in order for token + This must be used in the ``permission_classes`` attribute in order for token authentication to work. - Requires implementing either permission_required or - get_permission_required() in the view. + Requires implementing either ``permission_required`` or + ``get_permission_required()`` in the view. - Project type can be restricted to PROJECT_TYPE_CATEGORY or - PROJECT_TYPE_PROJECT by setting the project_type attribute in the view. + Project type can be restricted to ``PROJECT_TYPE_CATEGORY`` or + ``PROJECT_TYPE_PROJECT``, as defined in SODAR constants, by setting the + ``project_type`` attribute in the view. """ def has_permission(self, request, view): @@ -232,11 +233,12 @@ class SODARAPIBaseMixin: class SODARAPIBaseProjectMixin(ProjectAccessMixin, SODARAPIBaseMixin): """ - API view mixin for the base DRF APIView class with project permission + API view mixin for the base DRF ``APIView`` class with project permission checking, but without serializers and other generic view functionality. - Project type can be restricted to PROJECT_TYPE_CATEGORY or - PROJECT_TYPE_PROJECT by setting the project_type attribute in the view. + Project type can be restricted to ``PROJECT_TYPE_CATEGORY`` or + ``PROJECT_TYPE_PROJECT``, as defined in SODAR constants, by setting the + ``project_type`` attribute in the view. """ permission_classes = [SODARAPIProjectPermission] @@ -247,6 +249,10 @@ class APIProjectContextMixin(ProjectAccessMixin): """ Mixin to provide project context and queryset for generic API views. Can be used both in SODAR and SODAR Core API base views. + + If your model doesn't have a direct "project" relation, set + ``queryset_project_field`` in the implementing class to query based on e.g. + a nested foreignkey relation. """ def get_serializer_context(self, *args, **kwargs): @@ -255,8 +261,9 @@ def get_serializer_context(self, *args, **kwargs): return context def get_queryset(self): + project_field = getattr(self, 'queryset_project_field', 'project') return self.__class__.serializer_class.Meta.model.objects.filter( - project=self.get_project() + **{project_field: self.get_project()} ) @@ -267,18 +274,24 @@ class SODARAPIGenericProjectMixin( API view mixin for generic DRF API views with serializers, SODAR project context and permission checkin. - Unless overriding permission_classes with their own implementation, the user - MUST supply a permission_required attribute. + Unless overriding ``permission_classes`` with their own implementation, the + user MUST supply a ``permission_required`` attribute. + + Replace ``lookup_url_kwarg`` with your view's url kwarg (SODAR project + compatible model name in lowercase). - Replace lookup_url_kwarg with your view's url kwarg (SODAR project - compatible model name in lowercase) + If the lookup is done via a foreign key, change the ``lookup_field`` + attribute of your class into ``foreignkey__sodar_uuid``, e.g. + ``project__sodar_uuid`` for lists. - If the lookup is done via the project object, change lookup_field into - "sodar_uuid" + If your object(s) don't have a direct ``project`` relation, update the + ``queryset_project_field`` to point to the field, e.g. + ``someothermodel__project``. """ lookup_field = 'sodar_uuid' # Use project__sodar_uuid for lists lookup_url_kwarg = 'project' # Replace with relevant model + queryset_project_field = 'project' # Replace if no direct project relation class ProjectQuerysetMixin: @@ -316,7 +329,7 @@ class CoreAPIBaseMixin: class CoreAPIBaseProjectMixin(ProjectAccessMixin, CoreAPIBaseMixin): """ - SODAR Core API view mixin for the base DRF APIView class with project + SODAR Core API view mixin for the base DRF ``APIView`` class with project permission checking, but without serializers and other generic view functionality. """ @@ -331,6 +344,7 @@ class CoreAPIGenericProjectMixin( lookup_field = 'sodar_uuid' # Use project__sodar_uuid for lists lookup_url_kwarg = 'project' # Replace with relevant model + queryset_project_field = 'project' # Replace if no direct project relation # Projectroles Specific Base Views and Mixins ---------------------------------- From 43263b2d080ad313178aed93190091c9b16030ac Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Thu, 7 Sep 2023 13:40:12 +0200 Subject: [PATCH 03/10] fix project list rendering with finder roles (#1276) --- CHANGELOG.rst | 1 + docs/source/major_changes.rst | 1 + projectroles/tests/test_views_ajax.py | 65 ++++++++++++++++----------- projectroles/views_ajax.py | 7 ++- 4 files changed, 46 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 70dbeb99..dd008274 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -20,6 +20,7 @@ Fixed - **Projectroles** - User account update signals not triggered on login (#1274) + - Project list rendering failure with finder role (#1276) v0.13.1 (2023-08-30) diff --git a/docs/source/major_changes.rst b/docs/source/major_changes.rst index 3f7c2b2e..160a2c10 100644 --- a/docs/source/major_changes.rst +++ b/docs/source/major_changes.rst @@ -17,6 +17,7 @@ Release Highlights ================== - Add REST API project context queryset field override +- Fix project list view rendering issues with finder role - General bug fixes and minor updates diff --git a/projectroles/tests/test_views_ajax.py b/projectroles/tests/test_views_ajax.py index 503073e6..4b0e70dc 100644 --- a/projectroles/tests/test_views_ajax.py +++ b/projectroles/tests/test_views_ajax.py @@ -47,13 +47,12 @@ def setUp(self): self.cat_contributor_as = self.make_assignment( self.project, self.user_contributor_cat, self.role_contributor ) + self.url = reverse('projectroles:ajax_project_list') def test_get(self): """Test project list retrieval""" with self.login(self.user): - response = self.client.get( - reverse('projectroles:ajax_project_list'), - ) + response = self.client.get(self.url) self.assertEqual(response.status_code, 200) expected = { 'projects': [ @@ -96,9 +95,7 @@ def test_get_parent(self): """Test project list with parent project""" with self.login(self.user): response = self.client.get( - reverse('projectroles:ajax_project_list') - + '?parent=' - + str(self.category.sodar_uuid), + self.url + '?parent=' + str(self.category.sodar_uuid), ) self.assertEqual(response.status_code, 200) expected = { @@ -127,27 +124,21 @@ def test_get_parent(self): def test_get_inherited_owner(self): """Test project list for inherited owner""" with self.login(self.user_owner_cat): - response = self.client.get( - reverse('projectroles:ajax_project_list'), - ) + response = self.client.get(self.url) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data['projects']), 2) def test_get_inherited_contrib(self): """Test project list for inherited contributor""" with self.login(self.user_contributor_cat): - response = self.client.get( - reverse('projectroles:ajax_project_list'), - ) + response = self.client.get(self.url) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data['projects']), 2) def test_get_no_results(self): """Test project list with no results""" with self.login(self.user_no_roles): - response = self.client.get( - reverse('projectroles:ajax_project_list'), - ) + response = self.client.get(self.url) self.assertEqual(response.status_code, 200) self.assertEqual(response.data['projects'], []) self.assertIsNotNone(response.data['messages'].get('no_projects')) @@ -156,9 +147,7 @@ def test_get_project_parent(self): """Test project list with project as parent (should fail)""" with self.login(self.user): response = self.client.get( - reverse('projectroles:ajax_project_list') - + '?parent=' - + str(self.project.sodar_uuid), + self.url + '?parent=' + str(self.project.sodar_uuid), ) self.assertEqual(response.status_code, 400) @@ -167,9 +156,7 @@ def test_get_finder(self): user_finder = self.make_user('user_finder') self.make_assignment(self.category, user_finder, self.role_finder) with self.login(user_finder): - response = self.client.get( - reverse('projectroles:ajax_project_list') - ) + response = self.client.get(self.url) self.assertEqual(response.status_code, 200) res_data = response.data['projects'] self.assertEqual(len(res_data), 2) @@ -192,9 +179,7 @@ def test_get_finder_parent(self): self.make_assignment(self.category, user_finder, self.role_finder) with self.login(user_finder): response = self.client.get( - reverse('projectroles:ajax_project_list') - + '?parent=' - + str(self.category.sodar_uuid), + self.url + '?parent=' + str(self.category.sodar_uuid), ) self.assertEqual(response.status_code, 200) res_data = response.data['projects'] @@ -215,9 +200,7 @@ def test_get_finder_nested(self): user_finder = self.make_user('user_finder') self.make_assignment(sub_cat, user_finder, self.role_finder) with self.login(user_finder): - response = self.client.get( - reverse('projectroles:ajax_project_list') - ) + response = self.client.get(self.url) self.assertEqual(response.status_code, 200) res_data = response.data['projects'] self.assertEqual(len(res_data), 3) @@ -228,6 +211,34 @@ def test_get_finder_nested(self): self.assertEqual(res_data[2]['title'], sub_project.title) self.assertEqual(res_data[2]['access'], False) + def test_get_finder_other_branch(self): + """Test project list with finder role in another branch""" + # Give regular access to self.project + user_finder = self.make_user('user_finder') + self.make_assignment(self.project, user_finder, self.role_guest) + branch_cat = self.make_project( + 'TextCategory2', PROJECT_TYPE_CATEGORY, None + ) + self.make_assignment(branch_cat, self.user_owner, self.role_owner) + branch_project = self.make_project( + 'BranchProject', PROJECT_TYPE_PROJECT, branch_cat + ) + self.make_assignment(branch_project, self.user_owner, self.role_owner) + self.make_assignment(branch_cat, user_finder, self.role_finder) + with self.login(user_finder): + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + res_data = response.data['projects'] + self.assertEqual(len(res_data), 4) + self.assertEqual(res_data[0]['title'], self.category.title) + self.assertEqual(res_data[0]['access'], True) + self.assertEqual(res_data[1]['title'], self.project.title) + self.assertEqual(res_data[1]['access'], True) + self.assertEqual(res_data[2]['title'], branch_cat.title) + self.assertEqual(res_data[2]['access'], True) + self.assertEqual(res_data[3]['title'], branch_project.title) + self.assertEqual(res_data[3]['access'], False) + class TestProjectListColumnAjaxView( ProjectMixin, RoleAssignmentMixin, TestViewsBase diff --git a/projectroles/views_ajax.py b/projectroles/views_ajax.py index 225db969..1f54074d 100644 --- a/projectroles/views_ajax.py +++ b/projectroles/views_ajax.py @@ -189,7 +189,12 @@ def _get_access(cls, project, user, finder_cats, depth): ): return True # If user has finder role in a parent category, we need to check role - if finder_cats and depth > 0: + p_ft = project.full_title + if ( + finder_cats + and depth > 0 + and any([p_ft.startswith(c + CAT_DELIMITER) for c in finder_cats]) + ): for i in range(0, depth + 1): c = ' / '.join(project.full_title.split(' / ')[:i]) if c in finder_cats: From 792a099d39750e499797166cb69f8c6400214b2b Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Fri, 8 Sep 2023 12:38:56 +0200 Subject: [PATCH 04/10] update timeline layout (#1720, #1721) --- CHANGELOG.rst | 6 ++++ timeline/plugins.py | 7 ++-- timeline/static/timeline/css/timeline.css | 33 ++++++++----------- timeline/templates/timeline/_list_item.html | 14 +++++--- .../templates/timeline/timeline_site.html | 6 ++-- 5 files changed, 36 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dd008274..d1a27406 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,12 @@ Added - **Projectroles** - ``queryset_project_field`` override in ``APIProjectContextMixin`` (#1273) +Changed +------- + +- **Timeline** + - Update column width and responsiveness handling (#1721) + - View icon display for site views (#1720) Fixed ----- diff --git a/timeline/plugins.py b/timeline/plugins.py index defb7353..60cb1299 100644 --- a/timeline/plugins.py +++ b/timeline/plugins.py @@ -154,7 +154,7 @@ class SiteAppPlugin(SiteAppPluginPoint): urls = urlpatterns #: Iconify icon - icon = 'mdi:clock-time-eight' + icon = 'mdi:clock-time-eight-outline' #: Description string description = 'Timeline of Site-Wide Events' @@ -179,10 +179,11 @@ class AdminSiteAppPlugin(SiteAppPluginPoint): urls = urlpatterns #: Iconify icon - icon = 'mdi:cog-counterclockwise' + # icon = 'mdi:clock-star-four-points-outline' + icon = 'mdi:web-clock' #: Description string - description = 'Admin view for all site events' + description = 'Admin view for all timeline events on the site' #: Entry point URL ID entry_point_url_id = 'timeline:timeline_site_admin' diff --git a/timeline/static/timeline/css/timeline.css b/timeline/static/timeline/css/timeline.css index d5df89d7..4096066e 100644 --- a/timeline/static/timeline/css/timeline.css +++ b/timeline/static/timeline/css/timeline.css @@ -1,10 +1,20 @@ /* Main table */ +table#sodar-tl-table { + display: inline-table; +} table#sodar-tl-table tbody tr td:nth-child(1), table#sodar-tl-table tbody tr td:nth-child(2), table#sodar-tl-table tbody tr td:nth-child(3) { white-space: nowrap; } - +table#sodar-tl-table tbody tr td:nth-child(2) { + width: 200px; + max-width: 200px; +} +table#sodar-tl-table tbody tr td:nth-child(3) { + width: 220px; + max-width: 220px; +} table#sodar-tl-table tbody tr td:nth-child(4) { width: 100%; } @@ -14,11 +24,9 @@ table#sodar-tl-table-detail tbody tr td:nth-child(1), table#sodar-tl-table-detail tbody tr td:nth-child(3) { white-space: nowrap; } - table#sodar-tl-table-detail tbody tr td:nth-child(2) { width: 100%; } - table#sodar-tl-table-extra-data tbody tr td:nth-child(1) { white-space: nowrap; width: 100%; @@ -27,44 +35,37 @@ table#sodar-tl-table-extra-data tbody tr td:nth-child(1) { a.sodar-tl-link-detail:hover { text-decoration: underline; } - a.sodar-tl-link-extra-data:hover { text-decoration: underline; cursor: pointer; } - a.sodar-tl-link-extra { cursor: pointer; } - a.sodar-tl-link-status-extra-data:hover { cursor: pointer; } - .popover { font-size: 100%; /* Fix for Bootstrap 4.4 */ } /* Responsive modifications */ -@media screen and (max-width: 1100px) { +@media screen and (max-width: 1300px) { .table#sodar-tl-table thead tr th:nth-child(2), .table#sodar-tl-table tbody tr td:nth-child(2) { display: none; } } - -@media screen and (max-width: 900px) { +@media screen and (max-width: 1100px) { .table#sodar-tl-table tbody tr td:nth-child(1) { white-space: normal; } - .table#sodar-tl-table thead tr th:nth-child(3), .table#sodar-tl-table tbody tr td:nth-child(3) { display: none; } } - -@media screen and (max-width: 500px) { +@media screen and (max-width: 700px) { .table#sodar-tl-table thead tr th:nth-child(5), .table#sodar-tl-table tbody tr td:nth-child(5) { display: none; @@ -75,24 +76,19 @@ a.sodar-tl-link-status-extra-data:hover { max-width: 75% !important; font-family: monospace; } - pre.sodar-tl-json { font-family: monospace; font-size: 85%; } - .json-open-bracket, .json-close-bracket { color: #CC0011; } - .json-property { color: #1A5988; } - .json-semi-colon { color: #14171A; } - .json-value { color: #222222; } @@ -104,7 +100,6 @@ pre.sodar-tl-json { flex-wrap: wrap; border-bottom: 1px solid #dee2e6; } - .sodar-tl-copy-btn { position: absolute; top: 10px; diff --git a/timeline/templates/timeline/_list_item.html b/timeline/templates/timeline/_list_item.html index b356f76f..c7b1907a 100644 --- a/timeline/templates/timeline/_list_item.html +++ b/timeline/templates/timeline/_list_item.html @@ -21,14 +21,18 @@ {% endif %} - {% get_app_icon_html event plugin_lookup as event_icon %} - {{ event_icon|safe }} - {{ event.event_name }} +
+ {% get_app_icon_html event plugin_lookup as event_icon %} + {{ event_icon|safe }} + {{ event.event_name }} +
{% if event.user %} - {% get_user_html event.user as user_html %} - {{ user_html|safe }} +
+ {% get_user_html event.user as user_html %} + {{ user_html|safe }} +
{% else %} N/A {% endif %} diff --git a/timeline/templates/timeline/timeline_site.html b/timeline/templates/timeline/timeline_site.html index 88e54fab..6c097113 100644 --- a/timeline/templates/timeline/timeline_site.html +++ b/timeline/templates/timeline/timeline_site.html @@ -26,10 +26,10 @@

- {% if timeline_mode == 'site' %} - + {% if timeline_mode == 'site' or timeline_mode == 'object' %} + {% else %} - + {% endif %} {{ timeline_title }}

From b6acc876d6142538ce3459f5a30b0bc13a20d87c Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Mon, 18 Sep 2023 13:36:27 +0200 Subject: [PATCH 05/10] update permission tests (#1267) --- CHANGELOG.rst | 4 + adminalerts/tests/test_permissions.py | 142 +- adminalerts/tests/test_permissions_ajax.py | 28 +- appalerts/tests/test_permissions.py | 106 +- example_project_app/tests/test_permissions.py | 40 +- filesfolders/tests/test_permissions.py | 855 +++---- filesfolders/tests/test_permissions_api.py | 1537 +++++------- projectroles/tests/test_permissions.py | 2229 ++++++++++------- projectroles/tests/test_permissions_ajax.py | 101 +- projectroles/tests/test_permissions_api.py | 1808 ++++++++----- siteinfo/tests/test_permissions.py | 22 +- timeline/tests/test_permissions.py | 200 +- timeline/tests/test_permissions_ajax.py | 453 ++-- timeline/views.py | 11 +- tokens/tests/test_permissions.py | 52 +- userprofile/tests/test_permissions.py | 42 +- 16 files changed, 4165 insertions(+), 3465 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d1a27406..e5eb1774 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,6 +17,8 @@ Added Changed ------- +- **General** + - Refactor and cleanup permission tests (#1267) - **Timeline** - Update column width and responsiveness handling (#1721) - View icon display for site views (#1720) @@ -27,6 +29,8 @@ Fixed - **Projectroles** - User account update signals not triggered on login (#1274) - Project list rendering failure with finder role (#1276) +- **Timeline** + - Ajax view permission test issues (#1267) v0.13.1 (2023-08-30) diff --git a/adminalerts/tests/test_permissions.py b/adminalerts/tests/test_permissions.py index ebd09aa6..48d73ef6 100644 --- a/adminalerts/tests/test_permissions.py +++ b/adminalerts/tests/test_permissions.py @@ -1,4 +1,4 @@ -"""Permission tests for the adminalerts app""" +"""Test for UI view permissions in the adminalerts app""" from django.test import override_settings from django.urls import reverse @@ -9,8 +9,8 @@ from adminalerts.tests.test_models import AdminAlertMixin -class TestAdminAlertPermissions(AdminAlertMixin, TestSiteAppPermissionBase): - """Tests for AdminAlert permissions""" +class AdminalertsPermissionTestBase(AdminAlertMixin, TestSiteAppPermissionBase): + """Base test class for adminalerts UI view permission tests""" def setUp(self): super().setUp() @@ -22,99 +22,123 @@ def setUp(self): active=True, ) - def test_alert_list(self): - """Test permissions for AdminAlert list""" - url = reverse('adminalerts:list') + +class TestAdminAlertListView(AdminalertsPermissionTestBase): + """Permission tests for AdminAlertListView""" + + def setUp(self): + super().setUp() + self.url = reverse('adminalerts:list') + + def test_get(self): + """Test AdminAlertListView GET""" good_users = [self.superuser] bad_users = [self.anonymous, self.regular_user] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_alert_list_anon(self): - """Test permissions for AdminAlert list with anonymous access""" - url = reverse('adminalerts:list') + def test_get_anon(self): + """Test GET with anonymous access""" good_users = [self.superuser] bad_users = [self.anonymous, self.regular_user] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) + - def test_alert_detail(self): - """Test permissions for AdminAlert details""" - url = reverse( +class TestAdminAlertDetailView(AdminalertsPermissionTestBase): + """Permission tests for dminAlertDetailView""" + + def setUp(self): + super().setUp() + self.url = reverse( 'adminalerts:detail', kwargs={'adminalert': self.alert.sodar_uuid} ) + + def test_get(self): + """Test AdminAlertDetailView GET""" good_users = [self.superuser, self.regular_user] bad_users = [self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_alert_detail_anon(self): - """Test permissions for AdminAlert details with anonymous access""" - url = reverse( - 'adminalerts:detail', kwargs={'adminalert': self.alert.sodar_uuid} - ) + def test_get_anon(self): + """Test GET with anonymous access""" good_users = [self.superuser, self.regular_user] bad_users = [self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) - def test_alert_create(self): - """Test permissions for AdminAlert creation""" - url = reverse('adminalerts:create') + +class TestAdminAlertCreateView(AdminalertsPermissionTestBase): + """Permission tests for AdminAlertCreateView""" + + def setUp(self): + super().setUp() + self.url = reverse('adminalerts:create') + + def test_get(self): + """Test AdminAlertCreateView GET""" good_users = [self.superuser] bad_users = [self.anonymous, self.regular_user] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_alert_create_anon(self): - """Test permissions for AdminAlert creation with anonymous access""" - url = reverse('adminalerts:create') + def test_get_anon(self): + """Test GET with anonymous access""" good_users = [self.superuser] bad_users = [self.anonymous, self.regular_user] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) + - def test_alert_update(self): - """Test permissions for AdminAlert updating""" - url = reverse( +class TestAdminAlertUpdateView(AdminalertsPermissionTestBase): + """Permission tests for AdminAlertUpdateView""" + + def setUp(self): + super().setUp() + self.url = reverse( 'adminalerts:update', kwargs={'adminalert': self.alert.sodar_uuid} ) + + def test_get(self): + """Test AdminAlertUpdateView GET""" good_users = [self.superuser] bad_users = [self.anonymous, self.regular_user] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_alert_update_anon(self): - """Test permissions for AdminAlert updating with anonymous access""" - url = reverse( - 'adminalerts:update', kwargs={'adminalert': self.alert.sodar_uuid} - ) + def test_get_anon(self): + """Test GET with anonymous access""" good_users = [self.superuser] bad_users = [self.anonymous, self.regular_user] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) - def test_alert_delete(self): - """Test permissions for AdminAlert deletion""" - url = reverse( + +class TestAdminAlertDeleteView(AdminalertsPermissionTestBase): + """Permission tests for AdminAlertDeleteView""" + + def setUp(self): + super().setUp() + self.url = reverse( 'adminalerts:delete', kwargs={'adminalert': self.alert.sodar_uuid} ) + + def test_get(self): + """Test AdminAlertDeleteView GET""" good_users = [self.superuser] bad_users = [self.anonymous, self.regular_user] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_alert_delete_anon(self): - """Test permissions for AdminAlert deletion with anonymous access""" - url = reverse( - 'adminalerts:delete', kwargs={'adminalert': self.alert.sodar_uuid} - ) + def test_get_anon(self): + """Test GET with anonymous access""" good_users = [self.superuser] bad_users = [self.anonymous, self.regular_user] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) diff --git a/adminalerts/tests/test_permissions_ajax.py b/adminalerts/tests/test_permissions_ajax.py index be49ee92..9c2bb9e7 100644 --- a/adminalerts/tests/test_permissions_ajax.py +++ b/adminalerts/tests/test_permissions_ajax.py @@ -9,8 +9,10 @@ from adminalerts.tests.test_models import AdminAlertMixin -class TestAdminAlertPermissions(AdminAlertMixin, TestSiteAppPermissionBase): - """Tests for AdminAlert views""" +class TestAdminAlertActiveToggleAjaxView( + AdminAlertMixin, TestSiteAppPermissionBase +): + """Permission tests for AdminAlertActiveToggleAjaxView""" def setUp(self): super().setUp() @@ -21,23 +23,19 @@ def setUp(self): description='description', active=True, ) - - def test_active_toggle(self): - """Test permissions for activation Ajax view""" - url = reverse( + self.url = reverse( 'adminalerts:ajax_active_toggle', kwargs={'adminalert': self.alert.sodar_uuid}, ) + + def test_post(self): + """Test AdminAlertActiveToggleAjaxView POST""" good_users = [self.superuser] bad_users = [self.anonymous, self.regular_user] - self.assert_response(url, good_users, 200, method='POST') - self.assert_response(url, bad_users, 403, method='POST') + self.assert_response(self.url, good_users, 200, method='POST') + self.assert_response(self.url, bad_users, 403, method='POST') @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_active_toggle_anon(self): - """Test permissions for activation Ajax view with anonymous access""" - url = reverse( - 'adminalerts:ajax_active_toggle', - kwargs={'adminalert': self.alert.sodar_uuid}, - ) - self.assert_response(url, self.anonymous, 403, method='POST') + def test_post_anon(self): + """Test POST with anonymous access""" + self.assert_response(self.url, self.anonymous, 403, method='POST') diff --git a/appalerts/tests/test_permissions.py b/appalerts/tests/test_permissions.py index b4f775b5..bce409d7 100644 --- a/appalerts/tests/test_permissions.py +++ b/appalerts/tests/test_permissions.py @@ -1,16 +1,16 @@ -"""Permission tests for the appalerts app""" +"""Test for view permissions in the appalerts app""" +from django.test import override_settings from django.urls import reverse - # Projectroles dependency from projectroles.tests.test_permissions import TestSiteAppPermissionBase from appalerts.tests.test_models import AppAlertMixin -class TestAppAlertPermissions(AppAlertMixin, TestSiteAppPermissionBase): - """Tests for AppAlert permissions""" +class AppalertsPermissionTestBase(AppAlertMixin, TestSiteAppPermissionBase): + """Base test class for appalerts view permission tests""" def setUp(self): super().setUp() @@ -21,46 +21,96 @@ def setUp(self): user=self.regular_user, url=reverse('home') ) - def test_list(self): - """Test permissions for the alert list view""" - url = reverse('appalerts:list') + +class TestAppAlertListView(AppalertsPermissionTestBase): + """Permission tests for AppAlertListView""" + + def setUp(self): + super().setUp() + self.url = reverse('appalerts:list') + + def test_get(self): + """Test AppAlertListView GET""" good_users = [ self.superuser, self.regular_user, self.no_alert_user, ] - bad_users = [self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, self.anonymous, 302) + + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" + self.assert_response(self.url, self.anonymous, 302) + - def test_redirect(self): - """Test permissions for the alert list view""" - url = reverse( +class TestAppAlertRedirectView(AppalertsPermissionTestBase): + """Permission tests for AppAlertLinkRedirectView""" + + def setUp(self): + super().setUp() + self.url = reverse( 'appalerts:redirect', kwargs={'appalert': self.alert.sodar_uuid} ) - bad_url = reverse('appalerts:list') + self.bad_redirect_url = reverse('appalerts:list') + + def test_get(self): + """Test AppAlertLinkRedirectView GET""" good_users = [self.regular_user] bad_users = [self.superuser, self.no_alert_user, self.anonymous] self.assert_response( - url, good_users, 302, redirect_user=reverse('home') + self.url, good_users, 302, redirect_user=reverse('home') + ) + self.assert_response( + self.url, bad_users, 302, redirect_user=self.bad_redirect_url ) - self.assert_response(url, bad_users, 302, redirect_user=bad_url) - def test_ajax_status(self): - """Test permissions for the alert status ajax view""" - url = reverse('appalerts:ajax_status') + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" + self.assert_response( + self.url, self.anonymous, 302, redirect_user=self.bad_redirect_url + ) + + +class TestAppAlertStatusAjaxView(AppalertsPermissionTestBase): + """Permission tests for AppAlertStatusAjaxView""" + + def setUp(self): + super().setUp() + self.url = reverse('appalerts:ajax_status') + + def test_get(self): + """Test AppAlertStatusAjaxView GET""" good_users = [self.superuser, self.regular_user, self.no_alert_user] - bad_users = [self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 403) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, self.anonymous, 403) - def test_ajax_dismiss(self): - """Test permissions for the alert dismiss ajax view""" - url = reverse( + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" + self.assert_response(self.url, self.anonymous, 403) + + +class TestAppAlertDismissAjaxView(AppalertsPermissionTestBase): + """Permission tests for AppAlertDismissAjaxView""" + + def setUp(self): + super().setUp() + self.url = reverse( 'appalerts:ajax_dismiss', kwargs={'appalert': self.alert.sodar_uuid} ) + + def test_post(self): + """Test AppAlertDismissAjaxView POST""" good_users = [self.regular_user] bad_users = [self.superuser, self.no_alert_user] - self.assert_response(url, good_users, 200, method='POST') - self.assert_response(url, bad_users, 404, method='POST') - self.assert_response(url, self.anonymous, 403, method='POST') + self.assert_response(self.url, good_users, 200, method='POST') + self.assert_response(self.url, bad_users, 404, method='POST') + self.assert_response(self.url, self.anonymous, 403, method='POST') + + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_post_anon(self): + """Test POST with anonymous access""" + self.assert_response(self.url, self.anonymous, 403, method='POST') diff --git a/example_project_app/tests/test_permissions.py b/example_project_app/tests/test_permissions.py index 0c46c924..34eedc21 100644 --- a/example_project_app/tests/test_permissions.py +++ b/example_project_app/tests/test_permissions.py @@ -1,5 +1,6 @@ -"""UI view permission tests for example_project_app""" +"""Test for UI view permissions in example_project_app""" +from django.test import override_settings from django.urls import reverse # Projectroles dependency @@ -10,11 +11,11 @@ from filesfolders.tests.test_models import FolderMixin -class TestExampleViews(FolderMixin, AppSettingMixin, TestProjectPermissionBase): - """Permission tests for example UI views""" +class TestExampleView(FolderMixin, AppSettingMixin, TestProjectPermissionBase): + """Permission tests for ExampleView""" - def test_example_project(self): - """Test permissions for example view with project""" + def test_get(self): + """Test ExampleView GET""" url = reverse( 'example_project_app:example', kwargs={'project': self.project.sodar_uuid}, @@ -36,8 +37,17 @@ def test_example_project(self): self.project.set_public() self.assert_response(url, self.user_no_roles, 200) - def test_example_ext_model(self): - """Test permissions for example view with model from another app""" + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" + url = reverse( + 'example_project_app:example', + kwargs={'project': self.project.sodar_uuid}, + ) + self.assert_response(url, self.anonymous, 302) + + def test_get_ext_model(self): + """Test GET with model from another app""" # Create object from filesfolders app model folder = self.make_folder( name='TestFolder', @@ -66,3 +76,19 @@ def test_example_ext_model(self): self.assert_response(url, bad_users, 302) self.project.set_public() self.assert_response(url, self.user_no_roles, 200) + + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_ext_model_anon(self): + """Test GET with model from another app and anonymous access""" + folder = self.make_folder( + name='TestFolder', + project=self.project, + folder=None, + owner=self.user_owner, + description='', + ) + url = reverse( + 'example_project_app:example_ext_model', + kwargs={'filesfolders__folder': folder.sodar_uuid}, + ) + self.assert_response(url, self.anonymous, 302) diff --git a/filesfolders/tests/test_permissions.py b/filesfolders/tests/test_permissions.py index cd20a124..7da5cc5f 100644 --- a/filesfolders/tests/test_permissions.py +++ b/filesfolders/tests/test_permissions.py @@ -1,4 +1,4 @@ -"""Permission tests for the filesfolders app""" +"""Tests for UI view permissions in the filesfolders app""" from django.test import override_settings from django.urls import reverse @@ -31,14 +31,65 @@ SECRET = '7dqq83clo2iyhg29hifbor56og6911r5' -class TestListPermissions(TestProjectPermissionBase): - """Tests for the file list view""" +# Base Classes and Mixins ------------------------------------------------------ - def test_list(self): - """Test file list""" - url = reverse( + +class FilesfoldersPermissionTestMixin(FolderMixin, FileMixin, HyperLinkMixin): + """Mixin for filesfolders view permission test helpers""" + + def make_test_folder(self): + return self.make_folder( + name='folder', + project=self.project, + folder=None, + owner=self.user_owner, # Project owner is the owner of folder + description='', + ) + + def make_test_file(self, public=False): + if public: + app_settings.set( + APP_NAME, 'allow_public_links', True, project=self.project + ) + return self.make_file( + name='file.txt', + file_name='file.txt', + file_content=bytes('content'.encode('utf-8')), + project=self.project, + folder=None, + owner=self.user_owner, # Project owner is the file owner + description='', + public_url=public, + secret=SECRET, + ) + + def make_test_link(self): + return self.make_hyperlink( + name='Link', + url='https://www.google.com/', + project=self.project, + folder=None, + owner=self.user_owner, + description='', + ) + + +# Test Cases ------------------------------------------------------------------- + + +class TestProjectFileViewPermissions( + FilesfoldersPermissionTestMixin, TestProjectPermissionBase +): + """Tests for ProjectFileView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( 'filesfolders:list', kwargs={'project': self.project.sodar_uuid} ) + + def test_get(self): + """Test ProjectFileView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -51,28 +102,22 @@ def test_list(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) # Test public project self.project.set_public() - self.assert_response(url, self.user_no_roles, 200) - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.user_no_roles, 200) + self.assert_response(self.url, self.anonymous, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_list_anon(self): - """Test file list with anonynomus access""" - url = reverse( - 'filesfolders:list', kwargs={'project': self.project.sodar_uuid} - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, self.anonymous, 200) + self.assert_response(self.url, self.anonymous, 200) - def test_list_archive(self): - """Test file list for archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:list', kwargs={'project': self.project.sodar_uuid} - ) good_users = [ self.superuser, self.user_owner_cat, @@ -85,33 +130,27 @@ def test_list_archive(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 200) - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.user_no_roles, 200) + self.assert_response(self.url, self.anonymous, 302) -class TestFolderPermissions(FolderMixin, TestProjectPermissionBase): - """Tests for Folder views""" +class TestFolderCreateView( + FilesfoldersPermissionTestMixin, TestProjectPermissionBase +): + """Tests for FolderCreateView view permissions""" def setUp(self): super().setUp() - self.folder = self.make_folder( - name='folder', - project=self.project, - folder=None, - owner=self.user_owner, # Project owner is the owner of folder - description='', - ) - - def test_folder_create(self): - """Test folder creation""" - url = reverse( + self.url = reverse( 'filesfolders:folder_create', kwargs={'project': self.project.sodar_uuid}, ) + + def test_get(self): + """Test FolderCreateView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -128,32 +167,21 @@ def test_folder_create(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_folder_create_anon(self): - """Test folder creation with anonymous access""" - url = reverse( - 'filesfolders:folder_create', - kwargs={'project': self.project.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.anonymous, 302) - def test_folder_create_archive(self): - """Test folder creation for archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:folder_create', - kwargs={'project': self.project.sodar_uuid}, - ) - good_users = [ - self.superuser, - ] + good_users = [self.superuser] bad_users = [ self.user_owner_cat, self.user_delegate_cat, @@ -167,14 +195,13 @@ def test_folder_create_archive(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) - def test_folder_create_category(self): - """Test folder creation under category""" + def test_get_category(self): + """Test GET with folder under category (should fail)""" url = reverse( 'filesfolders:folder_create', kwargs={'project': self.category.sodar_uuid}, @@ -195,12 +222,22 @@ def test_folder_create_category(self): ] self.assert_response(url, bad_users, 302) - def test_folder_update(self): - """Test folder updating""" - url = reverse( + +class TestFolderUpdateView( + FilesfoldersPermissionTestMixin, TestProjectPermissionBase +): + """Tests for FolderUpdateView permissions""" + + def setUp(self): + super().setUp() + folder = self.make_test_folder() + self.url = reverse( 'filesfolders:folder_update', - kwargs={'item': self.folder.sodar_uuid}, + kwargs={'item': folder.sodar_uuid}, ) + + def test_get(self): + """Test FolderUpdateView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -217,29 +254,20 @@ def test_folder_update(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_folder_update_anon(self): - """Test folder updating with anonymous access""" - url = reverse( - 'filesfolders:folder_update', - kwargs={'item': self.folder.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.anonymous, 302) - def test_folder_update_archive(self): - """Test folder updating for archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:folder_update', - kwargs={'item': self.folder.sodar_uuid}, - ) good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -254,18 +282,27 @@ def test_folder_update_archive(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) - def test_folder_delete(self): - """Test folder deletion""" - url = reverse( + +class TestFolderDeleteView( + FilesfoldersPermissionTestMixin, TestProjectPermissionBase +): + """Tests for FolderDeleteView permissions""" + + def setUp(self): + super().setUp() + folder = self.make_test_folder() + self.url = reverse( 'filesfolders:folder_delete', - kwargs={'item': self.folder.sodar_uuid}, + kwargs={'item': folder.sodar_uuid}, ) + + def test_get(self): + """Test FolderDeleteView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -277,34 +314,25 @@ def test_folder_delete(self): self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, - self.user_contributor, # NOTE: not the owner of the folder + self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_folder_delete_anon(self): - """Test folder deletion with anonymous access""" - url = reverse( - 'filesfolders:folder_delete', - kwargs={'item': self.folder.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.anonymous, 302) - def test_folder_delete_archive(self): - """Test folder deletion for archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:folder_delete', - kwargs={'item': self.folder.sodar_uuid}, - ) good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -319,41 +347,26 @@ def test_folder_delete_archive(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) -class TestFilePermissions(FileMixin, TestProjectPermissionBase): - """Tests for File views""" +class TestFileCreateView( + FilesfoldersPermissionTestMixin, TestProjectPermissionBase +): + """Tests FileCreateView permissions""" def setUp(self): super().setUp() - app_settings.set( - APP_NAME, 'allow_public_links', True, project=self.project - ) - self.file_content = bytes('content'.encode('utf-8')) - # Init file - self.file = self.make_file( - name='file.txt', - file_name='file.txt', - file_content=self.file_content, - project=self.project, - folder=None, - owner=self.user_owner, # Project owner is the file owner - description='', - public_url=True, - secret=SECRET, - ) - - def test_file_create(self): - """Test file creation""" - url = reverse( + self.url = reverse( 'filesfolders:file_create', kwargs={'project': self.project.sodar_uuid}, ) + + def test_get(self): + """Test FileCreateView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -370,29 +383,20 @@ def test_file_create(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_file_create_anon(self): - """Test file creation with anonymous access""" - url = reverse( - 'filesfolders:file_create', - kwargs={'project': self.project.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.anonymous, 302) - def test_file_create_archive(self): - """Test file creation for archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:file_create', - kwargs={'project': self.project.sodar_uuid}, - ) good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -407,14 +411,13 @@ def test_file_create_archive(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) - def test_file_create_category(self): - """Test file creation under category""" + def test_get_category(self): + """Test GET under category (should fail)""" url = reverse( 'filesfolders:file_create', kwargs={'project': self.category.sodar_uuid}, @@ -435,11 +438,21 @@ def test_file_create_category(self): ] self.assert_response(url, bad_users, 302) - def test_file_update(self): - """Test file updating""" - url = reverse( - 'filesfolders:file_update', kwargs={'item': self.file.sodar_uuid} + +class TestFileUpdateView( + FilesfoldersPermissionTestMixin, TestProjectPermissionBase +): + """Tests for FileUpdateView permissions""" + + def setUp(self): + super().setUp() + file = self.make_test_file() + self.url = reverse( + 'filesfolders:file_update', kwargs={'item': file.sodar_uuid} ) + + def test_get(self): + """Test FileUpdateView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -456,27 +469,20 @@ def test_file_update(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_file_update_anon(self): - """Test file updating with anonymous access""" - url = reverse( - 'filesfolders:file_update', kwargs={'item': self.file.sodar_uuid} - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.anonymous, 302) - def test_file_update_archive(self): - """Test file updating for archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:file_update', kwargs={'item': self.file.sodar_uuid} - ) good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -486,22 +492,31 @@ def test_file_update_archive(self): self.user_finder_cat, self.user_owner, self.user_delegate, - self.user_contributor, # NOTE: not the owner of the file + self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) - def test_file_delete(self): - """Test file deletion""" - url = reverse( - 'filesfolders:file_delete', kwargs={'item': self.file.sodar_uuid} + +class TestFileDeleteView( + FilesfoldersPermissionTestMixin, TestProjectPermissionBase +): + """Tests for FileDeleteView permissions""" + + def setUp(self): + super().setUp() + file = self.make_test_file() + self.url = reverse( + 'filesfolders:file_delete', kwargs={'item': file.sodar_uuid} ) + + def test_get(self): + """Test FileDeleteView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -513,32 +528,25 @@ def test_file_delete(self): self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, - self.user_contributor, # NOTE: not the owner of the file + self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_file_delete_anon(self): - """Test file deletion with anonymous access""" - url = reverse( - 'filesfolders:file_delete', kwargs={'item': self.file.sodar_uuid} - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.anonymous, 302) - def test_file_delete_archive(self): - """Test file deletion for archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:file_delete', kwargs={'item': self.file.sodar_uuid} - ) good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -553,18 +561,27 @@ def test_file_delete_archive(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) - def test_file_public_link(self): - """Test generation of a public URL to a file""" - url = reverse( + +class TestFilePublicLinkView( + FilesfoldersPermissionTestMixin, TestProjectPermissionBase +): + """Tests for FilePublicLinkView permissions""" + + def setUp(self): + super().setUp() + file = self.make_test_file(public=True) + self.url = reverse( 'filesfolders:file_public_link', - kwargs={'file': self.file.sodar_uuid}, + kwargs={'file': file.sodar_uuid}, ) + + def test_get(self): + """Test FilePublicLinkView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -581,29 +598,20 @@ def test_file_public_link(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_file_public_link_anon(self): - """Test generation of public URL to file with anonymous access""" - url = reverse( - 'filesfolders:file_public_link', - kwargs={'file': self.file.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.anonymous, 302) - def test_file_public_link_archive(self): - """Test generation of public URL to file for archived project""" + def test_get_archive(self): + """Test get with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:file_public_link', - kwargs={'file': self.file.sodar_uuid}, - ) good_users = [ self.superuser, self.user_owner_cat, @@ -620,18 +628,27 @@ def test_file_public_link_archive(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) - def test_file_serve(self): - """Test file serving for authenticated users""" - url = reverse( + +class TestFileServeView( + FilesfoldersPermissionTestMixin, TestProjectPermissionBase +): + """Tests for FileServeView permissions""" + + def setUp(self): + super().setUp() + file = self.make_test_file() + self.url = reverse( 'filesfolders:file_serve', - kwargs={'file': self.file.sodar_uuid, 'file_name': self.file.name}, + kwargs={'file': file.sodar_uuid, 'file_name': file.name}, ) + + def test_get(self): + """Test FileServeView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -644,20 +661,21 @@ def test_file_serve(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 200) + self.assert_response(self.url, self.anonymous, 302) + + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, self.user_no_roles, 200) - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.anonymous, 200) - def test_file_serve_archive(self): - """Test file serving for authenticated users in archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:file_serve', - kwargs={'file': self.file.sodar_uuid, 'file_name': self.file.name}, - ) good_users = [ self.superuser, self.user_owner_cat, @@ -670,19 +688,57 @@ def test_file_serve_archive(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 200) - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.user_no_roles, 200) + self.assert_response(self.url, self.anonymous, 302) - def test_file_serve_public(self): - """Test public file serving""" - url = reverse( + +class TestFileServePublicView( + FilesfoldersPermissionTestMixin, TestProjectPermissionBase +): + """Tests for FileServePublicView permissions""" + + def setUp(self): + super().setUp() + file = self.make_test_file(public=True) + self.url = reverse( 'filesfolders:file_serve_public', - kwargs={'secret': SECRET, 'file_name': self.file.name}, + kwargs={'secret': SECRET, 'file_name': file.name}, ) + + def test_get(self): + """Test FileServePublicView GET""" + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_owner, + self.user_delegate, + self.user_contributor, + self.user_guest, + self.user_no_roles, + self.anonymous, + ] + self.assert_response(self.url, good_users, 200) + self.project.set_public() + self.assert_response( + self.url, [self.user_no_roles, self.anonymous], 200 + ) + + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" + self.project.set_public() + self.assert_response(self.url, self.anonymous, 200) + + def test_get_archived(self): + """Test FileServePublicView GET with archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, @@ -697,17 +753,17 @@ def test_file_serve_public(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) + self.assert_response(self.url, good_users, 200) + self.project.set_public() + self.assert_response( + self.url, [self.user_no_roles, self.anonymous], 200 + ) - def test_file_serve_public_disabled(self): - """Test public file serving if not allowed in project, should fail""" + def test_get_disabled(self): + """Test GET with public links disabled (should fail)""" app_settings.set( APP_NAME, 'allow_public_links', False, project=self.project ) - url = reverse( - 'filesfolders:file_serve_public', - kwargs={'secret': SECRET, 'file_name': self.file.name}, - ) bad_users = [ self.superuser, self.user_owner_cat, @@ -720,37 +776,25 @@ def test_file_serve_public_disabled(self): self.user_contributor, self.user_guest, self.user_no_roles, + self.anonymous, ] - for user in bad_users: - with self.login(user): - response = self.client.get(url) - self.assertEqual(response.status_code, 400) - # Anonymous - response = self.client.get(url) - self.assertEqual(response.status_code, 400) + self.assert_response(self.url, bad_users, 400) -class TestHyperLinkPermissions(HyperLinkMixin, TestProjectPermissionBase): - """Tests for HyperLink views""" +class TestHyperLinkCreateView( + FilesfoldersPermissionTestMixin, TestProjectPermissionBase +): + """Tests for HyperLinkCreateView permissions""" def setUp(self): super().setUp() - # Init link - self.hyperlink = self.make_hyperlink( - name='Link', - url='http://www.google.com/', - project=self.project, - folder=None, - owner=self.user_owner, - description='', - ) - - def test_hyperlink_create(self): - """Test hyperlink creation""" - url = reverse( + self.url = reverse( 'filesfolders:hyperlink_create', kwargs={'project': self.project.sodar_uuid}, ) + + def test_get(self): + """Test HyperLinkCreateView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -767,29 +811,20 @@ def test_hyperlink_create(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_hyperlink_create_anon(self): - """Test hyperlink creation with anonymous access""" - url = reverse( - 'filesfolders:hyperlink_create', - kwargs={'project': self.project.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.anonymous, 302) - def test_hyperlink_create_archive(self): - """Test hyperlink creation for archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:hyperlink_create', - kwargs={'project': self.project.sodar_uuid}, - ) good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -804,14 +839,13 @@ def test_hyperlink_create_archive(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) - def test_hyperlink_create_category(self): - """Test hyperlink creation under category""" + def test_get_category(self): + """Test GET under category (should fail)""" url = reverse( 'filesfolders:hyperlink_create', kwargs={'project': self.category.sodar_uuid}, @@ -832,12 +866,22 @@ def test_hyperlink_create_category(self): ] self.assert_response(url, bad_users, 302) - def test_hyperlink_update(self): - """Test hyperlink updating""" - url = reverse( + +class TestHyperLinkUpdateView( + FilesfoldersPermissionTestMixin, TestProjectPermissionBase +): + """Tests for HyperLinkUpdateView permissions""" + + def setUp(self): + super().setUp() + link = self.make_test_link() + self.url = reverse( 'filesfolders:hyperlink_update', - kwargs={'item': self.hyperlink.sodar_uuid}, + kwargs={'item': link.sodar_uuid}, ) + + def test_get(self): + """Test HyperLinkUpdateView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -849,24 +893,25 @@ def test_hyperlink_update(self): self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, - self.user_contributor, # NOTE: not the owner of the link + self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) + + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test hyperlink updating with anonymous access""" + self.project.set_public() + self.assert_response(self.url, self.anonymous, 302) - def test_hyperlink_update_archive(self): - """Test hyperlink updating for archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:hyperlink_update', - kwargs={'item': self.hyperlink.sodar_uuid}, - ) good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -881,28 +926,27 @@ def test_hyperlink_update_archive(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) - @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_hyperlink_update_anon(self): - """Test hyperlink updating with anonymous access""" - url = reverse( + +class TestHyperLinkDeleteView( + FilesfoldersPermissionTestMixin, TestProjectPermissionBase +): + """Tests for HyperLinkDeleteView permissions""" + + def setUp(self): + super().setUp() + link = self.make_test_link() + self.url = reverse( 'filesfolders:hyperlink_update', - kwargs={'item': self.hyperlink.sodar_uuid}, + kwargs={'item': link.sodar_uuid}, ) - self.project.set_public() - self.assert_response(url, self.anonymous, 302) - def test_hyperlink_delete(self): - """Test hyperlink deletion""" - url = reverse( - 'filesfolders:hyperlink_delete', - kwargs={'item': self.hyperlink.sodar_uuid}, - ) + def test_get(self): + """Test HyperLinkDeleteView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -919,29 +963,20 @@ def test_hyperlink_delete(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_hyperlink_delete_anon(self): - """Test hyperlink deletion with anonymous access""" - url = reverse( - 'filesfolders:hyperlink_delete', - kwargs={'item': self.hyperlink.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.anonymous, 302) - def test_hyperlink_delete_archive(self): - """Test hyperlink deletion for archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:hyperlink_delete', - kwargs={'item': self.hyperlink.sodar_uuid}, - ) good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -956,32 +991,32 @@ def test_hyperlink_delete_archive(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) -class TestBatchPermissions(FolderMixin, TestProjectPermissionBase): - """Tests for batch editing views""" +class TestBatchEditView( + FilesfoldersPermissionTestMixin, TestProjectPermissionBase +): + """Tests for BatchEditView permissions""" def setUp(self): super().setUp() - self.folder = self.make_folder( - name='folder', - project=self.project, - folder=None, - owner=self.user_owner, # Project owner is the owner of folder - description='', - ) - - def test_batch_edit(self): - """Test access to batch editing confirmation""" - url = reverse( + folder = self.make_test_folder() + self.url = reverse( 'filesfolders:batch_edit', kwargs={'project': self.project.sodar_uuid}, ) + self.post_data = { + 'batch-action': 'delete', + 'user-confirmed': '0', + 'batch_item_Folder_{}'.format(folder.sodar_uuid): '1', + } + + def test_post(self): + """Test BatchEditView POST""" # NOTE: Contributor is OK as checks for object perms happen after POST good_users = [ self.superuser, @@ -998,33 +1033,26 @@ def test_batch_edit(self): self.user_guest, self.user_no_roles, ] - post_data = { - 'batch-action': 'delete', - 'user-confirmed': '0', - 'batch_item_Folder_{}'.format(self.folder.sodar_uuid): '1', - } - for user in good_users: - with self.login(user): - response = self.client.post(url, post_data) - self.assertEqual(response.status_code, 200) - for user in bad_users: - with self.login(user): - response = self.client.post(url, post_data) - self.assertEqual(response.status_code, 302) - # Test public project + self.assert_response( + self.url, good_users, 200, method='POST', data=self.post_data + ) + self.assert_response( + self.url, bad_users, 302, method='POST', data=self.post_data + ) self.project.set_public() - for user in bad_users: - with self.login(user): - response = self.client.post(url, post_data) - self.assertEqual(response.status_code, 302) + self.assert_response( + self.url, bad_users, 302, method='POST', data=self.post_data + ) - def test_batch_edit_archive(self): - """Test access to batch editing confirmation for archived project""" + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_post_anon(self): + """Test POST with anonymous access""" + self.project.set_public() + self.assert_response(self.url, self.anonymous, 302) + + def test_post_archive(self): + """Test POST with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:batch_edit', - kwargs={'project': self.project.sodar_uuid}, - ) good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -1038,22 +1066,13 @@ def test_batch_edit_archive(self): self.user_guest, self.user_no_roles, ] - post_data = { - 'batch-action': 'delete', - 'user-confirmed': '0', - 'batch_item_Folder_{}'.format(self.folder.sodar_uuid): '1', - } - for user in good_users: - with self.login(user): - response = self.client.post(url, post_data) - self.assertEqual(response.status_code, 200) - for user in bad_users: - with self.login(user): - response = self.client.post(url, post_data) - self.assertEqual(response.status_code, 302) - # Test public project + self.assert_response( + self.url, good_users, 200, method='POST', data=self.post_data + ) + self.assert_response( + self.url, bad_users, 302, method='POST', data=self.post_data + ) self.project.set_public() - for user in bad_users: - with self.login(user): - response = self.client.post(url, post_data) - self.assertEqual(response.status_code, 302) + self.assert_response( + self.url, bad_users, 302, method='POST', data=self.post_data + ) diff --git a/filesfolders/tests/test_permissions_api.py b/filesfolders/tests/test_permissions_api.py index 4bb2be34..0e902bd7 100644 --- a/filesfolders/tests/test_permissions_api.py +++ b/filesfolders/tests/test_permissions_api.py @@ -1,4 +1,4 @@ -"""REST API view permission tests for the filesfolders app""" +"""Test for REST API view permissions in the filesfolders app""" import os import uuid @@ -10,56 +10,38 @@ from projectroles.tests.test_permissions_api import ( TestCoreProjectAPIPermissionBase, ) -from projectroles.utils import build_secret -from filesfolders.models import File, Folder, HyperLink -from filesfolders.tests.test_models import ( - FileMixin, - FolderMixin, - HyperLinkMixin, -) +from filesfolders.models import File, HyperLink + +from filesfolders.tests.test_permissions import FilesfoldersPermissionTestMixin # Local constants SECRET = '7dqq83clo2iyhg29hifbor56og6911r5' TEST_DATA_PATH = os.path.dirname(__file__) + '/data/' ZIP_PATH_NO_FILES = TEST_DATA_PATH + 'no_files.zip' +OBJ_UUID = uuid.uuid4() -class TestFolderAPIPermissions(FolderMixin, TestCoreProjectAPIPermissionBase): - """Tests for Folder API view permissions""" - - @classmethod - def _cleanup_folder_create(cls): - Folder.objects.order_by('-pk').first().delete() - - def _cleanup_folder_destroy(self, obj_uuid): - folder = self.make_folder( - name='folder', - project=self.project, - folder=None, - owner=self.user_owner, - description='', - ) - folder.sodar_uuid = obj_uuid - folder.save() +class TestFolderListCreateAPIView( + FilesfoldersPermissionTestMixin, TestCoreProjectAPIPermissionBase +): + """Tests FolderListCreateAPIView permissions""" def setUp(self): super().setUp() - self.folder = self.make_folder( - name='folder', - project=self.project, - folder=None, - owner=self.user_owner, # Project owner is the owner of folder - description='', - ) - - def test_folder_list(self): - """Test permissions for folder listing""" - url = reverse( + self.url = reverse( 'filesfolders:api_folder_list_create', kwargs={'project': self.project.sodar_uuid}, ) + self.post_data = { + 'name': 'New Folder', + 'flag': 'IMPORTANT', + 'description': 'Description', + } + + def test_get(self): + """Test FolderListCreateAPIView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -72,31 +54,22 @@ def test_folder_list(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles] - self.assert_response_api(url, good_users, 200) - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) - # Test public project + self.assert_response_api(self.url, good_users, 200) + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 200) + self.assert_response_api(self.url, self.user_no_roles, 200) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_folder_list_anon(self): - """Test permissions for folder listing with anonymous access""" - url = reverse( - 'filesfolders:api_folder_list_create', - kwargs={'project': self.project.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response_api(url, self.anonymous, 200) + self.assert_response_api(self.url, self.anonymous, 200) - def test_folder_list_archive(self): - """Test permissions for folder listing with archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:api_folder_list_create', - kwargs={'project': self.project.sodar_uuid}, - ) good_users = [ self.superuser, self.user_owner_cat, @@ -109,25 +82,15 @@ def test_folder_list_archive(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles] - self.assert_response_api(url, good_users, 200) - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) - # Test public project + self.assert_response_api(self.url, good_users, 200) + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 200) + self.assert_response_api(self.url, self.user_no_roles, 200) - def test_folder_create(self): - """Test permissions for folder creation""" - url = reverse( - 'filesfolders:api_folder_list_create', - kwargs={'project': self.project.sodar_uuid}, - ) - request_data = { - 'name': 'New Folder', - 'flag': 'IMPORTANT', - 'description': 'Folder\'s description', - } + def test_post(self): + """Test FolderListCreateAPIView POST""" good_users = [ self.superuser, self.user_owner_cat, @@ -144,63 +107,42 @@ def test_folder_create(self): self.user_no_roles, ] self.assert_response_api( - url, - good_users, - 201, - method='POST', - data=request_data, - cleanup_method=self._cleanup_folder_create, + self.url, good_users, 201, method='POST', data=self.post_data ) self.assert_response_api( - url, bad_users, 403, method='POST', data=request_data + self.url, bad_users, 403, method='POST', data=self.post_data ) self.assert_response_api( - url, self.anonymous, 401, method='POST', data=request_data + self.url, self.anonymous, 401, method='POST', data=self.post_data ) self.assert_response_api( - url, + self.url, good_users, 201, method='POST', - data=request_data, - cleanup_method=self._cleanup_folder_create, + data=self.post_data, knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='POST', data=request_data + self.url, + self.user_no_roles, + 403, + method='POST', + data=self.post_data, ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_folder_create_anon(self): - """Test permissions for folder creation with anonymous access""" - url = reverse( - 'filesfolders:api_folder_list_create', - kwargs={'project': self.project.sodar_uuid}, - ) - request_data = { - 'name': 'New Folder', - 'flag': 'IMPORTANT', - 'description': 'Folder\'s description', - } + def test_post_anon(self): + """Test POST with anonymous access""" self.project.set_public() self.assert_response_api( - url, self.anonymous, 401, method='POST', data=request_data + self.url, self.anonymous, 401, method='POST', data=self.post_data ) - def test_folder_create_archive(self): - """Test permissions for folder creation with archived project""" + def test_post_archive(self): + """Test POST with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:api_folder_list_create', - kwargs={'project': self.project.sodar_uuid}, - ) - request_data = { - 'name': 'New Folder', - 'flag': 'IMPORTANT', - 'description': 'Folder\'s description', - } good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -215,40 +157,59 @@ def test_folder_create_archive(self): self.user_no_roles, ] self.assert_response_api( - url, - good_users, - 201, - method='POST', - data=request_data, - cleanup_method=self._cleanup_folder_create, + self.url, good_users, 201, method='POST', data=self.post_data ) self.assert_response_api( - url, bad_users, 403, method='POST', data=request_data + self.url, bad_users, 403, method='POST', data=self.post_data ) self.assert_response_api( - url, self.anonymous, 401, method='POST', data=request_data + self.url, self.anonymous, 401, method='POST', data=self.post_data ) self.assert_response_api( - url, + self.url, good_users, 201, method='POST', - data=request_data, - cleanup_method=self._cleanup_folder_create, + data=self.post_data, knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='POST', data=request_data + self.url, + self.user_no_roles, + 403, + method='POST', + data=self.post_data, ) - def test_folder_retrieve(self): - """Test permissions for folder retrieval""" - url = reverse( + +class TestFolderRetrieveUpdateDestroyAPIView( + FilesfoldersPermissionTestMixin, TestCoreProjectAPIPermissionBase +): + """Tests FolderRetrieveUpdateDestroyAPIView permissions""" + + def _make_folder(self): + folder = self.make_test_folder() + folder.sodar_uuid = OBJ_UUID + folder.save() + return folder + + def setUp(self): + super().setUp() + folder = self._make_folder() + self.url = reverse( 'filesfolders:api_folder_retrieve_update_destroy', - kwargs={'folder': self.folder.sodar_uuid}, + kwargs={'folder': folder.sodar_uuid}, ) + self.put_data = { + 'name': 'UPDATED Folder', + 'flag': 'FLAG', + 'description': 'UPDATED Description', + } + self.patch_data = {'name': 'UPDATED Folder'} + + def test_get(self): + """Test FolderRetrieveUpdateDestroyAPIView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -261,31 +222,22 @@ def test_folder_retrieve(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles] - self.assert_response_api(url, good_users, 200, method='GET') - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) - # Test public project + self.assert_response_api(self.url, good_users, 200, method='GET') + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 200) + self.assert_response_api(self.url, self.user_no_roles, 200) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_folder_retrieve_anon(self): - """Test permissions for folder retrieval with anonymous access""" - url = reverse( - 'filesfolders:api_folder_retrieve_update_destroy', - kwargs={'folder': self.folder.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response_api(url, self.anonymous, 200) + self.assert_response_api(self.url, self.anonymous, 200) - def test_folder_retrieve_archive(self): - """Test permissions for folder retrieval with archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:api_folder_retrieve_update_destroy', - kwargs={'folder': self.folder.sodar_uuid}, - ) good_users = [ self.superuser, self.user_owner_cat, @@ -298,29 +250,19 @@ def test_folder_retrieve_archive(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles] - self.assert_response_api(url, good_users, 200, method='GET') - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - # Test public project + self.assert_response_api(self.url, good_users, 200, method='GET') + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 200) + self.assert_response_api(self.url, self.user_no_roles, 200) - def test_folder_update_put(self): - """Test permissions for folder updating with PUT""" - url = reverse( - 'filesfolders:api_folder_retrieve_update_destroy', - kwargs={'folder': self.folder.sodar_uuid}, - ) - request_data = { - 'name': 'UPDATED Folder', - 'flag': 'FLAG', - 'description': 'UPDATED Description', - } + def test_put(self): + """Test FolderRetrieveUpdateDestroyAPIView PUT""" good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_owner, # Owner of folder + self.user_owner, self.user_delegate, ] bad_users = [ @@ -332,52 +274,38 @@ def test_folder_update_put(self): self.user_no_roles, ] self.assert_response_api( - url, good_users, 200, method='PUT', data=request_data + self.url, good_users, 200, method='PUT', data=self.put_data ) self.assert_response_api( - url, bad_users, 403, method='PUT', data=request_data + self.url, bad_users, 403, method='PUT', data=self.put_data ) self.assert_response_api( - url, self.anonymous, 401, method='PUT', data=request_data + self.url, self.anonymous, 401, method='PUT', data=self.put_data ) self.assert_response_api( - url, good_users, 200, method='PUT', data=request_data, knox=True + self.url, + good_users, + 200, + method='PUT', + data=self.put_data, + knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='PUT', data=request_data + self.url, self.user_no_roles, 403, method='PUT', data=self.put_data ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_folder_update_put_anon(self): + def test_put_anon(self): """Test permissions for folder updating with anonymous access""" - url = reverse( - 'filesfolders:api_folder_retrieve_update_destroy', - kwargs={'folder': self.folder.sodar_uuid}, - ) - request_data = { - 'name': 'UPDATED Folder', - 'flag': 'FLAG', - 'description': 'UPDATED Description', - } self.project.set_public() self.assert_response_api( - url, self.anonymous, 401, method='PUT', data=request_data + self.url, self.anonymous, 401, method='PUT', data=self.put_data ) - def test_folder_update_put_archive(self): + def test_put_archive(self): """Test permissions for folder updating with PUT and archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:api_folder_retrieve_update_destroy', - kwargs={'folder': self.folder.sodar_uuid}, - ) - request_data = { - 'name': 'UPDATED Folder', - 'flag': 'FLAG', - 'description': 'UPDATED Description', - } good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -392,32 +320,26 @@ def test_folder_update_put_archive(self): self.user_no_roles, ] self.assert_response_api( - url, good_users, 200, method='PUT', data=request_data + self.url, good_users, 200, method='PUT', data=self.put_data ) self.assert_response_api( - url, bad_users, 403, method='PUT', data=request_data + self.url, bad_users, 403, method='PUT', data=self.put_data ) self.assert_response_api( - url, self.anonymous, 401, method='PUT', data=request_data + self.url, self.anonymous, 401, method='PUT', data=self.put_data ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='PUT', data=request_data + self.url, self.user_no_roles, 403, method='PUT', data=self.put_data ) - def test_folder_update_patch(self): - """Test permissions for folder updating with PATCH""" - url = reverse( - 'filesfolders:api_folder_retrieve_update_destroy', - kwargs={'folder': self.folder.sodar_uuid}, - ) - request_data = {'name': 'UPDATED Folder'} + def test_patch(self): + """Test FolderRetrieveUpdateDestroyAPIView PATCH""" good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_owner, # Owner of folder + self.user_owner, self.user_delegate, ] bad_users = [ @@ -429,44 +351,42 @@ def test_folder_update_patch(self): self.user_no_roles, ] self.assert_response_api( - url, good_users, 200, method='PATCH', data=request_data + self.url, good_users, 200, method='PATCH', data=self.patch_data ) self.assert_response_api( - url, bad_users, 403, method='PATCH', data=request_data + self.url, bad_users, 403, method='PATCH', data=self.patch_data ) self.assert_response_api( - url, self.anonymous, 401, method='PATCH', data=request_data + self.url, self.anonymous, 401, method='PATCH', data=self.patch_data ) self.assert_response_api( - url, good_users, 200, method='PATCH', data=request_data, knox=True + self.url, + good_users, + 200, + method='PATCH', + data=self.patch_data, + knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='PATCH', data=request_data + self.url, + self.user_no_roles, + 403, + method='PATCH', + data=self.patch_data, ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_folder_update_patch_anon(self): - """Test permissions for folder updating with anonymous access""" - url = reverse( - 'filesfolders:api_folder_retrieve_update_destroy', - kwargs={'folder': self.folder.sodar_uuid}, - ) - request_data = {'name': 'UPDATED Folder'} + def test_patch_anon(self): + """Test PATCH for with anonymous access""" self.project.set_public() self.assert_response_api( - url, self.anonymous, 401, method='PATCH', data=request_data + self.url, self.anonymous, 401, method='PATCH', data=self.patch_data ) - def test_folder_update_patch_archive(self): - """Test permissions for folder updating with PATCH and archived project""" + def test_patch_archive(self): + """Test PATCH with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:api_folder_retrieve_update_destroy', - kwargs={'folder': self.folder.sodar_uuid}, - ) - request_data = {'name': 'UPDATED Folder'} good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -481,33 +401,30 @@ def test_folder_update_patch_archive(self): self.user_no_roles, ] self.assert_response_api( - url, good_users, 200, method='PATCH', data=request_data + self.url, good_users, 200, method='PATCH', data=self.patch_data ) self.assert_response_api( - url, bad_users, 403, method='PATCH', data=request_data + self.url, bad_users, 403, method='PATCH', data=self.patch_data ) self.assert_response_api( - url, self.anonymous, 401, method='PATCH', data=request_data + self.url, self.anonymous, 401, method='PATCH', data=self.patch_data ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='PATCH', data=request_data + self.url, + self.user_no_roles, + 403, + method='PATCH', + data=self.patch_data, ) - def test_folder_destroy(self): - """Test permissions for folder destroying with DELETE""" - obj_uuid = uuid.uuid4() - c_kwargs = {'obj_uuid': obj_uuid} - url = reverse( - 'filesfolders:api_folder_retrieve_update_destroy', - kwargs={'folder': obj_uuid}, - ) + def test_delete(self): + """Test FolderRetrieveUpdateDestroyAPIView DELETE""" good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_owner, # Owner of folder + self.user_owner, self.user_delegate, ] bad_users = [ @@ -518,56 +435,37 @@ def test_folder_destroy(self): self.user_guest, self.user_no_roles, ] - self._cleanup_folder_destroy(**c_kwargs) self.assert_response_api( - url, + self.url, good_users, 204, method='DELETE', - cleanup_method=self._cleanup_folder_destroy, - cleanup_kwargs=c_kwargs, + cleanup_method=self._make_folder, ) - self.assert_response_api(url, bad_users, 403, method='DELETE') - self.assert_response_api(url, self.anonymous, 401, method='DELETE') + self.assert_response_api(self.url, bad_users, 403, method='DELETE') + self.assert_response_api(self.url, self.anonymous, 401, method='DELETE') self.assert_response_api( - url, + self.url, good_users, 204, method='DELETE', - cleanup_method=self._cleanup_folder_destroy, - cleanup_kwargs=c_kwargs, + cleanup_method=self._make_folder, knox=True, ) - # Test public project self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 403, method='DELETE') + self.assert_response_api( + self.url, self.user_no_roles, 403, method='DELETE' + ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_folder_destroy_anon(self): - """Test permissions for folder destroying with anonymous access""" - folder = self.make_folder( - name='folder', - project=self.project, - folder=None, - owner=self.user_owner, - description='', - ) - url = reverse( - 'filesfolders:api_folder_retrieve_update_destroy', - kwargs={'folder': folder.sodar_uuid}, - ) + def test_delete_anon(self): + """Test DELETE with anonymous access""" self.project.set_public() - self.assert_response_api(url, self.anonymous, 401, method='DELETE') + self.assert_response_api(self.url, self.anonymous, 401, method='DELETE') - def test_folder_destroy_archive(self): - """Test permissions for folder destroying with DELETE and archived project""" + def test_delete_archive(self): + """Test DELETEwith archived project""" self.project.set_archive() - obj_uuid = uuid.uuid4() - c_kwargs = {'obj_uuid': obj_uuid} - url = reverse( - 'filesfolders:api_folder_retrieve_update_destroy', - kwargs={'folder': obj_uuid}, - ) good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -581,66 +479,29 @@ def test_folder_destroy_archive(self): self.user_guest, self.user_no_roles, ] - self._cleanup_folder_destroy(**c_kwargs) self.assert_response_api( - url, + self.url, good_users, 204, method='DELETE', - cleanup_method=self._cleanup_folder_destroy, - cleanup_kwargs=c_kwargs, + cleanup_method=self._make_folder, ) - self.assert_response_api(url, bad_users, 403, method='DELETE') - self.assert_response_api(url, self.anonymous, 401, method='DELETE') - # Test public project + self.assert_response_api(self.url, bad_users, 403, method='DELETE') + self.assert_response_api(self.url, self.anonymous, 401, method='DELETE') self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 403, method='DELETE') - - -class TestFileAPIPermissions(FileMixin, TestCoreProjectAPIPermissionBase): - """Tests for File API view permissions""" - - def _cleanup_file_create(self): - file = File.objects.filter(name=self.new_file_name).first() - if file: - file.delete() - self.request_data['file'].seek(0) - - def _cleanup_file_update(self): - self.request_data['file'].seek(0) - - def _cleanup_file_destroy(self, obj_uuid): - file = self.make_file( - name='file2.txt', - file_name='file2.txt', - file_content=self.file_content, - project=self.project, - folder=None, - owner=self.user_owner, - description='', - public_url=True, - secret=build_secret(), - ) - file.sodar_uuid = obj_uuid - file.save() + self.assert_response_api( + self.url, self.user_no_roles, 403, method='DELETE' + ) - def setUp(self): - super().setUp() - self.file_content = bytes('content'.encode('utf-8')) - self.file = self.make_file( - name='file.txt', - file_name='file.txt', - file_content=self.file_content, - project=self.project, - folder=None, - owner=self.user_owner, - description='', - public_url=True, - secret=SECRET, - ) - self.new_file_name = 'New File' - self.request_data = { - 'name': self.new_file_name, + +class TestFileListCreateAPIView( + FilesfoldersPermissionTestMixin, TestCoreProjectAPIPermissionBase +): + """Tests FileListCreateAPIView permissions""" + + def _make_post_data(self): + self.post_data = { + 'name': 'New File', 'flag': 'IMPORTANT', 'description': 'File\'s description', 'secret': 'foo', @@ -648,16 +509,25 @@ def setUp(self): 'file': open(ZIP_PATH_NO_FILES, 'rb'), } - def tearDown(self): - self.request_data['file'].close() - super().tearDown() + def _cleanup(self): + File.objects.all().delete() + if hasattr(self, 'post_data'): + self.post_data['file'].seek(0) - def test_file_list(self): - """Test permissions for file listing""" - url = reverse( + def setUp(self): + super().setUp() + self.url = reverse( 'filesfolders:api_file_list_create', kwargs={'project': self.project.sodar_uuid}, ) + + def tearDown(self): + if hasattr(self, 'post_data'): + self.post_data['file'].close() + super().tearDown() + + def test_get(self): + """Test FileListCreateAPIView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -670,31 +540,22 @@ def test_file_list(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles] - self.assert_response_api(url, good_users, 200) - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) - # Test public project + self.assert_response_api(self.url, good_users, 200) + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 200) + self.assert_response_api(self.url, self.user_no_roles, 200) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_file_list_anon(self): + def test_get_anon(self): """Test permissions for file listing with anonymous access""" - url = reverse( - 'filesfolders:api_file_list_create', - kwargs={'project': self.project.sodar_uuid}, - ) self.project.set_public() - self.assert_response_api(url, self.anonymous, 200) + self.assert_response_api(self.url, self.anonymous, 200) - def test_file_list_archive(self): + def test_get_archive(self): """Test permissions for file listing with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:api_file_list_create', - kwargs={'project': self.project.sodar_uuid}, - ) good_users = [ self.superuser, self.user_owner_cat, @@ -707,20 +568,16 @@ def test_file_list_archive(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles] - self.assert_response_api(url, good_users, 200) - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) - # Test public project + self.assert_response_api(self.url, good_users, 200) + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 200) + self.assert_response_api(self.url, self.user_no_roles, 200) - def test_file_create(self): - """Test permissions for file creation""" - url = reverse( - 'filesfolders:api_file_list_create', - kwargs={'project': self.project.sodar_uuid}, - ) + def test_post(self): + """Test FileListCreateAPIView POST""" + self._make_post_data() # NOTE: Must call cleanup for ALL requests to seek the file good_users = [ self.superuser, @@ -738,79 +595,73 @@ def test_file_create(self): self.user_no_roles, ] self.assert_response_api( - url, + self.url, good_users, 201, method='POST', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_create, + data=self.post_data, + cleanup_method=self._cleanup, ) self.assert_response_api( - url, + self.url, bad_users, 403, method='POST', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_create, + data=self.post_data, + cleanup_method=self._cleanup, ) self.assert_response_api( - url, + self.url, self.anonymous, 401, method='POST', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_create, + data=self.post_data, + cleanup_method=self._cleanup, ) self.assert_response_api( - url, + self.url, good_users, 201, method='POST', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_create, + data=self.post_data, + cleanup_method=self._cleanup, knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, + self.url, self.user_no_roles, 403, method='POST', format='multipart', - data=self.request_data, + data=self.post_data, + cleanup_method=self._cleanup, ) - self.request_data['file'].close() + # self.request_data['file'].close() @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_file_create_anon(self): - """Test permissions for file creation with anonymous access""" - url = reverse( - 'filesfolders:api_file_list_create', - kwargs={'project': self.project.sodar_uuid}, - ) + def test_post_anon(self): + """Test POST with anonymous access""" + self._make_post_data() self.project.set_public() self.assert_response_api( - url, + self.url, self.anonymous, 401, method='POST', format='multipart', - data=self.request_data, + data=self.post_data, + cleanup_method=self._cleanup, ) - self.request_data['file'].close() - def test_file_create_archive(self): - """Test permissions for file creation with archived project""" + def test_post_archive(self): + """Test POST with archived project""" + self._make_post_data() self.project.set_archive() - url = reverse( - 'filesfolders:api_file_list_create', - kwargs={'project': self.project.sodar_uuid}, - ) good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -825,60 +676,89 @@ def test_file_create_archive(self): self.user_no_roles, ] self.assert_response_api( - url, + self.url, good_users, 201, method='POST', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_create, + data=self.post_data, + cleanup_method=self._cleanup, ) self.assert_response_api( - url, + self.url, bad_users, 403, method='POST', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_create, + data=self.post_data, + cleanup_method=self._cleanup, ) self.assert_response_api( - url, + self.url, self.anonymous, 401, method='POST', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_create, + data=self.post_data, + cleanup_method=self._cleanup, ) self.assert_response_api( - url, + self.url, good_users, 201, method='POST', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_create, + data=self.post_data, + cleanup_method=self._cleanup, knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, + self.url, self.user_no_roles, 403, method='POST', format='multipart', - data=self.request_data, + data=self.post_data, + cleanup_method=self._cleanup, ) - self.request_data['file'].close() - def test_file_retrieve(self): - """Test permissions for file retrieval""" - url = reverse( + +class TestFileRetrieveUpdateDestroyAPIView( + FilesfoldersPermissionTestMixin, TestCoreProjectAPIPermissionBase +): + """Tests FileRetrieveUpdateDestroyAPIView permissions""" + + def _make_file(self): + file = self.make_test_file() + file.sodar_uuid = OBJ_UUID + file.save() + return file + + def _make_put_data(self): + self.put_data = { + 'name': 'UPDATED File', + 'flag': 'FLAG', + 'description': 'UPDATED Description', + 'secret': 'foo', + 'public_url': True, + 'file': open(ZIP_PATH_NO_FILES, 'rb'), + } + + def _cleanup_put(self): + self.put_data['file'].seek(0) + + def setUp(self): + super().setUp() + file = self._make_file() + self.patch_data = {'name': 'UPDATED File'} + self.url = reverse( 'filesfolders:api_file_retrieve_update_destroy', - kwargs={'file': self.file.sodar_uuid}, + kwargs={'file': file.sodar_uuid}, ) + + def test_get(self): + """Test FileRetrieveUpdateDestroyAPIView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -891,31 +771,22 @@ def test_file_retrieve(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles] - self.assert_response_api(url, good_users, 200) - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) - # Test public project + self.assert_response_api(self.url, good_users, 200) + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 200) + self.assert_response_api(self.url, self.user_no_roles, 200) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_file_retrieve_anon(self): - """Test permissions for file retrieval with anonymous access""" - url = reverse( - 'filesfolders:api_file_retrieve_update_destroy', - kwargs={'file': self.file.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response_api(url, self.anonymous, 200) + self.assert_response_api(self.url, self.anonymous, 200) - def test_file_retrieve_archive(self): - """Test permissions for file retrieval with archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:api_file_retrieve_update_destroy', - kwargs={'file': self.file.sodar_uuid}, - ) good_users = [ self.superuser, self.user_owner_cat, @@ -928,32 +799,21 @@ def test_file_retrieve_archive(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles] - self.assert_response_api(url, good_users, 200) - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) - # Test public project + self.assert_response_api(self.url, good_users, 200) + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 200) + self.assert_response_api(self.url, self.user_no_roles, 200) - def test_file_update_put(self): - """Test permissions for file updating with PUT""" - url = reverse( - 'filesfolders:api_file_retrieve_update_destroy', - kwargs={'file': self.file.sodar_uuid}, - ) - self.request_data.update( - { - 'name': 'UPDATED Folder', - 'flag': 'FLAG', - 'description': 'UPDATED Description', - } - ) + def test_put(self): + """Test FileRetrieveUpdateDestroyAPIView PUT""" + self._make_put_data() good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_owner, # Owner of file + self.user_owner, self.user_delegate, ] bad_users = [ @@ -965,91 +825,70 @@ def test_file_update_put(self): self.user_no_roles, ] self.assert_response_api( - url, + self.url, good_users, 200, method='PUT', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_update, + data=self.put_data, + cleanup_method=self._cleanup_put, ) self.assert_response_api( - url, + self.url, bad_users, 403, method='PUT', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_update, + data=self.put_data, + cleanup_method=self._cleanup_put, ) self.assert_response_api( - url, + self.url, self.anonymous, 401, method='PUT', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_update, + data=self.put_data, + cleanup_method=self._cleanup_put, ) self.assert_response_api( - url, + self.url, good_users, 200, method='PUT', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_update, + data=self.put_data, + cleanup_method=self._cleanup_put, knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, + self.url, self.user_no_roles, 403, method='PUT', format='multipart', - data=self.request_data, + data=self.put_data, ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_file_update_put_anon(self): - """Test permissions for file updating with anonymous access""" - url = reverse( - 'filesfolders:api_file_retrieve_update_destroy', - kwargs={'file': self.file.sodar_uuid}, - ) - self.request_data.update( - { - 'name': 'UPDATED Folder', - 'flag': 'FLAG', - 'description': 'UPDATED Description', - } - ) + def test_put_anon(self): + """Test PUT with anonymous access""" + self._make_put_data() self.project.set_public() self.assert_response_api( - url, + self.url, self.anonymous, 401, method='PUT', format='multipart', - data=self.request_data, + data=self.put_data, ) - def test_file_update_put_archive(self): - """Test permissions for file updating with PUT and archived project""" + def test_put_archive(self): + """Test PUT with archived project""" + self._make_put_data() self.project.set_archive() - url = reverse( - 'filesfolders:api_file_retrieve_update_destroy', - kwargs={'file': self.file.sodar_uuid}, - ) - self.request_data.update( - { - 'name': 'UPDATED Folder', - 'flag': 'FLAG', - 'description': 'UPDATED Description', - } - ) good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -1064,55 +903,49 @@ def test_file_update_put_archive(self): self.user_no_roles, ] self.assert_response_api( - url, + self.url, good_users, 200, method='PUT', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_update, + data=self.put_data, + cleanup_method=self._cleanup_put, ) self.assert_response_api( - url, + self.url, bad_users, 403, method='PUT', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_update, + data=self.put_data, + cleanup_method=self._cleanup_put, ) self.assert_response_api( - url, + self.url, self.anonymous, 401, method='PUT', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_update, + data=self.put_data, + cleanup_method=self._cleanup_put, ) - # Test public project self.project.set_public() self.assert_response_api( - url, + self.url, self.user_no_roles, 403, method='PUT', format='multipart', - data=self.request_data, + data=self.put_data, ) - def test_file_update_patch(self): - """Test permissions for file updating with PATCH""" - url = reverse( - 'filesfolders:api_file_retrieve_update_destroy', - kwargs={'file': self.file.sodar_uuid}, - ) - self.request_data.update({'name': 'UPDATED Folder'}) + def test_patch(self): + """Test FileRetrieveUpdateDestroyAPIView PATCH""" good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_owner, # Owner of file + self.user_owner, self.user_delegate, ] bad_users = [ @@ -1124,79 +957,64 @@ def test_file_update_patch(self): self.user_no_roles, ] self.assert_response_api( - url, + self.url, good_users, 200, method='PATCH', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_update, + data=self.patch_data, ) self.assert_response_api( - url, + self.url, bad_users, 403, method='PATCH', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_update, + data=self.patch_data, ) self.assert_response_api( - url, + self.url, self.anonymous, 401, method='PATCH', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_update, + data=self.patch_data, ) self.assert_response_api( - url, + self.url, good_users, 200, method='PATCH', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_update, + data=self.patch_data, knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, + self.url, self.user_no_roles, 403, method='PATCH', format='multipart', - data=self.request_data, + data=self.patch_data, ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_file_update_patch_anon(self): - """Test permissions for file updating with anonymous access""" - url = reverse( - 'filesfolders:api_file_retrieve_update_destroy', - kwargs={'file': self.file.sodar_uuid}, - ) - self.request_data.update({'name': 'UPDATED Folder'}) + def test_patch_anon(self): + """Test PATCH with anonymous access""" self.project.set_public() self.assert_response_api( - url, + self.url, self.anonymous, 401, method='PATCH', format='multipart', - data=self.request_data, + data=self.patch_data, ) - def test_file_update_patch_archive(self): - """Test permissions for file updating with PATCH and archived project""" + def test_patch_archive(self): + """Test PATCH with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:api_file_retrieve_update_destroy', - kwargs={'file': self.file.sodar_uuid}, - ) - self.request_data.update({'name': 'UPDATED Folder'}) good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -1211,56 +1029,47 @@ def test_file_update_patch_archive(self): self.user_no_roles, ] self.assert_response_api( - url, + self.url, good_users, 200, method='PATCH', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_update, + data=self.patch_data, ) self.assert_response_api( - url, + self.url, bad_users, 403, method='PATCH', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_update, + data=self.patch_data, ) self.assert_response_api( - url, + self.url, self.anonymous, 401, method='PATCH', format='multipart', - data=self.request_data, - cleanup_method=self._cleanup_file_update, + data=self.patch_data, ) # Test public project self.project.set_public() self.assert_response_api( - url, + self.url, self.user_no_roles, 403, method='PATCH', format='multipart', - data=self.request_data, + data=self.patch_data, ) - def test_file_destroy(self): - """Test permissions for file destroying with DELETE""" - obj_uuid = uuid.uuid4() - c_kwargs = {'obj_uuid': obj_uuid} - url = reverse( - 'filesfolders:api_file_retrieve_update_destroy', - kwargs={'file': obj_uuid}, - ) + def test_delete(self): + """Test FileRetrieveUpdateDestroyAPIView DELETE""" good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_owner, # Owner of file + self.user_owner, self.user_delegate, ] bad_users = [ @@ -1271,70 +1080,40 @@ def test_file_destroy(self): self.user_guest, self.user_no_roles, ] - self._cleanup_file_destroy(**c_kwargs) self.assert_response_api( - url, + self.url, good_users, 204, method='DELETE', - cleanup_method=self._cleanup_file_destroy, - cleanup_kwargs=c_kwargs, + cleanup_method=self._make_file, ) - self.assert_response_api(url, bad_users, 403, method='DELETE') - self.assert_response_api(url, self.anonymous, 401, method='DELETE') + self.assert_response_api(self.url, bad_users, 403, method='DELETE') + self.assert_response_api(self.url, self.anonymous, 401, method='DELETE') self.assert_response_api( - url, + self.url, good_users, 204, method='DELETE', - cleanup_method=self._cleanup_file_destroy, - cleanup_kwargs=c_kwargs, + cleanup_method=self._make_file, knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, + self.url, self.user_no_roles, 403, method='DELETE', ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_file_destroy_anon(self): - """Test permissions for file destroying with anonymous access""" - file = self.make_file( - name='file2.txt', - file_name='file2.txt', - file_content=self.file_content, - project=self.project, - folder=None, - owner=self.user_owner, - description='', - public_url=True, - secret=build_secret(), - ) - url = reverse( - 'filesfolders:api_file_retrieve_update_destroy', - kwargs={'file': file.sodar_uuid}, - ) + def test_delete_anon(self): + """Test DELETE with anonymous access""" self.project.set_public() - self.assert_response_api( - url, - self.anonymous, - 401, - method='DELETE', - ) + self.assert_response_api(self.url, self.anonymous, 401, method='DELETE') - def test_file_destroy_archive(self): - """Test permissions for file destroying with DELETE and archived project""" + def test_delete_archive(self): + """Test DELETE with archived project""" self.project.set_archive() - obj_uuid = uuid.uuid4() - c_kwargs = {'obj_uuid': obj_uuid} - url = reverse( - 'filesfolders:api_file_retrieve_update_destroy', - kwargs={'file': obj_uuid}, - ) good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -1348,31 +1127,35 @@ def test_file_destroy_archive(self): self.user_guest, self.user_no_roles, ] - self._cleanup_file_destroy(**c_kwargs) self.assert_response_api( - url, + self.url, good_users, 204, method='DELETE', - cleanup_method=self._cleanup_file_destroy, - cleanup_kwargs=c_kwargs, + cleanup_method=self._make_file, ) - self.assert_response_api(url, bad_users, 403, method='DELETE') - self.assert_response_api(url, self.anonymous, 401, method='DELETE') - # Test public project + self.assert_response_api(self.url, bad_users, 403, method='DELETE') + self.assert_response_api(self.url, self.anonymous, 401, method='DELETE') self.project.set_public() self.assert_response_api( - url, - self.user_no_roles, - 403, - method='DELETE', + self.url, self.user_no_roles, 403, method='DELETE' ) - def test_file_serve(self): - """Test permissions for file serving""" - url = reverse( - 'filesfolders:api_file_serve', kwargs={'file': self.file.sodar_uuid} + +class TestFileServeAPIView( + FilesfoldersPermissionTestMixin, TestCoreProjectAPIPermissionBase +): + """Tests FileServeAPIView permissions""" + + def setUp(self): + super().setUp() + file = self.make_test_file() + self.url = reverse( + 'filesfolders:api_file_serve', kwargs={'file': file.sodar_uuid} ) + + def test_get(self): + """Test FileServeAPIView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -1385,29 +1168,22 @@ def test_file_serve(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles] - self.assert_response_api(url, good_users, 200, method='GET') - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) - # Test public project + self.assert_response_api(self.url, good_users, 200, method='GET') + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 200) + self.assert_response_api(self.url, self.user_no_roles, 200) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_file_serve_anon(self): - """Test permissions for file serving with anonymous access""" - url = reverse( - 'filesfolders:api_file_serve', kwargs={'file': self.file.sodar_uuid} - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response_api(url, self.anonymous, 200) + self.assert_response_api(self.url, self.anonymous, 200) - def test_file_serve_archive(self): - """Test permissions for file serving with archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:api_file_serve', kwargs={'file': self.file.sodar_uuid} - ) good_users = [ self.superuser, self.user_owner_cat, @@ -1420,53 +1196,38 @@ def test_file_serve_archive(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles] - self.assert_response_api(url, good_users, 200, method='GET') - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) - # Test public project + self.assert_response_api(self.url, good_users, 200, method='GET') + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 200) + self.assert_response_api(self.url, self.user_no_roles, 200) -class TestHyperLinkAPIPermissions( - HyperLinkMixin, TestCoreProjectAPIPermissionBase +class TestHyperLinkListCreateAPIView( + FilesfoldersPermissionTestMixin, TestCoreProjectAPIPermissionBase ): - """Tests for HyperLink API view permissions""" + """Tests HyperLinkListCreateAPIView permissions""" @classmethod - def _cleanup_link_create(cls): - HyperLink.objects.order_by('-pk').first().delete() - - def _cleanup_link_destroy(self, obj_uuid): - link = self.make_hyperlink( - name='New Link', - url='http://www.duckduckgo.com/', - project=self.project, - folder=None, - owner=self.user_owner, - description='', - ) - link.sodar_uuid = obj_uuid - link.save() + def _cleanup(cls): + HyperLink.objects.all().delete() def setUp(self): super().setUp() - self.hyperlink = self.make_hyperlink( - name='Link', - url='http://www.google.com/', - project=self.project, - folder=None, - owner=self.user_owner, - description='', - ) - - def test_hyperlink_list(self): - """Test permissions for hyperlink listing""" - url = reverse( + self.url = reverse( 'filesfolders:api_hyperlink_list_create', kwargs={'project': self.project.sodar_uuid}, ) + self.post_data = { + 'name': 'New HyperLink', + 'flag': 'IMPORTANT', + 'description': 'Description', + 'url': 'https://www.cubi.bihealth.org', + } + + def test_get(self): + """Test HyperLinkListCreateAPIView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -1479,31 +1240,22 @@ def test_hyperlink_list(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles] - self.assert_response_api(url, good_users, 200) - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) - # Test public project + self.assert_response_api(self.url, good_users, 200) + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 200) + self.assert_response_api(self.url, self.user_no_roles, 200) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_hyperlink_list_anon(self): - """Test permissions for hyperlink listing with anonymous access""" - url = reverse( - 'filesfolders:api_hyperlink_list_create', - kwargs={'project': self.project.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response_api(url, self.anonymous, 200) + self.assert_response_api(self.url, self.anonymous, 200) - def test_hyperlink_list_archive(self): - """Test permissions for hyperlink listing with archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:api_hyperlink_list_create', - kwargs={'project': self.project.sodar_uuid}, - ) good_users = [ self.superuser, self.user_owner_cat, @@ -1516,27 +1268,15 @@ def test_hyperlink_list_archive(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles] - self.assert_response_api(url, good_users, 200) - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) - # Test public project + self.assert_response_api(self.url, good_users, 200) + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 200) - - def test_hyperlink_create(self): - """Test permissions for hyperlink creation""" - url = reverse( - 'filesfolders:api_hyperlink_list_create', - kwargs={'project': self.project.sodar_uuid}, - ) - request_data = { - 'name': 'New HyperLink', - 'flag': 'IMPORTANT', - 'description': 'HyperLink\'s description', - 'url': 'http://www.cubi.bihealth.org', - } + self.assert_response_api(self.url, self.user_no_roles, 200) + def test_post(self): + """Test HyperLinkListCreateAPIView POST""" good_users = [ self.superuser, self.user_owner_cat, @@ -1553,66 +1293,49 @@ def test_hyperlink_create(self): self.user_no_roles, ] self.assert_response_api( - url, + self.url, good_users, 201, method='POST', - data=request_data, - cleanup_method=self._cleanup_link_create, + data=self.post_data, + cleanup_method=self._cleanup, ) self.assert_response_api( - url, bad_users, 403, method='POST', data=request_data + self.url, bad_users, 403, method='POST', data=self.post_data ) self.assert_response_api( - url, self.anonymous, 401, method='POST', data=request_data + self.url, self.anonymous, 401, method='POST', data=self.post_data ) self.assert_response_api( - url, + self.url, good_users, 201, method='POST', - data=request_data, - cleanup_method=self._cleanup_link_create, + data=self.post_data, + cleanup_method=self._cleanup, knox=True, ) # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='POST', data=request_data + self.url, + self.user_no_roles, + 403, + method='POST', + data=self.post_data, ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_hyperlink_create_anon(self): - """Test permissions for hyperlink creation with anonymous access""" - url = reverse( - 'filesfolders:api_hyperlink_list_create', - kwargs={'project': self.project.sodar_uuid}, - ) - request_data = { - 'name': 'New HyperLink', - 'flag': 'IMPORTANT', - 'description': 'HyperLink\'s description', - 'url': 'http://www.cubi.bihealth.org', - } + def test_post_anon(self): + """Test POST with anonymous access""" self.project.set_public() self.assert_response_api( - url, self.anonymous, 401, method='POST', data=request_data + self.url, self.anonymous, 401, method='POST', data=self.post_data ) - def test_hyperlink_create_archive(self): - """Test permissions for hyperlink creation with archived project""" + def test_post_archive(self): + """Test POST with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:api_hyperlink_list_create', - kwargs={'project': self.project.sodar_uuid}, - ) - request_data = { - 'name': 'New HyperLink', - 'flag': 'IMPORTANT', - 'description': 'HyperLink\'s description', - 'url': 'http://www.cubi.bihealth.org', - } - good_users = [self.superuser] bad_users = [ self.user_owner, @@ -1627,40 +1350,69 @@ def test_hyperlink_create_archive(self): self.user_no_roles, ] self.assert_response_api( - url, + self.url, good_users, 201, method='POST', - data=request_data, - cleanup_method=self._cleanup_link_create, + data=self.post_data, + cleanup_method=self._cleanup, ) self.assert_response_api( - url, bad_users, 403, method='POST', data=request_data + self.url, bad_users, 403, method='POST', data=self.post_data ) self.assert_response_api( - url, self.anonymous, 401, method='POST', data=request_data + self.url, self.anonymous, 401, method='POST', data=self.post_data ) self.assert_response_api( - url, + self.url, good_users, 201, method='POST', - data=request_data, - cleanup_method=self._cleanup_link_create, + data=self.post_data, + cleanup_method=self._cleanup, knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='POST', data=request_data + self.url, + self.user_no_roles, + 403, + method='POST', + data=self.post_data, ) - def test_hyperlink_retrieve(self): - """Test permissions for hyperlink retrieval""" - url = reverse( + +class TestHyperLinkRetrieveUpdateDestroyAPIView( + FilesfoldersPermissionTestMixin, TestCoreProjectAPIPermissionBase +): + """Tests HyperLinkRetrieveUpdateDestroyAPIView permissions""" + + def _make_link(self): + link = self.make_test_link() + link.sodar_uuid = OBJ_UUID + link.save() + return link + + def _cleanup_delete(self): + self._make_link() + + def setUp(self): + super().setUp() + link = self._make_link() + self.url = reverse( 'filesfolders:api_hyperlink_retrieve_update_destroy', - kwargs={'hyperlink': self.hyperlink.sodar_uuid}, + kwargs={'hyperlink': link.sodar_uuid}, ) + self.put_data = { + 'name': 'UPDATED HyperLink', + 'flag': 'FLAG', + 'description': 'UPDATED description', + 'url': 'https://www.bihealth.org', + } + self.patch_data = {'name': 'UPDATED Hyperlink'} + + def test_get(self): + """Test HyperLinkRetrieveUpdateDestroyAPIView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -1673,31 +1425,22 @@ def test_hyperlink_retrieve(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles] - self.assert_response_api(url, good_users, 200, method='GET') - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) - # Test public project + self.assert_response_api(self.url, good_users, 200, method='GET') + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 200) + self.assert_response_api(self.url, self.user_no_roles, 200) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_hyperlink_retrieve_anon(self): - """Test permissions for hyperlink retrieval with anonymous access""" - url = reverse( - 'filesfolders:api_hyperlink_retrieve_update_destroy', - kwargs={'hyperlink': self.hyperlink.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response_api(url, self.anonymous, 200) + self.assert_response_api(self.url, self.anonymous, 200) - def test_hyperlink_retrieve_archive(self): - """Test permissions for hyperlink retrieval with archived project""" + def test_get_archive(self): + """Test GET with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:api_hyperlink_retrieve_update_destroy', - kwargs={'hyperlink': self.hyperlink.sodar_uuid}, - ) good_users = [ self.superuser, self.user_owner_cat, @@ -1710,26 +1453,15 @@ def test_hyperlink_retrieve_archive(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles] - self.assert_response_api(url, good_users, 200, method='GET') - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) - # Test public project + self.assert_response_api(self.url, good_users, 200, method='GET') + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 200) + self.assert_response_api(self.url, self.user_no_roles, 200) - def test_hyperlink_update_put(self): - """Test permissions for hyperlink updating with PUT""" - url = reverse( - 'filesfolders:api_hyperlink_retrieve_update_destroy', - kwargs={'hyperlink': self.hyperlink.sodar_uuid}, - ) - request_data = { - 'name': 'UPDATED HyperLink', - 'flag': 'FLAG', - 'description': 'UPDATED Description', - 'url': 'http://www.bihealth.org', - } + def test_put(self): + """Test HyperLinkRetrieveUpdateDestroyAPIView PUT""" good_users = [ self.superuser, self.user_owner_cat, @@ -1746,54 +1478,38 @@ def test_hyperlink_update_put(self): self.user_no_roles, ] self.assert_response_api( - url, good_users, 200, method='PUT', data=request_data + self.url, good_users, 200, method='PUT', data=self.put_data ) self.assert_response_api( - url, bad_users, 403, method='PUT', data=request_data + self.url, bad_users, 403, method='PUT', data=self.put_data ) self.assert_response_api( - url, self.anonymous, 401, method='PUT', data=request_data + self.url, self.anonymous, 401, method='PUT', data=self.put_data ) self.assert_response_api( - url, good_users, 200, method='PUT', data=request_data, knox=True + self.url, + good_users, + 200, + method='PUT', + data=self.put_data, + knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='PUT', data=request_data + self.url, self.user_no_roles, 403, method='PUT', data=self.put_data ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_hyperlink_update_put_anon(self): - """Test permissions for hyperlink updating with anonymous access""" - url = reverse( - 'filesfolders:api_hyperlink_retrieve_update_destroy', - kwargs={'hyperlink': self.hyperlink.sodar_uuid}, - ) - request_data = { - 'name': 'UPDATED HyperLink', - 'flag': 'FLAG', - 'description': 'UPDATED Description', - 'url': 'http://www.bihealth.org', - } + def test_put_anon(self): + """Test PUT with anonymous access""" self.project.set_public() self.assert_response_api( - url, self.anonymous, 401, method='PUT', data=request_data + self.url, self.anonymous, 401, method='PUT', data=self.put_data ) - def test_hyperlink_update_put_archive(self): - """Test permissions for hyperlink updating with PUT and archived project""" + def test_put_archive(self): + """Test PUT with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:api_hyperlink_retrieve_update_destroy', - kwargs={'hyperlink': self.hyperlink.sodar_uuid}, - ) - request_data = { - 'name': 'UPDATED HyperLink', - 'flag': 'FLAG', - 'description': 'UPDATED Description', - 'url': 'http://www.bihealth.org', - } good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -1808,35 +1524,34 @@ def test_hyperlink_update_put_archive(self): self.user_no_roles, ] self.assert_response_api( - url, good_users, 200, method='PUT', data=request_data + self.url, good_users, 200, method='PUT', data=self.put_data ) self.assert_response_api( - url, bad_users, 403, method='PUT', data=request_data + self.url, bad_users, 403, method='PUT', data=self.put_data ) self.assert_response_api( - url, self.anonymous, 401, method='PUT', data=request_data + self.url, self.anonymous, 401, method='PUT', data=self.put_data ) self.assert_response_api( - url, good_users, 200, method='PUT', data=request_data, knox=True + self.url, + good_users, + 200, + method='PUT', + data=self.put_data, + knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='PUT', data=request_data + self.url, self.user_no_roles, 403, method='PUT', data=self.put_data ) - def test_hyperlink_update_patch(self): - """Test permissions for hyperlink updating with PATCH""" - url = reverse( - 'filesfolders:api_hyperlink_retrieve_update_destroy', - kwargs={'hyperlink': self.hyperlink.sodar_uuid}, - ) - request_data = {'name': 'UPDATED Hyperlink'} + def test_patch(self): + """Test HyperLinkRetrieveUpdateDestroyAPIView PATCH""" good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_owner, # Owner of link + self.user_owner, self.user_delegate, ] bad_users = [ @@ -1848,44 +1563,42 @@ def test_hyperlink_update_patch(self): self.user_no_roles, ] self.assert_response_api( - url, good_users, 200, method='PATCH', data=request_data + self.url, good_users, 200, method='PATCH', data=self.patch_data ) self.assert_response_api( - url, bad_users, 403, method='PATCH', data=request_data + self.url, bad_users, 403, method='PATCH', data=self.patch_data ) self.assert_response_api( - url, self.anonymous, 401, method='PATCH', data=request_data + self.url, self.anonymous, 401, method='PATCH', data=self.patch_data ) self.assert_response_api( - url, good_users, 200, method='PATCH', data=request_data, knox=True + self.url, + good_users, + 200, + method='PATCH', + data=self.patch_data, + knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='PATCH', data=request_data + self.url, + self.user_no_roles, + 403, + method='PATCH', + data=self.patch_data, ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_hyperlink_update_patch_anon(self): - """Test permissions for hyperlink updating with anonymous access""" - url = reverse( - 'filesfolders:api_hyperlink_retrieve_update_destroy', - kwargs={'hyperlink': self.hyperlink.sodar_uuid}, - ) - request_data = {'name': 'UPDATED Hyperlink'} + def test_patch_anon(self): + """Test PATCH with anonymous access""" self.project.set_public() self.assert_response_api( - url, self.anonymous, 401, method='PATCH', data=request_data + self.url, self.anonymous, 401, method='PATCH', data=self.patch_data ) - def test_hyperlink_update_patch_archive(self): - """Test permissions for hyperlink updating with PATCH and archived project""" + def test_patch_archive(self): + """Test PATCH with archived project""" self.project.set_archive() - url = reverse( - 'filesfolders:api_hyperlink_retrieve_update_destroy', - kwargs={'hyperlink': self.hyperlink.sodar_uuid}, - ) - request_data = {'name': 'UPDATED Hyperlink'} good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -1900,36 +1613,38 @@ def test_hyperlink_update_patch_archive(self): self.user_no_roles, ] self.assert_response_api( - url, good_users, 200, method='PATCH', data=request_data + self.url, good_users, 200, method='PATCH', data=self.patch_data ) self.assert_response_api( - url, bad_users, 403, method='PATCH', data=request_data + self.url, bad_users, 403, method='PATCH', data=self.patch_data ) self.assert_response_api( - url, self.anonymous, 401, method='PATCH', data=request_data + self.url, self.anonymous, 401, method='PATCH', data=self.patch_data ) self.assert_response_api( - url, good_users, 200, method='PATCH', data=request_data, knox=True + self.url, + good_users, + 200, + method='PATCH', + data=self.patch_data, + knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='PATCH', data=request_data + self.url, + self.user_no_roles, + 403, + method='PATCH', + data=self.patch_data, ) - def test_hyperlink_destroy(self): - """Test permissions for hyperlink destroying with DELETE""" - obj_uuid = uuid.uuid4() - c_kwargs = {'obj_uuid': obj_uuid} - url = reverse( - 'filesfolders:api_hyperlink_retrieve_update_destroy', - kwargs={'hyperlink': obj_uuid}, - ) + def test_delete(self): + """Test HyperLinkRetrieveUpdateDestroyAPIView DELETE""" good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_owner, # Owner of link + self.user_owner, self.user_delegate, ] bad_users = [ @@ -1940,67 +1655,42 @@ def test_hyperlink_destroy(self): self.user_guest, self.user_no_roles, ] - self._cleanup_link_destroy(**c_kwargs) + self.assert_response_api( - url, + self.url, good_users, 204, method='DELETE', - cleanup_method=self._cleanup_link_destroy, - cleanup_kwargs=c_kwargs, + cleanup_method=self._cleanup_delete, ) - self.assert_response_api(url, bad_users, 403, method='DELETE') - self.assert_response_api(url, self.anonymous, 401, method='DELETE') + self.assert_response_api(self.url, bad_users, 403, method='DELETE') + self.assert_response_api(self.url, self.anonymous, 401, method='DELETE') self.assert_response_api( - url, + self.url, good_users, 204, method='DELETE', - cleanup_method=self._cleanup_link_destroy, - cleanup_kwargs=c_kwargs, + cleanup_method=self._cleanup_delete, knox=True, ) # Test public project self.project.set_public() self.assert_response_api( - url, + self.url, self.user_no_roles, 403, method='DELETE', ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_hyperlink_destroy_anon(self): - """Test permissions for hyperlink destroying with anonymous access""" - link = self.make_hyperlink( - name='New Link', - url='http://www.duckduckgo.com/', - project=self.project, - folder=None, - owner=self.user_owner, - description='', - ) - url = reverse( - 'filesfolders:api_hyperlink_retrieve_update_destroy', - kwargs={'hyperlink': link.sodar_uuid}, - ) + def test_delete_anon(self): + """Test DELETE with anonymous access""" self.project.set_public() - self.assert_response_api( - url, - self.anonymous, - 401, - method='DELETE', - ) + self.assert_response_api(self.url, self.anonymous, 401, method='DELETE') - def test_hyperlink_destroy_archive(self): - """Test permissions for hyperlink destroying with DELETE and archived project""" + def test_delete_archive(self): + """Test DELETE with archived project""" self.project.set_archive() - obj_uuid = uuid.uuid4() - c_kwargs = {'obj_uuid': obj_uuid} - url = reverse( - 'filesfolders:api_hyperlink_retrieve_update_destroy', - kwargs={'hyperlink': obj_uuid}, - ) good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -2014,31 +1704,24 @@ def test_hyperlink_destroy_archive(self): self.user_guest, self.user_no_roles, ] - self._cleanup_link_destroy(**c_kwargs) self.assert_response_api( - url, + self.url, good_users, 204, method='DELETE', - cleanup_method=self._cleanup_link_destroy, - cleanup_kwargs=c_kwargs, + cleanup_method=self._cleanup_delete, ) - self.assert_response_api(url, bad_users, 403, method='DELETE') - self.assert_response_api(url, self.anonymous, 401, method='DELETE') + self.assert_response_api(self.url, bad_users, 403, method='DELETE') + self.assert_response_api(self.url, self.anonymous, 401, method='DELETE') self.assert_response_api( - url, + self.url, good_users, 204, method='DELETE', - cleanup_method=self._cleanup_link_destroy, - cleanup_kwargs=c_kwargs, + cleanup_method=self._cleanup_delete, knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, - self.user_no_roles, - 403, - method='DELETE', + self.url, self.user_no_roles, 403, method='DELETE' ) diff --git a/projectroles/tests/test_permissions.py b/projectroles/tests/test_permissions.py index 8803725e..aded328e 100644 --- a/projectroles/tests/test_permissions.py +++ b/projectroles/tests/test_permissions.py @@ -1,4 +1,4 @@ -"""UI view permission tests for the projectroles app""" +"""Tests for UI view permissions in the projectroles app""" from urllib.parse import urlencode, quote @@ -240,11 +240,11 @@ def setUp(self): self.anonymous = None -class TestBaseViews(TestProjectPermissionBase): - """Tests for base UI views""" +class TestGeneralViews(TestProjectPermissionBase): + """Tests for general non-project UI view permissions""" - def test_home(self): - """Test home view permissions""" + def test_get_home(self): + """Test HomeView GET""" url = reverse('home') good_users = [ self.superuser, @@ -264,8 +264,8 @@ def test_home(self): self.assert_response(url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_home_anon(self): - """Test home view permissions with anonymous access""" + def test_get_home_anon(self): + """Test HomeView GET with anonymous access""" url = reverse('home') good_users = [ self.superuser, @@ -283,8 +283,8 @@ def test_home_anon(self): ] self.assert_response(url, good_users, 200) - def test_project_search(self): - """Test search results permissions""" + def test_get_search(self): + """Test ProjectSearchResultsView GET""" url = reverse('projectroles:search') + '?' + urlencode({'s': 'test'}) good_users = [ self.superuser, @@ -304,8 +304,8 @@ def test_project_search(self): self.assert_response(reverse('home'), bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_project_search_anon(self): - """Test search results permissions with anonymous access""" + def test_get_search_anon(self): + """Test ProjectSearchResultsView GET with anonymous access""" url = reverse('projectroles:search') + '?' + urlencode({'s': 'test'}) good_users = [ self.superuser, @@ -323,8 +323,8 @@ def test_project_search_anon(self): ] self.assert_response(url, good_users, 200) - def test_project_search_advanced(self): - """Test advanced search view permissions""" + def test_get_search_advanced(self): + """Test ProjectAdvancedSearchView GET""" url = reverse('projectroles:search_advanced') good_users = [ self.superuser, @@ -344,8 +344,8 @@ def test_project_search_advanced(self): self.assert_response(reverse('home'), bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_project_search_advanced_anon(self): - """Test advanced search permissions view with anonymous access""" + def test_get_search_advanced_anon(self): + """Test ProjectAdvancedSearchView GET with anonymous access""" url = reverse('projectroles:search_advanced') good_users = [ self.superuser, @@ -363,8 +363,8 @@ def test_project_search_advanced_anon(self): ] self.assert_response(url, good_users, 200) - def test_login(self): - """Test login view permissions""" + def test_get_login(self): + """Test LoginView GET""" url = reverse('login') good_users = [ self.superuser, @@ -381,8 +381,8 @@ def test_login(self): ] self.assert_response(url, good_users, 200) - def test_logout(self): - """Test logout view permissions""" + def test_get_logout(self): + """Test logout view GET""" url = reverse('logout') good_users = [ self.superuser, @@ -405,8 +405,8 @@ def test_logout(self): redirect_anon='/login/', ) - def test_admin(self): - """Test admin view permissions""" + def test_get_admin(self): + """Test admin view GET""" url = '/admin/' good_users = [self.superuser] bad_users = [ @@ -432,8 +432,8 @@ def test_admin(self): ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_admin_anon(self): - """Test admin view permissions with anonymous access""" + def test_get_admin_anon(self): + """Test admin view GET with anonymous access""" url = '/admin/' good_users = [self.superuser] bad_users = [ @@ -459,60 +459,61 @@ def test_admin_anon(self): ) -class TestProjectViews(IPAllowMixin, TestProjectPermissionBase): - """Permission tests for Project UI views""" +class TestProjectDetailView(TestProjectPermissionBase): + """Tests for ProjectDetailView permissions""" - def test_category_details(self): - """Test category details permissions""" - url = reverse( + def setUp(self): + super().setUp() + self.url = reverse( + 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + ) + self.url_cat = reverse( 'projectroles:detail', kwargs={'project': self.category.sodar_uuid} ) + + def test_get(self): + """Test ProjectDetailView GET""" good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, - self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, ] - bad_users = [self.user_no_roles, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) # Test public project self.project.set_public() - self.assert_response(url, self.user_no_roles, 200) + self.assert_response(self.url, self.user_no_roles, 200) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_category_details_anon(self): - """Test permissions for category details with anonymous access""" - url = reverse( - 'projectroles:detail', kwargs={'project': self.category.sodar_uuid} - ) + def test_get_anon(self): + """Test GET with anonymous access""" good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, - self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, ] - bad_users = [self.user_no_roles, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) + self.project.set_public() + self.assert_response(self.url, bad_users, 200) - def test_project_details(self): - """Test project details permissions""" - url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} - ) + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, @@ -525,96 +526,136 @@ def test_project_details(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 200) + self.assert_response(self.url, self.user_no_roles, 200) - @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_project_details_anon(self): - """Test project details permissions with anonymous access""" - url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} - ) + def test_get_category(self): + """Test GET with category""" good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, + self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, ] - bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + bad_users = [self.user_no_roles, self.anonymous] + self.assert_response(self.url_cat, good_users, 200) + self.assert_response(self.url_cat, bad_users, 302) self.project.set_public() - self.assert_response(url, bad_users, 200) + self.assert_response(self.url_cat, self.user_no_roles, 200) - def test_project_details_ip_http_x_forwarded_for_block_all(self): - """Test IP allow list with HTTP_X_FORWARDED_FOR and block all""" - self.setup_ip_allowing([]) - url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} - ) + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_category_anon(self): + """Test GET with category and anonymous access""" good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, self.user_owner, self.user_delegate, + self.user_contributor, + self.user_guest, ] + bad_users = [self.user_no_roles, self.anonymous] + self.assert_response(self.url_cat, good_users, 200) + self.assert_response(self.url_cat, bad_users, 302) + + +class TestProjectCreateView(TestProjectPermissionBase): + """Tests for ProjectCreateView permissions""" + + def setUp(self): + super().setUp() + self.url_top = reverse('projectroles:create') + self.url_sub = reverse( + 'projectroles:create', kwargs={'project': self.category.sodar_uuid} + ) + + def test_get_top(self): + """Test ProjectCreateView GET for top level creation""" + good_users = [self.superuser] bad_users = [ + self.user_owner_cat, + self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, + self.user_owner, + self.user_delegate, self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - header = {'HTTP_X_FORWARDED_FOR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(self.url_top, good_users, 200) + self.assert_response(self.url_top, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302, header=header) + self.assert_response(self.url_top, self.user_no_roles, 302) - def test_project_details_ip_x_forwarded_for_block_all(self): - """Test IP allow list with X_FORWARDED_FOR and block all""" - self.setup_ip_allowing([]) - url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_top_anon(self): + """Test GET for top level creation with anonymous access""" + self.project.set_public() + self.assert_response( + self.url_top, [self.user_no_roles, self.anonymous], 302 ) + + def test_get_sub(self): + """Test GET for subproject creation""" good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_owner, - self.user_delegate, + self.user_contributor_cat, ] bad_users = [ - self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, + self.user_owner, + self.user_delegate, self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - header = {'X_FORWARDED_FOR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(self.url_sub, good_users, 200) + self.assert_response(self.url_sub, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302, header=header) + self.assert_response(self.url_sub, self.user_no_roles, 302) - def test_project_details_ip_forwarded_block_all(self): - """Test IP allow list with FORWARDED and block all""" - self.setup_ip_allowing([]) - url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_sub_anon(self): + """Test GET for subproject creation with anonymous access""" + self.project.set_public() + self.assert_response( + self.url_sub, [self.user_no_roles, self.anonymous], 302 ) + + +class TestProjectUpdateView(TestProjectPermissionBase): + """Tests for ProjectUpdateView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( + 'projectroles:update', kwargs={'project': self.project.sodar_uuid} + ) + self.url_cat = reverse( + 'projectroles:update', kwargs={'project': self.category.sodar_uuid} + ) + + def test_get(self): + """Test ProjectUpdateView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -631,18 +672,22 @@ def test_project_details_ip_forwarded_block_all(self): self.user_no_roles, self.anonymous, ] - header = {'FORWARDED': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302, header=header) + self.assert_response(self.url, self.user_no_roles, 302) - def test_project_details_ip_remote_addr_block_all(self): - """Test IP allow list with REMOTE_ADDR fwd and block all""" - self.setup_ip_allowing([]) - url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" + self.project.set_public() + self.assert_response( + self.url, [self.user_no_roles, self.anonymous], 302 ) + + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, @@ -659,102 +704,163 @@ def test_project_details_ip_remote_addr_block_all(self): self.user_no_roles, self.anonymous, ] - header = {'REMOTE_ADDR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302, header=header) + self.assert_response(self.url, self.user_no_roles, 302) - def test_project_details_ip_http_x_forwarded_for_allow_ip(self): - """Test IP allow list with HTTP_X_FORWARDED_FOR and allowed IP""" - self.setup_ip_allowing(['192.168.1.1']) - url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} - ) + def test_get_category(self): + """Test GET with category""" good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, + ] + bad_users = [ self.user_contributor_cat, self.user_guest_cat, + self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, + self.anonymous, + ] + self.assert_response(self.url_cat, good_users, 200) + self.assert_response(self.url_cat, bad_users, 302) + self.project.set_public() + self.assert_response(self.url_cat, self.user_no_roles, 302) + + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_category_anon(self): + """Test GET with category and anonymous access""" + self.project.set_public() + self.assert_response( + self.url_cat, [self.user_no_roles, self.anonymous], 302 + ) + + +class TestProjectArchiveView(TestProjectPermissionBase): + """Tests for ProjectArchiveView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( + 'projectroles:archive', kwargs={'project': self.project.sodar_uuid} + ) + self.url_cat = reverse( + 'projectroles:archive', kwargs={'project': self.category.sodar_uuid} + ) + + def test_get(self): + """Test ProjectArchiveView GET""" + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, ] bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, self.user_finder_cat, + self.user_contributor, + self.user_guest, self.user_no_roles, self.anonymous, ] - header = {'HTTP_X_FORWARDED_FOR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 200, header=header) + self.assert_response(self.url, self.user_no_roles, 302) - def test_project_details_ip_x_forwarded_for_allow_ip(self): - """Test IP allow list with X_FORWARDED_FOR and allowed IP""" - self.setup_ip_allowing(['192.168.1.1']) - url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} - ) + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 302) + + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_contributor_cat, - self.user_guest_cat, self.user_owner, self.user_delegate, - self.user_contributor, - self.user_guest, ] bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, self.user_finder_cat, + self.user_contributor, + self.user_guest, self.user_no_roles, self.anonymous, ] - header = {'X_FORWARDED_FOR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 200, header=header) + self.assert_response(self.url, self.user_no_roles, 302) - def test_project_details_ip_forwarded_allow_ip(self): - """Test IP allow list with FORWARDED and allowed IP""" - self.setup_ip_allowing(['192.168.1.1']) - url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} - ) - good_users = [ + def test_get_category(self): + """Test GET with category""" + bad_users_cat = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, + ] + bad_users_non_cat = [ self.user_contributor_cat, self.user_guest_cat, + self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, - ] - bad_users = [ - self.user_finder_cat, self.user_no_roles, self.anonymous, ] - header = {'FORWARDED': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response( + self.url_cat, + bad_users_cat, + 302, + redirect_user=reverse( + 'projectroles:detail', + kwargs={'project': self.category.sodar_uuid}, + ), + ) + self.assert_response( + self.url_cat, + bad_users_non_cat, + 302, # Non-category users get redirected to home + ) self.project.set_public() - self.assert_response(url, self.user_no_roles, 200, header=header) + self.assert_response(self.url_cat, self.user_no_roles, 302) - def test_project_details_ip_remote_addr_allow_ip(self): - """Test IP allow list with REMOTE_ADDR and allowed IP""" - self.setup_ip_allowing(['192.168.1.1']) - url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_category_anon(self): + """Test GET with category and anonymous access""" + self.project.set_public() + self.assert_response(self.url_cat, self.user_no_roles, 302) + + +class TestProjectRoleView(TestProjectPermissionBase): + """Tests for ProjectRoleView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( + 'projectroles:roles', kwargs={'project': self.project.sodar_uuid} + ) + self.url_cat = reverse( + 'projectroles:roles', kwargs={'project': self.category.sodar_uuid} ) + + def test_get(self): + """Test ProjectRoleView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -766,24 +872,23 @@ def test_project_details_ip_remote_addr_allow_ip(self): self.user_contributor, self.user_guest, ] - bad_users = [ - self.user_finder_cat, - self.user_no_roles, - self.anonymous, - ] - header = {'REMOTE_ADDR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 200, header=header) - - def test_project_details_ip_remote_addr_allow_network(self): - """Test IP allow list with REMOTE_ADDR and allowed network""" - self.setup_ip_allowing(['192.168.1.0/24']) + self.assert_response(self.url, self.user_no_roles, 200) - url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" + self.project.set_public() + self.assert_response( + self.url, [self.user_no_roles, self.anonymous], 200 ) + + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, @@ -795,23 +900,53 @@ def test_project_details_ip_remote_addr_allow_network(self): self.user_contributor, self.user_guest, ] - bad_users = [ + bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 200) + + def test_get_category(self): + """Test GET with category""" + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_contributor_cat, + self.user_guest_cat, self.user_finder_cat, + ] + bad_users = [ + self.user_owner, + self.user_delegate, + self.user_contributor, + self.user_guest, self.user_no_roles, self.anonymous, ] - header = {'REMOTE_ADDR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) - self.project.set_public() - self.assert_response(url, self.user_no_roles, 200, header=header) + self.assert_response(self.url_cat, good_users, 200) + self.assert_response(self.url_cat, bad_users, 302) + # Public guest access is disabled for categories + with self.assertRaises(ValidationError): + self.category.set_public() - def test_project_details_ip_remote_addr_not_in_list_ip(self): - """Test IP allow list with REMOTE_ADDR and IP not in list""" - self.setup_ip_allowing(['192.168.1.2']) - url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + +class TestRoleAssignmentCreateView(TestProjectPermissionBase): + """Tests for RoleAssignmentCreateView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( + 'projectroles:role_create', + kwargs={'project': self.project.sodar_uuid}, + ) + self.url_cat = reverse( + 'projectroles:role_create', + kwargs={'project': self.category.sodar_uuid}, ) + + def test_get(self): + """Test RoleAssignmentCreateView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -823,23 +958,26 @@ def test_project_details_ip_remote_addr_not_in_list_ip(self): self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, - self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - header = {'REMOTE_ADDR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302, header=header) + self.assert_response(self.url, self.user_no_roles, 302) - def test_project_details_ip_remote_addr_not_in_list_network(self): - """Test IP allow list with REMOTE_ADDR and network not in list""" - self.setup_ip_allowing(['192.168.2.0/24']) - url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" + self.project.set_public() + self.assert_response( + self.url, [self.user_no_roles, self.anonymous], 302 ) + + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, @@ -856,20 +994,20 @@ def test_project_details_ip_remote_addr_not_in_list_network(self): self.user_no_roles, self.anonymous, ] - header = {'REMOTE_ADDR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302, header=header) + self.assert_response(self.url, self.user_no_roles, 302) - def test_create_top(self): - """Test permissions for top level project creation""" - url = reverse('projectroles:create') - good_users = [self.superuser] - bad_users = [ + def test_get_category(self): + """Test GET with category""" + good_users = [ + self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_contributor_cat, + ] + bad_users = [ + self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, self.user_owner, @@ -879,58 +1017,61 @@ def test_create_top(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) + self.assert_response(self.url_cat, good_users, 200) + self.assert_response(self.url_cat, bad_users, 302) + # Public guest access is disabled for categories + with self.assertRaises(ValidationError): + self.category.set_public() - @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_create_top_anon(self): - """Test permissions for top level project creation with anonymous access""" - url = reverse('projectroles:create') - self.project.set_public() - self.assert_response(url, [self.user_no_roles, self.anonymous], 302) - def test_create_sub(self): - """Test permissions for subproject creation""" - url = reverse( - 'projectroles:create', kwargs={'project': self.category.sodar_uuid} +class TestRoleAssignmentUpdateView(TestProjectPermissionBase): + """Tests for RoleAssignmentUpdateView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( + 'projectroles:role_update', + kwargs={'roleassignment': self.contributor_as.sodar_uuid}, ) + self.url_cat = reverse( + 'projectroles:role_update', + kwargs={'roleassignment': self.contributor_as_cat.sodar_uuid}, + ) + + def test_get(self): + """Test RoleAssignmentUpdateView GET""" good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_contributor_cat, + self.user_owner, + self.user_delegate, ] bad_users = [ + self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, - self.user_owner, - self.user_delegate, - self.user_contributor, self.user_guest, + self.user_contributor, self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) + self.assert_response(self.url, self.user_no_roles, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_create_sub_anon(self): - """Test permissions for subproject creation with anonymous access""" - url = reverse( - 'projectroles:create', kwargs={'project': self.category.sodar_uuid} - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, [self.user_no_roles, self.anonymous], 302) - - def test_update(self): - """Test project update permissions""" - url = reverse( - 'projectroles:update', kwargs={'project': self.project.sodar_uuid} + self.assert_response( + self.url, [self.user_no_roles, self.anonymous], 302 ) + + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, @@ -942,36 +1083,57 @@ def test_update(self): self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, + self.user_guest, self.user_contributor, + self.user_no_roles, + self.anonymous, + ] + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 302) + + def test_get_category(self): + """Test GET with category""" + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + ] + bad_users = [ + self.user_owner, + self.user_delegate, + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, self.user_guest, + self.user_contributor, self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url_cat, good_users, 200) + self.assert_response(self.url_cat, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) + self.assert_response(self.url_cat, self.user_no_roles, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_update_anon(self): - """Test project update permissions with anonymous access""" - url = reverse( - 'projectroles:update', kwargs={'project': self.project.sodar_uuid} - ) + def test_get_category_anon(self): + """Test GET with category and anonymous access""" self.project.set_public() - self.assert_response(url, [self.user_no_roles, self.anonymous], 302) + self.assert_response( + self.url_cat, [self.user_no_roles, self.anonymous], 302 + ) - def test_update_category(self): - """Test category update permissions""" + def test_get_owner(self): + """Test GET with owner role (should fail)""" url = reverse( - 'projectroles:update', kwargs={'project': self.category.sodar_uuid} + 'projectroles:role_update', + kwargs={'roleassignment': self.owner_as.sodar_uuid}, ) - good_users = [ + bad_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - ] - bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -979,35 +1141,36 @@ def test_update_category(self): self.user_delegate, self.user_contributor, self.user_guest, + self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) self.assert_response(url, bad_users, 302) self.project.set_public() self.assert_response(url, self.user_no_roles, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_update_category_anon(self): - """Test category update permissions with anonymous access""" + def test_get_owner_anon(self): + """Test GET with owner role with anonymous access (should fail)""" url = reverse( - 'projectroles:update', kwargs={'project': self.category.sodar_uuid} + 'projectroles:role_update', + kwargs={'roleassignment': self.owner_as.sodar_uuid}, ) self.project.set_public() self.assert_response(url, [self.user_no_roles, self.anonymous], 302) - def test_archive(self): - """Test ProjectArchiveView permissions for project archiving""" + def test_get_delegate(self): + """Test GET with delegate role""" url = reverse( - 'projectroles:archive', kwargs={'project': self.project.sodar_uuid} + 'projectroles:role_update', + kwargs={'roleassignment': self.delegate_as.sodar_uuid}, ) good_users = [ self.superuser, self.user_owner_cat, - self.user_delegate_cat, self.user_owner, - self.user_delegate, ] bad_users = [ + self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -1021,89 +1184,120 @@ def test_archive(self): self.project.set_public() self.assert_response(url, self.user_no_roles, 302) - def test_archive_category(self): - """Test ProjectArchiveView permissions for category archiving""" - url = reverse( - 'projectroles:archive', kwargs={'project': self.category.sodar_uuid} + +class TestRoleAssignmentDeleteView(TestProjectPermissionBase): + """Tests for RoleAssignmentDeleteView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( + 'projectroles:role_delete', + kwargs={'roleassignment': self.contributor_as.sodar_uuid}, ) - bad_users_cat = [ + self.url_cat = reverse( + 'projectroles:role_delete', + kwargs={'roleassignment': self.contributor_as_cat.sodar_uuid}, + ) + + def test_get(self): + """Test RoleAssignmentDeleteView GET""" + good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, + self.user_owner, + self.user_delegate, ] - bad_users_other = [ + bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, - self.user_owner, - self.user_delegate, self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - self.assert_response( - url, - bad_users_cat, - 302, - redirect_user=reverse( - 'projectroles:detail', - kwargs={'project': self.category.sodar_uuid}, - ), - ) - self.assert_response( - url, - bad_users_other, - 302, # Non-category users get redirected to home - ) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) + self.assert_response(self.url, self.user_no_roles, 302) - def test_roles(self): - """Test role list permissions""" - url = reverse( - 'projectroles:roles', kwargs={'project': self.project.sodar_uuid} + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" + self.project.set_public() + self.assert_response( + self.url, [self.user_no_roles, self.anonymous], 302 ) + + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ self.user_contributor_cat, self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + self.anonymous, + ] + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 302) + + def test_get_category(self): + """Test RoleAssignmentDeleteView GET""" + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + ] + bad_users = [ self.user_owner, self.user_delegate, + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, self.user_contributor, self.user_guest, + self.user_no_roles, + self.anonymous, ] - bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url_cat, good_users, 200) + self.assert_response(self.url_cat, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 200) + self.assert_response(self.url_cat, self.user_no_roles, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_roles_anon(self): - """Test role list permissions with anonymous access""" - url = reverse( - 'projectroles:roles', kwargs={'project': self.project.sodar_uuid} - ) + def test_get_category_anon(self): + """Test GET with category and anonymous access""" self.project.set_public() - self.assert_response(url, [self.user_no_roles, self.anonymous], 200) + self.assert_response( + self.url_cat, [self.user_no_roles, self.anonymous], 302 + ) - def test_roles_category(self): - """Test role list permissions under category""" + def test_get_owner(self): + """Test GET with owner role (should fail)""" url = reverse( - 'projectroles:roles', kwargs={'project': self.category.sodar_uuid} + 'projectroles:role_delete', + kwargs={'roleassignment': self.owner_as.sodar_uuid}, ) - good_users = [ + bad_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, - ] - bad_users = [ self.user_owner, self.user_delegate, self.user_contributor, @@ -1111,29 +1305,38 @@ def test_roles_category(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) self.assert_response(url, bad_users, 302) - # public guest access is temporally disabled for categories - with self.assertRaises(ValidationError): - self.category.set_public() + self.project.set_public() + self.assert_response(url, self.user_no_roles, 302) - def test_role_create(self): - """Test role create permissions""" + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_owner_anon(self): + """Test GET with owner role and anonymous access (should fail)""" url = reverse( - 'projectroles:role_create', - kwargs={'project': self.project.sodar_uuid}, + 'projectroles:role_delete', + kwargs={'roleassignment': self.owner_as.sodar_uuid}, + ) + self.project.set_public() + self.assert_response(url, [self.user_no_roles, self.anonymous], 302) + + def test_get_delegate(self): + """Test GET with delegate role""" + url = reverse( + 'projectroles:role_delete', + kwargs={'roleassignment': self.delegate_as.sodar_uuid}, ) good_users = [ self.superuser, self.user_owner_cat, - self.user_delegate_cat, self.user_owner, - self.user_delegate, ] bad_users = [ + self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, + self.user_delegate, + self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, @@ -1143,78 +1346,87 @@ def test_role_create(self): self.project.set_public() self.assert_response(url, self.user_no_roles, 302) - @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_role_create_anon(self): - """Test role create permissions with anonymous access""" - url = reverse( - 'projectroles:role_create', + +class TestRoleAssignmentOwnerTransferView(TestProjectPermissionBase): + """Tests for RoleAssignmentOwnerTransferView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( + 'projectroles:role_owner_transfer', kwargs={'project': self.project.sodar_uuid}, ) - self.project.set_public() - self.assert_response(url, [self.user_no_roles, self.anonymous], 302) - def test_role_create_category(self): - """Test role create permissions under category""" - url = reverse( - 'projectroles:role_create', - kwargs={'project': self.category.sodar_uuid}, - ) + def test_get(self): + """Test RoleAssignmentOwnerTransferView GET""" good_users = [ self.superuser, self.user_owner_cat, - self.user_delegate_cat, + self.user_owner, ] bad_users = [ + self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, - self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # public guest access is temporarily disabled for categories - with self.assertRaises(ValidationError): - self.category.set_public() + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 302) - def test_role_create_archive(self): - """Test permissions for role creation in archived project""" - self.project.set_archive() - url = reverse( - 'projectroles:role_create', - kwargs={'project': self.project.sodar_uuid}, + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access (should fail)""" + self.project.set_public() + self.assert_response( + self.url, [self.user_no_roles, self.anonymous], 302 ) + + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, - self.user_delegate_cat, self.user_owner, - self.user_delegate, ] bad_users = [ + self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, + self.user_delegate, self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) # Should be allowed - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) + self.assert_response(self.url, self.user_no_roles, 302) - def test_role_update(self): - """Test role update permissions""" - url = reverse( - 'projectroles:role_update', - kwargs={'roleassignment': self.contributor_as.sodar_uuid}, + +class TestProjectInviteView(TestProjectPermissionBase): + """Tests for ProjectInviteView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( + 'projectroles:invites', kwargs={'project': self.project.sodar_uuid} + ) + self.url_cat = reverse( + 'projectroles:invites', kwargs={'project': self.category.sodar_uuid} ) + + def test_get(self): + """Test ProjectInviteView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -1226,32 +1438,27 @@ def test_role_update(self): self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, - self.user_guest, self.user_contributor, + self.user_guest, self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) + self.assert_response(self.url, self.user_no_roles, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_role_update_anon(self): - """Test role update permissions with anonymous access""" - url = reverse( - 'projectroles:role_update', - kwargs={'roleassignment': self.contributor_as.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, [self.user_no_roles, self.anonymous], 302) - - def test_role_delete(self): - """Test role delete permissions""" - url = reverse( - 'projectroles:role_delete', - kwargs={'roleassignment': self.contributor_as.sodar_uuid}, + self.assert_response( + self.url, [self.user_no_roles, self.anonymous], 302 ) + + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, @@ -1268,93 +1475,19 @@ def test_role_delete(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) - - @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_role_delete_anon(self): - """Test role delete permissions with anonymous access""" - url = reverse( - 'projectroles:role_delete', - kwargs={'roleassignment': self.contributor_as.sodar_uuid}, - ) - self.project.set_public() - self.assert_response(url, [self.user_no_roles, self.anonymous], 302) - - def test_role_update_owner(self): - """Test permissions for owner role update (should fail)""" - url = reverse( - 'projectroles:role_update', - kwargs={'roleassignment': self.owner_as.sodar_uuid}, - ) - bad_users = [ - self.superuser, - self.user_owner_cat, - self.user_delegate_cat, - self.user_contributor_cat, - self.user_guest_cat, - self.user_finder_cat, - self.user_owner, - self.user_delegate, - self.user_contributor, - self.user_guest, - self.user_no_roles, - self.anonymous, - ] - self.assert_response(url, bad_users, 302) - self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) - - @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_role_update_owner_anon(self): - """Test owner update permissions with anonymous access (should fail)""" - url = reverse( - 'projectroles:role_update', - kwargs={'roleassignment': self.owner_as.sodar_uuid}, - ) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, [self.user_no_roles, self.anonymous], 302) + self.assert_response(self.url, self.user_no_roles, 302) - def test_role_update_archive(self): - """Test permissions for role updating for archived project""" - self.project.set_archive() - url = reverse( - 'projectroles:role_update', - kwargs={'roleassignment': self.contributor_as.sodar_uuid}, - ) + def test_get_category(self): + """Test GET with category""" good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_owner, - self.user_delegate, - ] - bad_users = [ - self.user_contributor_cat, - self.user_guest_cat, - self.user_finder_cat, - self.user_contributor, - self.user_guest, - self.user_no_roles, - self.anonymous, ] - self.assert_response(url, good_users, 200) # Should be allowed - self.assert_response(url, bad_users, 302) - self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) - - def test_role_delete_owner(self): - """Test owner delete permissions (should fail)""" - url = reverse( - 'projectroles:role_delete', - kwargs={'roleassignment': self.owner_as.sodar_uuid}, - ) bad_users = [ - self.superuser, - self.user_owner_cat, - self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -1365,116 +1498,61 @@ def test_role_delete_owner(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, bad_users, 302) - self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) - - @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_role_delete_owner_anon(self): - """Test owner delete permissions with anonymous access (should fail)""" - url = reverse( - 'projectroles:role_delete', - kwargs={'roleassignment': self.owner_as.sodar_uuid}, - ) - self.project.set_public() - self.assert_response(url, [self.user_no_roles, self.anonymous], 302) + self.assert_response(self.url_cat, good_users, 200) + self.assert_response(self.url_cat, bad_users, 302) + # public guest access is temporally disabled for categories + with self.assertRaises(ValidationError): + self.category.set_public() - def test_role_update_delegate(self): - """Test delegate update permissions""" - url = reverse( - 'projectroles:role_update', - kwargs={'roleassignment': self.delegate_as.sodar_uuid}, - ) - good_users = [ - self.superuser, - self.user_owner_cat, - self.user_owner, - ] - bad_users = [ - self.user_delegate_cat, - self.user_contributor_cat, - self.user_guest_cat, - self.user_finder_cat, - self.user_contributor, - self.user_guest, - self.user_no_roles, - self.anonymous, - ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) - def test_role_delete_delegate(self): - """Test role delete permissions for delegate""" - url = reverse( - 'projectroles:role_delete', - kwargs={'roleassignment': self.delegate_as.sodar_uuid}, - ) - good_users = [ - self.superuser, - self.user_owner_cat, - self.user_owner, - ] - bad_users = [ - self.user_delegate_cat, - self.user_contributor_cat, - self.user_guest_cat, - self.user_finder_cat, - self.user_delegate, - self.user_contributor, - self.user_guest, - self.user_no_roles, - self.anonymous, - ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) +class TestProjectInviteCreateView(TestProjectPermissionBase): + """Tests for ProjectInviteCreateView permissions""" - def test_role_owner_transfer(self): - """Test owner update permissions""" - url = reverse( - 'projectroles:role_owner_transfer', + def setUp(self): + super().setUp() + self.url = reverse( + 'projectroles:invite_create', kwargs={'project': self.project.sodar_uuid}, ) + self.url_cat = reverse( + 'projectroles:invite_create', + kwargs={'project': self.category.sodar_uuid}, + ) + + def test_get(self): + """Test ProjectInviteCreateView GET""" good_users = [ self.superuser, self.user_owner_cat, + self.user_delegate_cat, self.user_owner, + self.user_delegate, ] bad_users = [ - self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, - self.user_delegate, self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) + self.assert_response(self.url, self.user_no_roles, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_role_owner_transfer_anon(self): - """Test owner update permissions with anonymous access (should fail)""" - url = reverse( - 'projectroles:role_owner_transfer', - kwargs={'project': self.project.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, [self.user_no_roles, self.anonymous], 302) - - def test_role_invite_create(self): - """Test invite create permissions""" - url = reverse( - 'projectroles:invite_create', - kwargs={'project': self.project.sodar_uuid}, + self.assert_response( + self.url, [self.user_no_roles, self.anonymous], 302 ) + + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, @@ -1491,27 +1569,13 @@ def test_role_invite_create(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) - - @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_role_invite_create_anon(self): - """Test invite create permissions with anonymous access (should fail)""" - url = reverse( - 'projectroles:invite_create', - kwargs={'project': self.project.sodar_uuid}, - ) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, [self.user_no_roles, self.anonymous], 302) + self.assert_response(self.url, self.user_no_roles, 302) - def test_role_invite_create_category(self): - """Test invite create permissions under category""" - url = reverse( - 'projectroles:invite_create', - kwargs={'project': self.category.sodar_uuid}, - ) + def test_get_category(self): + """Test GET with category""" good_users = [ self.superuser, self.user_owner_cat, @@ -1528,16 +1592,32 @@ def test_role_invite_create_category(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url_cat, good_users, 200) + self.assert_response(self.url_cat, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) + self.assert_response(self.url_cat, self.user_no_roles, 302) - def test_role_invite_list(self): - """Test invite list permissions""" - url = reverse( - 'projectroles:invites', kwargs={'project': self.project.sodar_uuid} + +class TestProjectInviteResendView(TestProjectPermissionBase): + """Tests for ProjectInviteResendView permissions""" + + def setUp(self): + super().setUp() + # Init invite + invite = self.make_invite( + email='test@example.com', + project=self.project, + role=self.role_contributor, + issuer=self.user_owner, + message='', + ) + self.url = reverse( + 'projectroles:invite_resend', + kwargs={'projectinvite': invite.sodar_uuid}, ) + + def test_get(self): + """Test ProjectInviteResendView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -1554,61 +1634,30 @@ def test_role_invite_list(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response( + self.url, + good_users, + 302, + redirect_user=reverse( + 'projectroles:invites', + kwargs={'project': self.project.sodar_uuid}, + ), + ) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) + self.assert_response(self.url, self.user_no_roles, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_role_invite_list_anon(self): - """Test invite list permissions with anonymous access""" - url = reverse( - 'projectroles:invites', kwargs={'project': self.project.sodar_uuid} - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, [self.user_no_roles, self.anonymous], 302) - - def test_role_invite_list_category(self): - """Test invite list permissions under category""" - url = reverse( - 'projectroles:invites', kwargs={'project': self.category.sodar_uuid} + self.assert_response( + self.url, [self.user_no_roles, self.anonymous], 302 ) - good_users = [ - self.superuser, - self.user_owner_cat, - self.user_delegate_cat, - ] - bad_users = [ - self.user_contributor_cat, - self.user_guest_cat, - self.user_finder_cat, - self.user_owner, - self.user_delegate, - self.user_contributor, - self.user_guest, - self.user_no_roles, - self.anonymous, - ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # public guest access is temporally disabled for categories - with self.assertRaises(ValidationError): - self.category.set_public() - def test_role_invite_resend(self): - """Test invite resend permissions""" - # Init invite - invite = self.make_invite( - email='test@example.com', - project=self.project, - role=self.role_contributor, - issuer=self.user_owner, - message='', - ) - url = reverse( - 'projectroles:invite_resend', - kwargs={'projectinvite': invite.sodar_uuid}, - ) + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, @@ -1626,7 +1675,7 @@ def test_role_invite_resend(self): self.anonymous, ] self.assert_response( - url, + self.url, good_users, 302, redirect_user=reverse( @@ -1634,12 +1683,16 @@ def test_role_invite_resend(self): kwargs={'project': self.project.sodar_uuid}, ), ) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) + self.assert_response(self.url, self.user_no_roles, 302) + - def test_role_invite_revoke(self): - """Test invite revoke permissions""" +class TestProjectInviteRevokeView(TestProjectPermissionBase): + """Tests for ProjectInviteRevokeView permissions""" + + def setUp(self): + super().setUp() # Init invite invite = self.make_invite( email='test@example.com', @@ -1648,11 +1701,13 @@ def test_role_invite_revoke(self): issuer=self.user_owner, message='', ) - - url = reverse( + self.url = reverse( 'projectroles:invite_revoke', kwargs={'projectinvite': invite.sodar_uuid}, ) + + def test_get(self): + """Test ProjectInviteRevokeView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -1669,20 +1724,123 @@ def test_role_invite_revoke(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 302) + self.assert_response(self.url, self.user_no_roles, 302) + + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" + self.project.set_public() + self.assert_response( + self.url, [self.user_no_roles, self.anonymous], 302 + ) + + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + self.anonymous, + ] + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 302) + + +class TestRemoteSiteViews(RemoteSiteMixin, TestSiteAppPermissionBase): + """Tests for UI view permissions in remote site views""" + + def setUp(self): + super().setUp() + self.site = self.make_site( + name=REMOTE_SITE_NAME, + url=REMOTE_SITE_URL, + mode=SODAR_CONSTANTS['SITE_MODE_TARGET'], + description='', + secret=REMOTE_SITE_SECRET, + ) + + def test_get_remote_sites(self): + """Test RemoteSiteListView GET""" + url = reverse('projectroles:remote_sites') + good_users = [self.superuser] + bad_users = [self.regular_user, self.anonymous] + self.assert_response(url, good_users, 200) + self.assert_response(url, bad_users, 302) + + def test_get_remote_site_create(self): + """Test RemoteSiteCreateView GET""" + url = reverse('projectroles:remote_site_create') + good_users = [self.superuser] + bad_users = [self.regular_user, self.anonymous] + self.assert_response(url, good_users, 200) + self.assert_response(url, bad_users, 302) + + def test_get_remmote_site_update(self): + """Test RemoteSiteUpdateView GET""" + url = reverse( + 'projectroles:remote_site_update', + kwargs={'remotesite': self.site.sodar_uuid}, + ) + good_users = [self.superuser] + bad_users = [self.regular_user, self.anonymous] + self.assert_response(url, good_users, 200) + self.assert_response(url, bad_users, 302) + + def test_get_remote_site_delete(self): + """Test RemoteSiteDeleteView GET""" + url = reverse( + 'projectroles:remote_site_delete', + kwargs={'remotesite': self.site.sodar_uuid}, + ) + good_users = [self.superuser] + bad_users = [self.regular_user, self.anonymous] + self.assert_response(url, good_users, 200) + self.assert_response(url, bad_users, 302) + + def test_get_remote_projects(self): + """Test RemoteProjectListView GET""" + url = reverse( + 'projectroles:remote_projects', + kwargs={'remotesite': self.site.sodar_uuid}, + ) + good_users = [self.superuser] + bad_users = [self.regular_user, self.anonymous] + self.assert_response(url, good_users, 200) + self.assert_response(url, bad_users, 302) + + def test_get_remote_project_batch_update(self): + """Test RemoteProjectBatchUpdateView GET""" + url = reverse( + 'projectroles:remote_projects_update', + kwargs={'remotesite': self.site.sodar_uuid}, + ) + good_users = [self.superuser] + bad_users = [self.regular_user, self.anonymous] + self.assert_response(url, good_users, 200) + self.assert_response(url, bad_users, 302) @override_settings(PROJECTROLES_SITE_MODE=SITE_MODE_TARGET) -class TestTargetProjectViews( - IPAllowMixin, - RemoteSiteMixin, - RemoteProjectMixin, - TestProjectPermissionBase, +class TestTargetSiteViews( + RemoteSiteMixin, RemoteProjectMixin, TestProjectPermissionBase ): - """Tests for Project updating views on a TARGET site""" + """Tests for UI view permissions on target site""" def setUp(self): super().setUp() @@ -1708,8 +1866,8 @@ def setUp(self): level=SODAR_CONSTANTS['REMOTE_LEVEL_READ_ROLES'], ) - def test_project_details(self): - """Test project details permissions""" + def test_get_project_detail(self): + """Test ProjectDetailView GET""" url = reverse( 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} ) @@ -1728,11 +1886,10 @@ def test_project_details(self): self.assert_response(url, good_users, 200) self.assert_response(url, bad_users, 302) - def test_project_details_ip_http_x_forwarded_for_block_all(self): - """Test target site IP allow list with X_FORWARDED_FOR and block all""" - self.setup_ip_allowing([]) + def test_get_project_update(self): + """Test ProjectUpdateView GET""" url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + 'projectroles:update', kwargs={'project': self.project.sodar_uuid} ) good_users = [ self.superuser, @@ -1750,298 +1907,238 @@ def test_project_details_ip_http_x_forwarded_for_block_all(self): self.user_no_roles, self.anonymous, ] - header = {'HTTP_X_FORWARDED_FOR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(url, good_users, 200) + self.assert_response(url, bad_users, 302, redirect_anon=reverse('home')) - def test_project_details_ip_x_forwarded_for_block_all(self): - """Test target site IP allow list with FORWARDED and block all""" - self.setup_ip_allowing([]) - url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} - ) - good_users = [ - self.superuser, + def test_get_create_top(self): + """Test ProjectCreateView GET""" + url = reverse('projectroles:create') + good_users = [self.superuser] + bad_users = [ self.user_owner_cat, self.user_delegate_cat, - self.user_owner, - self.user_delegate, - ] - bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, + self.user_owner, + self.user_delegate, self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - header = {'X_FORWARDED_FOR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(url, good_users, 200) + self.assert_response(url, bad_users, 302) - def test_project_details_ip_forwarded_block_all(self): - """Test target site IP allow list with FORWARDED and block all""" - self.setup_ip_allowing([]) + # TODO: Add separate tests for local/remote creation + # TODO: Remote creation should fail + def test_get_project_create_local(self): + """Test ProjectCreateView GET under local category""" + # Make category local + self.remote_category.delete() url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + 'projectroles:create', kwargs={'project': self.category.sodar_uuid} ) good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_owner, - self.user_delegate, + self.user_contributor_cat, ] bad_users = [ - self.user_contributor_cat, + self.anonymous, self.user_guest_cat, self.user_finder_cat, + self.user_owner, + self.user_delegate, self.user_contributor, self.user_guest, self.user_no_roles, - self.anonymous, ] - header = {'FORWARDED': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(url, good_users, 200) + self.assert_response(url, bad_users, 302) - def test_project_details_ip_remote_addr_block_all(self): - """Test target site IP allow list with REMOTE_ADDR fwd and block all""" - self.setup_ip_allowing([]) + def test_get_project_create_remote(self): + """Test ProjectCreateView GET under local category""" url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + 'projectroles:create', kwargs={'project': self.category.sodar_uuid} ) - good_users = [ + bad_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_owner, - self.user_delegate, - ] - bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, + self.user_owner, + self.user_delegate, self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - header = {'REMOTE_ADDR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(url, bad_users, 302) - def test_project_details_ip_http_x_forwarded_for_allow_ip(self): - """Test target site IP allow list with HTTP_X_FORWARDED_FOR and allowed IP""" - self.setup_ip_allowing(['192.168.1.1']) + @override_settings(PROJECTROLES_TARGET_CREATE=False) + def test_get_project_create_disallowed(self): + """Test ProjectCreateView GET with creation disallowed""" url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + 'projectroles:create', kwargs={'project': self.category.sodar_uuid} ) - good_users = [ + bad_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, + self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, - ] - bad_users = [ - self.user_finder_cat, self.user_no_roles, self.anonymous, ] - header = {'HTTP_X_FORWARDED_FOR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(url, bad_users, 302) - def test_project_details_ip_x_forwarded_for_allow_ip(self): - """Test target site IP allow list with X_FORWARDED_FOR and allowed IP""" - self.setup_ip_allowing(['192.168.1.1']) + def test_get_role_create(self): + """Test RoleAssignmentCreateView GET""" url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + 'projectroles:role_create', + kwargs={'project': self.project.sodar_uuid}, ) - good_users = [ + bad_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, + self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, - ] - bad_users = [ - self.user_finder_cat, self.user_no_roles, self.anonymous, ] - header = {'X_FORWARDED_FOR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(url, bad_users, 302, redirect_anon=reverse('home')) - def test_project_details_ip_allowing_forwarded_allow_ip(self): - """Test target site IP allow list with FORWARDED and allowed IP""" - self.setup_ip_allowing(['192.168.1.1']) + def test_get_role_update(self): + """Test RoleAssignmentUpdateView GET""" url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + 'projectroles:role_update', + kwargs={'roleassignment': self.contributor_as.sodar_uuid}, ) - good_users = [ + bad_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, + self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, - ] - bad_users = [ - self.user_finder_cat, self.user_no_roles, self.anonymous, ] - header = {'FORWARDED': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(url, bad_users, 302, redirect_anon=reverse('home')) - def test_project_details_ip_remote_addr_allow_ip(self): - """Test target site IP allow list with REMOTE_ADDR and allowed IP""" - self.setup_ip_allowing(['192.168.1.1']) + def test_get_role_update_delegate(self): + """Test RoleAssignmentUpdateView GET for delegate role""" url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + 'projectroles:role_update', + kwargs={'roleassignment': self.delegate_as.sodar_uuid}, ) - good_users = [ + bad_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, + self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, - ] - bad_users = [ - self.user_finder_cat, self.user_no_roles, self.anonymous, ] - header = {'REMOTE_ADDR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(url, bad_users, 302, redirect_anon=reverse('home')) - def test_project_details_ip_allowing_remote_addr_allow_network(self): - """Test target site IP allow list with REMOTE_ADDR and allowed network""" - self.setup_ip_allowing(['192.168.1.0/24']) + def test_get_role_delete(self): + """Test RoleAssignmentDeleteView GET""" url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + 'projectroles:role_delete', + kwargs={'roleassignment': self.contributor_as.sodar_uuid}, ) - good_users = [ - self.superuser, + bad_users = [ self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, + self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, - ] - bad_users = [ - self.user_finder_cat, self.user_no_roles, self.anonymous, ] - header = {'REMOTE_ADDR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(url, bad_users, 302, redirect_anon=reverse('home')) - def test_project_details_ip_remote_addr_not_in_list_ip(self): - """Test target site IP allow list with REMOTE_ADDR and IP not in list""" - self.setup_ip_allowing(['192.168.1.2']) + def test_get_role_delete_delegate(self): + """Test RoleAssignmentDeleteView GET for delegate role""" url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + 'projectroles:role_delete', + kwargs={'roleassignment': self.delegate_as.sodar_uuid}, ) - good_users = [ + bad_users = [ + self.anonymous, self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_owner, - self.user_delegate, - ] - bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, + self.user_owner, + self.user_delegate, self.user_contributor, self.user_guest, self.user_no_roles, - self.anonymous, ] - header = {'REMOTE_ADDR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) + self.assert_response(url, bad_users, 302, redirect_anon=reverse('home')) - def test_project_details_ip_remote_addr_not_in_list_network(self): - """Test target site IP allow list with REMOTE_ADDR and network not in list""" - self.setup_ip_allowing(['192.168.2.0/24']) + def test_get_project_invite_create(self): + """Test ProjectInviteCreateView GET""" url = reverse( - 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} + 'projectroles:invite_create', + kwargs={'project': self.project.sodar_uuid}, ) - good_users = [ + bad_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_owner, - self.user_delegate, - ] - bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, - self.user_contributor, - self.user_guest, - self.anonymous, - ] - header = {'REMOTE_ADDR': '192.168.1.1'} - self.assert_response(url, good_users, 200, header=header) - self.assert_response(url, bad_users, 302, header=header) - - def test_update(self): - """Test project update permissions as target""" - url = reverse( - 'projectroles:update', kwargs={'project': self.project.sodar_uuid} - ) - good_users = [ - self.superuser, - self.user_owner_cat, - self.user_delegate_cat, self.user_owner, self.user_delegate, - ] - bad_users = [ - self.user_contributor_cat, - self.user_guest_cat, - self.user_finder_cat, self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) self.assert_response(url, bad_users, 302, redirect_anon=reverse('home')) - def test_create_top_allowed(self): - """Test top project create permissions as target""" - url = reverse('projectroles:create') - good_users = [self.superuser] + def test_get_project_invite_list(self): + """Test ProjectInviteListView GET""" + url = reverse( + 'projectroles:invites', kwargs={'project': self.project.sodar_uuid} + ) bad_users = [ + self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, @@ -2054,238 +2151,378 @@ def test_create_top_allowed(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(url, bad_users, 302, redirect_anon=reverse('home')) - # TODO: Add separate tests for local/remote creation - # TODO: Remote creation should fail - def test_create_sub_local(self): - """Test project create permissions as target under local category""" - # Make category local - self.remote_category.delete() + +@override_settings(PROJECTROLES_SITE_MODE=SITE_MODE_TARGET) +class TestRevokedRemoteProjectViews( + RemoteSiteMixin, RemoteProjectMixin, TestProjectPermissionBase +): + """ + Tests for UI view permissions with revoked remote project on target site. + """ + + def setUp(self): + super().setUp() + self.site = self.make_site( + name=REMOTE_SITE_NAME, + url=REMOTE_SITE_URL, + mode=SODAR_CONSTANTS['SITE_MODE_SOURCE'], + description='', + secret=REMOTE_SITE_SECRET, + ) + self.remote_category = self.make_remote_project( + project_uuid=self.category.sodar_uuid, + project=self.category, + site=self.site, + level=SODAR_CONSTANTS['REMOTE_LEVEL_READ_INFO'], + ) + self.remote_project = self.make_remote_project( + project_uuid=self.project.sodar_uuid, + project=self.project, + site=self.site, + level=SODAR_CONSTANTS['REMOTE_LEVEL_REVOKED'], + ) + + def test_get_project_detail(self): + """Test ProjectDetailView GET""" url = reverse( - 'projectroles:create', kwargs={'project': self.category.sodar_uuid} + 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} ) good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, - self.user_contributor_cat, + self.user_owner, + self.user_delegate, ] bad_users = [ - self.anonymous, + self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, - self.user_owner, - self.user_delegate, self.user_contributor, self.user_guest, self.user_no_roles, + self.anonymous, ] self.assert_response(url, good_users, 200) self.assert_response(url, bad_users, 302) - def test_create_sub_remote(self): - """Test project create permissions as target under local category""" + def test_get_project_roles(self): + """Test ProjectRoleView GET""" url = reverse( - 'projectroles:create', kwargs={'project': self.category.sodar_uuid} + 'projectroles:roles', kwargs={'project': self.project.sodar_uuid} ) - bad_users = [ + good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, - self.user_owner, - self.user_delegate, self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] + self.assert_response(url, good_users, 200) self.assert_response(url, bad_users, 302) - @override_settings(PROJECTROLES_TARGET_CREATE=False) - def test_create_sub_disallowed(self): - """Test project create permissions with creation disallowed as target""" - url = reverse( - 'projectroles:create', kwargs={'project': self.category.sodar_uuid} + +class TestIPAllowing(IPAllowMixin, TestProjectPermissionBase): + """Tests for IP allow list permissions with ProjectDetailView""" + + def setUp(self): + super().setUp() + self.url = reverse( + 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} ) - bad_users = [ + + def test_get_http_x_forwarded_for_block_all(self): + """Test GET with HTTP_X_FORWARDED_FOR and block all""" + self.setup_ip_allowing([]) + good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + self.anonymous, + ] + header = {'HTTP_X_FORWARDED_FOR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 302, header=header) + + def test_get_x_forwarded_for_block_all(self): + """Test GET with X_FORWARDED_FOR and block all""" + self.setup_ip_allowing([]) + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, self.user_owner, self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - self.assert_response(url, bad_users, 302) + header = {'X_FORWARDED_FOR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 302, header=header) - def test_role_create(self): - """Test role create permissions as target""" - url = reverse( - 'projectroles:role_create', - kwargs={'project': self.project.sodar_uuid}, - ) - bad_users = [ + def test_get_forwarded_block_all(self): + """Test GET with FORWARDED and block all""" + self.setup_ip_allowing([]) + good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + self.anonymous, + ] + header = {'FORWARDED': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 302, header=header) + + def test_get_remote_addr_block_all(self): + """Test GET with REMOTE_ADDR fwd and block all""" + self.setup_ip_allowing([]) + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, self.user_owner, self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - self.assert_response(url, bad_users, 302, redirect_anon=reverse('home')) + header = {'REMOTE_ADDR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 302, header=header) - def test_role_update(self): - """Test role update permissions as target""" - url = reverse( - 'projectroles:role_update', - kwargs={'roleassignment': self.contributor_as.sodar_uuid}, - ) - bad_users = [ + def test_get_http_x_forwarded_for_allow_ip(self): + """Test GET with HTTP_X_FORWARDED_FOR and allowed IP""" + self.setup_ip_allowing(['192.168.1.1']) + good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, - self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, + ] + bad_users = [ + self.user_finder_cat, self.user_no_roles, self.anonymous, ] - self.assert_response(url, bad_users, 302, redirect_anon=reverse('home')) + header = {'HTTP_X_FORWARDED_FOR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 200, header=header) - def test_role_delete(self): - """Test role delete permissions as target""" - url = reverse( - 'projectroles:role_delete', - kwargs={'roleassignment': self.contributor_as.sodar_uuid}, - ) - bad_users = [ + def test_get_x_forwarded_for_allow_ip(self): + """Test GET with X_FORWARDED_FOR and allowed IP""" + self.setup_ip_allowing(['192.168.1.1']) + good_users = [ + self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, - self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, + ] + bad_users = [ + self.user_finder_cat, self.user_no_roles, self.anonymous, ] - self.assert_response(url, bad_users, 302, redirect_anon=reverse('home')) + header = {'X_FORWARDED_FOR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 200, header=header) - def test_role_update_delegate(self): - """Test delegate role update permissions as target""" - url = reverse( - 'projectroles:role_update', - kwargs={'roleassignment': self.delegate_as.sodar_uuid}, - ) - bad_users = [ + def test_get_forwarded_allow_ip(self): + """Test GET with FORWARDED and allowed IP""" + self.setup_ip_allowing(['192.168.1.1']) + good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, - self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, + ] + bad_users = [ + self.user_finder_cat, self.user_no_roles, self.anonymous, ] - self.assert_response(url, bad_users, 302, redirect_anon=reverse('home')) + header = {'FORWARDED': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 200, header=header) - def test_role_delete_delegate(self): - """Test role delete permissions for delegate as target""" - url = reverse( - 'projectroles:role_delete', - kwargs={'roleassignment': self.delegate_as.sodar_uuid}, - ) - bad_users = [ - self.anonymous, + def test_get_remote_addr_allow_ip(self): + """Test GET with REMOTE_ADDR and allowed IP""" + self.setup_ip_allowing(['192.168.1.1']) + good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, - self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, + ] + bad_users = [ + self.user_finder_cat, self.user_no_roles, + self.anonymous, ] - self.assert_response(url, bad_users, 302, redirect_anon=reverse('home')) + header = {'REMOTE_ADDR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 200, header=header) - def test_role_invite_create(self): - """Test invite create permissions as target""" - url = reverse( - 'projectroles:invite_create', - kwargs={'project': self.project.sodar_uuid}, - ) - bad_users = [ + def test_get_remote_addr_allow_network(self): + """Test GET with REMOTE_ADDR and allowed network""" + self.setup_ip_allowing(['192.168.1.0/24']) + good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, - self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, + ] + bad_users = [ + self.user_finder_cat, self.user_no_roles, self.anonymous, ] - self.assert_response(url, bad_users, 302, redirect_anon=reverse('home')) + header = {'REMOTE_ADDR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 200, header=header) - def test_role_invite_list(self): - """Test invite list permissions as target""" - url = reverse( - 'projectroles:invites', kwargs={'project': self.project.sodar_uuid} - ) - bad_users = [ + def test_get_remote_addr_not_in_list_ip(self): + """Test GET with REMOTE_ADDR and IP not in list""" + self.setup_ip_allowing(['192.168.1.2']) + good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + self.anonymous, + ] + header = {'REMOTE_ADDR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 302, header=header) + + def test_get_remote_addr_not_in_list_network(self): + """Test GET with REMOTE_ADDR and network not in list""" + self.setup_ip_allowing(['192.168.2.0/24']) + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, self.user_owner, self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, self.user_contributor, self.user_guest, self.user_no_roles, self.anonymous, ] - self.assert_response(url, bad_users, 302, redirect_anon=reverse('home')) + header = {'REMOTE_ADDR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 302, header=header) @override_settings(PROJECTROLES_SITE_MODE=SITE_MODE_TARGET) -class TestRevokedRemoteProject( - RemoteSiteMixin, RemoteProjectMixin, TestProjectPermissionBase +class TestIPAllowingTargetSite( + IPAllowMixin, RemoteSiteMixin, RemoteProjectMixin, TestProjectPermissionBase ): - """Tests for views for a revoked project on a TARGET site""" + """Tests for IP allow list permissions on target site""" def setUp(self): super().setUp() @@ -2302,20 +2539,21 @@ def setUp(self): project_uuid=self.category.sodar_uuid, project=self.category, site=self.site, - level=SODAR_CONSTANTS['REMOTE_LEVEL_READ_INFO'], + level=SODAR_CONSTANTS['REMOTE_LEVEL_READ_ROLES'], ) self.remote_project = self.make_remote_project( project_uuid=self.project.sodar_uuid, project=self.project, site=self.site, - level=SODAR_CONSTANTS['REMOTE_LEVEL_REVOKED'], + level=SODAR_CONSTANTS['REMOTE_LEVEL_READ_ROLES'], ) - - def test_project_details(self): - """Test REVOKED project details permissions as target""" - url = reverse( + self.url = reverse( 'projectroles:detail', kwargs={'project': self.project.sodar_uuid} ) + + def test_get_http_x_forwarded_for_block_all(self): + """Test GET with X_FORWARDED_FOR and block all""" + self.setup_ip_allowing([]) good_users = [ self.superuser, self.user_owner_cat, @@ -2332,14 +2570,13 @@ def test_project_details(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + header = {'HTTP_X_FORWARDED_FOR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) - def test_role_list(self): - """Test REVOKED project role list permissions as target""" - url = reverse( - 'projectroles:roles', kwargs={'project': self.project.sodar_uuid} - ) + def test_get_x_forwarded_for_block_all(self): + """Test GET with FORWARDED and block all""" + self.setup_ip_allowing([]) good_users = [ self.superuser, self.user_owner_cat, @@ -2356,80 +2593,212 @@ def test_role_list(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + header = {'X_FORWARDED_FOR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) + def test_get_forwarded_block_all(self): + """Test GET with FORWARDED and block all""" + self.setup_ip_allowing([]) + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + self.anonymous, + ] + header = {'FORWARDED': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) -class TestRemoteSiteApp(RemoteSiteMixin, TestSiteAppPermissionBase): - """Tests for remote site management views""" + def test_get_remote_addr_block_all(self): + """Test GET with REMOTE_ADDR fwd and block all""" + self.setup_ip_allowing([]) + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + self.anonymous, + ] + header = {'REMOTE_ADDR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) - def setUp(self): - super().setUp() - # Create site - self.site = self.make_site( - name=REMOTE_SITE_NAME, - url=REMOTE_SITE_URL, - mode=SODAR_CONSTANTS['SITE_MODE_TARGET'], - description='', - secret=REMOTE_SITE_SECRET, - ) + def test_get_http_x_forwarded_for_allow_ip(self): + """Test GET with HTTP_X_FORWARDED_FOR and allowed IP""" + self.setup_ip_allowing(['192.168.1.1']) + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_contributor_cat, + self.user_guest_cat, + self.user_owner, + self.user_delegate, + self.user_contributor, + self.user_guest, + ] + bad_users = [ + self.user_finder_cat, + self.user_no_roles, + self.anonymous, + ] + header = {'HTTP_X_FORWARDED_FOR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) - def test_site_list(self): - """Test remote site list view permissions""" - url = reverse('projectroles:remote_sites') - good_users = [self.superuser] - bad_users = [self.regular_user, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + def test_get_x_forwarded_for_allow_ip(self): + """Test GET with X_FORWARDED_FOR and allowed IP""" + self.setup_ip_allowing(['192.168.1.1']) + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_contributor_cat, + self.user_guest_cat, + self.user_owner, + self.user_delegate, + self.user_contributor, + self.user_guest, + ] + bad_users = [ + self.user_finder_cat, + self.user_no_roles, + self.anonymous, + ] + header = {'X_FORWARDED_FOR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) - def test_site_create(self): - """Test remote site create view permissions""" - url = reverse('projectroles:remote_site_create') - good_users = [self.superuser] - bad_users = [self.regular_user, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + def test_get_allowing_forwarded_allow_ip(self): + """Test GET with FORWARDED and allowed IP""" + self.setup_ip_allowing(['192.168.1.1']) + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_contributor_cat, + self.user_guest_cat, + self.user_owner, + self.user_delegate, + self.user_contributor, + self.user_guest, + ] + bad_users = [ + self.user_finder_cat, + self.user_no_roles, + self.anonymous, + ] + header = {'FORWARDED': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) - def test_site_update(self): - """Test remote site update view permissions""" - url = reverse( - 'projectroles:remote_site_update', - kwargs={'remotesite': self.site.sodar_uuid}, - ) - good_users = [self.superuser] - bad_users = [self.regular_user, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + def test_get_remote_addr_allow_ip(self): + """Test GET with REMOTE_ADDR and allowed IP""" + self.setup_ip_allowing(['192.168.1.1']) + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_contributor_cat, + self.user_guest_cat, + self.user_owner, + self.user_delegate, + self.user_contributor, + self.user_guest, + ] + bad_users = [ + self.user_finder_cat, + self.user_no_roles, + self.anonymous, + ] + header = {'REMOTE_ADDR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) - def test_site_delete(self): - """Test remote site delete view permissions""" - url = reverse( - 'projectroles:remote_site_delete', - kwargs={'remotesite': self.site.sodar_uuid}, - ) - good_users = [self.superuser] - bad_users = [self.regular_user, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + def test_get_allowing_remote_addr_allow_network(self): + """Test GET with REMOTE_ADDR and allowed network""" + self.setup_ip_allowing(['192.168.1.0/24']) + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_contributor_cat, + self.user_guest_cat, + self.user_owner, + self.user_delegate, + self.user_contributor, + self.user_guest, + ] + bad_users = [ + self.user_finder_cat, + self.user_no_roles, + self.anonymous, + ] + header = {'REMOTE_ADDR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) - def test_project_list(self): - """Test remote project list view permissions""" - url = reverse( - 'projectroles:remote_projects', - kwargs={'remotesite': self.site.sodar_uuid}, - ) - good_users = [self.superuser] - bad_users = [self.regular_user, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + def test_get_remote_addr_not_in_list_ip(self): + """Test GET with REMOTE_ADDR and IP not in list""" + self.setup_ip_allowing(['192.168.1.2']) + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + self.anonymous, + ] + header = {'REMOTE_ADDR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) - def test_project_update(self): - """Test remote project update view permissions""" - url = reverse( - 'projectroles:remote_projects_update', - kwargs={'remotesite': self.site.sodar_uuid}, - ) - good_users = [self.superuser] - bad_users = [self.regular_user, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + def test_get_remote_addr_not_in_list_network(self): + """Test GET with REMOTE_ADDR and network not in list""" + self.setup_ip_allowing(['192.168.2.0/24']) + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.anonymous, + ] + header = {'REMOTE_ADDR': '192.168.1.1'} + self.assert_response(self.url, good_users, 200, header=header) + self.assert_response(self.url, bad_users, 302, header=header) diff --git a/projectroles/tests/test_permissions_ajax.py b/projectroles/tests/test_permissions_ajax.py index af141281..3f936301 100644 --- a/projectroles/tests/test_permissions_ajax.py +++ b/projectroles/tests/test_permissions_ajax.py @@ -16,11 +16,11 @@ PROJECT_TYPE_PROJECT = SODAR_CONSTANTS['PROJECT_TYPE_PROJECT'] -class TestProjectViews(TestProjectPermissionBase): - """Permission tests for Project Ajax views""" +class TestProjectListAjaxViews(TestProjectPermissionBase): + """Tests for project list Ajax view permissions""" - def test_project_list_ajax(self): - """Test ProjectListAjaxView permissions""" + def test_get_project_list(self): + """Test ProjectListAjaxView GET""" url = reverse('projectroles:ajax_project_list') good_users = [ self.superuser, @@ -41,15 +41,15 @@ def test_project_list_ajax(self): self.assert_response(url, self.anonymous, 403) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_project_list_ajax_anon(self): - """Test ProjectListAjaxView permissions with anonymous access""" + def test_get_project_list_anon(self): + """Test ProjectListAjaxView GET with anonymous access""" url = reverse('projectroles:ajax_project_list') self.assert_response(url, self.anonymous, 200) self.project.set_public() self.assert_response(url, self.anonymous, 200) - def test_project_list_column_ajax(self): - """Test ProjectListColumnAjaxView permissions""" + def test_get_project_list_column(self): + """Test ProjectListColumnAjaxView GET""" url = reverse('projectroles:ajax_project_list_columns') data = {'projects': [str(self.project.sodar_uuid)]} req_kwargs = {'content_type': 'application/json'} @@ -93,8 +93,8 @@ def test_project_list_column_ajax(self): ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_project_list_column_ajax_anon(self): - """Test ProjectListColumnAjaxView permissions with anonymous access""" + def test_get_project_list_column_anon(self): + """Test ProjectListColumnAjaxView GET with anonymous access""" url = reverse('projectroles:ajax_project_list_columns') data = {'projects': [str(self.project.sodar_uuid)]} req_kwargs = {'content_type': 'application/json'} @@ -108,8 +108,8 @@ def test_project_list_column_ajax_anon(self): req_kwargs=req_kwargs, ) - def test_project_list_role_ajax(self): - """Test ProjectListRoleAjaxView permissions""" + def test_get_project_list_role(self): + """Test ProjectListRoleAjaxView GET""" url = reverse('projectroles:ajax_project_list_roles') data = {'projects': [str(self.project.sodar_uuid)]} req_kwargs = {'content_type': 'application/json'} @@ -153,8 +153,8 @@ def test_project_list_role_ajax(self): ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_project_list_role_ajax_anon(self): - """Test ProjectListRoleAjaxView permissions with anonymous access""" + def test_get_project_list_role_anon(self): + """Test ProjectListRoleAjaxView GET with anonymous access""" url = reverse('projectroles:ajax_project_list_roles') data = {'projects': [str(self.project.sodar_uuid)]} req_kwargs = {'content_type': 'application/json'} @@ -168,12 +168,23 @@ def test_project_list_role_ajax_anon(self): req_kwargs=req_kwargs, ) - def test_starring_ajax(self): - """Test ProjectStarringAjaxView permissions""" - url = reverse( + +class TestProjectStarringAjaxView(TestProjectPermissionBase): + """Tests for ProjectStarringAjaxView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( 'projectroles:ajax_star', kwargs={'project': self.project.sodar_uuid}, ) + self.url_cat = reverse( + 'projectroles:ajax_star', + kwargs={'project': self.category.sodar_uuid}, + ) + + def test_get(self): + """Test ProjectStarringAjaxView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -186,28 +197,19 @@ def test_starring_ajax(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] - self.assert_response(url, good_users, 200, method='POST') - self.assert_response(url, bad_users, 403, method='POST') - # Test public project + self.assert_response(self.url, good_users, 200, method='POST') + self.assert_response(self.url, bad_users, 403, method='POST') self.project.set_public() - self.assert_response(url, self.user_no_roles, 200, method='POST') + self.assert_response(self.url, self.user_no_roles, 200, method='POST') @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_starring_ajax_anon(self): - """Test ProjectStarringAjaxView permissions with anonymous access""" - url = reverse( - 'projectroles:ajax_star', - kwargs={'project': self.project.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, self.anonymous, 401, method='POST') + self.assert_response(self.url, self.anonymous, 401, method='POST') - def test_starring_ajax_category(self): - """Test ProjectStarringAjaxView permissions with category""" - url = reverse( - 'projectroles:ajax_star', - kwargs={'project': self.category.sodar_uuid}, - ) + def test_get_category(self): + """Test GET with category""" good_users = [ self.superuser, self.user_owner_cat, @@ -221,24 +223,25 @@ def test_starring_ajax_category(self): self.user_guest, ] bad_users = [self.user_no_roles, self.anonymous] - self.assert_response(url, good_users, 200, method='POST') - self.assert_response(url, bad_users, 403, method='POST') - # Test public project + self.assert_response(self.url_cat, good_users, 200, method='POST') + self.assert_response(self.url_cat, bad_users, 403, method='POST') self.project.set_public() - self.assert_response(url, self.user_no_roles, 200, method='POST') + self.assert_response( + self.url_cat, self.user_no_roles, 200, method='POST' + ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_starring_ajax_category_anon(self): - """Test ProjectStarringAjaxView permissions with category and anon access""" - url = reverse( - 'projectroles:ajax_star', - kwargs={'project': self.category.sodar_uuid}, - ) + def test_get_category_anon(self): + """Test GET with category and anonymous access""" self.project.set_public() - self.assert_response(url, self.anonymous, 401, method='POST') + self.assert_response(self.url_cat, self.anonymous, 401, method='POST') + + +class TestUserAjaxViews(TestProjectPermissionBase): + """Tests for user Ajax view permissions""" - def test_current_user(self): - """Test CurrentUserRetrieveAjaxView access""" + def test_get_current_user(self): + """Test CurrentUserRetrieveAjaxView GET""" url = reverse('projectroles:ajax_user_current') good_users = [ self.superuser, @@ -258,8 +261,8 @@ def test_current_user(self): self.assert_response(url, bad_users, 403) @override_settings(PROJECTROLES_ALLOW_LOCAL_USERS=True) - def test_user_autocomplete_ajax(self): - """Test UserAutocompleteAjaxView access""" + def test_get_autocomplete_ajax(self): + """Test UserAutocompleteAjaxView GET""" url = reverse('projectroles:ajax_autocomplete_user') good_users = [ self.superuser, diff --git a/projectroles/tests/test_permissions_api.py b/projectroles/tests/test_permissions_api.py index 88c36b1f..01a31122 100644 --- a/projectroles/tests/test_permissions_api.py +++ b/projectroles/tests/test_permissions_api.py @@ -9,7 +9,6 @@ Project, RoleAssignment, ProjectInvite, - AppSetting, SODAR_CONSTANTS, ) from projectroles.tests.test_permissions import TestProjectPermissionBase @@ -124,11 +123,11 @@ class TestCoreProjectAPIPermissionBase( # Tests ------------------------------------------------------------------------ -class TestAPIPermissions(TestCoreProjectAPIPermissionBase): - """Tests for projectroles API view permissions""" +class TestProjectListAPIView(TestCoreProjectAPIPermissionBase): + """Tests for ProjectListAPIView permissions""" - def test_project_list(self): - """Test ProjectListAPIView permissions""" + def test_get(self): + """Test ProjectListAPIView GET""" url = reverse('projectroles:api_project_list') good_users = [ self.superuser, @@ -147,12 +146,19 @@ def test_project_list(self): self.assert_response_api(url, self.anonymous, 401) self.assert_response_api(url, good_users, 200, knox=True) - def test_project_retrieve(self): - """Test ProjectRetrieveAPIView permissions""" - url = reverse( + +class TestProjectRetrieveAPIView(TestCoreProjectAPIPermissionBase): + """Tests for ProjectRetrieveAPIView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( 'projectroles:api_project_retrieve', kwargs={'project': self.project.sodar_uuid}, ) + + def test_get(self): + """Test ProjectRetrieveAPIView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -165,29 +171,54 @@ def test_project_retrieve(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles] - self.assert_response_api(url, good_users, 200) - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) - self.assert_response_api(url, bad_users, 403, knox=True) - # Test public project + self.assert_response_api(self.url, good_users, 200) + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) + self.assert_response_api(self.url, bad_users, 403, knox=True) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 200) + self.assert_response_api(self.url, self.user_no_roles, 200) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_project_retrieve_anon(self): - """Test ProjectRetrieveAPIView permissions with anonymous access""" - url = reverse( - 'projectroles:api_project_retrieve', - kwargs={'project': self.project.sodar_uuid}, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response_api(url, self.anonymous, 200) + self.assert_response_api(self.url, self.anonymous, 200) - def test_project_create_root(self): - """Test ProjectCreateAPIView permissions with no parent""" - url = reverse('projectroles:api_project_create') - post_data = { + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_contributor_cat, + self.user_guest_cat, + self.user_owner, + self.user_delegate, + self.user_contributor, + self.user_guest, + ] + bad_users = [self.user_finder_cat, self.user_no_roles] + self.assert_response_api(self.url, good_users, 200) + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) + self.assert_response_api(self.url, bad_users, 403, knox=True) + self.project.set_public() + self.assert_response_api(self.url, self.user_no_roles, 200) + + +class TestProjectCreateAPIView(TestCoreProjectAPIPermissionBase): + """Tests for ProjectCreateAPIView permissions""" + + def _cleanup(self): + Project.objects.filter(title=NEW_PROJECT_TITLE).delete() + + def setUp(self): + super().setUp() + self.url = reverse('projectroles:api_project_create') + self.post_data = { 'title': NEW_PROJECT_TITLE, 'type': SODAR_CONSTANTS['PROJECT_TYPE_CATEGORY'], 'parent': '', @@ -195,6 +226,17 @@ def test_project_create_root(self): 'readme': 'readme', 'owner': str(self.user_owner.sodar_uuid), } + self.post_data_parent = { + 'title': NEW_PROJECT_TITLE, + 'type': SODAR_CONSTANTS['PROJECT_TYPE_PROJECT'], + 'parent': str(self.category.sodar_uuid), + 'description': 'description', + 'readme': 'readme', + 'owner': str(self.user_owner.sodar_uuid), + } + + def test_post(self): + """Test ProjectCreateAPIView POST""" good_users = [self.superuser] bad_users = [ self.user_owner_cat, @@ -208,79 +250,56 @@ def test_project_create_root(self): self.user_guest, self.user_no_roles, ] - - def _cleanup(): - p = Project.objects.filter(title=NEW_PROJECT_TITLE).first() - if p: - p.delete() - self.assert_response_api( - url, + self.url, good_users, 201, method='POST', - data=post_data, - cleanup_method=_cleanup, + data=self.post_data, + cleanup_method=self._cleanup, ) self.assert_response_api( - url, bad_users, 403, method='POST', data=post_data + self.url, bad_users, 403, method='POST', data=self.post_data ) self.assert_response_api( - url, self.anonymous, 401, method='POST', data=post_data + self.url, self.anonymous, 401, method='POST', data=self.post_data ) - # Test with Knox self.assert_response_api( - url, + self.url, good_users, 201, method='POST', - data=post_data, + data=self.post_data, + cleanup_method=self._cleanup, knox=True, - cleanup_method=_cleanup, ) self.assert_response_api( - url, bad_users, 403, method='POST', data=post_data, knox=True + self.url, + bad_users, + 403, + method='POST', + data=self.post_data, + knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='POST', data=post_data + self.url, + self.user_no_roles, + 403, + method='POST', + data=self.post_data, ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_project_create_root_anon(self): - """Test ProjectCreateAPIView permission with no parent and anon access""" - url = reverse('projectroles:api_project_create') - post_data = { - 'title': NEW_PROJECT_TITLE, - 'type': SODAR_CONSTANTS['PROJECT_TYPE_CATEGORY'], - 'parent': '', - 'description': 'description', - 'readme': 'readme', - 'owner': str(self.user_owner.sodar_uuid), - } + def test_post_anon(self): + """Test POST with anonymous access""" self.project.set_public() self.assert_response_api( - url, self.anonymous, 401, method='POST', data=post_data + self.url, self.anonymous, 401, method='POST', data=self.post_data ) - def test_project_create(self): - """Test ProjectCreateAPIView permissions""" - url = reverse('projectroles:api_project_create') - post_data = { - 'title': NEW_PROJECT_TITLE, - 'type': SODAR_CONSTANTS['PROJECT_TYPE_PROJECT'], - 'parent': str(self.category.sodar_uuid), - 'description': 'description', - 'readme': 'readme', - 'owner': str(self.user_owner.sodar_uuid), - } - - def _cleanup(): - p = Project.objects.filter(title=NEW_PROJECT_TITLE).first() - if p: - p.delete() - + def test_post_parent(self): + """Test POST with parent category""" good_users = [ self.superuser, self.user_owner_cat, @@ -297,62 +316,72 @@ def _cleanup(): self.user_no_roles, ] self.assert_response_api( - url, + self.url, good_users, 201, method='POST', - data=post_data, - cleanup_method=_cleanup, + data=self.post_data_parent, + cleanup_method=self._cleanup, ) self.assert_response_api( - url, bad_users, 403, method='POST', data=post_data + self.url, bad_users, 403, method='POST', data=self.post_data_parent ) self.assert_response_api( - url, self.anonymous, 401, method='POST', data=post_data + self.url, + self.anonymous, + 401, + method='POST', + data=self.post_data_parent, ) - # Test with Knox self.assert_response_api( - url, + self.url, good_users, 201, method='POST', - data=post_data, + data=self.post_data_parent, + cleanup_method=self._cleanup, knox=True, - cleanup_method=_cleanup, ) self.assert_response_api( - url, bad_users, 403, method='POST', data=post_data, knox=True + self.url, + bad_users, + 403, + method='POST', + data=self.post_data_parent, + knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='POST', data=post_data + self.url, + self.user_no_roles, + 403, + method='POST', + data=self.post_data_parent, ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_project_create_anon(self): - """Test ProjectCreateAPIView permissions with anonymous access""" - url = reverse('projectroles:api_project_create') - post_data = { - 'title': NEW_PROJECT_TITLE, - 'type': SODAR_CONSTANTS['PROJECT_TYPE_PROJECT'], - 'parent': str(self.category.sodar_uuid), - 'description': 'description', - 'readme': 'readme', - 'owner': str(self.user_owner.sodar_uuid), - } + def test_post_parent_anon(self): + """Test POST with parent category and anonymous access""" self.project.set_public() self.assert_response_api( - url, self.anonymous, 401, method='POST', data=post_data + self.url, + self.anonymous, + 401, + method='POST', + data=self.post_data_parent, ) - def test_project_update(self): - """Test ProjectUpdateAPIView permissions""" - url = reverse( + +class TestProjectUpdateAPIView(TestCoreProjectAPIPermissionBase): + """Tests for ProjectUpdateAPIView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( 'projectroles:api_project_update', kwargs={'project': self.project.sodar_uuid}, ) - put_data = { + self.put_data = { 'title': NEW_PROJECT_TITLE, 'type': SODAR_CONSTANTS['PROJECT_TYPE_PROJECT'], 'parent': str(self.category.sodar_uuid), @@ -360,6 +389,9 @@ def test_project_update(self): 'readme': 'readme', 'owner': str(self.user_owner.sodar_uuid), } + + def test_put(self): + """Test ProjectUpdateAPIView PUT""" good_users = [ self.superuser, self.user_owner_cat, @@ -376,59 +408,115 @@ def test_project_update(self): self.user_no_roles, ] self.assert_response_api( - url, good_users, 200, method='PUT', data=put_data + self.url, good_users, 200, method='PUT', data=self.put_data ) self.assert_response_api( - url, bad_users, 403, method='PUT', data=put_data + self.url, bad_users, 403, method='PUT', data=self.put_data ) self.assert_response_api( - url, self.anonymous, 401, method='PUT', data=put_data + self.url, self.anonymous, 401, method='PUT', data=self.put_data ) - # Test with Knox self.assert_response_api( - url, good_users, 200, method='PUT', data=put_data, knox=True + self.url, + good_users, + 200, + method='PUT', + data=self.put_data, + knox=True, ) self.assert_response_api( - url, bad_users, 403, method='PUT', data=put_data, knox=True + self.url, + bad_users, + 403, + method='PUT', + data=self.put_data, + knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='PUT', data=put_data + self.url, self.user_no_roles, 403, method='PUT', data=self.put_data ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_project_update_anon(self): - """Test ProjectUpdateAPIView permissions with anonymous access""" - url = reverse( - 'projectroles:api_project_update', - kwargs={'project': self.project.sodar_uuid}, + def test_put_anon(self): + """Test PUT with anonymous access""" + self.project.set_public() + self.assert_response_api( + self.url, self.anonymous, 401, method='PUT', data=self.put_data + ) + + def test_put_archive(self): + """Test PUT with archived project""" + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + ] + self.assert_response_api( + self.url, good_users, 200, method='PUT', data=self.put_data + ) + self.assert_response_api( + self.url, bad_users, 403, method='PUT', data=self.put_data + ) + self.assert_response_api( + self.url, self.anonymous, 401, method='PUT', data=self.put_data + ) + self.assert_response_api( + self.url, + good_users, + 200, + method='PUT', + data=self.put_data, + knox=True, + ) + self.assert_response_api( + self.url, + bad_users, + 403, + method='PUT', + data=self.put_data, + knox=True, ) - put_data = { - 'title': NEW_PROJECT_TITLE, - 'type': SODAR_CONSTANTS['PROJECT_TYPE_PROJECT'], - 'parent': str(self.category.sodar_uuid), - 'description': 'description', - 'readme': 'readme', - 'owner': str(self.user_owner.sodar_uuid), - } self.project.set_public() self.assert_response_api( - url, self.anonymous, 401, method='PUT', data=put_data + self.url, self.user_no_roles, 403, method='PUT', data=self.put_data ) - def test_role_create(self): - """Test RoleAssignmentCreateAPIView permissions""" - # Create user for assignments - assign_user = self.make_user('assign_user') - url = reverse( + +class TestRoleAssignmentCreateAPIView(TestCoreProjectAPIPermissionBase): + """Tests for RoleAssignmentCreateAPIView permissions""" + + def _cleanup(self): + RoleAssignment.objects.filter( + project=self.project, + role__name=SODAR_CONSTANTS['PROJECT_ROLE_CONTRIBUTOR'], + user=self.assign_user, + ).delete() + + def setUp(self): + super().setUp() + self.assign_user = self.make_user('assign_user') + self.url = reverse( 'projectroles:api_role_create', kwargs={'project': self.project.sodar_uuid}, ) - post_data = { + self.post_data = { 'role': SODAR_CONSTANTS['PROJECT_ROLE_CONTRIBUTOR'], - 'user': str(assign_user.sodar_uuid), + 'user': str(self.assign_user.sodar_uuid), } + + def test_post(self): + """Test RoleAssignmentCreateAPIView POST""" good_users = [ self.superuser, self.user_owner_cat, @@ -444,81 +532,57 @@ def test_role_create(self): self.user_guest, self.user_no_roles, ] - - def _cleanup(): - role_as = RoleAssignment.objects.filter( - project=self.project, - role__name=SODAR_CONSTANTS['PROJECT_ROLE_CONTRIBUTOR'], - user=assign_user, - ).first() - if role_as: - role_as.delete() - self.assert_response_api( - url, + self.url, good_users, 201, method='POST', - data=post_data, - cleanup_method=_cleanup, + data=self.post_data, + cleanup_method=self._cleanup, ) self.assert_response_api( - url, bad_users, 403, method='POST', data=post_data + self.url, bad_users, 403, method='POST', data=self.post_data ) self.assert_response_api( - url, self.anonymous, 401, method='POST', data=post_data + self.url, self.anonymous, 401, method='POST', data=self.post_data ) - # Test with Knox self.assert_response_api( - url, + self.url, good_users, 201, method='POST', - data=post_data, + data=self.post_data, knox=True, - cleanup_method=_cleanup, + cleanup_method=self._cleanup, ) self.assert_response_api( - url, bad_users, 403, method='POST', data=post_data, knox=True + self.url, + bad_users, + 403, + method='POST', + data=self.post_data, + knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='POST', data=post_data + self.url, + self.user_no_roles, + 403, + method='POST', + data=self.post_data, ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_role_create_anon(self): - """Test RoleAssignmentCreateAPIView permissions with anonymous access""" - assign_user = self.make_user('assign_user') - url = reverse( - 'projectroles:api_role_create', - kwargs={'project': self.project.sodar_uuid}, - ) - post_data = { - 'role': SODAR_CONSTANTS['PROJECT_ROLE_CONTRIBUTOR'], - 'user': str(assign_user.sodar_uuid), - } + def test_post_anon(self): + """Test POST with anonymous access""" self.project.set_public() self.assert_response_api( - url, self.anonymous, 401, method='POST', data=post_data + self.url, self.anonymous, 401, method='POST', data=self.post_data ) - def test_role_update(self): - """Test RoleAssignmentUpdateAPIView permissions""" - # Create user and assignment - assign_user = self.make_user('assign_user') - update_as = self.make_assignment( - self.project, assign_user, self.role_contributor - ) - url = reverse( - 'projectroles:api_role_update', - kwargs={'roleassignment': update_as.sodar_uuid}, - ) - put_data = { - 'role': self.role_guest.name, - 'user': str(assign_user.sodar_uuid), - } + def test_post_archive(self): + """Test POST with archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, @@ -535,65 +599,66 @@ def test_role_update(self): self.user_no_roles, ] self.assert_response_api( - url, good_users, 200, method='PUT', data=put_data + self.url, + good_users, + 201, + method='POST', + data=self.post_data, + cleanup_method=self._cleanup, ) self.assert_response_api( - url, bad_users, 403, method='PUT', data=put_data + self.url, bad_users, 403, method='POST', data=self.post_data ) self.assert_response_api( - url, self.anonymous, 401, method='PUT', data=put_data + self.url, self.anonymous, 401, method='POST', data=self.post_data ) - # Test with Knox self.assert_response_api( - url, good_users, 200, method='PUT', data=put_data, knox=True + self.url, + good_users, + 201, + method='POST', + data=self.post_data, + knox=True, + cleanup_method=self._cleanup, ) self.assert_response_api( - url, bad_users, 403, method='PUT', data=put_data, knox=True + self.url, + bad_users, + 403, + method='POST', + data=self.post_data, + knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='PUT', data=put_data + self.url, + self.user_no_roles, + 403, + method='POST', + data=self.post_data, ) - @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_role_update_anon(self): - """Test RoleAssignmentUpdateAPIView permissions with anonymous access""" - # Create user and assignment - assign_user = self.make_user('assign_user') + +class TestRoleAssignmentUpdateAPIView(TestCoreProjectAPIPermissionBase): + """Tests for RoleAssignmentUpdateAPIView permissions""" + + def setUp(self): + super().setUp() + self.assign_user = self.make_user('assign_user') update_as = self.make_assignment( - self.project, assign_user, self.role_contributor + self.project, self.assign_user, self.role_contributor ) - url = reverse( + self.url = reverse( 'projectroles:api_role_update', kwargs={'roleassignment': update_as.sodar_uuid}, ) - put_data = { + self.put_data = { 'role': self.role_guest.name, - 'user': str(assign_user.sodar_uuid), + 'user': str(self.assign_user.sodar_uuid), } - self.project.set_public() - self.assert_response_api( - url, self.anonymous, 401, method='PUT', data=put_data - ) - def test_role_delete(self): - """Test RoleAssignmentDestroyAPIView permissions""" - # Create user and assignment - assign_user = self.make_user('assign_user') - role_uuid = uuid.uuid4() # Ensure fixed uuid - - def _cleanup(): - update_as = self.make_assignment( - self.project, assign_user, self.role_contributor - ) - update_as.sodar_uuid = role_uuid - update_as.save() - - url = reverse( - 'projectroles:api_role_destroy', - kwargs={'roleassignment': role_uuid}, - ) + def test_put(self): + """Test RoleAssignmentUpdateAPIView PUT""" good_users = [ self.superuser, self.user_owner_cat, @@ -609,146 +674,115 @@ def _cleanup(): self.user_guest, self.user_no_roles, ] - _cleanup() self.assert_response_api( - url, good_users, 204, method='DELETE', cleanup_method=_cleanup + self.url, good_users, 200, method='PUT', data=self.put_data ) - self.assert_response_api(url, bad_users, 403, method='DELETE') - self.assert_response_api(url, self.anonymous, 401, method='DELETE') - # Test with Knox self.assert_response_api( - url, + self.url, bad_users, 403, method='PUT', data=self.put_data + ) + self.assert_response_api( + self.url, self.anonymous, 401, method='PUT', data=self.put_data + ) + self.assert_response_api( + self.url, good_users, - 204, - method='DELETE', - cleanup_method=_cleanup, + 200, + method='PUT', + data=self.put_data, knox=True, ) self.assert_response_api( - url, bad_users, 403, method='DELETE', knox=True + self.url, + bad_users, + 403, + method='PUT', + data=self.put_data, + knox=True, ) - # Test public project self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 403, method='DELETE') + self.assert_response_api( + self.url, self.user_no_roles, 403, method='PUT', data=self.put_data + ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_role_delete_anon(self): - """Test RoleAssignmentDestroyAPIView permissions with anon access""" - # Create user and assignment - assign_user = self.make_user('assign_user') - role_uuid = uuid.uuid4() # Ensure fixed uuid - update_as = self.make_assignment( - self.project, assign_user, self.role_contributor - ) - update_as.sodar_uuid = role_uuid - update_as.save() - url = reverse( - 'projectroles:api_role_destroy', - kwargs={'roleassignment': role_uuid}, - ) + def test_put_anon(self): + """Test PUT with anonymous access""" self.project.set_public() - self.assert_response_api(url, self.anonymous, 401, method='DELETE') - - def test_owner_transfer(self): - """Test RoleAssignmentOwnerTransferAPIView permissions""" - # Create user for assignments - self.new_owner = self.make_user('new_owner') - self.new_owner_as = self.make_assignment( - self.project, self.new_owner, self.role_contributor - ) - url = reverse( - 'projectroles:api_role_owner_transfer', - kwargs={'project': self.project.sodar_uuid}, + self.assert_response_api( + self.url, self.anonymous, 401, method='PUT', data=self.put_data ) - post_data = { - 'new_owner': self.new_owner.username, - 'old_owner_role': SODAR_CONSTANTS['PROJECT_ROLE_CONTRIBUTOR'], - } - - def _cleanup(): - self.new_owner_as.refresh_from_db() - self.new_owner_as.role = self.role_contributor - self.new_owner_as.save() - - self.owner_as.refresh_from_db() - self.owner_as.role = self.role_owner - self.owner_as.save() + def test_put_archive(self): + """Test PUT with archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, + self.user_delegate_cat, self.user_owner, + self.user_delegate, ] bad_users = [ - self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, - self.user_delegate, self.user_contributor, self.user_guest, self.user_no_roles, ] self.assert_response_api( - url, - good_users, - 200, - method='POST', - data=post_data, - cleanup_method=_cleanup, + self.url, good_users, 200, method='PUT', data=self.put_data ) self.assert_response_api( - url, bad_users, 403, method='POST', data=post_data + self.url, bad_users, 403, method='PUT', data=self.put_data ) self.assert_response_api( - url, self.anonymous, 401, method='POST', data=post_data + self.url, self.anonymous, 401, method='PUT', data=self.put_data ) - # Test with Knox self.assert_response_api( - url, + self.url, good_users, 200, - method='POST', - data=post_data, + method='PUT', + data=self.put_data, knox=True, - cleanup_method=_cleanup, ) self.assert_response_api( - url, bad_users, 403, method='POST', data=post_data, knox=True + self.url, + bad_users, + 403, + method='PUT', + data=self.put_data, + knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='POST', data=post_data + self.url, self.user_no_roles, 403, method='PUT', data=self.put_data ) - @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_owner_transfer_anon(self): - """Test RoleAssignmentOwnerTransferAPIView with anon access""" - # Create user for assignments - self.new_owner = self.make_user('new_owner') - self.new_owner_as = self.make_assignment( - self.project, self.new_owner, self.role_contributor - ) - url = reverse( - 'projectroles:api_role_owner_transfer', - kwargs={'project': self.project.sodar_uuid}, - ) - post_data = { - 'new_owner': self.new_owner.username, - 'old_owner_role': SODAR_CONSTANTS['PROJECT_ROLE_CONTRIBUTOR'], - } - self.project.set_public() - self.assert_response_api( - url, self.anonymous, 401, method='POST', data=post_data + +class TestRoleAssignmentDestroyAPIView(TestCoreProjectAPIPermissionBase): + """Tests for RoleAssignmentDestroyAPIView permissions""" + + def _make_as(self): + role_as = self.make_assignment( + self.project, self.assign_user, self.role_contributor ) + role_as.sodar_uuid = self.role_uuid + role_as.save() - def test_invite_list(self): - """Test ProjectInviteListAPIView permissions""" - url = reverse( - 'projectroles:api_invite_list', - kwargs={'project': self.project.sodar_uuid}, + def setUp(self): + super().setUp() + self.assign_user = self.make_user('assign_user') + self.role_uuid = uuid.uuid4() + self._make_as() + self.url = reverse( + 'projectroles:api_role_destroy', + kwargs={'roleassignment': self.role_uuid}, ) + + def test_delete(self): + """Test RoleAssignmentDestroyAPIView DELETE""" good_users = [ self.superuser, self.user_owner_cat, @@ -764,35 +798,317 @@ def test_invite_list(self): self.user_guest, self.user_no_roles, ] - self.assert_response_api(url, good_users, 200) - self.assert_response_api(url, bad_users, 403) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) - # Test public project + self.assert_response_api( + self.url, + good_users, + 204, + method='DELETE', + cleanup_method=self._make_as, + ) + self.assert_response_api(self.url, bad_users, 403, method='DELETE') + self.assert_response_api(self.url, self.anonymous, 401, method='DELETE') + self.assert_response_api( + self.url, + good_users, + 204, + method='DELETE', + cleanup_method=self._make_as, + knox=True, + ) + self.assert_response_api( + self.url, bad_users, 403, method='DELETE', knox=True + ) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 403) + self.assert_response_api( + self.url, self.user_no_roles, 403, method='DELETE' + ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_invite_list_anon(self): - """Test ProjectInviteListAPIView permissions with anonymous access""" - url = reverse( + def test_delete_anon(self): + """Test DELETE with anonymous access""" + self.project.set_public() + self.assert_response_api(self.url, self.anonymous, 401, method='DELETE') + + def test_delete_archive(self): + """Test DELETE with archived project""" + self.project.set_archive() + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + ] + self.assert_response_api( + self.url, + good_users, + 204, + method='DELETE', + cleanup_method=self._make_as, + ) + self.assert_response_api(self.url, bad_users, 403, method='DELETE') + self.assert_response_api(self.url, self.anonymous, 401, method='DELETE') + self.assert_response_api( + self.url, + good_users, + 204, + method='DELETE', + cleanup_method=self._make_as, + knox=True, + ) + self.assert_response_api( + self.url, bad_users, 403, method='DELETE', knox=True + ) + self.project.set_public() + self.assert_response_api( + self.url, self.user_no_roles, 403, method='DELETE' + ) + + +class TestRoleAssignmentOwnerTransferAPIView(TestCoreProjectAPIPermissionBase): + """Tests for RoleAssignmentOwnerTransferAPIView permissions""" + + def _cleanup(self): + self.new_owner_as.refresh_from_db() + self.new_owner_as.role = self.role_contributor + self.new_owner_as.save() + self.owner_as.refresh_from_db() + self.owner_as.role = self.role_owner + self.owner_as.save() + + def setUp(self): + super().setUp() + self.new_owner = self.make_user('new_owner') + self.new_owner_as = self.make_assignment( + self.project, self.new_owner, self.role_contributor + ) + self.url = reverse( + 'projectroles:api_role_owner_transfer', + kwargs={'project': self.project.sodar_uuid}, + ) + self.post_data = { + 'new_owner': self.new_owner.username, + 'old_owner_role': SODAR_CONSTANTS['PROJECT_ROLE_CONTRIBUTOR'], + } + + def test_post(self): + """Test RoleAssignmentOwnerTransferAPIView POST""" + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_owner, + ] + bad_users = [ + self.user_delegate_cat, + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_delegate, + self.user_contributor, + self.user_guest, + self.user_no_roles, + ] + self.assert_response_api( + self.url, + good_users, + 200, + method='POST', + data=self.post_data, + cleanup_method=self._cleanup, + ) + self.assert_response_api( + self.url, bad_users, 403, method='POST', data=self.post_data + ) + self.assert_response_api( + self.url, self.anonymous, 401, method='POST', data=self.post_data + ) + self.assert_response_api( + self.url, + good_users, + 200, + method='POST', + data=self.post_data, + knox=True, + cleanup_method=self._cleanup, + ) + self.assert_response_api( + self.url, + bad_users, + 403, + method='POST', + data=self.post_data, + knox=True, + ) + self.project.set_public() + self.assert_response_api( + self.url, + self.user_no_roles, + 403, + method='POST', + data=self.post_data, + ) + + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_post_anon(self): + """Test POST with anonymous access""" + self.project.set_public() + self.assert_response_api( + self.url, self.anonymous, 401, method='POST', data=self.post_data + ) + + def test_post_archive(self): + """Test POST with archived project""" + self.project.set_archive() + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_owner, + ] + bad_users = [ + self.user_delegate_cat, + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_delegate, + self.user_contributor, + self.user_guest, + self.user_no_roles, + ] + self.assert_response_api( + self.url, + good_users, + 200, + method='POST', + data=self.post_data, + cleanup_method=self._cleanup, + ) + self.assert_response_api( + self.url, bad_users, 403, method='POST', data=self.post_data + ) + self.assert_response_api( + self.url, self.anonymous, 401, method='POST', data=self.post_data + ) + self.assert_response_api( + self.url, + good_users, + 200, + method='POST', + data=self.post_data, + knox=True, + cleanup_method=self._cleanup, + ) + self.assert_response_api( + self.url, + bad_users, + 403, + method='POST', + data=self.post_data, + knox=True, + ) + self.project.set_public() + self.assert_response_api( + self.url, + self.user_no_roles, + 403, + method='POST', + data=self.post_data, + ) + + +class TestProjectInviteListAPIView(TestCoreProjectAPIPermissionBase): + """Tests for ProjectInviteListAPIView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( 'projectroles:api_invite_list', kwargs={'project': self.project.sodar_uuid}, ) + + def test_get(self): + """Test ProjectInviteListAPIView GET""" + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + ] + self.assert_response_api(self.url, good_users, 200) + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) self.project.set_public() - self.assert_response_api(url, self.anonymous, 401) + self.assert_response_api(self.url, self.user_no_roles, 403) - def test_invite_create(self): - """Test ProjectInviteCreateAPIView permissions""" - email = 'new@example.com' - url = reverse( + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" + self.project.set_public() + self.assert_response_api(self.url, self.anonymous, 401) + + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + ] + self.assert_response_api(self.url, good_users, 200) + self.assert_response_api(self.url, bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) + self.project.set_public() + self.assert_response_api(self.url, self.user_no_roles, 403) + + +class TestProjectInviteCreateAPIView(TestCoreProjectAPIPermissionBase): + """Tests for ProjectInviteCreateAPIView permissions""" + + def _cleanup(self): + ProjectInvite.objects.filter(email=self.email).delete() + + def setUp(self): + super().setUp() + self.url = reverse( 'projectroles:api_invite_create', kwargs={'project': self.project.sodar_uuid}, ) - post_data = { - 'email': email, + self.email = 'new@example.com' + self.post_data = { + 'email': self.email, 'role': SODAR_CONSTANTS['PROJECT_ROLE_CONTRIBUTOR'], } + + def test_post(self): + """Test ProjectInviteCreateAPIView POST""" good_users = [ self.superuser, self.user_owner_cat, @@ -808,76 +1124,336 @@ def test_invite_create(self): self.user_guest, self.user_no_roles, ] + self.assert_response_api( + self.url, + good_users, + 201, + method='POST', + data=self.post_data, + cleanup_method=self._cleanup, + ) + self.assert_response_api( + self.url, bad_users, 403, method='POST', data=self.post_data + ) + self.assert_response_api( + self.url, self.anonymous, 401, method='POST', data=self.post_data + ) + self.assert_response_api( + self.url, + good_users, + 201, + method='POST', + data=self.post_data, + knox=True, + cleanup_method=self._cleanup, + ) + self.assert_response_api( + self.url, + bad_users, + 403, + method='POST', + data=self.post_data, + knox=True, + ) + self.project.set_public() + self.assert_response_api( + self.url, + self.user_no_roles, + 403, + method='POST', + data=self.post_data, + ) - def _cleanup(): - invite = ProjectInvite.objects.filter( - email=email, - ).first() - if invite: - invite.delete() + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_post_anon(self): + """Test POST with anonymous access""" + self.project.set_public() + self.assert_response_api( + self.url, self.anonymous, 401, method='POST', data=self.post_data + ) + def test_post_archive(self): + """Test POST with archived project""" + self.project.set_archive() + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + ] self.assert_response_api( - url, + self.url, good_users, 201, method='POST', - data=post_data, - cleanup_method=_cleanup, + data=self.post_data, + cleanup_method=self._cleanup, + ) + self.assert_response_api( + self.url, bad_users, 403, method='POST', data=self.post_data ) self.assert_response_api( - url, bad_users, 403, method='POST', data=post_data + self.url, self.anonymous, 401, method='POST', data=self.post_data ) self.assert_response_api( - url, self.anonymous, 401, method='POST', data=post_data + self.url, + good_users, + 201, + method='POST', + data=self.post_data, + knox=True, + cleanup_method=self._cleanup, + ) + self.assert_response_api( + self.url, + bad_users, + 403, + method='POST', + data=self.post_data, + knox=True, + ) + self.project.set_public() + self.assert_response_api( + self.url, + self.user_no_roles, + 403, + method='POST', + data=self.post_data, + ) + + +class TestProjectInviteRevokeAPIView(TestCoreProjectAPIPermissionBase): + """Tests for ProjectInviteRevokeAPIView( permissions""" + + def _cleanup(self): + self.invite.active = True + self.invite.save() + + def setUp(self): + super().setUp() + self.invite = self.make_invite( + email='new@example.com', + project=self.project, + role=self.role_contributor, + issuer=self.user_owner, + ) + self.url = reverse( + 'projectroles:api_invite_revoke', + kwargs={'projectinvite': self.invite.sodar_uuid}, + ) + + def test_post(self): + """Test ProjectInviteRevokeAPIView POST""" + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + ] + self.assert_response_api( + self.url, + good_users, + 200, + method='POST', + cleanup_method=self._cleanup, ) - # Test with Knox + self.assert_response_api(self.url, bad_users, 403, method='POST') + self.assert_response_api(self.url, self.anonymous, 401, method='POST') + self.assert_response_api( + self.url, + good_users, + 200, + method='POST', + knox=True, + cleanup_method=self._cleanup, + ) + self.assert_response_api( + self.url, bad_users, 403, method='POST', knox=True + ) + self.project.set_public() + self.assert_response_api( + self.url, self.user_no_roles, 403, method='POST' + ) + + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_post_anon(self): + """Test POST with anonymous access""" + self.project.set_public() + self.assert_response_api(self.url, self.anonymous, 401, method='POST') + + def test_post_archive(self): + """Test POST with archived project""" + self.project.set_archive() + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + ] + self.assert_response_api( + self.url, + good_users, + 200, + method='POST', + cleanup_method=self._cleanup, + ) + self.assert_response_api(self.url, bad_users, 403, method='POST') + self.assert_response_api(self.url, self.anonymous, 401, method='POST') + self.assert_response_api( + self.url, + good_users, + 200, + method='POST', + knox=True, + cleanup_method=self._cleanup, + ) + self.assert_response_api( + self.url, bad_users, 403, method='POST', knox=True + ) + self.project.set_public() + self.assert_response_api( + self.url, self.user_no_roles, 403, method='POST' + ) + + +class TestProjectInviteResendAPIView(TestCoreProjectAPIPermissionBase): + """Tests for ProjectInviteResendAPIView permissions""" + + def setUp(self): + super().setUp() + self.invite = self.make_invite( + email='new@example.com', + project=self.project, + role=self.role_contributor, + issuer=self.user_owner, + ) + self.url = reverse( + 'projectroles:api_invite_resend', + kwargs={'projectinvite': self.invite.sodar_uuid}, + ) + + def test_post(self): + """Test ProjectInviteResendAPIView POST""" + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + ] + self.assert_response_api(self.url, good_users, 200, method='POST') + self.assert_response_api(self.url, bad_users, 403, method='POST') + self.assert_response_api(self.url, self.anonymous, 401, method='POST') + self.assert_response_api( + self.url, + good_users, + 200, + method='POST', + knox=True, + ) + self.assert_response_api( + self.url, bad_users, 403, method='POST', knox=True + ) + self.project.set_public() + self.assert_response_api( + self.url, self.user_no_roles, 403, method='POST' + ) + + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_post_anon(self): + """Test POST with anonymous access""" + self.project.set_public() + self.assert_response_api(self.url, self.anonymous, 401, method='POST') + + def test_post_archive(self): + """Test POST with archived project""" + self.project.set_archive() + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + ] + self.assert_response_api(self.url, good_users, 200, method='POST') + self.assert_response_api(self.url, bad_users, 403, method='POST') + self.assert_response_api(self.url, self.anonymous, 401, method='POST') self.assert_response_api( - url, + self.url, good_users, - 201, + 200, method='POST', - data=post_data, knox=True, - cleanup_method=_cleanup, ) self.assert_response_api( - url, bad_users, 403, method='POST', data=post_data, knox=True + self.url, bad_users, 403, method='POST', knox=True ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='POST', data=post_data + self.url, self.user_no_roles, 403, method='POST' ) - @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_invite_create_anon(self): - """Test ProjectInviteCreateAPIView permissions with anonymous access""" - email = 'new@example.com' - url = reverse( - 'projectroles:api_invite_create', + +class TestProjectSettingRetrieveAPIView(TestCoreProjectAPIPermissionBase): + """Tests for ProjectSettingRetrieveAPIView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( + 'projectroles:api_project_setting_retrieve', kwargs={'project': self.project.sodar_uuid}, ) - post_data = { - 'email': email, - 'role': SODAR_CONSTANTS['PROJECT_ROLE_CONTRIBUTOR'], + # GET data for PROJECT setting, others defined within tests + self.get_data = { + 'app_name': 'example_project_app', + 'setting_name': 'project_str_setting', } - self.project.set_public() - self.assert_response_api( - url, self.anonymous, 401, method='POST', data=post_data - ) - def test_invite_revoke(self): - """Test ProjectInviteRevokeAPIView permissions""" - self.invite = self.make_invite( - email='new@example.com', - project=self.project, - role=self.role_contributor, - issuer=self.user_owner, - ) - url = reverse( - 'projectroles:api_invite_revoke', - kwargs={'projectinvite': self.invite.sodar_uuid}, - ) + def test_get_project_setting(self): + """Test ProjectSettingRetrieveAPIView GET with PROJECT scope""" good_users = [ self.superuser, self.user_owner_cat, @@ -893,72 +1469,39 @@ def test_invite_revoke(self): self.user_guest, self.user_no_roles, ] - - def _cleanup(): - self.invite.active = True - self.invite.save() - - self.assert_response_api( - url, - good_users, - 200, - method='POST', - cleanup_method=_cleanup, - ) - self.assert_response_api( - url, - bad_users, - 403, - method='POST', - ) + self.assert_response_api(self.url, good_users, 200, data=self.get_data) + self.assert_response_api(self.url, bad_users, 403, data=self.get_data) self.assert_response_api( - url, - self.anonymous, - 401, - method='POST', + self.url, self.anonymous, 401, data=self.get_data ) - # Test with Knox self.assert_response_api( - url, + self.url, good_users, 200, - method='POST', + data=self.get_data, knox=True, - cleanup_method=_cleanup, ) - self.assert_response_api(url, bad_users, 403, method='POST', knox=True) - # Test public project + self.assert_response_api( + self.url, bad_users, 403, data=self.get_data, knox=True + ) self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 403, method='POST') + self.assert_response_api( + self.url, self.user_no_roles, 403, data=self.get_data + ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_invite_revoke_anon(self): - """Test ProjectInviteRevokeAPIView permissions with anonymous access""" - self.invite = self.make_invite( - email='new@example.com', - project=self.project, - role=self.role_contributor, - issuer=self.user_owner, - ) - url = reverse( - 'projectroles:api_invite_revoke', - kwargs={'projectinvite': self.invite.sodar_uuid}, - ) + def test_get_project_setting_anon(self): + """Test GET with PROJECT scope and anonymous access""" self.project.set_public() - self.assert_response_api(url, self.anonymous, 401, method='POST') - - def test_invite_resend(self): - """Test ProjectInviteResendAPIView permissions with anonymous access""" - self.invite = self.make_invite( - email='new@example.com', - project=self.project, - role=self.role_contributor, - issuer=self.user_owner, - ) - url = reverse( - 'projectroles:api_invite_resend', - kwargs={'projectinvite': self.invite.sodar_uuid}, + self.assert_response_api( + self.url, + [self.user_no_roles, self.anonymous], + 403, + data=self.get_data, ) + + def test_get_project_setting_archive(self): + """Test GET with PROJECT scope and archived project""" good_users = [ self.superuser, self.user_owner_cat, @@ -974,188 +1517,153 @@ def test_invite_resend(self): self.user_guest, self.user_no_roles, ] + self.assert_response_api(self.url, good_users, 200, data=self.get_data) + self.assert_response_api(self.url, bad_users, 403, data=self.get_data) self.assert_response_api( - url, - good_users, - 200, - method='POST', - ) - self.assert_response_api( - url, - bad_users, - 403, - method='POST', - ) - self.assert_response_api( - url, - self.anonymous, - 401, - method='POST', + self.url, self.anonymous, 401, data=self.get_data ) - # Test with Knox self.assert_response_api( - url, + self.url, good_users, 200, - method='POST', + data=self.get_data, knox=True, ) - self.assert_response_api(url, bad_users, 403, method='POST', knox=True) - # Test public project - self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 403, method='POST') - - @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_invite_resend_anon(self): - """Test permissions for ProjectInviteResendAPIView with anonymous access""" - self.invite = self.make_invite( - email='new@example.com', - project=self.project, - role=self.role_contributor, - issuer=self.user_owner, - ) - url = reverse( - 'projectroles:api_invite_resend', - kwargs={'projectinvite': self.invite.sodar_uuid}, + self.assert_response_api( + self.url, bad_users, 403, data=self.get_data, knox=True ) self.project.set_public() - self.assert_response_api(url, self.anonymous, 401, method='POST') - - def test_project_setting_retrieve(self): - """Test ProjectSettingRetrieveAPIView permissions""" - url = reverse( - 'projectroles:api_project_setting_retrieve', - kwargs={'project': self.project.sodar_uuid}, + self.assert_response_api( + self.url, self.user_no_roles, 403, data=self.get_data ) + + def test_get_project_user_setting(self): + """Test GET with PROJECT_USER scope""" get_data = { 'app_name': 'example_project_app', - 'setting_name': 'project_str_setting', + 'setting_name': 'project_user_str_setting', + 'user': str(self.user_owner.sodar_uuid), } good_users = [ self.superuser, - self.user_owner_cat, - self.user_delegate_cat, self.user_owner, - self.user_delegate, ] bad_users = [ + self.user_owner_cat, + self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, + self.user_delegate, self.user_contributor, self.user_guest, self.user_no_roles, ] - - def _cleanup(): - AppSetting.objects.all().delete() - + self.assert_response_api(self.url, good_users, 200, data=get_data) + self.assert_response_api(self.url, bad_users, 403, data=get_data) + self.assert_response_api(self.url, self.anonymous, 401, data=get_data) self.assert_response_api( - url, + self.url, good_users, 200, data=get_data, - cleanup_method=_cleanup, + knox=True, ) - self.assert_response_api(url, bad_users, 403, data=get_data) - self.assert_response_api(url, self.anonymous, 401, data=get_data) - # Test with Knox self.assert_response_api( - url, - good_users, - 200, - data=get_data, - knox=True, - cleanup_method=_cleanup, + self.url, bad_users, 403, data=get_data, knox=True ) - self.assert_response_api(url, bad_users, 403, data=get_data, knox=True) - # Test public project self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 403, data=get_data) + self.assert_response_api( + self.url, self.user_no_roles, 403, data=get_data + ) - def test_project_setting_retrieve_user(self): - """Test ProjectSettingRetrieveAPIView permissions with PROJECT_USER setting""" - url = reverse( - 'projectroles:api_project_setting_retrieve', + +class TestProjectSettingSetAPIView(TestCoreProjectAPIPermissionBase): + """Tests for ProjectSettingSetAPIView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( + 'projectroles:api_project_setting_set', kwargs={'project': self.project.sodar_uuid}, ) - get_data = { + # POST data for PROJECT setting, others defined within tests + self.post_data = { 'app_name': 'example_project_app', - 'setting_name': 'project_user_str_setting', - 'user': str(self.user_owner.sodar_uuid), + 'setting_name': 'project_str_setting', + 'value': 'value', } + + def test_post_project_setting(self): + """Test ProjectSettingSetAPIView POST with PROJECT scope""" good_users = [ self.superuser, + self.user_owner_cat, + self.user_delegate_cat, self.user_owner, + self.user_delegate, ] bad_users = [ - self.user_owner_cat, - self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, - self.user_delegate, self.user_contributor, self.user_guest, self.user_no_roles, ] - - def _cleanup(): - AppSetting.objects.all().delete() - self.assert_response_api( - url, + self.url, good_users, 200, - data=get_data, - cleanup_method=_cleanup, + method='POST', + data=self.post_data, + ) + self.assert_response_api( + self.url, bad_users, 403, method='POST', data=self.post_data + ) + self.assert_response_api( + self.url, self.anonymous, 401, method='POST', data=self.post_data ) - self.assert_response_api(url, bad_users, 403, data=get_data) - self.assert_response_api(url, self.anonymous, 401, data=get_data) - # Test with Knox self.assert_response_api( - url, + self.url, good_users, 200, - data=get_data, + method='POST', + data=self.post_data, + knox=True, + ) + self.assert_response_api( + self.url, + bad_users, + 403, + method='POST', + data=self.post_data, knox=True, - cleanup_method=_cleanup, ) - self.assert_response_api(url, bad_users, 403, data=get_data, knox=True) - # Test public project self.project.set_public() - self.assert_response_api(url, self.user_no_roles, 403, data=get_data) + self.assert_response_api( + self.url, + self.user_no_roles, + 403, + method='POST', + data=self.post_data, + ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_project_setting_retrieve_anon(self): - """Test ProjectSettingRetrieveAPIView permissions with anonymous access""" - url = reverse( - 'projectroles:api_project_setting_retrieve', - kwargs={'project': self.project.sodar_uuid}, - ) - get_data = { - 'app_name': 'example_project_app', - 'setting_name': 'project_str_setting', - } + def test_post_project_setting_anon(self): + """Test POST with PROJECT scope and anonymous access""" self.project.set_public() self.assert_response_api( - url, + self.url, [self.user_no_roles, self.anonymous], 403, - data=get_data, + method='POST', + data=self.post_data, ) - def test_project_setting_set(self): - """Test ProjectSettingSetAPIView permissions""" - url = reverse( - 'projectroles:api_project_setting_set', - kwargs={'project': self.project.sodar_uuid}, - ) - post_data = { - 'app_name': 'example_project_app', - 'setting_name': 'project_str_setting', - 'value': 'value', - } + def test_post_project_setting_archive(self): + """Test POST with PROJECT scope and archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, @@ -1171,49 +1679,46 @@ def test_project_setting_set(self): self.user_guest, self.user_no_roles, ] - - def _cleanup(): - AppSetting.objects.all().delete() - self.assert_response_api( - url, + self.url, good_users, 200, method='POST', - data=post_data, - cleanup_method=_cleanup, + data=self.post_data, ) self.assert_response_api( - url, bad_users, 403, method='POST', data=post_data + self.url, bad_users, 403, method='POST', data=self.post_data ) self.assert_response_api( - url, self.anonymous, 401, method='POST', data=post_data + self.url, self.anonymous, 401, method='POST', data=self.post_data ) - # Test with Knox self.assert_response_api( - url, + self.url, good_users, 200, method='POST', - data=post_data, + data=self.post_data, knox=True, - cleanup_method=_cleanup, ) self.assert_response_api( - url, bad_users, 403, method='POST', data=post_data, knox=True + self.url, + bad_users, + 403, + method='POST', + data=self.post_data, + knox=True, ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='POST', data=post_data + self.url, + self.user_no_roles, + 403, + method='POST', + data=self.post_data, ) - def test_project_setting_set_user(self): - """Test ProjectSettingSetAPIView permissions with PROJECT_USER scope""" - url = reverse( - 'projectroles:api_project_setting_set', - kwargs={'project': self.project.sodar_uuid}, - ) + def test_post_project_user_setting(self): + """Test POST with PROJECT_USER scope""" post_data = { 'app_name': 'example_project_app', 'setting_name': 'project_user_str_setting', @@ -1232,71 +1737,49 @@ def test_project_setting_set_user(self): self.user_guest, self.user_no_roles, ] - - def _cleanup(): - AppSetting.objects.all().delete() - self.assert_response_api( - url, + self.url, good_users, 200, method='POST', data=post_data, - cleanup_method=_cleanup, ) self.assert_response_api( - url, bad_users, 403, method='POST', data=post_data + self.url, bad_users, 403, method='POST', data=post_data ) self.assert_response_api( - url, self.anonymous, 401, method='POST', data=post_data + self.url, self.anonymous, 401, method='POST', data=post_data ) - # Test with Knox self.assert_response_api( - url, + self.url, good_users, 200, method='POST', data=post_data, knox=True, - cleanup_method=_cleanup, ) self.assert_response_api( - url, bad_users, 403, method='POST', data=post_data, knox=True + self.url, bad_users, 403, method='POST', data=post_data, knox=True ) - # Test public project self.project.set_public() self.assert_response_api( - url, self.user_no_roles, 403, method='POST', data=post_data + self.url, self.user_no_roles, 403, method='POST', data=post_data ) - @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_project_setting_set_anon(self): - """Test ProjectSettingSetAPIView permissions with anonymous access""" - url = reverse( - 'projectroles:api_project_setting_set', - kwargs={'project': self.project.sodar_uuid}, - ) - post_data = { - 'app_name': 'example_project_app', - 'setting_name': 'project_str_setting', - 'value': 'value', - } - self.project.set_public() - self.assert_response_api( - url, - [self.user_no_roles, self.anonymous], - 403, - method='POST', - data=post_data, - ) - def test_user_setting_retrieve(self): - """Test UserSettingRetrieveAPIView permissions""" - url = reverse('projectroles:api_user_setting_retrieve') - get_data = { +class TestUserSettingRetrieveAPIView(TestCoreProjectAPIPermissionBase): + """Tests for UserSettingRetrieveAPIView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse('projectroles:api_user_setting_retrieve') + self.get_data = { 'app_name': 'example_project_app', 'setting_name': 'user_str_setting', } + + def test_get_retrieve(self): + """Test UserSettingRetrieveAPIView GET""" good_users = [ self.user_owner_cat, self.user_delegate_cat, @@ -1309,51 +1792,41 @@ def test_user_setting_retrieve(self): self.user_guest, self.user_no_roles, ] - - def _cleanup(): - AppSetting.objects.all().delete() - + self.assert_response_api(self.url, good_users, 200, data=self.get_data) self.assert_response_api( - url, - good_users, - 200, - data=get_data, - cleanup_method=_cleanup, + self.url, self.anonymous, 403, data=self.get_data ) - self.assert_response_api(url, self.anonymous, 403, data=get_data) - # Test with Knox self.assert_response_api( - url, + self.url, good_users, 200, - data=get_data, + data=self.get_data, knox=True, - cleanup_method=_cleanup, ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_user_setting_retrieve_anon(self): - """Test UserSettingRetrieveAPIView permissions with anonymous access""" - url = reverse('projectroles:api_user_setting_retrieve') - get_data = { - 'app_name': 'example_project_app', - 'setting_name': 'user_str_setting', - } + def test_get_anon(self): + """Test GET with anonymous access""" + self.project.set_public() self.assert_response_api( - url, - [self.anonymous], - 403, - data=get_data, + self.url, [self.anonymous], 403, data=self.get_data ) - def test_user_setting_set(self): - """Test UserSettingSetAPIView permissions""" - url = reverse('projectroles:api_user_setting_set') - post_data = { + +class TestUserSettingSetAPIView(TestCoreProjectAPIPermissionBase): + """Tests for UserSettingSetAPIView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse('projectroles:api_user_setting_set') + self.post_data = { 'app_name': 'example_project_app', 'setting_name': 'user_str_setting', 'value': 'value', } + + def test_post(self): + """Test UserSettingSetAPIView POST""" good_users = [ self.user_owner_cat, self.user_delegate_cat, @@ -1366,53 +1839,43 @@ def test_user_setting_set(self): self.user_guest, self.user_no_roles, ] - - def _cleanup(): - AppSetting.objects.all().delete() - self.assert_response_api( - url, - good_users, - 200, - method='POST', - data=post_data, - cleanup_method=_cleanup, + self.url, good_users, 200, method='POST', data=self.post_data ) self.assert_response_api( - url, self.anonymous, 403, method='POST', data=post_data + self.url, self.anonymous, 403, method='POST', data=self.post_data ) - # Test with Knox self.assert_response_api( - url, + self.url, good_users, 200, method='POST', - data=post_data, + data=self.post_data, knox=True, - cleanup_method=_cleanup, ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_user_setting_set_anon(self): - """Test UserSettingSetAPIView permissions with anonymous access""" - url = reverse('projectroles:api_user_setting_set') - post_data = { - 'app_name': 'example_project_app', - 'setting_name': 'user_str_setting', - 'value': 'value', - } + def test_post_anon(self): + """Test POST with anonymous access""" self.project.set_public() self.assert_response_api( - url, + self.url, [self.anonymous], 403, method='POST', - data=post_data, + data=self.post_data, ) - def test_user_list(self): - """Test permissions for UserListAPIView""" - url = reverse('projectroles:api_user_list') + +class TestUserListAPIView(TestCoreProjectAPIPermissionBase): + """Tests for UserSettingSetAPIView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse('projectroles:api_user_list') + + def test_get(self): + """Test UserListAPIView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -1426,13 +1889,25 @@ def test_user_list(self): self.user_guest, self.user_no_roles, ] - self.assert_response_api(url, good_users, 200) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) + self.assert_response_api(self.url, good_users, 200) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) + + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" + self.assert_response_api(self.url, [self.anonymous], 401) - def test_user_current(self): - """Test permissions for CurrentUserRetrieveAPIView""" - url = reverse('projectroles:api_user_current') + +class TestCurrentUserRetrieveAPIView(TestCoreProjectAPIPermissionBase): + """Tests for CurrentUserRetrieveAPIView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse('projectroles:api_user_current') + + def test_get(self): + """Test CurrentUserRetrieveAPIView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -1446,6 +1921,11 @@ def test_user_current(self): self.user_guest, self.user_no_roles, ] - self.assert_response_api(url, good_users, 200) - self.assert_response_api(url, self.anonymous, 401) - self.assert_response_api(url, good_users, 200, knox=True) + self.assert_response_api(self.url, good_users, 200) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, good_users, 200, knox=True) + + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" + self.assert_response_api(self.url, [self.anonymous], 401) diff --git a/siteinfo/tests/test_permissions.py b/siteinfo/tests/test_permissions.py index 9ed8bd16..675b96ef 100644 --- a/siteinfo/tests/test_permissions.py +++ b/siteinfo/tests/test_permissions.py @@ -1,4 +1,4 @@ -"""Permission tests for the siteinfo app""" +"""Tests for UI view permissions in the siteinfo app""" from django.test import override_settings from django.urls import reverse @@ -7,19 +7,21 @@ from projectroles.tests.test_permissions import TestSiteAppPermissionBase -class TestSiteInfoPermissions(TestSiteAppPermissionBase): - """Tests for siteinfo view permissions""" +class TestSiteInfoViewPermissions(TestSiteAppPermissionBase): + """Tests for SiteInfoView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse('siteinfo:info') def test_site_info(self): - """Test site info view""" - url = reverse('siteinfo:info') + """Test SiteInfoView GET""" good_users = [self.superuser] bad_users = [self.anonymous, self.regular_user] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) def test_site_info_anon(self): - """Test site info view with anonymous access""" - url = reverse('siteinfo:info') - self.assert_response(url, self.anonymous, 302) + """Test GET with anonymous access""" + self.assert_response(self.url, self.anonymous, 302) diff --git a/timeline/tests/test_permissions.py b/timeline/tests/test_permissions.py index c025c9b8..5dd83f4f 100644 --- a/timeline/tests/test_permissions.py +++ b/timeline/tests/test_permissions.py @@ -1,4 +1,4 @@ -"""UI view permission tests for the timeline app""" +"""Tests for UI view permissions in the timeline app""" from django.test import override_settings from django.urls import reverse @@ -7,14 +7,17 @@ from projectroles.tests.test_permissions import TestProjectPermissionBase -class TestTimelinePermissions(TestProjectPermissionBase): - """Tests for timeline views""" +class TestProjectTimelineView(TestProjectPermissionBase): + """Tests for ProjectTimelineView permissions""" - def test_project_list(self): - """Test project event list""" - url = reverse( + def setUp(self): + super().setUp() + self.url = reverse( 'timeline:list_project', kwargs={'project': self.project.sodar_uuid} ) + + def test_get(self): + """Test ProjectTimelineView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -27,53 +30,81 @@ def test_project_list(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 200) - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.user_no_roles, 200) + self.assert_response(self.url, self.anonymous, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_project_list_anon(self): - """Test project event list with anonynomus access""" - url = reverse( - 'timeline:list_project', kwargs={'project': self.project.sodar_uuid} - ) + def test_get_anon(self): + """Test GET with anonynomus access""" self.project.set_public() - self.assert_response(url, self.anonymous, 200) + self.assert_response(self.url, self.anonymous, 200) - def test_site_list(self): - """Test site event list""" - url = reverse('timeline:list_site') + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, - self.user_finder_cat, self.user_owner, self.user_delegate, self.user_contributor, self.user_guest, - self.user_no_roles, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, self.anonymous, 302) + bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 200) + self.assert_response(self.url, self.anonymous, 302) - @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_stite_list_anon(self): - """Test site event list with anonynomus access""" - url = reverse('timeline:list_site') - self.assert_response(url, self.anonymous, 302) - - def test_admin_list(self): - """Test admin event list""" - url = reverse('timeline:timeline_site_admin') + +class TestSiteTimelineView(TestProjectPermissionBase): + """Tests for SiteTimelineView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse('timeline:list_site') + + def test_get(self): + """Test SiteTimelineView GET""" good_users = [ self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_owner, + self.user_delegate, + self.user_contributor, + self.user_guest, + self.user_no_roles, ] + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, self.anonymous, 302) + + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonynomus access""" + self.assert_response(self.url, self.anonymous, 302) + + +class TestAdminTimelineView(TestProjectPermissionBase): + """Tests for AdminTimelineView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse('timeline:timeline_site_admin') + + def test_get(self): + """Test AdminTimelineView GET""" + good_users = [self.superuser] bad_users = [ self.user_owner_cat, self.user_delegate_cat, @@ -87,18 +118,21 @@ def test_admin_list(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_admin_list_anon(self): - """Test admin list with anonymous access""" - url = reverse('timeline:timeline_site_admin') - self.assert_response(url, self.anonymous, 302) - - def test_project_event_object_list(self): - """Test project event object list""" - url = reverse( + def test_get_anon(self): + """Test GET with anonymous access""" + self.assert_response(self.url, self.anonymous, 302) + + +class TestProjectObjectTimelineView(TestProjectPermissionBase): + """Tests for ProjectObjectTimelineView permissions""" + + def setUp(self): + super().setUp() + self.url = reverse( 'timeline:list_object', kwargs={ 'project': self.project.sodar_uuid, @@ -106,6 +140,9 @@ def test_project_event_object_list(self): 'object_uuid': self.user_owner.sodar_uuid, }, ) + + def test_get(self): + """Test ProjectObjectTimelineView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -118,36 +155,55 @@ def test_project_event_object_list(self): self.user_guest, ] bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 200) - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.user_no_roles, 200) + self.assert_response(self.url, self.anonymous, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) def test_project_event_object_list_anon(self): - """Test object event list with anonynomus access""" - url = reverse( - 'timeline:list_object', - kwargs={ - 'project': self.project.sodar_uuid, - 'object_model': 'User', - 'object_uuid': self.user_owner.sodar_uuid, - }, - ) + """Test GET with anonynomus access""" + self.project.set_public() + self.assert_response(self.url, self.anonymous, 200) + + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_contributor_cat, + self.user_guest_cat, + self.user_owner, + self.user_delegate, + self.user_contributor, + self.user_guest, + ] + bad_users = [self.user_finder_cat, self.user_no_roles, self.anonymous] + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 302) self.project.set_public() - self.assert_response(url, self.anonymous, 200) + self.assert_response(self.url, self.user_no_roles, 200) + self.assert_response(self.url, self.anonymous, 302) + + +class TestSiteObjectTimelineView(TestProjectPermissionBase): + """Tests for SiteObjectTimelineView permissions""" - def test_site_event_object_list(self): - """Test site event object list""" - url = reverse( + def setUp(self): + super().setUp() + self.url = reverse( 'timeline:list_object_site', kwargs={ 'object_model': 'User', 'object_uuid': self.user_owner.sodar_uuid, }, ) + + def test_get(self): + """Test SiteObjectTimelineView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -161,22 +217,14 @@ def test_site_event_object_list(self): self.user_guest, self.user_no_roles, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, self.anonymous, 302) - # Test public project + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, self.anonymous, 302) self.project.set_public() - self.assert_response(url, self.user_no_roles, 200) - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.user_no_roles, 200) + self.assert_response(self.url, self.anonymous, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_site_event_object_list_anon(self): - """Test site event list with anonymous access""" - url = reverse( - 'timeline:list_object_site', - kwargs={ - 'object_model': 'User', - 'object_uuid': self.user_owner.sodar_uuid, - }, - ) + def test_get_anon(self): + """Test GET with anonymous access""" self.project.set_public() - self.assert_response(url, self.anonymous, 302) + self.assert_response(self.url, self.anonymous, 302) diff --git a/timeline/tests/test_permissions_ajax.py b/timeline/tests/test_permissions_ajax.py index 35219d48..52de8811 100644 --- a/timeline/tests/test_permissions_ajax.py +++ b/timeline/tests/test_permissions_ajax.py @@ -1,4 +1,4 @@ -"""Ajax API view permission tests for the timeline app""" +"""Tests for Ajax view permissions in the timeline app""" from django.test import override_settings from django.urls import reverse @@ -12,37 +12,24 @@ ) -class TestTimelineAjaxPermissions( +class TestProjectEventDetailAjaxView( ProjectEventMixin, ProjectEventStatusMixin, TestProjectPermissionBase ): - """Tests for timeline Ajax API view permissions""" + """Tests for ProjectEventDetailAjaxView permissions""" def setUp(self): super().setUp() self.event = self.make_event( self.project, 'projectroles', self.user_owner, 'project_create' ) - self.event_status = self.make_event_status( - self.event, 'OK', extra_data={'example_data': 'example_extra_data'} - ) - self.site_event = self.make_event( - None, 'projectroles', self.user_owner, 'test_event' - ) - self.site_event_status = self.make_event_status( - self.site_event, - 'OK', - extra_data={'example_data': 'example_extra_data'}, - ) - self.regular_user = self.make_user('regular_user') - - def test_detail_project(self): - """Test ProjectEventDetailAjaxView permissions""" - url = reverse( + self.make_event_status(self.event, 'OK') + self.url = reverse( 'timeline:ajax_detail_project', - kwargs={ - 'projectevent': self.event.sodar_uuid, - }, + kwargs={'projectevent': self.event.sodar_uuid}, ) + + def test_get(self): + """Test ProjectEventDetailAjaxView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -59,30 +46,45 @@ def test_detail_project(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 403) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 403) self.project.set_public() - self.assert_response(url, self.anonymous, 403) + self.assert_response(self.url, self.anonymous, 403) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_detail_project_anon(self): - """Test ProjectEventDetailAjaxView permissions with anonymous access""" - url = reverse( - 'timeline:ajax_detail_project', - kwargs={'projectevent': self.event.sodar_uuid}, - ) - self.assert_response(url, self.anonymous, 403) + def test_get_anon(self): + """Test GET with anonymous access""" + self.project.set_public() + self.assert_response(self.url, self.anonymous, 200) + + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_contributor_cat, + self.user_guest_cat, + self.user_owner, + self.user_delegate, + self.user_contributor, + self.user_guest, + ] + bad_users = [ + self.user_finder_cat, + self.user_no_roles, + self.anonymous, + ] + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 403) self.project.set_public() - self.assert_response(url, self.anonymous, 200) + self.assert_response(self.url, self.anonymous, 403) - def test_detail_project_classified(self): - """Test ProjectEventDetailAjaxView permissions with classified event""" + def test_get_classified(self): + """Test GET with classified event""" self.event.classified = True self.event.save() - url = reverse( - 'timeline:ajax_detail_project', - kwargs={'projectevent': self.event.sodar_uuid}, - ) good_users = [ self.superuser, self.user_owner_cat, @@ -99,78 +101,82 @@ def test_detail_project_classified(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 403) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 403) self.project.set_public() - self.assert_response(url, self.anonymous, 403) + self.assert_response(self.url, self.anonymous, 403) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_detail_project_classified_anon(self): - """Test ProjectEventDetailAjaxView with classified event and anonymous access""" + def test_get_classified_anon(self): + """Test GET with classified event and anonymous access""" self.event.classified = True self.event.save() - url = reverse( - 'timeline:ajax_detail_project', - kwargs={'projectevent': self.event.sodar_uuid}, - ) - self.assert_response(url, self.anonymous, 403) self.project.set_public() - self.assert_response(url, self.anonymous, 403) + self.assert_response(self.url, self.anonymous, 403) - def test_detail_site(self): - """Test SiteEventDetailAjaxView permissions""" - url = reverse( + +class TestSiteEventDetailAjaxView( + ProjectEventMixin, ProjectEventStatusMixin, TestProjectPermissionBase +): + """Tests for SiteEventDetailAjaxView permissions""" + + def setUp(self): + super().setUp() + self.event = self.make_event( + None, 'projectroles', self.user_owner, 'test_event' + ) + self.make_event_status(self.event, 'OK') + self.regular_user = self.make_user('regular_user') + self.url = reverse( 'timeline:ajax_detail_site', - kwargs={'projectevent': self.site_event.sodar_uuid}, + kwargs={'projectevent': self.event.sodar_uuid}, ) - good_users = [ - self.superuser, - self.regular_user, - ] - self.assert_response(url, good_users, 200) - self.assert_response(url, self.anonymous, 403) + + def test_get(self): + """Test SiteEventDetailAjaxView GET""" + good_users = [self.superuser, self.regular_user] + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, self.anonymous, 403) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_detail_site_anon(self): - """Test SiteEventDetailAjaxView permissions with anonymous access""" - url = reverse( - 'timeline:ajax_detail_site', - kwargs={'projectevent': self.site_event.sodar_uuid}, - ) - self.assert_response(url, self.anonymous, 403) + def test_get_anon(self): + """Test GET with anonymous access""" + self.assert_response(self.url, self.anonymous, 403) - def test_detail_site_classified(self): - """Test SiteEventDetailAjaxView permissions with classified event""" + def test_get_classified(self): + """Test GET with classified event""" self.event.classified = True self.event.save() - url = reverse( - 'timeline:ajax_detail_site', - kwargs={'projectevent': self.site_event.sodar_uuid}, - ) - good_users = [ - self.superuser, - self.regular_user, - ] - self.assert_response(url, good_users, 200) - self.assert_response(url, self.anonymous, 403) + bad_users = [self.regular_user, self.anonymous] + self.assert_response(self.url, self.superuser, 200) + self.assert_response(self.url, bad_users, 403) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_detail_site_classified_anon(self): - """Test SiteEventDetailAjaxView permissions with classified event and anonymous access""" + def test_get_classified_anon(self): + """Test GET with classified event and anonymous access""" self.event.classified = True self.event.save() - url = reverse( - 'timeline:ajax_detail_site', - kwargs={'projectevent': self.site_event.sodar_uuid}, - ) - self.assert_response(url, self.anonymous, 403) + self.assert_response(self.url, self.anonymous, 403) + + +class TestProjectEventExtraAjaxView( + ProjectEventMixin, ProjectEventStatusMixin, TestProjectPermissionBase +): + """Tests for ProjectEventExtraAjaxView permissions""" - def test_extra_data_project(self): - """Test ProjectEventExtraDataAjaxView permissions""" - url = reverse( + def setUp(self): + super().setUp() + self.event = self.make_event( + self.project, 'projectroles', self.user_owner, 'project_create' + ) + self.make_event_status(self.event, 'OK') + self.url = reverse( 'timeline:ajax_extra_project', kwargs={'projectevent': self.event.sodar_uuid}, ) + + def test_get(self): + """Test ProjectEventExtraAjaxView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -187,28 +193,45 @@ def test_extra_data_project(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 403) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 403) self.project.set_public() - self.assert_response(url, self.anonymous, 403) + self.assert_response(self.url, self.anonymous, 403) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_extra_data_project_anon(self): + def test_get_anon(self): """Test SiteEventDetailAjaxView permissions with anonymous access""" - url = reverse( - 'timeline:ajax_extra_site', - kwargs={'projectevent': self.site_event.sodar_uuid}, - ) - self.assert_response(url, self.anonymous, 403) + self.project.set_public() + self.assert_response(self.url, self.anonymous, 403) + + def test_get_archive(self): + """Test GET with archived project""" + self.project.set_archive() + good_users = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_owner, + self.user_delegate, + ] + bad_users = [ + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + self.user_contributor, + self.user_guest, + self.user_no_roles, + self.anonymous, + ] + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 403) + self.project.set_public() + self.assert_response(self.url, self.anonymous, 403) - def test_extra_data_project_classified(self): - """Test ProjectEventExtraDataAjaxView with classified event""" + def test_get_classified(self): + """Test GET with classified event""" self.event.classified = True self.event.save() - url = reverse( - 'timeline:ajax_extra_project', - kwargs={'projectevent': self.event.sodar_uuid}, - ) good_users = [ self.superuser, self.user_owner_cat, @@ -225,73 +248,87 @@ def test_extra_data_project_classified(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 403) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 403) self.project.set_public() - self.assert_response(url, self.anonymous, 403) + self.assert_response(self.url, self.anonymous, 403) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_extra_data_project_classified_anon(self): - """Test ProjectEventExtraDataAjaxView with classified event and anonymous access""" + def test_get_classified_anon(self): + """Test GET with classified event and anonymous access""" self.event.classified = True self.event.save() - url = reverse( - 'timeline:ajax_extra_project', - kwargs={'projectevent': self.event.sodar_uuid}, - ) - self.assert_response(url, self.anonymous, 403) self.project.set_public() - self.assert_response(url, self.anonymous, 403) + self.assert_response(self.url, self.anonymous, 403) + - def test_extra_data_site(self): - """Test SiteEventExtraDataAjaxView permissions""" - url = reverse( +class TestSiteEventExtraAjaxView( + ProjectEventMixin, ProjectEventStatusMixin, TestProjectPermissionBase +): + """Tests for SiteEventExtraAjaxView permissions""" + + def setUp(self): + super().setUp() + self.event = self.make_event( + None, + 'projectroles', + self.user_owner, + 'test_event', + extra_data={'example_data': 'example_extra_data'}, + ) + self.event_status = self.make_event_status(self.event, 'OK') + self.regular_user = self.make_user('regular_user') + self.url = reverse( 'timeline:ajax_extra_site', - kwargs={'projectevent': self.site_event.sodar_uuid}, + kwargs={'projectevent': self.event.sodar_uuid}, ) - self.assert_response(url, self.superuser, 200) - self.assert_response(url, self.anonymous, 403) + + def test_get(self): + """Test SiteEventExtraAjaxView GET""" + self.assert_response(self.url, self.superuser, 200) + self.assert_response(self.url, [self.regular_user, self.anonymous], 403) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_extra_data_site_anon(self): - """Test SiteEventDetailAjaxView permissions with anonymous access""" - url = reverse( - 'timeline:ajax_extra_site', - kwargs={'projectevent': self.site_event.sodar_uuid}, - ) - self.assert_response(url, self.anonymous, 403) + def test_get_anon(self): + """Test GET with anonymous access""" + self.assert_response(self.url, self.anonymous, 403) - def test_extra_data_site_classified(self): - """Test SiteEventExtraDataAjaxView permissions with classified event""" + def test_get_classified(self): + """Test GET with classified event""" self.event.classified = True self.event.save() - url = reverse( - 'timeline:ajax_extra_site', - kwargs={'projectevent': self.site_event.sodar_uuid}, - ) - self.assert_response(url, self.superuser, 200) - self.assert_response(url, self.anonymous, 403) + self.assert_response(self.url, self.superuser, 200) + self.assert_response(self.url, [self.regular_user, self.anonymous], 403) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_extra_data_site_classified_anon(self): - """Test SiteEventExtraDataAjaxView with classified event and anonymous access""" + def test_get_classified_anon(self): + """Test GET with classified event and anonymous access""" self.event.classified = True self.event.save() - url = reverse( - 'timeline:ajax_extra_site', - kwargs={'projectevent': self.site_event.sodar_uuid}, - ) - self.assert_response(url, self.superuser, 200) - self.assert_response(url, self.anonymous, 403) + self.assert_response(self.url, self.superuser, 200) + self.assert_response(self.url, [self.regular_user, self.anonymous], 403) + + +class TestEventStatusExtraAjaxViewProject( + ProjectEventMixin, ProjectEventStatusMixin, TestProjectPermissionBase +): + """Tests for EventStatusExtraAjaxView permissions with a project event""" - def test_status_extra_data_project(self): - """Test ProjectEventExtraDataAjaxView permissions""" - url = reverse( + def setUp(self): + super().setUp() + self.event = self.make_event( + self.project, 'projectroles', self.user_owner, 'project_create' + ) + self.event_status = self.make_event_status( + self.event, 'OK', extra_data={'example_data': 'example_extra_data'} + ) + self.url = reverse( 'timeline:ajax_extra_status', - kwargs={ - 'eventstatus': self.event_status.sodar_uuid, - }, + kwargs={'eventstatus': self.event_status.sodar_uuid}, ) + + def test_get(self): + """Test EventStatusExtraAjaxView GET""" good_users = [ self.superuser, self.user_owner_cat, @@ -308,32 +345,21 @@ def test_status_extra_data_project(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 403) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 403) self.project.set_public() - self.assert_response(url, self.anonymous, 403) + self.assert_response(self.url, self.anonymous, 403) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_status_extra_data_project_anon(self): - """Test SiteEventDetailAjaxView permissions with anonymous access""" - url = reverse( - 'timeline:ajax_extra_status', - kwargs={ - 'eventstatus': self.site_event_status.sodar_uuid, - }, - ) - self.assert_response(url, self.anonymous, 403) + def test_get_anon(self): + """Test GET with anonymous access""" + self.project.set_public() + self.assert_response(self.url, self.anonymous, 403) - def test_status_extra_data_project_classified(self): - """Test ProjectEventExtraDataAjaxView with classified event""" + def test_get_classified(self): + """Test GET with classified event""" self.event.classified = True self.event.save() - url = reverse( - 'timeline:ajax_extra_status', - kwargs={ - 'eventstatus': self.event_status.sodar_uuid, - }, - ) good_users = [ self.superuser, self.user_owner_cat, @@ -350,70 +376,63 @@ def test_status_extra_data_project_classified(self): self.user_no_roles, self.anonymous, ] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 403) + self.assert_response(self.url, good_users, 200) + self.assert_response(self.url, bad_users, 403) self.project.set_public() - self.assert_response(url, self.anonymous, 403) + self.assert_response(self.url, self.anonymous, 403) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_status_extra_data_project_classified_anon(self): - """Test ProjectEventExtraDataAjaxView with classified event and anonymous access""" + def test_get_classified_anon(self): + """Test GET with classified event and anonymous access""" self.event.classified = True self.event.save() - url = reverse( - 'timeline:ajax_extra_status', - kwargs={ - 'eventstatus': self.event_status.sodar_uuid, - }, - ) - self.assert_response(url, self.anonymous, 403) self.project.set_public() - self.assert_response(url, self.anonymous, 403) + self.assert_response(self.url, self.anonymous, 403) + - def test_status_extra_data_site(self): - """Test SiteEventExtraDataAjaxView permissions""" - url = reverse( +class TestEventStatusExtraAjaxViewSite( + ProjectEventMixin, ProjectEventStatusMixin, TestProjectPermissionBase +): + """Tests for EventStatusExtraAjaxView permissions with a site event""" + + def setUp(self): + super().setUp() + self.event = self.make_event( + None, 'projectroles', self.user_owner, 'test_event' + ) + self.event_status = self.make_event_status( + self.event, + 'OK', + extra_data={'example_data': 'example_extra_data'}, + ) + self.regular_user = self.make_user('regular_user') + self.url = reverse( 'timeline:ajax_extra_status', kwargs={ - 'eventstatus': self.site_event_status.sodar_uuid, + 'eventstatus': self.event_status.sodar_uuid, }, ) - self.assert_response(url, self.superuser, 200) - self.assert_response(url, self.anonymous, 403) + + def test_get(self): + """Test SiteEventExtraAjaxView GET""" + self.assert_response(self.url, self.superuser, 200) + self.assert_response(self.url, [self.regular_user, self.anonymous], 403) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_status_extra_data_site_anon(self): - """Test SiteEventDetailAjaxView permissions with anonymous access""" - url = reverse( - 'timeline:ajax_extra_status', - kwargs={ - 'eventstatus': self.site_event_status.sodar_uuid, - }, - ) - self.assert_response(url, self.anonymous, 403) + def test_get_anon(self): + """Test GET with anonymous access""" + self.assert_response(self.url, self.anonymous, 403) - def test_status_extra_data_site_classified(self): - """Test SiteEventExtraDataAjaxView permissions with classified event""" + def test_get_classified(self): + """Test GET with classified event""" self.event.classified = True self.event.save() - url = reverse( - 'timeline:ajax_extra_status', - kwargs={ - 'eventstatus': self.site_event_status.sodar_uuid, - }, - ) - self.assert_response(url, self.superuser, 200) - self.assert_response(url, self.anonymous, 403) + self.assert_response(self.url, self.superuser, 200) + self.assert_response(self.url, [self.regular_user, self.anonymous], 403) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_status_extra_data_site_classified_anon(self): - """Test SiteEventExtraDataAjaxView with classified event and anonymous access""" + def test_get_classified_anon(self): + """Test GET with classified event and anonymous access""" self.event.classified = True self.event.save() - url = reverse( - 'timeline:ajax_extra_status', - kwargs={ - 'eventstatus': self.site_event_status.sodar_uuid, - }, - ) - self.assert_response(url, self.anonymous, 403) + self.assert_response(self.url, self.anonymous, 403) diff --git a/timeline/views.py b/timeline/views.py index 3f53d1dc..109dea19 100644 --- a/timeline/views.py +++ b/timeline/views.py @@ -70,10 +70,7 @@ class ProjectTimelineView( class SiteTimelineView( - LoginRequiredMixin, - LoggedInPermissionMixin, - EventTimelineMixin, - ListView, + LoginRequiredMixin, LoggedInPermissionMixin, EventTimelineMixin, ListView ): """View for displaying timeline events for site-wide events""" @@ -83,11 +80,7 @@ class SiteTimelineView( paginate_by = getattr(settings, 'TIMELINE_PAGINATION', DEFAULT_PAGINATION) -class AdminTimelineView( - LoginRequiredMixin, - LoggedInPermissionMixin, - ListView, -): +class AdminTimelineView(LoginRequiredMixin, LoggedInPermissionMixin, ListView): """View for displaying timeline events for admin site view""" def get_context_data(self, *args, **kwargs): diff --git a/tokens/tests/test_permissions.py b/tokens/tests/test_permissions.py index daeebee7..19a1c583 100644 --- a/tokens/tests/test_permissions.py +++ b/tokens/tests/test_permissions.py @@ -1,4 +1,4 @@ -"""Permission tests for the tokens app""" +"""Tests for UI view permissions in the tokens app""" from django.test import override_settings from django.urls import reverse @@ -12,45 +12,35 @@ class TestTokenPermissions(TestSiteAppPermissionBase): """Tests for token view permissions""" - def test_list(self): - """Test permissions for token list""" + def test_get_list(self): + """Test tUserTokenListView GET""" url = reverse('tokens:list') - good_users = [self.superuser, self.regular_user] - bad_users = [self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(url, [self.superuser, self.regular_user], 200) + self.assert_response(url, self.anonymous, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_list_anon(self): - """Test permissions for token list with anonymous access""" + def test_get_list_anon(self): + """Test UserTokenListView GET with anonymous access""" url = reverse('tokens:list') - good_users = [self.superuser, self.regular_user] - bad_users = [self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(url, [self.superuser, self.regular_user], 200) + self.assert_response(url, self.anonymous, 302) - def test_create(self): - """Test permissions for token creation""" + def test_get_create(self): + """Test UserTokenCreateView GET""" url = reverse('tokens:create') - good_users = [self.superuser, self.regular_user] - bad_users = [self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(url, [self.superuser, self.regular_user], 200) + self.assert_response(url, self.anonymous, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_create_anon(self): - """Test permissions for token creation with anonymous access""" + def test_get_create_anon(self): + """Test UserTokenCreateView GET with anonymous access""" url = reverse('tokens:create') - good_users = [self.superuser, self.regular_user] - bad_users = [self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(url, [self.superuser, self.regular_user], 200) + self.assert_response(url, self.anonymous, 302) - def test_delete(self): - """Test permissions for token deletion""" + def test_get_delete(self): + """Test UserTokenDeleteView GET""" token = AuthToken.objects.create(self.regular_user, None) url = reverse('tokens:delete', kwargs={'pk': token[0].pk}) - good_users = [self.regular_user] - bad_users = [self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(url, self.regular_user, 200) + self.assert_response(url, self.anonymous, 302) diff --git a/userprofile/tests/test_permissions.py b/userprofile/tests/test_permissions.py index 586e4570..aadceec4 100644 --- a/userprofile/tests/test_permissions.py +++ b/userprofile/tests/test_permissions.py @@ -1,4 +1,4 @@ -"""Tests for permissions in the userprofile app""" +"""Tests for UI view permissions in the userprofile app""" from django.test import override_settings from django.urls import reverse @@ -10,36 +10,28 @@ class TestUserProfilePermissions(TestSiteAppPermissionBase): """Tests for userprofile view permissions""" - def test_profile(self): - """Test permissions for user profile view""" + def test_get_profile(self): + """Test UserDetailView GET""" url = reverse('userprofile:detail') - good_users = [self.superuser, self.regular_user] - bad_users = [self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(url, [self.superuser, self.regular_user], 200) + self.assert_response(url, self.anonymous, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_profile_anon(self): - """Test permissions for user profile view with anonymous access""" + def test_get_profile_anon(self): + """Test UserDetailView GET with anonymous access""" url = reverse('userprofile:detail') - good_users = [self.superuser, self.regular_user] - bad_users = [self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(url, [self.superuser, self.regular_user], 200) + self.assert_response(url, self.anonymous, 302) - def test_settings_update(self): - """Test permissions for user settings update view""" + def test_get_settings_update(self): + """Test UserSettingUpdateView GET""" url = reverse('userprofile:settings_update') - good_users = [self.superuser, self.regular_user] - bad_users = [self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(url, [self.superuser, self.regular_user], 200) + self.assert_response(url, self.anonymous, 302) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_settings_update_anon(self): - """Test permissions for update view with anonymous access""" + def test_get_settings_update_anon(self): + """Test UserSettingUpdateView GET with anonymous access""" url = reverse('userprofile:settings_update') - good_users = [self.superuser, self.regular_user] - bad_users = [self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 302) + self.assert_response(url, [self.superuser, self.regular_user], 200) + self.assert_response(url, self.anonymous, 302) From 74e96ea137c8bdd787de3d92e730eb4deb40c564 Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Mon, 18 Sep 2023 13:44:15 +0200 Subject: [PATCH 06/10] update ADMINS django setting with env support (#1280) --- CHANGELOG.rst | 1 + config/settings/base.py | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e5eb1774..6e8cf838 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -19,6 +19,7 @@ Changed - **General** - Refactor and cleanup permission tests (#1267) + - Enable setting ``ADMINS`` Django setting via env (#1280) - **Timeline** - Update column width and responsiveness handling (#1721) - View icon display for site views (#1720) diff --git a/config/settings/base.py b/config/settings/base.py index 9a68e69a..cfd2e449 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -137,7 +137,14 @@ # MANAGER CONFIGURATION # ------------------------------------------------------------------------------ -ADMINS = [("""Admin User""", 'admin.user@example.com')] +# Provide ADMINS as: Name:email,Name:email +ADMINS = [ + x.split(':') + for x in env.list( + 'ADMINS', + default=['Admin:admin@example.com', 'Admin2:admin2@example.com'], + ) +] # See: https://docs.djangoproject.com/en/3.2/ref/settings/#managers MANAGERS = ADMINS From 71b1a38ae48407e0c67305e52d8b1fd880026e21 Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Wed, 20 Sep 2023 11:24:02 +0200 Subject: [PATCH 07/10] fix email module crash with empty ADMINS setting (#1287) --- CHANGELOG.rst | 1 + config/settings/base.py | 5 +---- config/settings/test.py | 5 +++++ projectroles/email.py | 14 ++++++++------ projectroles/tests/test_email.py | 13 +++++++++++++ 5 files changed, 28 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6e8cf838..724c1e5d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -30,6 +30,7 @@ Fixed - **Projectroles** - User account update signals not triggered on login (#1274) - Project list rendering failure with finder role (#1276) + - Crash in ``email`` module with empty ``ADMINS`` setting (#1287) - **Timeline** - Ajax view permission test issues (#1267) diff --git a/config/settings/base.py b/config/settings/base.py index cfd2e449..6be4c413 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -140,10 +140,7 @@ # Provide ADMINS as: Name:email,Name:email ADMINS = [ x.split(':') - for x in env.list( - 'ADMINS', - default=['Admin:admin@example.com', 'Admin2:admin2@example.com'], - ) + for x in env.list('ADMINS', default=['Admin User:admin@example.com']) ] # See: https://docs.djangoproject.com/en/3.2/ref/settings/#managers diff --git a/config/settings/test.py b/config/settings/test.py index 47d0e710..26a56b74 100644 --- a/config/settings/test.py +++ b/config/settings/test.py @@ -18,6 +18,11 @@ # Note: This key only used for development and testing. SECRET_KEY = env('DJANGO_SECRET_KEY', default='CHANGEME!!!') +# MANAGER CONFIGURATION +# ------------------------------------------------------------------------------ +ADMINS = [('Admin User', 'admin@example.com')] +MANAGERS = ADMINS + # Mail settings # ------------------------------------------------------------------------------ EMAIL_HOST = 'localhost' diff --git a/projectroles/email.py b/projectroles/email.py index 2ad426c4..69361055 100644 --- a/projectroles/email.py +++ b/projectroles/email.py @@ -23,7 +23,6 @@ EMAIL_SENDER = settings.EMAIL_SENDER DEBUG = settings.DEBUG SITE_TITLE = settings.SITE_INSTANCE_TITLE -ADMIN_RECIPIENT = settings.ADMINS[0] # Local constants EMAIL_RE = re.compile(r'(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)') @@ -285,11 +284,14 @@ def get_email_footer(): custom_footer = getattr(settings, 'PROJECTROLES_EMAIL_FOOTER', None) if custom_footer: return '\n' + custom_footer - return MESSAGE_FOOTER.format( - site_title=SITE_TITLE, - admin_name=ADMIN_RECIPIENT[0], - admin_email=ADMIN_RECIPIENT[1], - ) + admin_recipient = settings.ADMINS[0] if settings.ADMINS else None + if admin_recipient: + return MESSAGE_FOOTER.format( + site_title=SITE_TITLE, + admin_name=admin_recipient[0], + admin_email=admin_recipient[1], + ) + return '' def get_invite_subject(project): diff --git a/projectroles/tests/test_email.py b/projectroles/tests/test_email.py index 76a80636..b819502f 100644 --- a/projectroles/tests/test_email.py +++ b/projectroles/tests/test_email.py @@ -1,5 +1,6 @@ """Tests for email sending in the projectroles Django app""" +from django.conf import settings from django.core import mail from django.test import override_settings from django.urls import reverse @@ -14,6 +15,7 @@ send_project_create_mail, get_email_user, get_user_addr, + get_email_footer, ) from projectroles.tests.test_models import ( ProjectMixin, @@ -326,6 +328,17 @@ def test_generic_mail_multiple(self): self.assertEqual(email_sent, 2) self.assertEqual(len(mail.outbox), 2) + def test_get_email_footer(self): + """Test get_email_footer() with default admin""" + footer = get_email_footer() + self.assertIn(settings.ADMINS[0][0], footer) + self.assertIn(settings.ADMINS[0][1], footer) + + @override_settings(ADMINS=[]) + def test_get_email_footer_no_admin(self): + """Test get_email_footer() with empty admin list""" + self.assertEqual(get_email_footer(), '') + @override_settings(PROJECTROLES_EMAIL_HEADER=CUSTOM_HEADER) def test_custom_header(self): """Test send_generic_mail() with custom header""" From 9ef77d057a80eee3d999953e2d3e28bec5a9fdc0 Mon Sep 17 00:00:00 2001 From: Dzmitry Hramyka Date: Wed, 20 Sep 2023 15:32:07 +0200 Subject: [PATCH 08/10] add sodar-pr-btn-submit-once class and usage (#1233) --- .../templates/filesfolders/file_form.html | 2 +- .../templates/filesfolders/folder_form.html | 2 +- .../filesfolders/hyperlink_form.html | 2 +- .../static/projectroles/js/projectroles.js | 15 ++++++++ .../templates/projectroles/project_form.html | 2 +- .../projectroles/projectinvite_form.html | 2 +- .../projectroles/remotesite_form.html | 2 +- .../projectroles/roleassignment_form.html | 2 +- .../templates/projectroles/user_form.html | 2 +- projectroles/tests/test_ui.py | 35 ++++++++++++++++++- tokens/templates/tokens/token_create.html | 2 +- 11 files changed, 58 insertions(+), 10 deletions(-) diff --git a/filesfolders/templates/filesfolders/file_form.html b/filesfolders/templates/filesfolders/file_form.html index ba595751..da8526dc 100644 --- a/filesfolders/templates/filesfolders/file_form.html +++ b/filesfolders/templates/filesfolders/file_form.html @@ -73,7 +73,7 @@

> Cancel - diff --git a/filesfolders/templates/filesfolders/hyperlink_form.html b/filesfolders/templates/filesfolders/hyperlink_form.html index 980c5286..fae41126 100644 --- a/filesfolders/templates/filesfolders/hyperlink_form.html +++ b/filesfolders/templates/filesfolders/hyperlink_form.html @@ -61,7 +61,7 @@

> Cancel -

diff --git a/projectroles/templates/projectroles/remotesite_form.html b/projectroles/templates/projectroles/remotesite_form.html index 82636da6..4576fde6 100644 --- a/projectroles/templates/projectroles/remotesite_form.html +++ b/projectroles/templates/projectroles/remotesite_form.html @@ -25,7 +25,7 @@

{% if object.pk %}Update{% else %}Add{% endif %} {% if site_mode == 'TARGET' href="{{ request.session.real_referer }}"> Cancel - diff --git a/projectroles/templates/projectroles/roleassignment_form.html b/projectroles/templates/projectroles/roleassignment_form.html index 28988df2..172ab9c2 100644 --- a/projectroles/templates/projectroles/roleassignment_form.html +++ b/projectroles/templates/projectroles/roleassignment_form.html @@ -44,7 +44,7 @@

Add Member

data-toggle="modal" data-target="#sodar-modal"> Preview - diff --git a/projectroles/tests/test_ui.py b/projectroles/tests/test_ui.py index 72f0166c..c262fe58 100644 --- a/projectroles/tests/test_ui.py +++ b/projectroles/tests/test_ui.py @@ -1,6 +1,8 @@ """UI tests for the projectroles app""" import socket +import time + from urllib.parse import urlencode from django.conf import settings @@ -15,7 +17,10 @@ from django.urls import reverse from selenium import webdriver -from selenium.common.exceptions import NoSuchElementException +from selenium.common.exceptions import ( + NoSuchElementException, + StaleElementReferenceException, +) from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as ec from selenium.webdriver.support.ui import WebDriverWait, Select @@ -1688,6 +1693,34 @@ def test_settings_label_icon(self): ).find_element(By.TAG_NAME, 'svg') self.assertTrue(logo.is_displayed()) + def test_submit_button(self): + """Test rendering of submit button""" + url = reverse( + 'projectroles:create', kwargs={'project': self.category.sodar_uuid} + ) + self.login_and_redirect( + self.superuser, url, wait_elem=None, wait_loc='ID' + ) + element = self.selenium.find_element( + By.CLASS_NAME, 'sodar-pr-btn-submit-once' + ) + self.assertEqual(element.text, 'Create') + self.assertTrue(element.is_enabled()) + # Define maximum number of retries and retry interval + max_retries = 50 + retry_interval = 0.2 + element.click() + for i in range(max_retries): + try: + if element.is_enabled() and i < max_retries - 1: + time.sleep(retry_interval) + else: + self.fail( + 'Element did not become enabled within the timeout' + ) + except StaleElementReferenceException: + break + class TestProjectUpdateView(TestUIBase): """Tests for ProjectUpdateView UI""" diff --git a/tokens/templates/tokens/token_create.html b/tokens/templates/tokens/token_create.html index 58a6679b..26f130f9 100644 --- a/tokens/templates/tokens/token_create.html +++ b/tokens/templates/tokens/token_create.html @@ -20,7 +20,7 @@

Create API Token

href="{% url 'tokens:list' %}"> Cancel - From a57f28c8e8e5b0282c327eb406fbccdeb0f17ca6 Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Thu, 21 Sep 2023 15:32:19 +0200 Subject: [PATCH 09/10] add release cleanup issue template (#1289) --- .github/ISSUE_TEMPLATE/release_cleanup.md | 33 +++++++++++++++++++++++ CHANGELOG.rst | 2 ++ 2 files changed, 35 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/release_cleanup.md diff --git a/.github/ISSUE_TEMPLATE/release_cleanup.md b/.github/ISSUE_TEMPLATE/release_cleanup.md new file mode 100644 index 00000000..61b13a3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/release_cleanup.md @@ -0,0 +1,33 @@ +--- +name: Release Cleanup +about: Minor tasks and checklist for maintainer to cleanup and prepare a release +title: 'Cleanup and prepare RELEASE_VERSION' +labels: documentation, internal +assignees: 'mikkonie' + +--- + +## Minor Tasks + +TBA + +## Issues to add to CHANGELOG + +TBA + +## Release Checklist + +- [ ] Review code style and cleanup if needed +- [ ] Review and update doc entries if needed +- [ ] Ensure all relevant updates are in `CHANGELOG` and major changes doc +- [ ] Ensure new version is in `CORE_API_ALLOWED_VERSIONS` +- [ ] Upgrade version number of pypi package references in `README` and docs +- [ ] Upgrade docs config version number (usually at `x.y.z-WIP` when developing) +- [ ] Update latest version info in `codemeta.json` +- [ ] Update version number and date in `CHANGELOG` +- [ ] Update version number and date in `Major Changes` doc +- [ ] Ensure docs can be built without errors + +## Notes + +N/A diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 724c1e5d..22031065 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,8 @@ Unreleased Added ----- +- **General** + - Release cleanup issue template (#1289) - **Projectroles** - ``queryset_project_field`` override in ``APIProjectContextMixin`` (#1273) From 737ef1c9f3a2294b9e8942f3af932b722273edc3 Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Thu, 21 Sep 2023 16:53:59 +0200 Subject: [PATCH 10/10] cleanup and prepare v0.13.2 release (#1275) --- CHANGELOG.rst | 6 ++++-- README.rst | 2 +- bgjobs/templates/bgjobs/_details_card.html | 2 +- codemeta.json | 6 +++--- docs/source/app_projectroles_api_rest.rst | 2 +- docs/source/app_projectroles_integration.rst | 2 +- docs/source/app_projectroles_settings.rst | 2 +- docs/source/conf.py | 2 +- docs/source/dev_project_app.rst | 4 +++- docs/source/dev_resource.rst | 9 +++++++++ docs/source/getting_started.rst | 2 +- docs/source/major_changes.rst | 16 +++++++++++++--- .../templates/filesfolders/_details_card.html | 2 +- .../templates/filesfolders/file_form.html | 2 +- .../templates/filesfolders/folder_form.html | 2 +- .../templates/filesfolders/hyperlink_form.html | 2 +- .../static/projectroles/js/projectroles.js | 2 +- .../templates/projectroles/project_form.html | 2 +- .../projectroles/projectinvite_form.html | 2 +- .../projectroles/remoteproject_update.html | 2 +- .../templates/projectroles/remotesite_form.html | 2 +- .../projectroles/roleassignment_form.html | 2 +- .../templates/projectroles/user_form.html | 2 +- projectroles/templatetags/projectroles_tags.py | 2 +- projectroles/tests/test_ui.py | 2 +- projectroles/views_api.py | 2 +- siteinfo/views.py | 3 ++- tokens/templates/tokens/token_create.html | 2 +- 28 files changed, 56 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 22031065..08d54b68 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,16 +5,18 @@ Changelog for the **SODAR Core** Django app package. Loosely follows the `Keep a Changelog `_ guidelines. -Unreleased -========== +v0.13.2 (2023-09-21) +==================== Added ----- - **General** - Release cleanup issue template (#1289) + - Use ``sodar-btn-submit-once`` in object create forms (#1233) - **Projectroles** - ``queryset_project_field`` override in ``APIProjectContextMixin`` (#1273) + - ``sodar-btn-submit-once`` class for forms (#1233) Changed ------- diff --git a/README.rst b/README.rst index 8dbcbc62..556a5926 100644 --- a/README.rst +++ b/README.rst @@ -115,7 +115,7 @@ and breaking changes are possible. .. code-block:: console - pip install django-sodar-core==0.13.1 + pip install django-sodar-core==0.13.2 For installing a development version you can point your dependency to a specific commit ID in GitHub. Note that these versions may not be stable. diff --git a/bgjobs/templates/bgjobs/_details_card.html b/bgjobs/templates/bgjobs/_details_card.html index 4dfbdced..faf9ecc4 100644 --- a/bgjobs/templates/bgjobs/_details_card.html +++ b/bgjobs/templates/bgjobs/_details_card.html @@ -18,7 +18,7 @@ {% endfor %} {% else %} - No background jobs + No background jobs. {% endif %} diff --git a/codemeta.json b/codemeta.json index 0e7c1972..572ac12b 100644 --- a/codemeta.json +++ b/codemeta.json @@ -40,12 +40,12 @@ ], "identifier": "https://doi.org/10.5281/zenodo.4269346", "codeRepository": "https://github.com/bihealth/sodar-core", - "datePublished": "2023-08-30", - "dateModified": "2023-08-30", + "datePublished": "2023-09-21", + "dateModified": "2023-09-21", "dateCreated": "2019-06-26", "description": "SODAR Core: A Django-based framework for scientific data management and analysis web apps", "keywords": "Python, Django, scientific data managmenent, software library", "license": "MIT", "title": "SODAR Core", - "version": "v0.13.0" + "version": "v0.13.2" } diff --git a/docs/source/app_projectroles_api_rest.rst b/docs/source/app_projectroles_api_rest.rst index 011727fd..36aef4f1 100644 --- a/docs/source/app_projectroles_api_rest.rst +++ b/docs/source/app_projectroles_api_rest.rst @@ -44,7 +44,7 @@ expected version. .. code-block:: console - Accept: application/vnd.bihealth.sodar-core+json; version=0.13.1 + Accept: application/vnd.bihealth.sodar-core+json; version=0.13.2 .. note:: diff --git a/docs/source/app_projectroles_integration.rst b/docs/source/app_projectroles_integration.rst index fb38b438..12fb195f 100644 --- a/docs/source/app_projectroles_integration.rst +++ b/docs/source/app_projectroles_integration.rst @@ -85,7 +85,7 @@ release tag or commit ID. .. code-block:: console - django-sodar-core==0.13.1 + django-sodar-core==0.13.2 Install the requirements for development: diff --git a/docs/source/app_projectroles_settings.rst b/docs/source/app_projectroles_settings.rst index b4517646..ecb300f2 100644 --- a/docs/source/app_projectroles_settings.rst +++ b/docs/source/app_projectroles_settings.rst @@ -246,7 +246,7 @@ The following projectroles settings are **optional**: (list) ``PROJECTROLES_HIDE_APP_LINKS`` **DEPRECATED**, use ``PROJECTROLES_HIDE_PROJECT_APPS`` instead. This will be - emoved in v0.14 + removed in v1.0 ``PROJECTROLES_DELEGATE_LIMIT`` The number of delegate roles allowed per project. The amount is limited to 1 per project if not set, unlimited if set to 0. Will be ignored for remote diff --git a/docs/source/conf.py b/docs/source/conf.py index 8e677798..1664d52d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -29,7 +29,7 @@ # The short X.Y version version = '0.13' # The full version, including alpha/beta/rc tags -release = '0.13.2-WIP' +release = '0.13.2' # -- General configuration --------------------------------------------------- diff --git a/docs/source/dev_project_app.rst b/docs/source/dev_project_app.rst index 38b28d5d..1ba0ddb7 100644 --- a/docs/source/dev_project_app.rst +++ b/docs/source/dev_project_app.rst @@ -192,7 +192,9 @@ member variables and functions as instructed in comments and docstrings. The following variables and functions are **mandatory**: ``name`` - App name. In most cases this should match the app package name. + App name. If only introducing a single plugin in your app, it is recommended + to have this match the app name. Note that the name variables of plugins are + expected to be unique, although not currently strictly enforced. ``title`` Printable app title. ``urls`` diff --git a/docs/source/dev_resource.rst b/docs/source/dev_resource.rst index 0c89e0a5..b750bc4b 100644 --- a/docs/source/dev_resource.rst +++ b/docs/source/dev_resource.rst @@ -141,6 +141,15 @@ Markdown For fields supporting markdown, it is recommended to use the ``SODARPagedownWidget`` found in ``projectroles.models``. +Submit Multi-Click Protection +----------------------------- + +To avoid unwanted effects from a user clicking the submit button on a form +multiple times, it is recommended to use the ``sodar-btn-submit-once`` class on +the submit button in your server-side form templates. Introducing this class +will disable the button after the initial click while the form is submitted. +This is especially recommended for forms responsible for creating objects. + App Settings ============ diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 87fa4bf8..a8157dee 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -17,7 +17,7 @@ the package is under active development and breaking changes are expected. .. code-block:: console - pip install django-sodar-core==0.13.1 + pip install django-sodar-core==0.13.2 Please note that the django-sodar-core package only installs :term:`Django apps`, which you need to include in a diff --git a/docs/source/major_changes.rst b/docs/source/major_changes.rst index 160a2c10..1f0aeb8d 100644 --- a/docs/source/major_changes.rst +++ b/docs/source/major_changes.rst @@ -10,13 +10,14 @@ older SODAR Core version. For a complete list of changes in current and previous releases, see the :ref:`full changelog`. -v0.13.2 (WIP) -************* +v0.13.2 (2023-09-21) +******************** Release Highlights ================== - Add REST API project context queryset field override +- Add sodar-btn-submit-once class for forms with usage - Fix project list view rendering issues with finder role - General bug fixes and minor updates @@ -208,6 +209,15 @@ Advanced search has been updated to use POST requests. This should not require any changes in the plugin search implementation. However, if you have set up view tests for advanced search in your apps, they may have to be updated. +Base Template Content Element Changed +------------------------------------- + +The behaviour of the ``sodar-app-content`` element in the projectroles base +template has changed. The element can now be assigned the +``sodar-app-content-project`` class if a project context is present. If you are +referring to this element in custom Javascript, it is recommended to refer to +the element with the ID ``#sodar-app-content`` instead of the class name. + System Prerequisites -------------------- @@ -225,7 +235,7 @@ PROJECTROLES_HIDE_APP_LINKS Deprecated The ``PROJECTROLES_HIDE_APP_LINKS`` Django setting has been depreacted. Instead, you should use ``PROJECTROLES_HIDE_PROJECT_APPS`` which now handles the same functionality. Support for the ``PROJECTROLES_HIDE_APP_LINKS`` setting will be -removed in v0.14. +removed in v1.0. Deprecated App Settings API Methods Removed ------------------------------------------- diff --git a/filesfolders/templates/filesfolders/_details_card.html b/filesfolders/templates/filesfolders/_details_card.html index 62295bb0..3f5b7ec8 100644 --- a/filesfolders/templates/filesfolders/_details_card.html +++ b/filesfolders/templates/filesfolders/_details_card.html @@ -54,7 +54,7 @@ {% endfor %} {% else %} - No files or links + No files or links. {% endif %} diff --git a/filesfolders/templates/filesfolders/file_form.html b/filesfolders/templates/filesfolders/file_form.html index da8526dc..11a62dd2 100644 --- a/filesfolders/templates/filesfolders/file_form.html +++ b/filesfolders/templates/filesfolders/file_form.html @@ -73,7 +73,7 @@

> Cancel - diff --git a/filesfolders/templates/filesfolders/hyperlink_form.html b/filesfolders/templates/filesfolders/hyperlink_form.html index fae41126..f76a8ed3 100644 --- a/filesfolders/templates/filesfolders/hyperlink_form.html +++ b/filesfolders/templates/filesfolders/hyperlink_form.html @@ -61,7 +61,7 @@

> Cancel - diff --git a/projectroles/templates/projectroles/remoteproject_update.html b/projectroles/templates/projectroles/remoteproject_update.html index 9aa75d42..601ca8e8 100644 --- a/projectroles/templates/projectroles/remoteproject_update.html +++ b/projectroles/templates/projectroles/remoteproject_update.html @@ -69,7 +69,7 @@

Modified Access

-
diff --git a/projectroles/templates/projectroles/remotesite_form.html b/projectroles/templates/projectroles/remotesite_form.html index 4576fde6..7b99f782 100644 --- a/projectroles/templates/projectroles/remotesite_form.html +++ b/projectroles/templates/projectroles/remotesite_form.html @@ -25,7 +25,7 @@

{% if object.pk %}Update{% else %}Add{% endif %} {% if site_mode == 'TARGET' href="{{ request.session.real_referer }}"> Cancel - diff --git a/projectroles/templates/projectroles/roleassignment_form.html b/projectroles/templates/projectroles/roleassignment_form.html index 172ab9c2..9a9a0627 100644 --- a/projectroles/templates/projectroles/roleassignment_form.html +++ b/projectroles/templates/projectroles/roleassignment_form.html @@ -44,7 +44,7 @@

Add Member

data-toggle="modal" data-target="#sodar-modal"> Preview - diff --git a/projectroles/templatetags/projectroles_tags.py b/projectroles/templatetags/projectroles_tags.py index f19b0db3..2166101e 100644 --- a/projectroles/templatetags/projectroles_tags.py +++ b/projectroles/templatetags/projectroles_tags.py @@ -89,7 +89,7 @@ def is_app_visible(plugin, project, user): app_hidden = False if plugin.name in getattr(settings, 'PROJECTROLES_HIDE_PROJECT_APPS', []): app_hidden = True - # TODO: Remove this in SODAR Core v0.14 (see issue #1143) + # TODO: Remove this in SODAR Core v1.0 (see issue #1143) elif plugin.name in getattr(settings, 'PROJECTROLES_HIDE_APP_LINKS', []): app_hidden = True if ( diff --git a/projectroles/tests/test_ui.py b/projectroles/tests/test_ui.py index c262fe58..300cdb14 100644 --- a/projectroles/tests/test_ui.py +++ b/projectroles/tests/test_ui.py @@ -1702,7 +1702,7 @@ def test_submit_button(self): self.superuser, url, wait_elem=None, wait_loc='ID' ) element = self.selenium.find_element( - By.CLASS_NAME, 'sodar-pr-btn-submit-once' + By.CLASS_NAME, 'sodar-btn-submit-once' ) self.assertEqual(element.text, 'Create') self.assertTrue(element.is_enabled()) diff --git a/projectroles/views_api.py b/projectroles/views_api.py index 2b576794..7c4f82c8 100644 --- a/projectroles/views_api.py +++ b/projectroles/views_api.py @@ -98,7 +98,7 @@ CORE_API_DEFAULT_VERSION = re.match( r'^([0-9.]+)(?:[+|\-][\S]+)?$', core_version )[1] -CORE_API_ALLOWED_VERSIONS = ['0.13.0', '0.13.1'] +CORE_API_ALLOWED_VERSIONS = ['0.13.0', '0.13.1', '0.13.2'] # Local constants INVALID_PROJECT_TYPE_MSG = ( diff --git a/siteinfo/views.py b/siteinfo/views.py index 68f3f18e..9ac9f56e 100644 --- a/siteinfo/views.py +++ b/siteinfo/views.py @@ -20,6 +20,7 @@ # Local constants CORE_SETTINGS = [ + 'ADMINS', 'ALLOWED_HOSTS', 'APPS_DIR', 'AUTH_LDAP_SERVER_URI', @@ -54,7 +55,7 @@ 'PROJECTROLES_ENABLE_PROFILING', 'PROJECTROLES_ENABLE_SEARCH', 'PROJECTROLES_HELP_HIGHLIGHT_DAYS', - 'PROJECTROLES_HIDE_APP_LINKS', # TODO: Remove in v0.14 (see issue #1143) + 'PROJECTROLES_HIDE_APP_LINKS', # TODO: Remove in v1.0 (see issue #1143) 'PROJECTROLES_HIDE_PROJECT_APPS', 'PROJECTROLES_INLINE_HEAD_INCLUDE', 'PROJECTROLES_INVITE_EXPIRY_DAYS', diff --git a/tokens/templates/tokens/token_create.html b/tokens/templates/tokens/token_create.html index 26f130f9..ffacfa80 100644 --- a/tokens/templates/tokens/token_create.html +++ b/tokens/templates/tokens/token_create.html @@ -20,7 +20,7 @@

Create API Token

href="{% url 'tokens:list' %}"> Cancel -