1212from django .core .cache import cache
1313from django .core .exceptions import ValidationError
1414from django .core .files .storage import default_storage
15+ from django .test .utils import override_settings
1516from django .utils import timezone
1617
1718import pytest
@@ -124,6 +125,9 @@ def test_models_documents_soft_delete(depth):
124125# get_abilities
125126
126127
128+ @override_settings (
129+ AI_ALLOW_REACH_FROM = random .choice (["public" , "authenticated" , "restricted" ])
130+ )
127131@pytest .mark .parametrize (
128132 "is_authenticated,reach,role" ,
129133 [
@@ -175,6 +179,9 @@ def test_models_documents_get_abilities_forbidden(
175179 assert document .get_abilities (user ) == expected_abilities
176180
177181
182+ @override_settings (
183+ AI_ALLOW_REACH_FROM = random .choice (["public" , "authenticated" , "restricted" ])
184+ )
178185@pytest .mark .parametrize (
179186 "is_authenticated,reach" ,
180187 [
@@ -243,8 +250,8 @@ def test_models_documents_get_abilities_editor(
243250 expected_abilities = {
244251 "accesses_manage" : False ,
245252 "accesses_view" : False ,
246- "ai_transform" : True ,
247- "ai_translate" : True ,
253+ "ai_transform" : is_authenticated ,
254+ "ai_translate" : is_authenticated ,
248255 "attachment_upload" : True ,
249256 "children_create" : is_authenticated ,
250257 "children_list" : True ,
@@ -271,6 +278,9 @@ def test_models_documents_get_abilities_editor(
271278 assert all (value is False for value in document .get_abilities (user ).values ())
272279
273280
281+ @override_settings (
282+ AI_ALLOW_REACH_FROM = random .choice (["public" , "authenticated" , "restricted" ])
283+ )
274284def test_models_documents_get_abilities_owner (django_assert_num_queries ):
275285 """Check abilities returned for the owner of a document."""
276286 user = factories .UserFactory ()
@@ -300,12 +310,16 @@ def test_models_documents_get_abilities_owner(django_assert_num_queries):
300310 }
301311 with django_assert_num_queries (1 ):
302312 assert document .get_abilities (user ) == expected_abilities
313+
303314 document .soft_delete ()
304315 document .refresh_from_db ()
305316 expected_abilities ["move" ] = False
306317 assert document .get_abilities (user ) == expected_abilities
307318
308319
320+ @override_settings (
321+ AI_ALLOW_REACH_FROM = random .choice (["public" , "authenticated" , "restricted" ])
322+ )
309323def test_models_documents_get_abilities_administrator (django_assert_num_queries ):
310324 """Check abilities returned for the administrator of a document."""
311325 user = factories .UserFactory ()
@@ -335,11 +349,15 @@ def test_models_documents_get_abilities_administrator(django_assert_num_queries)
335349 }
336350 with django_assert_num_queries (1 ):
337351 assert document .get_abilities (user ) == expected_abilities
352+
338353 document .soft_delete ()
339354 document .refresh_from_db ()
340355 assert all (value is False for value in document .get_abilities (user ).values ())
341356
342357
358+ @override_settings (
359+ AI_ALLOW_REACH_FROM = random .choice (["public" , "authenticated" , "restricted" ])
360+ )
343361def test_models_documents_get_abilities_editor_user (django_assert_num_queries ):
344362 """Check abilities returned for the editor of a document."""
345363 user = factories .UserFactory ()
@@ -369,23 +387,31 @@ def test_models_documents_get_abilities_editor_user(django_assert_num_queries):
369387 }
370388 with django_assert_num_queries (1 ):
371389 assert document .get_abilities (user ) == expected_abilities
390+
372391 document .soft_delete ()
373392 document .refresh_from_db ()
374393 assert all (value is False for value in document .get_abilities (user ).values ())
375394
376395
377- def test_models_documents_get_abilities_reader_user (django_assert_num_queries ):
396+ @pytest .mark .parametrize ("ai_access_setting" , ["public" , "authenticated" , "restricted" ])
397+ def test_models_documents_get_abilities_reader_user (
398+ ai_access_setting , django_assert_num_queries
399+ ):
378400 """Check abilities returned for the reader of a document."""
379401 user = factories .UserFactory ()
380402 document = factories .DocumentFactory (users = [(user , "reader" )])
403+
381404 access_from_link = (
382405 document .link_reach != "restricted" and document .link_role == "editor"
383406 )
407+
384408 expected_abilities = {
385409 "accesses_manage" : False ,
386410 "accesses_view" : True ,
387- "ai_transform" : access_from_link ,
388- "ai_translate" : access_from_link ,
411+ # If you get your editor rights from the link role and not your access role
412+ # You should not access AI if it's restricted to users with specific access
413+ "ai_transform" : access_from_link and ai_access_setting != "restricted" ,
414+ "ai_translate" : access_from_link and ai_access_setting != "restricted" ,
389415 "attachment_upload" : access_from_link ,
390416 "children_create" : access_from_link ,
391417 "children_list" : True ,
@@ -404,11 +430,14 @@ def test_models_documents_get_abilities_reader_user(django_assert_num_queries):
404430 "versions_list" : True ,
405431 "versions_retrieve" : True ,
406432 }
407- with django_assert_num_queries (1 ):
408- assert document .get_abilities (user ) == expected_abilities
409- document .soft_delete ()
410- document .refresh_from_db ()
411- assert all (value is False for value in document .get_abilities (user ).values ())
433+
434+ with override_settings (AI_ALLOW_REACH_FROM = ai_access_setting ):
435+ with django_assert_num_queries (1 ):
436+ assert document .get_abilities (user ) == expected_abilities
437+
438+ document .soft_delete ()
439+ document .refresh_from_db ()
440+ assert all (value is False for value in document .get_abilities (user ).values ())
412441
413442
414443def test_models_documents_get_abilities_preset_role (django_assert_num_queries ):
@@ -446,6 +475,44 @@ def test_models_documents_get_abilities_preset_role(django_assert_num_queries):
446475 }
447476
448477
478+ @override_settings (AI_ALLOW_REACH_FROM = "public" )
479+ @pytest .mark .parametrize (
480+ "is_authenticated,reach" ,
481+ [
482+ (True , "public" ),
483+ (False , "public" ),
484+ (True , "authenticated" ),
485+ ],
486+ )
487+ def test_models_document_get_abilities_ai_access_authenticated (is_authenticated , reach ):
488+ """Validate AI abilities when AI is available to any anonymous user with editor rights."""
489+ user = factories .UserFactory () if is_authenticated else AnonymousUser ()
490+ document = factories .DocumentFactory (link_reach = reach , link_role = "editor" )
491+
492+ abilities = document .get_abilities (user )
493+ assert abilities ["ai_transform" ] is True
494+ assert abilities ["ai_translate" ] is True
495+
496+
497+ @override_settings (AI_ALLOW_REACH_FROM = "authenticated" )
498+ @pytest .mark .parametrize (
499+ "is_authenticated,reach" ,
500+ [
501+ (True , "public" ),
502+ (False , "public" ),
503+ (True , "authenticated" ),
504+ ],
505+ )
506+ def test_models_document_get_abilities_ai_access_public (is_authenticated , reach ):
507+ """Validate AI abilities when AI is available only to authenticated users with editor rights."""
508+ user = factories .UserFactory () if is_authenticated else AnonymousUser ()
509+ document = factories .DocumentFactory (link_reach = reach , link_role = "editor" )
510+
511+ abilities = document .get_abilities (user )
512+ assert abilities ["ai_transform" ] == is_authenticated
513+ assert abilities ["ai_translate" ] == is_authenticated
514+
515+
449516def test_models_documents_get_versions_slice_pagination (settings ):
450517 """
451518 The "get_versions_slice" method should allow navigating all versions of
0 commit comments