From b601644cca2e05bc834e98b145850820dbecd9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Wed, 29 Jun 2016 16:44:00 +0200 Subject: [PATCH] Update parent node's _updated when updating/creating an asset --- .../modules/blender_cloud/home_project.py | 112 +++++++++++++----- 1 file changed, 81 insertions(+), 31 deletions(-) diff --git a/pillar/application/modules/blender_cloud/home_project.py b/pillar/application/modules/blender_cloud/home_project.py index 69fa04fd..f0199e54 100644 --- a/pillar/application/modules/blender_cloud/home_project.py +++ b/pillar/application/modules/blender_cloud/home_project.py @@ -1,7 +1,8 @@ import copy import logging +import datetime -from bson import ObjectId +from bson import ObjectId, tz_util from eve.methods.post import post_internal from eve.methods.put import put_internal from eve.methods.get import get @@ -209,6 +210,55 @@ def is_home_project(project_id, user_id): '_deleted': False}) > 0 +def mark_node_updated(node_id): + """Uses pymongo to set the node's _updated to "now".""" + + now = datetime.datetime.now(tz=tz_util.utc) + nodes_coll = current_app.data.driver.db['nodes'] + + return nodes_coll.update_one({'_id': node_id}, + {'$set': {'_updated': now}}) + + +def get_home_project_parent_node(node, projection, name_for_log): + """Returns a partial parent node document, but only if the node is a home project node.""" + + user_id = authentication.current_user_id() + if not user_id: + log.debug('%s: user not logged in.', name_for_log) + return None + + parent_id = node.get('parent') + if not parent_id: + log.debug('%s: ignoring top-level node.', name_for_log) + return None + + project_id = node.get('project') + if not project_id: + log.debug('%s: ignoring node without project ID', name_for_log) + return None + + project_id = ObjectId(project_id) + if not is_home_project(project_id, user_id): + log.debug('%s: node not part of home project.', name_for_log) + return None + + # Get the parent node for permission checking. + parent_id = ObjectId(parent_id) + + nodes_coll = current_app.data.driver.db['nodes'] + projection['project'] = 1 + parent_node = nodes_coll.find_one(parent_id, projection=projection) + + if parent_node['project'] != project_id: + log.warning('%s: User %s is trying to reference ' + 'parent node %s from different project %s, expected project %s.', + name_for_log, user_id, parent_id, parent_node['project'], project_id) + raise wz_exceptions.BadRequest('Trying to create cross-project links.') + + return parent_node + + def check_home_project_nodes_permissions(nodes): for node in nodes: check_home_project_node_permissions(node) @@ -217,38 +267,15 @@ def check_home_project_nodes_permissions(nodes): def check_home_project_node_permissions(node): """Grants POST access to the node when the user has POST access on its parent.""" - user_id = authentication.current_user_id() - if not user_id: - log.debug('check_home_project_node_permissions: user not logged in.') + parent_node = get_home_project_parent_node(node, + {'permissions': 1, + 'project': 1, + 'node_type': 1}, + 'check_home_project_node_permissions') + if parent_node is None: return - parent_id = node.get('parent') - if not parent_id: - log.debug('check_home_project_node_permissions: not checking for top-level node.') - return - - project_id = node.get('project') - if not project_id: - log.debug('check_home_project_node_permissions: ignoring node without project ID') - return - - project_id = ObjectId(project_id) - if not is_home_project(project_id, user_id): - log.debug('check_home_project_node_permissions: node not part of home project.') - return - - # Get the parent node for permission checking. - parent_id = ObjectId(parent_id) - nodes_coll = current_app.data.driver.db['nodes'] - parent_node = nodes_coll.find_one(parent_id, - projection={'permissions': 1, - 'project': 1, - 'node_type': 1}) - if parent_node['project'] != project_id: - log.warning('check_home_project_node_permissions: User %s is trying to reference ' - 'parent node %s from different project %s, expected project %s.', - user_id, parent_id, parent_node['project'], project_id) - raise wz_exceptions.BadRequest('Trying to create cross-project links.') + parent_id = parent_node['_id'] has_access = authorization.has_permissions('nodes', parent_node, 'POST') if not has_access: @@ -264,7 +291,30 @@ def check_home_project_node_permissions(node): node['permissions'] = copy.deepcopy(parent_node['permissions']) +def mark_parents_as_updated(nodes): + for node in nodes: + mark_parent_as_updated(node) + + +def mark_parent_as_updated(node, original=None): + parent_node = get_home_project_parent_node(node, + {'permissions': 1, + 'node_type': 1}, + 'mark_parent_as_updated') + if parent_node is None: + return + + # Mark the parent node as 'updated' if this is an asset and the parent is a group. + if node.get('node_type') == 'asset' and parent_node['node_type'] == 'group': + log.debug('Node %s updated, marking parent=%s as updated too', + node['_id'], parent_node['_id']) + mark_node_updated(parent_node['_id']) + + def setup_app(app, url_prefix): app.register_blueprint(blueprint, url_prefix=url_prefix) app.on_insert_nodes += check_home_project_nodes_permissions + app.on_inserted_nodes += mark_parents_as_updated + app.on_updated_nodes += mark_parent_as_updated + app.on_replaced_nodes += mark_parent_as_updated