1
# Python
2 6
import contextlib
3 6
import logging
4 6
import threading
5 6
import json
6

7
# Django
8 6
from django.conf import settings
9 6
from django.db.models.signals import post_save
10 6
from django.dispatch import receiver
11

12
# Django-CRUM
13 6
from crum import get_current_request, get_current_user
14 6
from crum.signals import current_user_getter
15

16
# CyBorgBackup
17 6
from cyborgbackup.main.models import User, JobEvent, Client, Policy, Schedule, Job, ActivityStream, Repository
18 6
from cyborgbackup.api.serializers import (JobEventWebSocketSerializer, JobSerializer, ClientSerializer,
19
                                          RepositorySerializer, ScheduleSerializer, PolicySerializer)
20 6
from cyborgbackup.main.utils.common import model_instance_diff, model_to_dict, camelcase_to_underscore
21

22 6
from cyborgbackup.main import consumers
23

24 6
__all__ = []
25

26 6
logger = logging.getLogger('cyborgbackup.main.signals')
27

28

29 6
def get_current_user_or_none():
30 6
    u = get_current_user()
31 6
    if not isinstance(u, User):
32 6
        return None
33 0
    return u
34

35

36 6
def emit_event_detail(serializer, relation, **kwargs):
37 0
    instance = kwargs['instance']
38 0
    created = kwargs['created']
39 0
    if created:
40 0
        event_serializer = serializer(instance)
41 0
        consumers.emit_channel_notification(
42
            '-'.join([event_serializer.get_group_name(instance), str(getattr(instance, relation))]),
43
            event_serializer.data
44
        )
45

46

47 6
@receiver(post_save, sender=JobEvent)
48
def emit_job_event_detail(sender, **kwargs):
49 0
    emit_event_detail(JobEventWebSocketSerializer, 'job_id', **kwargs)
50

51

52 6
class ActivityStreamEnabled(threading.local):
53 6
    def __init__(self):
54 6
        self.enabled = False
55

56 6
    def __nonzero__(self):
57 0
        return bool(self.enabled and getattr(settings, 'ACTIVITY_STREAM_ENABLED', True))
58

59

60 6
activity_stream_enabled = ActivityStreamEnabled()
61

62

63 6
@contextlib.contextmanager
64
def disable_activity_stream():
65
    '''
66
    Context manager to disable capturing activity stream changes.
67
    '''
68 0
    try:
69 0
        previous_value = activity_stream_enabled.enabled
70 0
        activity_stream_enabled.enabled = False
71 0
        yield
72
    finally:
73 0
        activity_stream_enabled.enabled = previous_value
74

75

76 6
model_serializer_mapping = {
77
    Job: JobSerializer,
78
    Client: ClientSerializer,
79
    Policy: PolicySerializer,
80
    Repository: RepositorySerializer,
81
    Schedule: ScheduleSerializer,
82
}
83

84

85 6
def activity_stream_create(sender, instance, created, **kwargs):
86 6
    if created and activity_stream_enabled:
87 6
        _type = type(instance)
88 6
        if getattr(_type, '_deferred', False):
89 0
            return
90 6
        object1 = camelcase_to_underscore(instance.__class__.__name__)
91 6
        changes = model_to_dict(instance, model_serializer_mapping)
92
        # Special case where Job survey password variables need to be hidden
93 6
        if type(instance) == Job:
94 0
            if 'extra_vars' in changes:
95 0
                changes['extra_vars'] = instance.display_extra_vars()
96 6
        activity_entry = ActivityStream(
97
            operation='create',
98
            object1=object1,
99
            changes=json.dumps(changes),
100
            actor=get_current_user_or_none())
101 6
        if instance._meta.model_name != 'setting':  # Is not conf.Setting instance
102 6
            activity_entry.save()
103 6
            getattr(activity_entry, object1).add(instance)
104

105

106 6
def activity_stream_update(sender, instance, **kwargs):
107 6
    if instance.id is None:
108 6
        return
109 6
    if not activity_stream_enabled:
110 0
        return
111 6
    try:
112 6
        old = sender.objects.get(id=instance.id)
113 6
    except sender.DoesNotExist:
114 6
        return
115

116 6
    new = instance
117 6
    changes = model_instance_diff(old, new, model_serializer_mapping)
118 6
    if changes is None:
119 0
        return
120 6
    _type = type(instance)
121 6
    if getattr(_type, '_deferred', False):
122 0
        return
123 6
    object1 = camelcase_to_underscore(instance.__class__.__name__)
124

125 6
    activity_entry = ActivityStream(
126
        operation='update',
127
        object1=object1,
128
        changes=json.dumps(changes),
129
        actor=get_current_user_or_none())
130 6
    if instance._meta.model_name != 'setting':  # Is not conf.Setting instance
131 6
        activity_entry.save()
132 6
        getattr(activity_entry, object1).add(instance)
133

134

135 6
def activity_stream_delete(sender, instance, **kwargs):
136 6
    if not activity_stream_enabled:
137 0
        return
138 6
    _type = type(instance)
139 6
    if getattr(_type, '_deferred', False):
140 0
        return
141 6
    changes = model_to_dict(instance)
142 6
    object1 = camelcase_to_underscore(instance.__class__.__name__)
143 6
    activity_entry = ActivityStream(
144
        operation='delete',
145
        changes=json.dumps(changes),
146
        object1=object1,
147
        actor=get_current_user_or_none())
148 6
    activity_entry.save()
149

150

151 6
def activity_stream_associate(sender, instance, **kwargs):
152 6
    if not activity_stream_enabled:
153 0
        return
154 6
    if kwargs['action'] in ['pre_add', 'pre_remove']:
155 6
        if kwargs['action'] == 'pre_add':
156 6
            action = 'associate'
157 0
        elif kwargs['action'] == 'pre_remove':
158 0
            action = 'disassociate'
159
        else:
160 0
            return
161 6
        obj1 = instance
162 6
        _type = type(instance)
163 6
        if getattr(_type, '_deferred', False):
164 0
            return
165 6
        object1 = camelcase_to_underscore(obj1.__class__.__name__)
166 6
        if object1 == 'activity_stream':
167 6
            return
168 6
        obj_rel = sender.__module__ + "." + sender.__name__
169

170 6
        for entity_acted in kwargs['pk_set']:
171 6
            obj2 = kwargs['model']
172 6
            obj2_id = entity_acted
173 6
            obj2_actual = obj2.objects.filter(id=obj2_id)
174 6
            if not obj2_actual.exists():
175 0
                continue
176 6
            obj2_actual = obj2_actual[0]
177 6
            _type = type(obj2_actual)
178 6
            if getattr(_type, '_deferred', False):
179 0
                return
180 6
            object2 = camelcase_to_underscore(obj2.__name__)
181 6
            activity_entry = ActivityStream(
182
                changes=json.dumps(dict(object1=object1,
183
                                        object1_pk=obj1.pk,
184
                                        object2=object2,
185
                                        object2_pk=obj2_id,
186
                                        action=action,
187
                                        relationship=obj_rel)),
188
                operation=action,
189
                object1=object1,
190
                object2=object2,
191
                object_relationship_type=obj_rel,
192
                actor=get_current_user_or_none())
193 6
            activity_entry.save()
194 6
            getattr(activity_entry, object1).add(obj1)
195 6
            getattr(activity_entry, object2).add(obj2_actual)
196

197

198 6
@receiver(current_user_getter)
199
def get_current_user_from_drf_request(sender, **kwargs):
200
    '''
201
    Provider a signal handler to return the current user from the current
202
    request when using Django REST Framework. Requires that the APIView set
203
    drf_request on the underlying Django Request object.
204
    '''
205 6
    request = get_current_request()
206 6
    drf_request_user = getattr(request, 'drf_request_user', False)
207 6
    return (drf_request_user, 0)
208

209

210 6
def sync_superuser_status_to_rbac(instance, **kwargs):
211
    'When the is_superuser flag is changed on a user, reflect that in the membership of the System Admnistrator role'
212 0
    update_fields = kwargs.get('update_fields', None)
213 0
    if update_fields and 'is_superuser' not in update_fields:
214 0
        return
215

216

217
# def create_user_role(instance, **kwargs):
218
#     if not kwargs.get('created', True):
219
#         return
220
#     try:
221
#         Role.objects.get(
222
#             content_type=ContentType.objects.get_for_model(instance),
223
#             object_id=instance.id,
224
#             role_field='admin_role'
225
#         )
226
#     except Role.DoesNotExist:
227
#         role = Role.objects.create(
228
#             role_field='admin_role',
229
#             content_object=instance,
230
#         )
231
#         role.members.add(instance)
232

233

234 6
post_save.connect(sync_superuser_status_to_rbac, sender=User)

Read our documentation on viewing source code .

Loading