mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 22:43:34 -07:00
theme + settings refactor
This commit is contained in:
parent
664b50c7f0
commit
866e7de498
19 changed files with 236 additions and 262 deletions
|
@ -12,7 +12,6 @@ from routes import (
|
||||||
setting_routes,
|
setting_routes,
|
||||||
static_routes,
|
static_routes,
|
||||||
theme_routes,
|
theme_routes,
|
||||||
user_routes,
|
|
||||||
)
|
)
|
||||||
from routes.recipe import (
|
from routes.recipe import (
|
||||||
all_recipe_routes,
|
all_recipe_routes,
|
||||||
|
@ -22,18 +21,6 @@ from routes.recipe import (
|
||||||
)
|
)
|
||||||
from utils.logger import logger
|
from utils.logger import logger
|
||||||
|
|
||||||
"""
|
|
||||||
TODO:
|
|
||||||
- [x] Fix Duplicate Category
|
|
||||||
- [x] Fix category overflow
|
|
||||||
- [ ] Enable Database Name Versioning
|
|
||||||
- [ ] Finish Frontend Category Management
|
|
||||||
- [x] Delete Category
|
|
||||||
- [ ] Sort Sidebar A-Z
|
|
||||||
- [ ] Refactor Test Endpoints - Abstract to fixture?
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
app = FastAPI(
|
app = FastAPI(
|
||||||
title="Mealie",
|
title="Mealie",
|
||||||
description="A place for all your recipes",
|
description="A place for all your recipes",
|
||||||
|
@ -51,6 +38,10 @@ def start_scheduler():
|
||||||
import services.scheduler.scheduled_jobs
|
import services.scheduler.scheduled_jobs
|
||||||
|
|
||||||
|
|
||||||
|
def init_settings():
|
||||||
|
import services.theme_services
|
||||||
|
|
||||||
|
|
||||||
def api_routers():
|
def api_routers():
|
||||||
# Recipes
|
# Recipes
|
||||||
app.include_router(all_recipe_routes.router)
|
app.include_router(all_recipe_routes.router)
|
||||||
|
@ -64,8 +55,6 @@ def api_routers():
|
||||||
app.include_router(theme_routes.router)
|
app.include_router(theme_routes.router)
|
||||||
# Backups/Imports Routes
|
# Backups/Imports Routes
|
||||||
app.include_router(backup_routes.router)
|
app.include_router(backup_routes.router)
|
||||||
# User Routes
|
|
||||||
app.include_router(user_routes.router)
|
|
||||||
# Migration Routes
|
# Migration Routes
|
||||||
app.include_router(migration_routes.router)
|
app.include_router(migration_routes.router)
|
||||||
app.include_router(debug_routes.router)
|
app.include_router(debug_routes.router)
|
||||||
|
@ -90,6 +79,7 @@ app.include_router(static_routes.router)
|
||||||
# generate_api_docs(app)
|
# generate_api_docs(app)
|
||||||
|
|
||||||
start_scheduler()
|
start_scheduler()
|
||||||
|
init_settings()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
logger.info("-----SYSTEM STARTUP-----")
|
logger.info("-----SYSTEM STARTUP-----")
|
||||||
|
|
|
@ -9,7 +9,6 @@ from db.sql.theme_models import SiteThemeModel
|
||||||
"""
|
"""
|
||||||
# TODO
|
# TODO
|
||||||
- [ ] Abstract Classes to use save_new, and update from base models
|
- [ ] Abstract Classes to use save_new, and update from base models
|
||||||
- [x] Create Category and Tags Table with Many to Many relationship
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,7 +48,7 @@ class _Settings(BaseDocument):
|
||||||
self.primary_key = "name"
|
self.primary_key = "name"
|
||||||
self.sql_model = SiteSettingsModel
|
self.sql_model = SiteSettingsModel
|
||||||
|
|
||||||
def save_new(self, session: Session, main: dict, webhooks: dict) -> str:
|
def create(self, session: Session, main: dict, webhooks: dict) -> str:
|
||||||
new_settings = self.sql_model(main.get("name"), webhooks)
|
new_settings = self.sql_model(main.get("name"), webhooks)
|
||||||
|
|
||||||
session.add(new_settings)
|
session.add(new_settings)
|
||||||
|
|
|
@ -106,7 +106,7 @@ class BaseDocument:
|
||||||
|
|
||||||
return db_entry
|
return db_entry
|
||||||
|
|
||||||
def save_new(self, session: Session, document: dict) -> dict:
|
def create(self, session: Session, document: dict) -> dict:
|
||||||
"""Creates a new database entry for the given SQL Alchemy Model.
|
"""Creates a new database entry for the given SQL Alchemy Model.
|
||||||
|
|
||||||
Args: \n
|
Args: \n
|
||||||
|
|
38
mealie/models/meal_models.py
Normal file
38
mealie/models/meal_models.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
from datetime import date
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class Meal(BaseModel):
|
||||||
|
slug: Optional[str]
|
||||||
|
name: Optional[str]
|
||||||
|
date: date
|
||||||
|
dateText: str
|
||||||
|
image: Optional[str]
|
||||||
|
description: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
|
class MealData(BaseModel):
|
||||||
|
name: Optional[str]
|
||||||
|
slug: str
|
||||||
|
dateText: str
|
||||||
|
|
||||||
|
|
||||||
|
class MealPlan(BaseModel):
|
||||||
|
uid: Optional[str]
|
||||||
|
startDate: date
|
||||||
|
endDate: date
|
||||||
|
meals: List[Meal]
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
schema_extra = {
|
||||||
|
"example": {
|
||||||
|
"startDate": date.today(),
|
||||||
|
"endDate": date.today(),
|
||||||
|
"meals": [
|
||||||
|
{"slug": "Packed Mac and Cheese", "date": date.today()},
|
||||||
|
{"slug": "Eggs and Toast", "date": date.today()},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,39 +1,80 @@
|
||||||
from typing import List, Optional
|
import datetime
|
||||||
from pydantic.main import BaseModel
|
from typing import Any, List, Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel, validator
|
||||||
|
from slugify import slugify
|
||||||
|
|
||||||
|
|
||||||
|
class RecipeNote(BaseModel):
|
||||||
|
title: str
|
||||||
|
text: str
|
||||||
|
|
||||||
|
|
||||||
|
class RecipeStep(BaseModel):
|
||||||
|
text: str
|
||||||
|
|
||||||
class AllRecipeResponse(BaseModel):
|
|
||||||
|
|
||||||
|
class Recipe(BaseModel):
|
||||||
|
# Standard Schema
|
||||||
|
name: str
|
||||||
|
description: Optional[str]
|
||||||
|
image: Optional[Any]
|
||||||
|
recipeYield: Optional[str]
|
||||||
|
recipeIngredient: Optional[list]
|
||||||
|
recipeInstructions: Optional[list]
|
||||||
|
|
||||||
|
totalTime: Optional[str] = None
|
||||||
|
prepTime: Optional[str] = None
|
||||||
|
performTime: Optional[str] = None
|
||||||
|
|
||||||
|
# Mealie Specific
|
||||||
|
slug: Optional[str] = ""
|
||||||
|
categories: Optional[List[str]] = []
|
||||||
|
tags: Optional[List[str]] = []
|
||||||
|
dateAdded: Optional[datetime.date]
|
||||||
|
notes: Optional[List[RecipeNote]] = []
|
||||||
|
rating: Optional[int]
|
||||||
|
orgURL: Optional[str]
|
||||||
|
extras: Optional[dict] = {}
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
schema_extra = {
|
schema_extra = {
|
||||||
"example": [
|
"example": {
|
||||||
{
|
"name": "Chicken and Rice With Leeks and Salsa Verde",
|
||||||
"slug": "crockpot-buffalo-chicken",
|
"description": "This one-skillet dinner gets deep oniony flavor from lots of leeks cooked down to jammy tenderness.",
|
||||||
"image": "crockpot-buffalo-chicken.jpg",
|
"image": "chicken-and-rice-with-leeks-and-salsa-verde.jpg",
|
||||||
"name": "Crockpot Buffalo Chicken",
|
"recipeYield": "4 Servings",
|
||||||
},
|
"recipeIngredient": [
|
||||||
{
|
"1 1/2 lb. skinless, boneless chicken thighs (4-8 depending on size)",
|
||||||
"slug": "downtown-marinade",
|
"Kosher salt, freshly ground pepper",
|
||||||
"image": "downtown-marinade.jpg",
|
"3 Tbsp. unsalted butter, divided",
|
||||||
"name": "Downtown Marinade",
|
],
|
||||||
},
|
"recipeInstructions": [
|
||||||
{
|
{
|
||||||
"slug": "detroit-style-pepperoni-pizza",
|
"text": "Season chicken with salt and pepper.",
|
||||||
"image": "detroit-style-pepperoni-pizza.jpg",
|
},
|
||||||
"name": "Detroit-Style Pepperoni Pizza",
|
],
|
||||||
},
|
"slug": "chicken-and-rice-with-leeks-and-salsa-verde",
|
||||||
{
|
"tags": ["favorite", "yummy!"],
|
||||||
"slug": "crispy-carrots",
|
"categories": ["Dinner", "Pasta"],
|
||||||
"image": "crispy-carrots.jpg",
|
"notes": [{"title": "Watch Out!", "text": "Prep the day before!"}],
|
||||||
"name": "Crispy Carrots",
|
"orgURL": "https://www.bonappetit.com/recipe/chicken-and-rice-with-leeks-and-salsa-verde",
|
||||||
},
|
"rating": 3,
|
||||||
]
|
"extras": {"message": "Don't forget to defrost the chicken!"},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@validator("slug", always=True, pre=True)
|
||||||
|
def validate_slug(slug: str, values):
|
||||||
|
name: str = values["name"]
|
||||||
|
calc_slug: str = slugify(name)
|
||||||
|
|
||||||
|
if slug == calc_slug:
|
||||||
|
return slug
|
||||||
|
else:
|
||||||
|
slug = calc_slug
|
||||||
|
return slug
|
||||||
|
|
||||||
|
|
||||||
class AllRecipeRequest(BaseModel):
|
class AllRecipeRequest(BaseModel):
|
||||||
properties: List[str]
|
properties: List[str]
|
||||||
|
|
26
mealie/models/settings_models.py
Normal file
26
mealie/models/settings_models.py
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class Webhooks(BaseModel):
|
||||||
|
webhookTime: str = "00:00"
|
||||||
|
webhookURLs: Optional[List[str]] = []
|
||||||
|
enabled: bool = False
|
||||||
|
|
||||||
|
|
||||||
|
class SiteSettings(BaseModel):
|
||||||
|
name: str = "main"
|
||||||
|
webhooks: Webhooks
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
schema_extra = {
|
||||||
|
"example": {
|
||||||
|
"name": "main",
|
||||||
|
"webhooks": {
|
||||||
|
"webhookTime": "00:00",
|
||||||
|
"webhookURLs": ["https://mywebhookurl.com/webhook"],
|
||||||
|
"enable": False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
31
mealie/models/theme_models.py
Normal file
31
mealie/models/theme_models.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
class Colors(BaseModel):
|
||||||
|
primary: str
|
||||||
|
accent: str
|
||||||
|
secondary: str
|
||||||
|
success: str
|
||||||
|
info: str
|
||||||
|
warning: str
|
||||||
|
error: str
|
||||||
|
|
||||||
|
|
||||||
|
class SiteTheme(BaseModel):
|
||||||
|
name: str
|
||||||
|
colors: Colors
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
schema_extra = {
|
||||||
|
"example": {
|
||||||
|
"name": "default",
|
||||||
|
"colors": {
|
||||||
|
"primary": "#E58325",
|
||||||
|
"accent": "#00457A",
|
||||||
|
"secondary": "#973542",
|
||||||
|
"success": "#5AB1BB",
|
||||||
|
"info": "#4990BA",
|
||||||
|
"warning": "#FF4081",
|
||||||
|
"error": "#EF5350",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +0,0 @@
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from pydantic import BaseModel
|
|
||||||
|
|
||||||
|
|
||||||
class User(BaseModel):
|
|
||||||
username: str
|
|
||||||
email: Optional[str] = None
|
|
||||||
full_name: Optional[str] = None
|
|
||||||
disabled: Optional[bool] = None
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
from db.database import db
|
||||||
from db.db_setup import generate_session
|
from db.db_setup import generate_session
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
from services.settings_services import SiteSettings
|
from models.settings_models import SiteSettings
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
from utils.post_webhooks import post_webhooks
|
from utils.post_webhooks import post_webhooks
|
||||||
from utils.snackbar import SnackResponse
|
from utils.snackbar import SnackResponse
|
||||||
|
@ -12,7 +13,7 @@ router = APIRouter(prefix="/api/site-settings", tags=["Settings"])
|
||||||
def get_main_settings(session: Session = Depends(generate_session)):
|
def get_main_settings(session: Session = Depends(generate_session)):
|
||||||
""" Returns basic site settings """
|
""" Returns basic site settings """
|
||||||
|
|
||||||
return SiteSettings.get_site_settings(session)
|
return db.settings.get(session, "main")
|
||||||
|
|
||||||
|
|
||||||
@router.post("/webhooks/test")
|
@router.post("/webhooks/test")
|
||||||
|
@ -25,6 +26,6 @@ def test_webhooks():
|
||||||
@router.put("")
|
@router.put("")
|
||||||
def update_settings(data: SiteSettings, session: Session = Depends(generate_session)):
|
def update_settings(data: SiteSettings, session: Session = Depends(generate_session)):
|
||||||
""" Returns Site Settings """
|
""" Returns Site Settings """
|
||||||
data.update(session)
|
db.settings.update(session, "main", data.dict())
|
||||||
|
|
||||||
return SnackResponse.success("Settings Updated")
|
return SnackResponse.success("Settings Updated")
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
from db.db_setup import generate_session
|
from db.db_setup import generate_session
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
from services.settings_services import SiteTheme
|
from models.theme_models import SiteTheme
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
from utils.snackbar import SnackResponse
|
from utils.snackbar import SnackResponse
|
||||||
|
from db.database import db
|
||||||
|
|
||||||
router = APIRouter(prefix="/api", tags=["Themes"])
|
router = APIRouter(prefix="/api", tags=["Themes"])
|
||||||
|
|
||||||
|
@ -11,13 +12,13 @@ router = APIRouter(prefix="/api", tags=["Themes"])
|
||||||
def get_all_themes(session: Session = Depends(generate_session)):
|
def get_all_themes(session: Session = Depends(generate_session)):
|
||||||
""" Returns all site themes """
|
""" Returns all site themes """
|
||||||
|
|
||||||
return SiteTheme.get_all(session)
|
return db.themes.get_all(session)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/themes/create")
|
@router.post("/themes/create")
|
||||||
def create_theme(data: SiteTheme, session: Session = Depends(generate_session)):
|
def create_theme(data: SiteTheme, session: Session = Depends(generate_session)):
|
||||||
""" Creates a site color theme database entry """
|
""" Creates a site color theme database entry """
|
||||||
data.save_to_db(session)
|
db.themes.create(session, data.dict())
|
||||||
|
|
||||||
return SnackResponse.success("Theme Saved")
|
return SnackResponse.success("Theme Saved")
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@ def create_theme(data: SiteTheme, session: Session = Depends(generate_session)):
|
||||||
@router.get("/themes/{theme_name}")
|
@router.get("/themes/{theme_name}")
|
||||||
def get_single_theme(theme_name: str, session: Session = Depends(generate_session)):
|
def get_single_theme(theme_name: str, session: Session = Depends(generate_session)):
|
||||||
""" Returns a named theme """
|
""" Returns a named theme """
|
||||||
return SiteTheme.get_by_name(session, theme_name)
|
return db.themes.get(session, theme_name)
|
||||||
|
|
||||||
|
|
||||||
@router.put("/themes/{theme_name}")
|
@router.put("/themes/{theme_name}")
|
||||||
|
@ -33,7 +34,7 @@ def update_theme(
|
||||||
theme_name: str, data: SiteTheme, session: Session = Depends(generate_session)
|
theme_name: str, data: SiteTheme, session: Session = Depends(generate_session)
|
||||||
):
|
):
|
||||||
""" Update a theme database entry """
|
""" Update a theme database entry """
|
||||||
data.update_document(session)
|
db.themes.update(session, theme_name, data.dict())
|
||||||
|
|
||||||
return SnackResponse.info(f"Theme Updated: {theme_name}")
|
return SnackResponse.info(f"Theme Updated: {theme_name}")
|
||||||
|
|
||||||
|
@ -41,6 +42,6 @@ def update_theme(
|
||||||
@router.delete("/themes/{theme_name}")
|
@router.delete("/themes/{theme_name}")
|
||||||
def delete_theme(theme_name: str, session: Session = Depends(generate_session)):
|
def delete_theme(theme_name: str, session: Session = Depends(generate_session)):
|
||||||
""" Deletes theme from the database """
|
""" Deletes theme from the database """
|
||||||
SiteTheme.delete_theme(session, theme_name)
|
db.themes.delete(session, theme_name)
|
||||||
|
|
||||||
return SnackResponse.error(f"Theme Deleted: {theme_name}")
|
return SnackResponse.error(f"Theme Deleted: {theme_name}")
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
from fastapi import APIRouter, Depends
|
|
||||||
from fastapi.security import OAuth2PasswordRequestForm
|
|
||||||
|
|
||||||
# from fastapi_login import LoginManager
|
|
||||||
# from fastapi_login.exceptions import InvalidCredentialsException
|
|
||||||
|
|
||||||
router = APIRouter()
|
|
||||||
|
|
||||||
# SECRET = "876cfb59db03d9c17cefec967b00255d3f7d93a823e5dc2a"
|
|
||||||
# manager = LoginManager(SECRET, tokenUrl="/api/auth/token")
|
|
||||||
|
|
||||||
# fake_db = {"johndoe@e.mail": {"password": "hunter2"}}
|
|
||||||
|
|
||||||
|
|
||||||
# @manager.user_loader
|
|
||||||
# def load_user(email: str): # could also be an asynchronous function
|
|
||||||
# user = fake_db.get(email)
|
|
||||||
# return user
|
|
||||||
|
|
||||||
|
|
||||||
# @router.post("/api/auth/token", tags=["User Gen"])
|
|
||||||
# def login(data: OAuth2PasswordRequestForm = Depends()):
|
|
||||||
# email = data.username
|
|
||||||
# password = data.password
|
|
||||||
|
|
||||||
# user = load_user(email) # we are using the same function to retrieve the user
|
|
||||||
# if not user:
|
|
||||||
# raise InvalidCredentialsException # you can also use your own HTTPException
|
|
||||||
# elif password != user["password"]:
|
|
||||||
# raise InvalidCredentialsException
|
|
||||||
|
|
||||||
# access_token = manager.create_access_token(data=dict(sub=email))
|
|
||||||
# return {"access_token": access_token, "token_type": "bearer"}
|
|
|
@ -4,11 +4,11 @@ from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from app_config import BACKUP_DIR, IMG_DIR, TEMP_DIR, TEMPLATE_DIR
|
from app_config import BACKUP_DIR, IMG_DIR, TEMP_DIR, TEMPLATE_DIR
|
||||||
|
from db.database import db
|
||||||
from db.db_setup import create_session
|
from db.db_setup import create_session
|
||||||
from jinja2 import Template
|
from jinja2 import Template
|
||||||
from services.meal_services import MealPlan
|
from services.meal_services import MealPlan
|
||||||
from services.recipe_services import Recipe
|
from services.recipe_services import Recipe
|
||||||
from services.settings_services import SiteSettings, SiteTheme
|
|
||||||
from utils.logger import logger
|
from utils.logger import logger
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,20 +88,18 @@ class ExportDatabase:
|
||||||
shutil.copy(file, self.img_dir.joinpath(file.name))
|
shutil.copy(file, self.img_dir.joinpath(file.name))
|
||||||
|
|
||||||
def export_settings(self):
|
def export_settings(self):
|
||||||
all_settings = SiteSettings.get_site_settings(self.session)
|
all_settings = db.settings.get(self.session, "main")
|
||||||
out_file = self.settings_dir.joinpath("settings.json")
|
out_file = self.settings_dir.joinpath("settings.json")
|
||||||
ExportDatabase._write_json_file(all_settings.dict(), out_file)
|
ExportDatabase._write_json_file(all_settings, out_file)
|
||||||
|
|
||||||
def export_themes(self):
|
def export_themes(self):
|
||||||
all_themes = SiteTheme.get_all(self.session)
|
all_themes = db.themes.get_all(self.session)
|
||||||
if all_themes:
|
if all_themes:
|
||||||
all_themes = [x.dict() for x in all_themes]
|
|
||||||
out_file = self.themes_dir.joinpath("themes.json")
|
out_file = self.themes_dir.joinpath("themes.json")
|
||||||
ExportDatabase._write_json_file(all_themes, out_file)
|
ExportDatabase._write_json_file(all_themes, out_file)
|
||||||
|
|
||||||
def export_meals(
|
def export_meals(self):
|
||||||
self,
|
#! Problem Parseing Datetime Objects... May come back to this
|
||||||
): #! Problem Parseing Datetime Objects... May come back to this
|
|
||||||
meal_plans = MealPlan.get_all(self.session)
|
meal_plans = MealPlan.get_all(self.session)
|
||||||
if meal_plans:
|
if meal_plans:
|
||||||
meal_plans = [x.dict() for x in meal_plans]
|
meal_plans = [x.dict() for x in meal_plans]
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
import json
|
import json
|
||||||
import shutil
|
import shutil
|
||||||
import zipfile
|
import zipfile
|
||||||
|
from logging import error
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from app_config import BACKUP_DIR, IMG_DIR, TEMP_DIR
|
from app_config import BACKUP_DIR, IMG_DIR, TEMP_DIR
|
||||||
|
from db.database import db
|
||||||
|
from models.theme_models import SiteTheme
|
||||||
from services.recipe_services import Recipe
|
from services.recipe_services import Recipe
|
||||||
from services.settings_services import SiteSettings, SiteTheme
|
from services.settings_services import SiteSettings
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
from utils.logger import logger
|
from utils.logger import logger
|
||||||
|
|
||||||
|
@ -54,6 +57,7 @@ class ImportDatabase:
|
||||||
raise Exception("Import file does not exist")
|
raise Exception("Import file does not exist")
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
report = {}
|
||||||
if self.imp_recipes:
|
if self.imp_recipes:
|
||||||
report = self.import_recipes()
|
report = self.import_recipes()
|
||||||
if self.imp_settings:
|
if self.imp_settings:
|
||||||
|
@ -128,11 +132,13 @@ class ImportDatabase:
|
||||||
themes_file = self.import_dir.joinpath("themes", "themes.json")
|
themes_file = self.import_dir.joinpath("themes", "themes.json")
|
||||||
|
|
||||||
with open(themes_file, "r") as f:
|
with open(themes_file, "r") as f:
|
||||||
themes: list = json.loads(f.read())
|
themes: list[dict] = json.loads(f.read())
|
||||||
for theme in themes:
|
for theme in themes:
|
||||||
|
if theme.get("name") == "default":
|
||||||
|
continue
|
||||||
new_theme = SiteTheme(**theme)
|
new_theme = SiteTheme(**theme)
|
||||||
try:
|
try:
|
||||||
new_theme.save_to_db(self.session)
|
db.themes.create(self.session, new_theme.dict())
|
||||||
except:
|
except:
|
||||||
logger.info(f"Unable Import Theme {new_theme.name}")
|
logger.info(f"Unable Import Theme {new_theme.name}")
|
||||||
|
|
||||||
|
@ -142,9 +148,7 @@ class ImportDatabase:
|
||||||
with open(settings_file, "r") as f:
|
with open(settings_file, "r") as f:
|
||||||
settings: dict = json.loads(f.read())
|
settings: dict = json.loads(f.read())
|
||||||
|
|
||||||
settings = SiteSettings(**settings)
|
db.settings.update(self.session, settings)
|
||||||
|
|
||||||
settings.update(self.session)
|
|
||||||
|
|
||||||
def clean_up(self):
|
def clean_up(self):
|
||||||
shutil.rmtree(TEMP_DIR)
|
shutil.rmtree(TEMP_DIR)
|
||||||
|
|
|
@ -8,19 +8,6 @@ from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
from services.recipe_services import Recipe
|
from services.recipe_services import Recipe
|
||||||
|
|
||||||
CWD = Path(__file__).parent
|
|
||||||
THIS_WEEK = CWD.parent.joinpath("data", "meal_plan", "this_week.json")
|
|
||||||
NEXT_WEEK = CWD.parent.joinpath("data", "meal_plan", "next_week.json")
|
|
||||||
WEEKDAYS = [
|
|
||||||
"monday",
|
|
||||||
"tuesday",
|
|
||||||
"wednesday",
|
|
||||||
"thursday",
|
|
||||||
"friday",
|
|
||||||
"saturday",
|
|
||||||
"sunday",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class Meal(BaseModel):
|
class Meal(BaseModel):
|
||||||
slug: Optional[str]
|
slug: Optional[str]
|
||||||
|
@ -81,7 +68,7 @@ class MealPlan(BaseModel):
|
||||||
self.meals = meals
|
self.meals = meals
|
||||||
|
|
||||||
def save_to_db(self, session: Session):
|
def save_to_db(self, session: Session):
|
||||||
db.meals.save_new(session, self.dict())
|
db.meals.create(session, self.dict())
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all(session: Session) -> List:
|
def get_all(session: Session) -> List:
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, List, Optional
|
from typing import Any, List, Optional
|
||||||
|
|
||||||
|
@ -98,7 +97,7 @@ class Recipe(BaseModel):
|
||||||
except:
|
except:
|
||||||
recipe_dict["image"] = "no image"
|
recipe_dict["image"] = "no image"
|
||||||
|
|
||||||
recipe_doc = db.recipes.save_new(session, recipe_dict)
|
recipe_doc = db.recipes.create(session, recipe_dict)
|
||||||
recipe = Recipe(**recipe_doc)
|
recipe = Recipe(**recipe_doc)
|
||||||
|
|
||||||
return recipe.slug
|
return recipe.slug
|
||||||
|
|
|
@ -3,8 +3,9 @@ from db.db_setup import create_session
|
||||||
from services.backups.exports import auto_backup_job
|
from services.backups.exports import auto_backup_job
|
||||||
from services.scheduler.global_scheduler import scheduler
|
from services.scheduler.global_scheduler import scheduler
|
||||||
from services.scheduler.scheduler_utils import Cron, cron_parser
|
from services.scheduler.scheduler_utils import Cron, cron_parser
|
||||||
from services.settings_services import SiteSettings
|
|
||||||
from utils.logger import logger
|
from utils.logger import logger
|
||||||
|
from models.settings_models import SiteSettings
|
||||||
|
from db.database import db
|
||||||
from utils.post_webhooks import post_webhooks
|
from utils.post_webhooks import post_webhooks
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +16,8 @@ def update_webhook_schedule():
|
||||||
poll the database for changes and reschedule the webhook time
|
poll the database for changes and reschedule the webhook time
|
||||||
"""
|
"""
|
||||||
session = create_session()
|
session = create_session()
|
||||||
settings = SiteSettings.get_site_settings(session=session)
|
settings = db.settings.get(session, "main")
|
||||||
|
settings = SiteSettings(**settings)
|
||||||
time = cron_parser(settings.webhooks.webhookTime)
|
time = cron_parser(settings.webhooks.webhookTime)
|
||||||
job = JOB_STORE.get("webhooks")
|
job = JOB_STORE.get("webhooks")
|
||||||
|
|
||||||
|
|
|
@ -1,135 +1,6 @@
|
||||||
from typing import List, Optional
|
|
||||||
|
|
||||||
from db.database import db
|
from db.database import db
|
||||||
from db.db_setup import create_session, sql_exists
|
from db.db_setup import create_session, sql_exists
|
||||||
from pydantic import BaseModel
|
from models.settings_models import SiteSettings, Webhooks
|
||||||
from sqlalchemy.orm.session import Session
|
|
||||||
from utils.logger import logger
|
|
||||||
|
|
||||||
|
|
||||||
class Webhooks(BaseModel):
|
|
||||||
webhookTime: str = "00:00"
|
|
||||||
webhookURLs: Optional[List[str]] = []
|
|
||||||
enabled: bool = False
|
|
||||||
|
|
||||||
|
|
||||||
class SiteSettings(BaseModel):
|
|
||||||
name: str = "main"
|
|
||||||
webhooks: Webhooks
|
|
||||||
|
|
||||||
class Config:
|
|
||||||
schema_extra = {
|
|
||||||
"example": {
|
|
||||||
"name": "main",
|
|
||||||
"webhooks": {
|
|
||||||
"webhookTime": "00:00",
|
|
||||||
"webhookURLs": ["https://mywebhookurl.com/webhook"],
|
|
||||||
"enable": False,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_all(session: Session):
|
|
||||||
db.settings.get_all(session)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_site_settings(cls, session: Session):
|
|
||||||
try:
|
|
||||||
document = db.settings.get(session=session, match_value="main")
|
|
||||||
except:
|
|
||||||
webhooks = Webhooks()
|
|
||||||
default_entry = SiteSettings(name="main", webhooks=webhooks)
|
|
||||||
document = db.settings.save_new(
|
|
||||||
session, default_entry.dict(), webhooks.dict()
|
|
||||||
)
|
|
||||||
|
|
||||||
return cls(**document)
|
|
||||||
|
|
||||||
def update(self, session: Session):
|
|
||||||
db.settings.update(session, "main", new_data=self.dict())
|
|
||||||
|
|
||||||
|
|
||||||
class Colors(BaseModel):
|
|
||||||
primary: str
|
|
||||||
accent: str
|
|
||||||
secondary: str
|
|
||||||
success: str
|
|
||||||
info: str
|
|
||||||
warning: str
|
|
||||||
error: str
|
|
||||||
|
|
||||||
|
|
||||||
class SiteTheme(BaseModel):
|
|
||||||
name: str
|
|
||||||
colors: Colors
|
|
||||||
|
|
||||||
class Config:
|
|
||||||
schema_extra = {
|
|
||||||
"example": {
|
|
||||||
"name": "default",
|
|
||||||
"colors": {
|
|
||||||
"primary": "#E58325",
|
|
||||||
"accent": "#00457A",
|
|
||||||
"secondary": "#973542",
|
|
||||||
"success": "#5AB1BB",
|
|
||||||
"info": "#4990BA",
|
|
||||||
"warning": "#FF4081",
|
|
||||||
"error": "#EF5350",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_by_name(cls, session: Session, theme_name):
|
|
||||||
db_entry = db.themes.get(session, theme_name)
|
|
||||||
name = db_entry.get("name")
|
|
||||||
colors = Colors(**db_entry.get("colors"))
|
|
||||||
|
|
||||||
return cls(name=name, colors=colors)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_all(session: Session):
|
|
||||||
all_themes = db.themes.get_all(session)
|
|
||||||
for index, theme in enumerate(all_themes):
|
|
||||||
name = theme.get("name")
|
|
||||||
colors = Colors(**theme.get("colors"))
|
|
||||||
|
|
||||||
all_themes[index] = SiteTheme(name=name, colors=colors)
|
|
||||||
|
|
||||||
return all_themes
|
|
||||||
|
|
||||||
def save_to_db(self, session: Session):
|
|
||||||
db.themes.save_new(session, self.dict())
|
|
||||||
|
|
||||||
def update_document(self, session: Session):
|
|
||||||
db.themes.update(session, self.name, self.dict())
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def delete_theme(session: Session, theme_name: str) -> str:
|
|
||||||
""" Removes the theme by name """
|
|
||||||
db.themes.delete(session, theme_name)
|
|
||||||
|
|
||||||
|
|
||||||
def default_theme_init():
|
|
||||||
default_colors = {
|
|
||||||
"primary": "#E58325",
|
|
||||||
"accent": "#00457A",
|
|
||||||
"secondary": "#973542",
|
|
||||||
"success": "#5AB1BB",
|
|
||||||
"info": "#4990BA",
|
|
||||||
"warning": "#FF4081",
|
|
||||||
"error": "#EF5350",
|
|
||||||
}
|
|
||||||
session = create_session()
|
|
||||||
try:
|
|
||||||
SiteTheme.get_by_name(session, "default")
|
|
||||||
logger.info("Default theme exists... skipping generation")
|
|
||||||
except:
|
|
||||||
logger.info("Generating Default Theme")
|
|
||||||
colors = Colors(**default_colors)
|
|
||||||
default_theme = SiteTheme(name="default", colors=colors)
|
|
||||||
default_theme.save_to_db(session)
|
|
||||||
|
|
||||||
|
|
||||||
def default_settings_init():
|
def default_settings_init():
|
||||||
|
@ -139,11 +10,10 @@ def default_settings_init():
|
||||||
except:
|
except:
|
||||||
webhooks = Webhooks()
|
webhooks = Webhooks()
|
||||||
default_entry = SiteSettings(name="main", webhooks=webhooks)
|
default_entry = SiteSettings(name="main", webhooks=webhooks)
|
||||||
document = db.settings.save_new(session, default_entry.dict(), webhooks.dict())
|
document = db.settings.create(session, default_entry.dict(), webhooks.dict())
|
||||||
|
|
||||||
session.close()
|
session.close()
|
||||||
|
|
||||||
|
|
||||||
if not sql_exists:
|
if not sql_exists:
|
||||||
default_settings_init()
|
default_settings_init()
|
||||||
default_theme_init()
|
|
||||||
|
|
28
mealie/services/theme_services.py
Normal file
28
mealie/services/theme_services.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
from db.database import db
|
||||||
|
from db.db_setup import create_session, sql_exists
|
||||||
|
from utils.logger import logger
|
||||||
|
|
||||||
|
|
||||||
|
def default_theme_init():
|
||||||
|
default_theme = {
|
||||||
|
"name": "default",
|
||||||
|
"colors": {
|
||||||
|
"primary": "#E58325",
|
||||||
|
"accent": "#00457A",
|
||||||
|
"secondary": "#973542",
|
||||||
|
"success": "#5AB1BB",
|
||||||
|
"info": "#4990BA",
|
||||||
|
"warning": "#FF4081",
|
||||||
|
"error": "#EF5350",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
session = create_session()
|
||||||
|
try:
|
||||||
|
db.themes.create(session, default_theme)
|
||||||
|
logger.info("Generating default theme...")
|
||||||
|
except:
|
||||||
|
logger.info("Default Theme Exists.. skipping generation")
|
||||||
|
|
||||||
|
|
||||||
|
if not sql_exists:
|
||||||
|
default_theme_init()
|
|
@ -1,15 +1,17 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
from db.database import db
|
||||||
from db.db_setup import create_session
|
from db.db_setup import create_session
|
||||||
|
from models.settings_models import SiteSettings
|
||||||
from services.meal_services import MealPlan
|
from services.meal_services import MealPlan
|
||||||
from services.recipe_services import Recipe
|
from services.recipe_services import Recipe
|
||||||
from services.settings_services import SiteSettings
|
|
||||||
|
|
||||||
|
|
||||||
def post_webhooks():
|
def post_webhooks():
|
||||||
session = create_session()
|
session = create_session()
|
||||||
all_settings = SiteSettings.get_site_settings(session)
|
all_settings = db.get(session, "main")
|
||||||
|
all_settings = SiteSettings(**all_settings)
|
||||||
|
|
||||||
if all_settings.webhooks.enabled:
|
if all_settings.webhooks.enabled:
|
||||||
todays_meal = Recipe.get_by_slug(MealPlan.today()).dict()
|
todays_meal = Recipe.get_by_slug(MealPlan.today()).dict()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue