From 0455c73e498e93ba23a7e5b728af6d7d11867ccb Mon Sep 17 00:00:00 2001
From: Valentin Rigal <rigal@teklia.com>
Date: Thu, 10 Dec 2020 13:29:22 +0100
Subject: [PATCH] Mixin tests

---
 arkindex/project/tests/test_acl_mixin.py  | 102 ++++++++++++++++++++++
 arkindex/sql_validation/right_access.sql  |  13 +++
 arkindex/sql_validation/rights_filter.sql |  17 ++++
 3 files changed, 132 insertions(+)
 create mode 100644 arkindex/project/tests/test_acl_mixin.py
 create mode 100644 arkindex/sql_validation/right_access.sql
 create mode 100644 arkindex/sql_validation/rights_filter.sql

diff --git a/arkindex/project/tests/test_acl_mixin.py b/arkindex/project/tests/test_acl_mixin.py
new file mode 100644
index 0000000000..6ddc9d45f6
--- /dev/null
+++ b/arkindex/project/tests/test_acl_mixin.py
@@ -0,0 +1,102 @@
+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.tests import FixtureTestCase
+from arkindex.users.models import Group, Right, User
+
+
+class TestACLMixin(FixtureTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        r"""
+        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
+        """
+
+        super().setUpClass()
+        cls.user1 = User.objects.create_user('user1@test.test', display_name='User1')
+        cls.user2 = User.objects.create_user('user2@test.test', display_name='User2')
+        cls.user3 = User.objects.create_user('user3@test.test', display_name='User3')
+
+        cls.group1 = Group.objects.create(name='Group1')
+        cls.group2 = Group.objects.create(name='Group2')
+
+        cls.repo1 = Repository.objects.create(type=RepositoryType.Worker, url='http://repo1')
+        cls.corpus1 = Corpus.objects.create(name="Corpus1")
+        cls.corpus2 = Corpus.objects.create(name="Corpus2")
+
+        Right.objects.bulk_create([
+            Right(user=cls.user1, content_object=cls.group1, 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.corpus2, level=75),
+            Right(group=cls.group1, content_object=cls.repo1, level=100),
+            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.group_type = ContentType.objects.get_for_model(Group)
+
+    def test_right_via_group_restriction(self):
+        # User rights on corpora via a group are restricted to the group level
+        acl_mixin = ACLMixin(self.user3)
+        params = {
+            'user_id': self.user3.id,
+            'group_id': self.group2.id,
+            'group_type_id': self.group_type.id,
+            'corpus_type_id': self.corpus_type.id,
+            'level': 80,
+        }
+        with self.assertExactQueries('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]
+        )
+
+    def test_right_direct_access(self):
+        # User 2 has a direct access to the above corpus with a level of 90
+        acl_mixin = ACLMixin(self.user2)
+        params = {
+            'user_id': self.user2.id,
+            'group_id': self.group2.id,
+            'corpus_id': self.corpus1.id,
+            'group_type_id': self.group_type.id,
+            'corpus_type_id': self.corpus_type.id,
+            'level': 80,
+        }
+        with self.assertExactQueries('right_access.sql', params=params):
+            has_access = acl_mixin.has_access(self.corpus1, 80)
+        self.assertTrue(has_access)
+
+    def test_right_group_members_restriction(self):
+        # User rights on corpora via a group are restricted to user level inside the group
+        acl_mixin = ACLMixin(self.user1)
+        self.assertFalse(
+            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))
diff --git a/arkindex/sql_validation/right_access.sql b/arkindex/sql_validation/right_access.sql
new file mode 100644
index 0000000000..b04ae0a56f
--- /dev/null
+++ b/arkindex/sql_validation/right_access.sql
@@ -0,0 +1,13 @@
+SELECT (1) AS "a"
+FROM "users_right"
+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"."content_id" = '{corpus_id}'::uuid
+       AND "users_right"."content_type_id" = {corpus_type_id}
+       AND (("users_right"."user_id" = {user_id}
+             AND "users_right"."level" >= {level})
+            OR (T5."user_id" = {user_id}
+                AND "users_right"."level" >= {level}
+                AND T5."level" >= {level})))
+LIMIT 1
diff --git a/arkindex/sql_validation/rights_filter.sql b/arkindex/sql_validation/rights_filter.sql
new file mode 100644
index 0000000000..1ae974fc3a
--- /dev/null
+++ b/arkindex/sql_validation/rights_filter.sql
@@ -0,0 +1,17 @@
+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"
+INNER 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})
-- 
GitLab