Skip to content
This repository has been archived by the owner on Feb 5, 2024. It is now read-only.

Commit

Permalink
feat: add swap API (#21)
Browse files Browse the repository at this point in the history
* chore: move cron api logic to app.core.cron

* feat: add crud.meal.swap

* chore: rename swapmodes

* chore: bump version to 1.4.0
  • Loading branch information
sralloza authored Nov 7, 2021
1 parent 14b161f commit 5c53a85
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 51 deletions.
19 changes: 1 addition & 18 deletions app/api/cron.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
"""Cron related API endpoints."""

from enum import Enum

from fastapi import APIRouter, BackgroundTasks, Depends

from ..cron import backup_database, check_frozen_meals, update_notion_meals
from ..core.cron import CRON_MAP, ValidCron
from ..deps.security import token_middleware
from ..utils.responses import gen_responses

Expand All @@ -15,21 +13,6 @@
)


class ValidCron(Enum):
"""Defined crons that can be launched from the API."""

BACKUP_DATABASE = "backup-database"
CHECK_FROZEN_MEALS = "check-frozen-meals"
UPDATE_NOTION_MEALS = "update-notion-meals"


CRON_MAP = {
ValidCron.BACKUP_DATABASE: backup_database,
ValidCron.CHECK_FROZEN_MEALS: check_frozen_meals,
ValidCron.UPDATE_NOTION_MEALS: update_notion_meals,
}


@router.post(
"/{cron}",
response_model_exclude_unset=True,
Expand Down
45 changes: 17 additions & 28 deletions app/api/meals.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
"""Meal related API endpoints."""

import datetime
from enum import Enum
from typing import Any, List, Union
from typing import List, Union

from fastapi import APIRouter, BackgroundTasks, Depends, Query
from pydantic import parse_obj_as
from fastapi import APIRouter, BackgroundTasks, Depends
from starlette.responses import Response

from .. import crud
from ..core.meals import SwapMode, paginate, simplify, simplify_asked
from ..cron.update_notion_meals import update_notion_meals
from ..deps.database import get_db
from ..deps.security import token_middleware
Expand All @@ -22,30 +21,6 @@
)


class OutputEnum(Enum):
"""Output types for meals."""

SIMPLE = "simple"
NORMAL = "normal"


def simplify_asked(output: OutputEnum = Query(None, description="Simplify output")):
"""Returns true if the output must be simplified."""
return output == OutputEnum.SIMPLE


def paginate(skip: int = 0, limit: int = 100):
"""Returns the pagination."""
return {"skip": skip, "limit": limit}


def simplify(input_data: Any, simplified_model: Any, simplify_flag: bool):
"""Simplifies output if needed."""
if not simplify_flag:
return input_data
return parse_obj_as(simplified_model, input_data)


@router.get(
"",
response_model_exclude_unset=True,
Expand Down Expand Up @@ -173,6 +148,20 @@ def create_multiple_meals(
return result


@router.put(
"/swap",
response_model=List[Union[Meal, SimpleMeal]],
response_model_exclude_unset=True,
summary="Swap meals",
)
def swap_meals(
*, db=Depends(get_db), meal_1: datetime.date, meal_2: datetime.date, mode: SwapMode
):
"""Swaps meal attributes."""

return crud.meal.swap(db, date_1=meal_1, date_2=meal_2, mode=mode)


@router.put(
"/{date}",
response_model=Union[Meal, SimpleMeal],
Expand Down
20 changes: 20 additions & 0 deletions app/core/cron.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""Cron core."""

from enum import Enum

from ..cron import backup_database, check_frozen_meals, update_notion_meals


class ValidCron(Enum):
"""Defined crons that can be launched from the API."""

BACKUP_DATABASE = "backup-database"
CHECK_FROZEN_MEALS = "check-frozen-meals"
UPDATE_NOTION_MEALS = "update-notion-meals"


CRON_MAP = {
ValidCron.BACKUP_DATABASE: backup_database,
ValidCron.CHECK_FROZEN_MEALS: check_frozen_meals,
ValidCron.UPDATE_NOTION_MEALS: update_notion_meals,
}
50 changes: 50 additions & 0 deletions app/core/meals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Meals core."""


from enum import Enum
from typing import Any

from fastapi import Query
from pydantic import parse_obj_as


class SwapMode(Enum):
"""Valid swap modes."""

ALL = "all"
LUNCH = "lunch"
LUNCH_1 = "lunch1"
LUNCH_2 = "lunch2"
DINNER = "dinner"


class OutputEnum(Enum):
"""Output types for meals."""

SIMPLE = "simple"
NORMAL = "normal"


def simplify_asked(output: OutputEnum = Query(None, description="Simplify output")):
"""Returns true if the output must be simplified."""
return output == OutputEnum.SIMPLE


def paginate(skip: int = 0, limit: int = 100):
"""Returns the pagination."""
return {"skip": skip, "limit": limit}


def simplify(input_data: Any, simplified_model: Any, simplify_flag: bool):
"""Simplifies output if needed."""
if not simplify_flag:
return input_data
return parse_obj_as(simplified_model, input_data)


def swap_attrs(obj1: Any, obj2: Any, attrname: str):
attr1 = getattr(obj1, attrname)
attr2 = getattr(obj2, attrname)

setattr(obj1, attrname, attr2)
setattr(obj2, attrname, attr1)
51 changes: 47 additions & 4 deletions app/crud/crud_meal.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
"""Meals CRUD operations."""

from datetime import datetime, timedelta
import datetime
from typing import List

from sqlalchemy import func
from sqlalchemy.orm.session import Session

from ..core.meals import SwapMode, swap_attrs
from ..crud.base import CRUDBase
from ..models import Meal
from ..schemas.meal import MealCreate, MealUpdate
Expand All @@ -30,7 +31,7 @@ def get_today_or_404(self, db: Session):
"""Get today's menu or return 404."""
meal_db = self.get_today(db)
if not meal_db:
self.raise_not_found_error(id=datetime.now().date())
self.raise_not_found_error(id=datetime.datetime.now().date())
return meal_db

def get_tomorrow_or_404(self, db: Session):
Expand All @@ -43,11 +44,11 @@ def get_tomorrow_or_404(self, db: Session):
@staticmethod
def get_tomorrow_date():
"""Returns tomorrow's date."""
return (datetime.now() + timedelta(days=1)).date()
return (datetime.datetime.now() + datetime.timedelta(days=1)).date()

def get_by_date_delta(self, db: Session, *, delta_days: int):
"""Get menu using a relative time delta."""
date = (datetime.now() + timedelta(days=delta_days)).date()
date = (datetime.datetime.now() + datetime.timedelta(days=delta_days)).date()
return self.get(db, id=date)

def get_today(self, db: Session):
Expand Down Expand Up @@ -76,6 +77,48 @@ def get_current_week(self, db: Session):
week = get_current_week()
return self.get_week(db, week=week)

def swap(
self,
db: Session,
*,
date_1: datetime.date,
date_2: datetime.date,
mode: SwapMode
) -> List[Meal]:
"""Swaps two meals data."""
obj1 = self.get_or_404(db, id=date_1)
obj2 = self.get_or_404(db, id=date_2)

attrnames = []
if mode == SwapMode.ALL:
attrnames += ["lunch1", "lunch2", "dinner"]
elif mode == SwapMode.LUNCH:
attrnames += ["lunch1", "lunch2"]
elif mode == SwapMode.LUNCH_1:
attrnames.append("lunch1")
elif mode == SwapMode.LUNCH_2:
attrnames.append("lunch2")
elif mode == SwapMode.DINNER:
attrnames.append("dinner")

if "lunch1" in attrnames:
attrnames.append("lunch1_frozen")
if "lunch2" in attrnames:
attrnames.append("lunch2_frozen")
if "dinner" in attrnames:
attrnames.append("dinner_frozen")

for attr in attrnames:
swap_attrs(obj1, obj2, attr)

db.add(obj1)
db.add(obj2)
db.commit()
db.refresh(obj1)
db.refresh(obj2)

return [obj1, obj2]

def remove_week(self, db: Session, *, week: int):
"""Remove meals for the entire week."""
meals = self.get_week(db, week=week)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "meal-planner"
version = "1.3.0"
version = "1.4.0"
description = ""
authors = ["Diego Alloza González <[email protected]>"]
packages = [
Expand Down

0 comments on commit 5c53a85

Please sign in to comment.