Procedural node add and edit forms
This commit is contained in:
parent
cc534ae4ef
commit
be5c33c581
@ -23,6 +23,7 @@ thumb = Thumbnail(app)
|
|||||||
assets = Environment(app)
|
assets = Environment(app)
|
||||||
|
|
||||||
# Import controllers
|
# Import controllers
|
||||||
|
from application.modules.nodes import node_types
|
||||||
from application.modules.nodes import nodes
|
from application.modules.nodes import nodes
|
||||||
from application.modules.main import homepage
|
from application.modules.main import homepage
|
||||||
from application.modules.shots import shots
|
from application.modules.shots import shots
|
||||||
@ -32,4 +33,5 @@ from application.modules.projects import projects
|
|||||||
app.register_blueprint(filemanager)
|
app.register_blueprint(filemanager)
|
||||||
app.register_blueprint(shots, url_prefix='/shots')
|
app.register_blueprint(shots, url_prefix='/shots')
|
||||||
app.register_blueprint(projects, url_prefix='/projects')
|
app.register_blueprint(projects, url_prefix='/projects')
|
||||||
|
app.register_blueprint(node_types, url_prefix='/node-types')
|
||||||
app.register_blueprint(nodes, url_prefix='/nodes')
|
app.register_blueprint(nodes, url_prefix='/nodes')
|
||||||
|
@ -11,19 +11,22 @@ from application import db
|
|||||||
|
|
||||||
from application.modules.nodes.models import Node, NodeType
|
from application.modules.nodes.models import Node, NodeType
|
||||||
from application.modules.nodes.forms import NodeTypeForm
|
from application.modules.nodes.forms import NodeTypeForm
|
||||||
|
from application.modules.nodes.forms import get_node_form
|
||||||
|
from application.modules.nodes.forms import process_node_form
|
||||||
|
|
||||||
|
|
||||||
# Name of the Blueprint
|
# Name of the Blueprint
|
||||||
|
node_types = Blueprint('node_types', __name__)
|
||||||
nodes = Blueprint('nodes', __name__)
|
nodes = Blueprint('nodes', __name__)
|
||||||
|
|
||||||
@nodes.route("/")
|
@node_types.route("/")
|
||||||
def index():
|
def index():
|
||||||
"""Display the node types
|
"""Display the node types
|
||||||
"""
|
"""
|
||||||
node_types = [t for t in NodeType.query.all()]
|
node_types = [t for t in NodeType.query.all()]
|
||||||
|
|
||||||
return render_template('nodes/index.html',
|
return render_template('node_types/index.html',
|
||||||
title='nodes',
|
title='node_types',
|
||||||
node_types=node_types)
|
node_types=node_types)
|
||||||
|
|
||||||
shots = []
|
shots = []
|
||||||
@ -45,7 +48,7 @@ def index():
|
|||||||
shots=shots)
|
shots=shots)
|
||||||
|
|
||||||
|
|
||||||
@nodes.route("/add", methods=('GET', 'POST'))
|
@node_types.route("/add", methods=['GET', 'POST'])
|
||||||
def add():
|
def add():
|
||||||
form = NodeTypeForm()
|
form = NodeTypeForm()
|
||||||
|
|
||||||
@ -58,5 +61,52 @@ def add():
|
|||||||
db.session.add(node_type)
|
db.session.add(node_type)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
return redirect(url_for('nodes.index'))
|
return redirect(url_for('node_types.index'))
|
||||||
return render_template('nodes/add.html', form=form)
|
return render_template('node_types/add.html', form=form)
|
||||||
|
|
||||||
|
|
||||||
|
@nodes.route("/<node_type>/add", methods=['GET', 'POST'])
|
||||||
|
def add(node_type):
|
||||||
|
"""Generic function to add a node of any type
|
||||||
|
"""
|
||||||
|
form = get_node_form(node_type)
|
||||||
|
if form.validate_on_submit():
|
||||||
|
if process_node_form(form):
|
||||||
|
return redirect('/')
|
||||||
|
else:
|
||||||
|
print form.errors
|
||||||
|
return render_template('nodes/add.html',
|
||||||
|
node_type=node_type,
|
||||||
|
form=form)
|
||||||
|
|
||||||
|
|
||||||
|
@nodes.route("/<int:node_id>/edit", methods=['GET', 'POST'])
|
||||||
|
def edit(node_id):
|
||||||
|
"""Generic node editing form
|
||||||
|
"""
|
||||||
|
node = Node.query.get_or_404(node_id)
|
||||||
|
form = get_node_form(node.node_type.url)
|
||||||
|
|
||||||
|
if form.validate_on_submit():
|
||||||
|
if process_node_form(form, node_id):
|
||||||
|
return redirect(url_for('node.edit', node_id=node_id))
|
||||||
|
|
||||||
|
form.name.data = node.name
|
||||||
|
form.description.data = node.description
|
||||||
|
|
||||||
|
# We populate the form, basing ourselves on the default node properties
|
||||||
|
for node_property in node.properties:
|
||||||
|
for field in form:
|
||||||
|
if field.name == node_property.custom_field.name_url:
|
||||||
|
value = node_property.value
|
||||||
|
# We cast values into the right type
|
||||||
|
if node_property.custom_field.field_type == 'integer':
|
||||||
|
value = int(value)
|
||||||
|
if node_property.custom_field.field_type == 'select':
|
||||||
|
value = int(value)
|
||||||
|
field.data = value
|
||||||
|
|
||||||
|
|
||||||
|
return render_template('nodes/edit.html',
|
||||||
|
node=node,
|
||||||
|
form=form)
|
@ -4,13 +4,112 @@ from wtforms import BooleanField
|
|||||||
from wtforms import SelectField
|
from wtforms import SelectField
|
||||||
from wtforms import TextAreaField
|
from wtforms import TextAreaField
|
||||||
from wtforms import IntegerField
|
from wtforms import IntegerField
|
||||||
|
from wtforms import HiddenField
|
||||||
|
|
||||||
|
from application.modules.nodes.models import CustomFields
|
||||||
from wtforms.validators import DataRequired
|
from wtforms.validators import DataRequired
|
||||||
|
|
||||||
from application.modules.nodes.models import Node, NodeType
|
from application import db
|
||||||
|
|
||||||
|
from application.modules.nodes.models import Node, NodeType, NodeProperties
|
||||||
|
|
||||||
|
|
||||||
class NodeTypeForm(Form):
|
class NodeTypeForm(Form):
|
||||||
name = TextField('Node Name', validators=[DataRequired()])
|
name = TextField('Name', validators=[DataRequired()])
|
||||||
url = TextField('Url', validators=[DataRequired()])
|
url = TextField('Url', validators=[DataRequired()])
|
||||||
description = TextAreaField('Description', validators=[DataRequired()])
|
description = TextAreaField('Description', validators=[DataRequired()])
|
||||||
is_extended = BooleanField('Is extended')
|
is_extended = BooleanField('Is extended')
|
||||||
|
|
||||||
|
|
||||||
|
def get_node_form(node_type):
|
||||||
|
node_type = NodeType.query.filter_by(url=node_type).first()
|
||||||
|
class ProceduralForm(Form):
|
||||||
|
pass
|
||||||
|
|
||||||
|
setattr(ProceduralForm,
|
||||||
|
'name',
|
||||||
|
TextField('Name', validators=[DataRequired()]))
|
||||||
|
setattr(ProceduralForm,
|
||||||
|
'description',
|
||||||
|
TextAreaField('Description', validators=[DataRequired()]))
|
||||||
|
setattr(ProceduralForm,
|
||||||
|
'node_type_id',
|
||||||
|
HiddenField(default=node_type.id))
|
||||||
|
|
||||||
|
for custom_field in CustomFields.query\
|
||||||
|
.join(NodeType)\
|
||||||
|
.filter(NodeType.url == node_type.url):
|
||||||
|
|
||||||
|
if custom_field.field_type == 'text':
|
||||||
|
field_properties = TextAreaField(custom_field.name,
|
||||||
|
validators=[DataRequired()])
|
||||||
|
elif custom_field.field_type == 'string':
|
||||||
|
field_properties = TextField(custom_field.name,
|
||||||
|
validators=[DataRequired()])
|
||||||
|
elif custom_field.field_type == 'integer':
|
||||||
|
field_properties = IntegerField(custom_field.name,
|
||||||
|
validators=[DataRequired()])
|
||||||
|
elif custom_field.field_type == 'select':
|
||||||
|
options = Node.query\
|
||||||
|
.join(NodeType)\
|
||||||
|
.filter(NodeType.url==custom_field.name_url)\
|
||||||
|
.all()
|
||||||
|
field_properties = SelectField(custom_field.name,
|
||||||
|
coerce=int,
|
||||||
|
choices=[(option.id, option.name) for option in options] )
|
||||||
|
|
||||||
|
setattr(ProceduralForm, custom_field.name_url, field_properties)
|
||||||
|
|
||||||
|
return ProceduralForm()
|
||||||
|
|
||||||
|
|
||||||
|
def process_node_form(form, node_id=None):
|
||||||
|
"""Generic function used to process new nodes, as well as edits
|
||||||
|
"""
|
||||||
|
if form.validate_on_submit():
|
||||||
|
node_type = NodeType.query.get(form.node_type_id.data)
|
||||||
|
if node_id:
|
||||||
|
node = Node.query.get(node_id)
|
||||||
|
node.name = form.name.data
|
||||||
|
node.description = form.description.data
|
||||||
|
else:
|
||||||
|
node = Node(
|
||||||
|
name=form.name.data,
|
||||||
|
description=form.description.data,
|
||||||
|
node_type_id=form.node_type_id.data)
|
||||||
|
db.session.add(node)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
for custom_field in CustomFields.query\
|
||||||
|
.join(NodeType)\
|
||||||
|
.filter(NodeType.url == node_type.url):
|
||||||
|
|
||||||
|
for field in form:
|
||||||
|
if field.name == custom_field.name_url:
|
||||||
|
if node_id:
|
||||||
|
# Query for the indivitual property
|
||||||
|
# TODO: collect all properties and loop through them
|
||||||
|
node_property = NodeProperties.query\
|
||||||
|
.filter_by(node_id=node_id)\
|
||||||
|
.filter_by(custom_field_id=custom_field.id)\
|
||||||
|
.first()
|
||||||
|
if node_property:
|
||||||
|
# Update the value of the property
|
||||||
|
node_property.value = field.data
|
||||||
|
else:
|
||||||
|
# If the property is missing we add it
|
||||||
|
node_property = NodeProperties(
|
||||||
|
node_id=node.id,
|
||||||
|
custom_field_id=custom_field.id,
|
||||||
|
value=field.data)
|
||||||
|
db.session.add(node_property)
|
||||||
|
else:
|
||||||
|
node_property = NodeProperties(
|
||||||
|
node_id=node.id,
|
||||||
|
custom_field_id=custom_field.id,
|
||||||
|
value=field.data)
|
||||||
|
db.session.add(node_property)
|
||||||
|
db.session.commit()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
@ -47,10 +47,12 @@
|
|||||||
<li><a role="menuitem" tabindex="-1" href="">Tasks</a></li>
|
<li><a role="menuitem" tabindex="-1" href="">Tasks</a></li>
|
||||||
<li><a role="menuitem" tabindex="-1" href="">Profile</a></li>
|
<li><a role="menuitem" tabindex="-1" href="">Profile</a></li>
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
|
<li><a role="menuitem" tabindex="-1" href="{{url_for('node_types.index')}}">Task Types</a></li>
|
||||||
|
<li class="divider"></li>
|
||||||
<li><a role="menuitem" tabindex="-1" href="">Log out</a></li>
|
<li><a role="menuitem" tabindex="-1" href="">Log out</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</div><!--/.navbar-collapse -->
|
</div><!--/.navbar-collapse -->
|
||||||
</div>
|
</div>
|
||||||
|
31
attract/application/templates/node_types/add.html
Normal file
31
attract/application/templates/node_types/add.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div class="col-md-9">
|
||||||
|
<h2>Add Node type</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<form method="POST" action="{{url_for('node_types.add')}}">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
<div class="form-group">
|
||||||
|
{{ form.name.label }}
|
||||||
|
{{ form.name(size=20, class='form-control') }}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
{{ form.description.label }}
|
||||||
|
{{ form.description(size=20, class='form-control') }}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
{{ form.url.label }}
|
||||||
|
{{ form.url(size=20, class='form-control') }}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
{{ form.is_extended.label }}
|
||||||
|
{{ form.is_extended(class='form-control') }}
|
||||||
|
</div>
|
||||||
|
<input class="btn btn-default" type="submit" value="Add Node Type">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -44,7 +44,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<a href="{{url_for('nodes.add')}}" class="btn btn-default">Add</a>
|
<a href="{{url_for('node_types.add')}}" class="btn btn-default">Add</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -2,28 +2,25 @@
|
|||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<h2>Add Node type</h2>
|
<h2>Add {{ node_type }}</h2>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<form method="POST" action="{{url_for('nodes.add')}}">
|
<form method="POST" action="{{url_for('nodes.add', node_type=node_type)}}">
|
||||||
{{ form.hidden_tag() }}
|
{% for field in form %}
|
||||||
<div class="form-group">
|
{% if field.name == 'csrf_token' %}
|
||||||
{{ form.name.label }}
|
{{ field }}
|
||||||
{{ form.name(size=20, class='form-control') }}
|
{% else %}
|
||||||
</div>
|
{% if field.type == "HiddenField" %}
|
||||||
<div class="form-group">
|
{{ field }}
|
||||||
{{ form.description.label }}
|
{% else %}
|
||||||
{{ form.description(size=20, class='form-control') }}
|
<div class="form-group">
|
||||||
</div>
|
{{ field.label }}
|
||||||
<div class="form-group">
|
{{ field(class='form-control') }}
|
||||||
{{ form.url.label }}
|
</div>
|
||||||
{{ form.url(size=20, class='form-control') }}
|
{% endif %}
|
||||||
</div>
|
{% endif %}
|
||||||
<div class="form-group">
|
{% endfor %}
|
||||||
{{ form.is_extended.label }}
|
<input class="btn btn-default" type="submit" value="Create {{ node_type.name }}">
|
||||||
{{ form.is_extended(class='form-control') }}
|
|
||||||
</div>
|
|
||||||
<input class="btn btn-default" type="submit" value="Add Node Type">
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
28
attract/application/templates/nodes/edit.html
Normal file
28
attract/application/templates/nodes/edit.html
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div class="col-md-9">
|
||||||
|
<h2>Edit {{ node.node_type.name }}</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<form method="POST" action="{{url_for('nodes.edit', node_id=node.id)}}">
|
||||||
|
{% for field in form %}
|
||||||
|
{% if field.name == 'csrf_token' %}
|
||||||
|
{{ field }}
|
||||||
|
{% else %}
|
||||||
|
{% if field.type == "HiddenField" %}
|
||||||
|
{{ field }}
|
||||||
|
{% else %}
|
||||||
|
<div class="form-group">
|
||||||
|
{{ field.label }}
|
||||||
|
{{ field(class='form-control') }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<input class="btn btn-default" type="submit" value="Edit {{ node.node_type.name }}">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -34,7 +34,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-default btn-xs" href="{{url_for('shots.edit', shot_id=shot['id'])}}"><i class="glyphicon glyphicon-edit"></i> Edit</a>
|
<a class="btn btn-default btn-xs" href="{{url_for('nodes.edit', node_id=shot['id'])}}"><i class="glyphicon glyphicon-edit"></i> Edit</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@ -56,7 +56,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<a href="{{url_for('shots.add')}}" class="btn btn-default">Add</a>
|
<a href="{{url_for('nodes.add', node_type='shot')}}" class="btn btn-default">Add</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user