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")