• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

safe-global / safe-config-service / 7528317545

11 Jan 2024 03:28PM UTC coverage: 99.757% (-0.02%) from 99.772%
7528317545

push

github

web-flow
Invalidate safe apps for removed chains (#1020)

- Decouples `post_delete` signal from the affected flow, as it remains as it is.
- Change the handling of `post_save` signal to handle `pre_save` signal, to have access to the instance's `Chain` list before the update is made.
- Both the `Chain` items related to the `SafeApp` before and after the update are stored in a `Set` to avoid repetitions. Hooks are dispatched for all the `Chain` items in the set.

4923 of 4935 relevant lines covered (99.76%)

1.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.04
/src/safe_apps/signals.py
1
import logging
1✔
2
from typing import Any
1✔
3

4
from django.conf import settings
1✔
5
from django.core.cache import caches
1✔
6
from django.db.models.signals import (
1✔
7
    m2m_changed,
8
    post_delete,
9
    post_save,
10
    pre_delete,
11
    pre_save,
12
)
13
from django.dispatch import receiver
1✔
14

15
from clients.safe_client_gateway import HookEvent, flush, hook_event
1✔
16

17
from .models import Feature, Provider, SafeApp, Tag
1✔
18

19
logger = logging.getLogger(__name__)
1✔
20

21

22
@receiver(pre_save, sender=SafeApp)
1✔
23
def on_safe_app_update(sender: SafeApp, instance: SafeApp, **kwargs: Any) -> None:
1✔
24
    logger.info("Clearing safe-apps cache")
1✔
25
    caches["safe-apps"].clear()
1✔
26
    if settings.FF_HOOK_EVENTS:
1✔
27
        chain_ids = set(instance.chain_ids)
1✔
28
        if instance.app_id is not None:  # existing SafeApp being updated
1✔
29
            previous = SafeApp.objects.filter(app_id=instance.app_id).first()
1✔
30
            if previous is not None:
1✔
31
                chain_ids.update(previous.chain_ids)
1✔
32
        for chain_id in chain_ids:
1✔
33
            hook_event(
1✔
34
                HookEvent(type=HookEvent.Type.SAFE_APPS_UPDATE, chain_id=chain_id)
1✔
35
            )
36
    else:
×
37
        flush()
1✔
38

39

40
@receiver(post_delete, sender=SafeApp)
1✔
41
def on_safe_app_delete(sender: SafeApp, instance: SafeApp, **kwargs: Any) -> None:
1✔
42
    logger.info("Clearing safe-apps cache")
1✔
43
    caches["safe-apps"].clear()
1✔
44
    if settings.FF_HOOK_EVENTS:
1✔
45
        for chain_id in instance.chain_ids:
1✔
46
            hook_event(
1✔
47
                HookEvent(type=HookEvent.Type.SAFE_APPS_UPDATE, chain_id=chain_id)
1✔
48
            )
49
    else:
×
50
        flush()
1✔
51

52

53
@receiver(post_save, sender=Provider)
1✔
54
@receiver(post_delete, sender=Provider)
1✔
55
def on_provider_update(sender: Provider, instance: Provider, **kwargs: Any) -> None:
1✔
56
    logger.info("Clearing safe-apps cache")
1✔
57
    caches["safe-apps"].clear()
1✔
58
    if settings.FF_HOOK_EVENTS:
1✔
59
        for safe_app in instance.safeapp_set.all():
1✔
60
            for chain_id in safe_app.chain_ids:
1✔
61
                hook_event(
1✔
62
                    HookEvent(type=HookEvent.Type.SAFE_APPS_UPDATE, chain_id=chain_id)
1✔
63
                )
64
    else:
×
65
        flush()
1✔
66

67

68
# pre_delete is used because on pre_delete the model still has safe_apps
69
# which is not the case on post_delete
70
@receiver(post_save, sender=Tag)
1✔
71
@receiver(pre_delete, sender=Tag)
1✔
72
def on_tag_update(sender: Tag, instance: Tag, **kwargs: Any) -> None:
1✔
73
    logger.info("Clearing safe-apps cache")
1✔
74
    caches["safe-apps"].clear()
1✔
75
    if settings.FF_HOOK_EVENTS:
1✔
76
        for safe_app in instance.safe_apps.all():
1✔
77
            for chain_id in safe_app.chain_ids:
1✔
78
                hook_event(
1✔
79
                    HookEvent(type=HookEvent.Type.SAFE_APPS_UPDATE, chain_id=chain_id)
1✔
80
                )
81
    else:
×
82
        flush()
1✔
83

84

85
@receiver(m2m_changed, sender=Tag.safe_apps.through)
1✔
86
def on_tag_chains_update(
1✔
87
    sender: Tag, instance: Tag, action: str, pk_set: set[int], **kwargs: Any
1✔
88
) -> None:
1✔
89
    logger.info("TagChains update. Triggering CGW webhook")
1✔
90
    caches["safe-apps"].clear()
1✔
91
    if action == "post_add" or action == "post_remove":
1✔
92
        if settings.FF_HOOK_EVENTS:
1✔
93
            chain_ids = set()
1✔
94
            for safe_app in SafeApp.objects.filter(app_id__in=pk_set):
1✔
95
                for chain_id in safe_app.chain_ids:
1✔
96
                    chain_ids.add(chain_id)
1✔
97
            for chain_id in chain_ids:
1✔
98
                hook_event(
1✔
99
                    HookEvent(type=HookEvent.Type.SAFE_APPS_UPDATE, chain_id=chain_id)
1✔
100
                )
101
        else:
102
            flush()
1✔
103

104

105
# pre_delete is used because on pre_delete the model still has safe_apps
106
# which is not the case on post_delete
107
@receiver(post_save, sender=Feature)
1✔
108
@receiver(pre_delete, sender=Feature)
1✔
109
def on_feature_update(sender: Feature, instance: Feature, **kwargs: Any) -> None:
1✔
110
    logger.info("Feature update. Triggering CGW webhook")
1✔
111
    caches["safe-apps"].clear()
1✔
112
    if settings.FF_HOOK_EVENTS:
1✔
113
        for safe_app in instance.safe_apps.all():
1✔
114
            for chain_id in safe_app.chain_ids:
1✔
115
                hook_event(
1✔
116
                    HookEvent(type=HookEvent.Type.SAFE_APPS_UPDATE, chain_id=chain_id)
1✔
117
                )
118
    else:
119
        flush()
1✔
120

121

122
@receiver(m2m_changed, sender=Feature.safe_apps.through)
1✔
123
def on_feature_safe_apps_update(
1✔
124
    sender: Feature, instance: Feature, action: str, pk_set: set[int], **kwargs: Any
1✔
125
) -> None:
1✔
126
    logger.info("FeatureSafeApps update. Triggering CGW webhook")
1✔
127
    caches["safe-apps"].clear()
1✔
128
    if action == "post_add" or action == "post_remove":
1✔
129
        if settings.FF_HOOK_EVENTS:
1✔
130
            chain_ids = set()
1✔
131
            for safe_app in SafeApp.objects.filter(app_id__in=pk_set):
1✔
132
                for chain_id in safe_app.chain_ids:
1✔
133
                    chain_ids.add(chain_id)
1✔
134
            for chain_id in chain_ids:
1✔
135
                hook_event(
1✔
136
                    HookEvent(type=HookEvent.Type.SAFE_APPS_UPDATE, chain_id=chain_id)
1✔
137
                )
138
        else:
139
            flush()
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc