diff --git a/passbook/core/templatetags/passbook_user_settings.py b/passbook/core/templatetags/passbook_user_settings.py index 7c0287eec..39b7ee6b6 100644 --- a/passbook/core/templatetags/passbook_user_settings.py +++ b/passbook/core/templatetags/passbook_user_settings.py @@ -16,10 +16,10 @@ register = template.Library() # pylint: disable=unused-argument def user_stages(context: RequestContext) -> List[UIUserSettings]: """Return list of all stages which apply to user""" - _all_stages: Iterable[Stage] = Stage.objects.all().select_subclasses() + _all_stages: Iterable[Stage] = Stage.__subclasses__() matching_stages: List[UIUserSettings] = [] for stage in _all_stages: - user_settings = stage.ui_user_settings + user_settings = stage.ui_user_settings(context) if not user_settings: continue matching_stages.append(user_settings) diff --git a/passbook/flows/apps.py b/passbook/flows/apps.py index f31f699da..b5eeb0666 100644 --- a/passbook/flows/apps.py +++ b/passbook/flows/apps.py @@ -13,5 +13,5 @@ class PassbookFlowsConfig(AppConfig): verbose_name = "passbook Flows" def ready(self): - """Load policy cache clearing signals""" + """Flow signals that clear the cache""" import_module("passbook.flows.signals") diff --git a/passbook/flows/models.py b/passbook/flows/models.py index d049a6885..2e7a2eed5 100644 --- a/passbook/flows/models.py +++ b/passbook/flows/models.py @@ -7,6 +7,7 @@ from django.http import HttpRequest from django.utils.translation import gettext_lazy as _ from model_utils.managers import InheritanceManager from structlog import get_logger +from django.template.context import RequestContext from passbook.core.types import UIUserSettings from passbook.lib.utils.reflection import class_to_path @@ -15,6 +16,13 @@ from passbook.policies.models import PolicyBindingModel LOGGER = get_logger() +class NotConfiguredAction(models.TextChoices): + """Decides how the FlowExecutor should proceed when a stage isn't configured""" + + SKIP = "skip" + # CONFIGURE = "configure" + + class FlowDesignation(models.TextChoices): """Designation of what a Flow should be used for. At a later point, this should be replaced by a database entry.""" @@ -25,7 +33,7 @@ class FlowDesignation(models.TextChoices): ENROLLMENT = "enrollment" UNRENOLLMENT = "unenrollment" RECOVERY = "recovery" - PASSWORD_CHANGE = "password_change" # nosec # noqa + USER_SETTINGS = "user_settings" class Stage(models.Model): @@ -40,8 +48,8 @@ class Stage(models.Model): type = "" form = "" - @property - def ui_user_settings(self) -> Optional[UIUserSettings]: + @staticmethod + def ui_user_settings(context: RequestContext) -> Optional[UIUserSettings]: """Entrypoint to integrate with User settings. Can either return None if no user settings are available, or an instanace of UIUserSettings.""" return None diff --git a/passbook/flows/signals.py b/passbook/flows/signals.py index d4353ef94..e725477c9 100644 --- a/passbook/flows/signals.py +++ b/passbook/flows/signals.py @@ -7,6 +7,12 @@ from structlog import get_logger LOGGER = get_logger() +def delete_cache_prefix(prefix: str) -> int: + """Delete keys prefixed with `prefix` and return count of deleted keys.""" + keys = cache.keys(prefix) + cache.delete_many(keys) + return len(keys) + @receiver(post_save) # pylint: disable=unused-argument def invalidate_flow_cache(sender, instance, **_): @@ -15,17 +21,14 @@ def invalidate_flow_cache(sender, instance, **_): from passbook.flows.planner import cache_key if isinstance(instance, Flow): - LOGGER.debug("Invalidating Flow cache", flow=instance) - cache.delete(f"{cache_key(instance)}*") + total = delete_cache_prefix(f"{cache_key(instance)}*") + LOGGER.debug("Invalidating Flow cache", flow=instance, len=total) if isinstance(instance, FlowStageBinding): - LOGGER.debug("Invalidating Flow cache from FlowStageBinding", binding=instance) - cache.delete(f"{cache_key(instance.flow)}*") + total = delete_cache_prefix(f"{cache_key(instance.flow)}*") + LOGGER.debug("Invalidating Flow cache from FlowStageBinding", binding=instance, len=total) if isinstance(instance, Stage): - LOGGER.debug("Invalidating Flow cache from Stage", stage=instance) total = 0 for binding in FlowStageBinding.objects.filter(stage=instance): prefix = cache_key(binding.flow) - keys = cache.keys(f"{prefix}*") - total += len(keys) - cache.delete_many(keys) - LOGGER.debug("Deleted keys", len=total) + total += delete_cache_prefix(f"{prefix}*") + LOGGER.debug("Invalidating Flow cache from Stage", stage=instance, len=total) diff --git a/passbook/flows/urls.py b/passbook/flows/urls.py index c1a50a526..ca83335f7 100644 --- a/passbook/flows/urls.py +++ b/passbook/flows/urls.py @@ -36,11 +36,6 @@ urlpatterns = [ ToDefaultFlow.as_view(designation=FlowDesignation.UNRENOLLMENT), name="default-unenrollment", ), - path( - "-/default/password_change/", - ToDefaultFlow.as_view(designation=FlowDesignation.PASSWORD_CHANGE), - name="default-password-change", - ), path("b//", FlowExecutorView.as_view(), name="flow-executor"), path( "/", FlowExecutorShellView.as_view(), name="flow-executor-shell"