2017-09-14 12:09:54 +02:00
|
|
|
import logging
|
|
|
|
|
2016-11-08 18:25:23 +01:00
|
|
|
from flask import Markup
|
|
|
|
|
2016-08-19 09:19:06 +02:00
|
|
|
from pillarsdk import Node
|
|
|
|
from pillarsdk.exceptions import ForbiddenAccess
|
|
|
|
from pillarsdk.exceptions import ResourceNotFound
|
2016-09-29 17:34:24 +02:00
|
|
|
from flask_login import current_user
|
2016-08-19 09:19:06 +02:00
|
|
|
|
|
|
|
from pillar.web import system_util
|
|
|
|
|
|
|
|
GROUP_NODES = {'group', 'storage', 'group_texture', 'group_hdri'}
|
2017-09-28 17:50:31 +02:00
|
|
|
|
|
|
|
# Node types that shouldn't be embedded in the project view.
|
|
|
|
# Rather those nodes have their own end point for viewing.
|
|
|
|
# Such nodes should implement a finder in web/nodes/finders.py.
|
2018-04-16 16:22:38 +02:00
|
|
|
CUSTOM_VIEW_NODE_TYPES = {'blog', 'page'}
|
2017-09-28 17:50:31 +02:00
|
|
|
|
2017-09-14 12:09:54 +02:00
|
|
|
log = logging.getLogger(__name__)
|
2016-08-19 09:19:06 +02:00
|
|
|
|
|
|
|
|
|
|
|
def jstree_parse_node(node, children=None):
|
|
|
|
"""Generate JStree node from node object"""
|
2016-10-04 12:38:00 +02:00
|
|
|
from pillar.web.nodes.routes import url_for_node
|
|
|
|
|
2016-08-19 09:19:06 +02:00
|
|
|
node_type = node.node_type
|
|
|
|
# Define better the node type
|
|
|
|
if node_type == 'asset':
|
2017-09-14 12:09:54 +02:00
|
|
|
if not node.properties or not node.properties.content_type:
|
|
|
|
log.warning('Asset node %s has no node.properties.content_type: %s', node._id, node)
|
|
|
|
else:
|
|
|
|
node_type = node.properties.content_type
|
2016-11-29 15:35:12 +01:00
|
|
|
|
2016-08-19 09:19:06 +02:00
|
|
|
parsed_node = dict(
|
|
|
|
id="n_{0}".format(node._id),
|
2016-11-25 12:45:29 +01:00
|
|
|
a_attr={"href": url_for_node(node=node)},
|
|
|
|
li_attr={"data-node-type": node.node_type},
|
2017-09-28 17:50:31 +02:00
|
|
|
custom_view=node_type in CUSTOM_VIEW_NODE_TYPES,
|
2016-11-08 18:25:23 +01:00
|
|
|
text=Markup.escape(node.name),
|
2016-08-19 09:19:06 +02:00
|
|
|
type=node_type,
|
|
|
|
children=False)
|
2016-11-29 15:35:12 +01:00
|
|
|
|
2016-08-19 09:19:06 +02:00
|
|
|
# Append children property only if it is a directory type
|
|
|
|
if node_type in GROUP_NODES:
|
|
|
|
parsed_node['children'] = True
|
|
|
|
|
2016-11-29 15:35:12 +01:00
|
|
|
if node.permissions and node.permissions.world:
|
|
|
|
parsed_node['li_attr']['is_free'] = True
|
|
|
|
|
2016-08-19 09:19:06 +02:00
|
|
|
return parsed_node
|
|
|
|
|
|
|
|
|
|
|
|
def jstree_get_children(node_id, project_id=None):
|
|
|
|
api = system_util.pillar_api()
|
|
|
|
children_list = []
|
|
|
|
lookup = {
|
|
|
|
'projection': {
|
|
|
|
'name': 1, 'parent': 1, 'node_type': 1, 'properties.order': 1,
|
|
|
|
'properties.status': 1, 'properties.content_type': 1, 'user': 1,
|
|
|
|
'project': 1},
|
2016-09-29 17:34:24 +02:00
|
|
|
'sort': [('properties.order', 1), ('_created', 1)],
|
|
|
|
'where': {
|
|
|
|
'$and': [
|
|
|
|
{'node_type': {'$regex': '^(?!attract_)'}},
|
2018-09-13 16:16:52 +02:00
|
|
|
{'node_type': {'$not': {'$in': ['comment', 'post', 'blog', 'page']}}},
|
2016-09-29 17:34:24 +02:00
|
|
|
],
|
|
|
|
}
|
|
|
|
}
|
2016-08-19 09:19:06 +02:00
|
|
|
if node_id:
|
|
|
|
if node_id.startswith('n_'):
|
|
|
|
node_id = node_id.split('_')[1]
|
2016-09-29 17:34:24 +02:00
|
|
|
lookup['where']['parent'] = node_id
|
2016-08-19 09:19:06 +02:00
|
|
|
elif project_id:
|
2016-09-29 17:34:24 +02:00
|
|
|
lookup['where']['project'] = project_id
|
|
|
|
lookup['where']['parent'] = {'$exists': False}
|
2016-08-19 09:19:06 +02:00
|
|
|
|
|
|
|
try:
|
|
|
|
children = Node.all(lookup, api=api)
|
|
|
|
for child in children['_items']:
|
2016-11-25 12:56:41 +01:00
|
|
|
# TODO: allow nodes that don't have a status property to be visible
|
|
|
|
# in the node tree (for example blog)
|
2016-09-29 17:34:24 +02:00
|
|
|
is_pub = child.properties.status == 'published'
|
|
|
|
if is_pub or (current_user.is_authenticated and child.user == current_user.objectid):
|
|
|
|
children_list.append(jstree_parse_node(child))
|
2016-08-19 09:19:06 +02:00
|
|
|
except ForbiddenAccess:
|
|
|
|
pass
|
|
|
|
return children_list
|
|
|
|
|
|
|
|
|
|
|
|
def jstree_build_children(node):
|
|
|
|
return dict(
|
|
|
|
id="n_{0}".format(node._id),
|
2016-11-08 18:25:23 +01:00
|
|
|
text=Markup.escape(node.name),
|
2016-08-19 09:19:06 +02:00
|
|
|
type=node.node_type,
|
|
|
|
children=jstree_get_children(node._id)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def jstree_build_from_node(node):
|
|
|
|
"""Give a node, traverse the tree bottom to top and expand the relevant
|
|
|
|
branches.
|
|
|
|
|
|
|
|
:param node: the base node, where tree building starts
|
|
|
|
"""
|
|
|
|
api = system_util.pillar_api()
|
|
|
|
# Parse the node and mark it as selected
|
|
|
|
child_node = jstree_parse_node(node)
|
2016-11-29 14:39:47 +01:00
|
|
|
child_node['state'] = dict(selected=True, opened=True)
|
2016-08-19 09:19:06 +02:00
|
|
|
|
|
|
|
# Splice the specified child node between the other project children.
|
|
|
|
def select_node(x):
|
|
|
|
if x['id'] == child_node['id']:
|
|
|
|
return child_node
|
|
|
|
return x
|
|
|
|
|
|
|
|
# Get the parent node
|
|
|
|
parent = None
|
2017-12-22 12:29:51 +01:00
|
|
|
parent_projection = {'projection': {
|
|
|
|
'name': 1,
|
|
|
|
'parent': 1,
|
|
|
|
'project': 1,
|
|
|
|
'node_type': 1,
|
|
|
|
'properties.content_type': 1,
|
|
|
|
}}
|
|
|
|
|
2016-08-19 09:19:06 +02:00
|
|
|
if node.parent:
|
|
|
|
try:
|
2017-12-22 12:29:51 +01:00
|
|
|
parent = Node.find(node.parent, parent_projection, api=api)
|
2016-08-19 09:19:06 +02:00
|
|
|
# Define the child node of the tree (usually an asset)
|
|
|
|
except ResourceNotFound:
|
|
|
|
# If not found, we might be on the top level, in which case we skip the
|
|
|
|
# while loop and use child_node
|
|
|
|
pass
|
|
|
|
except ForbiddenAccess:
|
|
|
|
pass
|
|
|
|
|
|
|
|
while parent:
|
|
|
|
# Get the parent's parent
|
|
|
|
parent_parent = jstree_parse_node(parent)
|
|
|
|
# Get the parent's children (this will also include child_node)
|
|
|
|
parent_children = [select_node(x) for x in jstree_get_children(parent_parent['id'])]
|
|
|
|
parent_parent.pop('children', None)
|
|
|
|
# Overwrite children_node with the current parent
|
|
|
|
child_node = parent_parent
|
|
|
|
# Set the node to open so that jstree actually displays the nodes
|
2016-11-29 14:39:47 +01:00
|
|
|
child_node['state'] = dict(selected=True, opened=True)
|
2016-08-19 09:19:06 +02:00
|
|
|
# Push in the computed children into the parent
|
|
|
|
child_node['children'] = parent_children
|
|
|
|
# If we have a parent
|
|
|
|
if parent.parent:
|
|
|
|
try:
|
2017-12-22 12:29:51 +01:00
|
|
|
parent = Node.find(parent.parent, parent_projection, api=api)
|
2016-08-19 09:19:06 +02:00
|
|
|
except ResourceNotFound:
|
|
|
|
parent = None
|
|
|
|
else:
|
|
|
|
parent = None
|
|
|
|
# Get top level nodes for the project
|
|
|
|
project_children = jstree_get_children(None, node.project)
|
|
|
|
|
|
|
|
nodes_list = [select_node(x) for x in project_children]
|
|
|
|
return nodes_list
|