Add more detail to event messages

Pass the Referer header (which should be the URL to the webclient
which sent the request) and the query string (if applicable) to event
messages. This will allow linking in emails, and also make tag email
templates simpler.

Change-Id: I43c01bb8e8555205b26e86579114d52ef4068397
This commit is contained in:
Adam Coldrick 2016-01-14 15:03:57 +00:00
parent 89d02664fb
commit a0095fde81
10 changed files with 56 additions and 21 deletions

View File

@ -59,7 +59,9 @@ def event_create(values):
publish(author_id=request.current_user_id or None,
method="POST",
url=request.headers.get('Referer') or None,
path=request.path or None,
query_string=request.query_string or None,
status=response.status_code or None,
resource="timeline_event",
resource_id=new_event.id or None,

View File

@ -102,7 +102,9 @@ class NotificationHook(hooks.PecanHook):
# happening.
publish(author_id=request.current_user_id,
method=request.method,
url=request.headers.get('Referer'),
path=request.path,
query_string=request.query_string,
status=response.status_code,
resource=resource,
resource_id=resource_id,

View File

@ -131,16 +131,19 @@ class Payload(object):
self.payload = payload
def publish(resource, author_id=None, method=None, path=None, status=None,
resource_id=None, sub_resource=None, sub_resource_id=None,
resource_before=None, resource_after=None):
def publish(resource, author_id=None, method=None, url=None, path=None,
query_string=None, status=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.
:param resource: The extrapolated resource type (project, story, etc).
:param author_id: The ID of the author who performed this action.
:param method: The HTTP Method used.
:param url: The Referer header from the request.
:param path: The HTTP Path used.
:param query_string: The HTTP query string used.
:param status: The HTTP Status code of the response.
:param resource_id: The ID of the resource.
:param sub_resource: The extracted subresource (user_token, etc)
@ -158,7 +161,9 @@ def publish(resource, author_id=None, method=None, path=None, status=None,
payload = {
"author_id": author_id,
"method": method,
"url": url,
"path": path,
"query_string": query_string,
"status": status,
"resource": resource,
"resource_id": resource_id,

View File

@ -74,7 +74,9 @@ def handle_event(ext, body):
payload = json.loads(body)
return ext.obj.event(author_id=payload['author_id'] or None,
method=payload['method'] or None,
url=payload['url'] or None,
path=payload['path'] or None,
query_string=payload['query_string'] or None,
status=payload['status'] or None,
resource=payload['resource'] or None,
resource_id=payload['resource_id'] or None,

View File

@ -47,15 +47,17 @@ class EmailWorkerBase(EmailPluginBase, WorkerTaskBase):
__metaclass__ = abc.ABCMeta
def handle(self, session, author, method, path, status, resource,
resource_id, sub_resource=None, sub_resource_id=None,
def handle(self, session, author, method, url, path, query_string, status,
resource, resource_id, sub_resource=None, sub_resource_id=None,
resource_before=None, resource_after=None):
"""Handle an event.
:param session: An event-specific SQLAlchemy session.
:param author: The author's user record.
:param method: The HTTP Method.
:param url: The Referer header from the request.
:param path: The full HTTP Path requested.
:param query_string: The HTTP query string from the request.
:param status: The returned HTTP Status of the response.
:param resource: The resource type.
:param resource_id: The ID of the resource.
@ -85,8 +87,10 @@ class EmailWorkerBase(EmailPluginBase, WorkerTaskBase):
author=author,
subscribers=subscribers,
method=method,
url=url,
status=status,
path=path,
query_string=query_string,
resource=resource,
resource_id=resource_id,
sub_resource=sub_resource,
@ -95,17 +99,19 @@ class EmailWorkerBase(EmailPluginBase, WorkerTaskBase):
resource_after=resource_after)
@abc.abstractmethod
def handle_email(self, session, author, subscribers, method, path, status,
resource, resource_id, sub_resource=None,
sub_resource_id=None, resource_before=None,
resource_after=None):
def handle_email(self, session, author, subscribers, method, url, path,
query_string, status, resource, resource_id,
sub_resource=None, sub_resource_id=None,
resource_before=None, resource_after=None):
"""Handle an email notification for the given subscribers.
:param session: An event-specific SQLAlchemy session.
:param author: The author's user record.
:param subscribers: A list of subscribers that should receive an email.
:param method: The HTTP Method.
:param url: The Referer header from the request.
:param path: The full HTTP Path requested.
:param query_string: The query string from the request.
:param status: The returned HTTP Status of the response.
:param resource: The resource type.
:param resource_id: The ID of the resource.
@ -189,10 +195,10 @@ class SubscriptionEmailWorker(EmailWorkerBase):
have indicated that they wish to receive emails, but don't want digests.
"""
def handle_email(self, session, author, subscribers, method, path, status,
resource, resource_id, sub_resource=None,
sub_resource_id=None, resource_before=None,
resource_after=None):
def handle_email(self, session, author, subscribers, method, url, path,
query_string, status, resource, resource_id,
sub_resource=None, sub_resource_id=None,
resource_before=None, resource_after=None):
"""Send an email for a specific event.
We assume that filtering logic has already occurred when this method
@ -202,7 +208,9 @@ class SubscriptionEmailWorker(EmailWorkerBase):
:param author: The author's user record.
:param subscribers: A list of subscribers that should receive an email.
:param method: The HTTP Method.
:param url: The Referer header from the request.
:param path: The full HTTP Path requested.
:param query_string: The query string from the request.
:param status: The returned HTTP Status of the response.
:param resource: The resource type.
:param resource_id: The ID of the resource.
@ -269,6 +277,8 @@ class SubscriptionEmailWorker(EmailWorkerBase):
author=author,
resource=resource_instance,
sub_resource=sub_resource_instance,
url=url,
query_string=query_string,
before=before,
after=after)
# Send the email.

View File

@ -161,8 +161,8 @@ class WorkerTaskBase(PluginBase):
__metaclass__ = abc.ABCMeta
def event(self, author_id, method, path, status, resource, resource_id,
sub_resource=None, sub_resource_id=None,
def event(self, author_id, method, url, path, query_string, status,
resource, resource_id, sub_resource=None, sub_resource_id=None,
resource_before=None, resource_after=None):
"""Handle an event.
@ -176,7 +176,9 @@ class WorkerTaskBase(PluginBase):
self.handle(session=session,
author=author,
method=method,
url=url,
path=path,
query_string=query_string,
status=status,
resource=resource,
resource_id=resource_id,
@ -193,15 +195,17 @@ class WorkerTaskBase(PluginBase):
return db_api.entity_get(klass, resource_id, session=session)
@abc.abstractmethod
def handle(self, session, author, method, path, status, resource,
resource_id, sub_resource=None, sub_resource_id=None,
def handle(self, session, author, method, url, path, query_string, status,
resource, resource_id, sub_resource=None, sub_resource_id=None,
resource_before=None, resource_after=None):
"""Handle an event.
:param session: An event-specific SQLAlchemy session.
:param author: The author's user record.
:param method: The HTTP Method.
:param url: The Referer header from the request.
:param path: The full HTTP Path requested.
:param query_string: The HTTP query string provided.
:param status: The returned HTTP Status of the response.
:param resource: The resource type.
:param resource_id: The ID of the resource.

View File

@ -28,8 +28,8 @@ class Subscription(WorkerTaskBase):
"""
return True
def handle(self, session, author, method, path, status, resource,
resource_id, sub_resource=None, sub_resource_id=None,
def handle(self, session, author, method, url, path, query_string, status,
resource, resource_id, 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.
@ -37,7 +37,9 @@ class Subscription(WorkerTaskBase):
:param session: An event-specific SQLAlchemy session.
:param author: The author's user record.
:param method: The HTTP Method.
:param url: The Referer header from the request.
:param path: The full HTTP Path requested.
:param query_string: The HTTP query string from the request.
:param status: The returned HTTP Status of the response.
:param resource: The resource type.
:param resource_id: The ID of the resource.

View File

@ -252,6 +252,8 @@ class TestNotificationHook(base.BaseDbTestCase):
mock_state = Mock()
mock_state.request.current_user_id = '1'
mock_state.request.method = 'PUT'
mock_state.request.headers = {'Referer': 'http://localhost/'}
mock_state.request.query_string = ''
mock_state.request.path = '/v1/tasks/1'
mock_state.response.status_code = '200'
mock_state.old_entity_values = sot_json
@ -261,7 +263,9 @@ class TestNotificationHook(base.BaseDbTestCase):
mock_publish.assert_called_with(
author_id=mock_state.request.current_user_id,
method=mock_state.request.method,
url=mock_state.request.headers['Referer'],
path=mock_state.request.path,
query_string=mock_state.request.query_string,
status=mock_state.response.status_code,
resource='task',
resource_id='1',

View File

@ -42,7 +42,9 @@ class TestEmailWorkerBase(base.FunctionalTest):
worker_base.handle(session=session,
author=user_1,
method='POST',
url='http://localhost/',
path='/test',
query_string='',
status=201,
resource='story',
resource_id=1)
@ -154,7 +156,9 @@ class TestSubscriptionEmailWorker(base.FunctionalTest):
author=author,
subscribers=subscribers,
method='PUT',
url='http://localhost/',
path='/stories/1',
query_string='',
status=200,
resource='story',
resource_id=1,

View File

@ -65,8 +65,8 @@ class TestWorkerTaskBase(base.FunctionalTest):
class TestWorkerPlugin(plugin_base.WorkerTaskBase):
def handle(self, session, author, method, path, status, resource,
resource_id, sub_resource=None, sub_resource_id=None,
def handle(self, session, author, method, url, path, query_string, status,
resource, resource_id, sub_resource=None, sub_resource_id=None,
resource_before=None, resource_after=None):
pass