1
0
Fork 0
mirror of https://github.com/shouptech/humulus.git synced 2026-02-03 20:49:44 +00:00

Compare commits

..

2 commits

Author SHA1 Message Date
5968623b76 Add link back to style 2019-07-08 15:33:28 -06:00
40fe65cd69 Add style selection in forms 2019-07-08 14:59:50 -06:00
7 changed files with 88 additions and 11 deletions

View file

@ -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):

View file

@ -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():

View file

@ -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

View file

@ -20,7 +20,15 @@
{% block body %}
<div class="row"><h1>{{ recipe.name }}</h1></div>
{% if style %}
<div class="row">
{% if session.logged_in %}
<h2><a href="{{ url_for('styles.info', id=style._id) }}">{{ style.id }} {{ style.name }}</a></h2>
{% else %}
<h2>{{ style.id }} {{ style.name }}</h2>
{% endif %}
</div>
{% endif %}
{#-
Recipe Details
-#}

View file

@ -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',

View file

@ -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',

View file

@ -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