mirror of
https://github.com/StefBuwalda/cal_counter.git
synced 2025-10-30 03:10:00 +00:00
Migrated add_meal_v2 routes and templates to add_meal, renaming endpoints and updating references throughout the app. Removed legacy daily_log2 route and template, consolidating to daily_log. Moved macro_arr_to_json to utils.py for reuse. Updated navigation and redirect logic to use new routes. Improved item finding and barcode scanning UI.
178 lines
5.0 KiB
Python
178 lines
5.0 KiB
Python
from flask import (
|
|
Blueprint,
|
|
redirect,
|
|
url_for,
|
|
render_template,
|
|
session,
|
|
request,
|
|
jsonify,
|
|
)
|
|
from flask_login import current_user
|
|
from forms import FoodItemForm, FoodLogForm
|
|
from application import db
|
|
from models import FoodItem, FoodLog
|
|
from sqlalchemy import and_, or_
|
|
from datetime import datetime
|
|
from sqlalchemy.sql.elements import BinaryExpression
|
|
from typing import cast
|
|
|
|
bp = Blueprint(
|
|
"add_meal",
|
|
__name__,
|
|
url_prefix="/add_meal",
|
|
template_folder="templates",
|
|
)
|
|
|
|
|
|
def date_present(func):
|
|
def check_date():
|
|
if "selected_date" not in session:
|
|
return redirect(url_for("user.daily_log"))
|
|
|
|
|
|
def item_selected(func):
|
|
def check_item():
|
|
if check_item():
|
|
if "item_id" not in session:
|
|
return redirect(url_for("add_meal.find_item"))
|
|
|
|
|
|
@bp.before_request
|
|
def login_required():
|
|
if not current_user.is_authenticated:
|
|
return redirect(url_for("auth.login"))
|
|
|
|
|
|
@date_present
|
|
@bp.route("/find_item", methods=["GET"])
|
|
def find_item():
|
|
return render_template("find_item.html")
|
|
|
|
|
|
@date_present
|
|
@bp.route("/select_item/<string:input>", methods=["GET"])
|
|
def select_item(input: str):
|
|
# Check if input is a barcode
|
|
if input.isdigit():
|
|
item = current_user.food_items.filter_by(barcode=input).first()
|
|
|
|
else:
|
|
item = current_user.food_items.filter_by(name=input).first()
|
|
|
|
if item is None:
|
|
# Does not exist, add item
|
|
return redirect(url_for("add_meal.add_new_item", input=input))
|
|
|
|
# Track item to add and continue to next step
|
|
session["item_id"] = item.id
|
|
return redirect(url_for("add_meal.step4"))
|
|
|
|
|
|
@date_present
|
|
@bp.route("/add_new_item/<string:input>", methods=["GET"])
|
|
def add_new_item(input: str):
|
|
form = FoodItemForm()
|
|
|
|
if input.isdigit():
|
|
form.barcode.data = input
|
|
else:
|
|
form.name.data = input
|
|
return render_template("add_new_item.html", form=form)
|
|
|
|
|
|
@date_present
|
|
@bp.route("/add_new_item/<string:input>", methods=["POST"])
|
|
def post_new_item(input: str):
|
|
form = FoodItemForm()
|
|
|
|
if form.validate_on_submit():
|
|
# Form has valid input
|
|
barcode = form.barcode.data
|
|
name = form.name.data
|
|
assert name
|
|
assert form.energy.data is not None
|
|
assert form.protein.data is not None
|
|
assert form.carbs.data is not None
|
|
assert form.fat.data is not None
|
|
|
|
# Check if name or barcode already exists
|
|
name_filter = cast(BinaryExpression, FoodItem.name == name)
|
|
barcode_filter = cast(BinaryExpression, FoodItem.barcode == barcode)
|
|
filter_exp = or_(name_filter, barcode_filter)
|
|
item = current_user.food_items.filter(filter_exp).first()
|
|
|
|
if item is None:
|
|
# Item does not exist, add to DB
|
|
barcode = (
|
|
barcode if barcode else None
|
|
) # Turn empty strings into None
|
|
db.session.add(
|
|
FoodItem(
|
|
name=name,
|
|
owner_id=current_user.id,
|
|
energy=form.energy.data,
|
|
protein=form.protein.data,
|
|
carbs=form.carbs.data,
|
|
fat=form.fat.data,
|
|
barcode=barcode,
|
|
saturated_fat=form.saturated_fat.data,
|
|
sugar=form.sugar.data,
|
|
)
|
|
)
|
|
db.session.commit()
|
|
print("[DEBUG] New FoodItem Added")
|
|
input = barcode if barcode else name # update input
|
|
else:
|
|
print(f"Item exists: {item.barcode} {item.name}")
|
|
|
|
# Item added or already present, return to step 3.
|
|
return redirect(url_for("add_meal.select_item", input=input))
|
|
else:
|
|
print("[DEBUG] Form Invalid")
|
|
return redirect(url_for("add_meal.add_new_item", input=input))
|
|
|
|
|
|
@date_present
|
|
@item_selected
|
|
@bp.route("/step4", methods=["GET", "POST"])
|
|
def step4():
|
|
form = FoodLogForm()
|
|
item = db.session.get(FoodItem, session["item_id"])
|
|
if not item:
|
|
return redirect(url_for("add_meal.find_item"))
|
|
|
|
if form.validate_on_submit():
|
|
assert form.amount.data
|
|
db.session.add(
|
|
FoodLog(
|
|
food_item_id=item.id,
|
|
user_id=current_user.id,
|
|
amount=form.amount.data,
|
|
date_=datetime.strptime(
|
|
session["selected_date"], "%Y-%m-%d"
|
|
).date(),
|
|
)
|
|
)
|
|
db.session.commit()
|
|
session.pop("item_id")
|
|
session.pop("selected_date")
|
|
return redirect(url_for("user.daily_log"))
|
|
|
|
return render_template("step4.html", item=item, form=form)
|
|
|
|
|
|
@date_present
|
|
@bp.route("/query", methods=["GET"])
|
|
def query():
|
|
q = request.args.get("q", "").strip().lower()
|
|
if not q:
|
|
return jsonify([])
|
|
|
|
words = q.split()
|
|
filters = [
|
|
FoodItem.name.ilike(f"%{word}%") for word in words # type: ignore
|
|
]
|
|
|
|
results = current_user.food_items.filter(and_(*filters)).all()
|
|
return jsonify([item.name for item in results])
|