+
mdi-download
@@ -118,6 +111,9 @@ export default {
},
},
methods: {
+ assetURL(assetName) {
+ return api.recipes.recipeAssetPath(this.slug, assetName);
+ },
setFileObject(obj) {
this.fileObject = obj;
},
diff --git a/frontend/src/components/Recipe/RecipeViewer/index.vue b/frontend/src/components/Recipe/RecipeViewer/index.vue
index d4a4fac9a..74498da71 100644
--- a/frontend/src/components/Recipe/RecipeViewer/index.vue
+++ b/frontend/src/components/Recipe/RecipeViewer/index.vue
@@ -18,7 +18,7 @@
color="secondary darken-1"
class="rounded-sm static"
>
- {{ yields }}
+ {{ recipe.yields }}
diff --git a/frontend/src/pages/Admin/Dashboard/BackupViewer.vue b/frontend/src/pages/Admin/Dashboard/BackupViewer.vue
index 5ef125968..6752d8dd2 100644
--- a/frontend/src/pages/Admin/Dashboard/BackupViewer.vue
+++ b/frontend/src/pages/Admin/Dashboard/BackupViewer.vue
@@ -71,7 +71,7 @@ export default {
components: { StatCard, ImportDialog, TheUploadBtn, ImportSummaryDialog },
data() {
return {
- color: "secondary",
+ color: "accent",
selectedName: "",
selectedDate: "",
loading: false,
diff --git a/frontend/src/pages/Admin/Dashboard/EventViewer.vue b/frontend/src/pages/Admin/Dashboard/EventViewer.vue
index 5070c677b..e03186f94 100644
--- a/frontend/src/pages/Admin/Dashboard/EventViewer.vue
+++ b/frontend/src/pages/Admin/Dashboard/EventViewer.vue
@@ -54,7 +54,7 @@ export default {
components: { StatCard },
data() {
return {
- color: "secondary",
+ color: "accent",
total: 0,
events: [],
icons: {
diff --git a/mealie/app.py b/mealie/app.py
index 162351990..f493e2432 100644
--- a/mealie/app.py
+++ b/mealie/app.py
@@ -1,18 +1,20 @@
import uvicorn
from fastapi import FastAPI
-from mealie.core import root_logger
from mealie.core.config import APP_VERSION, settings
-from mealie.routes import backup_routes, debug_routes, migration_routes, theme_routes, utility_routes
+from mealie.core.root_logger import get_logger
+from mealie.routes import (backup_routes, debug_routes, migration_routes,
+ theme_routes, utility_routes)
from mealie.routes.about import about_router
-from mealie.routes.groups import groups
-from mealie.routes.mealplans import mealplans
-from mealie.routes.recipe import router as recipe_router
-from mealie.routes.site_settings import all_settings
-from mealie.routes.users import users
+from mealie.routes.groups import groups_router
+from mealie.routes.mealplans import meal_plan_router
+from mealie.routes.media import media_router
+from mealie.routes.recipe import recipe_router
+from mealie.routes.site_settings import settings_router
+from mealie.routes.users import user_router
from mealie.services.events import create_general_event
-logger = root_logger.get_logger()
+logger = get_logger()
app = FastAPI(
title="Mealie",
@@ -29,15 +31,16 @@ def start_scheduler():
def api_routers():
# Authentication
- app.include_router(users.router)
- app.include_router(groups.router)
+ app.include_router(user_router)
+ app.include_router(groups_router)
# Recipes
app.include_router(recipe_router)
+ app.include_router(media_router)
app.include_router(about_router)
# Meal Routes
- app.include_router(mealplans.router)
+ app.include_router(meal_plan_router)
# Settings Routes
- app.include_router(all_settings.router)
+ app.include_router(settings_router)
app.include_router(theme_routes.router)
# Backups/Imports Routes
app.include_router(backup_routes.router)
diff --git a/mealie/routes/about/__init__.py b/mealie/routes/about/__init__.py
index e36affaa9..70eb8f5c8 100644
--- a/mealie/routes/about/__init__.py
+++ b/mealie/routes/about/__init__.py
@@ -1,7 +1,7 @@
from fastapi import APIRouter
-from .events import router as events_router
+from . import events
about_router = APIRouter(prefix="/api/about")
-about_router.include_router(events_router)
+about_router.include_router(events.router)
diff --git a/mealie/routes/groups/__init__.py b/mealie/routes/groups/__init__.py
index e69de29bb..f8935bdb6 100644
--- a/mealie/routes/groups/__init__.py
+++ b/mealie/routes/groups/__init__.py
@@ -0,0 +1,8 @@
+from fastapi import APIRouter
+
+from . import crud, groups
+
+groups_router = APIRouter()
+
+groups_router.include_router(crud.router)
+groups_router.include_router(groups.router)
diff --git a/mealie/routes/mealplans/__init__.py b/mealie/routes/mealplans/__init__.py
index e69de29bb..c2dfae352 100644
--- a/mealie/routes/mealplans/__init__.py
+++ b/mealie/routes/mealplans/__init__.py
@@ -0,0 +1,9 @@
+from fastapi import APIRouter
+
+from . import crud, helpers, mealplans
+
+meal_plan_router = APIRouter()
+
+meal_plan_router.include_router(crud.router)
+meal_plan_router.include_router(helpers.router)
+meal_plan_router.include_router(mealplans.router)
diff --git a/mealie/routes/media/__init__.py b/mealie/routes/media/__init__.py
new file mode 100644
index 000000000..e28579ee6
--- /dev/null
+++ b/mealie/routes/media/__init__.py
@@ -0,0 +1,7 @@
+from fastapi import APIRouter
+
+from . import recipe
+
+media_router = APIRouter(prefix="/api/media", tags=["Site Media"])
+
+media_router.include_router(recipe.router)
diff --git a/mealie/routes/media/recipe.py b/mealie/routes/media/recipe.py
new file mode 100644
index 000000000..ad8ffac4e
--- /dev/null
+++ b/mealie/routes/media/recipe.py
@@ -0,0 +1,41 @@
+from enum import Enum
+
+from fastapi import APIRouter, HTTPException, status
+from mealie.schema.recipe import Recipe
+from starlette.responses import FileResponse
+
+"""
+These routes are for development only! These assets are served by Caddy when not
+in development mode. If you make changes, be sure to test the production container.
+"""
+
+router = APIRouter(prefix="/recipes")
+
+
+class ImageType(str, Enum):
+ original = "original.webp"
+ small = "min-original.webp"
+ tiny = "tiny-original.webp"
+
+
+@router.get("/{recipe_slug}/images/{file_name}")
+async def get_recipe_img(recipe_slug: str, file_name: ImageType = ImageType.original):
+ """Takes in a recipe slug, returns the static image. This route is proxied in the docker image
+ and should not hit the API in production"""
+ recipe_image = Recipe(slug=recipe_slug).image_dir.joinpath(file_name.value)
+
+ if recipe_image:
+ return FileResponse(recipe_image)
+ else:
+ raise HTTPException(status.HTTP_404_NOT_FOUND)
+
+
+@router.get("/{recipe_slug}/assets/{file_name}")
+async def get_recipe_asset(recipe_slug: str, file_name: str):
+ """ Returns a recipe asset """
+ file = Recipe(slug=recipe_slug).asset_dir.joinpath(file_name)
+
+ try:
+ return FileResponse(file)
+ except Exception:
+ raise HTTPException(status.HTTP_404_NOT_FOUND)
diff --git a/mealie/routes/media/user.py b/mealie/routes/media/user.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/mealie/routes/recipe/__init__.py b/mealie/routes/recipe/__init__.py
index 1d54034f0..fb9a0d55b 100644
--- a/mealie/routes/recipe/__init__.py
+++ b/mealie/routes/recipe/__init__.py
@@ -1,10 +1,9 @@
from fastapi import APIRouter
-from mealie.routes.recipe import all_recipe_routes, category_routes, recipe_crud_routes, recipe_media, tag_routes
+from mealie.routes.recipe import all_recipe_routes, category_routes, recipe_crud_routes, tag_routes
-router = APIRouter()
+recipe_router = APIRouter()
-router.include_router(all_recipe_routes.router)
-router.include_router(recipe_crud_routes.router)
-router.include_router(recipe_media.router)
-router.include_router(category_routes.router)
-router.include_router(tag_routes.router)
+recipe_router.include_router(all_recipe_routes.router)
+recipe_router.include_router(recipe_crud_routes.router)
+recipe_router.include_router(category_routes.router)
+recipe_router.include_router(tag_routes.router)
diff --git a/mealie/routes/recipe/recipe_crud_routes.py b/mealie/routes/recipe/recipe_crud_routes.py
index 6604b84e6..110393050 100644
--- a/mealie/routes/recipe/recipe_crud_routes.py
+++ b/mealie/routes/recipe/recipe_crud_routes.py
@@ -1,13 +1,17 @@
+from shutil import copyfileobj
+
from fastapi import APIRouter, Depends, File, Form, HTTPException, status
+from fastapi.datastructures import UploadFile
from mealie.core.root_logger import get_logger
from mealie.db.database import db
from mealie.db.db_setup import generate_session
from mealie.routes.deps import get_current_user
-from mealie.schema.recipe import Recipe, RecipeURLIn
+from mealie.schema.recipe import Recipe, RecipeAsset, RecipeURLIn
from mealie.services.events import create_recipe_event
from mealie.services.image.image import scrape_image, write_image
from mealie.services.recipe.media import check_assets, delete_assets
from mealie.services.scraper.scraper import create_from_url
+from slugify import slugify
from sqlalchemy.orm.session import Session
router = APIRouter(prefix="/api/recipes", tags=["Recipe CRUD"])
@@ -126,3 +130,30 @@ def scrape_image_url(
""" Removes an existing image and replaces it with the incoming file. """
scrape_image(url.url, recipe_slug)
+
+
+@router.post("/{recipe_slug}/assets", response_model=RecipeAsset)
+def upload_recipe_asset(
+ recipe_slug: str,
+ name: str = Form(...),
+ icon: str = Form(...),
+ extension: str = Form(...),
+ file: UploadFile = File(...),
+ session: Session = Depends(generate_session),
+ current_user=Depends(get_current_user),
+):
+ """ Upload a file to store as a recipe asset """
+ file_name = slugify(name) + "." + extension
+ asset_in = RecipeAsset(name=name, icon=icon, file_name=file_name)
+ dest = Recipe(slug=recipe_slug).asset_dir.joinpath(file_name)
+
+ with dest.open("wb") as buffer:
+ copyfileobj(file.file, buffer)
+
+ if not dest.is_file():
+ raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ recipe: Recipe = db.recipes.get(session, recipe_slug)
+ recipe.assets.append(asset_in)
+ db.recipes.update(session, recipe_slug, recipe.dict())
+ return asset_in
diff --git a/mealie/routes/recipe/recipe_media.py b/mealie/routes/recipe/recipe_media.py
deleted file mode 100644
index e7c3402a5..000000000
--- a/mealie/routes/recipe/recipe_media.py
+++ /dev/null
@@ -1,70 +0,0 @@
-import shutil
-from enum import Enum
-
-from fastapi import APIRouter, Depends, File, Form, HTTPException, status
-from fastapi.datastructures import UploadFile
-from mealie.db.database import db
-from mealie.db.db_setup import generate_session
-from mealie.routes.deps import get_current_user
-from mealie.schema.recipe import Recipe, RecipeAsset
-from slugify import slugify
-from sqlalchemy.orm.session import Session
-from starlette.responses import FileResponse
-
-router = APIRouter(prefix="/api/recipes/media", tags=["Recipe Media"])
-
-
-class ImageType(str, Enum):
- original = "original.webp"
- small = "min-original.webp"
- tiny = "tiny-original.webp"
-
-
-@router.get("/{recipe_slug}/images/{file_name}")
-async def get_recipe_img(recipe_slug: str, file_name: ImageType = ImageType.original):
- """Takes in a recipe slug, returns the static image. This route is proxied in the docker image
- and should not hit the API in production"""
- recipe_image = Recipe(slug=recipe_slug).image_dir.joinpath(file_name.value)
-
- if recipe_image:
- return FileResponse(recipe_image)
- else:
- raise HTTPException(status.HTTP_404_NOT_FOUND)
-
-
-@router.get("/{recipe_slug}/assets/{file_name}")
-async def get_recipe_asset(recipe_slug: str, file_name: str):
- """ Returns a recipe asset """
- file = Recipe(slug=recipe_slug).asset_dir.joinpath(file_name)
-
- try:
- return FileResponse(file)
- except Exception:
- raise HTTPException(status.HTTP_404_NOT_FOUND)
-
-
-@router.post("/{recipe_slug}/assets", response_model=RecipeAsset)
-def upload_recipe_asset(
- recipe_slug: str,
- name: str = Form(...),
- icon: str = Form(...),
- extension: str = Form(...),
- file: UploadFile = File(...),
- session: Session = Depends(generate_session),
- current_user=Depends(get_current_user),
-):
- """ Upload a file to store as a recipe asset """
- file_name = slugify(name) + "." + extension
- asset_in = RecipeAsset(name=name, icon=icon, file_name=file_name)
- dest = Recipe(slug=recipe_slug).asset_dir.joinpath(file_name)
-
- with dest.open("wb") as buffer:
- shutil.copyfileobj(file.file, buffer)
-
- if not dest.is_file():
- raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR)
-
- recipe: Recipe = db.recipes.get(session, recipe_slug)
- recipe.assets.append(asset_in)
- db.recipes.update(session, recipe_slug, recipe.dict())
- return asset_in
diff --git a/mealie/routes/site_settings/__init__.py b/mealie/routes/site_settings/__init__.py
index e69de29bb..ec356e63f 100644
--- a/mealie/routes/site_settings/__init__.py
+++ b/mealie/routes/site_settings/__init__.py
@@ -0,0 +1,9 @@
+from fastapi import APIRouter
+
+from . import all_settings, custom_pages, site_settings
+
+settings_router = APIRouter()
+
+settings_router.include_router(all_settings.router)
+settings_router.include_router(custom_pages.router)
+settings_router.include_router(site_settings.router)
diff --git a/mealie/routes/users/__init__.py b/mealie/routes/users/__init__.py
index e69de29bb..c2e751728 100644
--- a/mealie/routes/users/__init__.py
+++ b/mealie/routes/users/__init__.py
@@ -0,0 +1,9 @@
+from fastapi import APIRouter
+
+from . import auth, crud, sign_up
+
+user_router = APIRouter()
+
+user_router.include_router(auth.router)
+user_router.include_router(crud.router)
+user_router.include_router(sign_up.router)
diff --git a/mealie/routes/users/users.py b/mealie/routes/users/users.py
deleted file mode 100644
index 9f3088a99..000000000
--- a/mealie/routes/users/users.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from fastapi import APIRouter
-from mealie.routes.users import auth, crud, sign_up
-
-router = APIRouter()
-
-router.include_router(sign_up.router)
-router.include_router(auth.router)
-router.include_router(sign_up.router)
-router.include_router(crud.router)