sync - build workin

This commit is contained in:
2025-09-29 11:49:31 -07:00
parent 72059afe47
commit 494320c8f3
4 changed files with 172 additions and 72 deletions

View File

@@ -160,6 +160,32 @@ def sample_template(db_session, sample_meal):
return template return template
@pytest.fixture
def sample_weekly_menu(db_session, sample_template):
"""Create a sample weekly menu with templates assigned to days"""
weekly_menu = WeeklyMenu(name="Sample Weekly Menu")
db_session.add(weekly_menu)
db_session.commit()
db_session.refresh(weekly_menu)
# Assign sample_template to Monday (day 0) and Tuesday (day 1)
weekly_menu_day_monday = WeeklyMenuDay(
weekly_menu_id=weekly_menu.id,
day_of_week=0,
template_id=sample_template.id
)
weekly_menu_day_tuesday = WeeklyMenuDay(
weekly_menu_id=weekly_menu.id,
day_of_week=1,
template_id=sample_template.id
)
db_session.add(weekly_menu_day_monday)
db_session.add(weekly_menu_day_tuesday)
db_session.commit()
db_session.refresh(weekly_menu)
return weekly_menu
@pytest.fixture @pytest.fixture
def sample_plan(db_session, sample_meal): def sample_plan(db_session, sample_meal):
"""Create a sample plan""" """Create a sample plan"""

110
main.py
View File

@@ -13,7 +13,6 @@ from fastapi.responses import HTMLResponse
from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime, ForeignKey, Text, Date, Boolean from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime, ForeignKey, Text, Date, Boolean
from sqlalchemy import or_ from sqlalchemy import or_
from sqlalchemy.orm import sessionmaker, Session, relationship, declarative_base from sqlalchemy.orm import sessionmaker, Session, relationship, declarative_base
from sqlalchemy.orm import joinedload
from pydantic import BaseModel, ConfigDict from pydantic import BaseModel, ConfigDict
from typing import List, Optional from typing import List, Optional
from datetime import date, datetime from datetime import date, datetime
@@ -1567,6 +1566,113 @@ async def weekly_menu_page(request: Request, db: Session = Depends(get_db)):
"templates": templates_list "templates": templates_list
}) })
@app.post("/weeklymenu/create")
async def create_weekly_menu(request: Request, db: Session = Depends(get_db)):
"""Create a new weekly menu with template assignments."""
try:
form_data = await request.form()
name = form_data.get("name")
template_assignments_str = form_data.get("template_assignments")
if not name:
return {"status": "error", "message": "Weekly menu name is required"}
# Check if weekly menu already exists
existing_weekly_menu = db.query(WeeklyMenu).filter(WeeklyMenu.name == name).first()
if existing_weekly_menu:
return {"status": "error", "message": f"Weekly menu with name '{name}' already exists"}
weekly_menu = WeeklyMenu(name=name)
db.add(weekly_menu)
db.flush() # To get the weekly_menu.id
if template_assignments_str:
assignments = template_assignments_str.split(',')
for assignment in assignments:
day_of_week_str, template_id_str = assignment.split(':', 1)
day_of_week = int(day_of_week_str)
template_id = int(template_id_str)
# Check if template exists
template = db.query(Template).filter(Template.id == template_id).first()
if not template:
raise HTTPException(status_code=400, detail=f"Template with ID {template_id} not found.")
weekly_menu_day = WeeklyMenuDay(
weekly_menu_id=weekly_menu.id,
day_of_week=day_of_week,
template_id=template_id
)
db.add(weekly_menu_day)
db.commit()
return {"status": "success", "message": "Weekly menu created successfully"}
except Exception as e:
db.rollback()
logging.error(f"Error creating weekly menu: {e}")
return {"status": "error", "message": str(e)}
@app.post("/weeklymenu/{weekly_menu_id}/apply")
async def apply_weekly_menu(weekly_menu_id: int, request: Request, db: Session = Depends(get_db)):
"""Apply a weekly menu to a person's plan for a specific week."""
try:
from datetime import datetime, timedelta
form_data = await request.form()
person = form_data.get("person")
week_start_date_str = form_data.get("week_start_date")
confirm_overwrite = form_data.get("confirm_overwrite") == "true"
if not person or not week_start_date_str:
return {"status": "error", "message": "Person and week start date are required."}
week_start_date = datetime.fromisoformat(week_start_date_str).date()
weekly_menu = db.query(WeeklyMenu).filter(WeeklyMenu.id == weekly_menu_id).first()
if not weekly_menu:
return {"status": "error", "message": "Weekly menu not found."}
# Check if there are existing plans for the target week
existing_plans = db.query(Plan).filter(
Plan.person == person,
Plan.date >= week_start_date,
Plan.date < (week_start_date + timedelta(days=7))
).all()
if existing_plans and not confirm_overwrite:
return {"status": "confirm_overwrite", "message": "Meals already planned for this week. Do you want to overwrite them?"}
# If confirmed or no existing plans, delete existing plans for the week
if existing_plans:
db.query(Plan).filter(
Plan.person == person,
Plan.date >= week_start_date,
Plan.date < (week_start_date + timedelta(days=7))
).delete()
db.flush()
# Apply each day of the weekly menu
for weekly_menu_day in weekly_menu.weekly_menu_days:
target_date = week_start_date + timedelta(days=weekly_menu_day.day_of_week)
template = weekly_menu_day.template
if template:
for template_meal in template.template_meals:
plan = Plan(
person=person,
date=target_date,
meal_id=template_meal.meal_id,
meal_time=template_meal.meal_time
)
db.add(plan)
db.commit()
return {"status": "success", "message": "Weekly menu applied successfully."}
except Exception as e:
db.rollback()
logging.error(f"Error applying weekly menu: {e}")
return {"status": "error", "message": str(e)}
# Plan tab # Plan tab
@app.get("/plan", response_class=HTMLResponse) @app.get("/plan", response_class=HTMLResponse)
@@ -2199,7 +2305,7 @@ async def templates_page(request: Request, db: Session = Depends(get_db)):
@app.get("/api/templates", response_model=List[TemplateDetail]) @app.get("/api/templates", response_model=List[TemplateDetail])
async def get_templates_api(db: Session = Depends(get_db)): async def get_templates_api(db: Session = Depends(get_db)):
"""API endpoint to get all templates with meal details.""" """API endpoint to get all templates with meal details."""
templates = db.query(Template).options(joinedload(Template.template_meals).joinedload(TemplateMeal.meal)).all() templates = db.query(Template).options(orm.joinedload(Template.template_meals).joinedload(TemplateMeal.meal)).all()
results = [] results = []
for t in templates: for t in templates:

View File

@@ -1,70 +0,0 @@
import pytest
from fastapi.testclient import TestClient
from main import app, get_db
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool
from datetime import date
import os
# Use an in-memory SQLite database for testing
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"
engine = create_engine(
SQLALCHEMY_DATABASE_URL,
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# Create tables
from main import Base, Template, Meal, TemplateMeal
Base.metadata.create_all(bind=engine)
def override_get_db():
try:
db = TestingSessionLocal()
yield db
finally:
db.close()
app.dependency_overrides[get_db] = override_get_db
client = TestClient(app)
def test_templates_page_renders_without_error():
"""Test that the /templates page renders without a TypeError."""
# Create a test template and meal
db = TestingSessionLocal()
meal = Meal(name="Test Meal", meal_type="breakfast", meal_time="Breakfast")
db.add(meal)
db.commit()
db.refresh(meal)
template = Template(name="Test Template")
db.add(template)
db.commit()
db.refresh(template)
template_meal = TemplateMeal(template_id=template.id, meal_id=meal.id, meal_time="Breakfast")
db.add(template_meal)
db.commit()
db.close()
# Test the HTML page
response = client.get("/templates")
assert response.status_code == 200
assert "text/html" in response.headers["content-type"]
# Test the API endpoint
response = client.get("/api/templates")
assert response.status_code == 200
assert response.headers["content-type"] == "application/json"
data = response.json()
assert len(data) == 1
assert data[0]["name"] == "Test Template"
assert len(data[0]["template_meals"]) == 1
assert data[0]["template_meals"][0]["meal_name"] == "Test Meal"

View File

@@ -14,6 +14,44 @@ class TestWeeklyMenuRoutes:
assert b"Weekly" in response.content or b"weekly" in response.content or b"Menu" in response.content assert b"Weekly" in response.content or b"weekly" in response.content or b"Menu" in response.content
def test_create_weekly_menu_route(self, client, sample_template):
"""Test POST /weeklymenu/create route"""
form_data = {
"name": "My New Weekly Menu",
"template_assignments": f"0:{sample_template.id},1:{sample_template.id}"
}
response = client.post("/weeklymenu/create", data=form_data)
assert response.status_code == 200
assert response.json() == {"status": "success", "message": "Weekly menu created successfully"}
def test_create_weekly_menu_route(self, client, sample_template):
"""Test POST /weeklymenu/create route"""
form_data = {
"name": "My New Weekly Menu",
"template_assignments": f"0:{sample_template.id},1:{sample_template.id}"
}
response = client.post("/weeklymenu/create", data=form_data)
assert response.status_code == 200
assert response.json() == {"status": "success", "message": "Weekly menu created successfully"}
def test_apply_weekly_menu_route(self, client, db_session, sample_weekly_menu):
"""Test POST /weeklymenu/{weekly_menu_id}/apply route"""
from datetime import date, timedelta
today = date.today()
# Find Monday of current week
week_start_date = (today - timedelta(days=today.weekday())).isoformat()
form_data = {
"person": "Sarah",
"week_start_date": week_start_date,
"confirm_overwrite": "false"
}
response = client.post(f"/weeklymenu/{sample_weekly_menu.id}/apply", data=form_data)
assert response.status_code == 200
assert response.json() == {"status": "success", "message": "Weekly menu applied successfully."}
class TestWeeklyMenuCRUD: class TestWeeklyMenuCRUD:
"""Test weekly menu CRUD operations""" """Test weekly menu CRUD operations"""