diff --git a/storyboard/db/api/timeline_events.py b/storyboard/db/api/timeline_events.py index 7967f94f..45ee6f0f 100644 --- a/storyboard/db/api/timeline_events.py +++ b/storyboard/db/api/timeline_events.py @@ -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, diff --git a/storyboard/notifications/notification_hook.py b/storyboard/notifications/notification_hook.py index fb7016ed..7aa5267a 100644 --- a/storyboard/notifications/notification_hook.py +++ b/storyboard/notifications/notification_hook.py @@ -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, diff --git a/storyboard/notifications/publisher.py b/storyboard/notifications/publisher.py index 80580e1d..d09c411b 100644 --- a/storyboard/notifications/publisher.py +++ b/storyboard/notifications/publisher.py @@ -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, diff --git a/storyboard/notifications/subscriber.py b/storyboard/notifications/subscriber.py index 29b7c87e..dc0ca645 100644 --- a/storyboard/notifications/subscriber.py +++ b/storyboard/notifications/subscriber.py @@ -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, diff --git a/storyboard/plugin/email/workers.py b/storyboard/plugin/email/workers.py index 17760168..0b08fabc 100644 --- a/storyboard/plugin/email/workers.py +++ b/storyboard/plugin/email/workers.py @@ -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. diff --git a/storyboard/plugin/event_worker.py b/storyboard/plugin/event_worker.py index 295daeb4..e24d2086 100644 --- a/storyboard/plugin/event_worker.py +++ b/storyboard/plugin/event_worker.py @@ -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. diff --git a/storyboard/plugin/subscription/base.py b/storyboard/plugin/subscription/base.py index c11932ba..ee4042d4 100644 --- a/storyboard/plugin/subscription/base.py +++ b/storyboard/plugin/subscription/base.py @@ -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. diff --git a/storyboard/tests/notifications/test_notification_hook.py b/storyboard/tests/notifications/test_notification_hook.py index 82a4d1dc..981c5a1c 100644 --- a/storyboard/tests/notifications/test_notification_hook.py +++ b/storyboard/tests/notifications/test_notification_hook.py @@ -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', diff --git a/storyboard/tests/plugin/email/test_workers.py b/storyboard/tests/plugin/email/test_workers.py index f8e6fbcc..6fe74985 100644 --- a/storyboard/tests/plugin/email/test_workers.py +++ b/storyboard/tests/plugin/email/test_workers.py @@ -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, diff --git a/storyboard/tests/plugin/test_event_worker.py b/storyboard/tests/plugin/test_event_worker.py index a183852f..f72b5d13 100644 --- a/storyboard/tests/plugin/test_event_worker.py +++ b/storyboard/tests/plugin/test_event_worker.py @@ -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