Add manual food item entry and update food item management

Introduces a new route and template for manually adding food items. Updates food item edit and delete operations to use the food item's ID instead of barcode and adds ownership checks. Adjusts form and model to make barcode optional, and updates navigation and dashboard templates to reflect these changes.
This commit is contained in:
2025-06-29 17:41:58 +02:00
parent e00bfee948
commit a6f6cdf346
8 changed files with 114 additions and 35 deletions

1
app.py
View File

@@ -115,7 +115,6 @@ def add_food_item():
assert form.protein.data is not None
assert form.carbs.data is not None
assert form.fat.data is not None
assert form.barcode.data is not None
db.session.add(
FoodItem(
name=form.name.data,

View File

@@ -23,11 +23,9 @@
<li class="nav-item">
<a class="nav-link" href="{{ url_for('scan') }}">Scan</a>
</li>
{% if current_user.is_admin %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('admin.food_items') }}">Food Items</a>
<a class="nav-link" href="{{ url_for('user.add_food_item_manual') }}">Add Manually</a>
</li>
{% endif %}
</ul>
<ul class="navbar-nav ms-auto">
{% if current_user.is_authenticated %}

View File

@@ -2,6 +2,7 @@ from flask import Blueprint, redirect, url_for, render_template, flash
from flask_login import current_user
from application import db
from forms import FoodItemForm
from models import FoodItem
user_bp = Blueprint(
"user",
@@ -22,14 +23,17 @@ def dashboard():
return render_template("dashboard.html", items=items)
@user_bp.route("/delete_food_item/<int:barcode>", methods=["POST"])
def delete_food_item(barcode: int):
item = current_user.food_items.filter_by(barcode=barcode).first()
@user_bp.route("/delete_food_item/<int:id>", methods=["POST"])
def delete_food_item(id: int):
item = FoodItem.query.get(id)
if item:
db.session.delete(item)
db.session.commit()
if item.owner_id == current_user.id:
db.session.delete(item)
db.session.commit()
else:
flash("You do not own this food item!")
else:
flash(f"You do not own a food item with barcode {barcode}")
flash("This food item does not exist")
return redirect(url_for("user.dashboard"))
@@ -45,23 +49,52 @@ fields = [
]
@user_bp.route("/edit_food_item/<int:barcode>", methods=["GET", "POST"])
def edit_food_item(barcode: int):
item = current_user.food_items.filter_by(barcode=barcode).first()
@user_bp.route("/edit_food_item/<int:id>", methods=["GET", "POST"])
def edit_food_item(id: int):
item = FoodItem.query.get(id)
if item:
form = FoodItemForm()
if form.validate_on_submit():
item.updateFromForm(form=form)
db.session.commit()
return redirect(url_for("user.dashboard"))
form.barcode.data = item.barcode
form.name.data = item.name
form.energy.data = item.energy_100
form.protein.data = item.protein_100
form.carbs.data = item.carbs_100
form.sugar.data = item.sugar_100
form.fat.data = item.fat_100
form.saturated_fat.data = item.saturated_fat_100
return render_template("edit_food_item.html", form=form)
else:
if item.owner_id == current_user.id:
form = FoodItemForm()
if form.validate_on_submit():
item.updateFromForm(form=form)
db.session.commit()
return redirect(url_for("user.dashboard"))
form.barcode.data = item.barcode
form.name.data = item.name
form.energy.data = item.energy_100
form.protein.data = item.protein_100
form.carbs.data = item.carbs_100
form.sugar.data = item.sugar_100
form.fat.data = item.fat_100
form.saturated_fat.data = item.saturated_fat_100
return render_template("edit_food_item.html", form=form)
return redirect(url_for("user.dashboard"))
@user_bp.route("/add_food_item_manual", methods=["GET", "POST"])
def add_food_item_manual():
form = FoodItemForm()
for item in form:
print(item)
if form.validate_on_submit():
assert form.name.data is not None
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
db.session.add(
FoodItem(
name=form.name.data,
owner_id=current_user.id,
energy=form.energy.data,
protein=form.protein.data,
carbs=form.carbs.data,
fat=form.fat.data,
barcode=form.barcode.data,
saturated_fat=form.saturated_fat.data,
sugar=form.sugar.data,
)
)
db.session.commit()
return redirect(url_for("user.dashboard"))
return render_template("add_food_item_manual.html", form=form)

View File

@@ -0,0 +1,49 @@
{% extends "base.html" %}
{% block content %}
<form method="POST">
{{ form.hidden_tag() }}
<div class="mb-3">
{{ form.barcode.label(class="form-label") }}
{{ form.barcode(class="form-control") }}
</div>
<div class="mb-3">
{{ form.name.label(class="form-label") }}
{{ form.name(class="form-control") }}
</div>
<div class="mb-3">
{{ form.energy.label(class="form-label") }}
{{ form.energy(class="form-control") }}
</div>
<div class="mb-3">
{{ form.protein.label(class="form-label") }}
{{ form.protein(class="form-control") }}
</div>
<div class="mb-3">
{{ form.carbs.label(class="form-label") }}
{{ form.carbs(class="form-control") }}
</div>
<div class="mb-3">
{{ form.sugar.label(class="form-label") }}
{{ form.sugar(class="form-control") }}
</div>
<div class="mb-3">
{{ form.fat.label(class="form-label") }}
{{ form.fat(class="form-control") }}
</div>
<div class="mb-3">
{{ form.saturated_fat.label(class="form-label") }}
{{ form.saturated_fat(class="form-control") }}
</div>
{{ form.submit(class="btn btn-primary") }}
</form>
{% endblock%}

View File

@@ -33,10 +33,10 @@ Food Nutritional Info
<td class="bg-body-tertiary">{{ food.protein_100 }}</td>
<td class="bg-body-tertiary">
<div class="d-flex gap-1">
<form method="GET" action="{{ url_for('user.edit_food_item', barcode=food.barcode) }}">
<form method="GET" action="{{ url_for('user.edit_food_item', id=food.id) }}">
<button type="submit" class="btn btn-warning btn-sm">Edit</button>
</form>
<form method="POST" action="{{ url_for('user.delete_food_item', barcode=food.barcode) }}"
<form method="POST" action="{{ url_for('user.delete_food_item', id=food.id) }}"
onsubmit="return confirm('Are you sure you want to delete this item?');">
<button type="submit" class="btn btn-danger btn-sm">Delete</button>
</form>

View File

@@ -6,7 +6,7 @@ from wtforms import (
IntegerField,
FloatField,
)
from wtforms.validators import DataRequired, InputRequired
from wtforms.validators import DataRequired, InputRequired, Optional
class LoginForm(FlaskForm):
@@ -16,12 +16,12 @@ class LoginForm(FlaskForm):
class FoodItemForm(FlaskForm):
barcode = IntegerField("Barcode", validators=[InputRequired()])
barcode = IntegerField("Barcode", validators=[Optional()])
name = StringField("Product Name", validators=[DataRequired()])
energy = IntegerField("Energy per 100g", validators=[InputRequired()])
protein = FloatField("protein per 100g", validators=[InputRequired()])
carbs = FloatField("carbs per 100g", validators=[InputRequired()])
sugar = FloatField("sugar per 100g")
sugar = FloatField("sugar per 100g", validators=[Optional()])
fat = FloatField("fat per 100g", validators=[InputRequired()])
saturated_fat = FloatField("saturated_fat per 100g")
submit = SubmitField("Add Item")

View File

@@ -39,7 +39,7 @@ class Unit(db.Model):
class FoodItem(db.Model):
__tablename__ = "food_item"
id = db.Column(db.Integer, primary_key=True)
barcode = db.Column(db.Integer, nullable=False)
barcode = db.Column(db.Integer)
owner_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
name = db.Column(db.String(150), nullable=False)
@@ -62,7 +62,7 @@ class FoodItem(db.Model):
protein: float,
carbs: float,
fat: float,
barcode: int,
barcode: Optional[int] = None,
sugar: Optional[float] = None,
saturated_fat: Optional[float] = None,
):