diff --git a/invenio_users_resources/config.py b/invenio_users_resources/config.py index a81b719..823c1aa 100644 --- a/invenio_users_resources/config.py +++ b/invenio_users_resources/config.py @@ -124,13 +124,15 @@ USERS_RESOURCES_ADMINISTRATION_ENABLED = True """Enable the user administration""" +USERS_RESOURCES_USE_MODERATION_LOCK = True +"""Enable or disable using a per-user lock for moderation actions.""" + USERS_RESOURCES_MODERATION_LOCK_DEFAULT_TIMEOUT = 30 """Default timeout, in seconds, to lock a user when moderating.""" USERS_RESOURCES_MODERATION_LOCK_RENEWAL_TIMEOUT = 120 """Renewal timeout, in seconds, to increase the lock time for a user when moderating.""" - USERS_RESOURCES_DOMAINS_SEARCH = { "sort": [ "bestmatch", diff --git a/invenio_users_resources/services/users/config.py b/invenio_users_resources/services/users/config.py index b280747..660cdd1 100644 --- a/invenio_users_resources/services/users/config.py +++ b/invenio_users_resources/services/users/config.py @@ -178,6 +178,9 @@ class UsersServiceConfig(RecordServiceConfig, ConfiguratorMixin): # leaking account information. search = UserSearchOptions + # Moderation lock + use_moderation_lock = FromConfig("USERS_RESOURCES_USE_MODERATION_LOCK", True) + # For admin user search_all = FromConfigSearchOptions( "USERS_RESOURCES_SEARCH", diff --git a/invenio_users_resources/services/users/service.py b/invenio_users_resources/services/users/service.py index 3b69af2..af67139 100644 --- a/invenio_users_resources/services/users/service.py +++ b/invenio_users_resources/services/users/service.py @@ -143,7 +143,8 @@ def block(self, identity, id_, uow=None): raise ValidationError("User is already blocked.") # Throws if not acquired - ModerationMutex(id_).acquire() + self._acquire_moderation_lock(id_) + user.block() uow.register(RecordCommitOp(user, indexer=self.indexer, index_refresh=True)) @@ -167,7 +168,8 @@ def restore(self, identity, id_, uow=None): raise ValidationError("User is not blocked.") # Throws if not acquired - ModerationMutex(id_).acquire() + self._acquire_moderation_lock(id_) + user.activate() # User is blocked from now on, "after" actions are executed separately. uow.register(RecordCommitOp(user, indexer=self.indexer, index_refresh=True)) @@ -178,6 +180,11 @@ def restore(self, identity, id_, uow=None): ) return True + def _acquire_moderation_lock(self, user_id): + """Acquire the moderation lock for a specific user.""" + if self.config.use_moderation_lock: + ModerationMutex(user_id).acquire() + @unit_of_work() def approve(self, identity, id_, uow=None): """Approves a user.""" @@ -192,7 +199,8 @@ def approve(self, identity, id_, uow=None): raise ValidationError("User is already verified.") # Throws if not acquired - ModerationMutex(id_).acquire() + self._acquire_moderation_lock(id_) + user.verify() uow.register(RecordCommitOp(user, indexer=self.indexer, index_refresh=True)) diff --git a/invenio_users_resources/services/users/tasks.py b/invenio_users_resources/services/users/tasks.py index 6025d7b..f3ab574 100644 --- a/invenio_users_resources/services/users/tasks.py +++ b/invenio_users_resources/services/users/tasks.py @@ -9,6 +9,8 @@ """Users service tasks.""" +from contextlib import ExitStack + from celery import shared_task from flask import current_app from invenio_records_resources.services.uow import UnitOfWork @@ -78,8 +80,10 @@ def execute_moderation_actions(user_id=None, action=None): """ actions = current_actions_registry.get(action, []) - with ModerationMutex(user_id) as lock: - lock.acquire_or_renew(renewal_timeout) + with ExitStack() as stack: + if current_users_service.config.use_moderation_lock: + lock = stack.enter_context(ModerationMutex(user_id)) + lock.acquire_or_renew(renewal_timeout) # Create a uow that is shared by all the callables uow = UnitOfWork()