diff --git a/arkindex/project/tests/test_acl_mixin.py b/arkindex/project/tests/test_acl_mixin.py index 6ddc9d45f62b9b10273ebec48d69c2d8a9a52686..e3f5d91c76893b5c4ee8e88e888c5907968e5f10 100644 --- a/arkindex/project/tests/test_acl_mixin.py +++ b/arkindex/project/tests/test_acl_mixin.py @@ -2,9 +2,9 @@ from django.contrib.contenttypes.models import ContentType from arkindex.dataimport.models import Repository, RepositoryType from arkindex.documents.models import Corpus -from arkindex.project.mixins import ACLMixin +from arkindex.project.mixins import ACLMixin, NewCorpusACLMixin, RepositoryACLMixin from arkindex.project.tests import FixtureTestCase -from arkindex.users.models import Group, Right, User +from arkindex.users.models import Group, Right, Role, User class TestACLMixin(FixtureTestCase): @@ -15,15 +15,15 @@ class TestACLMixin(FixtureTestCase): Create user and groups with rights on a Corpus and a Repository We use a simple rights configuration for those tests - User1 User2 User3 - | | | / | - 100 10 | 80 | - \ / 90 | 75 - Group1 | Group2 | - / \ | /\ | - 100 75 | 100 50 | - | \ | / \ | - Repo1 Corpus1 Corpus2 + User1 User2 User3 + | | / | / | + | 100 10 | 100 | + 100 \ / 90 | 75 + | Group1 | Group2 | + | / \ | /\ | + | 80 75 | 100 50 | + | / \ | / \ | + Repo1 Corpus1 Corpus2 """ super().setUpClass() @@ -40,16 +40,18 @@ class TestACLMixin(FixtureTestCase): Right.objects.bulk_create([ Right(user=cls.user1, content_object=cls.group1, level=100), + Right(user=cls.user1, content_object=cls.repo1, level=100), Right(user=cls.user2, content_object=cls.group1, level=10), - Right(user=cls.user3, content_object=cls.group2, level=80), Right(user=cls.user2, content_object=cls.corpus1, level=90), + Right(user=cls.user3, content_object=cls.group2, level=100), Right(user=cls.user3, content_object=cls.corpus2, level=75), - Right(group=cls.group1, content_object=cls.repo1, level=100), + Right(group=cls.group1, content_object=cls.repo1, level=80), Right(group=cls.group1, content_object=cls.corpus1, level=75), Right(group=cls.group2, content_object=cls.corpus1, level=100), Right(group=cls.group2, content_object=cls.corpus2, level=50), ]) cls.corpus_type = ContentType.objects.get_for_model(Corpus) + cls.repo_type = ContentType.objects.get_for_model(Repository) cls.group_type = ContentType.objects.get_for_model(Group) def test_right_via_group_restriction(self): @@ -62,13 +64,10 @@ class TestACLMixin(FixtureTestCase): 'corpus_type_id': self.corpus_type.id, 'level': 80, } - with self.assertExactQueries('rights_filter.sql', params=params): + with self.assertExactQueries('corpus_rights_filter.sql', params=params): # List to queryset to fire the DB request - queryset_list = list(acl_mixin.rights_filter(Corpus, 80)) - self.assertCountEqual( - queryset_list, - [self.corpus1] - ) + corpora = list(acl_mixin.rights_filter(Corpus, 80)) + self.assertCountEqual(corpora, [self.corpus1]) def test_right_direct_access(self): # User 2 has a direct access to the above corpus with a level of 90 @@ -81,7 +80,7 @@ class TestACLMixin(FixtureTestCase): 'corpus_type_id': self.corpus_type.id, 'level': 80, } - with self.assertExactQueries('right_access.sql', params=params): + with self.assertExactQueries('corpus_right_access.sql', params=params): has_access = acl_mixin.has_access(self.corpus1, 80) self.assertTrue(has_access) @@ -92,11 +91,89 @@ class TestACLMixin(FixtureTestCase): acl_mixin.has_access(self.corpus1, 80) ) - def test_has_read_access_null(self): - # Only instances with defined level may pass mixin acces check - acl_mixin = ACLMixin(self.user1) - # User1 has the maximun level on the repository but write access level is not declared - self.assertFalse(hasattr(self.repo1, 'WRITE_LEVEL')) - self.assertFalse(acl_mixin.has_write_access(self.repo1)) - # However he has an execute privilege for this repository - self.assertTrue(acl_mixin.has_execute_access(self.repo1)) + def test_corpus_acl_mixin_has_read_access(self): + corpus_acl_mixin = NewCorpusACLMixin(self.user2) + with self.assertNumQueries(1): + read_access = corpus_acl_mixin.has_read_access(self.corpus1) + self.assertTrue(read_access) + + def test_corpus_acl_mixin_has_write_access(self): + # User2 has a direct access to Corpus1 with an adequate level + corpus_acl_mixin = NewCorpusACLMixin(self.user2) + with self.assertNumQueries(1): + write_access = corpus_acl_mixin.has_write_access(self.corpus1) + self.assertTrue(write_access) + + def test_corpus_acl_mixin_has_admin_access(self): + # Admin access requires either to have an admin right or to be a django admin/internal user + admin_access = [ + (self.user, 1, False), + (self.superuser, 0, True), + (self.user1, 1, False), + (self.user2, 1, False), + (self.user3, 1, True) + ] + for user, queries, access_check in admin_access: + corpus_acl_mixin = NewCorpusACLMixin(user) + with self.assertNumQueries(queries): + admin_access = corpus_acl_mixin.has_admin_access(self.corpus1) + self.assertEqual(admin_access, access_check) + + def test_corpus_acl_mixin_readable(self): + # Corpora with the public attribute are accessible by any user + corpus_acl_mixin = NewCorpusACLMixin(self.user1) + params = { + 'user_id': self.user1.id, + 'group_id': self.group2.id, + 'group_type_id': self.group_type.id, + 'corpus_type_id': self.corpus_type.id, + 'level': Role.Guest.value, + } + with self.assertExactQueries('corpus_rights_filter_public.sql', params=params): + corpora = list(corpus_acl_mixin.readable_corpora()) + self.assertCountEqual(corpora, [self.corpus, self.corpus1]) + + def test_corpus_acl_mixin_writable(self): + corpus_acl_mixin = NewCorpusACLMixin(self.user1) + with self.assertNumQueries(1): + corpora = list(corpus_acl_mixin.writable_corpora()) + self.assertCountEqual(corpora, [self.corpus1]) + + def test_repo_acl_mixin_has_read_access(self): + repo_acl_mixin = RepositoryACLMixin(self.user2) + with self.assertNumQueries(1): + read_access = repo_acl_mixin.has_read_access(self.repo1) + self.assertTrue(read_access) + + def test_repo_acl_mixin_has_write_access(self): + repo_acl_mixin = RepositoryACLMixin(self.user2) + with self.assertNumQueries(1): + exec_access = repo_acl_mixin.has_execution_access(self.repo1) + self.assertFalse(exec_access) + + def test_repo_acl_mixin_has_admin_access(self): + # Admin access requires either to have an admin right or to be a django admin/internal user + admin_access = [ + (self.user, 1, False), + (self.superuser, 0, True), + (self.user1, 1, True), + (self.user2, 1, False), + (self.user3, 1, False) + ] + for user, queries, access_check in admin_access: + repo_acl_mixin = RepositoryACLMixin(user) + with self.assertNumQueries(queries): + admin_access = repo_acl_mixin.has_admin_access(self.repo1) + self.assertEqual(admin_access, access_check) + + def test_repo_acl_mixin_readable(self): + repo_acl_mixin = RepositoryACLMixin(self.user2) + with self.assertNumQueries(1): + repos = list(repo_acl_mixin.readable_repositories()) + self.assertCountEqual(repos, [self.repo1]) + + def test_repo_acl_mixin_executable(self): + repo_acl_mixin = RepositoryACLMixin(self.user2) + with self.assertNumQueries(1): + repos = list(repo_acl_mixin.executable_repositories()) + self.assertEqual(repos, []) diff --git a/arkindex/sql_validation/right_access.sql b/arkindex/sql_validation/corpus_right_access.sql similarity index 100% rename from arkindex/sql_validation/right_access.sql rename to arkindex/sql_validation/corpus_right_access.sql diff --git a/arkindex/sql_validation/rights_filter.sql b/arkindex/sql_validation/corpus_rights_filter.sql similarity index 100% rename from arkindex/sql_validation/rights_filter.sql rename to arkindex/sql_validation/corpus_rights_filter.sql diff --git a/arkindex/sql_validation/corpus_rights_filter_public.sql b/arkindex/sql_validation/corpus_rights_filter_public.sql new file mode 100644 index 0000000000000000000000000000000000000000..549bde046d62949723f617f208c9e97d5ed86ff7 --- /dev/null +++ b/arkindex/sql_validation/corpus_rights_filter_public.sql @@ -0,0 +1,18 @@ +SELECT DISTINCT "documents_corpus"."created", + "documents_corpus"."updated", + "documents_corpus"."id", + "documents_corpus"."name", + "documents_corpus"."description", + "documents_corpus"."repository_id", + "documents_corpus"."public", + LEAST("users_right"."level", T5."level") AS "max_level" +FROM "documents_corpus" +LEFT OUTER JOIN "users_right" ON ("documents_corpus"."id" = "users_right"."content_id" + AND ("users_right"."content_type_id" = {corpus_type_id})) +LEFT OUTER JOIN "users_group" ON ("users_right"."group_id" = "users_group"."id") +LEFT OUTER JOIN "users_right" T5 ON ("users_group"."id" = T5."content_id" + AND (T5."content_type_id" = {group_type_id})) +WHERE ((("users_right"."user_id" = {user_id} + OR T5."user_id" = {user_id}) + AND LEAST("users_right"."level", T5."level") >= {level}) + OR "documents_corpus"."public")