@@ -882,6 +882,82 @@ def test_updating_root_propagates_to_descendants(self):
882882 self .assertEqual (child .visibility , GroupProfile .Visibility .PRIVATE )
883883 self .assertEqual (grandchild .visibility , GroupProfile .Visibility .PRIVATE )
884884
885+ def test_save_propagates_visibility_to_descendants (self ):
886+ """Changing visibility via save() (as in admin) propagates to descendants."""
887+ parent_group = Group .objects .create (name = "Parent" )
888+ parent = GroupProfile .add_root (
889+ group = parent_group ,
890+ slug = "parent" ,
891+ visibility = GroupProfile .Visibility .PUBLIC ,
892+ )
893+
894+ child_group = Group .objects .create (name = "Child" )
895+ child = parent .add_child (
896+ group = child_group ,
897+ slug = "child" ,
898+ )
899+
900+ grandchild_group = Group .objects .create (name = "Grandchild" )
901+ grandchild = child .add_child (
902+ group = grandchild_group ,
903+ slug = "grandchild" ,
904+ )
905+
906+ # All should be PUBLIC initially
907+ self .assertEqual (parent .visibility , GroupProfile .Visibility .PUBLIC )
908+ child .refresh_from_db ()
909+ grandchild .refresh_from_db ()
910+ self .assertEqual (child .visibility , GroupProfile .Visibility .PUBLIC )
911+ self .assertEqual (grandchild .visibility , GroupProfile .Visibility .PUBLIC )
912+
913+ # Change root to PRIVATE via save() (simulates admin form submission)
914+ parent .visibility = GroupProfile .Visibility .PRIVATE
915+ parent .save ()
916+
917+ # All descendants should now be PRIVATE
918+ parent .refresh_from_db ()
919+ child .refresh_from_db ()
920+ grandchild .refresh_from_db ()
921+ self .assertEqual (parent .visibility , GroupProfile .Visibility .PRIVATE )
922+ self .assertEqual (child .visibility , GroupProfile .Visibility .PRIVATE )
923+ self .assertEqual (grandchild .visibility , GroupProfile .Visibility .PRIVATE )
924+
925+ def test_cannot_change_subgroup_visibility (self ):
926+ """Attempting to change subgroup visibility is overridden by parent."""
927+ parent_group = Group .objects .create (name = "Parent" )
928+ parent = GroupProfile .add_root (
929+ group = parent_group ,
930+ slug = "parent" ,
931+ visibility = GroupProfile .Visibility .PRIVATE ,
932+ )
933+
934+ child_group = Group .objects .create (name = "Child" )
935+ child = parent .add_child (
936+ group = child_group ,
937+ slug = "child" ,
938+ )
939+
940+ # Verify child is PRIVATE (inherited)
941+ child .refresh_from_db ()
942+ self .assertEqual (child .visibility , GroupProfile .Visibility .PRIVATE )
943+
944+ # Try to change child to PUBLIC (simulates admin form submission)
945+ child .visibility = GroupProfile .Visibility .PUBLIC
946+ child .save ()
947+
948+ # Refresh and verify it's still PRIVATE (overridden by parent)
949+ child .refresh_from_db ()
950+ self .assertEqual (child .visibility , GroupProfile .Visibility .PRIVATE )
951+
952+ # Verify descendants also remain PRIVATE
953+ grandchild_group = Group .objects .create (name = "Grandchild" )
954+ grandchild = child .add_child (
955+ group = grandchild_group ,
956+ slug = "grandchild" ,
957+ )
958+ grandchild .refresh_from_db ()
959+ self .assertEqual (grandchild .visibility , GroupProfile .Visibility .PRIVATE )
960+
885961
886962class ModeratedVisibilityTests (TestCase ):
887963 """Test MODERATED visibility with nested groups."""
0 commit comments