mirror of
https://github.com/shouptech/humulus.git
synced 2026-02-03 16:09:44 +00:00
Add style selection in forms
This commit is contained in:
parent
868d12fced
commit
40fe65cd69
7 changed files with 82 additions and 11 deletions
|
|
@ -27,7 +27,9 @@ from wtforms import (Form, StringField, DecimalField, TextAreaField, FieldList,
|
|||
from wtforms.validators import DataRequired, Optional
|
||||
|
||||
from humulus.auth import login_required
|
||||
from humulus.couch import get_doc_or_404, put_doc, update_doc, get_view
|
||||
from humulus.couch import (get_doc, get_doc_or_404, put_doc, update_doc,
|
||||
get_view)
|
||||
from humulus.styles import get_styles_list
|
||||
|
||||
bp = Blueprint('recipes', __name__, url_prefix='/recipes')
|
||||
|
||||
|
|
@ -169,6 +171,7 @@ class RecipeForm(FlaskForm):
|
|||
max_entries=20
|
||||
)
|
||||
yeast = FormField(YeastForm)
|
||||
style = SelectField('Style', choices=[], validators=[Optional()])
|
||||
|
||||
@property
|
||||
def doc(self):
|
||||
|
|
@ -182,7 +185,8 @@ class RecipeForm(FlaskForm):
|
|||
'volume': str(self.volume.data),
|
||||
'notes': self.notes.data,
|
||||
'$type': 'recipe',
|
||||
'type': self.type.data
|
||||
'type': self.type.data,
|
||||
'style': self.style.data
|
||||
}
|
||||
|
||||
recipe['fermentables'] = [f.doc for f in self.fermentables]
|
||||
|
|
@ -202,6 +206,7 @@ class RecipeForm(FlaskForm):
|
|||
self.efficiency.data = Decimal(data['efficiency'])
|
||||
self.volume.data = Decimal(data['volume'])
|
||||
self.notes.data = data['notes']
|
||||
self.style.data = data['style']
|
||||
|
||||
for fermentable in data['fermentables']:
|
||||
self.fermentables.append_entry({
|
||||
|
|
@ -282,6 +287,7 @@ def index():
|
|||
@login_required
|
||||
def create():
|
||||
form = RecipeForm()
|
||||
form.style.choices = get_styles_list()
|
||||
|
||||
if form.validate_on_submit():
|
||||
response = put_doc(form.doc)
|
||||
|
|
@ -308,7 +314,17 @@ def create_json():
|
|||
|
||||
@bp.route('/info/<id>')
|
||||
def info(id):
|
||||
return render_template('recipes/info.html', recipe=get_doc_or_404(id))
|
||||
recipe = get_doc_or_404(id)
|
||||
|
||||
style = None
|
||||
if recipe['style'] != '':
|
||||
try:
|
||||
style = get_doc(recipe['style'])
|
||||
except KeyError:
|
||||
flash('Could not find style `{}`.'.format(recipe['style']),
|
||||
'warning')
|
||||
|
||||
return render_template('recipes/info.html', recipe=recipe, style=style)
|
||||
|
||||
|
||||
@bp.route('/info/<id>/json')
|
||||
|
|
@ -334,6 +350,7 @@ def delete(id):
|
|||
def update(id):
|
||||
# Get the recipe from the database and validate it is the same revision
|
||||
form = RecipeForm()
|
||||
form.style.choices = get_styles_list()
|
||||
recipe = get_doc_or_404(id)
|
||||
if form.validate_on_submit():
|
||||
if recipe['_rev'] != request.args.get('rev', None):
|
||||
|
|
|
|||
|
|
@ -103,6 +103,20 @@ def import_styles(url):
|
|||
put_doc(doc)
|
||||
|
||||
|
||||
def get_styles_list():
|
||||
"""Returns a list containing id and names of all styles."""
|
||||
view = get_view('_design/styles', 'by-category')
|
||||
styles = [['', '']]
|
||||
for row in view(include_docs=False)['rows']:
|
||||
print(row)
|
||||
styles.append([row['id'], '{}{} {}'.format(
|
||||
row['key'][0],
|
||||
row['key'][1],
|
||||
row['value']
|
||||
)])
|
||||
return styles
|
||||
|
||||
|
||||
@click.command('import-styles')
|
||||
@with_appcontext
|
||||
def import_command():
|
||||
|
|
|
|||
|
|
@ -26,9 +26,12 @@
|
|||
-#}
|
||||
<div class="row">
|
||||
<div class="col-sm-6">{{ render_field_with_errors(form.name) }}</div>
|
||||
<div class="col-sm-2">{{ render_field_with_errors(form.type) }}</div>
|
||||
<div class="col-sm-2">{{ render_field_with_errors(form.efficiency, 'ingredient-field') }}</div>
|
||||
<div class="col-sm-2">{{ render_field_with_errors(form.volume, 'ingredient-field') }}</div>
|
||||
<div class="col-sm-3">{{ render_field_with_errors(form.efficiency, 'ingredient-field') }}</div>
|
||||
<div class="col-sm-3">{{ render_field_with_errors(form.volume, 'ingredient-field') }}</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm">{{ render_field_with_errors(form.style) }}</div>
|
||||
<div class="col-sm">{{ render_field_with_errors(form.type) }}</div>
|
||||
</div>
|
||||
{#-
|
||||
Fermentable Ingredients
|
||||
|
|
|
|||
|
|
@ -20,7 +20,9 @@
|
|||
|
||||
{% block body %}
|
||||
<div class="row"><h1>{{ recipe.name }}</h1></div>
|
||||
|
||||
{% if style %}
|
||||
<div class="row"><h2>{{ style.id }} {{ style.name }}</h2></div>
|
||||
{% endif %}
|
||||
{#-
|
||||
Recipe Details
|
||||
-#}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,8 @@ def app():
|
|||
'notes': 'Test',
|
||||
'volume': '5.5',
|
||||
'fermentables': [],
|
||||
'hops': []
|
||||
'hops': [],
|
||||
'style': ''
|
||||
})
|
||||
put_doc({
|
||||
'_id': 'partial-yeast-recipe',
|
||||
|
|
@ -66,7 +67,8 @@ def app():
|
|||
'name': 'US-05',
|
||||
'low_attenuation': '60',
|
||||
'high_attenuation': '72',
|
||||
}
|
||||
},
|
||||
'style': ''
|
||||
})
|
||||
put_doc({
|
||||
'_id': 'full-recipe',
|
||||
|
|
@ -76,6 +78,7 @@ def app():
|
|||
'name': 'Awesome Beer',
|
||||
'notes': 'This is a test beer that contains most possible fields.',
|
||||
'volume': '2.5',
|
||||
'style': 'style_1A',
|
||||
'fermentables': [
|
||||
{
|
||||
'name': '2row',
|
||||
|
|
@ -181,6 +184,7 @@ def sample_recipes():
|
|||
'lager': {
|
||||
'efficiency': '72',
|
||||
'type': 'All-Grain',
|
||||
'style': '',
|
||||
'fermentables': [
|
||||
{
|
||||
'amount': '9.5',
|
||||
|
|
@ -239,6 +243,7 @@ def sample_recipes():
|
|||
'sweetstout': {
|
||||
'efficiency': '72',
|
||||
'type': 'All-Grain',
|
||||
'style': '',
|
||||
'fermentables': [
|
||||
{
|
||||
'amount': '2.75',
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ def test_create(client, app, auth):
|
|||
'name': 'Test',
|
||||
'notes': 'Test',
|
||||
'volume': '5.5',
|
||||
'style': 'style_1A'
|
||||
}
|
||||
response = client.post('/recipes/create', data=data)
|
||||
assert response.status_code == 302
|
||||
|
|
@ -147,6 +148,7 @@ def test_create(client, app, auth):
|
|||
assert doc['notes'] == 'Test'
|
||||
assert doc['volume'] == '5.5'
|
||||
assert doc['efficiency'] == '65'
|
||||
assert doc['style'] == 'style_1A'
|
||||
|
||||
|
||||
def test_update(client, app, auth):
|
||||
|
|
@ -205,8 +207,12 @@ def test_update(client, app, auth):
|
|||
assert 'Update conflict' in flash_message
|
||||
|
||||
|
||||
def test_info(client):
|
||||
def test_info(client, monkeypatch):
|
||||
"""Test success in retrieving a recipe document."""
|
||||
def mock_get_doc(id):
|
||||
# This function always raises KeyError
|
||||
raise KeyError(id)
|
||||
|
||||
# Validate 404
|
||||
response = client.get('/recipes/info/thisdoesnotexist')
|
||||
assert response.status_code == 404
|
||||
|
|
@ -216,6 +222,17 @@ def test_info(client):
|
|||
assert response.status_code == 200
|
||||
assert b'Awesome Lager' in response.data
|
||||
|
||||
# Validate response for recipe with style
|
||||
response = client.get('/recipes/info/full-recipe')
|
||||
assert response.status_code == 200
|
||||
assert b'Awesome Beer' in response.data
|
||||
assert b'Test Style' in response.data
|
||||
|
||||
# Validate warning is flashed when style cannot be found
|
||||
monkeypatch.setattr('humulus.recipes.get_doc', mock_get_doc)
|
||||
response = client.get('/recipes/info/full-recipe')
|
||||
assert b'Could not find style' in response.data
|
||||
|
||||
|
||||
def test_info_json(client):
|
||||
"""Test success in retrieving a JSON recipe."""
|
||||
|
|
@ -279,6 +296,7 @@ def test_recipe_form_doc(app):
|
|||
recipe.volume.data = Decimal('5.5')
|
||||
recipe.notes.data = 'This is a test'
|
||||
recipe.type.data = 'All-Grain'
|
||||
recipe.style.data = 'style_1A'
|
||||
|
||||
assert recipe.doc == {
|
||||
'name': 'Test',
|
||||
|
|
@ -289,6 +307,7 @@ def test_recipe_form_doc(app):
|
|||
'fermentables': [],
|
||||
'hops': [],
|
||||
'$type': 'recipe',
|
||||
'style': 'style_1A'
|
||||
}
|
||||
|
||||
ferm = FermentableForm()
|
||||
|
|
@ -321,6 +340,7 @@ def test_recipe_form_doc(app):
|
|||
'volume': '5.5',
|
||||
'notes': 'This is a test',
|
||||
'$type': 'recipe',
|
||||
'style': 'style_1A',
|
||||
'fermentables': [{
|
||||
'name': 'Test',
|
||||
'type': 'Grain',
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from humulus.styles import import_styles, sub_to_doc
|
||||
from humulus.styles import import_styles, sub_to_doc, get_styles_list
|
||||
|
||||
COMPLETE_STYLE = '''<subcategory id="1A">
|
||||
<name>Test Style</name>
|
||||
|
|
@ -182,6 +182,16 @@ def test_import_command(runner, monkeypatch):
|
|||
assert 'Imported BJCP styles.' in result.output
|
||||
|
||||
|
||||
def test_get_styles_choices(app):
|
||||
"""Test success in getting list of styles."""
|
||||
with app.app_context():
|
||||
styles = get_styles_list()
|
||||
assert styles == [
|
||||
['', ''],
|
||||
['style_1A', '1A Test Style']
|
||||
]
|
||||
|
||||
|
||||
def test_index(auth, client):
|
||||
"""Test success in retrieving index."""
|
||||
# Test not logged in
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue