From 809de13ed87acb31ad09e68d35c3423be6c44f46 Mon Sep 17 00:00:00 2001 From: jableader Date: Mon, 14 Oct 2024 16:59:05 +1100 Subject: [PATCH] Use iso format date stamps --- main.py | 5 ++++- meals/db.py | 18 +++++++++--------- recipes/db.py | 17 ++++++++++------- shopping/db.py | 24 +++++++++++++----------- tests/test_main.py | 6 +++--- tests/test_shopping.py | 10 +++++----- 6 files changed, 44 insertions(+), 36 deletions(-) diff --git a/main.py b/main.py index 7870f69..b074dcd 100644 --- a/main.py +++ b/main.py @@ -228,11 +228,14 @@ async def update_meal(meal_id: int, meal: meals.Meal, conn: sqlite3.Connection = @app.post("/api/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: + if consumed_date and not consumed_date.tzinfo: + return JSONResponse(status_code=400, content={'message': 'Consumed date must include timezone'}) + 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 meals.mark_consumed(conn, meal, consumed_date or datetime.datetime.now().astimezone()) await shopping.unrequest_meal(conn, meal) await conn.commit() diff --git a/meals/db.py b/meals/db.py index e97251a..fe777e1 100644 --- a/meals/db.py +++ b/meals/db.py @@ -35,8 +35,8 @@ async def create(conn): await conn.execute(''' CREATE TABLE IF NOT EXISTS Meal ( id INTEGER PRIMARY KEY, - suggested_date TEXT, - consumed_date TEXT, + suggested_date DATETIME, + consumed_date DATETIME DEFAULT NULL, deleted_date TEXT DEFAULT NULL, purchase_date TEXT DEFAULT NULL );''') @@ -93,7 +93,7 @@ async def insert_meal(conn, meal: Meal): async with conn.execute(''' INSERT INTO Meal (suggested_date) VALUES (?) - ''', (meal.suggested_date,)) as cursor: + ''', (meal.suggested_date.isoformat(),)) as cursor: meal.id = cursor.lastrowid await sync_meal_participants(conn, meal.id, meal.chefs, 'chef') @@ -167,7 +167,7 @@ async def delete_meal(conn, meal_id: int) -> None: UPDATE Meal SET deleted_date = ? WHERE id = ? - ''', (datetime.datetime.now(), meal_id)) + ''', (datetime.datetime.now().astimezone().isoformat(), meal_id)) async def sync_extra_ingredients(conn, meal_id: int, ingredients: List[Ingredient]) -> None: await delete_ingredients_by_meal_id(conn, meal_id) @@ -196,7 +196,7 @@ async def update_meal(conn, meal: Meal) -> None: UPDATE Meal SET suggested_date = ? WHERE id = ? - ''', (meal.suggested_date, meal.id)) + ''', (meal.suggested_date.isoformat(), meal.id)) await sync_meal_participants(conn, meal.id, meal.chefs, 'chef') await sync_meal_participants(conn, meal.id, meal.cleanup, 'cleanup') @@ -205,22 +205,22 @@ async def update_meal(conn, meal: Meal) -> None: await sync_extra_ingredients(conn, meal.id, meal.extra_ingredients) await sync_meal_recipes(conn, meal.id, meal.recipes) -async def mark_consumed(conn, meal: Meal, date: datetime.datetime = datetime.datetime.now()) -> None: +async def mark_consumed(conn, meal: Meal, date: datetime.datetime) -> None: meal.consumed_date = date await conn.execute(''' UPDATE Meal SET consumed_date = ? WHERE id = ? - ''', (date, meal.id)) + ''', (date.isoformat(), meal.id)) async def mark_purchased(conn, meal: Meal) -> Meal: - meal.purchase_date = datetime.datetime.now() + meal.purchase_date = datetime.datetime.now().astimezone() await conn.execute(''' UPDATE Meal SET purchase_date = ? WHERE id = ? - ''', (meal.purchase_date, meal.id)) + ''', (meal.purchase_date.isoformat(), meal.id)) return meal \ No newline at end of file diff --git a/recipes/db.py b/recipes/db.py index 1ec524d..ac0f870 100644 --- a/recipes/db.py +++ b/recipes/db.py @@ -18,7 +18,7 @@ class Recipe(BaseModel): ingredients: List[Ingredient] = [] based_on_recipe: Optional[int] = None - date_created: datetime.datetime = datetime.datetime.now() + date_created: datetime.datetime = datetime.datetime.now().astimezone() created_by_id: Optional[int] created_by: Optional[Person] = None @@ -35,13 +35,13 @@ async def create(conn): serves INTEGER NOT NULL, image_urls TEXT NOT NULL, based_on_recipe INTEGER NULL, - - date_created DATETIME DEFAULT CURRENT_TIMESTAMP, + + date_created DATETIME NOT NULL, created_by_id INTEGER NOT NULL, - + date_hidden DATETIME DEFAULT NULL, hidden_by_id INTEGER DEFAULT NULL, - + FOREIGN KEY (based_on_recipe) REFERENCES Recipe(id) FOREIGN KEY (created_by_id) REFERENCES Person(id) FOREIGN KEY (hidden_by_id) REFERENCES Person(id) @@ -51,6 +51,9 @@ def _as_insert_field(recipe: Recipe, name: str): value = getattr(recipe, name) if name == 'image_urls': return json.dumps(value) + if isinstance(value, datetime.datetime): + return value.isoformat() + return value async def insert_recipe(conn, recipe: Recipe): @@ -68,9 +71,9 @@ async def insert_recipe(conn, recipe: Recipe): async def hide_recipe(conn, recipe_id: int, person: Person): await conn.execute(''' UPDATE Recipe - SET date_hidden = CURRENT_TIMESTAMP, hidden_by_id = ? + SET date_hidden = ?, hidden_by_id = ? WHERE id = ? - ''', (person.id, recipe_id)) + ''', (datetime.datetime.now().astimezone().isoformat(), person.id, recipe_id)) def row_to_recipe(col_tuples: List[Tuple[str, ...]]) -> Recipe: d = {k:v for k,v in col_tuples} diff --git a/shopping/db.py b/shopping/db.py index 2a3c1de..b71299a 100644 --- a/shopping/db.py +++ b/shopping/db.py @@ -22,7 +22,7 @@ class ShoppingListRequest(BaseModel): meal_id: Optional[int] = None meal: Optional[Meal] = None - created_date: datetime = datetime.now() + created_date: datetime = datetime.now().astimezone() class ShoppingListResult(BaseModel): KEYS: ClassVar[List[str]] = ['id', 'product_id', 'list_id', 'quantity', 'unit' ] @@ -44,7 +44,7 @@ class StoreEnum(str, Enum): class ShoppingList(BaseModel): KEYS: ClassVar[List[str]] = ['id', 'created_date', 'store_name'] id: int = -1 - created_date: datetime = datetime.now() + created_date: datetime = datetime.now().astimezone() store_name: StoreEnum = '' requests: List[ShoppingListRequest] = [] @@ -54,8 +54,8 @@ async def create(conn): await conn.execute(''' CREATE TABLE IF NOT EXISTS ShoppingList ( id INTEGER PRIMARY KEY, - created_date TEXT, - store_name TEXT, + created_date DATETIME, + store_name TEXT );''') await conn.execute(''' @@ -100,10 +100,12 @@ def validate_request(request: ShoppingListRequest) -> None: raise ValueError('Ingredient requests must have a person') async def insert_shopping_list(conn, shopping_list: ShoppingList): + shopping_list.created_date = datetime.now().astimezone() + async with conn.execute(''' INSERT INTO ShoppingList (created_date, store_name) - VALUES (CURRENT_TIMESTAMP, ?) - ''', (shopping_list.store_name,)) as cursor: + VALUES (?, ?) + ''', (shopping_list.created_date.isoformat(), shopping_list.store_name,)) as cursor: shopping_list.id = cursor.lastrowid for request in shopping_list.requests: @@ -123,7 +125,7 @@ async def insert_shopping_list(conn, shopping_list: ShoppingList): async with conn.execute(''' INSERT INTO ShoppingListRequest (ingredient_id, list_id, person_id, meal_id, created_date) VALUES (?, ?, ?, ?, ?) - ''', (request.ingredient_id, shopping_list.id, request.person_id, request.meal_id, request.created_date)) as cursor: + ''', (request.ingredient_id, shopping_list.id, request.person_id, request.meal_id, request.created_date.isoformat())) as cursor: request.id = cursor.lastrowid for item in shopping_list.results: @@ -244,22 +246,22 @@ async def request_ingredient(conn, person: Person, ingredient: Ingredient) -> Sh await insert_ingredient(conn, ingredient) - request = ShoppingListRequest(ingredient_id=ingredient.id, ingredient=ingredient, person_id=person.id, created_date=datetime.now()) + request = ShoppingListRequest(ingredient_id=ingredient.id, ingredient=ingredient, person_id=person.id, created_date=datetime.now().astimezone()) async with conn.execute(''' INSERT INTO ShoppingListRequest (ingredient_id, person_id, created_date) VALUES (?, ?, ?) - ''', (request.ingredient_id, request.person_id, request.created_date)) as cursor: + ''', (request.ingredient_id, request.person_id, request.created_date.isoformat())) as cursor: request.id = cursor.lastrowid return request async def request_meal(conn, person: Person, meal: Meal) -> ShoppingListRequest: - request = ShoppingListRequest(meal_id=meal.id, meal=meal, person_id=person.id, created_date=datetime.now()) + request = ShoppingListRequest(meal_id=meal.id, meal=meal, person_id=person.id, created_date=datetime.now().astimezone()) async with conn.execute(''' INSERT INTO ShoppingListRequest (meal_id, person_id, created_date) VALUES (?, ?, ?) - ''', (request.meal_id, request.person_id, request.created_date)) as cursor: + ''', (request.meal_id, request.person_id, request.created_date.isoformat())) as cursor: request.id = cursor.lastrowid return request diff --git a/tests/test_main.py b/tests/test_main.py index c1118c6..a688fef 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -235,11 +235,11 @@ class TestMeals(unittest.IsolatedAsyncioTestCase): 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) + updated_meal = await main.mark_consumed(meal_id=meal.id, consumed_date=datetime.datetime.now().astimezone(), 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)) + self.assertLessEqual(datetime.datetime.now().astimezone() - 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) @@ -250,7 +250,7 @@ class TestMeals(unittest.IsolatedAsyncioTestCase): 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)) + self.assertLessEqual(datetime.datetime.now().astimezone() - meal_by_id.consumed_date, datetime.timedelta(seconds=1)) async def testUpdate(self) -> None: diff --git a/tests/test_shopping.py b/tests/test_shopping.py index a992758..28c137b 100644 --- a/tests/test_shopping.py +++ b/tests/test_shopping.py @@ -46,7 +46,7 @@ class TestShopping(unittest.IsolatedAsyncioTestCase): await recipes.insert_recipe(self.conn, mr.recipe) mr.recipe_id = mr.recipe.id - meal.suggested_date = datetime.now() + timedelta(days=1) + meal.suggested_date = datetime.now().astimezone() + timedelta(days=1) await meals.insert_meal(self.conn, meal) shopping_list = await shopping.current_shopping_list(self.conn) @@ -109,7 +109,7 @@ class TestShopping(unittest.IsolatedAsyncioTestCase): await products.insert_product(self.conn, ingredient.product, {}) shopping_list = await shopping.current_shopping_list(self.conn) - await shopping.mark_found(self.conn, ingredient, date_found=datetime.now()) + await shopping.mark_found(self.conn, ingredient, date_found=datetime.now().astimezone()) shopping_list = await shopping.current_shopping_list(self.conn) self.assertEqual(len(shopping_list.results), 1) @@ -118,7 +118,7 @@ class TestShopping(unittest.IsolatedAsyncioTestCase): self.assertEqual(shopping_list.results[0].unit, ingredient.unit) ingredient.quantity = 2 - await shopping.mark_found(self.conn, ingredient, date_found=datetime.now()) + await shopping.mark_found(self.conn, ingredient, date_found=datetime.now().astimezone()) shopping_list = await shopping.current_shopping_list(self.conn) self.assertEqual(len(shopping_list.results), 1) @@ -127,7 +127,7 @@ class TestShopping(unittest.IsolatedAsyncioTestCase): self.assertEqual(shopping_list.results[0].unit, ingredient.unit) ingredient.unit = 'kg' - await shopping.mark_found(self.conn, ingredient, date_found=datetime.now()) + await shopping.mark_found(self.conn, ingredient, date_found=datetime.now().astimezone()) shopping_list = await shopping.current_shopping_list(self.conn) self.assertEqual(len(shopping_list.results), 2) @@ -149,7 +149,7 @@ class TestShopping(unittest.IsolatedAsyncioTestCase): shopping_list = await shopping.mark_purchased(self.conn) self.assertIsNotNone(shopping_list.purchased_date) - self.assertLessEqual(shopping_list.purchased_date - datetime.now(), timedelta(seconds=1)) + self.assertLessEqual(shopping_list.purchased_date - datetime.now().astimezone(), timedelta(seconds=1)) new_shopping_list = await shopping.current_shopping_list(self.conn) self.assertNotEqual(shopping_list.id, new_shopping_list.id)