2323
2424from openedx_authz .engine .adapter import ExtendedAdapter
2525
26+ try :
27+ from cms .djangoapps .contentstore .toggles import libraries_v2_enabled
28+ except ImportError :
29+ # If the CMS is not available, define a dummy toggle that is always enabled
30+ class DummyToggle :
31+ @staticmethod
32+ def is_enabled ():
33+ return True
34+
35+ libraries_v2_enabled = DummyToggle ()
36+
37+
2638logger = logging .getLogger (__name__ )
2739
2840
@@ -57,6 +69,84 @@ def __new__(cls):
5769 cls ._enforcer = cls ._initialize_enforcer ()
5870 return cls ._enforcer
5971
72+ @classmethod
73+ def configure_enforcer_auto_loading (cls , auto_load_policy_interval : int = None ):
74+ """Enable auto-load policy and auto-save on the enforcer.
75+
76+ This method ensures that the singleton enforcer instance is created
77+ and ready for use.
78+
79+ Returns:
80+ None
81+ """
82+ if not cls ._enforcer .is_auto_loading_running ():
83+ cls ._enforcer .start_auto_load_policy (auto_load_policy_interval )
84+
85+ @classmethod
86+ def is_auto_save_enabled (cls ) -> bool :
87+ """Check if auto-save is currently enabled on the enforcer.
88+
89+ Returns:
90+ bool: True if auto-save is enabled, False otherwise
91+ """
92+ if cls ._enforcer is None :
93+ return False
94+ return cls ._enforcer ._e .auto_save # pylint: disable=protected-access
95+
96+ @classmethod
97+ def configure_enforcer_auto_save (cls , auto_save_policy : bool ):
98+ """Configure auto-save on the enforcer.
99+
100+ This method ensures that auto-save is enabled or disabled based on
101+ the auto_save_policy parameter.
102+
103+ Args:
104+ auto_save_policy: True to enable auto-save, False to disable
105+
106+ Returns:
107+ None
108+ """
109+ if cls .is_auto_save_enabled () != auto_save_policy :
110+ cls ._enforcer .enable_auto_save (auto_save_policy )
111+
112+ @classmethod
113+ def deactivate_enforcer (cls ):
114+ """Deactivate the current enforcer instance, if any.
115+
116+ This method stops the auto-load policy thread. It can be used in testing
117+ or when re-initialization of the enforcer is needed. IT DOES NOT
118+ clear the singleton instance to avoid initializing it again unintentionally.
119+
120+ Returns:
121+ None
122+ """
123+ if cls ._enforcer is not None :
124+ try :
125+ cls ._enforcer .stop_auto_load_policy ()
126+ cls ._enforcer .enable_auto_save (False )
127+ except Exception as e : # pylint: disable=broad-exception-caught
128+ logger .error (f"Error stopping auto-load policy thread: { e } " )
129+
130+ @classmethod
131+ def configure_enforcer_auto_save_and_load (cls ):
132+ """Enable auto-load policy and auto-save on the enforcer.
133+
134+ This method ensures that the singleton enforcer instance is configured
135+ for auto-load and auto-save based on settings.
136+
137+ Returns:
138+ None
139+ """
140+ auto_load_policy_interval = getattr (settings , "CASBIN_AUTO_LOAD_POLICY_INTERVAL" , 0 )
141+ auto_save_policy = getattr (settings , "CASBIN_AUTO_SAVE_POLICY" , True )
142+
143+ if auto_load_policy_interval > 0 :
144+ cls .configure_enforcer_auto_loading (auto_load_policy_interval )
145+ else :
146+ logger .warning ("CASBIN_AUTO_LOAD_POLICY_INTERVAL is not set or zero; auto-load is disabled." )
147+
148+ cls .configure_enforcer_auto_save (auto_save_policy )
149+
60150 @classmethod
61151 def get_enforcer (cls ) -> SyncedEnforcer :
62152 """Get the enforcer instance, creating it if needed.
@@ -66,10 +156,21 @@ def get_enforcer(cls) -> SyncedEnforcer:
66156 """
67157 if cls ._enforcer is None :
68158 cls ._enforcer = cls ._initialize_enforcer ()
159+
160+ # HACK: This code block will only be useful when in Ulmo to deactivate
161+ # the enforcer when the new library experience is disabled. It should be
162+ # removed for the next release cycle.
163+ # When replaced, we will only need to configure the enforcer here. Which
164+ # is in charge of enabling/disabling auto-load and auto-save.
165+ if libraries_v2_enabled .is_enabled ():
166+ cls .configure_enforcer_auto_save_and_load ()
167+ else :
168+ cls .deactivate_enforcer ()
169+
69170 return cls ._enforcer
70171
71- @staticmethod
72- def _initialize_enforcer () -> SyncedEnforcer :
172+ @classmethod
173+ def _initialize_enforcer (cls ) -> SyncedEnforcer :
73174 """
74175 Create and configure the Casbin SyncedEnforcer instance.
75176
@@ -93,12 +194,5 @@ def _initialize_enforcer() -> SyncedEnforcer:
93194
94195 adapter = ExtendedAdapter ()
95196 enforcer = SyncedEnforcer (settings .CASBIN_MODEL , adapter )
96- auto_load_policy_interval = getattr (settings , "CASBIN_AUTO_LOAD_POLICY_INTERVAL" , 0 )
97- if auto_load_policy_interval > 0 :
98- enforcer .start_auto_load_policy (auto_load_policy_interval )
99- enforcer .enable_auto_save (True )
100- else :
101- # Disable auto-save to prevent unnecessary database writes
102- enforcer .enable_auto_save (False )
103197
104198 return enforcer
0 commit comments