diff --git a/pillar/application/__init__.py b/pillar/application/__init__.py index 6a78e119..e1425eb8 100644 --- a/pillar/application/__init__.py +++ b/pillar/application/__init__.py @@ -127,9 +127,9 @@ from application.utils.authorization import check_permissions from application.utils.gcs import update_file_name from application.utils.algolia import algolia_index_user_save from application.utils.algolia import algolia_index_node_save -from application.utils.activities import activity_create from application.utils.activities import activity_subscribe -# from application.utils.activities import notification_parse +from application.utils.activities import activity_object_add +from application.utils.activities import notification_parse from modules.file_storage import process_file from modules.file_storage import delete_file from modules.file_storage import generate_link @@ -177,18 +177,34 @@ def before_inserting_nodes(items): def after_inserting_nodes(items): for item in items: - activity_create(item['user'], 'node', item['_id']) + context_object_id = item['parent'] if item['node_type'] == 'comment': - verb = 'commented' + nodes_collection = app.data.driver.db['nodes'] + parent = nodes_collection.find_one({'_id': item['parent']}) + # Always subscribe to the parent node + activity_subscribe(item['user'], 'node', item['parent']) + if parent['node_type'] == 'comment': + # If the parent is a comment, we provide its own parent as + # context. We do this in order to point the user to an asset + # or group when viewing the notification. + verb = 'replied' + context_object_id = parent['parent'] + # Subscribe to the parent of the parent comment (post or group) + activity_subscribe(item['user'], 'node', parent['parent']) + else: + activity_subscribe(item['user'], 'node', item['_id']) + verb = 'commented' else: verb = 'posted' - activity_subscribe( + activity_subscribe(item['user'], 'node', item['_id']) + + activity_object_add( item['user'], verb, 'node', item['_id'], 'node', - item['parent'] + context_object_id ) def item_parse_attachments(response): @@ -255,16 +271,22 @@ def project_node_type_has_method(response): # Check permissions and append the allowed_methods to the node_type check_permissions(node_type, 'GET', append_allowed_methods=True) -# def before_returning_notifications(response): -# for item in response['_items']: -# notification_parse(item) +def before_returning_item_notifications(response): + if request.args.get('parse'): + notification_parse(response) + +def before_returning_resource_notifications(response): + for item in response['_items']: + if request.args.get('parse'): + notification_parse(item) app.on_fetched_item_nodes += before_returning_item_permissions app.on_fetched_item_nodes += item_parse_attachments app.on_fetched_resource_nodes += before_returning_resource_permissions app.on_fetched_resource_nodes += resource_parse_attachments app.on_fetched_item_node_types += before_returning_item_permissions -# app.on_fetched_resource_notifications += before_returning_notifications +app.on_fetched_item_notifications += before_returning_item_notifications +app.on_fetched_resource_notifications += before_returning_resource_notifications app.on_fetched_resource_node_types += before_returning_resource_permissions app.on_replace_nodes += before_replacing_node app.on_replaced_nodes += after_replacing_node diff --git a/pillar/application/utils/activities.py b/pillar/application/utils/activities.py index eb3b64b1..6eacf2a5 100644 --- a/pillar/application/utils/activities.py +++ b/pillar/application/utils/activities.py @@ -1,66 +1,80 @@ +from flask import g from eve.methods.post import post_internal from application import app -# def notification_parse(notification): -# # TODO: finish fixing this -# activities_collection = app.data.driver.db['activities'] -# users_collection = app.data.driver.db['users'] -# nodes_collection = app.data.driver.db['nodes'] -# activity = activities_collection.find_one({'_id': notification['_id']}) -# actor = users_collection.find_one({'_id': activity['actor_user']}) -# # Context is optional -# context_object_type = None -# context_object_name = None -# context_object_url = None +def notification_parse(notification): + # notification = dict(a='n') + # TODO: finish fixing this + activities_collection = app.data.driver.db['activities'] + activities_subscriptions_collection = app.data.driver.db['activities-subscriptions'] + users_collection = app.data.driver.db['users'] + nodes_collection = app.data.driver.db['nodes'] + activity = activities_collection.find_one({'_id': notification['activity']}) + # actor = users_collection.find_one({'_id': activity['actor_user']}) + # Context is optional + context_object_type = None + context_object_name = None + context_object_url = None -# if activity['object_type'] == 'node': -# node = nodes_collection.find_one({'_id': activity['object']}) -# # project = Project.find(node.project, { -# # 'projection': '{"name":1, "url":1}'}, api=api) -# # Initial support only for node_type comments -# if node['node_type'] == 'comment': -# # comment = Comment.query.get_or_404(notification_object.object_id) -# node['parent'] = nodes_collection.find_one({'_id': node['parent']}) -# object_type = 'comment' -# object_name = '' + if activity['object_type'] != 'node': + return + node = nodes_collection.find_one({'_id': activity['object']}) + # Initial support only for node_type comments + if node['node_type'] != 'comment': + return + node['parent'] = nodes_collection.find_one({'_id': node['parent']}) + object_type = 'comment' + object_name = '' + object_id = activity['object'] -# object_url = url_for('nodes.view', node_id=node._id, redir=1) -# if node.parent.user == current_user.objectid: -# owner = "your {0}".format(node.parent.node_type) -# else: -# parent_comment_user = User.find(node.parent.user, api=api) -# owner = "{0}'s {1}".format(parent_comment_user.username, -# node.parent.node_type) + if node['parent']['user'] == g.current_user['user_id']: + owner = "your {0}".format(node['parent']['node_type']) + else: -# context_object_type = node.parent.node_type -# context_object_name = owner -# context_object_url = url_for('nodes.view', node_id=node.parent._id, redir=1) -# if activity.verb == 'replied': -# action = 'replied to' -# elif activity.verb == 'commented': -# action = 'left a comment on' -# else: -# action = activity.verb -# else: -# return None -# else: -# return None + parent_comment_user = users_collection.find_one( + {'_id': node['parent']['user']}) + owner = "{0}'s {1}".format(parent_comment_user['username'], + node['parent']['node_type']) + + context_object_type = node['parent']['node_type'] + context_object_name = owner + context_object_id = activity['context_object'] + if activity['verb'] == 'replied': + action = 'replied to' + elif activity['verb'] == 'commented': + action = 'left a comment on' + else: + action = activity['verb'] + + lookup = { + 'user': g.current_user['user_id'], + 'context_object_type': 'node', + 'context_object': context_object_id, + } + + subscription = activities_subscriptions_collection.find_one(lookup) + if subscription and subscription['notifications']['web'] == True: + is_subscribed = True + else: + is_subscribed = False + + updates = dict( + _id=notification['_id'], + actor=activity['actor_user'], + action=action, + object_type=object_type, + object_name=object_name, + object_id=str(object_id), + context_object_type=context_object_type, + context_object_name=context_object_name, + context_object_id=str(context_object_id), + date=activity['_created'], + is_read=('is_read' in notification and notification['is_read']), + is_subscribed=is_subscribed, + subscription=subscription['_id'] + ) + notification.update(updates) -# return dict( -# _id=notification._id, -# username=actor.username, -# username_avatar=actor.gravatar(), -# action=action, -# object_type=object_type, -# object_name=object_name, -# object_url=object_url, -# context_object_type=context_object_type, -# context_object_name=context_object_name, -# context_object_url=context_object_url, -# date=pretty_date(activity._created), -# is_read=notification.is_read, -# # is_subscribed=notification.is_subscribed -# ) def notification_get_subscriptions(context_object_type, context_object_id, actor_user_id): subscriptions_collection = app.data.driver.db['activities-subscriptions'] @@ -73,7 +87,7 @@ def notification_get_subscriptions(context_object_type, context_object_id, actor return subscriptions_collection.find(lookup) -def activity_create(user_id, context_object_type, context_object_id): +def activity_subscribe(user_id, context_object_type, context_object_id): """Subscribe a user to changes for a specific context. We create a subscription if none is found. @@ -94,7 +108,7 @@ def activity_create(user_id, context_object_type, context_object_id): post_internal('activities-subscriptions', lookup) -def activity_subscribe(actor_user_id, verb, object_type, object_id, +def activity_object_add(actor_user_id, verb, object_type, object_id, context_object_type, context_object_id): """Add a notification object and creates a notification for each user that - is not the original author of the post @@ -124,6 +138,9 @@ def activity_subscribe(actor_user_id, verb, object_type, object_id, ) activity = post_internal('activities', activity) + if activity[3] != 201: + # If creation failed for any reason, do not create a any notifcation + return for subscription in subscriptions: notification = dict( user=subscription['user'],