category/tag database relationship and endpoints

This commit is contained in:
hayden
2021-01-30 17:25:05 -09:00
parent 016108d35f
commit d6794cba7d
14 changed files with 178 additions and 102 deletions

View File

@@ -8,16 +8,32 @@ from routes import (
backup_routes, backup_routes,
meal_routes, meal_routes,
migration_routes, migration_routes,
recipe_routes,
setting_routes, setting_routes,
static_routes, static_routes,
user_routes, user_routes,
category_routes,
) )
from routes.recipe import (
all_recipe_routes,
category_routes,
recipe_crud_routes,
tag_routes,
)
from utils.api_docs import generate_api_docs from utils.api_docs import generate_api_docs
from utils.logger import logger from utils.logger import logger
"""
TODO:
- [ ] Fix Duplicate Category
- [ ] Fix Duplicate Tags
- [ ] Add Endpoint
- [ ] Endpoint Tests
- [ ] Setup Database Migrations
- [ ] Finish Frontend Category Management
- [ ] Ingredient Drag-Drop / Reorder
- [ ] Refactor Endpoints
"""
app = FastAPI( app = FastAPI(
title="Mealie", title="Mealie",
description="A place for all your recipes", description="A place for all your recipes",
@@ -32,15 +48,21 @@ def mount_static_files():
def api_routers(): def api_routers():
# First # Recipes
print() app.include_router(all_recipe_routes.router)
app.include_router(recipe_routes.router) app.include_router(recipe_crud_routes.router)
app.include_router(meal_routes.router)
app.include_router(setting_routes.router)
app.include_router(backup_routes.router)
app.include_router(user_routes.router)
app.include_router(migration_routes.router)
app.include_router(category_routes.router) app.include_router(category_routes.router)
app.include_router(tag_routes.router)
# Meal Routes
app.include_router(meal_routes.router)
# Settings Routes
app.include_router(setting_routes.router)
# Backups/Imports Routes
app.include_router(backup_routes.router)
# User Routes
app.include_router(user_routes.router)
# Migration Routes
app.include_router(migration_routes.router)
if PRODUCTION: if PRODUCTION:

View File

@@ -2,14 +2,14 @@ from sqlalchemy.orm.session import Session
from db.db_base import BaseDocument from db.db_base import BaseDocument
from db.sql.meal_models import MealPlanModel from db.sql.meal_models import MealPlanModel
from db.sql.recipe_models import RecipeModel from db.sql.recipe_models import Category, RecipeModel, Tag
from db.sql.settings_models import SiteSettingsModel from db.sql.settings_models import SiteSettingsModel
from db.sql.theme_models import SiteThemeModel 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
- [ ] Create Category and Tags Table with Many to Many relationship - [x] Create Category and Tags Table with Many to Many relationship
""" """
@@ -19,13 +19,25 @@ class _Recipes(BaseDocument):
self.sql_model = RecipeModel self.sql_model = RecipeModel
def update_image(self, session: Session, slug: str, extension: str) -> str: def update_image(self, session: Session, slug: str, extension: str) -> str:
entry = self._query_one(session, match_value=slug) entry: RecipeModel = self._query_one(session, match_value=slug)
entry.image = f"{slug}.{extension}" entry.image = f"{slug}.{extension}"
session.commit() session.commit()
return f"{slug}.{extension}" return f"{slug}.{extension}"
class _Categories(BaseDocument):
def __init__(self) -> None:
self.primary_key = "name"
self.sql_model = Category
class _Tags(BaseDocument):
def __init__(self) -> None:
self.primary_key = "name"
self.sql_model = Tag
class _Meals(BaseDocument): class _Meals(BaseDocument):
def __init__(self) -> None: def __init__(self) -> None:
self.primary_key = "uid" self.primary_key = "uid"
@@ -58,6 +70,8 @@ class Database:
self.meals = _Meals() self.meals = _Meals()
self.settings = _Settings() self.settings = _Settings()
self.themes = _Themes() self.themes = _Themes()
self.categories = _Categories()
self.tags = _Tags()
db = Database() db = Database()

View File

@@ -1,5 +1,6 @@
from typing import List, Union from typing import List
from sqlalchemy.orm import load_only
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
from db.sql.model_base import SqlAlchemyBase from db.sql.model_base import SqlAlchemyBase
@@ -22,6 +23,13 @@ class BaseDocument:
return list return list
def get_all_primary_keys(self, session: Session):
results = session.query(self.sql_model).options(
load_only(str(self.primary_key))
)
results_as_dict = [x.dict() for x in results]
return [x.get(self.primary_key) for x in results_as_dict]
def _query_one( def _query_one(
self, session: Session, match_value: str, match_key: str = None self, session: Session, match_value: str, match_key: str = None
) -> SqlAlchemyBase: ) -> SqlAlchemyBase:
@@ -79,7 +87,7 @@ class BaseDocument:
Returns: Returns:
dict: A dictionary representation of the database entry dict: A dictionary representation of the database entry
""" """
new_document = self.sql_model(**document) new_document = self.sql_model(session=session, **document)
session.add(new_document) session.add(new_document)
return_data = new_document.dict() return_data = new_document.dict()
session.commit() session.commit()

View File

@@ -17,7 +17,9 @@ class Meal(SqlAlchemyBase):
image = sa.Column(sa.String) image = sa.Column(sa.String)
description = sa.Column(sa.String) description = sa.Column(sa.String)
def __init__(self, slug, name, date, dateText, image, description) -> None: def __init__(
self, slug, name, date, dateText, image, description, session=None
) -> None:
self.slug = slug self.slug = slug
self.name = name self.name = name
self.date = date self.date = date
@@ -45,7 +47,7 @@ class MealPlanModel(SqlAlchemyBase, BaseMixins):
endDate = sa.Column(sa.Date) endDate = sa.Column(sa.Date)
meals: List[Meal] = orm.relation(Meal) meals: List[Meal] = orm.relation(Meal)
def __init__(self, startDate, endDate, meals, uid=None) -> None: def __init__(self, startDate, endDate, meals, uid=None, session=None) -> None:
self.startDate = startDate self.startDate = startDate
self.endDate = endDate self.endDate = endDate
self.meals = [Meal(**meal) for meal in meals] self.meals = [Meal(**meal) for meal in meals]

View File

@@ -6,6 +6,7 @@ import sqlalchemy as sa
import sqlalchemy.orm as orm import sqlalchemy.orm as orm
from db.sql.model_base import BaseMixins, SqlAlchemyBase from db.sql.model_base import BaseMixins, SqlAlchemyBase
from sqlalchemy.ext.orderinglist import ordering_list from sqlalchemy.ext.orderinglist import ordering_list
from utils.logger import logger
class ApiExtras(SqlAlchemyBase): class ApiExtras(SqlAlchemyBase):
@@ -23,36 +24,80 @@ class ApiExtras(SqlAlchemyBase):
return {self.key_name: self.value} return {self.key_name: self.value}
recipes2categories = sa.Table("recipes2categories", SqlAlchemyBase.metadata, recipes2categories = sa.Table(
"recipes2categories",
SqlAlchemyBase.metadata,
sa.Column("recipe_id", sa.Integer, sa.ForeignKey("recipes.id")), sa.Column("recipe_id", sa.Integer, sa.ForeignKey("recipes.id")),
sa.Column("category_id", sa.Integer, sa.ForeignKey("categories.id"))) sa.Column("category_name", sa.String, sa.ForeignKey("categories.name")),
)
recipes2tags = sa.Table(
"recipes2tags",
SqlAlchemyBase.metadata,
sa.Column("recipe_id", sa.Integer, sa.ForeignKey("recipes.id")),
sa.Column("tag_id", sa.Integer, sa.ForeignKey("tags.id")),
)
class Category(SqlAlchemyBase): class Category(SqlAlchemyBase):
__tablename__ = "categories" __tablename__ = "categories"
id = sa.Column(sa.Integer, primary_key=True) id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String, index=True) name = sa.Column(sa.String, index=True)
recipes = orm.relationship( recipes = orm.relationship(
"RecipeModel", "RecipeModel", secondary=recipes2categories, back_populates="categories"
secondary=recipes2categories,
back_populates="categories"
) )
def __init__(self, name) -> None: def __init__(self, name) -> None:
self.name = name self.name = name
@classmethod
def create_if_not_exist(cls, session, name: str):
try:
result = session.query(Category).filter_by(**{"name": name}).one()
logger.info("Category Exists, Associating Recipe")
return result
except:
logger.info("Category doesn't exists, creating category")
return cls(name=name)
def to_str(self): def to_str(self):
return self.name return self.name
def dict(self):
return {"id": self.id, "name": self.name, "recipes": [x.dict() for x in self.recipes]}
class Tag(SqlAlchemyBase): class Tag(SqlAlchemyBase):
__tablename__ = "tags" __tablename__ = "tags"
id = sa.Column(sa.Integer, primary_key=True) id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id"))
name = sa.Column(sa.String, index=True) name = sa.Column(sa.String, index=True)
recipes = orm.relationship(
"RecipeModel", secondary=recipes2tags, back_populates="tags"
)
def to_str(self): def to_str(self):
return self.name return self.name
def __init__(self, name) -> None:
self.name = name
def dict(self):
return {"id": self.id, "name": self.name, "recipes": [x.dict() for x in self.recipes]}
@classmethod
def create_if_not_exist(cls, session, name: str):
try:
result = session.query(Tag).filter_by(**{"name": name}).one()
logger.info("Tag Exists, Associating Recipe")
return result
except:
logger.info("Tag doesn't exists, creating tag")
return cls(name=name)
class Note(SqlAlchemyBase): class Note(SqlAlchemyBase):
__tablename__ = "notes" __tablename__ = "notes"
@@ -128,25 +173,20 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
# Mealie Specific # Mealie Specific
slug = sa.Column(sa.String, index=True, unique=True) slug = sa.Column(sa.String, index=True, unique=True)
categories: List = orm.relationship( categories: List = orm.relationship(
"Category", "Category", secondary=recipes2categories, back_populates="recipes"
secondary=recipes2categories,
back_populates="recipes",
) )
tags: List[Tag] = orm.relationship( tags: List[Tag] = orm.relationship(
"Tag", "Tag", secondary=recipes2tags, back_populates="recipes"
cascade="all, delete",
) )
dateAdded = sa.Column(sa.Date, default=date.today) dateAdded = sa.Column(sa.Date, default=date.today)
notes: List[Note] = orm.relationship( notes: List[Note] = orm.relationship("Note", cascade="all, delete")
"Note",
cascade="all, delete",
)
rating = sa.Column(sa.Integer) rating = sa.Column(sa.Integer)
orgURL = sa.Column(sa.String) orgURL = sa.Column(sa.String)
extras: List[ApiExtras] = orm.relationship("ApiExtras", cascade="all, delete") extras: List[ApiExtras] = orm.relationship("ApiExtras", cascade="all, delete")
def __init__( def __init__(
self, self,
session,
name: str = None, name: str = None,
description: str = None, description: str = None,
image: str = None, image: str = None,
@@ -182,8 +222,12 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
# Mealie Specific # Mealie Specific
self.slug = slug self.slug = slug
self.categories = [Category(cat) for cat in categories]
self.tags = [Tag(name=tag) for tag in tags] self.categories = [
(Category.create_if_not_exist(session, cat)) for cat in categories
]
self.tags = [Tag.create_if_not_exist(session, name=tag) for tag in tags]
self.dateAdded = dateAdded self.dateAdded = dateAdded
self.notes = [Note(**note) for note in notes] self.notes = [Note(**note) for note in notes]
self.rating = rating self.rating = rating
@@ -212,10 +256,11 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
extras: dict = None, extras: dict = None,
): ):
"""Updated a database entry by removing nested rows and rebuilds the row through the __init__ functions""" """Updated a database entry by removing nested rows and rebuilds the row through the __init__ functions"""
list_of_tables = [RecipeIngredient, RecipeInstruction, Tag, ApiExtras] list_of_tables = [RecipeIngredient, RecipeInstruction, ApiExtras]
RecipeModel._sql_remove_list(session, list_of_tables, self.id) RecipeModel._sql_remove_list(session, list_of_tables, self.id)
self.__init__( self.__init__(
session=session,
name=name, name=name,
description=description, description=description,
image=image, image=image,

View File

@@ -8,7 +8,7 @@ class SiteSettingsModel(SqlAlchemyBase):
name = sa.Column(sa.String, primary_key=True) name = sa.Column(sa.String, primary_key=True)
webhooks = orm.relationship("WebHookModel", uselist=False, cascade="all, delete") webhooks = orm.relationship("WebHookModel", uselist=False, cascade="all, delete")
def __init__(self, name: str = None, webhooks: dict = None) -> None: def __init__(self, name: str = None, webhooks: dict = None, session=None) -> None:
self.name = name self.name = name
self.webhooks = WebHookModel(**webhooks) self.webhooks = WebHookModel(**webhooks)
@@ -33,7 +33,7 @@ class WebHookModel(SqlAlchemyBase, BaseMixins):
enabled = sa.Column(sa.Boolean, default=False) enabled = sa.Column(sa.Boolean, default=False)
def __init__( def __init__(
self, webhookURLs: list, webhookTime: str, enabled: bool = False self, webhookURLs: list, webhookTime: str, enabled: bool = False, session=None
) -> None: ) -> None:
self.webhookURLs = [WebhookURLModel(url=x) for x in webhookURLs] self.webhookURLs = [WebhookURLModel(url=x) for x in webhookURLs]

View File

@@ -8,7 +8,7 @@ class SiteThemeModel(SqlAlchemyBase):
name = sa.Column(sa.String, primary_key=True) name = sa.Column(sa.String, primary_key=True)
colors = orm.relationship("ThemeColorsModel", uselist=False, cascade="all, delete") colors = orm.relationship("ThemeColorsModel", uselist=False, cascade="all, delete")
def __init__(self, name: str, colors: dict) -> None: def __init__(self, name: str, colors: dict, session=None) -> None:
self.name = name self.name = name
self.colors = ThemeColorsModel(**colors) self.colors = ThemeColorsModel(**colors)

View File

@@ -1,11 +1,13 @@
from pydantic.main import BaseModel from typing import List
class Category(BaseModel): from pydantic.main import BaseModel
from services.recipe_services import Recipe
class RecipeCategoryResponse(BaseModel):
id: int
name: str name: str
recipes: List[Recipe]
class Config: class Config:
schema_extra = { schema_extra = {"example": {"id": 1, "name": "dinner", "recipes": [{}]}}
"example": {
"name": "Breakfast"
}
}

View File

@@ -11,10 +11,10 @@ from sqlalchemy.orm.session import Session
from starlette.responses import FileResponse from starlette.responses import FileResponse
from utils.snackbar import SnackResponse from utils.snackbar import SnackResponse
router = APIRouter(tags=["Import / Export"]) router = APIRouter(prefix="/api/backups", tags=["Import / Export"])
@router.get("/api/backups/available/", response_model=Imports) @router.get("/available/", response_model=Imports)
def available_imports(): def available_imports():
"""Returns a list of avaiable .zip files for import into Mealie.""" """Returns a list of avaiable .zip files for import into Mealie."""
imports = [] imports = []
@@ -31,7 +31,7 @@ def available_imports():
return Imports(imports=imports, templates=templates) return Imports(imports=imports, templates=templates)
@router.post("/api/backups/export/database/", status_code=201) @router.post("/export/database/", status_code=201)
def export_database(data: BackupJob, db: Session = Depends(generate_session)): def export_database(data: BackupJob, db: Session = Depends(generate_session)):
"""Generates a backup of the recipe database in json format.""" """Generates a backup of the recipe database in json format."""
export_path = backup_all( export_path = backup_all(
@@ -51,7 +51,7 @@ def export_database(data: BackupJob, db: Session = Depends(generate_session)):
) )
@router.post("/api/backups/upload/") @router.post("/upload/")
def upload_backup_zipfile(archive: UploadFile = File(...)): def upload_backup_zipfile(archive: UploadFile = File(...)):
""" Upload a .zip File to later be imported into Mealie """ """ Upload a .zip File to later be imported into Mealie """
dest = BACKUP_DIR.joinpath(archive.filename) dest = BACKUP_DIR.joinpath(archive.filename)
@@ -65,7 +65,7 @@ def upload_backup_zipfile(archive: UploadFile = File(...)):
return SnackResponse.error("Failure uploading file") return SnackResponse.error("Failure uploading file")
@router.get("/api/backups/{file_name}/download/") @router.get("/{file_name}/download/")
def upload_nextcloud_zipfile(file_name: str): def upload_nextcloud_zipfile(file_name: str):
""" Upload a .zip File to later be imported into Mealie """ """ Upload a .zip File to later be imported into Mealie """
file = BACKUP_DIR.joinpath(file_name) file = BACKUP_DIR.joinpath(file_name)
@@ -78,7 +78,7 @@ def upload_nextcloud_zipfile(file_name: str):
return SnackResponse.error("No File Found") return SnackResponse.error("No File Found")
@router.post("/api/backups/{file_name}/import/", status_code=200) @router.post("/{file_name}/import/", status_code=200)
def import_database( def import_database(
file_name: str, import_data: ImportJob, db: Session = Depends(generate_session) file_name: str, import_data: ImportJob, db: Session = Depends(generate_session)
): ):
@@ -98,20 +98,16 @@ def import_database(
return imported return imported
@router.delete( @router.delete("/{file_name}/delete/", tags=["Import / Export"], status_code=200)
"/api/backups/{backup_name}/delete/", def delete_backup(file_name: str):
tags=["Import / Export"],
status_code=200,
)
def delete_backup(backup_name: str):
""" Removes a database backup from the file system """ """ Removes a database backup from the file system """
try: try:
BACKUP_DIR.joinpath(backup_name).unlink() BACKUP_DIR.joinpath(file_name).unlink()
except: except:
HTTPException( HTTPException(
status_code=400, status_code=400,
detail=SnackResponse.error("Unable to Delete Backup. See Log File"), detail=SnackResponse.error("Unable to Delete Backup. See Log File"),
) )
return SnackResponse.success(f"{backup_name} Deleted") return SnackResponse.success(f"{file_name} Deleted")

View File

@@ -1,14 +0,0 @@
from typing import List
from models.category_models import Category
from services.category_services import get_all
from fastapi import APIRouter, HTTPException
from utils.snackbar import SnackResponse
router = APIRouter(tags=["Category"])
@router.get("/api/category/all", response_model=List[Category])
def get_all_categories():
""" Returns a list of all categories """
return get_all()

View File

@@ -6,17 +6,17 @@ from services.meal_services import MealPlan
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
from utils.snackbar import SnackResponse from utils.snackbar import SnackResponse
router = APIRouter(tags=["Meal Plan"]) router = APIRouter(prefix="/api/meal-plan", tags=["Meal Plan"])
@router.get("/api/meal-plan/all/", response_model=List[MealPlan]) @router.get("/all/", response_model=List[MealPlan])
def get_all_meals(db: Session = Depends(generate_session)): def get_all_meals(db: Session = Depends(generate_session)):
""" Returns a list of all available Meal Plan """ """ Returns a list of all available Meal Plan """
return MealPlan.get_all(db) return MealPlan.get_all(db)
@router.post("/api/meal-plan/create/") @router.post("/create/")
def set_meal_plan(data: MealPlan, db: Session = Depends(generate_session)): def set_meal_plan(data: MealPlan, db: Session = Depends(generate_session)):
""" Creates a meal plan database entry """ """ Creates a meal plan database entry """
data.process_meals(db) data.process_meals(db)
@@ -30,7 +30,7 @@ def set_meal_plan(data: MealPlan, db: Session = Depends(generate_session)):
return SnackResponse.success("Mealplan Created") return SnackResponse.success("Mealplan Created")
@router.post("/api/meal-plan/{plan_id}/update/") @router.post("/{plan_id}/update/")
def update_meal_plan( def update_meal_plan(
plan_id: str, meal_plan: MealPlan, db: Session = Depends(generate_session) plan_id: str, meal_plan: MealPlan, db: Session = Depends(generate_session)
): ):
@@ -49,7 +49,7 @@ def update_meal_plan(
return SnackResponse.success("Mealplan Updated") return SnackResponse.success("Mealplan Updated")
@router.delete("/api/meal-plan/{plan_id}/delete/") @router.delete("/{plan_id}/delete/")
def delete_meal_plan(plan_id, db: Session = Depends(generate_session)): def delete_meal_plan(plan_id, db: Session = Depends(generate_session)):
""" Removes a meal plan from the database """ """ Removes a meal plan from the database """
@@ -58,10 +58,7 @@ def delete_meal_plan(plan_id, db: Session = Depends(generate_session)):
return SnackResponse.success("Mealplan Deleted") return SnackResponse.success("Mealplan Deleted")
@router.get( @router.get("/today/", tags=["Meal Plan"])
"/api/meal-plan/today/",
tags=["Meal Plan"],
)
def get_today(db: Session = Depends(generate_session)): def get_today(db: Session = Depends(generate_session)):
""" """
Returns the recipe slug for the meal scheduled for today. Returns the recipe slug for the meal scheduled for today.
@@ -71,7 +68,7 @@ def get_today(db: Session = Depends(generate_session)):
return MealPlan.today(db) return MealPlan.today(db)
@router.get("/api/meal-plan/this-week/", response_model=MealPlan) @router.get("/this-week/", response_model=MealPlan)
def get_this_week(db: Session = Depends(generate_session)): def get_this_week(db: Session = Depends(generate_session)):
""" Returns the meal plan data for this week """ """ Returns the meal plan data for this week """

View File

@@ -11,10 +11,10 @@ from services.migrations.nextcloud import migrate as nextcloud_migrate
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
from utils.snackbar import SnackResponse from utils.snackbar import SnackResponse
router = APIRouter(tags=["Migration"]) router = APIRouter(prefix="/api/migrations", tags=["Migration"])
@router.get("/api/migrations/", response_model=List[Migrations]) @router.get("/", response_model=List[Migrations])
def get_avaiable_nextcloud_imports(): def get_avaiable_nextcloud_imports():
""" Returns a list of avaiable directories that can be imported into Mealie """ """ Returns a list of avaiable directories that can be imported into Mealie """
response_data = [] response_data = []
@@ -35,7 +35,7 @@ def get_avaiable_nextcloud_imports():
return response_data return response_data
@router.post("/api/migrations/{type}/{file_name}/import/") @router.post("/{type}/{file_name}/import/")
def import_nextcloud_directory( def import_nextcloud_directory(
type: str, file_name: str, db: Session = Depends(generate_session) type: str, file_name: str, db: Session = Depends(generate_session)
): ):
@@ -49,11 +49,11 @@ def import_nextcloud_directory(
return SnackResponse.error("Incorrect Migration Type Selected") return SnackResponse.error("Incorrect Migration Type Selected")
@router.delete("/api/migrations/{folder}/{file}/delete/") @router.delete("/{type}/{file_name}/delete/")
def delete_migration_data(folder: str, file: str): def delete_migration_data(type: str, file_name: str):
""" Removes migration data from the file system """ """ Removes migration data from the file system """
remove_path = MIGRATION_DIR.joinpath(folder, file) remove_path = MIGRATION_DIR.joinpath(type, file_name)
if remove_path.is_file(): if remove_path.is_file():
remove_path.unlink() remove_path.unlink()
@@ -65,7 +65,7 @@ def delete_migration_data(folder: str, file: str):
return SnackResponse.info(f"Migration Data Remove: {remove_path.absolute()}") return SnackResponse.info(f"Migration Data Remove: {remove_path.absolute()}")
@router.post("/api/migrations/{type}/upload/") @router.post("/{type}/upload/")
def upload_nextcloud_zipfile(type: str, archive: UploadFile = File(...)): def upload_nextcloud_zipfile(type: str, archive: UploadFile = File(...)):
""" Upload a .zip File to later be imported into Mealie """ """ Upload a .zip File to later be imported into Mealie """
dir = MIGRATION_DIR.joinpath(type) dir = MIGRATION_DIR.joinpath(type)

View File

@@ -5,24 +5,23 @@ 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
router = APIRouter(tags=["Settings"]) router = APIRouter(prefix="/api/site-settings", tags=["Settings"])
@router.get("/")
@router.get("/api/site-settings/")
def get_main_settings(db: Session = Depends(generate_session)): def get_main_settings(db: Session = Depends(generate_session)):
""" Returns basic site settings """ """ Returns basic site settings """
return SiteSettings.get_site_settings(db) return SiteSettings.get_site_settings(db)
@router.post("/api/site-settings/webhooks/test/") @router.post("/webhooks/test/")
def test_webhooks(): def test_webhooks():
""" Run the function to test your webhooks """ """ Run the function to test your webhooks """
return post_webhooks() return post_webhooks()
@router.post("/api/site-settings/update/") @router.post("/update/")
def update_settings(data: SiteSettings, db: Session = Depends(generate_session)): def update_settings(data: SiteSettings, db: Session = Depends(generate_session)):
""" Returns Site Settings """ """ Returns Site Settings """
data.update(db) data.update(db)
@@ -36,20 +35,20 @@ def update_settings(data: SiteSettings, db: Session = Depends(generate_session))
return SnackResponse.success("Settings Updated") return SnackResponse.success("Settings Updated")
@router.get("/api/site-settings/themes/", tags=["Themes"]) @router.get("/themes/", tags=["Themes"])
def get_all_themes(db: Session = Depends(generate_session)): def get_all_themes(db: Session = Depends(generate_session)):
""" Returns all site themes """ """ Returns all site themes """
return SiteTheme.get_all(db) return SiteTheme.get_all(db)
@router.get("/api/site-settings/themes/{theme_name}/", tags=["Themes"]) @router.get("/themes/{theme_name}/", tags=["Themes"])
def get_single_theme(theme_name: str, db: Session = Depends(generate_session)): def get_single_theme(theme_name: str, db: Session = Depends(generate_session)):
""" Returns a named theme """ """ Returns a named theme """
return SiteTheme.get_by_name(db, theme_name) return SiteTheme.get_by_name(db, theme_name)
@router.post("/api/site-settings/themes/create/", tags=["Themes"]) @router.post("/themes/create/", tags=["Themes"])
def create_theme(data: SiteTheme, db: Session = Depends(generate_session)): def create_theme(data: SiteTheme, db: Session = Depends(generate_session)):
""" Creates a site color theme database entry """ """ Creates a site color theme database entry """
data.save_to_db(db) data.save_to_db(db)
@@ -63,7 +62,7 @@ def create_theme(data: SiteTheme, db: Session = Depends(generate_session)):
return SnackResponse.success("Theme Saved") return SnackResponse.success("Theme Saved")
@router.post("/api/site-settings/themes/{theme_name}/update/", tags=["Themes"]) @router.post("/themes/{theme_name}/update/", tags=["Themes"])
def update_theme( def update_theme(
theme_name: str, data: SiteTheme, db: Session = Depends(generate_session) theme_name: str, data: SiteTheme, db: Session = Depends(generate_session)
): ):
@@ -79,7 +78,7 @@ def update_theme(
return SnackResponse.success("Theme Updated") return SnackResponse.success("Theme Updated")
@router.delete("/api/site-settings/themes/{theme_name}/delete/", tags=["Themes"]) @router.delete("/themes/{theme_name}/delete/", tags=["Themes"])
def delete_theme(theme_name: str, db: Session = Depends(generate_session)): def delete_theme(theme_name: str, db: Session = Depends(generate_session)):
""" Deletes theme from the database """ """ Deletes theme from the database """
SiteTheme.delete_theme(db, theme_name) SiteTheme.delete_theme(db, theme_name)

5
mealie/run.sh Normal file
View File

@@ -0,0 +1,5 @@
## Run Migration
## Start Application
uvicorn app:app --host 0.0.0.0 --port 80