def register(): if not app.config["ALLOW_REGISTER"]: abort(404) if request.method == "GET": return render_template("accounts/register.html", form=RegisterForm()) form = RegisterForm(request.form) if not form.validate(): return render_template("accounts/register.html", form=form) if Account.is_username_taken(form.username.data): return render_template( "accounts/register.html", form=form, error="Username is already taken.", ) password_hash = \ bcrypt.generate_password_hash(form.password.data).decode("utf-8") account = Account( username=form.username.data, password_hash=password_hash, role="user", ) db.session().add(account) db.session.commit() login_user(account) return redirect(url_for("index"))
def delete_my_account(): if request.method == "GET": return redirect(url_for("my_account")) db.session().delete( Account.query.filter_by(id=current_user.id).first_or_404()) logout_user() db.session().commit() return redirect(url_for("index"))
def delete_shopping_list_item(item_id: int): if request.method == "GET": return redirect(url_for("get_shopping_list")) delete_count = ShoppingListItem.query.filter_by( id=item_id, account_id=current_user.id, ).delete() db.session().flush() Ingredient.delete_unused_ingredients(current_user.id) db.session().commit() return redirect(url_for("get_shopping_list"))
def delete_recipe(recipe_id: int): if request.method == "GET": return redirect(url_for("get_recipe", recipe_id=recipe_id)) Recipe.query.filter_by( id=recipe_id, account_id=current_user.id, ).delete() db.session().flush() Ingredient.delete_unused_ingredients(current_user.id) db.session().commit() return redirect(url_for("get_recipes"))
def insert_if_missing(name, account_id): ingredient = Ingredient.query.filter( Ingredient.account_id == account_id, func.lower(Ingredient.name) == func.lower(name), ).first() if ingredient: return ingredient ingredient = Ingredient(name) ingredient.account_id = account_id db.session().add(ingredient) db.session().flush() return ingredient
def delete_unused_ingredients(account_id): stmt = text(""" DELETE FROM ingredients WHERE ingredients.id IN ( SELECT i.id FROM ingredients i LEFT JOIN recipe_ingredient ri ON ri.ingredient_id = i.id LEFT JOIN shopping_list_items sli ON sli.ingredient_id = i.id WHERE i.account_id = :account_id AND ri.id IS NULL AND sli.id IS NULL )""").params(account_id=account_id) db.session().execute(stmt)
def create_shopping_list_item(): if request.method == "GET": return redirect(url_for("get_shopping_list")) form = RecipeIngredientForm(request.form) if not form.validate(): return render_shopping_list(form, "new") item = ShoppingListItem() item.amount, item.amount_unit = form.parse_amount() item.account_id = current_user.id ingredient = Ingredient.insert_if_missing(form.name.data, current_user.id) item.ingredient_id = ingredient.id db.session().add(item) db.session().commit() return redirect(url_for("get_shopping_list"))
def insert_ingredients_from_form(self, form): ingredients = [] missing_ingredients = [] ingredients_by_name = {} for recipe_ingredient_form in form.ingredient_amounts: name = recipe_ingredient_form.data["name"].strip() lower_name = name.lower() existing_ingredient = ingredients_by_name.get(lower_name) if not existing_ingredient: existing_ingredient = Ingredient.query.filter( Ingredient.account_id == self.account_id, func.lower(Ingredient.name) == lower_name, ).first() if not existing_ingredient: existing_ingredient = Ingredient(name) existing_ingredient.account_id = self.account_id missing_ingredients.append(existing_ingredient) ingredients_by_name[lower_name] = existing_ingredient ingredients.append(existing_ingredient) db.session().bulk_save_objects(missing_ingredients, return_defaults=True) db.session().flush() recipe_ingredients = [] for index, recipe_ingredient_form in enumerate(form.ingredient_amounts): amount, unit = recipe_ingredient_form.parse_amount() recipe_ingredients.append(RecipeIngredient( amount=amount, amount_unit=unit, ingredient_id=ingredients[index].id, recipe_id=self.id, group_name=recipe_ingredient_form.group.data, )) db.session().bulk_save_objects(recipe_ingredients) db.session().flush()
def change_password(): if request.method == "GET": return redirect(url_for("my_account")) form = ChangePasswordForm() if not form.validate(): return jsonify(error_messages=form.errors), 400 if not bcrypt.check_password_hash(current_user.password_hash, form.current_password.data): return jsonify(error_messages={ "current_password": ["Current password is incorrect"], }), 400 current_user.password_hash = \ bcrypt.generate_password_hash(form.new_password.data).decode("utf-8") db.session().commit() return ""
def update_shopping_list_item(item_id: int): if request.method == "GET": return redirect(url_for("get_shopping_list")) form = RecipeIngredientForm(request.form) if not form.validate(): return render_shopping_list(form, item_id) item = ShoppingListItem.query.filter_by( id=item_id, account_id=current_user.id, ).first_or_404() item.amount, item.amount_unit = form.parse_amount() ingredient = Ingredient.insert_if_missing(form.name.data.strip(), current_user.id) item.ingredient_id = ingredient.id db.session().flush() Ingredient.delete_unused_ingredients(current_user.id) db.session().commit() return redirect(url_for("get_shopping_list"))
def update_account(account_id): if request.method == "GET": return redirect(url_for("get_accounts")) form = EditAccountForm() if not form.validate(): return jsonify(error_messages=form.errors), 400 account = Account.query.filter_by(id=account_id).first_or_404() username_duplicate = \ Account.query.filter_by(username=form.username.data).first() if username_duplicate and username_duplicate.id != account.id: return jsonify(error_messages={ "username": ["Username is already taken"], }), 400 account.username = form.username.data account.role = form.role.data if form.password.data: account.password_hash = bcrypt.generate_password_hash( form.password.data, ).decode("utf-8") db.session().commit() return ""
def update_recipe(recipe_id: int): form = EditRecipeForm(request.form) if not form.validate(): return render_edit_form( url_for("update_recipe", recipe_id=recipe_id), url_for('get_recipe', recipe_id=recipe_id), form, ) recipe = Recipe.query.filter_by( id=recipe_id, account_id=current_user.id, ).first_or_404() recipe.name = form.name.data recipe.description = form.description.data recipe.steps = form.steps.data RecipeIngredient.query.filter_by(recipe_id=recipe.id).delete() db.session.flush() recipe.insert_ingredients_from_form(form) Ingredient.delete_unused_ingredients(current_user.id) db.session().commit() return redirect(url_for("get_recipe", recipe_id=recipe_id))
def get_top_recipe_collectors(count): stmt = text(""" SELECT accounts.username username, COUNT(recipes.id) recipe_count FROM accounts LEFT JOIN recipes ON recipes.account_id = accounts.id GROUP BY accounts.username ORDER BY COUNT(recipes.id) DESC, accounts.username LIMIT :count """).params(count=count) rows = db.session().execute(stmt) try: return rows.fetchall() finally: rows.close()
def create_account(): if request.method == "GET": return redirect(url_for("get_accounts")) form = EditAccountForm() if not form.validate(): return jsonify(error_messages=form.errors), 400 if Account.is_username_taken(form.username.data): return jsonify(error_messages={ "username": ["Username is already taken"], }), 400 if form.password.data: password = form.password.data else: password = secrets.token_urlsafe(64) db.session().add( Account( username=form.username.data, role=form.role.data, password_hash=bcrypt.generate_password_hash(password).decode( "utf-8"), )) db.session().commit() return ""
def add_ingredient_to_shopping_list(): if request.method == "GET": return redirect(url_for("get_shopping_list")) form = AddIngredientToShoppingListForm() if not form.validate(): abort(400) item = ShoppingListItem.query.filter_by( account_id=current_user.id, ingredient_id=form.ingredient_id.data, amount_unit=form.amount_unit.data, ).first() if item is None: db.session().add( ShoppingListItem( amount=Decimal(clamp_amount(form.amount.data)), amount_unit=form.amount_unit.data, ingredient_id=form.ingredient_id.data, account_id=current_user.id, )) else: item.amount = clamp_amount(item.amount + Decimal(clamp_amount(form.amount.data))) db.session().commit() return redirect(url_for("get_recipe", recipe_id=form.recipe_id.data))
def get_ingredients(self): stmt = text(""" SELECT ri.amount AS amount, ri.amount_unit AS amount_unit, ri.group_name AS group_name, i.id AS id, i.name AS name FROM ingredients i, recipe_ingredient ri WHERE ri.recipe_id = :recipe_id AND i.account_id = :account_id AND ri.ingredient_id = i.id ORDER BY ri.id """).bindparams(recipe_id=self.id, account_id=self.account_id) return db.session().execute(stmt)
def ingredient_completions(): query = request.args.get("query", "") try: count = int(request.args.get("count", "10")) if count <= 0: raise ValueError() except ValueError: return jsonify( error="Query parameter 'count' must be a natural number."), 400 completions = db.session().execute( select( columns=[Ingredient.name], from_obj=Ingredient, whereclause=(Ingredient.account_id == current_user.id) & Ingredient.name.contains(query), distinct=True, ).limit(count)) return jsonify(completions=[completion[0] for completion in completions])
def get_shopping_list_amounts(self): stmt = text(""" SELECT i.id AS id, SUM(sli.amount) AS amount, sli.amount_unit AS unit FROM ( SELECT DISTINCT i.id AS id, i.name AS name FROM ingredients i, recipe_ingredient ri WHERE i.account_id = :account_id AND i.id = ri.ingredient_id AND ri.recipe_id = :recipe_id ) i LEFT JOIN shopping_list_items sli ON sli.ingredient_id = i.id WHERE sli.account_id = :account_id GROUP BY i.id, sli.amount_unit """).bindparams(recipe_id=self.id, account_id=self.account_id) return db.session().execute(stmt)
def create_recipe(): form = EditRecipeForm() if request.method == "GET" or not form.validate(): return render_edit_form( url_for("create_recipe"), url_for("get_recipes"), form, ) recipe = Recipe( name=form.name.data, description=form.description.data, steps=form.steps.data, ) recipe.account_id = current_user.id db.session().add(recipe) db.session().flush() recipe.insert_ingredients_from_form(form) db.session().commit() return redirect(url_for("get_recipes"))
def delete_account(account_id): if request.method == "GET": return redirect(url_for("get_accounts")) Account.query.filter_by(id=account_id).delete() db.session().commit() return redirect(url_for("get_accounts"))
def get_miner_by_name(user, miner_name): return db.session(Miner).filter_by(user=user, name=miner_name)
def is_username_taken(username): return db.session().query( exists().where(Account.username == username)).scalar()