diff --git a/pillar/web/utils/jstree.py b/pillar/web/utils/jstree.py
index 0f8e0cac..37b1f262 100644
--- a/pillar/web/utils/jstree.py
+++ b/pillar/web/utils/jstree.py
@@ -1,3 +1,5 @@
+import logging
+
from flask import Markup
from pillarsdk import Node
@@ -8,6 +10,7 @@ from flask_login import current_user
from pillar.web import system_util
GROUP_NODES = {'group', 'storage', 'group_texture', 'group_hdri'}
+log = logging.getLogger(__name__)
def jstree_parse_node(node, children=None):
@@ -17,7 +20,10 @@ def jstree_parse_node(node, children=None):
node_type = node.node_type
# Define better the node type
if node_type == 'asset':
- node_type = node.properties.content_type
+ 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
parsed_node = dict(
id="n_{0}".format(node._id),
diff --git a/tests/test_web/test_jstree.py b/tests/test_web/test_jstree.py
new file mode 100644
index 00000000..adc256a1
--- /dev/null
+++ b/tests/test_web/test_jstree.py
@@ -0,0 +1,67 @@
+from unittest import mock
+
+from bson import ObjectId
+from dateutil.parser import parse
+from flask import Markup
+
+from pillarsdk import Node
+from pillar.tests import AbstractPillarTest
+
+
+class JSTreeTest(AbstractPillarTest):
+ def test_jstree_parse_node(self):
+ from pillar.web.utils.jstree import jstree_parse_node
+
+ node_doc = {'_id': ObjectId('55f338f92beb3300c4ff99fe'),
+ '_created': parse('2015-09-11T22:26:33.000+0200'),
+ '_updated': parse('2015-10-30T22:44:27.000+0100'),
+ '_etag': '5248485b4ea7e55e858ff84b1bd4aae88917a37c',
+ 'picture': ObjectId('55f338f92beb3300c4ff99de'),
+ 'description': 'Play the full movie and see how it was cobbled together.',
+ 'parent': ObjectId('55f338f92beb3300c4ff99f9'),
+ 'project': ObjectId('55f338f92beb3300c4ff99e5'),
+ 'node_type': 'asset',
+ 'user': ObjectId('552b066b41acdf5dec4436f2'),
+ 'properties': {'status': 'published',
+ 'file': ObjectId('55f338f92beb3300c4ff99c2'),
+ 'content_type': 'file'},
+ 'name': 'Live Edit'}
+
+ # Mocking url_for_node prevents us from setting up a project and an URLer service.
+ with mock.patch('pillar.web.nodes.routes.url_for_node') as mock_url_for_node:
+ mock_url_for_node.return_value = '/the/url'
+ parsed = jstree_parse_node(Node(node_doc))
+
+ self.assertEqual(parsed, {
+ 'id': 'n_55f338f92beb3300c4ff99fe',
+ 'a_attr': {'href': '/the/url'},
+ 'li_attr': {'data-node-type': 'asset'},
+ 'text': Markup('Live <strong>Edit</strong>'),
+ 'type': 'file',
+ 'children': False,
+ })
+ def test_jstree_parse_just_created_node(self):
+ from pillar.web.utils.jstree import jstree_parse_node
+
+ node_doc = {'_id': ObjectId('55f338f92beb3300c4ff99fe'),
+ '_created': parse('2015-09-11T22:26:33.000+0200'),
+ '_updated': parse('2015-10-30T22:44:27.000+0100'),
+ '_etag': '5248485b4ea7e55e858ff84b1bd4aae88917a37c',
+ 'project': ObjectId('55f338f92beb3300c4ff99e5'),
+ 'node_type': 'asset',
+ 'user': ObjectId('552b066b41acdf5dec4436f2'),
+ 'name': 'Live Edit'}
+
+ # Mocking url_for_node prevents us from setting up a project and an URLer service.
+ with mock.patch('pillar.web.nodes.routes.url_for_node') as mock_url_for_node:
+ mock_url_for_node.return_value = '/the/url'
+ parsed = jstree_parse_node(Node(node_doc))
+
+ self.assertEqual(parsed, {
+ 'id': 'n_55f338f92beb3300c4ff99fe',
+ 'a_attr': {'href': '/the/url'},
+ 'li_attr': {'data-node-type': 'asset'},
+ 'text': Markup('Live <strong>Edit</strong>'),
+ 'type': 'asset',
+ 'children': False,
+ })