mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-12-21 09:45:18 -05:00
category/tag database relationship and endpoints
This commit is contained in:
@@ -8,16 +8,32 @@ from routes import (
|
||||
backup_routes,
|
||||
meal_routes,
|
||||
migration_routes,
|
||||
recipe_routes,
|
||||
setting_routes,
|
||||
static_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.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(
|
||||
title="Mealie",
|
||||
description="A place for all your recipes",
|
||||
@@ -32,15 +48,21 @@ def mount_static_files():
|
||||
|
||||
|
||||
def api_routers():
|
||||
# First
|
||||
print()
|
||||
app.include_router(recipe_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)
|
||||
# Recipes
|
||||
app.include_router(all_recipe_routes.router)
|
||||
app.include_router(recipe_crud_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:
|
||||
|
||||
@@ -2,14 +2,14 @@ from sqlalchemy.orm.session import Session
|
||||
|
||||
from db.db_base import BaseDocument
|
||||
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.theme_models import SiteThemeModel
|
||||
|
||||
"""
|
||||
# TODO
|
||||
- [ ] 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
|
||||
|
||||
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}"
|
||||
session.commit()
|
||||
|
||||
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):
|
||||
def __init__(self) -> None:
|
||||
self.primary_key = "uid"
|
||||
@@ -58,6 +70,8 @@ class Database:
|
||||
self.meals = _Meals()
|
||||
self.settings = _Settings()
|
||||
self.themes = _Themes()
|
||||
self.categories = _Categories()
|
||||
self.tags = _Tags()
|
||||
|
||||
|
||||
db = Database()
|
||||
|
||||
@@ -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 db.sql.model_base import SqlAlchemyBase
|
||||
@@ -22,6 +23,13 @@ class BaseDocument:
|
||||
|
||||
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(
|
||||
self, session: Session, match_value: str, match_key: str = None
|
||||
) -> SqlAlchemyBase:
|
||||
@@ -79,7 +87,7 @@ class BaseDocument:
|
||||
Returns:
|
||||
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)
|
||||
return_data = new_document.dict()
|
||||
session.commit()
|
||||
|
||||
@@ -17,7 +17,9 @@ class Meal(SqlAlchemyBase):
|
||||
image = 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.name = name
|
||||
self.date = date
|
||||
@@ -45,7 +47,7 @@ class MealPlanModel(SqlAlchemyBase, BaseMixins):
|
||||
endDate = sa.Column(sa.Date)
|
||||
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.endDate = endDate
|
||||
self.meals = [Meal(**meal) for meal in meals]
|
||||
|
||||
@@ -6,6 +6,7 @@ import sqlalchemy as sa
|
||||
import sqlalchemy.orm as orm
|
||||
from db.sql.model_base import BaseMixins, SqlAlchemyBase
|
||||
from sqlalchemy.ext.orderinglist import ordering_list
|
||||
from utils.logger import logger
|
||||
|
||||
|
||||
class ApiExtras(SqlAlchemyBase):
|
||||
@@ -23,36 +24,80 @@ class ApiExtras(SqlAlchemyBase):
|
||||
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("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):
|
||||
__tablename__ = "categories"
|
||||
id = sa.Column(sa.Integer, primary_key=True)
|
||||
name = sa.Column(sa.String, index=True)
|
||||
recipes = orm.relationship(
|
||||
"RecipeModel",
|
||||
secondary=recipes2categories,
|
||||
back_populates="categories"
|
||||
"RecipeModel", secondary=recipes2categories, back_populates="categories"
|
||||
)
|
||||
|
||||
def __init__(self, name) -> None:
|
||||
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):
|
||||
return self.name
|
||||
|
||||
def dict(self):
|
||||
return {"id": self.id, "name": self.name, "recipes": [x.dict() for x in self.recipes]}
|
||||
|
||||
|
||||
class Tag(SqlAlchemyBase):
|
||||
__tablename__ = "tags"
|
||||
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)
|
||||
recipes = orm.relationship(
|
||||
"RecipeModel", secondary=recipes2tags, back_populates="tags"
|
||||
)
|
||||
|
||||
def to_str(self):
|
||||
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):
|
||||
__tablename__ = "notes"
|
||||
@@ -128,25 +173,20 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
|
||||
# Mealie Specific
|
||||
slug = sa.Column(sa.String, index=True, unique=True)
|
||||
categories: List = orm.relationship(
|
||||
"Category",
|
||||
secondary=recipes2categories,
|
||||
back_populates="recipes",
|
||||
"Category", secondary=recipes2categories, back_populates="recipes"
|
||||
)
|
||||
tags: List[Tag] = orm.relationship(
|
||||
"Tag",
|
||||
cascade="all, delete",
|
||||
"Tag", secondary=recipes2tags, back_populates="recipes"
|
||||
)
|
||||
dateAdded = sa.Column(sa.Date, default=date.today)
|
||||
notes: List[Note] = orm.relationship(
|
||||
"Note",
|
||||
cascade="all, delete",
|
||||
)
|
||||
notes: List[Note] = orm.relationship("Note", cascade="all, delete")
|
||||
rating = sa.Column(sa.Integer)
|
||||
orgURL = sa.Column(sa.String)
|
||||
extras: List[ApiExtras] = orm.relationship("ApiExtras", cascade="all, delete")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
session,
|
||||
name: str = None,
|
||||
description: str = None,
|
||||
image: str = None,
|
||||
@@ -182,8 +222,12 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
|
||||
|
||||
# Mealie Specific
|
||||
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.notes = [Note(**note) for note in notes]
|
||||
self.rating = rating
|
||||
@@ -212,10 +256,11 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
|
||||
extras: dict = None,
|
||||
):
|
||||
"""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)
|
||||
|
||||
self.__init__(
|
||||
session=session,
|
||||
name=name,
|
||||
description=description,
|
||||
image=image,
|
||||
|
||||
@@ -8,7 +8,7 @@ class SiteSettingsModel(SqlAlchemyBase):
|
||||
name = sa.Column(sa.String, primary_key=True)
|
||||
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.webhooks = WebHookModel(**webhooks)
|
||||
|
||||
@@ -33,7 +33,7 @@ class WebHookModel(SqlAlchemyBase, BaseMixins):
|
||||
enabled = sa.Column(sa.Boolean, default=False)
|
||||
|
||||
def __init__(
|
||||
self, webhookURLs: list, webhookTime: str, enabled: bool = False
|
||||
self, webhookURLs: list, webhookTime: str, enabled: bool = False, session=None
|
||||
) -> None:
|
||||
|
||||
self.webhookURLs = [WebhookURLModel(url=x) for x in webhookURLs]
|
||||
|
||||
@@ -8,7 +8,7 @@ class SiteThemeModel(SqlAlchemyBase):
|
||||
name = sa.Column(sa.String, primary_key=True)
|
||||
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.colors = ThemeColorsModel(**colors)
|
||||
|
||||
|
||||
@@ -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
|
||||
recipes: List[Recipe]
|
||||
|
||||
class Config:
|
||||
schema_extra = {
|
||||
"example": {
|
||||
"name": "Breakfast"
|
||||
}
|
||||
}
|
||||
schema_extra = {"example": {"id": 1, "name": "dinner", "recipes": [{}]}}
|
||||
|
||||
@@ -11,10 +11,10 @@ from sqlalchemy.orm.session import Session
|
||||
from starlette.responses import FileResponse
|
||||
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():
|
||||
"""Returns a list of avaiable .zip files for import into Mealie."""
|
||||
imports = []
|
||||
@@ -31,7 +31,7 @@ def available_imports():
|
||||
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)):
|
||||
"""Generates a backup of the recipe database in json format."""
|
||||
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(...)):
|
||||
""" Upload a .zip File to later be imported into Mealie """
|
||||
dest = BACKUP_DIR.joinpath(archive.filename)
|
||||
@@ -65,7 +65,7 @@ def upload_backup_zipfile(archive: UploadFile = 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):
|
||||
""" Upload a .zip File to later be imported into Mealie """
|
||||
file = BACKUP_DIR.joinpath(file_name)
|
||||
@@ -78,7 +78,7 @@ def upload_nextcloud_zipfile(file_name: str):
|
||||
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(
|
||||
file_name: str, import_data: ImportJob, db: Session = Depends(generate_session)
|
||||
):
|
||||
@@ -98,20 +98,16 @@ def import_database(
|
||||
return imported
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/api/backups/{backup_name}/delete/",
|
||||
tags=["Import / Export"],
|
||||
status_code=200,
|
||||
)
|
||||
def delete_backup(backup_name: str):
|
||||
@router.delete("/{file_name}/delete/", tags=["Import / Export"], status_code=200)
|
||||
def delete_backup(file_name: str):
|
||||
""" Removes a database backup from the file system """
|
||||
|
||||
try:
|
||||
BACKUP_DIR.joinpath(backup_name).unlink()
|
||||
BACKUP_DIR.joinpath(file_name).unlink()
|
||||
except:
|
||||
HTTPException(
|
||||
status_code=400,
|
||||
detail=SnackResponse.error("Unable to Delete Backup. See Log File"),
|
||||
)
|
||||
|
||||
return SnackResponse.success(f"{backup_name} Deleted")
|
||||
return SnackResponse.success(f"{file_name} Deleted")
|
||||
|
||||
@@ -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()
|
||||
@@ -6,17 +6,17 @@ from services.meal_services import MealPlan
|
||||
from sqlalchemy.orm.session import Session
|
||||
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)):
|
||||
""" Returns a list of all available Meal Plan """
|
||||
|
||||
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)):
|
||||
""" Creates a meal plan database entry """
|
||||
data.process_meals(db)
|
||||
@@ -30,7 +30,7 @@ def set_meal_plan(data: MealPlan, db: Session = Depends(generate_session)):
|
||||
return SnackResponse.success("Mealplan Created")
|
||||
|
||||
|
||||
@router.post("/api/meal-plan/{plan_id}/update/")
|
||||
@router.post("/{plan_id}/update/")
|
||||
def update_meal_plan(
|
||||
plan_id: str, meal_plan: MealPlan, db: Session = Depends(generate_session)
|
||||
):
|
||||
@@ -49,7 +49,7 @@ def update_meal_plan(
|
||||
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)):
|
||||
""" 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")
|
||||
|
||||
|
||||
@router.get(
|
||||
"/api/meal-plan/today/",
|
||||
tags=["Meal Plan"],
|
||||
)
|
||||
@router.get("/today/", tags=["Meal Plan"])
|
||||
def get_today(db: Session = Depends(generate_session)):
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
@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)):
|
||||
""" Returns the meal plan data for this week """
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ from services.migrations.nextcloud import migrate as nextcloud_migrate
|
||||
from sqlalchemy.orm.session import Session
|
||||
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():
|
||||
""" Returns a list of avaiable directories that can be imported into Mealie """
|
||||
response_data = []
|
||||
@@ -35,7 +35,7 @@ def get_avaiable_nextcloud_imports():
|
||||
return response_data
|
||||
|
||||
|
||||
@router.post("/api/migrations/{type}/{file_name}/import/")
|
||||
@router.post("/{type}/{file_name}/import/")
|
||||
def import_nextcloud_directory(
|
||||
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")
|
||||
|
||||
|
||||
@router.delete("/api/migrations/{folder}/{file}/delete/")
|
||||
def delete_migration_data(folder: str, file: str):
|
||||
@router.delete("/{type}/{file_name}/delete/")
|
||||
def delete_migration_data(type: str, file_name: str):
|
||||
""" 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():
|
||||
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()}")
|
||||
|
||||
|
||||
@router.post("/api/migrations/{type}/upload/")
|
||||
@router.post("/{type}/upload/")
|
||||
def upload_nextcloud_zipfile(type: str, archive: UploadFile = File(...)):
|
||||
""" Upload a .zip File to later be imported into Mealie """
|
||||
dir = MIGRATION_DIR.joinpath(type)
|
||||
|
||||
@@ -5,24 +5,23 @@ from sqlalchemy.orm.session import Session
|
||||
from utils.post_webhooks import post_webhooks
|
||||
from utils.snackbar import SnackResponse
|
||||
|
||||
router = APIRouter(tags=["Settings"])
|
||||
router = APIRouter(prefix="/api/site-settings", tags=["Settings"])
|
||||
|
||||
|
||||
@router.get("/api/site-settings/")
|
||||
@router.get("/")
|
||||
def get_main_settings(db: Session = Depends(generate_session)):
|
||||
""" Returns basic site settings """
|
||||
|
||||
return SiteSettings.get_site_settings(db)
|
||||
|
||||
|
||||
@router.post("/api/site-settings/webhooks/test/")
|
||||
@router.post("/webhooks/test/")
|
||||
def test_webhooks():
|
||||
""" Run the function to test your webhooks """
|
||||
|
||||
return post_webhooks()
|
||||
|
||||
|
||||
@router.post("/api/site-settings/update/")
|
||||
@router.post("/update/")
|
||||
def update_settings(data: SiteSettings, db: Session = Depends(generate_session)):
|
||||
""" Returns Site Settings """
|
||||
data.update(db)
|
||||
@@ -36,20 +35,20 @@ def update_settings(data: SiteSettings, db: Session = Depends(generate_session))
|
||||
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)):
|
||||
""" Returns all site themes """
|
||||
|
||||
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)):
|
||||
""" Returns a named theme """
|
||||
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)):
|
||||
""" Creates a site color theme database entry """
|
||||
data.save_to_db(db)
|
||||
@@ -63,7 +62,7 @@ def create_theme(data: SiteTheme, db: Session = Depends(generate_session)):
|
||||
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(
|
||||
theme_name: str, data: SiteTheme, db: Session = Depends(generate_session)
|
||||
):
|
||||
@@ -79,7 +78,7 @@ def update_theme(
|
||||
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)):
|
||||
""" Deletes theme from the database """
|
||||
SiteTheme.delete_theme(db, theme_name)
|
||||
|
||||
5
mealie/run.sh
Normal file
5
mealie/run.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
## Run Migration
|
||||
|
||||
|
||||
## Start Application
|
||||
uvicorn app:app --host 0.0.0.0 --port 80
|
||||
Reference in New Issue
Block a user