Compare commits

..

No commits in common. "407d649d993858e031b4a6aa2196832e6b8ed80f" and "7882b16bd412dfbb9df844d6508536a7b420dedc" have entirely different histories.

6 changed files with 23 additions and 88 deletions

18
main.py
View file

@ -3,7 +3,7 @@ import products, recipes, db, meals, persons, ingredients, shopping
import datetime
from pydantic import BaseModel
from typing import List, Annotated, Optional, Union
from typing import List, Annotated, Union
from fastapi import FastAPI, Depends, Query, Cookie
from fastapi.responses import JSONResponse
from fastapi.encoders import jsonable_encoder
@ -146,10 +146,10 @@ async def delete_recipe(recipe_id: int, conn: sqlite3.Connection = Depends(get_d
await conn.commit()
return recipe
@app.get("/meals/upcoming")
async def get_upcoming_meals(date_from: Annotated[datetime.datetime, Query(alias='from')], to: datetime.datetime, conn: sqlite3.Connection = Depends(get_db)) -> List[meals.Meal]:
@app.get("/meals/")
async def get_meals(date_from: Annotated[datetime.datetime, Query(alias='from')], to: datetime.datetime, conn: sqlite3.Connection = Depends(get_db)) -> List[meals.Meal]:
result = []
async for meal in meals.find_upcoming_meals_by_date_range(conn, date_from, to):
async for meal in meals.find_meals_by_date_range(conn, date_from, to):
await meals.load_recipes(conn, meal)
await meals.load_extra_ingredients(conn, meal)
await meals.load_participants(conn, meal)
@ -229,16 +229,6 @@ async def update_meal(meal_id: int, meal: meals.Meal, conn: sqlite3.Connection =
return await get_meal(meal_id, conn)
@app.post("/meals/{meal_id}/consumed")
async def mark_consumed(meal_id: int, consumed_date: Optional[datetime.datetime] = None, conn: sqlite3.Connection = Depends(get_db), person: persons.Person = Depends(cookie_person)) -> meals.Meal:
meal = await meals.find_meal_by_id(conn, meal_id)
if not meal:
return JSONResponse(status_code=404, content={'message': 'Meal not found'})
await meals.mark_consumed(conn, meal, consumed_date or datetime.datetime.now())
await conn.commit()
return meal
@app.delete("/meals/{meal_id}")
async def delete_meal(meal_id: int, conn: sqlite3.Connection = Depends(get_db)) -> meals.Meal:
meal = await meals.find_meal_by_id(conn, meal_id)

View file

@ -10,10 +10,10 @@ from persons import Person
import datetime
class Meal(BaseModel):
KEYS: ClassVar[List[str]] = ['id', 'suggested_date', 'consumed_date']
KEYS: ClassVar[List[str]] = ['id', 'meal_date']
id: int = -1
suggested_date: datetime.datetime
consumed_date: Optional[datetime.datetime] = None
meal_date: datetime.datetime
purchase_date: Optional[datetime.datetime] = None
chefs: List[Person] = []
cleanup: List[Person] = []
@ -21,15 +21,11 @@ class Meal(BaseModel):
recipes: List[Recipe] = []
extra_ingredients: List[Ingredient] = []
# Set from shopping list
purchase_date: Optional[datetime.datetime] = None
async def create(conn):
await conn.execute('''
CREATE TABLE IF NOT EXISTS Meal (
id INTEGER PRIMARY KEY,
suggested_date TEXT,
consumed_date TEXT
meal_date TEXT
);''')
await conn.execute('''
@ -75,9 +71,9 @@ async def insert_meal_recipe(conn, meal_id: int, recipe_id: int):
async def insert_meal(conn, meal: Meal):
async with conn.execute('''
INSERT INTO Meal (suggested_date)
INSERT INTO Meal (meal_date)
VALUES (?)
''', (meal.suggested_date,)) as cursor:
''', (meal.meal_date,)) as cursor:
meal.id = cursor.lastrowid
await sync_meal_participants(conn, meal.id, meal.chefs, 'chef')
@ -103,10 +99,10 @@ async def find_meal_by_id(conn, meal_id: int) -> Meal:
await load_extra_ingredients(conn, meal)
return meal
async def find_upcoming_meals_by_date_range(conn, start: datetime, end: datetime) -> AsyncIterator[Meal]:
async def find_meals_by_date_range(conn, start: datetime, end: datetime) -> AsyncIterator[Meal]:
async with conn.execute(f'''
SELECT {','.join(Meal.KEYS)} FROM Meal
WHERE suggested_date >= ? AND suggested_date <= ? AND consumed_date IS NULL
WHERE meal_date >= ? AND meal_date <= ?
''', (start, end)) as cursor:
async for row in cursor:
yield await with_purchase_date(conn, Meal(**{k:v for k,v in zip(Meal.KEYS, row)}))
@ -185,9 +181,9 @@ async def sync_recipes(conn, meal_id: int, recipes: List[Recipe]) -> None:
async def update_meal(conn, meal: Meal) -> None:
await conn.execute('''
UPDATE Meal
SET suggested_date = ?
SET meal_date = ?
WHERE id = ?
''', (meal.suggested_date, meal.id))
''', (meal.meal_date, meal.id))
await sync_meal_participants(conn, meal.id, meal.chefs, 'chef')
await sync_meal_participants(conn, meal.id, meal.cleanup, 'cleanup')
@ -196,15 +192,6 @@ async def update_meal(conn, meal: Meal) -> None:
await sync_extra_ingredients(conn, meal.id, meal.extra_ingredients)
await sync_recipes(conn, meal.id, meal.recipes)
async def mark_consumed(conn, meal: Meal, date: datetime.datetime = datetime.datetime.now()) -> None:
meal.consumed_date = date
await conn.execute('''
UPDATE Meal
SET consumed_date = ?
WHERE id = ?
''', (date, meal.id))
async def with_purchase_date(conn, meal: Meal) -> Meal:
async with conn.execute('''
SELECT purchased_date FROM ShoppingList

View file

@ -1,4 +1,4 @@
from meals import Meal, find_upcoming_meals_by_date_range, find_meal_by_id
from meals import Meal, find_meals_by_date_range, find_meal_by_id
from ingredients import Ingredient, insert_ingredient
from persons import Person
from products import Product
@ -245,7 +245,7 @@ async def load_shopping_list(conn, id: int) -> ShoppingList:
async def _upcoming_meals(conn) -> AsyncIterator[Meal]:
start = datetime.now()
end = start + timedelta(days=7)
async for meal in find_upcoming_meals_by_date_range(conn, start, end):
async for meal in find_meals_by_date_range(conn, start, end):
if meal.purchase_date is None:
yield meal

View file

@ -231,7 +231,7 @@ class Meals:
id=0,
create_date=datetime(2021, 12, 25),
created_by=Persons.jacob,
suggested_date=datetime(2021, 12, 25),
meal_date=datetime(2021, 12, 25),
chefs=[Persons.jacob],
cleanup=[Persons.ryan],
consumers=[Persons.ellie, Persons.chris],

View file

@ -191,7 +191,7 @@ class TestMeals(unittest.IsolatedAsyncioTestCase):
self.assertIsNotNone(meal_by_id)
self.assertEqual(meal_by_id.id, meal.id)
self.assertEqual(meal_by_id.suggested_date, meal.suggested_date)
self.assertEqual(meal_by_id.meal_date, meal.meal_date)
self.assertEqual(len(meal_by_id.chefs), 1)
self.assertEqual(meal_by_id.chefs[0].id, meal.chefs[0].id)
self.assertEqual(meal_by_id.chefs[0].name, meal.chefs[0].name)
@ -214,12 +214,12 @@ class TestMeals(unittest.IsolatedAsyncioTestCase):
self.assertEqual(meal_by_id.extra_ingredients[0].id, extra_ingredient.id)
self.assertEqual(meal_by_id.extra_ingredients[0].line, extra_ingredient.line)
meals_by_date_range = await main.get_upcoming_meals(meal.suggested_date, meal.suggested_date, self.conn)
meals_by_date_range = await main.get_meals(meal.meal_date, meal.meal_date, self.conn)
self.assertIsNotNone(meals_by_date_range)
self.assertIsInstance(meals_by_date_range, list, msg=meals_by_date_range.body if hasattr(meals_by_date_range, 'body') else meals_by_date_range)
self.assertEqual(len(meals_by_date_range), 1)
self.assertEqual(meals_by_date_range[0].id, meal.id)
self.assertEqual(meals_by_date_range[0].suggested_date, meal.suggested_date)
self.assertEqual(meals_by_date_range[0].meal_date, meal.meal_date)
self.assertEqual(len(meals_by_date_range[0].chefs), 1)
self.assertEqual(meals_by_date_range[0].chefs[0].id, meal.chefs[0].id)
self.assertEqual(meals_by_date_range[0].chefs[0].name, meal.chefs[0].name)
@ -230,48 +230,6 @@ class TestMeals(unittest.IsolatedAsyncioTestCase):
self.assertEqual(meals_by_date_range[0].recipes[0].id, recipe.id)
self.assertEqual(meals_by_date_range[0].recipes[0].name, recipe.name)
async def testMarkConsumed(self) -> None:
meal = test_data.Meals.broccoli_soup_for_jacob
recipe = meal.recipes[0]
recipe_ingredient = recipe.ingredients[0]
recipe_product = recipe_ingredient.product
extra_ingredient = meal.extra_ingredients[0]
extra_product = extra_ingredient.product
person = test_data.Persons.jacob
await products_db.insert_product(self.conn, recipe_product, {})
await products_db.insert_product(self.conn, extra_product, {})
created_recipe = await main.create_recipe(recipe, self.conn, person)
recipe.id = created_recipe.id
create_response = await main.create_meal(meal, self.conn)
self.assertIsNotNone(create_response)
self.assertIsInstance(create_response, meals.Meal, msg=create_response.body if hasattr(create_response, 'body') else create_response)
meal_by_id = await main.get_meal(meal.id, self.conn)
self.assertIsNotNone(meal_by_id)
self.assertIsInstance(meal_by_id, meals.Meal, msg=meal_by_id.body if hasattr(meal_by_id, 'body') else meal_by_id)
self.assertIsNone(meal_by_id.consumed_date)
updated_meal = await main.mark_consumed(meal_id=meal.id, conn=self.conn)
self.assertIsNotNone(updated_meal)
self.assertIsInstance(updated_meal, meals.Meal, msg=updated_meal.body if hasattr(updated_meal, 'body') else updated_meal)
self.assertIsNotNone(updated_meal.consumed_date)
self.assertLessEqual(datetime.datetime.now() - updated_meal.consumed_date, datetime.timedelta(seconds=1))
upcoming_meals = await main.get_upcoming_meals(meal.suggested_date, meal.suggested_date, self.conn)
self.assertIsNotNone(upcoming_meals)
self.assertIsInstance(upcoming_meals, list, msg=upcoming_meals.body if hasattr(upcoming_meals, 'body') else upcoming_meals)
self.assertEqual(len(upcoming_meals), 0)
meal_by_id = await main.get_meal(meal.id, self.conn)
self.assertIsNotNone(meal_by_id)
self.assertIsInstance(meal_by_id, meals.Meal, msg=meal_by_id.body if hasattr(meal_by_id, 'body') else meal_by_id)
self.assertIsNotNone(meal_by_id.consumed_date)
self.assertLessEqual(datetime.datetime.now() - meal_by_id.consumed_date, datetime.timedelta(seconds=1))
async def testUpdate(self) -> None:
meal = test_data.Meals.broccoli_soup_for_jacob
@ -293,7 +251,7 @@ class TestMeals(unittest.IsolatedAsyncioTestCase):
self.assertIsNotNone(saved_meal)
self.assertIsInstance(saved_meal, meals.Meal, msg=saved_meal.body if hasattr(saved_meal, 'body') else saved_meal)
saved_meal.suggested_date = datetime.datetime.fromisoformat('2021-01-01T12:00:00')
saved_meal.meal_date = datetime.datetime.fromisoformat('2021-01-01T12:00:00')
saved_meal.recipes = [test_data.Recipes.how_to_steam_green_beans]
saved_meal.extra_ingredients.append(test_data.Ingredients.butter)
saved_meal.chefs.append(test_data.Persons.ryan)
@ -305,7 +263,7 @@ class TestMeals(unittest.IsolatedAsyncioTestCase):
self.assertIsInstance(updated_meal, meals.Meal, msg=updated_meal.body if hasattr(updated_meal, 'body') else updated_meal)
self.assertEqual(updated_meal.id, saved_meal.id)
self.assertEqual(updated_meal.suggested_date, saved_meal.suggested_date)
self.assertEqual(updated_meal.meal_date, saved_meal.meal_date)
self.assertPersons(updated_meal.chefs, saved_meal.chefs)
self.assertPersons(updated_meal.cleanup, saved_meal.cleanup)
self.assertPersons(updated_meal.consumers, saved_meal.consumers)

View file

@ -45,7 +45,7 @@ class TestShopping(unittest.IsolatedAsyncioTestCase):
for recipe in meal.recipes:
await recipes.insert_recipe(self.conn, recipe)
meal.suggested_date = datetime.now() + timedelta(days=1)
meal.meal_date = datetime.now() + timedelta(days=1)
await meals.insert_meal(self.conn, meal)
shopping_list = await shopping.current_shopping_list(self.conn)