Page MenuHome
No OneTemporary

import logging
from datetime import datetime
from datetime import date
import pillarsdk
from flask import current_app
from flask_wtf import Form
from wtforms import StringField
from wtforms import DateField
from wtforms import SelectField
from wtforms import HiddenField
from wtforms import BooleanField
from wtforms import IntegerField
from wtforms import FloatField
from wtforms import TextAreaField
from wtforms import DateTimeField
from wtforms import SelectMultipleField
from wtforms import FieldList
from wtforms.validators import DataRequired
from pillar.web.utils import system_util
from pillar.web.utils.forms import FileSelectField
from pillar.web.utils.forms import CustomFormField
from pillar.web.utils.forms import build_file_select_form
from . import attachments
log = logging.getLogger(__name__)
def iter_node_properties(node_type):
"""Generator, iterates over all node properties with form schema."""
node_schema = node_type['dyn_schema'].to_dict()
form_schema = node_type['form_schema'].to_dict()
for prop_name, prop_schema in node_schema.items():
prop_fschema = form_schema.get(prop_name, {})
if not prop_fschema.get('visible', True):
yield prop_name, prop_schema, prop_fschema
def add_form_properties(form_class, node_type):
"""Add fields to a form based on the node and form schema provided.
:type node_schema: dict
:param node_schema: the validation schema used by Cerberus
:type form_class: class
:param form_class: The form class to which we append fields
:type form_schema: dict
:param form_schema: description of how to build the form (which fields to
show and hide)
for prop_name, schema_prop, form_prop in iter_node_properties(node_type):
# Recursive call if detects a dict
field_type = schema_prop['type']
if field_type == 'dict':
assert prop_name == 'attachments'
field = attachments.attachment_form_group_create(schema_prop)
elif field_type == 'list':
if prop_name == 'files':
schema = schema_prop['schema']['schema']
file_select_form = build_file_select_form(schema)
field = FieldList(CustomFormField(file_select_form),
elif 'allowed' in schema_prop['schema']:
choices = [(c, c) for c in schema_prop['schema']['allowed']]
field = SelectMultipleField(choices=choices)
field = SelectMultipleField(choices=[])
elif 'allowed' in schema_prop:
select = []
for option in schema_prop['allowed']:
select.append((str(option), str(option)))
field = SelectField(choices=select)
elif field_type == 'datetime':
if form_prop.get('dateonly'):
field = DateField(prop_name,
field = DateTimeField(prop_name,
elif field_type == 'integer':
field = IntegerField(prop_name, default=0)
elif field_type == 'float':
field = FloatField(prop_name, default=0.0)
elif field_type == 'boolean':
field = BooleanField(prop_name)
elif field_type == 'objectid' and 'data_relation' in schema_prop:
if schema_prop['data_relation']['resource'] == 'files':
field = FileSelectField(prop_name)
field = StringField(prop_name)
elif schema_prop.get('maxlength', 0) > 64:
field = TextAreaField(prop_name)
field = StringField(prop_name)
setattr(form_class, prop_name, field)
def get_node_form(node_type):
"""Get a procedurally generated WTForm, based on the dyn_schema and
node_schema of a specific node_type.
:type node_type: dict
:param node_type: Describes the node type via dyn_schema, form_schema and
class ProceduralForm(Form):
parent_prop = node_type['parent'] = StringField('Name', validators=[DataRequired()])
# Parenting
if parent_prop:
parent_names = ", ".join(parent_prop)
ProceduralForm.parent = HiddenField('Parent ({0})'.format(parent_names))
ProceduralForm.description = TextAreaField('Description')
ProceduralForm.picture = FileSelectField('Picture', file_format='image')
ProceduralForm.node_type = HiddenField(default=node_type['name'])
add_form_properties(ProceduralForm, node_type)
return ProceduralForm()
def recursive(path, rdict, data):
item = path.pop(0)
if not item in rdict:
rdict[item] = {}
if len(path) > 0:
rdict[item] = recursive(path, rdict[item], data)
rdict[item] = data
return rdict
def process_node_form(form, node_id=None, node_type=None, user=None):
"""Generic function used to process new nodes, as well as edits
if not user:
log.warning('process_node_form(node_id=%s) called while user not logged in', node_id)
return False
api = system_util.pillar_api()
node_schema = node_type['dyn_schema'].to_dict()
form_schema = node_type['form_schema'].to_dict()
if node_id:
# Update existing node
node = pillarsdk.Node.find(node_id, api=api) =
node.description =
if 'picture' in form:
node.picture =
if node.picture == 'None' or node.picture == '':
node.picture = None
if 'parent' in form:
if != "":
node.parent =
for prop_name, schema_prop, form_prop in iter_node_properties(node_type):
data = form[prop_name].data
if schema_prop['type'] == 'dict':
data = attachments.attachment_form_parse_post_data(data)
elif schema_prop['type'] == 'integer':
if not data:
data = None
data = int(form[prop_name].data)
elif schema_prop['type'] == 'float':
if not data:
data = None
data = float(form[prop_name].data)
elif schema_prop['type'] == 'datetime':
data = datetime.strftime(data, current_app.config['RFC1123_DATE_FORMAT'])
elif schema_prop['type'] == 'list':
if prop_name == 'files':
# Only keep those items that actually refer to a file.
data = [file_item for file_item in data
if file_item.get('file')]
log.warning('Ignoring property %s of type %s',
prop_name, schema_prop['type'])
# elif pr == 'tags':
# data = [tag.strip() for tag in data.split(',')]
elif schema_prop['type'] == 'objectid':
if data == '':
# Set empty object to None so it gets removed by the
# SDK before node.update()
data = None
if prop_name in form:
data = form[prop_name].data
path = prop_name.split('__')
assert len(path) == 1
if len(path) > 1:
recursive_prop = recursive(
path,, data) = recursive_prop
else:[prop_name] = data
ok = node.update(api=api)
if not ok:
log.warning('Unable to update node: %s', node.error)
# if
# image_data = request.files[].read()
# post = node.replace_picture(image_data, api=api)
return ok
# Create a new node
node = pillarsdk.Node()
prop = {}
files = {}
prop['name'] =
prop['description'] =
prop['user'] = user
if 'picture' in form:
prop['picture'] =
if prop['picture'] == 'None' or prop['picture'] == '':
prop['picture'] = None
if 'parent' in form:
prop['parent'] =
prop['properties'] = {}
def get_data(node_schema, form_schema, prefix=""):
for pr in node_schema:
schema_prop = node_schema[pr]
form_prop = form_schema.get(pr, {})
if pr == 'items':
if 'visible' in form_prop and not form_prop['visible']:
prop_name = "{0}{1}".format(prefix, pr)
if schema_prop['type'] == 'dict':
data = form[prop_name].data
if schema_prop['type'] == 'media':
tmpfile = '/tmp/binary_data'
binfile = open(tmpfile, 'rb')
files[pr] = binfile
if schema_prop['type'] == 'integer':
if data == '':
data = 0
if schema_prop['type'] == 'list':
if data == '':
data = []
if schema_prop['type'] == 'datetime':
data = datetime.strftime(data, app.config['RFC1123_DATE_FORMAT'])
if schema_prop['type'] == 'objectid':
if data == '':
data = None
path = prop_name.split('__')
if len(path) > 1:
prop['properties'] = recursive(path, prop['properties'], data)
prop['properties'][prop_name] = data
get_data(node_schema, form_schema)
prop['node_type'] =
post =, api=api)
return post

File Metadata

Mime Type
Tue, Jul 14, 2:28 AM (2 d)
Storage Engine
Storage Format
Raw Data
Storage Handle

Event Timeline