mirror of
https://github.com/ansible/awx.git
synced 2026-05-07 17:37:37 -02:30
Implement AC-667... user serializer to determine read-only fields and use those to decide what to populate in activity stream create instances AND when to create active stream update instances
This commit is contained in:
@@ -13,6 +13,7 @@ from django.dispatch import receiver
|
|||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.main.models import *
|
from awx.main.models import *
|
||||||
|
from awx.api.serializers import *
|
||||||
from awx.main.utils import model_instance_diff, model_to_dict, camelcase_to_underscore
|
from awx.main.utils import model_instance_diff, model_to_dict, camelcase_to_underscore
|
||||||
|
|
||||||
__all__ = []
|
__all__ = []
|
||||||
@@ -186,6 +187,18 @@ def update_host_last_job_after_job_deleted(sender, **kwargs):
|
|||||||
|
|
||||||
# Set via ActivityStreamRegistrar to record activity stream events
|
# Set via ActivityStreamRegistrar to record activity stream events
|
||||||
|
|
||||||
|
model_serializer_mapping = {Organization: OrganizationSerializer,
|
||||||
|
Inventory: InventorySerializer,
|
||||||
|
Host: HostSerializer,
|
||||||
|
Group: GroupSerializer,
|
||||||
|
InventorySource: InventorySourceSerializer,
|
||||||
|
Credential: CredentialSerializer,
|
||||||
|
Team: TeamSerializer,
|
||||||
|
Project: ProjectSerializer,
|
||||||
|
Permission: PermissionSerializer,
|
||||||
|
JobTemplate: JobTemplateSerializer,
|
||||||
|
Job: JobSerializer}
|
||||||
|
|
||||||
def activity_stream_create(sender, instance, created, **kwargs):
|
def activity_stream_create(sender, instance, created, **kwargs):
|
||||||
if created:
|
if created:
|
||||||
# TODO: Rethink details of the new instance
|
# TODO: Rethink details of the new instance
|
||||||
@@ -193,7 +206,7 @@ def activity_stream_create(sender, instance, created, **kwargs):
|
|||||||
activity_entry = ActivityStream(
|
activity_entry = ActivityStream(
|
||||||
operation='create',
|
operation='create',
|
||||||
object1=object1,
|
object1=object1,
|
||||||
changes=json.dumps(model_to_dict(instance)))
|
changes=json.dumps(model_to_dict(instance, model_serializer_mapping)))
|
||||||
activity_entry.save()
|
activity_entry.save()
|
||||||
getattr(activity_entry, object1).add(instance)
|
getattr(activity_entry, object1).add(instance)
|
||||||
|
|
||||||
@@ -209,7 +222,9 @@ def activity_stream_update(sender, instance, **kwargs):
|
|||||||
return
|
return
|
||||||
|
|
||||||
new = instance
|
new = instance
|
||||||
changes = model_instance_diff(old, new)
|
changes = model_instance_diff(old, new, model_serializer_mapping)
|
||||||
|
if changes is None:
|
||||||
|
return
|
||||||
object1 = camelcase_to_underscore(instance.__class__.__name__)
|
object1 = camelcase_to_underscore(instance.__class__.__name__)
|
||||||
activity_entry = ActivityStream(
|
activity_entry = ActivityStream(
|
||||||
operation='update',
|
operation='update',
|
||||||
|
|||||||
@@ -225,10 +225,12 @@ def update_scm_url(scm_type, url, username=True, password=True,
|
|||||||
parts.query, parts.fragment])
|
parts.query, parts.fragment])
|
||||||
return new_url
|
return new_url
|
||||||
|
|
||||||
def model_instance_diff(old, new):
|
def model_instance_diff(old, new, serializer_mapping=None):
|
||||||
"""
|
"""
|
||||||
Calculate the differences between two model instances. One of the instances may be None (i.e., a newly
|
Calculate the differences between two model instances. One of the instances may be None (i.e., a newly
|
||||||
created model or deleted model). This will cause all fields with a value to have changed (from None).
|
created model or deleted model). This will cause all fields with a value to have changed (from None).
|
||||||
|
serializer_mapping are used to determine read-only fields.
|
||||||
|
When provided, read-only fields will not be included in the resulting dictionary
|
||||||
"""
|
"""
|
||||||
from django.db.models import Model
|
from django.db.models import Model
|
||||||
from awx.main.models.organization import Credential
|
from awx.main.models.organization import Credential
|
||||||
@@ -249,28 +251,42 @@ def model_instance_diff(old, new):
|
|||||||
else:
|
else:
|
||||||
fields = set()
|
fields = set()
|
||||||
|
|
||||||
for field in fields:
|
if serializer_mapping is not None and new.__class__ in serializer_mapping:
|
||||||
old_value = str(getattr(old, field.name, None))
|
serializer_actual = serializer_mapping[new.__class__]()
|
||||||
new_value = str(getattr(new, field.name, None))
|
allowed_fields = [x for x in serializer_actual.fields if not serializer_actual.fields[x].read_only] + ['id']
|
||||||
|
else:
|
||||||
|
allowed_fields = [x.name for x in new._meta.fields]
|
||||||
|
|
||||||
if old_value != new_value and field.name not in Credential.PASSWORD_FIELDS:
|
for field in allowed_fields:
|
||||||
diff[field.name] = (old_value, new_value)
|
old_value = str(getattr(old, field, None))
|
||||||
elif field.name in Credential.PASSWORD_FIELDS:
|
new_value = str(getattr(new, field, None))
|
||||||
diff[field.name] = ("hidden", "hidden")
|
|
||||||
|
if old_value != new_value and field not in Credential.PASSWORD_FIELDS:
|
||||||
|
diff[field] = (old_value, new_value)
|
||||||
|
elif old_value != new_value and field in Credential.PASSWORD_FIELDS:
|
||||||
|
diff[field] = ("hidden", "hidden")
|
||||||
|
|
||||||
if len(diff) == 0:
|
if len(diff) == 0:
|
||||||
diff = None
|
diff = None
|
||||||
|
|
||||||
return diff
|
return diff
|
||||||
|
|
||||||
def model_to_dict(obj):
|
def model_to_dict(obj, serializer_mapping=None):
|
||||||
"""
|
"""
|
||||||
Serialize a model instance to a dictionary as best as possible
|
Serialize a model instance to a dictionary as best as possible
|
||||||
|
serializer_mapping are used to determine read-only fields.
|
||||||
|
When provided, read-only fields will not be included in the resulting dictionary
|
||||||
"""
|
"""
|
||||||
from awx.main.models.organization import Credential
|
from awx.main.models.organization import Credential
|
||||||
attr_d = {}
|
attr_d = {}
|
||||||
|
if serializer_mapping is not None and obj.__class__ in serializer_mapping:
|
||||||
|
serializer_actual = serializer_mapping[obj.__class__]()
|
||||||
|
allowed_fields = [x for x in serializer_actual.fields if not serializer_actual.fields[x].read_only] + ['id']
|
||||||
|
else:
|
||||||
|
allowed_fields = [x.name for x in obj._meta.fields]
|
||||||
for field in obj._meta.fields:
|
for field in obj._meta.fields:
|
||||||
# FIXME: This needs to be aware of fields not to be included in the AS delta log
|
if field.name not in allowed_fields:
|
||||||
|
continue
|
||||||
if field.name not in Credential.PASSWORD_FIELDS:
|
if field.name not in Credential.PASSWORD_FIELDS:
|
||||||
attr_d[field.name] = str(getattr(obj, field.name, None))
|
attr_d[field.name] = str(getattr(obj, field.name, None))
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user