diff --git a/storyboard/notifications/subscriptions_handler.py b/storyboard/notifications/subscriptions_handler.py deleted file mode 100644 index 8329cb70..00000000 --- a/storyboard/notifications/subscriptions_handler.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import json - -from storyboard.db.api import comments as comments_api -from storyboard.db.api import stories as story_api -from storyboard.db.api import subscription_events as sub_events_api -from storyboard.db.api import subscriptions as subscriptions_api -from storyboard.db.api import timeline_events as timeline_api - - -def handle_timeline_events(event, author_id, subscribers): - - for user_id in subscribers: - if event.event_type == 'user_comment': - event_info = resolve_comments(event) - - else: - event_info = event.event_info - - sub_events_api.subscription_events_create({ - "author_id": author_id, - "subscriber_id": user_id, - "event_type": event.event_type, - "event_info": event_info - }) - - -def handle_resources(method, resource_id, sub_resource_id, author_id, - subscribers): - - if sub_resource_id: - - for user_id in subscribers: - - if method == 'DELETE': - event_type = 'project removed from project_group' - event_info = json.dumps({'project_group_id': resource_id, - 'project_id': sub_resource_id}) - - else: - event_type = 'project added to project_group' - event_info = json.dumps({'project_group_id': resource_id, - 'project_id': sub_resource_id}) - - sub_events_api.subscription_events_create({ - "author_id": author_id, - "subscriber_id": user_id, - "event_type": event_type, - "event_info": event_info - }) - - else: - if method == 'DELETE': - # Handling project_group targeted. - for user_id in subscribers: - sub_events_api.subscription_events_create({ - "author_id": author_id, - "subscriber_id": user_id, - "event_type": 'project_group deleted', - "event_info": json.dumps({'project_group_id': resource_id}) - }) - - -def handle_deletions(resource_name, resource_id): - target_subs = [] - sub_ids = set() - resource_name = resource_name[:-1] - - target_sub = subscriptions_api.subscription_get_all_by_target( - resource_name, resource_id) - target_subs.extend(target_sub) - - for sub in target_subs: - sub_ids.add(sub.id) - - for sub_id in sub_ids: - subscriptions_api.subscription_delete(sub_id) - - -def resolve_comments(event): - event_info = { - 'comment_id': event.comment_id or None, - } - - # Retrieve the content of the comment. - comment = comments_api.comment_get(event.comment_id) - event_info['comment_content'] = comment.content - - # Retrieve the story ID of the comment. - timeline_events = timeline_api.events_get_all(comment_id=event.comment_id) - if timeline_events: - story = story_api.story_get(timeline_events[0].story_id) - - if story: - event_info['story_id'] = story.id - event_info['story_title'] = story.title - - return json.dumps(event_info) diff --git a/storyboard/worker/task/subscription.py b/storyboard/worker/task/subscription.py index cd947a36..da96fed2 100644 --- a/storyboard/worker/task/subscription.py +++ b/storyboard/worker/task/subscription.py @@ -12,16 +12,22 @@ # implied. See the License for the specific language governing permissions and # limitations under the License. -from storyboard.db.api import subscriptions -from storyboard.db.api import timeline_events -from storyboard.notifications.subscriptions_handler import handle_deletions -from storyboard.notifications.subscriptions_handler import handle_resources -from storyboard.notifications.subscriptions_handler import \ - handle_timeline_events +import json + +import storyboard.db.api.base as db_api +from storyboard.db.api import subscriptions as sub_api +import storyboard.db.models as models from storyboard.worker.task.base import WorkerTaskBase class Subscription(WorkerTaskBase): + def enabled(self): + """This plugin is always enabled. + + :return: True + """ + return True + def handle(self, author_id, method, path, status, resource, resource_id, sub_resource=None, sub_resource_id=None, resource_before=None, resource_after=None): @@ -39,26 +45,139 @@ class Subscription(WorkerTaskBase): :param resource_before: The resource state before this event occurred. :param resource_after: The resource state after this event occurred. """ + session = db_api.get_session(in_request=False, autocommit=False) - if resource == 'timeline_event': - event = timeline_events.event_get(resource_id) - subscribers = subscriptions.subscription_get_all_subscriber_ids( - 'story', event.story_id - ) - handle_timeline_events(event, author_id, subscribers) + try: + if resource == 'timeline_event': + event = db_api.entity_get(models.TimeLineEvent, resource_id, + session=session) + subscribers = sub_api.subscription_get_all_subscriber_ids( + 'story', event.story_id, session=session) + self.handle_timeline_events(session, event, author_id, + subscribers) - elif resource == 'project_group': - subscribers = subscriptions.subscription_get_all_subscriber_ids( - resource, resource_id - ) - handle_resources(method=method, - resource_id=resource_id, - sub_resource_id=sub_resource_id, - author_id=author_id, - subscribers=subscribers) + elif resource == 'project_group': + subscribers = sub_api.subscription_get_all_subscriber_ids( + resource, resource_id, session=session) + self.handle_resources(session=session, + method=method, + resource_id=resource_id, + sub_resource_id=sub_resource_id, + author_id=author_id, + subscribers=subscribers) - if method == 'DELETE' and not sub_resource_id: - handle_deletions(resource, resource_id) + if method == 'DELETE' and not sub_resource_id: + self.handle_deletions(session, resource, resource_id) - def enabled(self): - return True + session.commit() + session.flush() + except Exception: + session.rollback() + + def handle_deletions(self, session, resource_name, resource_id): + target_subs = [] + sub_ids = set() + resource_name = resource_name[:-1] + + target_sub = db_api.entity_get_all(models.Subscription, + target_type=resource_name, + target_id=resource_id, + session=session) + target_subs.extend(target_sub) + + for sub in target_subs: + sub_ids.add(sub.id) + + for sub_id in sub_ids: + db_api.entity_hard_delete(models.Subscription, + sub_id, + session=session) + + def handle_timeline_events(self, session, event, author_id, subscribers): + + for user_id in subscribers: + if event.event_type == 'user_comment': + event_info = json.dumps( + self.resolve_comments(session=session, event=event) + ) + + else: + event_info = event.event_info + + db_api.entity_create(models.SubscriptionEvents, { + "author_id": author_id, + "subscriber_id": user_id, + "event_type": event.event_type, + "event_info": event_info + }, session=session) + + def handle_resources(self, session, method, resource_id, sub_resource_id, + author_id, subscribers): + + if sub_resource_id: + + for user_id in subscribers: + + if method == 'DELETE': + event_type = 'project removed from project_group' + event_info = json.dumps({'project_group_id': resource_id, + 'project_id': sub_resource_id}) + + else: + event_type = 'project added to project_group' + event_info = json.dumps({'project_group_id': resource_id, + 'project_id': sub_resource_id}) + + db_api.entity_create(models.SubscriptionEvents, { + "author_id": author_id, + "subscriber_id": user_id, + "event_type": event_type, + "event_info": event_info + }, session=session) + + else: + if method == 'DELETE': + # Handling project_group targeted. + for user_id in subscribers: + db_api.entity_create(models.SubscriptionEvents, { + "author_id": author_id, + "subscriber_id": user_id, + "event_type": 'project_group deleted', + "event_info": json.dumps( + {'project_group_id': resource_id}) + }, session=session) + + def resolve_comments(self, session, event): + + # Sanity check. If there's no comment_id, exit. + if 'comment_id' not in event: + return None + + # Retrieve the content of the comment. + comment = db_api.entity_get(models.Comment, + event.comment_id, + session=session) + if not comment: + return None + + # Retrieve the timeline events. + timeline_event = session.query(models.TimeLineEvent) \ + .filter(models.TimeLineEvent.comment_id == event.comment_id) \ + .first() + if not timeline_event: + return None + + # Retrieve the story from the timeline event. + story = db_api.entity_get(models.Story, + timeline_event.story_id, + session=session) + if not story: + return None + + # Construct and return the comment's event_info object. + return { + 'comment_id': comment.id, + 'comment_content': comment.content, + 'story_id': story.id, + 'story_title': story.title + }