diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 17696141..b346d7f1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -19,6 +19,10 @@ Added - App setting ``user_modifiable`` validation (#1536) - ``AppSettingAPI.get_all_by_scope()`` helper (#1534) - ``removeroles`` management command (#1391, #1541) + - Site read only mode (#21) + - ``site_read_only`` site app setting (#21) + - ``is_site_writable()`` rule predicate (#21) + - ``PermissionTestMixin.set_site_read_only()`` helper (#21) Changed ------- diff --git a/docs/source/major_changes.rst b/docs/source/major_changes.rst index bbdf0ec3..77b99a12 100644 --- a/docs/source/major_changes.rst +++ b/docs/source/major_changes.rst @@ -16,6 +16,7 @@ v1.1.0 (WIP) Release Highlights ================== +- Add site read-only mode - Add removeroles management command - Add app setting type constants - Add app setting definition as objects diff --git a/projectroles/app_settings.py b/projectroles/app_settings.py index 17c3100f..a8215900 100644 --- a/projectroles/app_settings.py +++ b/projectroles/app_settings.py @@ -131,6 +131,18 @@ user_modifiable=True, global_edit=True, ), + PluginAppSettingDef( + name='site_read_only', + scope=APP_SETTING_SCOPE_SITE, + type=APP_SETTING_TYPE_BOOLEAN, + default=False, + label='Site read-only mode', + description='Set site in read-only mode. Data altering operations will ' + 'be prohibited. Mode must be explicitly unset to allow data' + 'modification.', + user_modifiable=True, + global_edit=False, + ), ] diff --git a/projectroles/rules.py b/projectroles/rules.py index 37a30fbb..2732246b 100644 --- a/projectroles/rules.py +++ b/projectroles/rules.py @@ -2,8 +2,13 @@ from django.conf import settings +from projectroles.app_settings import AppSettingAPI from projectroles.models import RoleAssignment, SODAR_CONSTANTS + +app_settings = AppSettingAPI() + + # SODAR constants PROJECT_ROLE_OWNER = SODAR_CONSTANTS['PROJECT_ROLE_OWNER'] PROJECT_ROLE_DELEGATE = SODAR_CONSTANTS['PROJECT_ROLE_DELEGATE'] @@ -108,7 +113,9 @@ def has_roles(user): @rules.predicate def is_modifiable_project(user, obj): """Whether or not project metadata is modifiable""" - return False if obj.is_remote() else True + if obj.is_remote() or app_settings.get('projectroles', 'site_read_only'): + return False + return True @rules.predicate @@ -117,16 +124,20 @@ def can_modify_project_data(user, obj): Whether or not project app data can be modified, due to e.g. project archiving status. """ - return not obj.archive + return not obj.archive and not app_settings.get( + 'projectroles', 'site_read_only' + ) @rules.predicate def can_create_projects(user, obj): - """Whether or not new projects can be generated on the site""" + """Whether or not new projects can be created on the site""" if settings.PROJECTROLES_SITE_MODE == SITE_MODE_TARGET and ( not settings.PROJECTROLES_TARGET_CREATE or (obj and obj.is_remote()) ): return False + if app_settings.get('projectroles', 'site_read_only'): + return False return True @@ -154,6 +165,12 @@ def is_target_site(): return settings.PROJECTROLES_SITE_MODE == SITE_MODE_TARGET +@rules.predicate +def is_site_writable(): + """Return True if site has not been set in read-only mode""" + return not app_settings.get('projectroles', 'site_read_only') + + # Combined predicates ---------------------------------------------------------- @@ -186,7 +203,7 @@ def is_target_site(): # Allow project updating rules.add_perm( 'projectroles.update_project', - is_project_update_user, + is_project_update_user & is_site_writable, ) # Allow creation of projects @@ -194,10 +211,13 @@ def is_target_site(): 'projectroles.create_project', is_project_create_user & can_create_projects ) +# Allow viewing PROJECT scope settings +rules.add_perm('projectroles.view_project_settings', is_project_update_user) + # Allow updating project settings rules.add_perm( 'projectroles.update_project_settings', - is_role_update_user & is_modifiable_project, + is_project_update_user & is_modifiable_project, ) # Allow viewing project roles @@ -241,3 +261,9 @@ def is_target_site(): rules.add_perm( 'projectroles.view_hidden_projects', rules.is_superuser | is_project_owner ) + +# Allow starring/unstarring a project +rules.add_perm( + 'projectroles.star_project', + (can_view_project | has_category_child_role) & is_site_writable, +) diff --git a/projectroles/tests/test_permissions.py b/projectroles/tests/test_permissions.py index 31180c1b..5fadcfb8 100644 --- a/projectroles/tests/test_permissions.py +++ b/projectroles/tests/test_permissions.py @@ -8,6 +8,7 @@ from test_plus.test import TestCase +from projectroles.app_settings import AppSettingAPI from projectroles.models import SODAR_CONSTANTS from projectroles.utils import build_secret from projectroles.tests.test_models import ( @@ -21,6 +22,9 @@ ) +app_settings = AppSettingAPI() + + # SODAR constants PROJECT_ROLE_OWNER = SODAR_CONSTANTS['PROJECT_ROLE_OWNER'] PROJECT_ROLE_DELEGATE = SODAR_CONSTANTS['PROJECT_ROLE_DELEGATE'] @@ -44,6 +48,14 @@ class PermissionTestMixin: """Helper class for permission tests""" + def set_site_read_only(self, value=True): + """ + Helper to set site read only mode to the desired value. + + :param value: Boolean + """ + app_settings.set('projectroles', 'site_read_only', value=value) + def send_request(self, url, method, req_kwargs): req_method = getattr(self.client, method.lower(), None) if not req_method: @@ -222,6 +234,27 @@ def setUp(self): self.guest_as = self.make_assignment( self.project, self.user_guest, self.role_guest ) + # User helpers + self.all_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, + ] # All users + # All authenticated users + self.all_auth_users = self.all_users[:-1] + # All users except for superuser + self.non_superusers = self.all_users[1:] + # All authenticated non-superusers + self.auth_non_superusers = self.non_superusers[:-1] class SiteAppPermissionTestBase( @@ -287,6 +320,27 @@ def test_get_home_anon(self): ] self.assert_response(url, good_users, 200) + def test_get_home_read_only(self): + """Test HomeView GET with site read-only mode""" + self.set_site_read_only() + url = reverse('home') + 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, + ] + bad_users = [self.anonymous] + self.assert_response(url, good_users, 200) + self.assert_response(url, bad_users, 302) + def test_get_search(self): """Test ProjectSearchResultsView GET""" url = reverse('projectroles:search') + '?' + urlencode({'s': 'test'}) @@ -327,6 +381,27 @@ def test_get_search_anon(self): ] self.assert_response(url, good_users, 200) + def test_get_search_read_only(self): + """Test ProjectSearchResultsView GET with site read-only mode""" + self.set_site_read_only() + url = reverse('projectroles:search') + '?' + urlencode({'s': 'test'}) + 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, + ] + bad_users = [self.anonymous] + self.assert_response(url, good_users, 200) + self.assert_response(reverse('home'), bad_users, 302) + def test_get_search_advanced(self): """Test ProjectAdvancedSearchView GET""" url = reverse('projectroles:search_advanced') @@ -474,10 +549,7 @@ def setUp(self): self.url_cat = reverse( 'projectroles:detail', kwargs={'project': self.category.sodar_uuid} ) - - def test_get(self): - """Test ProjectDetailView GET""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, @@ -488,91 +560,73 @@ def test_get(self): 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) - # Test public project - self.project.set_public() - self.assert_response(self.url, self.user_no_roles, 200) - - @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_get_anon(self): - """Test GET with anonymous access""" - good_users = [ + self.bad_users = [ + self.user_finder_cat, + self.user_no_roles, + self.anonymous, + ] + self.good_users_cat = [ 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(self.url, good_users, 200) - self.assert_response(self.url, bad_users, 302) + self.bad_users_cat = [self.user_no_roles, self.anonymous] + + def test_get(self): + """Test ProjectDetailView GET""" + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) + # Test public project + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 200) + + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) + def test_get_anon(self): + """Test GET with anonymous access""" + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() - self.assert_response(self.url, bad_users, 200) + self.assert_response(self.url, self.bad_users, 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.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 200) + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) + 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_no_roles, self.anonymous] - self.assert_response(self.url_cat, good_users, 200) - self.assert_response(self.url_cat, bad_users, 302) + self.assert_response(self.url_cat, self.good_users_cat, 200) + self.assert_response(self.url_cat, self.bad_users_cat, 302) self.project.set_public() self.assert_response(self.url_cat, self.user_no_roles, 200) @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) + self.assert_response(self.url_cat, self.good_users_cat, 200) + self.assert_response(self.url_cat, self.bad_users_cat, 302) + + def test_get_category_read_only(self): + """Test GET with category and site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url_cat, self.good_users_cat, 200) + self.assert_response(self.url_cat, self.bad_users_cat, 302) class TestProjectCreateView(ProjectPermissionTestBase): @@ -584,11 +638,8 @@ def setUp(self): 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.good_users_top = [self.superuser] + self.bad_users_top = [ self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, @@ -601,28 +652,13 @@ def test_get_top(self): self.user_no_roles, self.anonymous, ] - 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(self.url_top, self.user_no_roles, 302) - - @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.good_users_sub = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_contributor_cat, ] - bad_users = [ + self.bad_users_sub = [ self.user_guest_cat, self.user_finder_cat, self.user_owner, @@ -632,8 +668,34 @@ def test_get_sub(self): self.user_no_roles, self.anonymous, ] - self.assert_response(self.url_sub, good_users, 200) - self.assert_response(self.url_sub, bad_users, 302) + + def test_get_top(self): + """Test ProjectCreateView GET for top level creation""" + self.assert_response(self.url_top, self.good_users_top, 200) + self.assert_response(self.url_top, self.bad_users_top, 302) + self.project.set_public() + self.assert_response(self.url_top, self.user_no_roles, 302) + + @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_top_read_only(self): + """Test GET for top level with site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url_top, self.good_users_top, 200) + self.assert_response(self.url_top, self.bad_users_top, 302) + self.project.set_public() + self.assert_response(self.url_top, self.user_no_roles, 302) + + def test_get_sub(self): + """Test GET for subproject creation""" + self.assert_response(self.url_sub, self.good_users_sub, 200) + self.assert_response(self.url_sub, self.bad_users_sub, 302) self.project.set_public() self.assert_response(self.url_sub, self.user_no_roles, 302) @@ -645,6 +707,15 @@ def test_get_sub_anon(self): self.url_sub, [self.user_no_roles, self.anonymous], 302 ) + def test_get_sub_read_only(self): + """Test GET for subproject with site read-only mode""" + self.set_site_read_only() + # Only superuser should have access in read-only mode + self.assert_response(self.url_sub, self.superuser, 200) + self.assert_response(self.url_sub, self.non_superusers, 302) + self.project.set_public() + self.assert_response(self.url_sub, self.user_no_roles, 302) + class TestProjectUpdateView(ProjectPermissionTestBase): """Tests for ProjectUpdateView permissions""" @@ -657,17 +728,14 @@ def setUp(self): self.url_cat = reverse( 'projectroles:update', kwargs={'project': self.category.sodar_uuid} ) - - def test_get(self): - """Test ProjectUpdateView GET""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -676,8 +744,26 @@ def test_get(self): self.user_no_roles, self.anonymous, ] - self.assert_response(self.url, good_users, 200) - self.assert_response(self.url, bad_users, 302) + self.good_users_cat = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + ] + self.bad_users_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.anonymous, + ] + + def test_get(self): + """Test ProjectUpdateView GET""" + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) @@ -692,46 +778,21 @@ def test_get_anon(self): 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.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url, self.superuser, 200) + self.assert_response(self.url, self.non_superusers, 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_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.assert_response(self.url_cat, self.good_users_cat, 200) + self.assert_response(self.url_cat, self.bad_users_cat, 302) self.project.set_public() self.assert_response(self.url_cat, self.user_no_roles, 302) @@ -743,6 +804,12 @@ def test_get_category_anon(self): self.url_cat, [self.user_no_roles, self.anonymous], 302 ) + def test_get_category_read_only(self): + """Test GET with category and site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url_cat, self.superuser, 200) + self.assert_response(self.url_cat, self.non_superusers, 302) + class TestProjectArchiveView(ProjectPermissionTestBase): """Tests for ProjectArchiveView permissions""" @@ -755,17 +822,14 @@ def setUp(self): self.url_cat = reverse( 'projectroles:archive', kwargs={'project': self.category.sodar_uuid} ) - - def test_get(self): - """Test ProjectArchiveView GET""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -774,8 +838,11 @@ def test_get(self): self.user_no_roles, self.anonymous, ] - self.assert_response(self.url, good_users, 200) - self.assert_response(self.url, bad_users, 302) + + def test_get(self): + """Test ProjectArchiveView GET""" + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) @@ -788,27 +855,17 @@ def test_get_anon(self): 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.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url, self.superuser, 200) + self.assert_response(self.url, self.non_superusers, 302) + def test_get_category(self): """Test GET with category""" bad_users_cat = [ @@ -862,10 +919,7 @@ def setUp(self): self.url_cat = reverse( 'projectroles:roles', kwargs={'project': self.category.sodar_uuid} ) - - def test_get(self): - """Test ProjectRoleView GET""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, @@ -876,12 +930,35 @@ def test_get(self): 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(self.url, self.user_no_roles, 200) - + self.bad_users = [ + self.user_finder_cat, + self.user_no_roles, + self.anonymous, + ] + self.good_users_cat = [ + self.superuser, + self.user_owner_cat, + self.user_delegate_cat, + self.user_contributor_cat, + self.user_guest_cat, + self.user_finder_cat, + ] + self.bad_users_cat = [ + self.user_owner, + self.user_delegate, + self.user_contributor, + self.user_guest, + self.user_no_roles, + self.anonymous, + ] + + def test_get(self): + """Test ProjectRoleView GET""" + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 200) + @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) def test_get_anon(self): """Test GET with anonymous access""" @@ -893,47 +970,34 @@ def test_get_anon(self): 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.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 200) + + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + # View should still be browseable + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.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, - ] - self.assert_response(self.url_cat, good_users, 200) - self.assert_response(self.url_cat, bad_users, 302) + self.assert_response(self.url_cat, self.good_users_cat, 200) + self.assert_response(self.url_cat, self.bad_users_cat, 302) # Public guest access is disabled for categories with self.assertRaises(ValidationError): self.category.set_public() + def test_get_category_read_only(self): + """Test GET with category and site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url_cat, self.good_users_cat, 200) + self.assert_response(self.url_cat, self.bad_users_cat, 302) + class TestRoleAssignmentCreateView(ProjectPermissionTestBase): """Tests for RoleAssignmentCreateView permissions""" @@ -948,17 +1012,14 @@ def setUp(self): 'projectroles:role_create', kwargs={'project': self.category.sodar_uuid}, ) - - def test_get(self): - """Test RoleAssignmentCreateView GET""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -966,8 +1027,11 @@ def test_get(self): self.user_no_roles, self.anonymous, ] - self.assert_response(self.url, good_users, 200) - self.assert_response(self.url, bad_users, 302) + + def test_get(self): + """Test RoleAssignmentCreateView GET""" + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) @@ -982,27 +1046,17 @@ def test_get_anon(self): 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.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url, self.superuser, 200) + self.assert_response(self.url, self.non_superusers, 302) + def test_get_category(self): """Test GET with category""" good_users = [ @@ -1027,6 +1081,12 @@ def test_get_category(self): with self.assertRaises(ValidationError): self.category.set_public() + def test_get_category_read_only(self): + """Test GET with category and site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url_cat, self.superuser, 200) + self.assert_response(self.url_cat, self.non_superusers, 302) + class TestRoleAssignmentUpdateView(ProjectPermissionTestBase): """Tests for RoleAssignmentUpdateView permissions""" @@ -1041,17 +1101,14 @@ def setUp(self): 'projectroles:role_update', kwargs={'roleassignment': self.contributor_as_cat.sodar_uuid}, ) - - def test_get(self): - """Test RoleAssignmentUpdateView GET""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -1060,8 +1117,11 @@ def test_get(self): self.user_no_roles, self.anonymous, ] - self.assert_response(self.url, good_users, 200) - self.assert_response(self.url, bad_users, 302) + + def test_get(self): + """Test RoleAssignmentUpdateView GET""" + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) @@ -1076,27 +1136,17 @@ def test_get_anon(self): 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_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.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url, self.superuser, 200) + self.assert_response(self.url, self.non_superusers, 302) + def test_get_category(self): """Test GET with category""" good_users = [ @@ -1128,6 +1178,12 @@ def test_get_category_anon(self): self.url_cat, [self.user_no_roles, self.anonymous], 302 ) + def test_get_category_read_only(self): + """Test GET with category and site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url_cat, self.superuser, 200) + self.assert_response(self.url_cat, self.non_superusers, 302) + def test_get_owner(self): """Test GET with owner role (should fail)""" url = reverse( @@ -1202,17 +1258,14 @@ def setUp(self): 'projectroles:role_delete', kwargs={'roleassignment': self.contributor_as_cat.sodar_uuid}, ) - - def test_get(self): - """Test RoleAssignmentDeleteView GET""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -1221,8 +1274,11 @@ def test_get(self): self.user_no_roles, self.anonymous, ] - self.assert_response(self.url, good_users, 200) - self.assert_response(self.url, bad_users, 302) + + def test_get(self): + """Test RoleAssignmentDeleteView GET""" + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) @@ -1237,29 +1293,19 @@ def test_get_anon(self): 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.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url, self.superuser, 200) + self.assert_response(self.url, self.non_superusers, 302) + def test_get_category(self): - """Test RoleAssignmentDeleteView GET""" + """Test GET with category""" good_users = [ self.superuser, self.user_owner_cat, @@ -1289,6 +1335,12 @@ def test_get_category_anon(self): self.url_cat, [self.user_no_roles, self.anonymous], 302 ) + def test_get_category_read_only(self): + """Test GET with category and site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url_cat, self.superuser, 200) + self.assert_response(self.url_cat, self.non_superusers, 302) + def test_get_owner(self): """Test GET with owner role (should fail)""" url = reverse( @@ -1360,15 +1412,16 @@ def setUp(self): 'projectroles:role_owner_transfer', kwargs={'project': self.project.sodar_uuid}, ) - - def test_get(self): - """Test RoleAssignmentOwnerTransferView GET""" - good_users = [ + self.url_cat = reverse( + 'projectroles:role_owner_transfer', + kwargs={'project': self.category.sodar_uuid}, + ) + self.good_users = [ self.superuser, self.user_owner_cat, self.user_owner, ] - bad_users = [ + self.bad_users = [ self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, @@ -1379,8 +1432,11 @@ def test_get(self): self.user_no_roles, self.anonymous, ] - self.assert_response(self.url, good_users, 200) - self.assert_response(self.url, bad_users, 302) + + def test_get(self): + """Test RoleAssignmentOwnerTransferView GET""" + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) @@ -1395,26 +1451,45 @@ def test_get_anon(self): def test_get_archive(self): """Test GET with archived project""" self.project.set_archive() + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) + self.project.set_public() + self.assert_response(self.url, self.user_no_roles, 302) + + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url, self.superuser, 200) + self.assert_response(self.url, self.non_superusers, 302) + + def test_get_category(self): + """Test GET with category""" good_users = [ self.superuser, self.user_owner_cat, - self.user_owner, ] bad_users = [ self.user_delegate_cat, + self.user_owner, + self.user_delegate, 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(self.url, good_users, 200) - self.assert_response(self.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(self.url, self.user_no_roles, 302) + self.assert_response(self.url_cat, self.user_no_roles, 302) + + def test_get_category_read_only(self): + """Test GET with category and site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url_cat, self.superuser, 200) + self.assert_response(self.url_cat, self.non_superusers, 302) class TestProjectInviteView(ProjectPermissionTestBase): @@ -1428,17 +1503,14 @@ def setUp(self): self.url_cat = reverse( 'projectroles:invites', kwargs={'project': self.category.sodar_uuid} ) - - def test_get(self): - """Test ProjectInviteView GET""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -1447,8 +1519,11 @@ def test_get(self): self.user_no_roles, self.anonymous, ] - self.assert_response(self.url, good_users, 200) - self.assert_response(self.url, bad_users, 302) + + def test_get(self): + """Test ProjectInviteView GET""" + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) @@ -1463,27 +1538,17 @@ def test_get_anon(self): 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.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url, self.superuser, 200) + self.assert_response(self.url, self.non_superusers, 302) + def test_get_category(self): """Test GET with category""" good_users = [ @@ -1508,6 +1573,12 @@ def test_get_category(self): with self.assertRaises(ValidationError): self.category.set_public() + def test_get_category_read_only(self): + """Test GET with category and site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url_cat, self.superuser, 200) + self.assert_response(self.url_cat, self.non_superusers, 302) + class TestProjectInviteCreateView(ProjectPermissionTestBase): """Tests for ProjectInviteCreateView permissions""" @@ -1522,17 +1593,14 @@ def setUp(self): 'projectroles:invite_create', kwargs={'project': self.category.sodar_uuid}, ) - - def test_get(self): - """Test ProjectInviteCreateView GET""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -1541,8 +1609,11 @@ def test_get(self): self.user_no_roles, self.anonymous, ] - self.assert_response(self.url, good_users, 200) - self.assert_response(self.url, bad_users, 302) + + def test_get(self): + """Test ProjectInviteCreateView GET""" + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) @@ -1557,27 +1628,17 @@ def test_get_anon(self): 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.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url, self.superuser, 200) + self.assert_response(self.url, self.non_superusers, 302) + def test_get_category(self): """Test GET with category""" good_users = [ @@ -1598,8 +1659,12 @@ def test_get_category(self): ] 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) + + def test_get_category_read_only(self): + """Test GET with category and site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url_cat, self.superuser, 200) + self.assert_response(self.url_cat, self.non_superusers, 302) class TestProjectInviteResendView(ProjectPermissionTestBase): @@ -1619,17 +1684,14 @@ def setUp(self): 'projectroles:invite_resend', kwargs={'projectinvite': invite.sodar_uuid}, ) - - def test_get(self): - """Test ProjectInviteResendView GET""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -1638,16 +1700,19 @@ def test_get(self): self.user_no_roles, self.anonymous, ] + + def test_get(self): + """Test ProjectInviteResendView GET""" self.assert_response( self.url, - good_users, + self.good_users, 302, redirect_user=reverse( 'projectroles:invites', kwargs={'project': self.project.sodar_uuid}, ), ) - self.assert_response(self.url, bad_users, 302) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) @@ -1662,32 +1727,16 @@ def test_get_anon(self): 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, + self.good_users, 302, redirect_user=reverse( 'projectroles:invites', kwargs={'project': self.project.sodar_uuid}, ), ) - self.assert_response(self.url, bad_users, 302) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) @@ -1709,17 +1758,14 @@ def setUp(self): 'projectroles:invite_revoke', kwargs={'projectinvite': invite.sodar_uuid}, ) - - def test_get(self): - """Test ProjectInviteRevokeView GET""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -1728,8 +1774,11 @@ def test_get(self): self.user_no_roles, self.anonymous, ] - self.assert_response(self.url, good_users, 200) - self.assert_response(self.url, bad_users, 302) + + def test_get(self): + """Test ProjectInviteRevokeView GET""" + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) @@ -1744,27 +1793,17 @@ def test_get_anon(self): 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.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 302) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 302) + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url, self.superuser, 200) + self.assert_response(self.url, self.non_superusers, 302) + class TestRemoteSiteViews(RemoteSiteMixin, SiteAppPermissionTestBase): """Tests for UI view permissions in remote site views""" diff --git a/projectroles/tests/test_permissions_ajax.py b/projectroles/tests/test_permissions_ajax.py index b9c14d73..29dcc753 100644 --- a/projectroles/tests/test_permissions_ajax.py +++ b/projectroles/tests/test_permissions_ajax.py @@ -24,20 +24,7 @@ class TestProjectListAjaxViews(ProjectPermissionTestBase): def test_get_project_list(self): """Test ProjectListAjaxView GET""" url = reverse('projectroles:ajax_project_list') - 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.all_auth_users, 200) self.assert_response(url, self.anonymous, 403) self.project.set_public() self.assert_response(url, self.anonymous, 403) @@ -50,27 +37,23 @@ def test_get_project_list_anon(self): self.project.set_public() self.assert_response(url, self.anonymous, 200) + def test_get_project_list_read_only(self): + """Test ProjectListAjaxView GET with site read-only mode""" + self.set_site_read_only() + url = reverse('projectroles:ajax_project_list') + self.assert_response(url, self.all_auth_users, 200) + self.assert_response(url, self.anonymous, 403) + self.project.set_public() + self.assert_response(url, self.anonymous, 403) + 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'} - 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, + self.all_auth_users, 200, method='POST', data=data, @@ -110,27 +93,37 @@ def test_get_project_list_column_anon(self): req_kwargs=req_kwargs, ) + def test_get_project_list_column_read_only(self): + """Test ProjectListColumnAjaxView GET with site read-only mode""" + self.set_site_read_only() + url = reverse('projectroles:ajax_project_list_columns') + data = {'projects': [str(self.project.sodar_uuid)]} + req_kwargs = {'content_type': 'application/json'} + self.assert_response( + url, + self.all_auth_users, + 200, + method='POST', + data=data, + req_kwargs=req_kwargs, + ) + self.assert_response( + url, + self.anonymous, + 403, + method='POST', + data=data, + req_kwargs=req_kwargs, + ) + 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'} - 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, + self.all_auth_users, 200, method='POST', data=data, @@ -170,6 +163,38 @@ def test_get_project_list_role_anon(self): req_kwargs=req_kwargs, ) + def test_get_project_list_role_read_only(self): + """Test ProjectListRoleAjaxView GET with site read-only mode""" + self.set_site_read_only() + url = reverse('projectroles:ajax_project_list_roles') + data = {'projects': [str(self.project.sodar_uuid)]} + req_kwargs = {'content_type': 'application/json'} + self.assert_response( + url, + self.all_auth_users, + 200, + method='POST', + data=data, + req_kwargs=req_kwargs, + ) + self.assert_response( + url, + self.anonymous, + 403, + method='POST', + data=data, + req_kwargs=req_kwargs, + ) + self.project.set_public() + self.assert_response( + url, + self.anonymous, + 403, + method='POST', + data=data, + req_kwargs=req_kwargs, + ) + class TestProjectStarringAjaxView(ProjectPermissionTestBase): """Tests for ProjectStarringAjaxView permissions""" @@ -185,8 +210,8 @@ def setUp(self): kwargs={'project': self.category.sodar_uuid}, ) - def test_get(self): - """Test ProjectStarringAjaxView GET""" + def test_post(self): + """Test ProjectStarringAjaxView POST""" good_users = [ self.superuser, self.user_owner_cat, @@ -205,13 +230,19 @@ def test_get(self): self.assert_response(self.url, self.user_no_roles, 200, method='POST') @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_get_anon(self): - """Test GET with anonymous access""" + def test_post_anon(self): + """Test POST with anonymous access""" self.project.set_public() self.assert_response(self.url, self.anonymous, 401, method='POST') - def test_get_category(self): - """Test GET with category""" + def test_post_read_only(self): + """Test POST with site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url, self.superuser, 200, method='POST') + self.assert_response(self.url, self.non_superusers, 403, method='POST') + + def test_post_category(self): + """Test POST with category""" good_users = [ self.superuser, self.user_owner_cat, @@ -233,11 +264,19 @@ def test_get_category(self): ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_get_category_anon(self): - """Test GET with category and anonymous access""" + def test_post_category_anon(self): + """Test POST with category and anonymous access""" self.project.set_public() self.assert_response(self.url_cat, self.anonymous, 401, method='POST') + def test_post_category_read_only(self): + """Test POST with category and site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url_cat, self.superuser, 200, method='POST') + self.assert_response( + self.url_cat, self.non_superusers, 403, method='POST' + ) + class TestRemoteProjectAccessAjaxView( RemoteSiteMixin, RemoteProjectMixin, ProjectPermissionTestBase @@ -261,10 +300,7 @@ def setUp(self): 'projectroles:ajax_remote_access', kwargs={'project': self.project.sodar_uuid}, ) + '?rp={}'.format(self.remote_project.sodar_uuid) - - def test_get(self): - """Test RemoteProjectAccessAjaxView GET""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, @@ -275,9 +311,16 @@ def test_get(self): 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.bad_users = [ + self.user_finder_cat, + self.user_no_roles, + self.anonymous, + ] + + def test_get(self): + """Test RemoteProjectAccessAjaxView GET""" + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 403) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 200) @@ -290,20 +333,14 @@ def test_get_anon(self): 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.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 403) + + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 403) class TestSidebarContentAjaxView(ProjectPermissionTestBase): @@ -319,10 +356,7 @@ def setUp(self): 'projectroles:ajax_sidebar', kwargs={'project': self.category.sodar_uuid}, ) - - def test_get(self): - """Test SidebarContentAjaxView GET""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, @@ -333,9 +367,29 @@ def test_get(self): 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.bad_users = [ + self.user_finder_cat, + self.user_no_roles, + self.anonymous, + ] + self.good_users_cat = [ + 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.bad_users_cat = [self.user_no_roles, self.anonymous] + + def test_get(self): + """Test SidebarContentAjaxView GET""" + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 403) self.project.set_public() self.assert_response(self.url, self.user_no_roles, 200) @@ -348,38 +402,19 @@ def test_get_anon(self): 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.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 403) + + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url, self.good_users, 200) + self.assert_response(self.url, self.bad_users, 403) 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_no_roles, self.anonymous] - self.assert_response(self.url_cat, good_users, 200) - self.assert_response(self.url_cat, bad_users, 403) + self.assert_response(self.url_cat, self.good_users_cat, 200) + self.assert_response(self.url_cat, self.bad_users_cat, 403) self.project.set_public() self.assert_response(self.url_cat, self.user_no_roles, 200) @@ -389,6 +424,12 @@ def test_get_category_anon(self): self.project.set_public() self.assert_response(self.url_cat, self.anonymous, 200) + def test_get_category_read_only(self): + """Test GET with category and site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url_cat, self.good_users_cat, 200) + self.assert_response(self.url_cat, self.bad_users_cat, 403) + class TestUserDropdownContentAjaxView(ProjectPermissionTestBase): """Tests for UserDropdownContentAjaxView permissions""" @@ -399,22 +440,14 @@ def setUp(self): def test_get(self): """Test UserDropdownContentAjaxView GET""" - 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, - self.user_finder_cat, - self.user_no_roles, - ] - bad_users = [self.anonymous] - self.assert_response(self.url, good_users, 200) - self.assert_response(self.url, bad_users, 403) + self.assert_response(self.url, self.all_auth_users, 200) + self.assert_response(self.url, self.anonymous, 403) + + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response(self.url, self.all_auth_users, 200) + self.assert_response(self.url, self.anonymous, 403) class TestUserAjaxViews(ProjectPermissionTestBase): @@ -423,40 +456,27 @@ class TestUserAjaxViews(ProjectPermissionTestBase): def test_get_current_user(self): """Test CurrentUserRetrieveAjaxView GET""" url = reverse('projectroles:ajax_user_current') - 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, - ] - bad_users = [self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 403) + self.assert_response(url, self.all_auth_users, 200) + self.assert_response(url, self.anonymous, 403) + + def test_get_current_user_read_only(self): + """Test CurrentUserRetrieveAjaxView GET with site read-only mode""" + self.set_site_read_only() + url = reverse('projectroles:ajax_user_current') + self.assert_response(url, self.all_auth_users, 200) + self.assert_response(url, self.anonymous, 403) @override_settings(PROJECTROLES_ALLOW_LOCAL_USERS=True) def test_get_autocomplete_ajax(self): """Test UserAutocompleteAjaxView GET""" url = reverse('projectroles:ajax_autocomplete_user') - 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, - ] - bad_users = [self.anonymous] - self.assert_response(url, good_users, 200) - self.assert_response(url, bad_users, 403) + self.assert_response(url, self.all_auth_users, 200) + self.assert_response(url, self.anonymous, 403) + + @override_settings(PROJECTROLES_ALLOW_LOCAL_USERS=True) + def test_get_autocomplete_ajax_read_only(self): + """Test UserAutocompleteAjaxView GET with site read-only mode""" + self.set_site_read_only() + url = reverse('projectroles:ajax_autocomplete_user') + self.assert_response(url, self.all_auth_users, 200) + self.assert_response(url, self.anonymous, 403) diff --git a/projectroles/tests/test_permissions_api.py b/projectroles/tests/test_permissions_api.py index c82f8386..a2bf5915 100644 --- a/projectroles/tests/test_permissions_api.py +++ b/projectroles/tests/test_permissions_api.py @@ -125,25 +125,21 @@ class ProjectrolesAPIPermissionTestBase(ProjectAPIPermissionTestBase): class TestProjectListAPIView(ProjectrolesAPIPermissionTestBase): """Tests for ProjectListAPIView permissions""" + def setUp(self): + super().setUp() + self.url = reverse('projectroles:api_project_list') + def test_get(self): """Test ProjectListAPIView GET""" - url = reverse('projectroles:api_project_list') - 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_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, self.all_auth_users, 200) + self.assert_response_api(self.url, self.anonymous, 401) + self.assert_response_api(self.url, self.all_auth_users, 200, knox=True) + + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response_api(self.url, self.all_auth_users, 200) + self.assert_response_api(self.url, self.anonymous, 401) class TestProjectRetrieveAPIView(ProjectrolesAPIPermissionTestBase): @@ -155,10 +151,7 @@ def setUp(self): 'projectroles:api_project_retrieve', kwargs={'project': self.project.sodar_uuid}, ) - - def test_get(self): - """Test ProjectRetrieveAPIView GET""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, @@ -169,12 +162,15 @@ def test_get(self): 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.bad_users = [self.user_finder_cat, self.user_no_roles] + + def test_get(self): + """Test ProjectRetrieveAPIView GET""" + self.assert_response_api(self.url, self.good_users, 200) + self.assert_response_api(self.url, self.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.assert_response_api(self.url, self.good_users, 200, knox=True) + self.assert_response_api(self.url, self.bad_users, 403, knox=True) self.project.set_public() self.assert_response_api(self.url, self.user_no_roles, 200) @@ -187,26 +183,21 @@ def test_get_anon(self): 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.good_users, 200) + self.assert_response_api(self.url, self.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.assert_response_api(self.url, self.good_users, 200, knox=True) + self.assert_response_api(self.url, self.bad_users, 403, knox=True) self.project.set_public() self.assert_response_api(self.url, self.user_no_roles, 200) + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response_api(self.url, self.good_users, 200) + self.assert_response_api(self.url, self.bad_users, 403) + self.assert_response_api(self.url, self.anonymous, 401) + class TestProjectCreateAPIView(ProjectrolesAPIPermissionTestBase): """Tests for ProjectCreateAPIView permissions""" @@ -234,21 +225,10 @@ def setUp(self): 'owner': str(self.user_owner.sodar_uuid), } - def test_post(self): - """Test ProjectCreateAPIView POST""" + def test_post_top(self): + """Test ProjectCreateAPIView POST on top level""" 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, - ] + bad_users = self.auth_non_superusers self.assert_response_api( self.url, good_users, @@ -290,13 +270,33 @@ def test_post(self): ) @override_settings(PROJECTROLES_ALLOW_ANONYMOUS=True) - def test_post_anon(self): - """Test POST with anonymous access""" + def test_post_top_anon(self): + """Test POST with top level and anonymous access""" self.project.set_public() self.assert_response_api( self.url, self.anonymous, 401, method='POST', data=self.post_data ) + def test_post_top_read_only(self): + """Test POST on top level with site read-only mode""" + self.set_site_read_only() + good_users = [self.superuser] + bad_users = self.auth_non_superusers + 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 + ) + def test_post_parent(self): """Test POST with parent category""" good_users = [ @@ -370,6 +370,30 @@ def test_post_parent_anon(self): data=self.post_data_parent, ) + def test_post_parent_read_only(self): + """Test POST with parent category and site read-only mode""" + self.set_site_read_only() + good_users = [self.superuser] + bad_users = self.auth_non_superusers + self.assert_response_api( + self.url, + good_users, + 201, + method='POST', + data=self.post_data_parent, + cleanup_method=self._cleanup, + ) + self.assert_response_api( + self.url, bad_users, 403, method='POST', data=self.post_data_parent + ) + self.assert_response_api( + self.url, + self.anonymous, + 401, + method='POST', + data=self.post_data_parent, + ) + class TestProjectUpdateAPIView(ProjectrolesAPIPermissionTestBase): """Tests for ProjectUpdateAPIView permissions""" @@ -388,17 +412,14 @@ def setUp(self): 'readme': 'readme', 'owner': str(self.user_owner.sodar_uuid), } - - def test_put(self): - """Test ProjectUpdateAPIView PUT""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -406,18 +427,21 @@ def test_put(self): self.user_guest, self.user_no_roles, ] + + def test_put(self): + """Test ProjectUpdateAPIView PUT""" self.assert_response_api( - self.url, good_users, 200, method='PUT', data=self.put_data + self.url, self.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.url, self.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, + self.good_users, 200, method='PUT', data=self.put_data, @@ -425,7 +449,7 @@ def test_put(self): ) self.assert_response_api( self.url, - bad_users, + self.bad_users, 403, method='PUT', data=self.put_data, @@ -446,33 +470,18 @@ def test_put_anon(self): 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.url, self.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.url, self.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, + self.good_users, 200, method='PUT', data=self.put_data, @@ -480,7 +489,7 @@ def test_put_archive(self): ) self.assert_response_api( self.url, - bad_users, + self.bad_users, 403, method='PUT', data=self.put_data, @@ -491,6 +500,19 @@ def test_put_archive(self): self.url, self.user_no_roles, 403, method='PUT', data=self.put_data ) + def test_put_read_only(self): + """Test PUT with site read-only mode""" + self.set_site_read_only() + self.assert_response_api( + self.url, self.superuser, 200, method='PUT', data=self.put_data + ) + self.assert_response_api( + self.url, self.bad_users, 403, method='PUT', data=self.put_data + ) + self.assert_response_api( + self.url, self.anonymous, 401, method='PUT', data=self.put_data + ) + class TestRoleAssignmentCreateAPIView(ProjectrolesAPIPermissionTestBase): """Tests for RoleAssignmentCreateAPIView permissions""" @@ -513,17 +535,14 @@ def setUp(self): 'role': SODAR_CONSTANTS['PROJECT_ROLE_CONTRIBUTOR'], 'user': str(self.assign_user.sodar_uuid), } - - def test_post(self): - """Test RoleAssignmentCreateAPIView POST""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -531,23 +550,26 @@ def test_post(self): self.user_guest, self.user_no_roles, ] + + def test_post(self): + """Test RoleAssignmentCreateAPIView POST""" self.assert_response_api( self.url, - good_users, + self.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.url, self.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, + self.good_users, 201, method='POST', data=self.post_data, @@ -556,7 +578,7 @@ def test_post(self): ) self.assert_response_api( self.url, - bad_users, + self.bad_users, 403, method='POST', data=self.post_data, @@ -582,38 +604,23 @@ def test_post_anon(self): 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, + self.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.url, self.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, + self.good_users, 201, method='POST', data=self.post_data, @@ -622,7 +629,7 @@ def test_post_archive(self): ) self.assert_response_api( self.url, - bad_users, + self.bad_users, 403, method='POST', data=self.post_data, @@ -637,6 +644,28 @@ def test_post_archive(self): data=self.post_data, ) + def test_post_read_only(self): + """Test POST with site read-only mode""" + self.set_site_read_only() + self.assert_response_api( + self.url, + self.superuser, + 201, + method='POST', + data=self.post_data, + cleanup_method=self._cleanup, + ) + self.assert_response_api( + self.url, + self.auth_non_superusers, + 403, + method='POST', + data=self.post_data, + ) + self.assert_response_api( + self.url, self.anonymous, 401, method='POST', data=self.post_data + ) + class TestRoleAssignmentUpdateAPIView(ProjectrolesAPIPermissionTestBase): """Tests for RoleAssignmentUpdateAPIView permissions""" @@ -655,17 +684,14 @@ def setUp(self): 'role': self.role_guest.name, 'user': str(self.assign_user.sodar_uuid), } - - def test_put(self): - """Test RoleAssignmentUpdateAPIView PUT""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -673,18 +699,21 @@ def test_put(self): self.user_guest, self.user_no_roles, ] + + def test_put(self): + """Test RoleAssignmentUpdateAPIView PUT""" self.assert_response_api( - self.url, good_users, 200, method='PUT', data=self.put_data + self.url, self.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.url, self.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, + self.good_users, 200, method='PUT', data=self.put_data, @@ -692,7 +721,7 @@ def test_put(self): ) self.assert_response_api( self.url, - bad_users, + self.bad_users, 403, method='PUT', data=self.put_data, @@ -714,33 +743,18 @@ def test_put_anon(self): 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_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.url, self.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.url, self.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, + self.good_users, 200, method='PUT', data=self.put_data, @@ -748,7 +762,7 @@ def test_put_archive(self): ) self.assert_response_api( self.url, - bad_users, + self.bad_users, 403, method='PUT', data=self.put_data, @@ -759,6 +773,23 @@ def test_put_archive(self): self.url, self.user_no_roles, 403, method='PUT', data=self.put_data ) + def test_put_read_only(self): + """Test PUT with site read-only mode""" + self.set_site_read_only() + self.assert_response_api( + self.url, self.superuser, 200, method='PUT', data=self.put_data + ) + self.assert_response_api( + self.url, + self.auth_non_superusers, + 403, + method='PUT', + data=self.put_data, + ) + self.assert_response_api( + self.url, self.anonymous, 401, method='PUT', data=self.put_data + ) + class TestRoleAssignmentDestroyAPIView(ProjectrolesAPIPermissionTestBase): """Tests for RoleAssignmentDestroyAPIView permissions""" @@ -779,17 +810,14 @@ def setUp(self): 'projectroles:api_role_destroy', kwargs={'roleassignment': self.role_uuid}, ) - - def test_delete(self): - """Test RoleAssignmentDestroyAPIView DELETE""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -797,25 +825,28 @@ def test_delete(self): self.user_guest, self.user_no_roles, ] + + def test_delete(self): + """Test RoleAssignmentDestroyAPIView DELETE""" self.assert_response_api( self.url, - good_users, + self.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.bad_users, 403, method='DELETE') self.assert_response_api(self.url, self.anonymous, 401, method='DELETE') self.assert_response_api( self.url, - good_users, + self.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.url, self.bad_users, 403, method='DELETE', knox=True ) self.project.set_public() self.assert_response_api( @@ -831,46 +862,46 @@ def test_delete_anon(self): 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, + self.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.bad_users, 403, method='DELETE') self.assert_response_api(self.url, self.anonymous, 401, method='DELETE') self.assert_response_api( self.url, - good_users, + self.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.url, self.bad_users, 403, method='DELETE', knox=True ) self.project.set_public() self.assert_response_api( self.url, self.user_no_roles, 403, method='DELETE' ) + def test_delete_read_only(self): + """Test DELETE with site read-only mode""" + self.set_site_read_only() + self.assert_response_api( + self.url, + self.superuser, + 204, + method='DELETE', + cleanup_method=self._make_as, + ) + self.assert_response_api( + self.url, self.auth_non_superusers, 403, method='DELETE' + ) + self.assert_response_api(self.url, self.anonymous, 401, method='DELETE') + class TestRoleAssignmentOwnerTransferAPIView(ProjectrolesAPIPermissionTestBase): """Tests for RoleAssignmentOwnerTransferAPIView permissions""" @@ -897,15 +928,12 @@ def setUp(self): 'new_owner': self.new_owner.username, 'old_owner_role': SODAR_CONSTANTS['PROJECT_ROLE_CONTRIBUTOR'], } - - def test_post(self): - """Test RoleAssignmentOwnerTransferAPIView POST""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_owner, ] - bad_users = [ + self.bad_users = [ self.user_delegate_cat, self.user_contributor_cat, self.user_guest_cat, @@ -915,23 +943,26 @@ def test_post(self): self.user_guest, self.user_no_roles, ] + + def test_post(self): + """Test RoleAssignmentOwnerTransferAPIView POST""" self.assert_response_api( self.url, - good_users, + self.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.url, self.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, + self.good_users, 200, method='POST', data=self.post_data, @@ -940,7 +971,7 @@ def test_post(self): ) self.assert_response_api( self.url, - bad_users, + self.bad_users, 403, method='POST', data=self.post_data, @@ -966,38 +997,23 @@ def test_post_anon(self): 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, + self.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.url, self.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, + self.good_users, 200, method='POST', data=self.post_data, @@ -1006,7 +1022,7 @@ def test_post_archive(self): ) self.assert_response_api( self.url, - bad_users, + self.bad_users, 403, method='POST', data=self.post_data, @@ -1021,6 +1037,28 @@ def test_post_archive(self): data=self.post_data, ) + def test_post_read_only(self): + """Test POST with site read-only mode""" + self.set_site_read_only() + self.assert_response_api( + self.url, + self.superuser, + 200, + method='POST', + data=self.post_data, + cleanup_method=self._cleanup, + ) + self.assert_response_api( + self.url, + self.auth_non_superusers, + 403, + method='POST', + data=self.post_data, + ) + self.assert_response_api( + self.url, self.anonymous, 401, method='POST', data=self.post_data + ) + class TestProjectInviteListAPIView(ProjectrolesAPIPermissionTestBase): """Tests for ProjectInviteListAPIView permissions""" @@ -1031,17 +1069,14 @@ def setUp(self): 'projectroles:api_invite_list', kwargs={'project': self.project.sodar_uuid}, ) - - def test_get(self): - """Test ProjectInviteListAPIView GET""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -1049,10 +1084,13 @@ def test_get(self): 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) + + def test_get(self): + """Test ProjectInviteListAPIView GET""" + self.assert_response_api(self.url, self.good_users, 200) + self.assert_response_api(self.url, self.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, self.good_users, 200, knox=True) self.project.set_public() self.assert_response_api(self.url, self.user_no_roles, 403) @@ -1065,28 +1103,20 @@ def test_get_anon(self): 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.good_users, 200) + self.assert_response_api(self.url, self.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, self.good_users, 200, knox=True) self.project.set_public() self.assert_response_api(self.url, self.user_no_roles, 403) + def test_get_read_only(self): + """Test GET with archived project and site read-only mode""" + self.set_site_read_only() + self.assert_response_api(self.url, self.superuser, 200) + self.assert_response_api(self.url, self.auth_non_superusers, 403) + self.assert_response_api(self.url, self.anonymous, 401) + class TestProjectInviteCreateAPIView(ProjectrolesAPIPermissionTestBase): """Tests for ProjectInviteCreateAPIView permissions""" @@ -1105,17 +1135,14 @@ def setUp(self): 'email': self.email, 'role': SODAR_CONSTANTS['PROJECT_ROLE_CONTRIBUTOR'], } - - def test_post(self): - """Test ProjectInviteCreateAPIView POST""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -1123,23 +1150,26 @@ def test_post(self): self.user_guest, self.user_no_roles, ] + + def test_post(self): + """Test ProjectInviteCreateAPIView POST""" self.assert_response_api( self.url, - good_users, + self.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.url, self.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, + self.good_users, 201, method='POST', data=self.post_data, @@ -1148,7 +1178,7 @@ def test_post(self): ) self.assert_response_api( self.url, - bad_users, + self.bad_users, 403, method='POST', data=self.post_data, @@ -1174,38 +1204,23 @@ def test_post_anon(self): 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, + self.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.url, self.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, + self.good_users, 201, method='POST', data=self.post_data, @@ -1214,7 +1229,7 @@ def test_post_archive(self): ) self.assert_response_api( self.url, - bad_users, + self.bad_users, 403, method='POST', data=self.post_data, @@ -1229,9 +1244,31 @@ def test_post_archive(self): data=self.post_data, ) + def test_post_read_only(self): + """Test POST with site read-only mode""" + self.set_site_read_only() + self.assert_response_api( + self.url, + self.superuser, + 201, + method='POST', + data=self.post_data, + cleanup_method=self._cleanup, + ) + self.assert_response_api( + self.url, + self.auth_non_superusers, + 403, + method='POST', + data=self.post_data, + ) + self.assert_response_api( + self.url, self.anonymous, 401, method='POST', data=self.post_data + ) + class TestProjectInviteRevokeAPIView(ProjectrolesAPIPermissionTestBase): - """Tests for ProjectInviteRevokeAPIView( permissions""" + """Tests for ProjectInviteRevokeAPIView permissions""" def _cleanup(self): self.invite.active = True @@ -1249,17 +1286,14 @@ def setUp(self): 'projectroles:api_invite_revoke', kwargs={'projectinvite': self.invite.sodar_uuid}, ) - - def test_post(self): - """Test ProjectInviteRevokeAPIView POST""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -1267,25 +1301,28 @@ def test_post(self): self.user_guest, self.user_no_roles, ] + + def test_post(self): + """Test ProjectInviteRevokeAPIView POST""" self.assert_response_api( self.url, - good_users, + self.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.bad_users, 403, method='POST') self.assert_response_api(self.url, self.anonymous, 401, method='POST') self.assert_response_api( self.url, - good_users, + self.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.url, self.bad_users, 403, method='POST', knox=True ) self.project.set_public() self.assert_response_api( @@ -1301,46 +1338,46 @@ def test_post_anon(self): 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, + self.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.bad_users, 403, method='POST') self.assert_response_api(self.url, self.anonymous, 401, method='POST') self.assert_response_api( self.url, - good_users, + self.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.url, self.bad_users, 403, method='POST', knox=True ) self.project.set_public() self.assert_response_api( self.url, self.user_no_roles, 403, method='POST' ) + def test_post_read_only(self): + """Test POST with site read-only mode""" + self.set_site_read_only() + self.assert_response_api( + self.url, + self.superuser, + 200, + method='POST', + cleanup_method=self._cleanup, + ) + self.assert_response_api( + self.url, self.auth_non_superusers, 403, method='POST' + ) + self.assert_response_api(self.url, self.anonymous, 401, method='POST') + class TestProjectInviteResendAPIView(ProjectrolesAPIPermissionTestBase): """Tests for ProjectInviteResendAPIView permissions""" @@ -1357,17 +1394,14 @@ def setUp(self): 'projectroles:api_invite_resend', kwargs={'projectinvite': self.invite.sodar_uuid}, ) - - def test_post(self): - """Test ProjectInviteResendAPIView POST""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -1375,18 +1409,21 @@ def test_post(self): 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') + + def test_post(self): + """Test ProjectInviteResendAPIView POST""" + self.assert_response_api(self.url, self.good_users, 200, method='POST') + self.assert_response_api(self.url, self.bad_users, 403, method='POST') self.assert_response_api(self.url, self.anonymous, 401, method='POST') self.assert_response_api( self.url, - good_users, + self.good_users, 200, method='POST', knox=True, ) self.assert_response_api( - self.url, bad_users, 403, method='POST', knox=True + self.url, self.bad_users, 403, method='POST', knox=True ) self.project.set_public() self.assert_response_api( @@ -1402,39 +1439,33 @@ def test_post_anon(self): 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.good_users, 200, method='POST') + self.assert_response_api(self.url, self.bad_users, 403, method='POST') self.assert_response_api(self.url, self.anonymous, 401, method='POST') self.assert_response_api( self.url, - good_users, + self.good_users, 200, method='POST', knox=True, ) self.assert_response_api( - self.url, bad_users, 403, method='POST', knox=True + self.url, self.bad_users, 403, method='POST', knox=True ) self.project.set_public() self.assert_response_api( self.url, self.user_no_roles, 403, method='POST' ) + def test_post_read_only(self): + """Test POST with site read-only mode""" + self.set_site_read_only() + self.assert_response_api(self.url, self.superuser, 200, method='POST') + self.assert_response_api( + self.url, self.auth_non_superusers, 403, method='POST' + ) + self.assert_response_api(self.url, self.anonymous, 401, method='POST') + class TestProjectSettingRetrieveAPIView(ProjectrolesAPIPermissionTestBase): """Tests for ProjectSettingRetrieveAPIView permissions""" @@ -1450,17 +1481,14 @@ def setUp(self): 'plugin_name': 'example_project_app', 'setting_name': 'project_str_setting', } - - def test_get_project_setting(self): - """Test ProjectSettingRetrieveAPIView GET with PROJECT scope""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -1468,20 +1496,27 @@ def test_get_project_setting(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) + + def test_get_project_setting(self): + """Test ProjectSettingRetrieveAPIView GET with PROJECT scope""" + self.assert_response_api( + self.url, self.good_users, 200, data=self.get_data + ) + self.assert_response_api( + self.url, self.bad_users, 403, data=self.get_data + ) self.assert_response_api( self.url, self.anonymous, 401, data=self.get_data ) self.assert_response_api( self.url, - good_users, + self.good_users, 200, data=self.get_data, knox=True, ) self.assert_response_api( - self.url, bad_users, 403, data=self.get_data, knox=True + self.url, self.bad_users, 403, data=self.get_data, knox=True ) self.project.set_public() self.assert_response_api( @@ -1501,41 +1536,43 @@ def test_get_project_setting_anon(self): def test_get_project_setting_archive(self): """Test GET with PROJECT scope and 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, data=self.get_data) - self.assert_response_api(self.url, bad_users, 403, data=self.get_data) + self.assert_response_api( + self.url, self.good_users, 200, data=self.get_data + ) + self.assert_response_api( + self.url, self.bad_users, 403, data=self.get_data + ) self.assert_response_api( self.url, self.anonymous, 401, data=self.get_data ) self.assert_response_api( self.url, - good_users, + self.good_users, 200, data=self.get_data, knox=True, ) self.assert_response_api( - self.url, bad_users, 403, data=self.get_data, knox=True + self.url, self.bad_users, 403, data=self.get_data, knox=True ) self.project.set_public() self.assert_response_api( self.url, self.user_no_roles, 403, data=self.get_data ) + def test_get_project_setting_read_only(self): + """Test GET with PROJECT scope and site read-only mode""" + self.set_site_read_only() + self.assert_response_api( + self.url, self.good_users, 200, data=self.get_data + ) + self.assert_response_api( + self.url, self.bad_users, 403, data=self.get_data + ) + self.assert_response_api( + self.url, self.anonymous, 401, data=self.get_data + ) + def test_get_project_user_setting(self): """Test GET with PROJECT_USER scope""" get_data = { @@ -1576,6 +1613,33 @@ def test_get_project_user_setting(self): self.url, self.user_no_roles, 403, data=get_data ) + def test_get_project_user_setting_read_only(self): + """Test GET with PROJECT_USER scope and site read-only mode""" + self.set_site_read_only() + get_data = { + 'plugin_name': 'example_project_app', + 'setting_name': 'project_user_str_setting', + 'user': str(self.user_owner.sodar_uuid), + } + good_users = [ + self.superuser, + self.user_owner, + ] + 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, + ] + 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) + class TestProjectSettingSetAPIView(ProjectrolesAPIPermissionTestBase): """Tests for ProjectSettingSetAPIView permissions""" @@ -1592,17 +1656,14 @@ def setUp(self): 'setting_name': 'project_str_setting', 'value': 'value', } - - def test_post_project_setting(self): - """Test ProjectSettingSetAPIView POST with PROJECT scope""" - good_users = [ + self.good_users = [ self.superuser, self.user_owner_cat, self.user_delegate_cat, self.user_owner, self.user_delegate, ] - bad_users = [ + self.bad_users = [ self.user_contributor_cat, self.user_guest_cat, self.user_finder_cat, @@ -1610,22 +1671,25 @@ def test_post_project_setting(self): self.user_guest, self.user_no_roles, ] + + def test_post_project_setting(self): + """Test ProjectSettingSetAPIView POST with PROJECT scope""" self.assert_response_api( self.url, - good_users, + self.good_users, 200, method='POST', data=self.post_data, ) self.assert_response_api( - self.url, bad_users, 403, method='POST', data=self.post_data + self.url, self.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, + self.good_users, 200, method='POST', data=self.post_data, @@ -1633,7 +1697,7 @@ def test_post_project_setting(self): ) self.assert_response_api( self.url, - bad_users, + self.bad_users, 403, method='POST', data=self.post_data, @@ -1663,37 +1727,22 @@ def test_post_project_setting_anon(self): 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, - 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, + self.good_users, 200, method='POST', data=self.post_data, ) self.assert_response_api( - self.url, bad_users, 403, method='POST', data=self.post_data + self.url, self.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, + self.good_users, 200, method='POST', data=self.post_data, @@ -1701,7 +1750,7 @@ def test_post_project_setting_archive(self): ) self.assert_response_api( self.url, - bad_users, + self.bad_users, 403, method='POST', data=self.post_data, @@ -1716,6 +1765,27 @@ def test_post_project_setting_archive(self): data=self.post_data, ) + def test_post_project_setting_read_only(self): + """Test POST with PROJECT scope and site read-only mode""" + self.set_site_read_only() + self.assert_response_api( + self.url, + self.superuser, + 200, + method='POST', + data=self.post_data, + ) + self.assert_response_api( + self.url, + self.auth_non_superusers, + 403, + method='POST', + data=self.post_data, + ) + self.assert_response_api( + self.url, self.anonymous, 401, method='POST', data=self.post_data + ) + def test_post_project_user_setting(self): """Test POST with PROJECT_USER scope""" post_data = { @@ -1765,6 +1835,33 @@ def test_post_project_user_setting(self): self.url, self.user_no_roles, 403, method='POST', data=post_data ) + def test_post_project_user_setting_read_only(self): + """Test POST with PROJECT_USER scope and site read-only mode""" + self.set_site_read_only() + post_data = { + 'plugin_name': 'example_project_app', + 'setting_name': 'project_user_str_setting', + 'value': 'value', + 'user': str(self.user_owner.sodar_uuid), + } + self.assert_response_api( + self.url, + self.superuser, + 200, + method='POST', + data=post_data, + ) + self.assert_response_api( + self.url, + self.auth_non_superusers, + 403, + method='POST', + data=post_data, + ) + self.assert_response_api( + self.url, self.anonymous, 401, method='POST', data=post_data + ) + class TestUserSettingRetrieveAPIView(ProjectrolesAPIPermissionTestBase): """Tests for UserSettingRetrieveAPIView permissions""" @@ -1777,27 +1874,17 @@ def setUp(self): 'setting_name': 'user_str_setting', } - def test_get_retrieve(self): + def test_get(self): """Test UserSettingRetrieveAPIView GET""" - good_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.assert_response_api(self.url, good_users, 200, data=self.get_data) + self.assert_response_api( + self.url, self.auth_non_superusers, 200, data=self.get_data + ) self.assert_response_api( self.url, self.anonymous, 403, data=self.get_data ) self.assert_response_api( self.url, - good_users, + self.auth_non_superusers, 200, data=self.get_data, knox=True, @@ -1811,6 +1898,16 @@ def test_get_anon(self): self.url, [self.anonymous], 403, data=self.get_data ) + def test_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response_api( + self.url, self.auth_non_superusers, 200, data=self.get_data + ) + self.assert_response_api( + self.url, self.anonymous, 403, data=self.get_data + ) + class TestUserSettingSetAPIView(ProjectrolesAPIPermissionTestBase): """Tests for UserSettingSetAPIView permissions""" @@ -1826,27 +1923,19 @@ def setUp(self): def test_post(self): """Test UserSettingSetAPIView POST""" - good_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.assert_response_api( - self.url, good_users, 200, method='POST', data=self.post_data + self.url, + self.auth_non_superusers, + 200, + method='POST', + data=self.post_data, ) self.assert_response_api( self.url, self.anonymous, 403, method='POST', data=self.post_data ) self.assert_response_api( self.url, - good_users, + self.auth_non_superusers, 200, method='POST', data=self.post_data, @@ -1865,9 +1954,23 @@ def test_post_anon(self): data=self.post_data, ) + def test_post_read_only(self): + """Test POST with site read-only mode""" + self.set_site_read_only() + self.assert_response_api( + self.url, + self.auth_non_superusers, + 200, + method='POST', + data=self.post_data, + ) + self.assert_response_api( + self.url, self.anonymous, 403, method='POST', data=self.post_data + ) + class TestUserListAPIView(ProjectrolesAPIPermissionTestBase): - """Tests for UserSettingSetAPIView permissions""" + """Tests for UserListAPIView permissions""" def setUp(self): super().setUp() @@ -1875,28 +1978,21 @@ def setUp(self): def test_get(self): """Test UserListAPIView 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_api(self.url, good_users, 200) + self.assert_response_api(self.url, self.all_auth_users, 200) 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, self.all_auth_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_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response_api(self.url, self.all_auth_users, 200) + self.assert_response_api(self.url, self.anonymous, 401) + class TestCurrentUserRetrieveAPIView(ProjectrolesAPIPermissionTestBase): """Tests for CurrentUserRetrieveAPIView permissions""" @@ -1907,24 +2003,17 @@ def setUp(self): def test_get(self): """Test CurrentUserRetrieveAPIView 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_api(self.url, good_users, 200) + self.assert_response_api(self.url, self.all_auth_users, 200) 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, self.all_auth_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_get_read_only(self): + """Test GET with site read-only mode""" + self.set_site_read_only() + self.assert_response_api(self.url, self.all_auth_users, 200) + self.assert_response_api(self.url, self.anonymous, 401) diff --git a/projectroles/views_ajax.py b/projectroles/views_ajax.py index bc50f8d5..cd48c915 100644 --- a/projectroles/views_ajax.py +++ b/projectroles/views_ajax.py @@ -411,7 +411,7 @@ def post(self, request, *args, **kwargs): class ProjectStarringAjaxView(SODARBaseProjectAjaxView): """View to handle starring and unstarring a project""" - permission_required = 'projectroles.view_project' + permission_required = 'projectroles.star_project' def post(self, request, *args, **kwargs): # HACK: Manually refuse access to anonymous as this view is an exception diff --git a/projectroles/views_api.py b/projectroles/views_api.py index 06b7fc08..b87b3496 100644 --- a/projectroles/views_api.py +++ b/projectroles/views_api.py @@ -882,21 +882,21 @@ def get_request_value(cls, request): return request.data['value'] @classmethod - def check_project_perms( - cls, setting_def, project, request_user, setting_user - ): + def check_project_perms(cls, setting_def, project, request, setting_user): """ Check permissions for project settings. :param setting_def: PluginAppSettingDef object :param project: Project object - :param request_user: User object for requesting user + :param request: HttpRequest object :param setting_user: User object for the setting user or None """ if setting_def.scope == APP_SETTING_SCOPE_PROJECT: - if not request_user.has_perm( - 'projectroles.update_project_settings', project - ): + if request.method == 'GET': + perm = 'projectroles.view_project_settings' + else: + perm = 'projectroles.update_project_settings' + if not request.user.has_perm(perm, project): raise PermissionDenied( 'User lacks permission to access PROJECT scope app ' 'settings in this project' @@ -906,10 +906,18 @@ def check_project_perms( raise serializers.ValidationError( 'No user given for PROJECT_USER setting' ) - if request_user != setting_user and not request_user.is_superuser: + if request.user != setting_user and not request.user.is_superuser: raise PermissionDenied( 'User is not allowed to update settings for other users' ) + if ( + request.method == 'POST' + and not request.user.is_superuser + and app_settings.get('projectroles', 'site_read_only') + ): + raise PermissionDenied( + 'Site in read-only mode, operation not allowed' + ) @classmethod def _get_setting_obj( @@ -1017,9 +1025,7 @@ def get_object(self): setting_user = User.objects.filter( sodar_uuid=self.request.GET['user'] ).first() - self.check_project_perms( - s_def, project, self.request.user, setting_user - ) + self.check_project_perms(s_def, project, self.request, setting_user) # Return new object with default setting if not set return self.get_setting_for_api( @@ -1081,7 +1087,7 @@ def post(self, request, *args, **kwargs): setting_user = User.objects.filter( sodar_uuid=request.data['user'] ).first() - self.check_project_perms(s_def, project, request.user, setting_user) + self.check_project_perms(s_def, project, request, setting_user) # Set setting value with validation, return possible errors try: