mirror of
https://github.com/shouptech/humulus.git
synced 2026-02-03 18:19:42 +00:00
Add complete recipe update capability
This commit is contained in:
parent
6233b089cf
commit
5f7639232c
5 changed files with 290 additions and 141 deletions
|
|
@ -30,7 +30,7 @@ bp = Blueprint('recipes', __name__, url_prefix='/recipes')
|
||||||
class FermentableForm(Form):
|
class FermentableForm(Form):
|
||||||
"""Form for fermentables.
|
"""Form for fermentables.
|
||||||
|
|
||||||
CSRF is disabled for this subform (using `Form as parent class) because it
|
CSRF is disabled for this form.yeast.form (using `Form as parent class) because it
|
||||||
is never used by itself.
|
is never used by itself.
|
||||||
"""
|
"""
|
||||||
name = StringField('Name', validators=[DataRequired()])
|
name = StringField('Name', validators=[DataRequired()])
|
||||||
|
|
@ -60,7 +60,7 @@ class FermentableForm(Form):
|
||||||
class HopForm(Form):
|
class HopForm(Form):
|
||||||
"""Form for hops.
|
"""Form for hops.
|
||||||
|
|
||||||
CSRF is disabled for this subform (using `Form as parent class) because it
|
CSRF is disabled for this form.yeast.form (using `Form as parent class) because it
|
||||||
is never used by itself.
|
is never used by itself.
|
||||||
"""
|
"""
|
||||||
name = StringField('Name', validators=[DataRequired()])
|
name = StringField('Name', validators=[DataRequired()])
|
||||||
|
|
@ -89,7 +89,7 @@ class HopForm(Form):
|
||||||
class YeastForm(Form):
|
class YeastForm(Form):
|
||||||
"""Form for yeast.
|
"""Form for yeast.
|
||||||
|
|
||||||
CSRF is disabled for this subform (using `Form as parent class) because it
|
CSRF is disabled for this form.yeast.form (using `Form as parent class) because it
|
||||||
is never used by itself.
|
is never used by itself.
|
||||||
"""
|
"""
|
||||||
name = StringField('Name', validators=[Optional()])
|
name = StringField('Name', validators=[Optional()])
|
||||||
|
|
@ -173,9 +173,7 @@ class RecipeForm(FlaskForm):
|
||||||
'notes': self.notes.data
|
'notes': self.notes.data
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(self.fermentables) > 0:
|
|
||||||
recipe['fermentables'] = [f.doc for f in self.fermentables]
|
recipe['fermentables'] = [f.doc for f in self.fermentables]
|
||||||
if len(self.hops) > 0:
|
|
||||||
recipe['hops'] = [h.doc for h in self.hops]
|
recipe['hops'] = [h.doc for h in self.hops]
|
||||||
if self.yeast.doc['name']:
|
if self.yeast.doc['name']:
|
||||||
recipe['yeast'] = self.yeast.doc
|
recipe['yeast'] = self.yeast.doc
|
||||||
|
|
@ -208,9 +206,8 @@ def delete(id):
|
||||||
@bp.route('/update/<id>', methods=('GET', 'POST'))
|
@bp.route('/update/<id>', methods=('GET', 'POST'))
|
||||||
def update(id):
|
def update(id):
|
||||||
# Get the recipe from the database and validate it is the same revision
|
# Get the recipe from the database and validate it is the same revision
|
||||||
recipe = get_doc_or_404(id)
|
|
||||||
|
|
||||||
form = RecipeForm()
|
form = RecipeForm()
|
||||||
|
recipe = get_doc_or_404(id)
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
if recipe['_rev'] != request.args.get('rev', None):
|
if recipe['_rev'] != request.args.get('rev', None):
|
||||||
flash(
|
flash(
|
||||||
|
|
@ -218,7 +215,7 @@ def update(id):
|
||||||
'Update conflict for recipe: {}. '
|
'Update conflict for recipe: {}. '
|
||||||
'Your changes have been lost.'.format(recipe['name'])
|
'Your changes have been lost.'.format(recipe['name'])
|
||||||
),
|
),
|
||||||
'error'
|
'danger'
|
||||||
)
|
)
|
||||||
return redirect(url_for('recipes.info', id=id))
|
return redirect(url_for('recipes.info', id=id))
|
||||||
# Copy values from submitted form to the existing recipe and save
|
# Copy values from submitted form to the existing recipe and save
|
||||||
|
|
@ -228,5 +225,61 @@ def update(id):
|
||||||
|
|
||||||
flash('Updated recipe: {}'.format(form.name.data), 'success')
|
flash('Updated recipe: {}'.format(form.name.data), 'success')
|
||||||
return redirect(url_for('recipes.info', id=id))
|
return redirect(url_for('recipes.info', id=id))
|
||||||
|
else:
|
||||||
|
# Copy the recipe's data into the form.
|
||||||
|
# Is there an easier way to do this?
|
||||||
|
form.name.data = recipe['name']
|
||||||
|
form.efficiency.data = Decimal(recipe['efficiency'])
|
||||||
|
form.volume.data = Decimal(recipe['volume'])
|
||||||
|
form.notes.data = recipe['notes']
|
||||||
|
|
||||||
return render_template('recipes/update.html', form=form)
|
for fermentable in recipe['fermentables']:
|
||||||
|
form.fermentables.append_entry({
|
||||||
|
'name': fermentable['name'],
|
||||||
|
'type': fermentable['type'],
|
||||||
|
'amount': Decimal(fermentable['amount']),
|
||||||
|
'ppg': Decimal(fermentable['ppg']),
|
||||||
|
'color': Decimal(fermentable['color'])
|
||||||
|
})
|
||||||
|
|
||||||
|
for hop in recipe['hops']:
|
||||||
|
form.hops.append_entry({
|
||||||
|
'name': hop['name'],
|
||||||
|
'use': hop['use'],
|
||||||
|
'alpha': Decimal(hop['alpha']),
|
||||||
|
'duration': Decimal(hop['duration']),
|
||||||
|
'amount': Decimal(hop['amount']),
|
||||||
|
})
|
||||||
|
|
||||||
|
if 'yeast' in recipe:
|
||||||
|
yeast = recipe['yeast']
|
||||||
|
form.yeast.form.name.data = yeast['name']
|
||||||
|
form.yeast.form.low_attenuation.data = (
|
||||||
|
Decimal(yeast['low_attenuation'])
|
||||||
|
)
|
||||||
|
form.yeast.form.high_attenuation.data = (
|
||||||
|
Decimal(yeast['high_attenuation'])
|
||||||
|
)
|
||||||
|
if 'type' in yeast:
|
||||||
|
form.yeast.form.type.data = yeast['type']
|
||||||
|
if 'lab' in yeast:
|
||||||
|
form.yeast.form.lab.data = yeast['lab']
|
||||||
|
if 'code' in yeast:
|
||||||
|
form.yeast.form.code.data = yeast['code']
|
||||||
|
if 'flocculation' in yeast:
|
||||||
|
form.yeast.form.flocculation.data = yeast['flocculation']
|
||||||
|
if 'min_temperature' in yeast:
|
||||||
|
form.yeast.form.min_temperature.data = (
|
||||||
|
Decimal(yeast['min_temperature'])
|
||||||
|
)
|
||||||
|
if 'max_temperature' in yeast:
|
||||||
|
form.yeast.form.max_temperature.data = (
|
||||||
|
Decimal(yeast['max_temperature'])
|
||||||
|
)
|
||||||
|
if 'abv_tolerance' in yeast:
|
||||||
|
form.yeast.form.abv_tolerance.data = (
|
||||||
|
Decimal(yeast['abv_tolerance'])
|
||||||
|
)
|
||||||
|
|
||||||
|
return render_template('recipes/update.html', form=form,
|
||||||
|
id=id, rev=recipe['_rev'])
|
||||||
|
|
|
||||||
130
src/humulus/templates/recipes/_macros.html
Normal file
130
src/humulus/templates/recipes/_macros.html
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
{#-
|
||||||
|
Copyright 2019 Mike Shoup
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-#}
|
||||||
|
{% from "_macros.html" import render_field_with_errors %}
|
||||||
|
|
||||||
|
{#
|
||||||
|
Used to render a form for creating/updating a recipe
|
||||||
|
#}
|
||||||
|
{% macro render_recipe_form(form, action_url, button_content) %}
|
||||||
|
<form method="POST" action="{{ action_url }}">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
{#-
|
||||||
|
Recipe Details
|
||||||
|
-#}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6">{{ render_field_with_errors(form.name) }}</div>
|
||||||
|
<div class="col-sm-3">{{ render_field_with_errors(form.efficiency) }}</div>
|
||||||
|
<div class="col-sm-3">{{ render_field_with_errors(form.volume) }}</div>
|
||||||
|
</div>
|
||||||
|
{#-
|
||||||
|
Fermentable Ingredients
|
||||||
|
-#}
|
||||||
|
<div class="row"><div class="col"><h3>Fermentables</h3></div></div>
|
||||||
|
<div id="ferms" data-length="{{ form.fermentables|length }}">
|
||||||
|
{% for fermentable in form.fermentables %}
|
||||||
|
<div class="border pl-2 pr-2 pt-1 pb-1 ferm-form" data-index="{{ loop.index0 }}">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
{{ render_field_with_errors(fermentable.form.name, 'form-control-sm') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm">{{ render_field_with_errors(fermentable.form.type, 'form-control-sm') }}</div>
|
||||||
|
<div class="col-sm">{{ render_field_with_errors(fermentable.form.amount, 'form-control-sm') }}</div>
|
||||||
|
<div class="col-sm">{{ render_field_with_errors(fermentable.form.ppg, 'form-control-sm') }}</div>
|
||||||
|
<div class="col-sm">{{ render_field_with_errors(fermentable.form.color, 'form-control-sm') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<button type="button" class="float-right btn btn-sm btn-outline-danger rem-ferm">Remove fermentable</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="row pt-1 pb-1">
|
||||||
|
<div class="col">
|
||||||
|
<button type="button" id="add-ferm" class="btn btn-secondary btn-sm">Add a fermentable</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{#-
|
||||||
|
Hop ingredients
|
||||||
|
-#}
|
||||||
|
<div class="row"><div class="col"><h3>Hops</h3></div></div>
|
||||||
|
<div id="hops" data-length="{{ form.hops|length }}">
|
||||||
|
{% for hop in form.hops %}
|
||||||
|
<div class="border pl-2 pr-2 pt-1 pb-1 hop-form" data-index="{{ loop.index0 }}">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
{{ render_field_with_errors(hop.form.name, 'form-control-sm') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm">{{ render_field_with_errors(hop.form.use, 'form-control-sm') }}</div>
|
||||||
|
<div class="col-sm">{{ render_field_with_errors(hop.form.alpha, 'form-control-sm') }}</div>
|
||||||
|
<div class="col-sm">{{ render_field_with_errors(hop.form.duration, 'form-control-sm') }}</div>
|
||||||
|
<div class="col-sm">{{ render_field_with_errors(hop.form.amount, 'form-control-sm') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<button type="button" class="float-right btn btn-sm btn-outline-danger rem-hop">Remove Hop</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="row pt-1 pb-1">
|
||||||
|
<div class="col">
|
||||||
|
<button type="button" id="add-hop" class="btn btn-secondary btn-sm">Add a hop</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{#-
|
||||||
|
Recipe Yeast
|
||||||
|
-#}
|
||||||
|
<div class="row"><div class="col"><h3>Yeast</h3></div></div>
|
||||||
|
<div id="yeast">
|
||||||
|
<div class="border pl-2 pr-2 pt-1 pb-1 yeast-form">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6">{{ render_field_with_errors(form.yeast.form.name, 'form-control-sm') }}</div>
|
||||||
|
<div class="col-sm-2">{{ render_field_with_errors(form.yeast.form.type, 'form-control-sm') }}</div>
|
||||||
|
<div class="col-sm-2">{{ render_field_with_errors(form.yeast.form.lab, 'form-control-sm') }}</div>
|
||||||
|
<div class="col-sm-2">{{ render_field_with_errors(form.yeast.form.code, 'form-control-sm') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm">{{ render_field_with_errors(form.yeast.form.low_attenuation, 'form-control-sm') }}</div>
|
||||||
|
<div class="col-sm">{{ render_field_with_errors(form.yeast.form.high_attenuation, 'form-control-sm') }}</div>
|
||||||
|
<div class="col-sm">{{ render_field_with_errors(form.yeast.form.flocculation, 'form-control-sm') }}</div>
|
||||||
|
<div class="col-sm">{{ render_field_with_errors(form.yeast.form.min_temperature, 'form-control-sm') }}</div>
|
||||||
|
<div class="col-sm">{{ render_field_with_errors(form.yeast.form.max_temperature, 'form-control-sm') }}</div>
|
||||||
|
<div class="col-sm">{{ render_field_with_errors(form.yeast.form.abv_tolerance, 'form-control-sm') }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{#-
|
||||||
|
Recipe Notes
|
||||||
|
-#}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">{{ render_field_with_errors(form.notes) }}</div>
|
||||||
|
</div>
|
||||||
|
{#-
|
||||||
|
Submit recipe
|
||||||
|
-#}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col"><button type="submit" class="btn btn-primary">{{ button_content }}</button></div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<script src="{{ url_for('static', filename='recipes.js') }}"></script>
|
||||||
|
{% endmacro %}
|
||||||
|
|
@ -13,119 +13,12 @@
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-#}
|
-#}
|
||||||
{% from "_macros.html" import render_field_with_errors %}
|
{% from "recipes/_macros.html" import render_recipe_form %}
|
||||||
|
|
||||||
{% extends '_base.html' %}
|
{% extends '_base.html' %}
|
||||||
{% block title %}Create Recipe{% endblock %}
|
{% block title %}Create Recipe{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="row"><h1>Create a new recipe</h1></div>
|
<div class="row"><h1>Create a new recipe</h1></div>
|
||||||
<form method="POST" action="{{ url_for('recipes.create') }}">
|
{{ render_recipe_form(form, url_for('recipes.create'), 'Create recipe') }}
|
||||||
{{ form.hidden_tag() }}
|
|
||||||
{#-
|
|
||||||
Recipe Details
|
|
||||||
-#}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-6">{{ render_field_with_errors(form.name) }}</div>
|
|
||||||
<div class="col-sm-3">{{ render_field_with_errors(form.efficiency) }}</div>
|
|
||||||
<div class="col-sm-3">{{ render_field_with_errors(form.volume) }}</div>
|
|
||||||
</div>
|
|
||||||
{#-
|
|
||||||
Fermentable Ingredients
|
|
||||||
-#}
|
|
||||||
<div class="row"><div class="col"><h3>Fermentables</h3></div></div>
|
|
||||||
<div id="ferms" data-length="{{ form.fermentables|length }}">
|
|
||||||
{% for fermentable in form.fermentables %}
|
|
||||||
<div class="border pl-2 pr-2 pt-1 pb-1 ferm-form" data-index="{{ loop.index0 }}">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
{{ render_field_with_errors(fermentable.form.name, 'form-control-sm') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm">{{ render_field_with_errors(fermentable.form.type, 'form-control-sm') }}</div>
|
|
||||||
<div class="col-sm">{{ render_field_with_errors(fermentable.form.amount, 'form-control-sm') }}</div>
|
|
||||||
<div class="col-sm">{{ render_field_with_errors(fermentable.form.ppg, 'form-control-sm') }}</div>
|
|
||||||
<div class="col-sm">{{ render_field_with_errors(fermentable.form.color, 'form-control-sm') }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<button type="button" class="float-right btn btn-sm btn-outline-danger rem-ferm">Remove fermentable</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<div class="row pt-1 pb-1">
|
|
||||||
<div class="col">
|
|
||||||
<button type="button" id="add-ferm" class="btn btn-secondary btn-sm">Add a fermentable</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{#-
|
|
||||||
Hop ingredients
|
|
||||||
-#}
|
|
||||||
<div class="row"><div class="col"><h3>Hops</h3></div></div>
|
|
||||||
<div id="hops" data-length="{{ form.hops|length }}">
|
|
||||||
{% for hop in form.hops %}
|
|
||||||
<div class="border pl-2 pr-2 pt-1 pb-1 hop-form" data-index="{{ loop.index0 }}">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
{{ render_field_with_errors(hop.form.name, 'form-control-sm') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm">{{ render_field_with_errors(hop.form.use, 'form-control-sm') }}</div>
|
|
||||||
<div class="col-sm">{{ render_field_with_errors(hop.form.alpha, 'form-control-sm') }}</div>
|
|
||||||
<div class="col-sm">{{ render_field_with_errors(hop.form.duration, 'form-control-sm') }}</div>
|
|
||||||
<div class="col-sm">{{ render_field_with_errors(hop.form.amount, 'form-control-sm') }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<button type="button" class="float-right btn btn-sm btn-outline-danger rem-hop">Remove Hop</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<div class="row pt-1 pb-1">
|
|
||||||
<div class="col">
|
|
||||||
<button type="button" id="add-hop" class="btn btn-secondary btn-sm">Add a hop</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{#-
|
|
||||||
Recipe Yeast
|
|
||||||
-#}
|
|
||||||
<div class="row"><div class="col"><h3>Yeast</h3></div></div>
|
|
||||||
<div id="yeast">
|
|
||||||
<div class="border pl-2 pr-2 pt-1 pb-1 yeast-form">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-6">{{ render_field_with_errors(form.yeast.form.name, 'form-control-sm') }}</div>
|
|
||||||
<div class="col-sm-2">{{ render_field_with_errors(form.yeast.form.type, 'form-control-sm') }}</div>
|
|
||||||
<div class="col-sm-2">{{ render_field_with_errors(form.yeast.form.lab, 'form-control-sm') }}</div>
|
|
||||||
<div class="col-sm-2">{{ render_field_with_errors(form.yeast.form.code, 'form-control-sm') }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm">{{ render_field_with_errors(form.yeast.form.low_attenuation, 'form-control-sm') }}</div>
|
|
||||||
<div class="col-sm">{{ render_field_with_errors(form.yeast.form.high_attenuation, 'form-control-sm') }}</div>
|
|
||||||
<div class="col-sm">{{ render_field_with_errors(form.yeast.form.flocculation, 'form-control-sm') }}</div>
|
|
||||||
<div class="col-sm">{{ render_field_with_errors(form.yeast.form.min_temperature, 'form-control-sm') }}</div>
|
|
||||||
<div class="col-sm">{{ render_field_with_errors(form.yeast.form.max_temperature, 'form-control-sm') }}</div>
|
|
||||||
<div class="col-sm">{{ render_field_with_errors(form.yeast.form.abv_tolerance, 'form-control-sm') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{#-
|
|
||||||
Recipe Notes
|
|
||||||
-#}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">{{ render_field_with_errors(form.notes) }}</div>
|
|
||||||
</div>
|
|
||||||
{#-
|
|
||||||
Submit recipe
|
|
||||||
-#}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col"><button type="submit" class="btn btn-primary">Create Recipe</button></div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<script src="{{ url_for('static', filename='recipes.js') }}"></script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
{#-
|
||||||
|
Copyright 2019 Mike Shoup
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-#}
|
||||||
|
{% from "recipes/_macros.html" import render_recipe_form %}
|
||||||
|
|
||||||
|
{% extends '_base.html' %}
|
||||||
|
{% block title %}Update | {{ form.name.data }}{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div class="row"><h1>{{ form.name.data }}</h1></div>
|
||||||
|
{{ render_recipe_form(form, url_for('recipes.update', id=id, rev=rev), 'Update recipe') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
from humulus.couch import get_db, get_doc
|
from humulus.couch import get_db, get_doc, put_doc
|
||||||
from humulus.recipes import FermentableForm, HopForm, RecipeForm, YeastForm
|
from humulus.recipes import FermentableForm, HopForm, RecipeForm, YeastForm
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -45,37 +45,84 @@ def test_create(client, app):
|
||||||
|
|
||||||
def test_update(client, app):
|
def test_update(client, app):
|
||||||
"""Test success in updating a recipe document."""
|
"""Test success in updating a recipe document."""
|
||||||
# Test GET
|
|
||||||
id = 'awesome-lager'
|
|
||||||
response = client.get('/recipes/update/{}'.format(id))
|
|
||||||
|
|
||||||
# Get the doc, test a change, then post the update
|
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
data = get_doc(id)
|
doc = put_doc({
|
||||||
# Remove values that should not be posted with the data
|
'_id': 'test-update',
|
||||||
rev = data.pop('_rev') # Save the revision, will be used later
|
'name': 'Test Update',
|
||||||
data.pop('_id')
|
'efficiency': '60',
|
||||||
# Make a change to the data
|
'volume': '5.5',
|
||||||
data['name'] = '{} TEST'.format(data['name'])
|
'notes': 'This is a test',
|
||||||
|
'fermentables': [],
|
||||||
|
'hops': []
|
||||||
|
})
|
||||||
|
|
||||||
# Test valid response
|
# Test GET
|
||||||
response = client.post('/recipes/update/{}'.format(id),
|
response = client.get('/recipes/update/test-update')
|
||||||
query_string={'rev': rev}, data=data)
|
assert response.status_code == 200
|
||||||
|
assert b'Test Update' in response.data
|
||||||
|
|
||||||
|
# Make a change to the doc
|
||||||
|
data = {
|
||||||
|
'name': 'New Name',
|
||||||
|
'efficiency': '60',
|
||||||
|
'volume': '5.5',
|
||||||
|
'notes': 'This is a test'
|
||||||
|
}
|
||||||
|
response = client.post('/recipes/update/test-update',
|
||||||
|
query_string={'rev': doc['_rev']}, data=data)
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
with client.session_transaction() as session:
|
with client.session_transaction() as session:
|
||||||
flash_message = dict(session['_flashes']).get('error')
|
flash_message = dict(session['_flashes']).pop('danger', None)
|
||||||
assert flash_message is None
|
assert flash_message is None
|
||||||
# Validate document update
|
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
updated = get_doc(id)
|
updated = get_doc('test-update')
|
||||||
assert updated['name'] == data['name']
|
assert updated['name'] == 'New Name'
|
||||||
|
|
||||||
|
# Test form is filled correctly with ingredients
|
||||||
|
with app.app_context():
|
||||||
|
doc = put_doc({
|
||||||
|
'_id': 'test-update-1',
|
||||||
|
'name': 'Test Update With Ingredients',
|
||||||
|
'efficiency': '60',
|
||||||
|
'volume': '5.5',
|
||||||
|
'notes': 'This is a test',
|
||||||
|
'fermentables': [{
|
||||||
|
'name': '2-row',
|
||||||
|
'type': 'Grain',
|
||||||
|
'amount': '5',
|
||||||
|
'ppg': '37',
|
||||||
|
'color': '1.8'
|
||||||
|
}],
|
||||||
|
'hops': [{
|
||||||
|
'name': 'Nugget',
|
||||||
|
'use': 'Boil',
|
||||||
|
'alpha': '5.5',
|
||||||
|
'duration': '60',
|
||||||
|
'amount': '1'
|
||||||
|
}],
|
||||||
|
'yeast': {
|
||||||
|
'name': 'California Ale',
|
||||||
|
'low_attenuation': '70',
|
||||||
|
'high_attenuation': '80',
|
||||||
|
'type': 'Liquid',
|
||||||
|
'lab': 'Inland Island',
|
||||||
|
'code': 'INIS-001',
|
||||||
|
'flocculation': 'Medium',
|
||||||
|
'min_temperature': '60',
|
||||||
|
'max_temperature': '70',
|
||||||
|
'abv_tolerance': '15'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
response = client.get('/recipes/update/test-update-1')
|
||||||
|
assert b'Test Update With Ingredients' in response.data
|
||||||
|
|
||||||
|
|
||||||
# Test response without valid/conflicted rev
|
# Test response without valid/conflicted rev
|
||||||
response = client.post('/recipes/update/{}'.format(id),
|
response = client.post('/recipes/update/test-update',
|
||||||
query_string={'rev': ''}, data=data)
|
query_string={'rev': ''}, data=data)
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
with client.session_transaction() as session:
|
with client.session_transaction() as session:
|
||||||
flash_message = dict(session['_flashes']).get('error')
|
flash_message = dict(session['_flashes']).pop('danger', None)
|
||||||
assert 'Update conflict' in flash_message
|
assert 'Update conflict' in flash_message
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -145,6 +192,8 @@ def test_recipe_form_doc(app):
|
||||||
'efficiency': '65',
|
'efficiency': '65',
|
||||||
'volume': '5.5',
|
'volume': '5.5',
|
||||||
'notes': 'This is a test',
|
'notes': 'This is a test',
|
||||||
|
'fermentables': [],
|
||||||
|
'hops': [],
|
||||||
}
|
}
|
||||||
|
|
||||||
ferm = FermentableForm()
|
ferm = FermentableForm()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue