API events now include resource before/after state.

Workers are now provided with a full copy of the modified entity
before, and after, the applied change. Workers may use this data
to determine exactly what modifications were made to the entity,
which is particularly useful in PUT/Update requests.

Change-Id: I7e2b0a57b1303989046e40c85b553f0e11630f63
This commit is contained in:
Michael Krotscheck 2015-01-08 10:07:41 -08:00 committed by Thierry Carrez
parent 1d759aa113
commit eb0964362a
6 changed files with 32 additions and 7 deletions

View File

@ -17,7 +17,9 @@ import json
from oslo.config import cfg
from pecan import request
from pecan import response
from wsme.rest.json import tojson
from storyboard.api.v1.wmodels import TimeLineEvent
from storyboard.common import event_types
from storyboard.db.api import base as api_base
from storyboard.db import models
@ -52,12 +54,16 @@ def event_create(values):
# Build the payload. Use of None is included to ensure that we don't
# accidentally blow up the API call, but we don't anticipate it
# happening.
event_dict = tojson(TimeLineEvent,
TimeLineEvent.from_db_model(new_event))
publish(author_id=request.current_user_id or None,
method="POST",
path=request.path or None,
status=response.status_code or None,
resource="timeline_event",
resource_id=new_event.id or None)
resource_id=new_event.id or None,
resource_after=event_dict or None)
return new_event

View File

@ -77,6 +77,10 @@ class NotificationHook(hooks.PecanHook):
else:
resource_id = None
# Get a copy of the resource post-modification. Will return None in
# the case of a DELETE.
new_resource = self.map_resource(resource, resource_id)
# Build the payload. Use of None is included to ensure that we don't
# accidentally blow up the API call, but we don't anticipate it
# happening.
@ -87,7 +91,9 @@ class NotificationHook(hooks.PecanHook):
resource=resource,
resource_id=resource_id,
sub_resource=subresource,
sub_resource_id=subresource_id)
sub_resource_id=subresource_id,
resource_before=state.old_entity_values,
resource_after=new_resource)
def get_original_resource(self, resource, resource_id):
"""Given a resource name and ID, will load that resource and map it

View File

@ -132,7 +132,8 @@ class Payload(object):
def publish(resource, author_id=None, method=None, path=None, status=None,
resource_id=None, sub_resource=None, sub_resource_id=None):
resource_id=None, sub_resource=None, sub_resource_id=None,
resource_before=None, resource_after=None):
"""Send a message for an API event to the storyboard exchange. The message
will be automatically JSON encoded.
@ -144,6 +145,8 @@ def publish(resource, author_id=None, method=None, path=None, status=None,
:param resource_id: The ID of the resource.
:param sub_resource: The extracted subresource (user_token, etc)
:param sub_resource_id: THe ID of the subresource.
:param resource_before: The resource state before this event occurred.
:param resource_after: The resource state after this event occurred.
"""
global PUBLISHER
@ -160,7 +163,9 @@ def publish(resource, author_id=None, method=None, path=None, status=None,
"resource": resource,
"resource_id": resource_id,
"sub_resource": sub_resource,
"sub_resource_id": sub_resource_id
"sub_resource_id": sub_resource_id,
"resource_before": resource_before,
"resource_after": resource_after
}
if resource:

View File

@ -75,7 +75,9 @@ def handle_event(ext, body):
resource=payload['resource'] or None,
resource_id=payload['resource_id'] or None,
sub_resource=payload['sub_resource'] or None,
sub_resource_id=payload['sub_resource_id'] or None)
sub_resource_id=payload['sub_resource_id'] or None,
resource_before=payload['resource_before'] or None,
resource_after=payload['resource_after'] or None)
def check_enabled(ext):

View File

@ -34,7 +34,8 @@ class WorkerTaskBase(object):
@abc.abstractmethod
def handle(self, author_id, method, path, status, resource, resource_id,
sub_resource=None, sub_resource_id=None):
sub_resource=None, sub_resource_id=None,
resource_before=None, resource_after=None):
"""Handle an event.
:param author_id: ID of the author's user record.
@ -45,4 +46,6 @@ class WorkerTaskBase(object):
:param resource_id: The ID of the resource.
:param sub_resource: The subresource type.
:param sub_resource_id: The ID of the subresource.
:param resource_before: The resource state before this event occurred.
:param resource_after: The resource state after this event occurred.
"""

View File

@ -23,7 +23,8 @@ from storyboard.worker.task.base import WorkerTaskBase
class Subscription(WorkerTaskBase):
def handle(self, author_id, method, path, status, resource, resource_id,
sub_resource=None, sub_resource_id=None):
sub_resource=None, sub_resource_id=None,
resource_before=None, resource_after=None):
"""This worker handles API events and attempts to determine whether
they correspond to user subscriptions.
@ -35,6 +36,8 @@ class Subscription(WorkerTaskBase):
:param resource_id: The ID of the resource.
:param sub_resource: The subresource type.
:param sub_resource_id: The ID of the subresource.
:param resource_before: The resource state before this event occurred.
:param resource_after: The resource state after this event occurred.
"""
if resource == 'timeline_event':