1
0
Fork 0
mirror of https://github.com/shouptech/humulus.git synced 2026-02-03 18:19:42 +00:00

Add yeast

This commit is contained in:
Emma 2019-06-22 21:51:39 -06:00
parent c74ae966a3
commit 98404e38ef
3 changed files with 154 additions and 13 deletions

View file

@ -20,7 +20,7 @@ from flask import Blueprint, flash, redirect, render_template, url_for
from flask_wtf import FlaskForm
from wtforms import (Form, StringField, DecimalField, TextAreaField, FieldList,
FormField, SelectField)
from wtforms.validators import DataRequired
from wtforms.validators import DataRequired, Optional
from humulus.couch import get_doc_or_404, put_doc
@ -85,6 +85,62 @@ class HopForm(Form):
'amount': str(self.amount.data)
}
class YeastForm(Form):
"""Form for yeast.
CSRF is disabled for this subform (using `Form as parent class) because it
is never used by itself.
"""
name = StringField('Name', validators=[DataRequired()])
type = SelectField('Type', default='',
choices=[(c, c) for c in ['', 'Liquid', 'Dry']],
validators=[Optional()])
lab = StringField('Lab')
code = StringField('Lab Code')
flocculation = SelectField('Flocculation', default='',
choices=[(c, c) for c in ['', 'Low',
'Medium', 'High']],
validators=[Optional()])
low_attenuation = DecimalField('Low Attenuation',
validators=[DataRequired()])
high_attenuation = DecimalField('High Attenuation',
validators=[DataRequired()])
min_temperature = DecimalField('Min Temp (°F)',
validators=[Optional()])
max_temperature = DecimalField('Max Temp (°F)',
validators=[Optional()])
abv_tolerance = DecimalField('ABV % tolerance',
validators=[Optional()])
@property
def doc(self):
"""Returns a dictionary that can be deserialized into JSON.
Used for putting into CouchDB.
"""
yeast = {
'name': self.name.data,
'low_attenuation': str(self.low_attenuation.data),
'high_attenuation': str(self.high_attenuation.data)
}
if self.type.data:
yeast['type'] = self.type.data
if self.lab.data:
yeast['lab'] = self.lab.data
if self.code.data:
yeast['code'] = self.code.data
if self.flocculation.data:
yeast['flocculation'] = self.flocculation.data
if self.min_temperature.data:
yeast['min_temperature'] = str(self.min_temperature.data)
if self.max_temperature.data:
yeast['max_temperature'] = str(self.max_temperature.data)
if self.abv_tolerance.data:
yeast['abv_tolerance'] = str(self.abv_tolerance.data)
return yeast
class RecipeForm(FlaskForm):
"""Form for recipes."""
name = StringField('Name', validators=[DataRequired()])
@ -102,6 +158,7 @@ class RecipeForm(FlaskForm):
min_entries=0,
max_entries=20
)
yeast = FormField(YeastForm)
@property
def doc(self):
@ -109,15 +166,21 @@ class RecipeForm(FlaskForm):
Used for putting into CouchDB.
"""
return {
recipe = {
'name': self.name.data,
'efficiency': str(self.efficiency.data),
'volume': str(self.volume.data),
'notes': self.notes.data,
'fermentables': [f.doc for f in self.fermentables],
'hops': [h.doc for h in self.hops],
'notes': self.notes.data
}
if len(self.fermentables) > 0:
recipe['fermentables'] = [f.doc for f in self.fermentables]
if len(self.hops) > 0:
recipe['hops'] = [h.doc for h in self.hops]
if self.yeast.doc['name']:
recipe['yeast'] = self.yeast.doc
return recipe
@bp.route('/create', methods=('GET', 'POST'))
def create():
@ -127,7 +190,6 @@ def create():
response = put_doc(form.doc)
flash('Created recipe: {}'.format(form.name.data), 'success')
return redirect(url_for('recipes.info', id=response['_id']))
return render_template('recipes/create.html', form=form)

View file

@ -92,6 +92,28 @@
<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
-#}

View file

@ -15,7 +15,7 @@
from decimal import Decimal
from humulus.couch import get_db
from humulus.recipes import FermentableForm, HopForm, RecipeForm
from humulus.recipes import FermentableForm, HopForm, RecipeForm, YeastForm
def test_create(client, app):
@ -29,7 +29,10 @@ def test_create(client, app):
'efficiency': '65',
'name': 'Test',
'notes': 'Test',
'volume': '5.5'
'volume': '5.5',
'yeast-name': 'Test',
'yeast-low_attenuation': '60',
'yeast-high_attenuation': '75',
}
response = client.post('/recipes/create', data=data)
assert response.status_code == 302
@ -55,6 +58,41 @@ def test_info(client):
assert b'Awesome Lager' in response.data
def test_yeast_form_doc(app):
"""Evaluates conditionals in generation of doc from a yeast form."""
yeast = YeastForm()
yeast.name.data = 'Test'
yeast.low_attenuation.data = Decimal('60')
yeast.high_attenuation.data = Decimal('75')
assert yeast.doc == {
'name': 'Test',
'low_attenuation': '60',
'high_attenuation': '75'
}
yeast.type.data = 'Dry'
yeast.code.data = 'INIS-001'
yeast.lab.data = 'Inland Island'
yeast.flocculation.data = 'Low'
yeast.min_temperature.data = Decimal('40')
yeast.max_temperature.data = Decimal('50')
yeast.abv_tolerance.data = Decimal('15')
assert yeast.doc == {
'name': 'Test',
'low_attenuation': '60',
'high_attenuation': '75',
'flocculation': 'Low',
'type': 'Dry',
'code': 'INIS-001',
'lab': 'Inland Island',
'min_temperature': '40',
'max_temperature': '50',
'abv_tolerance': '15'
}
def test_recipe_form_doc(app):
"""Test if a recipeform can be turned into a document.
@ -64,6 +102,18 @@ def test_recipe_form_doc(app):
with app.app_context():
recipe = RecipeForm()
recipe.name.data = 'Test'
recipe.efficiency.data = Decimal('65')
recipe.volume.data = Decimal('5.5')
recipe.notes.data = 'This is a test'
assert recipe.doc == {
'name': 'Test',
'efficiency': '65',
'volume': '5.5',
'notes': 'This is a test',
}
ferm = FermentableForm()
ferm.name.data = 'Test'
ferm.type.data = 'Grain'
@ -78,12 +128,14 @@ def test_recipe_form_doc(app):
hop.duration.data = Decimal('60')
hop.amount.data = Decimal('0.5')
recipe.name.data = 'Test'
recipe.efficiency.data = Decimal('65')
recipe.volume.data = Decimal('5.5')
recipe.notes.data = 'This is a test'
yeast = YeastForm()
yeast.name.data = 'Test'
yeast.low_attenuation.data = '70'
yeast.high_attenuation.data = '75'
recipe.fermentables = [ferm]
recipe.hops = [hop]
recipe.yeast = yeast
assert recipe.doc == {
'name': 'Test',
@ -103,5 +155,10 @@ def test_recipe_form_doc(app):
'alpha': '12.5',
'duration': '60',
'amount': '0.5'
}]
}],
'yeast': {
'name': 'Test',
'low_attenuation': '70',
'high_attenuation': '75'
}
}