Attachment rendering for posts & node descriptions.
This commit is contained in:
@@ -7,12 +7,14 @@ _file_embedded_schema = {
|
||||
}
|
||||
}
|
||||
|
||||
ATTACHMENT_SLUG_REGEX = '[a-zA-Z0-9_ ]+'
|
||||
|
||||
_attachments_embedded_schema = {
|
||||
'type': 'dict',
|
||||
# TODO: will be renamed to 'keyschema' in Cerberus 1.0
|
||||
'propertyschema': {
|
||||
'type': 'string',
|
||||
'regex': '^[a-zA-Z0-9_ ]+$',
|
||||
'regex': '^%s$' % ATTACHMENT_SLUG_REGEX,
|
||||
},
|
||||
'valueschema': {
|
||||
'type': 'dict',
|
||||
|
@@ -691,7 +691,7 @@ def upgrade_attachment_schema(proj_url=None, all_projects=False):
|
||||
nodes = nodes_coll.find({
|
||||
'project': project['_id'],
|
||||
'node_type': {'$in': list(node_type_names)},
|
||||
'properties.attachments.0': {'$exists': True},
|
||||
'properties.attachments': {'$exists': True},
|
||||
})
|
||||
for node in nodes:
|
||||
log.info(' - Updating schema on node %s (%s)', node['_id'], node.get('name'))
|
||||
|
88
pillar/web/nodes/attachments.py
Normal file
88
pillar/web/nodes/attachments.py
Normal file
@@ -0,0 +1,88 @@
|
||||
import logging
|
||||
import re
|
||||
|
||||
from bson import ObjectId
|
||||
import flask
|
||||
import pillarsdk
|
||||
|
||||
from pillar.api.node_types import ATTACHMENT_SLUG_REGEX
|
||||
from pillar.web.utils import system_util
|
||||
|
||||
shortcode_re = re.compile(r'@\[(%s)\]' % ATTACHMENT_SLUG_REGEX)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def render_attachments(node, field_value):
|
||||
"""Renders attachments referenced in the field value.
|
||||
|
||||
Returns the rendered field.
|
||||
"""
|
||||
|
||||
# TODO: cache this based on the node's etag and attachment links expiry.
|
||||
|
||||
node_attachments = node[u'properties'][u'attachments']
|
||||
if isinstance(node_attachments, list):
|
||||
log.warning('Old-style attachments property found on node %s. Ignoring them, '
|
||||
'will result in attachments not being found.', node[u'_id'])
|
||||
return field_value
|
||||
|
||||
if not node_attachments:
|
||||
return field_value
|
||||
|
||||
def replace(match):
|
||||
slug = match.group(1)
|
||||
|
||||
try:
|
||||
att = node_attachments[slug]
|
||||
except KeyError:
|
||||
return u'[attachment "%s" not found]' % slug
|
||||
|
||||
return render_attachment(att)
|
||||
|
||||
return shortcode_re.sub(replace, field_value)
|
||||
|
||||
|
||||
def render_attachment(attachment):
|
||||
"""Renders an attachment as HTML"""
|
||||
|
||||
oid = ObjectId(attachment[u'oid'])
|
||||
collection = attachment.collection or u'files'
|
||||
|
||||
renderers = {
|
||||
'files': render_attachment_file
|
||||
}
|
||||
|
||||
try:
|
||||
renderer = renderers[collection]
|
||||
except KeyError:
|
||||
log.error(u'Unable to render attachment from collection %s', collection)
|
||||
return u'Unable to render attachment'
|
||||
|
||||
return renderer(oid)
|
||||
|
||||
|
||||
def render_attachment_file(oid):
|
||||
"""Renders a file attachment."""
|
||||
|
||||
api = system_util.pillar_api()
|
||||
sdk_file = pillarsdk.File.find(oid, api=api)
|
||||
|
||||
file_renderers = {
|
||||
'image': render_attachment_file_image
|
||||
}
|
||||
|
||||
mime_type_cat, _ = sdk_file.content_type.split('/', 1)
|
||||
try:
|
||||
renderer = file_renderers[mime_type_cat]
|
||||
except KeyError:
|
||||
return flask.render_template('nodes/attachments/file_generic.html', file=sdk_file)
|
||||
|
||||
return renderer(sdk_file)
|
||||
|
||||
|
||||
def render_attachment_file_image(sdk_file):
|
||||
"""Renders an image file."""
|
||||
|
||||
variations = {var.size: var for var in sdk_file.variations}
|
||||
return flask.render_template('nodes/attachments/file_image.html',
|
||||
file=sdk_file, vars=variations)
|
@@ -14,6 +14,7 @@ from pillar.web.nodes.routes import blueprint
|
||||
from pillar.web.nodes.routes import url_for_node
|
||||
from pillar.web.nodes.forms import get_node_form
|
||||
from pillar.web.nodes.forms import process_node_form
|
||||
import pillar.web.nodes.attachments
|
||||
from pillar.web.projects.routes import project_update_nodes_list
|
||||
|
||||
|
||||
@@ -53,6 +54,9 @@ def posts_view(project_id=None, project_url=None, url=None):
|
||||
if not (current_user.is_authenticated and post.has_method('PUT')):
|
||||
abort(403)
|
||||
|
||||
post['properties']['content'] = pillar.web.nodes.attachments.render_attachments(
|
||||
post, post['properties']['content'])
|
||||
|
||||
return render_template(
|
||||
'nodes/custom/post/view.html',
|
||||
blog=blog,
|
||||
@@ -72,6 +76,9 @@ def posts_view(project_id=None, project_url=None, url=None):
|
||||
for post in posts._items:
|
||||
post.picture = get_file(post.picture, api=api)
|
||||
|
||||
post['properties']['content'] = pillar.web.nodes.attachments.render_attachments(
|
||||
post, post['properties']['content'])
|
||||
|
||||
return render_template(
|
||||
'nodes/custom/blog/index.html',
|
||||
node_type_post=node_type_post,
|
||||
|
@@ -22,6 +22,7 @@ from wtforms import SelectMultipleField
|
||||
from flask_login import login_required
|
||||
from jinja2.exceptions import TemplateNotFound
|
||||
|
||||
import pillar.web.nodes.attachments
|
||||
from pillar.web.utils import caching
|
||||
from pillar.web.nodes.forms import get_node_form
|
||||
from pillar.web.nodes.forms import process_node_form
|
||||
@@ -260,6 +261,8 @@ def _view_handler_asset(node, template_path, template_action, link_allowed):
|
||||
# Treat it as normal file (zip, blend, application, etc)
|
||||
asset_type = 'file'
|
||||
|
||||
node['description'] = pillar.web.nodes.attachments.render_attachments(node, node['description'])
|
||||
|
||||
template_path = os.path.join(template_path, asset_type)
|
||||
|
||||
return template_path, template_action
|
||||
|
Reference in New Issue
Block a user