mirror of
https://github.com/shouptech/humulus.git
synced 2026-02-03 13:49:41 +00:00
Allow Recipe Types (#16)
* Adds a recipe type field for recipe form. (Closes #7) * Abort w/ 400 is view is not found
This commit is contained in:
parent
221ddbafe0
commit
e11fd79deb
7 changed files with 67 additions and 10 deletions
|
|
@ -10,6 +10,9 @@
|
|||
},
|
||||
"by-volume": {
|
||||
"map": "function (doc) {\n if (doc.$type == \"recipe\" && doc.volume && doc.name) {\n emit(doc.volume, doc.name)\n }\n}"
|
||||
},
|
||||
"by-type": {
|
||||
"map": "function (doc) {\n if (doc.$type == \"recipe\" && doc.type && doc.name) {\n emit(doc.type, doc.name)\n }\n}"
|
||||
}
|
||||
},
|
||||
"lists": {},
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@
|
|||
import json
|
||||
from decimal import Decimal
|
||||
|
||||
from flask import (Blueprint, flash, redirect, render_template, jsonify,
|
||||
import requests
|
||||
from flask import (abort, Blueprint, flash, redirect, render_template, jsonify,
|
||||
request, url_for)
|
||||
from flask_wtf import FlaskForm
|
||||
from flask_wtf.file import FileField, FileRequired
|
||||
|
|
@ -148,6 +149,11 @@ class YeastForm(Form):
|
|||
class RecipeForm(FlaskForm):
|
||||
"""Form for recipes."""
|
||||
name = StringField('Name', validators=[DataRequired()])
|
||||
type = SelectField('Type', default='',
|
||||
choices=[(c, c) for c in ['All-Grain',
|
||||
'Partial Extract',
|
||||
'Extract']],
|
||||
validators=[Optional()])
|
||||
efficiency = DecimalField('Batch Efficiency (%)',
|
||||
validators=[DataRequired()])
|
||||
volume = DecimalField('Batch Volume (gal)', validators=[DataRequired()])
|
||||
|
|
@ -176,6 +182,7 @@ class RecipeForm(FlaskForm):
|
|||
'volume': str(self.volume.data),
|
||||
'notes': self.notes.data,
|
||||
'$type': 'recipe',
|
||||
'type': self.type.data
|
||||
}
|
||||
|
||||
recipe['fermentables'] = [f.doc for f in self.fermentables]
|
||||
|
|
@ -191,6 +198,7 @@ class RecipeForm(FlaskForm):
|
|||
def copyfrom(self, data):
|
||||
"""Copies from a dictionary (data) into the current object"""
|
||||
self.name.data = data['name']
|
||||
self.type.data = data['type']
|
||||
self.efficiency.data = Decimal(data['efficiency'])
|
||||
self.volume.data = Decimal(data['volume'])
|
||||
self.notes.data = data['notes']
|
||||
|
|
@ -255,16 +263,16 @@ def index():
|
|||
['true', 'yes']
|
||||
)
|
||||
sort_by = request.args.get('sort_by', default='name', type=str)
|
||||
if sort_by == 'date':
|
||||
view = get_view('_design/recipes', 'by-date')
|
||||
elif sort_by == 'volume':
|
||||
view = get_view('_design/recipes', 'by-volume')
|
||||
else:
|
||||
view = get_view('_design/recipes', 'by-name')
|
||||
|
||||
view = get_view('_design/recipes', 'by-{}'.format(sort_by))
|
||||
try:
|
||||
rows = view(include_docs=True, descending=descending)['rows']
|
||||
except requests.exceptions.HTTPError:
|
||||
abort(400)
|
||||
|
||||
return render_template(
|
||||
'recipes/index.html',
|
||||
rows=view(include_docs=True, descending=descending)['rows'],
|
||||
rows=rows,
|
||||
descending=descending,
|
||||
sort_by=sort_by
|
||||
)
|
||||
|
|
|
|||
|
|
@ -26,8 +26,9 @@
|
|||
-#}
|
||||
<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, 'ingredient-field') }}</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.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>
|
||||
{#-
|
||||
Fermentable Ingredients
|
||||
|
|
|
|||
|
|
@ -49,6 +49,15 @@
|
|||
<a class="text-dark" href="{{ url_for('recipes.index', descending='false', sort_by='volume') }}">Batch Size</a>
|
||||
{% endif %}
|
||||
</th>
|
||||
<th>
|
||||
{% if sort_by == 'type' and descending %}
|
||||
<a class="text-dark" href="{{ url_for('recipes.index', descending='false', sort_by='type') }}">Type ↓</a>
|
||||
{% elif sort_by == 'type' %}
|
||||
<a class="text-dark" href="{{ url_for('recipes.index', descending='true', sort_by='type') }}">Type ↑</a>
|
||||
{% else %}
|
||||
<a class="text-dark" href="{{ url_for('recipes.index', descending='false', sort_by='type') }}">Type</a>
|
||||
{% endif %}
|
||||
</th>
|
||||
<th>
|
||||
{% if sort_by == 'date' and descending %}
|
||||
<a class="text-dark" href="{{ url_for('recipes.index', descending='false', sort_by='date') }}">Created On ↓</a>
|
||||
|
|
@ -64,6 +73,7 @@
|
|||
<tr>
|
||||
<td><a href="{{ url_for('recipes.info', id=row.id) }}">{{ row.doc.name }}</a></td>
|
||||
<td>{{ row.doc.volume }} gal.</td>
|
||||
<td>{{ row.doc.type }}</td>
|
||||
<td>{{ moment(row.doc.created) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
<div class="row">
|
||||
<div class="col">
|
||||
<dl>
|
||||
<dt>Recipe Type</dt>
|
||||
<dd>{{ recipe.type }}</dd>
|
||||
<dt>Batch Efficiency</dt>
|
||||
<dd>{{ recipe.efficiency|int }}%</dd>
|
||||
<dt>Batch Volume</dt>
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ def app():
|
|||
put_doc({
|
||||
'_id': 'awesome-lager',
|
||||
'$type': 'recipe',
|
||||
'type': 'All-Grain',
|
||||
'efficiency': '65',
|
||||
'name': 'Awesome Lager',
|
||||
'notes': 'Test',
|
||||
|
|
@ -56,6 +57,7 @@ def app():
|
|||
'$type': 'recipe',
|
||||
'efficiency': '75',
|
||||
'name': 'Partial Beer',
|
||||
'type': 'Extract',
|
||||
'notes': 'Contains only required fields for yeast.',
|
||||
'volume': '3.5',
|
||||
'fermentables': [],
|
||||
|
|
@ -70,6 +72,7 @@ def app():
|
|||
'_id': 'full-recipe',
|
||||
'$type': 'recipe',
|
||||
'efficiency': '78',
|
||||
'type': 'All-Grain',
|
||||
'name': 'Awesome Beer',
|
||||
'notes': 'This is a test beer that contains most possible fields.',
|
||||
'volume': '2.5',
|
||||
|
|
@ -160,6 +163,7 @@ def sample_recipes():
|
|||
return {
|
||||
'lager': {
|
||||
'efficiency': '72',
|
||||
'type': 'All-Grain',
|
||||
'fermentables': [
|
||||
{
|
||||
'amount': '9.5',
|
||||
|
|
@ -217,6 +221,7 @@ def sample_recipes():
|
|||
},
|
||||
'sweetstout': {
|
||||
'efficiency': '72',
|
||||
'type': 'All-Grain',
|
||||
'fermentables': [
|
||||
{
|
||||
'amount': '2.75',
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ from humulus.recipes import FermentableForm, HopForm, RecipeForm, YeastForm
|
|||
|
||||
def test_index(client):
|
||||
"""Test success in retrieving index."""
|
||||
# Test for bad request
|
||||
response = client.get('/recipes/?sort_by=foobar')
|
||||
assert response.status_code == 400
|
||||
|
||||
# Verify defaults
|
||||
response = client.get('/recipes/')
|
||||
assert response.status_code == 200
|
||||
|
|
@ -93,6 +97,27 @@ def test_index(client):
|
|||
response.data
|
||||
)
|
||||
|
||||
# Test sort by type ascending
|
||||
response = client.get('/recipes/?descending=false&sort_by=type')
|
||||
assert (
|
||||
b'"/recipes/?descending=false&sort_by=name">Name' in
|
||||
response.data
|
||||
)
|
||||
assert (
|
||||
b'"/recipes/?descending=true&sort_by=type">Type ↑' in
|
||||
response.data
|
||||
)
|
||||
|
||||
# Test sort by type descending
|
||||
response = client.get('/recipes/?descending=true&sort_by=type')
|
||||
assert (
|
||||
b'"/recipes/?descending=false&sort_by=name">Name' in
|
||||
response.data
|
||||
)
|
||||
assert (
|
||||
b'"/recipes/?descending=false&sort_by=type">Type ↓' in
|
||||
response.data
|
||||
)
|
||||
|
||||
def test_create(client, app, auth):
|
||||
"""Test success in creating a recipe document."""
|
||||
|
|
@ -253,10 +278,12 @@ def test_recipe_form_doc(app):
|
|||
recipe.efficiency.data = Decimal('65')
|
||||
recipe.volume.data = Decimal('5.5')
|
||||
recipe.notes.data = 'This is a test'
|
||||
recipe.type.data = 'All-Grain'
|
||||
|
||||
assert recipe.doc == {
|
||||
'name': 'Test',
|
||||
'efficiency': '65',
|
||||
'type': 'All-Grain',
|
||||
'volume': '5.5',
|
||||
'notes': 'This is a test',
|
||||
'fermentables': [],
|
||||
|
|
@ -290,6 +317,7 @@ def test_recipe_form_doc(app):
|
|||
assert recipe.doc == {
|
||||
'name': 'Test',
|
||||
'efficiency': '65',
|
||||
'type': 'All-Grain',
|
||||
'volume': '5.5',
|
||||
'notes': 'This is a test',
|
||||
'$type': 'recipe',
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue