Consolidated subscription logic, switched to managed session.

This patch takes all the helper methods from subscriptions_handler.py
and places them into the actual worker task. Furthermore, the
subscription worker now uses a self-managed session.

Change-Id: I1a68c92bc68dc0a1f0bf713ee43d0d2a74332c17
This commit is contained in:
Michael Krotscheck 2015-04-21 16:01:08 -07:00
parent 4761084e65
commit 5561fa4078
2 changed files with 144 additions and 137 deletions

View File

@ -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)

View File

@ -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)
try:
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)
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,
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)
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
}