Commit ce1f6560 authored by Francesca Sargent 's avatar Francesca Sargent
Browse files

Added Ingredient option to Recipe Steps

parent f186d713
......@@ -7,13 +7,23 @@ from wtforms.validators import Required, Length, Email, Regexp, Optional
from wtforms import ValidationError, validators, widgets
from flask.ext.pagedown.fields import PageDownField
from .. import db
from ..models import Role, User, Cuisine, Recipe, RecipeSteps, Method
from ..models import Role, User, Cuisine, Recipe, RecipeSteps, Method, Ingredient
class NameForm(Form):
name = StringField('What is your name?', validators=[Required()])
submit = SubmitField('Submit')
class SplitStringField(StringField):
def process_formdata(self, valuelist):
if valuelist:
if len(valuelist) == 1 and valuelist[0] == '':
self.data = []
else:
self.data = [x.strip() for x in valuelist[0].split(',')]
else:
self.data = []
class EditProfileForm(Form):
name = StringField('Real name', validators=[Length(0, 64)])
......@@ -21,6 +31,11 @@ class EditProfileForm(Form):
about_me = TextAreaField('About me')
submit = SubmitField('Submit')
class IngredientForm(Form):
name = StringField('Ingredient Name', validators=[Required(), Length(0,64)])
description = TextAreaField('Description')
submit = SubmitField('Submit')
class EditProfileAdminForm(Form):
email = StringField('Email', validators=[Required(), Length(1, 64),
......@@ -54,19 +69,12 @@ class EditProfileAdminForm(Form):
class RecipeStepForm(Form):
step_text = TextAreaField()
ingredients = SplitStringField(validators=[Optional()])
def __init__(self, *args, **kwargs):
kwargs['csrf_enabled'] = False
super(RecipeStepForm, self).__init__(*args, **kwargs)
class SplitStringField(StringField):
def process_formdata(self, valuelist):
if valuelist:
self.data = [x.strip() for x in valuelist[0].split(',')]
else:
self.data = []
class RecipeForm(Form):
name = StringField('Recipe Name', validators=[Required(), Length(0, 64)])
......
......@@ -9,9 +9,10 @@ from wtforms.validators import Required, Length, Email, Regexp, Optional
from wtforms import ValidationError, validators, widgets
from flask.ext.pagedown.fields import PageDownField
from .forms import EditProfileForm, EditProfileAdminForm, RecipeForm,\
CommentForm, CuisineForm, RecipeStepForm, MethodForm, RecipeEditForm, SplitStringField
CommentForm, CuisineForm, RecipeStepForm, MethodForm, RecipeEditForm, SplitStringField, \
IngredientForm
from .. import db
from ..models import Permission, Role, User, Recipe, Comment, Cuisine, RecipeSteps, Method
from ..models import Permission, Role, User, Recipe, Comment, Cuisine, RecipeSteps, Method, Ingredient
from ..decorators import admin_required, permission_required
......@@ -31,6 +32,17 @@ def addMethod(name):
return methods
def addIngredient(name):
if name is '':
return
else:
if Ingredient.query.filter_by(name=name).first() is None:
ingredient = [Ingredient(name=name, description='', timestamp='now', author=current_user._get_current_object())]
else:
ingredient = [Ingredient.query.filter_by(name=name).first()]
return ingredient
def returnListed(subcats):
lists = []
......@@ -87,6 +99,16 @@ def postall(type):
methods = pagination.items
return render_template('all_methods.html', user=user, methods=methods,
pagination=pagination, type=type)
if type == 'ingredient':
query = Ingredient.query
page = request.args.get('page', 1, type=int)
pagination = query.order_by(Ingredient.timestamp.desc()).paginate(
page, per_page=current_app.config['FLASKY_POSTS_PER_PAGE'],
error_out=False)
ingredients = pagination.items
return render_template('all_ingredients.html', user=user, ingredients=ingredients,
pagination=pagination, type=type)
......@@ -143,17 +165,26 @@ def poststuff(type):
recipe.methods = addCuisine(form.methods.data)
for index,step_entry in enumerate(form.steps.entries):
try:
step = RecipeSteps()
step.id = (str(recipe.id)+str(index))
step.step_id = index
step.step_text = step_entry.step_text.data
step.recipe_id = recipe.id
db.session.add(step)
except:
print "Query error"
if step_entry.step_text == '':
pass
else:
try:
step = RecipeSteps()
step.id = (str(recipe.id)+str(index))
step.step_id = index
step.step_text = step_entry.step_text.data
step.recipe_id = recipe.id
for ingredient in step_entry.ingredients.data:
if ingredient is '':
pass
else:
ingred = addIngredient(ingredient)
step.ingredients.extend(ingred)
db.session.add(step)
except:
print "Query error"
recipe.author = current_user._get_current_object()
......@@ -216,6 +247,21 @@ def poststuff(type):
flash('Your method has been added.')
return redirect(url_for('.index'))
if type == 'ingredient':
form = IngredientForm()
if current_user.can(Permission.WRITE_ARTICLES) and \
form.validate_on_submit():
ingredient = Ingredient()
ingredient.name = form.name.data
ingredient.description = form.description.data
ingredient.author = current_user._get_current_object()
db.session.add(ingredient)
db.session.flush()
flash('Your ingredient has been added.')
return redirect(url_for('.index'))
db.session.commit()
return render_template('post.html', form=form,
......@@ -351,6 +397,10 @@ def method(id):
method = [Method.query.get_or_404(id)]
return render_template('method.html', methods=method)
@main.route('/ingredient/<int:id>', methods=['GET', 'POST'])
def ingredient(id):
ingredient = [Ingredient.query.get_or_404(id)]
return render_template('ingredient.html', ingredients=ingredient)
@main.route('/recipe/<int:id>/edit', methods=['GET', 'POST'])
@login_required
......@@ -390,9 +440,12 @@ def editrecipe(id):
recipe.description = form.description.data
for index,step_entry in enumerate(form.steps.entries):
step_id = (str(recipe.id)+str(index))
if step_entry.step_text.data == '':
pass
else:
step_id = (str(recipe.id)+str(index))
try:
step_id = (str(recipe.id)+str(index))
step_exist = RecipeSteps.query.get(step_id)
......@@ -407,13 +460,16 @@ def editrecipe(id):
step.step_id = index
step.step_text = step_entry.step_text.data
step.recipe_id = recipe.id
db.session.add(step)
except:
print "Query error"
db.session.add(recipe)
for ingredient in step_entry.ingredients.data:
if ingredient is '':
pass
else:
ingred = addIngredient(ingredient)
step.ingredients.extend(ingred)
db.session.add(step)
db.session.add(recipe)
flash('The recipe has been updated.')
return redirect(url_for('.recipe', id=recipe.id))
......@@ -424,14 +480,16 @@ def editrecipe(id):
form.cuisines.data = returnListed(recipe.cuisines)
form.methods.data = returnListed(recipe.methods)
for i, step in enumerate(recipe.steps):
print "Step "+str(step.step_id)+" ingredients:", returnListed(step.ingredients)
form.steps[i].ingredients.data = returnListed(step.ingredients)
for i in range(0, recipe.steps.count()):
form.steps[i].step_text.data = recipe.steps[i].step_text
typeof = 'recipe'
return render_template('edit_recipe.html', form=form, typeof=typeof, recipes=[recipe])
return render_template('edit_recipe.html', form=form, type=typeof, recipes=[recipe])
@main.route('/method/<int:id>/edit', methods=['GET', 'POST'])
@login_required
......@@ -487,6 +545,27 @@ def editcuisine(id):
form.methods.data = returnListed(cuisine.methods)
return render_template('edit_recipe.html', form=form, type='cuisine')
@main.route('/ingredient/<int:id>/edit', methods=['GET', 'POST'])
@login_required
def editingredient(id):
db.session.autoflush = True
ingredient = Ingredient.query.get_or_404(id)
if current_user != ingredient.author and \
not current_user.can(Permission.ADMINISTER):
abort(403)
form = IngredientForm()
if form.validate_on_submit():
ingredient.name = form.name.data
ingredient.description = form.description.data
db.session.add(ingredient)
flash('The ingredient has been updated.')
return redirect(url_for('.ingredient', id=ingredient.id))
form.name.data = ingredient.name
form.description.data = ingredient.description
return render_template('edit_recipe.html', form=form, type='cuisine')
@main.route('/follow/<username>')
@login_required
......
......@@ -75,6 +75,7 @@ class User(UserMixin, db.Model):
recipes = db.relationship('Recipe', backref='author', lazy='dynamic')
cuisines = db.relationship('Cuisine', backref='author', lazy='dynamic')
methods = db.relationship('Method', backref='author', lazy='dynamic')
ingredients = db.relationship('Ingredient', backref='author', lazy='dynamic')
followed = db.relationship('Follow',
foreign_keys=[Follow.follower_id],
backref=db.backref('follower', lazy='joined'),
......@@ -275,6 +276,12 @@ cuisinemethods = db.Table('cuisinemethods',
db.Column('method_name', db.String(64), db.ForeignKey('methods.name'))
)
stepingredients = db.Table('stepingredients',
db.Column('id', db.Integer, primary_key=True, unique=True),
db.Column('step_id', db.Integer, db.ForeignKey('recipesteps.id')),
db.Column('ingredient_id', db.Integer, db.ForeignKey('ingredients.id'))
)
class Recipe(db.Model):
__tablename__ = 'recipes'
id = db.Column(db.Integer, primary_key=True)
......@@ -309,7 +316,7 @@ class Recipe(db.Model):
def on_changed_body(target, value, oldvalue, initiator):
allowed_tags = ['a', 'abbr', 'acronym', 'b', 'blockquote', 'code',
'em', 'i', 'li', 'ol', 'pre', 'strong', 'ul',
'h1', 'h2', 'h3', 'p']
'h1', 'h2', 'h3', 'p', 'marquee']
target.body_html = bleach.linkify(bleach.clean(
markdown(value, output_format='html'),
tags=allowed_tags, strip=True))
......@@ -322,6 +329,7 @@ class RecipeSteps(db.Model):
recipe_id = db.Column(db.Integer, db.ForeignKey('recipes.id'))
step_id = db.Column(db.Integer)
step_text = db.Column(db.Text)
ingredients = db.relationship('Ingredient', secondary=stepingredients, backref=db.backref('recipesteps', lazy='dynamic'))
class Cuisine(db.Model):
__tablename__ = 'cuisines'
......@@ -371,3 +379,11 @@ class Comment(db.Model):
tags=allowed_tags, strip=True))
db.event.listen(Comment.body, 'set', Comment.on_changed_body)
class Ingredient(db.Model):
__tablename__ = 'ingredients'
id = db.Column(db.Integer, primary_key=True, unique=True)
name = db.Column(db.String(64), unique=True)
description = db.Column(db.Text)
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
\ No newline at end of file
......@@ -148,7 +148,7 @@ ul#steps.form-control {
#steps > li > label {
display: none;
display: block;
}
.hide,
......@@ -168,8 +168,29 @@ textarea#steps-0-step_text {
min-height: 200px;
height: 34px;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
color: #555;
background-color: #fff;
background-image: none;
border: 1px solid #ccc;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
-webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
-o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
}
.ingredtext,
input#steps-0-ingredients {
display: block;
width: 100%;
min-height: 50px;
height: 34px;
padding: 6px 12px;
margin-top: 20px;
font-size: 14px;
margin-bottom: 20px;
line-height: 1.42857143;
color: #555;
background-color: #fff;
......
<ul class="recipes">
{% for ingredient in ingredients %}
<li class="recipe">
<div class="recipe-content">
<p><h4> {{ ingredient.name }} </h4>
Created by <a href="{{ url_for('.user', username=ingredient.author.username) }}">{{ ingredient.author.username }}</a></p>
<div class="recipe-body">
<p>{% if ingredient.description %}
{{ ingredient.description }}
{% else %}
{{ ingredient.description | safe }}
{% endif %} </p>
</div>
<div class="recipe-footer">
{% if current_user == ingredient.author %}
<a href="{{ url_for('.editingredient', id=ingredient.id) }}">
<span class="label label-primary">Edit</span>
</a>
{% elif current_user.is_administrator() %}
<a href="{{ url_for('.editingredient', id=ingredient.id) }}">
<span class="label label-danger">Edit [Admin]</span>
</a>
{% endif %}
<a href="{{ url_for('.ingredient', id=ingredient.id) }}">
<span class="label label-default">Permalink</span>
</a>
</div>
</li>
{% endfor %}
</ul>
{% extends "base.html" %}
{% import "_macros.html" as macros %}
{% block title %}Recipes{% endblock %}
{% block page_content %}
<h3>View all Ingredients</span></h3>
{% include '_ingredients.html' %}
{% if pagination %}
<!-- <div class="pagination">
{{ macros.pagination_widget(pagination, '.user', username=user.username) }}
</div> -->
{% endif %}
{% endblock %}
\ No newline at end of file
......@@ -39,6 +39,7 @@
<li><a href="{{ url_for('main.poststuff', type='cuisine') }}">Cuisine</a></li>
<li><a href="{{ url_for('main.poststuff', type='recipe') }}">Recipe</a></li>
<li><a href="{{ url_for('main.poststuff', type='method') }}">Method</a></li>
<li><a href="{{ url_for('main.poststuff', type='ingredient') }}">Ingredient</a></li>
</ul>
</li>
{% endif %}
......@@ -50,6 +51,7 @@
<li><a href="{{ url_for('main.postall', type='cuisine') }}">Cuisines</a></li>
<li><a href="{{ url_for('main.postall', type='recipe') }}">Recipes</a></li>
<li><a href="{{ url_for('main.postall', type='method') }}">Methods</a></li>
<li><a href="{{ url_for('main.postall', type='ingredient') }}">Ingredients</a></li>
</ul>
</li>
</ul>
......@@ -144,5 +146,79 @@
</script>
{{ moment.include_moment() }}
{% if type == 'recipe' %}
<script>
console.log('recipe')
var recipecount = parseInt('{% if recipes %}{%for recipe in recipes%}{{recipe.steps.count()}}{% endfor %}{% else %}0{% endif %}')
console.log(recipecount);
for (i=0; i<=recipecount; i++) {
var selector = '#steps-'+i+'-step_text'
var selector_ingreds = '#steps-'+i+'-ingredients'
var selector_table = 'table#steps-'+i
var selector_label = '#steps-'+i+' > tbody > tr > th > label'
var show_button = 'textarea#steps-'+i+'-step_text'
var label_select = 'label[for="steps-'+i+'"]'
$(selector).addClass('steptext');
$(selector_ingreds).addClass('ingredtext');
$(selector_ingreds).attr('placeholder', 'List Ingredients Here');
$(selector_table).addClass('fullwidth');
$(selector_label).addClass('hide');
$(label_select).html('Step ' + (i+1));
}
$('ul#steps').after('<div id="add_another_button">Add</div><div class="remove_this">Remove</div>')
$('div#add_another_button').click(function () {
console.log('clicked');
clone_field_list('li:last');
var lis = document.querySelectorAll('.steptext').length;
console.log(lis)
if (lis > 0) {
$('div.remove_this').fadeIn()
}
});
$("div.remove_this").click(function(e) {
$('ul#steps li:last').remove();
e.preventDefault();
var lis = document.querySelectorAll('.steptext').length;
if (lis === 1) {
$(this).fadeOut();
}
});
function clone_field_list(selector) {
var new_element = $(selector).clone(true);
var elem_id = new_element.find(':input')[0].id;
var elem_num = parseInt(elem_id.replace(/.*-(\d{1,4})-.*/m, '$1')) + 1;
new_element.find(':input').each(function() {
var id = $(this).attr('id').replace('-' + (elem_num - 1) + '-', '-' + elem_num + '-');
$(this).addClass('steptext');
$(this).html('');
});
new_element.find('label').each(function() {
var new_for = $(this).attr('for').replace('-' + (elem_num - 1) + '-', '-' + elem_num + '-');
$(this).attr('for', new_for);
$(this).html('Step ' + (elem_num + 1))
});
$(selector).after(new_element)
}
</script>
{% endif %}
{% endblock %}
......@@ -19,6 +19,15 @@ Created by <a href="{{ url_for('.user', username=cuisine.author.username) }}">{{
{% endif %}
{% if cuisine.recipes %}
<strong>Recipes: </strong> {% for recipe in cuisine.recipes %} <span class="badge"><a href="{{ url_for('.recipe', id=recipe.id) }}"> {{ recipe.name }} </a></span>{% endfor %} <br/>
<strong>Ingredients: </strong>{% for recipe in cuisine.recipes %}
{% for step in recipe.steps %}
{% if step.ingredients %}
{% for ingredient in step.ingredients %}
<span class="badge"><a href="{{ url_for('.ingredient', id=ingredient.id) }}"> {{ ingredient.name }} </a></span>
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
<p>{% if cuisine.description %}
......@@ -27,6 +36,8 @@ Created by <a href="{{ url_for('.user', username=cuisine.author.username) }}">{{
{{ cuisine.description | safe }}
{% endif %} </p>
<div class="recipe-footer">
{% if current_user == cuisine.author %}
<a href="{{ url_for('.editcuisine', id=cuisine.id) }}">
......
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% import "_macros.html" as macros %}
{% block title %}Open Sauces - Ingredient{% endblock %}
{% block page_content %}
{% for ingredient in ingredients %}
<div class="recipe-content">
<p><h4> {{ ingredient.name }} </h4>
Created by <a href="{{ url_for('.user', username=ingredient.author.username) }}">{{ ingredient.author.username }}</a></p>
<div class="recipe-body">
<p>{% if ingredient.description %}
{{ ingredient.description }}
{% else %}
{{ ingredient.description | safe }}
{% endif %} </p>
</div>
<div class="recipe-footer">
{% if current_user == ingredient.author %}
<a href="{{ url_for('.editingredient', id=ingredient.id) }}">
<span class="label label-primary">Edit</span>
</a>
{% elif current_user.is_administrator() %}
<a href="{{ url_for('.editingredient', id=ingredient.id) }}">
<span class="label label-danger">Edit [Admin]</span>
</a>
{% endif %}
<a href="{{ url_for('.ingredient', id=ingredient.id) }}">
<span class="label label-default">Permalink</span>
</a>
</div>
</div>
{% endfor %}
{% endblock %}
......@@ -7,7 +7,7 @@
{% block page_content %}
<div class="page-header">
<h1>Post a {{ type }}</h1>
<h1>Post {% if type == 'ingredient' %}an {% else %}a {% endif %} {{ type }}</h1>
</div>
<div>
{% if type == 'cuisine' %}
......@@ -18,6 +18,8 @@
{{ wtf.quick_form(form) }}
{% elif type == 'method' %}
{{ wtf.quick_form(form) }}
{% elif type == 'ingredient' %}
{{ wtf.quick_form(form) }}
{% endif %}
</div>
......@@ -63,4 +65,6 @@ $( document ).ready(function() {
});
</script>
{{ pagedown.include_pagedown() }}
{% if type == 'recipe' %}
{% endif %}
{% endblock %}
......@@ -16,16 +16,26 @@ Created by <a href="{{ url_for('.user', username=recipe.author.username) }}">{{
<p><strong>Associated Cuisines: </strong> {% for cuisine in recipe.cuisines %} <span class="badge"><a href="{{ url_for('.cuisine', id=cuisine.id) }}"> {{ cuisine.name }} </a></span>{% endfor %} <br/>
{% endif %}
{% if recipe.methods.count() > 0 %}
<strong>Associated Methods: </strong> {% for method in recipe.methods %} <span class="badge"> <a href="{{ url_for('.method', id=method.id) }}">{{ method.name }}</a> </span>{% endfor %} <br/></p>
<strong>Associated Methods: </strong> {% for method in recipe.methods %} <span class="badge"> <a href="{{ url_for('.method', id=method.id) }}">{{ method.name }}</a> </span>{% endfor %} <br/>
{% endif %}
<strong>Ingredients: </strong> {% for step in recipe.steps %}
{% if step.ingredients %}
{% for ingredient in step.ingredients %}
<span class="badge"><a href="{{ url_for('.ingredient', id=ingredient.id) }}"> {{ ingredient.name }} </a></span>
{% endfor %}
{% endif %}
{% endfor %}
</p>
<