diff --git a/attract/__init__.py b/attract/__init__.py index a9a671a..10430e7 100644 --- a/attract/__init__.py +++ b/attract/__init__.py @@ -88,9 +88,10 @@ class AttractExtension(PillarExtension): def setup_app(self, app): """Connects Blinker signals and sets up other app-dependent stuff in submodules.""" - from . import subversion, tasks, eve_hooks, shots + from . import comments, subversion, tasks, eve_hooks, shots subversion.task_logged.connect(self.task_manager.api_task_logged_in_svn) + comments.setup_app(app) tasks.setup_app(app) shots.setup_app(app) eve_hooks.setup_app(app) @@ -165,14 +166,21 @@ class AttractExtension(PillarExtension): def activities_for_node(self, node_id, max_results=20, page=1): """Returns a page of activities for the given task or shot. + Activities that are either on this node or have this node as context + are returned. + :returns: {'_items': [task, task, ...], '_meta': {Eve metadata}} """ api = pillar_api() activities = pillarsdk.Activity.all({ 'where': { - 'object_type': 'node', - 'object': node_id, + '$or': [ + {'object_type': 'node', + 'object': node_id}, + {'context_object_type': 'node', + 'context_object': node_id}, + ], }, 'sort': [('_created', -1)], 'max_results': max_results, diff --git a/attract/comments/__init__.py b/attract/comments/__init__.py new file mode 100644 index 0000000..7bdb461 --- /dev/null +++ b/attract/comments/__init__.py @@ -0,0 +1,5 @@ + +def setup_app(app): + from . import eve_hooks + + eve_hooks.setup_app(app) diff --git a/attract/comments/eve_hooks.py b/attract/comments/eve_hooks.py new file mode 100644 index 0000000..c0b14ec --- /dev/null +++ b/attract/comments/eve_hooks.py @@ -0,0 +1,39 @@ +import logging + +from pillar.api.nodes import only_for_node_type_decorator +import pillar.api.activities +import pillar.api.utils.authentication + +log = logging.getLogger(__name__) + +comment_nodes_only = only_for_node_type_decorator('comment') + + +@comment_nodes_only +def activity_after_creating_node(comment): + comment_id = comment['_id'] + parent_id = comment.get('parent', None) + + if not parent_id: + log.warning('Comment %s created without parent.' % comment_id) + return + + log.debug('Recording creation of comment as activity on node %s', parent_id) + + pillar.api.activities.register_activity( + pillar.api.utils.authentication.current_user_id(), + 'commented', + 'node', comment_id, + 'node', parent_id, + project_id=comment.get('project', None), + node_type=comment['node_type'], + ) + + +def activity_after_creating_nodes(nodes): + for node in nodes: + activity_after_creating_node(node) + + +def setup_app(app): + app.on_inserted_nodes += activity_after_creating_nodes diff --git a/attract/shots/eve_hooks.py b/attract/shots/eve_hooks.py index fe177ed..1013ef6 100644 --- a/attract/shots/eve_hooks.py +++ b/attract/shots/eve_hooks.py @@ -48,14 +48,19 @@ def activity_after_replacing_shot(shot, original): human_key = human_readable_properties[key] except KeyError: human_key = pillar.web.jinja.format_undertitle(key.rsplit('.', 1)[-1]) + descr = None - if key == 'properties.status': + # Some key- and value-specific overrides + if val_shot is pillar.api.utils.DoesNotExist: + descr = 'removed "%s" from shot "%s"' % (human_key, shot['name']) + elif key == 'properties.status': val_shot = pillar.web.jinja.format_undertitle(val_shot) elif isinstance(val_shot, basestring) and len(val_shot) > 80: val_shot = val_shot[:80] + u'…' - descr = 'changed "%s" to "%s" in shot "%s"' %\ - (human_key, val_shot, shot['name']) + if descr is None: + descr = 'changed "%s" to "%s" in shot "%s"' %\ + (human_key, val_shot, shot['name']) else: descr = 'edited shot "%s"' % shot['name'] diff --git a/attract/tasks/eve_hooks.py b/attract/tasks/eve_hooks.py index 5955926..3e4bc60 100644 --- a/attract/tasks/eve_hooks.py +++ b/attract/tasks/eve_hooks.py @@ -139,8 +139,10 @@ def activity_after_replacing_task(task, original): human_key = pillar.web.jinja.format_undertitle(key.rsplit('.', 1)[-1]) descr = None - # Some key-specific overrides - if key == 'properties.status': + # Some key- and value-specific overrides + if val_task is pillar.api.utils.DoesNotExist: + descr = 'removed "%s" from shot "%s"' % (human_key, task['name']) + elif key == 'properties.status': val_task = pillar.web.jinja.format_undertitle(val_task) elif key == 'properties.assigned_to.users': human_key = 'assigned users' @@ -148,6 +150,7 @@ def activity_after_replacing_task(task, original): descr = 'assigned task "%s" to %s' % (task['name'], val_task) elif isinstance(val_task, basestring) and len(val_task) > 80: val_task = val_task[:80] + u'…' + if descr is None: descr = 'changed %s to "%s" in task "%s"' % (human_key, val_task, task['name']) else: diff --git a/src/templates/attract/shots/view_shot_embed.jade b/src/templates/attract/shots/view_shot_embed.jade index 5ebb2e6..5f3512a 100644 --- a/src/templates/attract/shots/view_shot_embed.jade +++ b/src/templates/attract/shots/view_shot_embed.jade @@ -116,7 +116,7 @@ script. }); loadActivities("{{ url_for('.activities', project_url=project.url, shot_id=shot['_id']) }}"); // from 10_tasks.js - loadComments("{{ url_for('nodes.comments_for_node', node_id=shot['_id']) }}"); + loadComments("{{ url_for('nodes.commentform_for_node', node_id=shot['_id']) }}"); $('.js-help').openModalUrl('Help', "{{ url_for('attract.help', project_url=project.url) }}");