mirror of
https://github.com/shouptech/humulus.git
synced 2026-02-03 23:19:44 +00:00
Compare commits
No commits in common. "5968623b7630dcb6871ae5aa8bb03224d20657c4" and "868d12fcedf1ee594732becd95c5df21effb266a" have entirely different histories.
5968623b76
...
868d12fced
7 changed files with 11 additions and 88 deletions
|
|
@ -27,9 +27,7 @@ from wtforms import (Form, StringField, DecimalField, TextAreaField, FieldList,
|
||||||
from wtforms.validators import DataRequired, Optional
|
from wtforms.validators import DataRequired, Optional
|
||||||
|
|
||||||
from humulus.auth import login_required
|
from humulus.auth import login_required
|
||||||
from humulus.couch import (get_doc, get_doc_or_404, put_doc, update_doc,
|
from humulus.couch import get_doc_or_404, put_doc, update_doc, get_view
|
||||||
get_view)
|
|
||||||
from humulus.styles import get_styles_list
|
|
||||||
|
|
||||||
bp = Blueprint('recipes', __name__, url_prefix='/recipes')
|
bp = Blueprint('recipes', __name__, url_prefix='/recipes')
|
||||||
|
|
||||||
|
|
@ -171,7 +169,6 @@ class RecipeForm(FlaskForm):
|
||||||
max_entries=20
|
max_entries=20
|
||||||
)
|
)
|
||||||
yeast = FormField(YeastForm)
|
yeast = FormField(YeastForm)
|
||||||
style = SelectField('Style', choices=[], validators=[Optional()])
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def doc(self):
|
def doc(self):
|
||||||
|
|
@ -185,8 +182,7 @@ class RecipeForm(FlaskForm):
|
||||||
'volume': str(self.volume.data),
|
'volume': str(self.volume.data),
|
||||||
'notes': self.notes.data,
|
'notes': self.notes.data,
|
||||||
'$type': 'recipe',
|
'$type': 'recipe',
|
||||||
'type': self.type.data,
|
'type': self.type.data
|
||||||
'style': self.style.data
|
|
||||||
}
|
}
|
||||||
|
|
||||||
recipe['fermentables'] = [f.doc for f in self.fermentables]
|
recipe['fermentables'] = [f.doc for f in self.fermentables]
|
||||||
|
|
@ -206,7 +202,6 @@ class RecipeForm(FlaskForm):
|
||||||
self.efficiency.data = Decimal(data['efficiency'])
|
self.efficiency.data = Decimal(data['efficiency'])
|
||||||
self.volume.data = Decimal(data['volume'])
|
self.volume.data = Decimal(data['volume'])
|
||||||
self.notes.data = data['notes']
|
self.notes.data = data['notes']
|
||||||
self.style.data = data['style']
|
|
||||||
|
|
||||||
for fermentable in data['fermentables']:
|
for fermentable in data['fermentables']:
|
||||||
self.fermentables.append_entry({
|
self.fermentables.append_entry({
|
||||||
|
|
@ -287,7 +282,6 @@ def index():
|
||||||
@login_required
|
@login_required
|
||||||
def create():
|
def create():
|
||||||
form = RecipeForm()
|
form = RecipeForm()
|
||||||
form.style.choices = get_styles_list()
|
|
||||||
|
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
response = put_doc(form.doc)
|
response = put_doc(form.doc)
|
||||||
|
|
@ -314,17 +308,7 @@ def create_json():
|
||||||
|
|
||||||
@bp.route('/info/<id>')
|
@bp.route('/info/<id>')
|
||||||
def info(id):
|
def info(id):
|
||||||
recipe = get_doc_or_404(id)
|
return render_template('recipes/info.html', 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')
|
@bp.route('/info/<id>/json')
|
||||||
|
|
@ -350,7 +334,6 @@ def delete(id):
|
||||||
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
|
||||||
form = RecipeForm()
|
form = RecipeForm()
|
||||||
form.style.choices = get_styles_list()
|
|
||||||
recipe = get_doc_or_404(id)
|
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):
|
||||||
|
|
|
||||||
|
|
@ -103,20 +103,6 @@ def import_styles(url):
|
||||||
put_doc(doc)
|
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')
|
@click.command('import-styles')
|
||||||
@with_appcontext
|
@with_appcontext
|
||||||
def import_command():
|
def import_command():
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,9 @@
|
||||||
-#}
|
-#}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-6">{{ render_field_with_errors(form.name) }}</div>
|
<div class="col-sm-6">{{ render_field_with_errors(form.name) }}</div>
|
||||||
<div class="col-sm-3">{{ render_field_with_errors(form.efficiency, 'ingredient-field') }}</div>
|
<div class="col-sm-2">{{ render_field_with_errors(form.type) }}</div>
|
||||||
<div class="col-sm-3">{{ render_field_with_errors(form.volume, 'ingredient-field') }}</div>
|
<div class="col-sm-2">{{ render_field_with_errors(form.efficiency, 'ingredient-field') }}</div>
|
||||||
</div>
|
<div class="col-sm-2">{{ render_field_with_errors(form.volume, 'ingredient-field') }}</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>
|
</div>
|
||||||
{#-
|
{#-
|
||||||
Fermentable Ingredients
|
Fermentable Ingredients
|
||||||
|
|
|
||||||
|
|
@ -20,15 +20,7 @@
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="row"><h1>{{ recipe.name }}</h1></div>
|
<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
|
Recipe Details
|
||||||
-#}
|
-#}
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,7 @@ def app():
|
||||||
'notes': 'Test',
|
'notes': 'Test',
|
||||||
'volume': '5.5',
|
'volume': '5.5',
|
||||||
'fermentables': [],
|
'fermentables': [],
|
||||||
'hops': [],
|
'hops': []
|
||||||
'style': ''
|
|
||||||
})
|
})
|
||||||
put_doc({
|
put_doc({
|
||||||
'_id': 'partial-yeast-recipe',
|
'_id': 'partial-yeast-recipe',
|
||||||
|
|
@ -67,8 +66,7 @@ def app():
|
||||||
'name': 'US-05',
|
'name': 'US-05',
|
||||||
'low_attenuation': '60',
|
'low_attenuation': '60',
|
||||||
'high_attenuation': '72',
|
'high_attenuation': '72',
|
||||||
},
|
}
|
||||||
'style': ''
|
|
||||||
})
|
})
|
||||||
put_doc({
|
put_doc({
|
||||||
'_id': 'full-recipe',
|
'_id': 'full-recipe',
|
||||||
|
|
@ -78,7 +76,6 @@ def app():
|
||||||
'name': 'Awesome Beer',
|
'name': 'Awesome Beer',
|
||||||
'notes': 'This is a test beer that contains most possible fields.',
|
'notes': 'This is a test beer that contains most possible fields.',
|
||||||
'volume': '2.5',
|
'volume': '2.5',
|
||||||
'style': 'style_1A',
|
|
||||||
'fermentables': [
|
'fermentables': [
|
||||||
{
|
{
|
||||||
'name': '2row',
|
'name': '2row',
|
||||||
|
|
@ -184,7 +181,6 @@ def sample_recipes():
|
||||||
'lager': {
|
'lager': {
|
||||||
'efficiency': '72',
|
'efficiency': '72',
|
||||||
'type': 'All-Grain',
|
'type': 'All-Grain',
|
||||||
'style': '',
|
|
||||||
'fermentables': [
|
'fermentables': [
|
||||||
{
|
{
|
||||||
'amount': '9.5',
|
'amount': '9.5',
|
||||||
|
|
@ -243,7 +239,6 @@ def sample_recipes():
|
||||||
'sweetstout': {
|
'sweetstout': {
|
||||||
'efficiency': '72',
|
'efficiency': '72',
|
||||||
'type': 'All-Grain',
|
'type': 'All-Grain',
|
||||||
'style': '',
|
|
||||||
'fermentables': [
|
'fermentables': [
|
||||||
{
|
{
|
||||||
'amount': '2.75',
|
'amount': '2.75',
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,6 @@ def test_create(client, app, auth):
|
||||||
'name': 'Test',
|
'name': 'Test',
|
||||||
'notes': 'Test',
|
'notes': 'Test',
|
||||||
'volume': '5.5',
|
'volume': '5.5',
|
||||||
'style': 'style_1A'
|
|
||||||
}
|
}
|
||||||
response = client.post('/recipes/create', data=data)
|
response = client.post('/recipes/create', data=data)
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
|
|
@ -148,7 +147,6 @@ def test_create(client, app, auth):
|
||||||
assert doc['notes'] == 'Test'
|
assert doc['notes'] == 'Test'
|
||||||
assert doc['volume'] == '5.5'
|
assert doc['volume'] == '5.5'
|
||||||
assert doc['efficiency'] == '65'
|
assert doc['efficiency'] == '65'
|
||||||
assert doc['style'] == 'style_1A'
|
|
||||||
|
|
||||||
|
|
||||||
def test_update(client, app, auth):
|
def test_update(client, app, auth):
|
||||||
|
|
@ -207,12 +205,8 @@ def test_update(client, app, auth):
|
||||||
assert 'Update conflict' in flash_message
|
assert 'Update conflict' in flash_message
|
||||||
|
|
||||||
|
|
||||||
def test_info(client, monkeypatch):
|
def test_info(client):
|
||||||
"""Test success in retrieving a recipe document."""
|
"""Test success in retrieving a recipe document."""
|
||||||
def mock_get_doc(id):
|
|
||||||
# This function always raises KeyError
|
|
||||||
raise KeyError(id)
|
|
||||||
|
|
||||||
# Validate 404
|
# Validate 404
|
||||||
response = client.get('/recipes/info/thisdoesnotexist')
|
response = client.get('/recipes/info/thisdoesnotexist')
|
||||||
assert response.status_code == 404
|
assert response.status_code == 404
|
||||||
|
|
@ -222,17 +216,6 @@ def test_info(client, monkeypatch):
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert b'Awesome Lager' in response.data
|
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):
|
def test_info_json(client):
|
||||||
"""Test success in retrieving a JSON recipe."""
|
"""Test success in retrieving a JSON recipe."""
|
||||||
|
|
@ -296,7 +279,6 @@ def test_recipe_form_doc(app):
|
||||||
recipe.volume.data = Decimal('5.5')
|
recipe.volume.data = Decimal('5.5')
|
||||||
recipe.notes.data = 'This is a test'
|
recipe.notes.data = 'This is a test'
|
||||||
recipe.type.data = 'All-Grain'
|
recipe.type.data = 'All-Grain'
|
||||||
recipe.style.data = 'style_1A'
|
|
||||||
|
|
||||||
assert recipe.doc == {
|
assert recipe.doc == {
|
||||||
'name': 'Test',
|
'name': 'Test',
|
||||||
|
|
@ -307,7 +289,6 @@ def test_recipe_form_doc(app):
|
||||||
'fermentables': [],
|
'fermentables': [],
|
||||||
'hops': [],
|
'hops': [],
|
||||||
'$type': 'recipe',
|
'$type': 'recipe',
|
||||||
'style': 'style_1A'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ferm = FermentableForm()
|
ferm = FermentableForm()
|
||||||
|
|
@ -340,7 +321,6 @@ def test_recipe_form_doc(app):
|
||||||
'volume': '5.5',
|
'volume': '5.5',
|
||||||
'notes': 'This is a test',
|
'notes': 'This is a test',
|
||||||
'$type': 'recipe',
|
'$type': 'recipe',
|
||||||
'style': 'style_1A',
|
|
||||||
'fermentables': [{
|
'fermentables': [{
|
||||||
'name': 'Test',
|
'name': 'Test',
|
||||||
'type': 'Grain',
|
'type': 'Grain',
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
from humulus.styles import import_styles, sub_to_doc, get_styles_list
|
from humulus.styles import import_styles, sub_to_doc
|
||||||
|
|
||||||
COMPLETE_STYLE = '''<subcategory id="1A">
|
COMPLETE_STYLE = '''<subcategory id="1A">
|
||||||
<name>Test Style</name>
|
<name>Test Style</name>
|
||||||
|
|
@ -182,16 +182,6 @@ def test_import_command(runner, monkeypatch):
|
||||||
assert 'Imported BJCP styles.' in result.output
|
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):
|
def test_index(auth, client):
|
||||||
"""Test success in retrieving index."""
|
"""Test success in retrieving index."""
|
||||||
# Test not logged in
|
# Test not logged in
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue