mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-06-02 21:25:45 -04:00
chore: refactor base schema (#1098)
* remove dead backup code * implmenet own base model * refactor to use MealieModel instead of CamelModel * cleanup deps
This commit is contained in:
parent
bcd98cba2f
commit
11b4d2389a
@ -96,7 +96,7 @@ def generate_typescript_types() -> None:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
path_as_module = path_to_module(module)
|
path_as_module = path_to_module(module)
|
||||||
generate_typescript_defs(path_as_module, str(out_path), exclude=("CamelModel")) # type: ignore
|
generate_typescript_defs(path_as_module, str(out_path), exclude=("MealieModel")) # type: ignore
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
failed_modules.append(module)
|
failed_modules.append(module)
|
||||||
print("\nModule Errors:", module, "-----------------") # noqa
|
print("\nModule Errors:", module, "-----------------") # noqa
|
||||||
|
@ -3,11 +3,12 @@ import pathlib
|
|||||||
import _static
|
import _static
|
||||||
import dotenv
|
import dotenv
|
||||||
import requests
|
import requests
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from jinja2 import Template
|
from jinja2 import Template
|
||||||
from requests import Response
|
from requests import Response
|
||||||
from rich import print
|
from rich import print
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
BASE = pathlib.Path(__file__).parent.parent.parent
|
BASE = pathlib.Path(__file__).parent.parent.parent
|
||||||
|
|
||||||
API_KEY = dotenv.get_key(BASE / ".env", "CROWDIN_API_KEY")
|
API_KEY = dotenv.get_key(BASE / ".env", "CROWDIN_API_KEY")
|
||||||
@ -57,7 +58,7 @@ export const LOCALES = [{% for locale in locales %}
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class TargetLanguage(CamelModel):
|
class TargetLanguage(MealieModel):
|
||||||
id: str
|
id: str
|
||||||
name: str
|
name: str
|
||||||
locale: str
|
locale: str
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
|
|
||||||
from mealie.routes._base import BaseAdminController, controller
|
from mealie.routes._base import BaseAdminController, controller
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
from mealie.services.email import EmailService
|
from mealie.services.email import EmailService
|
||||||
|
|
||||||
router = APIRouter(prefix="/email")
|
router = APIRouter(prefix="/email")
|
||||||
|
|
||||||
|
|
||||||
class EmailReady(CamelModel):
|
class EmailReady(MealieModel):
|
||||||
ready: bool
|
ready: bool
|
||||||
|
|
||||||
|
|
||||||
class EmailSuccess(CamelModel):
|
class EmailSuccess(MealieModel):
|
||||||
success: bool
|
success: bool
|
||||||
error: str = None
|
error: str = None
|
||||||
|
|
||||||
|
|
||||||
class EmailTest(CamelModel):
|
class EmailTest(MealieModel):
|
||||||
email: str
|
email: str
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
from .mealie_model import *
|
||||||
|
from .types import *
|
44
mealie/schema/_mealie/mealie_model.py
Normal file
44
mealie/schema/_mealie/mealie_model.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TypeVar
|
||||||
|
|
||||||
|
from humps.main import camelize
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
T = TypeVar("T", bound=BaseModel)
|
||||||
|
|
||||||
|
|
||||||
|
class MealieModel(BaseModel):
|
||||||
|
class Config:
|
||||||
|
alias_generator = camelize
|
||||||
|
allow_population_by_field_name = True
|
||||||
|
|
||||||
|
def cast(self, cls: type[T], **kwargs) -> T:
|
||||||
|
"""
|
||||||
|
Cast the current model to another with additional arguments. Useful for
|
||||||
|
transforming DTOs into models that are saved to a database
|
||||||
|
"""
|
||||||
|
create_data = {field: getattr(self, field) for field in self.__fields__ if field in cls.__fields__}
|
||||||
|
create_data.update(kwargs or {})
|
||||||
|
return cls(**create_data)
|
||||||
|
|
||||||
|
def map_to(self, dest: T) -> T:
|
||||||
|
"""
|
||||||
|
Map matching values from the current model to another model. Model returned
|
||||||
|
for method chaining.
|
||||||
|
"""
|
||||||
|
|
||||||
|
for field in self.__fields__:
|
||||||
|
if field in dest.__fields__:
|
||||||
|
setattr(dest, field, getattr(self, field))
|
||||||
|
|
||||||
|
return dest
|
||||||
|
|
||||||
|
def map_from(self, src: BaseModel):
|
||||||
|
"""
|
||||||
|
Map matching values from another model to the current model.
|
||||||
|
"""
|
||||||
|
|
||||||
|
for field in src.__fields__:
|
||||||
|
if field in self.__fields__:
|
||||||
|
setattr(self, field, getattr(src, field))
|
@ -1,7 +1,7 @@
|
|||||||
from fastapi_camelcase import CamelModel
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
|
|
||||||
class AppStatistics(CamelModel):
|
class AppStatistics(MealieModel):
|
||||||
total_recipes: int
|
total_recipes: int
|
||||||
total_users: int
|
total_users: int
|
||||||
total_groups: int
|
total_groups: int
|
||||||
@ -9,7 +9,7 @@ class AppStatistics(CamelModel):
|
|||||||
untagged_recipes: int
|
untagged_recipes: int
|
||||||
|
|
||||||
|
|
||||||
class AppInfo(CamelModel):
|
class AppInfo(MealieModel):
|
||||||
production: bool
|
production: bool
|
||||||
version: str
|
version: str
|
||||||
demo_status: bool
|
demo_status: bool
|
||||||
@ -26,7 +26,7 @@ class AdminAboutInfo(AppInfo):
|
|||||||
build_id: str
|
build_id: str
|
||||||
|
|
||||||
|
|
||||||
class CheckAppConfig(CamelModel):
|
class CheckAppConfig(MealieModel):
|
||||||
email_ready: bool = False
|
email_ready: bool = False
|
||||||
ldap_ready: bool = False
|
ldap_ready: bool = False
|
||||||
base_url_set: bool = False
|
base_url_set: bool = False
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from fastapi_camelcase import CamelModel
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
|
|
||||||
class MaintenanceSummary(CamelModel):
|
class MaintenanceSummary(MealieModel):
|
||||||
data_dir_size: str
|
data_dir_size: str
|
||||||
log_file_size: str
|
log_file_size: str
|
||||||
cleanable_images: int
|
cleanable_images: int
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import validator
|
from pydantic import validator
|
||||||
from slugify import slugify
|
from slugify import slugify
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
from ..recipe.recipe_category import RecipeCategoryResponse
|
from ..recipe.recipe_category import RecipeCategoryResponse
|
||||||
|
|
||||||
|
|
||||||
class CustomPageBase(CamelModel):
|
class CustomPageBase(MealieModel):
|
||||||
name: str
|
name: str
|
||||||
slug: Optional[str]
|
slug: Optional[str]
|
||||||
position: int
|
position: int
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4, validator
|
from pydantic import UUID4, validator
|
||||||
from slugify import slugify
|
from slugify import slugify
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
from ..recipe.recipe_category import CategoryBase, RecipeCategoryResponse
|
from ..recipe.recipe_category import CategoryBase, RecipeCategoryResponse
|
||||||
|
|
||||||
|
|
||||||
class CreateCookBook(CamelModel):
|
class CreateCookBook(MealieModel):
|
||||||
name: str
|
name: str
|
||||||
description: str = ""
|
description: str = ""
|
||||||
slug: str = None
|
slug: str = None
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4
|
from pydantic import UUID4
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
from .group_preferences import UpdateGroupPreferences
|
from .group_preferences import UpdateGroupPreferences
|
||||||
|
|
||||||
|
|
||||||
class GroupAdminUpdate(CamelModel):
|
class GroupAdminUpdate(MealieModel):
|
||||||
id: UUID4
|
id: UUID4
|
||||||
name: str
|
name: str
|
||||||
preferences: UpdateGroupPreferences
|
preferences: UpdateGroupPreferences
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4, NoneStr
|
from pydantic import UUID4, NoneStr
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Group Events Notifier Options
|
# Group Events Notifier Options
|
||||||
|
|
||||||
|
|
||||||
class GroupEventNotifierOptions(CamelModel):
|
class GroupEventNotifierOptions(MealieModel):
|
||||||
"""
|
"""
|
||||||
These events are in-sync with the EventTypes found in the EventBusService.
|
These events are in-sync with the EventTypes found in the EventBusService.
|
||||||
If you modify this, make sure to update the EventBusService as well.
|
If you modify this, make sure to update the EventBusService as well.
|
||||||
@ -55,7 +56,7 @@ class GroupEventNotifierOptionsOut(GroupEventNotifierOptions):
|
|||||||
# Notifiers
|
# Notifiers
|
||||||
|
|
||||||
|
|
||||||
class GroupEventNotifierCreate(CamelModel):
|
class GroupEventNotifierCreate(MealieModel):
|
||||||
name: str
|
name: str
|
||||||
apprise_url: str
|
apprise_url: str
|
||||||
|
|
||||||
@ -71,7 +72,7 @@ class GroupEventNotifierUpdate(GroupEventNotifierSave):
|
|||||||
apprise_url: NoneStr = None
|
apprise_url: NoneStr = None
|
||||||
|
|
||||||
|
|
||||||
class GroupEventNotifierOut(CamelModel):
|
class GroupEventNotifierOut(MealieModel):
|
||||||
id: UUID4
|
id: UUID4
|
||||||
name: str
|
name: str
|
||||||
enabled: bool
|
enabled: bool
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4
|
from pydantic import UUID4
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
class GroupDataExport(CamelModel):
|
|
||||||
|
class GroupDataExport(MealieModel):
|
||||||
id: UUID4
|
id: UUID4
|
||||||
group_id: UUID4
|
group_id: UUID4
|
||||||
name: str
|
name: str
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import enum
|
import enum
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
|
|
||||||
class SupportedMigrations(str, enum.Enum):
|
class SupportedMigrations(str, enum.Enum):
|
||||||
@ -10,5 +10,5 @@ class SupportedMigrations(str, enum.Enum):
|
|||||||
mealie_alpha = "mealie_alpha"
|
mealie_alpha = "mealie_alpha"
|
||||||
|
|
||||||
|
|
||||||
class DataMigrationCreate(CamelModel):
|
class DataMigrationCreate(MealieModel):
|
||||||
source_type: SupportedMigrations
|
source_type: SupportedMigrations
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4
|
from pydantic import UUID4
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
class SetPermissions(CamelModel):
|
|
||||||
|
class SetPermissions(MealieModel):
|
||||||
user_id: UUID4
|
user_id: UUID4
|
||||||
can_manage: bool = False
|
can_manage: bool = False
|
||||||
can_invite: bool = False
|
can_invite: bool = False
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4
|
from pydantic import UUID4
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
class UpdateGroupPreferences(CamelModel):
|
|
||||||
|
class UpdateGroupPreferences(MealieModel):
|
||||||
private_group: bool = False
|
private_group: bool = False
|
||||||
first_day_of_week: int = 0
|
first_day_of_week: int = 0
|
||||||
|
|
||||||
|
@ -2,13 +2,13 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4
|
from pydantic import UUID4
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
from mealie.schema.recipe.recipe_ingredient import IngredientFood, IngredientUnit
|
from mealie.schema.recipe.recipe_ingredient import IngredientFood, IngredientUnit
|
||||||
|
|
||||||
|
|
||||||
class ShoppingListItemRecipeRef(CamelModel):
|
class ShoppingListItemRecipeRef(MealieModel):
|
||||||
recipe_id: UUID4
|
recipe_id: UUID4
|
||||||
recipe_quantity: float
|
recipe_quantity: float
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ class ShoppingListItemRecipeRefOut(ShoppingListItemRecipeRef):
|
|||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class ShoppingListItemCreate(CamelModel):
|
class ShoppingListItemCreate(MealieModel):
|
||||||
shopping_list_id: UUID4
|
shopping_list_id: UUID4
|
||||||
checked: bool = False
|
checked: bool = False
|
||||||
position: int = 0
|
position: int = 0
|
||||||
@ -51,11 +51,11 @@ class ShoppingListItemOut(ShoppingListItemUpdate):
|
|||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class ShoppingListCreate(CamelModel):
|
class ShoppingListCreate(MealieModel):
|
||||||
name: str = None
|
name: str = None
|
||||||
|
|
||||||
|
|
||||||
class ShoppingListRecipeRefOut(CamelModel):
|
class ShoppingListRecipeRefOut(MealieModel):
|
||||||
id: UUID4
|
id: UUID4
|
||||||
shopping_list_id: UUID4
|
shopping_list_id: UUID4
|
||||||
recipe_id: UUID4
|
recipe_id: UUID4
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import NoneStr
|
from pydantic import NoneStr
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
class CreateInviteToken(CamelModel):
|
|
||||||
|
class CreateInviteToken(MealieModel):
|
||||||
uses: int
|
uses: int
|
||||||
|
|
||||||
|
|
||||||
class SaveInviteToken(CamelModel):
|
class SaveInviteToken(MealieModel):
|
||||||
uses_left: int
|
uses_left: int
|
||||||
group_id: UUID
|
group_id: UUID
|
||||||
token: str
|
token: str
|
||||||
|
|
||||||
|
|
||||||
class ReadInviteToken(CamelModel):
|
class ReadInviteToken(MealieModel):
|
||||||
token: str
|
token: str
|
||||||
uses_left: int
|
uses_left: int
|
||||||
group_id: UUID
|
group_id: UUID
|
||||||
@ -23,11 +24,11 @@ class ReadInviteToken(CamelModel):
|
|||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class EmailInvitation(CamelModel):
|
class EmailInvitation(MealieModel):
|
||||||
email: str
|
email: str
|
||||||
token: str
|
token: str
|
||||||
|
|
||||||
|
|
||||||
class EmailInitationResponse(CamelModel):
|
class EmailInitationResponse(MealieModel):
|
||||||
success: bool
|
success: bool
|
||||||
error: NoneStr = None
|
error: NoneStr = None
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4
|
from pydantic import UUID4
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
class CreateWebhook(CamelModel):
|
|
||||||
|
class CreateWebhook(MealieModel):
|
||||||
enabled: bool = True
|
enabled: bool = True
|
||||||
name: str = ""
|
name: str = ""
|
||||||
url: str = ""
|
url: str = ""
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4
|
from pydantic import UUID4
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
class MultiPurposeLabelCreate(CamelModel):
|
|
||||||
|
class MultiPurposeLabelCreate(MealieModel):
|
||||||
name: str
|
name: str
|
||||||
color: str = "#E0E0E0"
|
color: str = "#E0E0E0"
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
from datetime import date
|
from datetime import date
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import validator
|
from pydantic import validator
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
class MealIn(CamelModel):
|
|
||||||
|
class MealIn(MealieModel):
|
||||||
slug: Optional[str]
|
slug: Optional[str]
|
||||||
name: Optional[str]
|
name: Optional[str]
|
||||||
description: Optional[str]
|
description: Optional[str]
|
||||||
@ -14,7 +15,7 @@ class MealIn(CamelModel):
|
|||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class MealDayIn(CamelModel):
|
class MealDayIn(MealieModel):
|
||||||
date: Optional[date]
|
date: Optional[date]
|
||||||
meals: list[MealIn]
|
meals: list[MealIn]
|
||||||
|
|
||||||
@ -29,7 +30,7 @@ class MealDayOut(MealDayIn):
|
|||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class MealPlanIn(CamelModel):
|
class MealPlanIn(MealieModel):
|
||||||
group: str
|
group: str
|
||||||
start_date: date
|
start_date: date
|
||||||
end_date: date
|
end_date: date
|
||||||
|
@ -3,9 +3,9 @@ from enum import Enum
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import validator
|
from pydantic import validator
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
from mealie.schema.recipe.recipe import RecipeSummary
|
from mealie.schema.recipe.recipe import RecipeSummary
|
||||||
|
|
||||||
|
|
||||||
@ -16,12 +16,12 @@ class PlanEntryType(str, Enum):
|
|||||||
side = "side"
|
side = "side"
|
||||||
|
|
||||||
|
|
||||||
class CreatRandomEntry(CamelModel):
|
class CreatRandomEntry(MealieModel):
|
||||||
date: date
|
date: date
|
||||||
entry_type: PlanEntryType = PlanEntryType.dinner
|
entry_type: PlanEntryType = PlanEntryType.dinner
|
||||||
|
|
||||||
|
|
||||||
class CreatePlanEntry(CamelModel):
|
class CreatePlanEntry(MealieModel):
|
||||||
date: date
|
date: date
|
||||||
entry_type: PlanEntryType = PlanEntryType.breakfast
|
entry_type: PlanEntryType = PlanEntryType.breakfast
|
||||||
title: str = ""
|
title: str = ""
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4
|
from pydantic import UUID4
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
class Category(CamelModel):
|
|
||||||
|
class Category(MealieModel):
|
||||||
id: UUID4
|
id: UUID4
|
||||||
name: str
|
name: str
|
||||||
slug: str
|
slug: str
|
||||||
@ -46,7 +47,7 @@ class PlanRulesType(str, Enum):
|
|||||||
unset = "unset"
|
unset = "unset"
|
||||||
|
|
||||||
|
|
||||||
class PlanRulesCreate(CamelModel):
|
class PlanRulesCreate(MealieModel):
|
||||||
day: PlanRulesDay = PlanRulesDay.unset
|
day: PlanRulesDay = PlanRulesDay.unset
|
||||||
entry_type: PlanRulesType = PlanRulesType.unset
|
entry_type: PlanRulesType = PlanRulesType.unset
|
||||||
categories: list[Category] = []
|
categories: list[Category] = []
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic.utils import GetterDict
|
from pydantic.utils import GetterDict
|
||||||
|
|
||||||
from mealie.db.models.group.shopping_list import ShoppingList
|
from mealie.db.models.group.shopping_list import ShoppingList
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
|
|
||||||
class ListItem(CamelModel):
|
class ListItem(MealieModel):
|
||||||
title: Optional[str]
|
title: Optional[str]
|
||||||
text: str = ""
|
text: str = ""
|
||||||
quantity: int = 1
|
quantity: int = 1
|
||||||
@ -16,7 +16,7 @@ class ListItem(CamelModel):
|
|||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class ShoppingListIn(CamelModel):
|
class ShoppingListIn(MealieModel):
|
||||||
name: str
|
name: str
|
||||||
group: Optional[str]
|
group: Optional[str]
|
||||||
items: list[ListItem]
|
items: list[ListItem]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from fastapi_camelcase import CamelModel
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
|
|
||||||
class GetAll(CamelModel):
|
class GetAll(MealieModel):
|
||||||
start: int = 0
|
start: int = 0
|
||||||
limit: int = 999
|
limit: int = 999
|
||||||
|
@ -5,13 +5,13 @@ from pathlib import Path
|
|||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4, BaseModel, Field, validator
|
from pydantic import UUID4, BaseModel, Field, validator
|
||||||
from pydantic.utils import GetterDict
|
from pydantic.utils import GetterDict
|
||||||
from slugify import slugify
|
from slugify import slugify
|
||||||
|
|
||||||
from mealie.core.config import get_app_dirs
|
from mealie.core.config import get_app_dirs
|
||||||
from mealie.db.models.recipe.recipe import RecipeModel
|
from mealie.db.models.recipe.recipe import RecipeModel
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
from .recipe_asset import RecipeAsset
|
from .recipe_asset import RecipeAsset
|
||||||
from .recipe_comments import RecipeCommentOut
|
from .recipe_comments import RecipeCommentOut
|
||||||
@ -23,7 +23,7 @@ from .recipe_step import RecipeStep
|
|||||||
app_dirs = get_app_dirs()
|
app_dirs = get_app_dirs()
|
||||||
|
|
||||||
|
|
||||||
class RecipeTag(CamelModel):
|
class RecipeTag(MealieModel):
|
||||||
id: UUID4 = None
|
id: UUID4 = None
|
||||||
name: str
|
name: str
|
||||||
slug: str
|
slug: str
|
||||||
@ -58,11 +58,11 @@ class CreateRecipeByUrlBulk(BaseModel):
|
|||||||
imports: list[CreateRecipeBulk]
|
imports: list[CreateRecipeBulk]
|
||||||
|
|
||||||
|
|
||||||
class CreateRecipe(CamelModel):
|
class CreateRecipe(MealieModel):
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
|
|
||||||
class RecipeSummary(CamelModel):
|
class RecipeSummary(MealieModel):
|
||||||
id: Optional[UUID4]
|
id: Optional[UUID4]
|
||||||
|
|
||||||
user_id: UUID4 = Field(default_factory=uuid4)
|
user_id: UUID4 = Field(default_factory=uuid4)
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
|
|
||||||
class RecipeAsset(CamelModel):
|
class RecipeAsset(MealieModel):
|
||||||
name: str
|
name: str
|
||||||
icon: str
|
icon: str
|
||||||
file_name: Optional[str]
|
file_name: Optional[str]
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import enum
|
import enum
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
from mealie.schema.recipe.recipe_category import CategoryBase, TagBase
|
from mealie.schema.recipe.recipe_category import CategoryBase, TagBase
|
||||||
|
|
||||||
|
|
||||||
@ -9,7 +8,7 @@ class ExportTypes(str, enum.Enum):
|
|||||||
JSON = "json"
|
JSON = "json"
|
||||||
|
|
||||||
|
|
||||||
class ExportBase(CamelModel):
|
class ExportBase(MealieModel):
|
||||||
recipes: list[str]
|
recipes: list[str]
|
||||||
|
|
||||||
|
|
||||||
@ -29,12 +28,12 @@ class DeleteRecipes(ExportBase):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BulkActionError(CamelModel):
|
class BulkActionError(MealieModel):
|
||||||
recipe: str
|
recipe: str
|
||||||
error: str
|
error: str
|
||||||
|
|
||||||
|
|
||||||
class BulkActionsResponse(CamelModel):
|
class BulkActionsResponse(MealieModel):
|
||||||
success: bool
|
success: bool
|
||||||
message: str
|
message: str
|
||||||
errors: list[BulkActionError] = []
|
errors: list[BulkActionError] = []
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4
|
from pydantic import UUID4
|
||||||
from pydantic.utils import GetterDict
|
from pydantic.utils import GetterDict
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
class CategoryIn(CamelModel):
|
|
||||||
|
class CategoryIn(MealieModel):
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,11 +2,12 @@ from datetime import datetime
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4
|
from pydantic import UUID4
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
class UserBase(CamelModel):
|
|
||||||
|
class UserBase(MealieModel):
|
||||||
id: int
|
id: int
|
||||||
username: Optional[str]
|
username: Optional[str]
|
||||||
admin: bool
|
admin: bool
|
||||||
@ -15,7 +16,7 @@ class UserBase(CamelModel):
|
|||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class RecipeCommentCreate(CamelModel):
|
class RecipeCommentCreate(MealieModel):
|
||||||
recipe_id: UUID4
|
recipe_id: UUID4
|
||||||
text: str
|
text: str
|
||||||
|
|
||||||
@ -24,7 +25,7 @@ class RecipeCommentSave(RecipeCommentCreate):
|
|||||||
user_id: UUID4
|
user_id: UUID4
|
||||||
|
|
||||||
|
|
||||||
class RecipeCommentUpdate(CamelModel):
|
class RecipeCommentUpdate(MealieModel):
|
||||||
id: UUID
|
id: UUID
|
||||||
text: str
|
text: str
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@ import enum
|
|||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
from uuid import UUID, uuid4
|
from uuid import UUID, uuid4
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4, Field
|
from pydantic import UUID4, Field
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
from mealie.schema._mealie.types import NoneFloat
|
from mealie.schema._mealie.types import NoneFloat
|
||||||
|
|
||||||
|
|
||||||
class UnitFoodBase(CamelModel):
|
class UnitFoodBase(MealieModel):
|
||||||
name: str
|
name: str
|
||||||
description: str = ""
|
description: str = ""
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ class IngredientUnit(CreateIngredientUnit):
|
|||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class RecipeIngredient(CamelModel):
|
class RecipeIngredient(MealieModel):
|
||||||
title: Optional[str]
|
title: Optional[str]
|
||||||
note: Optional[str]
|
note: Optional[str]
|
||||||
unit: Optional[Union[IngredientUnit, CreateIngredientUnit]]
|
unit: Optional[Union[IngredientUnit, CreateIngredientUnit]]
|
||||||
@ -64,7 +64,7 @@ class RecipeIngredient(CamelModel):
|
|||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class IngredientConfidence(CamelModel):
|
class IngredientConfidence(MealieModel):
|
||||||
average: NoneFloat = None
|
average: NoneFloat = None
|
||||||
comment: NoneFloat = None
|
comment: NoneFloat = None
|
||||||
name: NoneFloat = None
|
name: NoneFloat = None
|
||||||
@ -73,7 +73,7 @@ class IngredientConfidence(CamelModel):
|
|||||||
food: NoneFloat = None
|
food: NoneFloat = None
|
||||||
|
|
||||||
|
|
||||||
class ParsedIngredient(CamelModel):
|
class ParsedIngredient(MealieModel):
|
||||||
input: Optional[str]
|
input: Optional[str]
|
||||||
confidence: IngredientConfidence = IngredientConfidence()
|
confidence: IngredientConfidence = IngredientConfidence()
|
||||||
ingredient: RecipeIngredient
|
ingredient: RecipeIngredient
|
||||||
@ -84,12 +84,12 @@ class RegisteredParser(str, enum.Enum):
|
|||||||
brute = "brute"
|
brute = "brute"
|
||||||
|
|
||||||
|
|
||||||
class IngredientsRequest(CamelModel):
|
class IngredientsRequest(MealieModel):
|
||||||
parser: RegisteredParser = RegisteredParser.nlp
|
parser: RegisteredParser = RegisteredParser.nlp
|
||||||
ingredients: list[str]
|
ingredients: list[str]
|
||||||
|
|
||||||
|
|
||||||
class IngredientRequest(CamelModel):
|
class IngredientRequest(MealieModel):
|
||||||
parser: RegisteredParser = RegisteredParser.nlp
|
parser: RegisteredParser = RegisteredParser.nlp
|
||||||
ingredient: str
|
ingredient: str
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
|
|
||||||
class Nutrition(CamelModel):
|
class Nutrition(MealieModel):
|
||||||
calories: Optional[str]
|
calories: Optional[str]
|
||||||
fat_content: Optional[str]
|
fat_content: Optional[str]
|
||||||
protein_content: Optional[str]
|
protein_content: Optional[str]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from fastapi_camelcase import CamelModel
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
|
|
||||||
class RecipeSettings(CamelModel):
|
class RecipeSettings(MealieModel):
|
||||||
public: bool = False
|
public: bool = False
|
||||||
show_nutrition: bool = False
|
show_nutrition: bool = False
|
||||||
show_assets: bool = False
|
show_assets: bool = False
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4, Field
|
from pydantic import UUID4, Field
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
from .recipe import Recipe
|
from .recipe import Recipe
|
||||||
|
|
||||||
|
|
||||||
@ -10,7 +11,7 @@ def defaut_expires_at_time() -> datetime:
|
|||||||
return datetime.utcnow() + timedelta(days=30)
|
return datetime.utcnow() + timedelta(days=30)
|
||||||
|
|
||||||
|
|
||||||
class RecipeShareTokenCreate(CamelModel):
|
class RecipeShareTokenCreate(MealieModel):
|
||||||
recipe_id: UUID4
|
recipe_id: UUID4
|
||||||
expires_at: datetime = Field(default_factory=defaut_expires_at_time)
|
expires_at: datetime = Field(default_factory=defaut_expires_at_time)
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
from uuid import UUID, uuid4
|
from uuid import UUID, uuid4
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4, Field
|
from pydantic import UUID4, Field
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
class IngredientReferences(CamelModel):
|
|
||||||
|
class IngredientReferences(MealieModel):
|
||||||
"""
|
"""
|
||||||
A list of ingredient references.
|
A list of ingredient references.
|
||||||
"""
|
"""
|
||||||
@ -16,7 +17,7 @@ class IngredientReferences(CamelModel):
|
|||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class RecipeStep(CamelModel):
|
class RecipeStep(MealieModel):
|
||||||
id: Optional[UUID] = Field(default_factory=uuid4)
|
id: Optional[UUID] = Field(default_factory=uuid4)
|
||||||
title: Optional[str] = ""
|
title: Optional[str] = ""
|
||||||
text: str
|
text: str
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import typing
|
import typing
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4
|
from pydantic import UUID4
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
class RecipeToolCreate(CamelModel):
|
|
||||||
|
class RecipeToolCreate(MealieModel):
|
||||||
name: str
|
name: str
|
||||||
on_hand: bool = False
|
on_hand: bool = False
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
# TODO: Should these exist?!?!?!?!?
|
# TODO: Should these exist?!?!?!?!?
|
||||||
|
|
||||||
|
|
||||||
class RecipeSlug(CamelModel):
|
class RecipeSlug(MealieModel):
|
||||||
slug: str
|
slug: str
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import enum
|
import enum
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
from pydantic.types import UUID4
|
from pydantic.types import UUID4
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
|
|
||||||
class ReportCategory(str, enum.Enum):
|
class ReportCategory(str, enum.Enum):
|
||||||
backup = "backup"
|
backup = "backup"
|
||||||
@ -19,7 +20,7 @@ class ReportSummaryStatus(str, enum.Enum):
|
|||||||
partial = "partial"
|
partial = "partial"
|
||||||
|
|
||||||
|
|
||||||
class ReportEntryCreate(CamelModel):
|
class ReportEntryCreate(MealieModel):
|
||||||
report_id: UUID4
|
report_id: UUID4
|
||||||
timestamp: datetime.datetime = Field(default_factory=datetime.datetime.utcnow)
|
timestamp: datetime.datetime = Field(default_factory=datetime.datetime.utcnow)
|
||||||
success: bool = True
|
success: bool = True
|
||||||
@ -34,7 +35,7 @@ class ReportEntryOut(ReportEntryCreate):
|
|||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class ReportCreate(CamelModel):
|
class ReportCreate(MealieModel):
|
||||||
timestamp: datetime.datetime = Field(default_factory=datetime.datetime.utcnow)
|
timestamp: datetime.datetime = Field(default_factory=datetime.datetime.utcnow)
|
||||||
category: ReportCategory
|
category: ReportCategory
|
||||||
group_id: UUID4
|
group_id: UUID4
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
|
|
||||||
class ErrorResponse(BaseModel):
|
class ErrorResponse(BaseModel):
|
||||||
message: str
|
message: str
|
||||||
@ -31,7 +32,7 @@ class SuccessResponse(BaseModel):
|
|||||||
return cls(message=message).dict()
|
return cls(message=message).dict()
|
||||||
|
|
||||||
|
|
||||||
class FileTokenResponse(CamelModel):
|
class FileTokenResponse(MealieModel):
|
||||||
file_token: str
|
file_token: str
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -2,9 +2,10 @@ import datetime
|
|||||||
import enum
|
import enum
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
|
|
||||||
class ServerTaskNames(str, enum.Enum):
|
class ServerTaskNames(str, enum.Enum):
|
||||||
default = "Background Task"
|
default = "Background Task"
|
||||||
@ -18,7 +19,7 @@ class ServerTaskStatus(str, enum.Enum):
|
|||||||
failed = "failed"
|
failed = "failed"
|
||||||
|
|
||||||
|
|
||||||
class ServerTaskCreate(CamelModel):
|
class ServerTaskCreate(MealieModel):
|
||||||
group_id: UUID
|
group_id: UUID
|
||||||
name: ServerTaskNames = ServerTaskNames.default
|
name: ServerTaskNames = ServerTaskNames.default
|
||||||
created_at: datetime.datetime = Field(default_factory=datetime.datetime.now)
|
created_at: datetime.datetime = Field(default_factory=datetime.datetime.now)
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import validator
|
from pydantic import validator
|
||||||
from pydantic.types import NoneStr, constr
|
from pydantic.types import NoneStr, constr
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
class CreateUserRegistration(CamelModel):
|
|
||||||
|
class CreateUserRegistration(MealieModel):
|
||||||
group: NoneStr = None
|
group: NoneStr = None
|
||||||
group_token: NoneStr = None
|
group_token: NoneStr = None
|
||||||
email: constr(to_lower=True, strip_whitespace=True) # type: ignore
|
email: constr(to_lower=True, strip_whitespace=True) # type: ignore
|
||||||
|
@ -3,13 +3,13 @@ from pathlib import Path
|
|||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4
|
from pydantic import UUID4
|
||||||
from pydantic.types import constr
|
from pydantic.types import constr
|
||||||
from pydantic.utils import GetterDict
|
from pydantic.utils import GetterDict
|
||||||
|
|
||||||
from mealie.core.config import get_app_dirs, get_app_settings
|
from mealie.core.config import get_app_dirs, get_app_settings
|
||||||
from mealie.db.models.users import User
|
from mealie.db.models.users import User
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
from mealie.schema.group.group_preferences import ReadGroupPreferences
|
from mealie.schema.group.group_preferences import ReadGroupPreferences
|
||||||
from mealie.schema.recipe import RecipeSummary
|
from mealie.schema.recipe import RecipeSummary
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ from ..recipe import CategoryBase
|
|||||||
settings = get_app_settings()
|
settings = get_app_settings()
|
||||||
|
|
||||||
|
|
||||||
class LoingLiveTokenIn(CamelModel):
|
class LoingLiveTokenIn(MealieModel):
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
|
|
||||||
@ -38,19 +38,19 @@ class CreateToken(LoingLiveTokenIn):
|
|||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class ChangePassword(CamelModel):
|
class ChangePassword(MealieModel):
|
||||||
current_password: str
|
current_password: str
|
||||||
new_password: str
|
new_password: str
|
||||||
|
|
||||||
|
|
||||||
class GroupBase(CamelModel):
|
class GroupBase(MealieModel):
|
||||||
name: str
|
name: str
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
|
||||||
class UserBase(CamelModel):
|
class UserBase(MealieModel):
|
||||||
username: Optional[str]
|
username: Optional[str]
|
||||||
full_name: Optional[str] = None
|
full_name: Optional[str] = None
|
||||||
email: constr(to_lower=True, strip_whitespace=True) # type: ignore
|
email: constr(to_lower=True, strip_whitespace=True) # type: ignore
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
from fastapi_camelcase import CamelModel
|
|
||||||
from pydantic import UUID4
|
from pydantic import UUID4
|
||||||
|
|
||||||
|
from mealie.schema._mealie import MealieModel
|
||||||
|
|
||||||
from .user import PrivateUser
|
from .user import PrivateUser
|
||||||
|
|
||||||
|
|
||||||
class ForgotPassword(CamelModel):
|
class ForgotPassword(MealieModel):
|
||||||
email: str
|
email: str
|
||||||
|
|
||||||
|
|
||||||
class ValidateResetToken(CamelModel):
|
class ValidateResetToken(MealieModel):
|
||||||
token: str
|
token: str
|
||||||
|
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ class ResetPassword(ValidateResetToken):
|
|||||||
passwordConfirm: str
|
passwordConfirm: str
|
||||||
|
|
||||||
|
|
||||||
class SavePasswordResetToken(CamelModel):
|
class SavePasswordResetToken(MealieModel):
|
||||||
user_id: UUID4
|
user_id: UUID4
|
||||||
token: str
|
token: str
|
||||||
|
|
||||||
|
@ -1,143 +0,0 @@
|
|||||||
import json
|
|
||||||
import shutil
|
|
||||||
from datetime import datetime
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
from jinja2 import Template
|
|
||||||
from pathvalidate import sanitize_filename
|
|
||||||
from pydantic.main import BaseModel
|
|
||||||
|
|
||||||
from mealie.core import root_logger
|
|
||||||
from mealie.core.config import get_app_dirs
|
|
||||||
|
|
||||||
app_dirs = get_app_dirs()
|
|
||||||
from mealie.repos.all_repositories import get_repositories
|
|
||||||
|
|
||||||
logger = root_logger.get_logger()
|
|
||||||
|
|
||||||
|
|
||||||
class ExportDatabase:
|
|
||||||
def __init__(self, tag=None, templates=None) -> None:
|
|
||||||
"""Export a Mealie database. Export interacts directly with class objects and can be used
|
|
||||||
with any supported backend database platform. By default tags are timestamps, and no
|
|
||||||
Jinja2 templates are rendered
|
|
||||||
|
|
||||||
Args:
|
|
||||||
tag ([str], optional): A str to be used as a file tag. Defaults to None.
|
|
||||||
templates (list, optional): A list of template file names. Defaults to None.
|
|
||||||
"""
|
|
||||||
if tag:
|
|
||||||
export_tag = tag + "_" + datetime.now().strftime("%Y-%b-%d")
|
|
||||||
else:
|
|
||||||
export_tag = datetime.now().strftime("%Y-%b-%d")
|
|
||||||
|
|
||||||
self.main_dir = app_dirs.TEMP_DIR.joinpath(export_tag)
|
|
||||||
self.recipes = self.main_dir.joinpath("recipes")
|
|
||||||
self.templates_dir = self.main_dir.joinpath("templates")
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.templates = [app_dirs.TEMPLATE_DIR.joinpath(x) for x in templates]
|
|
||||||
except Exception:
|
|
||||||
self.templates = []
|
|
||||||
logger.info("No Jinja2 Templates Registered for Export")
|
|
||||||
|
|
||||||
required_dirs = [
|
|
||||||
self.main_dir,
|
|
||||||
self.recipes,
|
|
||||||
self.templates_dir,
|
|
||||||
]
|
|
||||||
|
|
||||||
for dir in required_dirs:
|
|
||||||
dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
def export_templates(self, recipe_list: list[BaseModel]):
|
|
||||||
if self.templates:
|
|
||||||
for template_path in self.templates:
|
|
||||||
out_dir = self.templates_dir.joinpath(template_path.name)
|
|
||||||
out_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
with open(template_path, "r") as f:
|
|
||||||
template = Template(f.read())
|
|
||||||
|
|
||||||
for recipe in recipe_list:
|
|
||||||
filename = recipe.slug + template_path.suffix
|
|
||||||
out_file = out_dir.joinpath(filename)
|
|
||||||
|
|
||||||
content = template.render(recipe=recipe)
|
|
||||||
|
|
||||||
with open(out_file, "w") as f:
|
|
||||||
f.write(content)
|
|
||||||
|
|
||||||
def export_recipe_dirs(self):
|
|
||||||
shutil.copytree(app_dirs.RECIPE_DATA_DIR, self.recipes, dirs_exist_ok=True)
|
|
||||||
|
|
||||||
def export_items(self, items: list[BaseModel], folder_name: str, export_list=True, slug_folder=False):
|
|
||||||
items = [x.dict() for x in items]
|
|
||||||
out_dir = self.main_dir.joinpath(folder_name)
|
|
||||||
out_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
if export_list:
|
|
||||||
ExportDatabase._write_json_file(items, out_dir.joinpath(f"{folder_name}.json"))
|
|
||||||
else:
|
|
||||||
for item in items:
|
|
||||||
final_dest = out_dir if not slug_folder else out_dir.joinpath(item.get("slug"))
|
|
||||||
final_dest.mkdir(exist_ok=True)
|
|
||||||
filename = sanitize_filename(f"{item.get('slug')}.json")
|
|
||||||
ExportDatabase._write_json_file(item, final_dest.joinpath(filename))
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _write_json_file(data: Union[dict, list], out_file: Path):
|
|
||||||
json_data = json.dumps(data, indent=4, default=str)
|
|
||||||
|
|
||||||
with open(out_file, "w") as f:
|
|
||||||
f.write(json_data)
|
|
||||||
|
|
||||||
def finish_export(self):
|
|
||||||
zip_path = app_dirs.BACKUP_DIR.joinpath(f"{self.main_dir.name}")
|
|
||||||
shutil.make_archive(zip_path, "zip", self.main_dir)
|
|
||||||
|
|
||||||
shutil.rmtree(app_dirs.TEMP_DIR, ignore_errors=True)
|
|
||||||
return str(zip_path.absolute()) + ".zip"
|
|
||||||
|
|
||||||
|
|
||||||
def backup_all(
|
|
||||||
session,
|
|
||||||
tag=None,
|
|
||||||
templates=None,
|
|
||||||
export_recipes=True,
|
|
||||||
export_settings=False,
|
|
||||||
export_users=True,
|
|
||||||
export_groups=True,
|
|
||||||
export_notifications=True,
|
|
||||||
):
|
|
||||||
db_export = ExportDatabase(tag=tag, templates=templates)
|
|
||||||
|
|
||||||
db = get_repositories(session)
|
|
||||||
|
|
||||||
if export_users:
|
|
||||||
all_users = db.users.get_all()
|
|
||||||
db_export.export_items(all_users, "users")
|
|
||||||
|
|
||||||
if export_groups:
|
|
||||||
all_groups = db.groups.get_all()
|
|
||||||
db_export.export_items(all_groups, "groups")
|
|
||||||
|
|
||||||
if export_recipes:
|
|
||||||
all_recipes = db.recipes.get_all()
|
|
||||||
db_export.export_recipe_dirs()
|
|
||||||
db_export.export_items(all_recipes, "recipes", export_list=False, slug_folder=True)
|
|
||||||
db_export.export_templates(all_recipes)
|
|
||||||
|
|
||||||
all_comments = db.comments.get_all()
|
|
||||||
db_export.export_items(all_comments, "comments")
|
|
||||||
|
|
||||||
if export_settings:
|
|
||||||
all_settings = db.settings.get_all()
|
|
||||||
db_export.export_items(all_settings, "settings")
|
|
||||||
|
|
||||||
if export_notifications:
|
|
||||||
all_notifications = db.event_notifications.get_all()
|
|
||||||
db_export.export_items(all_notifications, "notifications")
|
|
||||||
|
|
||||||
return db_export.finish_export()
|
|
@ -1,307 +0,0 @@
|
|||||||
import json
|
|
||||||
import shutil
|
|
||||||
import zipfile
|
|
||||||
from collections.abc import Callable
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from pydantic.main import BaseModel
|
|
||||||
from sqlalchemy.orm.session import Session
|
|
||||||
|
|
||||||
from mealie.core.config import get_app_dirs
|
|
||||||
from mealie.repos.all_repositories import get_repositories
|
|
||||||
from mealie.schema.admin import CommentImport, GroupImport, RecipeImport, UserImport
|
|
||||||
from mealie.schema.recipe import Recipe, RecipeCommentOut
|
|
||||||
from mealie.schema.user import PrivateUser, UpdateGroup
|
|
||||||
|
|
||||||
app_dirs = get_app_dirs()
|
|
||||||
|
|
||||||
|
|
||||||
class ImportDatabase:
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
user: PrivateUser,
|
|
||||||
session: Session,
|
|
||||||
zip_archive: str,
|
|
||||||
force_import: bool = False,
|
|
||||||
) -> None:
|
|
||||||
"""Import a database.zip file exported from mealie.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
session (Session): SqlAlchemy Session
|
|
||||||
zip_archive (str): The filename contained in the backups directory
|
|
||||||
force_import (bool, optional): Force import will update all existing recipes. If False existing recipes are skipped. Defaults to False.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
Exception: If the zip file does not exists an exception raise.
|
|
||||||
"""
|
|
||||||
self.user = user
|
|
||||||
self.session = session
|
|
||||||
self.db = get_repositories(session)
|
|
||||||
self.archive = app_dirs.BACKUP_DIR.joinpath(zip_archive)
|
|
||||||
self.force_imports = force_import
|
|
||||||
|
|
||||||
if self.archive.is_file():
|
|
||||||
self.import_dir = app_dirs.TEMP_DIR.joinpath("active_import")
|
|
||||||
self.import_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
with zipfile.ZipFile(self.archive, "r") as zip_ref:
|
|
||||||
zip_ref.extractall(self.import_dir)
|
|
||||||
else:
|
|
||||||
raise Exception("Import file does not exist")
|
|
||||||
|
|
||||||
def import_recipes(self):
|
|
||||||
recipe_dir: Path = self.import_dir.joinpath("recipes")
|
|
||||||
imports = []
|
|
||||||
successful_imports = {}
|
|
||||||
|
|
||||||
recipes = ImportDatabase.read_models_file(
|
|
||||||
file_path=recipe_dir,
|
|
||||||
model=Recipe,
|
|
||||||
single_file=False,
|
|
||||||
migrate=ImportDatabase._recipe_migration,
|
|
||||||
)
|
|
||||||
|
|
||||||
for recipe in recipes:
|
|
||||||
recipe: Recipe
|
|
||||||
|
|
||||||
recipe.group_id = self.user.group_id
|
|
||||||
recipe.user_id = self.user.id
|
|
||||||
|
|
||||||
import_status = self.import_model(
|
|
||||||
db_table=self.db.recipes,
|
|
||||||
model=recipe,
|
|
||||||
return_model=RecipeImport,
|
|
||||||
name_attr="name",
|
|
||||||
search_key="slug",
|
|
||||||
slug=recipe.slug,
|
|
||||||
)
|
|
||||||
|
|
||||||
if import_status.status:
|
|
||||||
successful_imports[recipe.slug] = recipe
|
|
||||||
|
|
||||||
imports.append(import_status)
|
|
||||||
|
|
||||||
self._import_images(successful_imports)
|
|
||||||
|
|
||||||
return imports
|
|
||||||
|
|
||||||
def import_comments(self):
|
|
||||||
comment_dir: Path = self.import_dir.joinpath("comments", "comments.json")
|
|
||||||
|
|
||||||
if not comment_dir.exists():
|
|
||||||
return
|
|
||||||
|
|
||||||
comments = ImportDatabase.read_models_file(file_path=comment_dir, model=RecipeCommentOut)
|
|
||||||
|
|
||||||
for comment in comments:
|
|
||||||
comment: RecipeCommentOut
|
|
||||||
|
|
||||||
self.import_model(
|
|
||||||
db_table=self.db.comments,
|
|
||||||
model=comment,
|
|
||||||
return_model=CommentImport,
|
|
||||||
name_attr="uuid",
|
|
||||||
search_key="uuid",
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _recipe_migration(recipe_dict: dict) -> dict:
|
|
||||||
if recipe_dict.get("categories", False):
|
|
||||||
recipe_dict["recipeCategory"] = recipe_dict.get("categories")
|
|
||||||
del recipe_dict["categories"]
|
|
||||||
try:
|
|
||||||
del recipe_dict["_id"]
|
|
||||||
del recipe_dict["date_added"]
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
# Migration from list to Object Type Data
|
|
||||||
try:
|
|
||||||
if "" in recipe_dict["tags"]:
|
|
||||||
recipe_dict["tags"] = [tag for tag in recipe_dict["tags"] if tag != ""]
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
if "" in recipe_dict["categories"]:
|
|
||||||
recipe_dict["categories"] = [cat for cat in recipe_dict["categories"] if cat != ""]
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if type(recipe_dict["extras"]) == list:
|
|
||||||
recipe_dict["extras"] = {}
|
|
||||||
|
|
||||||
recipe_dict["comments"] = []
|
|
||||||
|
|
||||||
return recipe_dict
|
|
||||||
|
|
||||||
def _import_images(self, successful_imports: list[Recipe]):
|
|
||||||
image_dir = self.import_dir.joinpath("images")
|
|
||||||
|
|
||||||
if image_dir.exists(): # Migrate from before v0.5.0
|
|
||||||
for image in image_dir.iterdir():
|
|
||||||
item: Recipe = successful_imports.get(image.stem) # type: ignore
|
|
||||||
|
|
||||||
if item:
|
|
||||||
dest_dir = item.image_dir
|
|
||||||
|
|
||||||
if image.is_dir():
|
|
||||||
shutil.copytree(image, dest_dir, dirs_exist_ok=True)
|
|
||||||
|
|
||||||
if image.is_file():
|
|
||||||
shutil.copy(image, dest_dir)
|
|
||||||
|
|
||||||
else:
|
|
||||||
recipe_dir = self.import_dir.joinpath("recipes")
|
|
||||||
shutil.copytree(recipe_dir, app_dirs.RECIPE_DATA_DIR, dirs_exist_ok=True)
|
|
||||||
|
|
||||||
def import_settings(self):
|
|
||||||
return []
|
|
||||||
|
|
||||||
def import_groups(self):
|
|
||||||
groups_file = self.import_dir.joinpath("groups", "groups.json")
|
|
||||||
groups = ImportDatabase.read_models_file(groups_file, UpdateGroup)
|
|
||||||
group_imports = []
|
|
||||||
|
|
||||||
for group in groups:
|
|
||||||
import_status = self.import_model(self.db.groups, group, GroupImport, search_key="name")
|
|
||||||
group_imports.append(import_status)
|
|
||||||
|
|
||||||
return group_imports
|
|
||||||
|
|
||||||
def import_users(self):
|
|
||||||
users_file = self.import_dir.joinpath("users", "users.json")
|
|
||||||
users = ImportDatabase.read_models_file(users_file, PrivateUser)
|
|
||||||
user_imports = []
|
|
||||||
for user in users:
|
|
||||||
if user.id == 1: # Update Default User
|
|
||||||
self.db.users.update(1, user.dict())
|
|
||||||
import_status = UserImport(name=user.full_name, status=True)
|
|
||||||
user_imports.append(import_status)
|
|
||||||
continue
|
|
||||||
|
|
||||||
import_status = self.import_model(
|
|
||||||
db_table=self.db.users,
|
|
||||||
model=user,
|
|
||||||
return_model=UserImport,
|
|
||||||
name_attr="full_name",
|
|
||||||
search_key="email",
|
|
||||||
)
|
|
||||||
|
|
||||||
user_imports.append(import_status)
|
|
||||||
|
|
||||||
return user_imports
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def read_models_file(file_path: Path, model: BaseModel, single_file=True, migrate: Callable = None):
|
|
||||||
"""A general purpose function that is used to process a backup `.json` file created by mealie
|
|
||||||
note that if the file doesn't not exists the function will return any empty list
|
|
||||||
|
|
||||||
Args:
|
|
||||||
file_path (Path): The path to the .json file or directory
|
|
||||||
model (BaseModel): The pydantic model that will be created from the .json file entries
|
|
||||||
single_file (bool, optional): If true, the json data will be treated as list, if false it will use glob style matches and treat each file as its own entry. Defaults to True.
|
|
||||||
migrate (Callable, optional): A migrate function that will be called on the data prior to creating a model. Defaults to None.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
[type]: [description]
|
|
||||||
"""
|
|
||||||
if not file_path.exists():
|
|
||||||
return []
|
|
||||||
|
|
||||||
if single_file:
|
|
||||||
with open(file_path, "r") as f:
|
|
||||||
file_data = json.loads(f.read())
|
|
||||||
|
|
||||||
if migrate:
|
|
||||||
file_data = [migrate(x) for x in file_data]
|
|
||||||
|
|
||||||
return [model(**g) for g in file_data]
|
|
||||||
|
|
||||||
all_models = []
|
|
||||||
for file in file_path.glob("**/*.json"):
|
|
||||||
with open(file, "r") as f:
|
|
||||||
file_data = json.loads(f.read())
|
|
||||||
|
|
||||||
if migrate:
|
|
||||||
file_data = migrate(file_data)
|
|
||||||
|
|
||||||
all_models.append(model(**file_data))
|
|
||||||
|
|
||||||
return all_models
|
|
||||||
|
|
||||||
def import_model(self, db_table, model, return_model, name_attr="name", search_key="id", **kwargs):
|
|
||||||
"""A general purpose function used to insert a list of pydantic modelsi into the database.
|
|
||||||
The assumption at this point is that the models that are inserted. If self.force_imports is true
|
|
||||||
any existing entries will be removed prior to creation
|
|
||||||
|
|
||||||
Args:
|
|
||||||
db_table ([type]): A database table like `db.users`
|
|
||||||
model ([type]): The Pydantic model that matches the database
|
|
||||||
return_model ([type]): The return model that will be used for the 'report'
|
|
||||||
name_attr (str, optional): The name property on the return model. Defaults to "name".
|
|
||||||
search_key (str, optional): The key used to identify if an the entry already exists. Defaults to "id"
|
|
||||||
**kwargs (): Any kwargs passed will be used to set attributes on the `return_model`
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
[type]: Returns the `return_model` specified.
|
|
||||||
"""
|
|
||||||
model_name = getattr(model, name_attr)
|
|
||||||
search_value = getattr(model, search_key)
|
|
||||||
|
|
||||||
item = db_table.get(search_value, search_key)
|
|
||||||
if item:
|
|
||||||
if not self.force_imports:
|
|
||||||
return return_model(
|
|
||||||
name=model_name,
|
|
||||||
status=False,
|
|
||||||
exception=f"Table entry with matching '{search_key}': '{search_value}' exists",
|
|
||||||
)
|
|
||||||
|
|
||||||
primary_key = getattr(item, db_table.primary_key)
|
|
||||||
db_table.delete(primary_key)
|
|
||||||
try:
|
|
||||||
db_table.create(model.dict())
|
|
||||||
import_status = return_model(name=model_name, status=True)
|
|
||||||
|
|
||||||
except Exception as inst:
|
|
||||||
self.session.rollback()
|
|
||||||
import_status = return_model(name=model_name, status=False, exception=str(inst))
|
|
||||||
|
|
||||||
for key, value in kwargs.items():
|
|
||||||
setattr(return_model, key, value)
|
|
||||||
|
|
||||||
return import_status
|
|
||||||
|
|
||||||
def clean_up(self):
|
|
||||||
shutil.rmtree(app_dirs.TEMP_DIR)
|
|
||||||
|
|
||||||
|
|
||||||
def import_database(
|
|
||||||
session: Session,
|
|
||||||
user: PrivateUser,
|
|
||||||
archive,
|
|
||||||
import_recipes=True,
|
|
||||||
import_settings=True,
|
|
||||||
import_users=True,
|
|
||||||
import_groups=True,
|
|
||||||
force_import: bool = False,
|
|
||||||
**_,
|
|
||||||
):
|
|
||||||
import_session = ImportDatabase(user, session, archive, force_import)
|
|
||||||
|
|
||||||
recipe_report = import_session.import_recipes() if import_recipes else []
|
|
||||||
settings_report = import_session.import_settings() if import_settings else []
|
|
||||||
group_report = import_session.import_groups() if import_groups else []
|
|
||||||
user_report = import_session.import_users() if import_users else []
|
|
||||||
notification_report: list = []
|
|
||||||
|
|
||||||
import_session.clean_up()
|
|
||||||
|
|
||||||
return {
|
|
||||||
"recipeImports": recipe_report,
|
|
||||||
"settingsImports": settings_report,
|
|
||||||
"groupImports": group_report,
|
|
||||||
"userImports": user_report,
|
|
||||||
"notificationImports": notification_report,
|
|
||||||
}
|
|
@ -1,4 +1,3 @@
|
|||||||
from .auto_backup import *
|
|
||||||
from .purge_group_exports import *
|
from .purge_group_exports import *
|
||||||
from .purge_password_reset import *
|
from .purge_password_reset import *
|
||||||
from .purge_registration import *
|
from .purge_registration import *
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
from mealie.core import root_logger
|
|
||||||
from mealie.core.config import get_app_dirs
|
|
||||||
|
|
||||||
app_dirs = get_app_dirs()
|
|
||||||
from mealie.db.db_setup import create_session
|
|
||||||
from mealie.services.backups.exports import backup_all
|
|
||||||
|
|
||||||
logger = root_logger.get_logger()
|
|
||||||
|
|
||||||
|
|
||||||
def auto_backup():
|
|
||||||
for backup in app_dirs.BACKUP_DIR.glob("Auto*.zip"):
|
|
||||||
backup.unlink()
|
|
||||||
|
|
||||||
templates = [template for template in app_dirs.TEMPLATE_DIR.iterdir()]
|
|
||||||
session = create_session()
|
|
||||||
backup_all(session=session, tag="Auto", templates=templates)
|
|
||||||
logger.info("generating automated backup")
|
|
||||||
session.close()
|
|
||||||
logger.info("automated backup generated")
|
|
38
poetry.lock
generated
38
poetry.lock
generated
@ -390,18 +390,6 @@ dev = ["python-jose[cryptography] (>=3.3.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<
|
|||||||
doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"]
|
doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"]
|
||||||
test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==21.9b0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "flask (>=1.1.2,<3.0.0)", "anyio[trio] (>=3.2.1,<4.0.0)", "types-ujson (==0.1.1)", "types-orjson (==3.6.0)", "types-dataclasses (==0.1.7)"]
|
test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==21.9b0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "flask (>=1.1.2,<3.0.0)", "anyio[trio] (>=3.2.1,<4.0.0)", "types-ujson (==0.1.1)", "types-orjson (==3.6.0)", "types-dataclasses (==0.1.7)"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fastapi-camelcase"
|
|
||||||
version = "1.0.5"
|
|
||||||
description = "Package provides an easy way to have camelcase request/response bodies for Pydantic"
|
|
||||||
category = "main"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
pydantic = "*"
|
|
||||||
pyhumps = "*"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "filelock"
|
name = "filelock"
|
||||||
version = "3.6.0"
|
version = "3.6.0"
|
||||||
@ -829,17 +817,6 @@ category = "dev"
|
|||||||
optional = false
|
optional = false
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pathvalidate"
|
|
||||||
version = "2.5.0"
|
|
||||||
description = "pathvalidate is a Python library to sanitize/validate a string such as filenames/file-paths/etc."
|
|
||||||
category = "main"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
test = ["allpairspy", "click", "faker", "pytest (>=6.0.1)", "pytest-discord (>=0.0.6)", "pytest-md-report (>=0.0.12)"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pillow"
|
name = "pillow"
|
||||||
version = "8.4.0"
|
version = "8.4.0"
|
||||||
@ -1003,7 +980,7 @@ python-versions = ">=3.5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyhumps"
|
name = "pyhumps"
|
||||||
version = "3.5.0"
|
version = "3.5.3"
|
||||||
description = "🐫 Convert strings (and dictionary keys) between snake case, camel case and pascal case in Python. Inspired by Humps for Node"
|
description = "🐫 Convert strings (and dictionary keys) between snake case, camel case and pascal case in Python. Inspired by Humps for Node"
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
@ -1622,7 +1599,7 @@ pgsql = ["psycopg2-binary"]
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.10"
|
python-versions = "^3.10"
|
||||||
content-hash = "4fba071019a62f5d75e7c9a297a7815b2fed6486bb3616b5029a6fb08001761f"
|
content-hash = "84c1d9352c058da5cc0f50ca195cbe0897ce64abfbe01d08b9da317b6dd70a70"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
aiofiles = [
|
aiofiles = [
|
||||||
@ -1852,9 +1829,6 @@ fastapi = [
|
|||||||
{file = "fastapi-0.74.1-py3-none-any.whl", hash = "sha256:b8ec8400623ef0b2ff558ebe06753b349f8e3a5dd38afea650800f2644ddba34"},
|
{file = "fastapi-0.74.1-py3-none-any.whl", hash = "sha256:b8ec8400623ef0b2ff558ebe06753b349f8e3a5dd38afea650800f2644ddba34"},
|
||||||
{file = "fastapi-0.74.1.tar.gz", hash = "sha256:b58a2c46df14f62ebe6f24a9439927539ba1959b9be55ba0e2f516a683e5b9d4"},
|
{file = "fastapi-0.74.1.tar.gz", hash = "sha256:b58a2c46df14f62ebe6f24a9439927539ba1959b9be55ba0e2f516a683e5b9d4"},
|
||||||
]
|
]
|
||||||
fastapi-camelcase = [
|
|
||||||
{file = "fastapi_camelcase-1.0.5.tar.gz", hash = "sha256:2cee005fb1b75649491b9f7cfccc640b12f028eb88084565f7d8cf415192026a"},
|
|
||||||
]
|
|
||||||
filelock = [
|
filelock = [
|
||||||
{file = "filelock-3.6.0-py3-none-any.whl", hash = "sha256:f8314284bfffbdcfa0ff3d7992b023d4c628ced6feb957351d4c48d059f56bc0"},
|
{file = "filelock-3.6.0-py3-none-any.whl", hash = "sha256:f8314284bfffbdcfa0ff3d7992b023d4c628ced6feb957351d4c48d059f56bc0"},
|
||||||
{file = "filelock-3.6.0.tar.gz", hash = "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85"},
|
{file = "filelock-3.6.0.tar.gz", hash = "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85"},
|
||||||
@ -2239,10 +2213,6 @@ pathspec = [
|
|||||||
{file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
|
{file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
|
||||||
{file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
|
{file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
|
||||||
]
|
]
|
||||||
pathvalidate = [
|
|
||||||
{file = "pathvalidate-2.5.0-py3-none-any.whl", hash = "sha256:e5b2747ad557363e8f4124f0553d68878b12ecabd77bcca7e7312d5346d20262"},
|
|
||||||
{file = "pathvalidate-2.5.0.tar.gz", hash = "sha256:119ba36be7e9a405d704c7b7aea4b871c757c53c9adc0ed64f40be1ed8da2781"},
|
|
||||||
]
|
|
||||||
pillow = [
|
pillow = [
|
||||||
{file = "Pillow-8.4.0-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:81f8d5c81e483a9442d72d182e1fb6dcb9723f289a57e8030811bac9ea3fef8d"},
|
{file = "Pillow-8.4.0-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:81f8d5c81e483a9442d72d182e1fb6dcb9723f289a57e8030811bac9ea3fef8d"},
|
||||||
{file = "Pillow-8.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f97cfb1e5a392d75dd8b9fd274d205404729923840ca94ca45a0af57e13dbe6"},
|
{file = "Pillow-8.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f97cfb1e5a392d75dd8b9fd274d205404729923840ca94ca45a0af57e13dbe6"},
|
||||||
@ -2453,8 +2423,8 @@ pygments = [
|
|||||||
{file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"},
|
{file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"},
|
||||||
]
|
]
|
||||||
pyhumps = [
|
pyhumps = [
|
||||||
{file = "pyhumps-3.5.0-py3-none-any.whl", hash = "sha256:2433eef13d1c258227a0bd5de9660ba17dd6a307e1255d2d20ec9287f8626d96"},
|
{file = "pyhumps-3.5.3-py3-none-any.whl", hash = "sha256:8d7e9865d6ddb6e64a2e97d951b78b5cc827d3d66cda1297310fc83b2ddf51dc"},
|
||||||
{file = "pyhumps-3.5.0.tar.gz", hash = "sha256:55e37f16846eaab26057200924cbdadd2152bf0a5d49175a42358464fa881c73"},
|
{file = "pyhumps-3.5.3.tar.gz", hash = "sha256:0ecf7fee84503b45afdd3841ec769b529d32dfaed855e07046ff8babcc0ab831"},
|
||||||
]
|
]
|
||||||
pylint = [
|
pylint = [
|
||||||
{file = "pylint-2.12.2-py3-none-any.whl", hash = "sha256:daabda3f7ed9d1c60f52d563b1b854632fd90035bcf01443e234d3dc794e3b74"},
|
{file = "pylint-2.12.2-py3-none-any.whl", hash = "sha256:daabda3f7ed9d1c60f52d563b1b854632fd90035bcf01443e234d3dc794e3b74"},
|
||||||
|
@ -25,13 +25,11 @@ requests = "^2.25.1"
|
|||||||
PyYAML = "^5.3.1"
|
PyYAML = "^5.3.1"
|
||||||
extruct = "^0.13.0"
|
extruct = "^0.13.0"
|
||||||
python-multipart = "^0.0.5"
|
python-multipart = "^0.0.5"
|
||||||
fastapi-camelcase = "^1.0.5"
|
|
||||||
bcrypt = "^3.2.0"
|
bcrypt = "^3.2.0"
|
||||||
python-jose = "^3.3.0"
|
python-jose = "^3.3.0"
|
||||||
passlib = "^1.7.4"
|
passlib = "^1.7.4"
|
||||||
lxml = "^4.7.1"
|
lxml = "^4.7.1"
|
||||||
Pillow = "^8.2.0"
|
Pillow = "^8.2.0"
|
||||||
pathvalidate = "^2.4.1"
|
|
||||||
apprise = "^0.9.6"
|
apprise = "^0.9.6"
|
||||||
recipe-scrapers = "^13.18.1"
|
recipe-scrapers = "^13.18.1"
|
||||||
psycopg2-binary = {version = "^2.9.1", optional = true}
|
psycopg2-binary = {version = "^2.9.1", optional = true}
|
||||||
@ -41,6 +39,7 @@ python-i18n = "^0.3.9"
|
|||||||
python-ldap = "^3.3.1"
|
python-ldap = "^3.3.1"
|
||||||
pydantic = "^1.9.0"
|
pydantic = "^1.9.0"
|
||||||
tzdata = "^2021.5"
|
tzdata = "^2021.5"
|
||||||
|
pyhumps = "^3.5.3"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
pylint = "^2.6.0"
|
pylint = "^2.6.0"
|
||||||
|
63
tests/unit_tests/schema_tests/test_mealie_model.py
Normal file
63
tests/unit_tests/schema_tests/test_mealie_model.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
from mealie.schema._mealie.mealie_model import MealieModel
|
||||||
|
|
||||||
|
|
||||||
|
class TestModel(MealieModel):
|
||||||
|
long_name: str
|
||||||
|
long_int: int
|
||||||
|
long_float: float
|
||||||
|
|
||||||
|
|
||||||
|
class TestModel2(MealieModel):
|
||||||
|
long_name: str
|
||||||
|
long_int: int
|
||||||
|
long_float: float
|
||||||
|
another_str: str
|
||||||
|
|
||||||
|
|
||||||
|
def test_camelize_variables():
|
||||||
|
model = TestModel(long_name="Hello", long_int=1, long_float=1.1)
|
||||||
|
|
||||||
|
as_dict = model.dict(by_alias=True)
|
||||||
|
|
||||||
|
assert as_dict["longName"] == "Hello"
|
||||||
|
assert as_dict["longInt"] == 1
|
||||||
|
assert as_dict["longFloat"] == 1.1
|
||||||
|
|
||||||
|
|
||||||
|
def test_cast_to():
|
||||||
|
|
||||||
|
model = TestModel(long_name="Hello", long_int=1, long_float=1.1)
|
||||||
|
|
||||||
|
model2 = model.cast(TestModel2, another_str="World")
|
||||||
|
|
||||||
|
assert model2.long_name == "Hello"
|
||||||
|
assert model2.long_int == 1
|
||||||
|
assert model2.long_float == 1.1
|
||||||
|
assert model2.another_str == "World"
|
||||||
|
|
||||||
|
|
||||||
|
def test_map_to():
|
||||||
|
|
||||||
|
model = TestModel(long_name="Model1", long_int=100, long_float=1.5)
|
||||||
|
|
||||||
|
model2 = TestModel2(long_name="Model2", long_int=1, long_float=1.1, another_str="World")
|
||||||
|
|
||||||
|
model.map_to(model2)
|
||||||
|
|
||||||
|
assert model2.long_name == "Model1"
|
||||||
|
assert model2.long_int == 100
|
||||||
|
assert model2.long_float == 1.5
|
||||||
|
assert model2.another_str == "World"
|
||||||
|
|
||||||
|
|
||||||
|
def test_map_from():
|
||||||
|
model = TestModel(long_name="Model1", long_int=50, long_float=1.5)
|
||||||
|
|
||||||
|
model2 = TestModel2(long_name="Hello", long_int=1, long_float=1.1, another_str="World")
|
||||||
|
|
||||||
|
model2.map_from(model)
|
||||||
|
|
||||||
|
assert model2.long_name == "Model1"
|
||||||
|
assert model2.long_int == 50
|
||||||
|
assert model2.long_float == 1.5
|
||||||
|
assert model2.another_str == "World"
|
Loading…
x
Reference in New Issue
Block a user