diff --git a/dev/scripts/output/app_routes.py b/dev/scripts/output/app_routes.py
index f46ec71025e4..1bbb8e9dda91 100644
--- a/dev/scripts/output/app_routes.py
+++ b/dev/scripts/output/app_routes.py
@@ -74,6 +74,9 @@ class AppRoutes:
def groups_id(self, id):
return f"{self.prefix}/groups/{id}"
+ def meal_plans_id(self, id):
+ return f"{self.prefix}/meal-plans/{id}"
+
def meal_plans_id_shopping_list(self, id):
return f"{self.prefix}/meal-plans/{id}/shopping-list"
@@ -122,6 +125,12 @@ class AppRoutes:
def users_id(self, id):
return f"{self.prefix}/users/{id}"
+ def users_id_favorites(self, id):
+ return f"{self.prefix}/users/{id}/favorites/"
+
+ def users_id_favorites_slug(self, id, slug):
+ return f"{self.prefix}/users/{id}/favorites/{slug}"
+
def users_id_image(self, id):
return f"{self.prefix}/users/{id}/image"
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index e2bf3b26adf4..ddcac105c591 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -17673,7 +17673,6 @@
"integrity": "sha512-8q67ORQ9O0Ms0nlqsXTVhaBefRBaLrzPxOewAZhdcO7onHwcO5/wRdWtHhZgfpCZlhY7NogkU16z3WnorSSkEA==",
"dev": true,
"requires": {
- "@babel/core": "^7.11.0",
"@babel/helper-compilation-targets": "^7.9.6",
"@babel/helper-module-imports": "^7.8.3",
"@babel/plugin-proposal-class-properties": "^7.8.3",
@@ -17686,7 +17685,6 @@
"@vue/babel-plugin-jsx": "^1.0.3",
"@vue/babel-preset-jsx": "^1.2.4",
"babel-plugin-dynamic-import-node": "^2.3.3",
- "core-js": "^3.6.5",
"core-js-compat": "^3.6.5",
"semver": "^6.1.0"
}
@@ -17849,7 +17847,8 @@
"version": "4.5.12",
"resolved": "https://registry.npmjs.org/@vue/cli-plugin-vuex/-/cli-plugin-vuex-4.5.12.tgz",
"integrity": "sha512-STgbvNv/3iHAKArc18b/qjN7RX1FTrfxPeHH26GOr/A8lJes7+CSluZZ8E5R7Zr/vL0zOqOkUVDAjFXVf4zWQA==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"@vue/cli-service": {
"version": "4.5.12",
@@ -18141,7 +18140,8 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@vue/preload-webpack-plugin/-/preload-webpack-plugin-1.1.2.tgz",
"integrity": "sha512-LIZMuJk38pk9U9Ur4YzHjlIyMuxPlACdBIHH9/nGYVTsaGKOSnSuELiE8vS9wa+dJpIYspYUOqk+L1Q4pgHQHQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"@vue/web-component-wrapper": {
"version": "1.3.0",
@@ -18361,7 +18361,8 @@
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
"integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"acorn-walk": {
"version": "7.2.0",
@@ -18400,13 +18401,15 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
"integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"alphanum-sort": {
"version": "1.0.2",
@@ -28209,7 +28212,8 @@
"vuetify": {
"version": "2.4.11",
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-2.4.11.tgz",
- "integrity": "sha512-xFNwr95tFRfbyGNg5DBuUkWaKazMBr+ptzoSSL4PGrI0qItY5Vuusxh+ETPtjUXxwz76v5zVtGvF5rWvGQjy7A=="
+ "integrity": "sha512-xFNwr95tFRfbyGNg5DBuUkWaKazMBr+ptzoSSL4PGrI0qItY5Vuusxh+ETPtjUXxwz76v5zVtGvF5rWvGQjy7A==",
+ "requires": {}
},
"vuetify-loader": {
"version": "1.7.2",
@@ -28259,7 +28263,8 @@
"vuex": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz",
- "integrity": "sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw=="
+ "integrity": "sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==",
+ "requires": {}
},
"vuex-persistedstate": {
"version": "4.0.0-beta.3",
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index bc433d6df936..28155a907a99 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -53,6 +53,7 @@ export default {
this.$store.dispatch("requestRecentRecipes");
this.$store.dispatch("refreshToken");
this.$store.dispatch("requestCurrentGroup");
+ this.$store.dispatch("requestUserData");
this.$store.dispatch("requestCategories");
this.$store.dispatch("requestTags");
this.darkModeSystemCheck();
diff --git a/frontend/src/api/api-utils.js b/frontend/src/api/api-utils.js
index 597423f2eee7..c492052c26fb 100644
--- a/frontend/src/api/api-utils.js
+++ b/frontend/src/api/api-utils.js
@@ -49,7 +49,7 @@ const apiReq = {
return handleResponse(response, getSuccessText);
},
- get: function(url, data, getErrorText = defaultErrorText) {
+ get: async function(url, data, getErrorText = defaultErrorText) {
return axios.get(url, data).catch(function(error) {
handleError(error, getErrorText);
});
diff --git a/frontend/src/api/apiRoutes.js b/frontend/src/api/apiRoutes.js
index a978ccd3b3ee..b5d1c5b3c8ef 100644
--- a/frontend/src/api/apiRoutes.js
+++ b/frontend/src/api/apiRoutes.js
@@ -54,6 +54,7 @@ export const API_ROUTES = {
categoriesCategory: (category) => `${prefix}/categories/${category}`,
debugLogNum: (num) => `${prefix}/debug/log/${num}`,
groupsId: (id) => `${prefix}/groups/${id}`,
+ mealPlansId: (id) => `${prefix}/meal-plans/${id}`,
mealPlansIdShoppingList: (id) => `${prefix}/meal-plans/${id}/shopping-list`,
mealPlansPlanId: (plan_id) => `${prefix}/meal-plans/${plan_id}`,
mediaRecipesRecipeSlugAssetsFileName: (recipe_slug, file_name) => `${prefix}/media/recipes/${recipe_slug}/assets/${file_name}`,
@@ -70,6 +71,8 @@ export const API_ROUTES = {
themesId: (id) => `${prefix}/themes/${id}`,
usersApiTokensTokenId: (token_id) => `${prefix}/users-tokens/${token_id}`,
usersId: (id) => `${prefix}/users/${id}`,
+ usersIdFavorites: (id) => `${prefix}/users/${id}/favorites`,
+ usersIdFavoritesSlug: (id, slug) => `${prefix}/users/${id}/favorites/${slug}`,
usersIdImage: (id) => `${prefix}/users/${id}/image`,
usersIdPassword: (id) => `${prefix}/users/${id}/password`,
usersIdResetPassword: (id) => `${prefix}/users/${id}/reset-password`,
diff --git a/frontend/src/api/users.js b/frontend/src/api/users.js
index 68e42c4ae6af..f6db9dfac851 100644
--- a/frontend/src/api/users.js
+++ b/frontend/src/api/users.js
@@ -1,4 +1,5 @@
import { baseURL } from "./api-utils";
+import { API_ROUTES } from "./apiRoutes";
import { apiReq } from "./api-utils";
import axios from "axios";
import i18n from "@/i18n.js";
@@ -91,6 +92,27 @@ export const userAPI = {
const response = await apiReq.delete(usersURLs.userAPIDelete(id));
return response.data;
},
+ /** Adds a Recipe to the users favorites
+ * @param id
+ */
+ async getFavorites(id) {
+ const response = await apiReq.get(API_ROUTES.usersIdFavorites(id));
+ return response.data;
+ },
+ /** Adds a Recipe to the users favorites
+ * @param id
+ */
+ async addFavorite(id, slug) {
+ const response = await apiReq.post(API_ROUTES.usersIdFavoritesSlug(id, slug));
+ return response.data;
+ },
+ /** Adds a Recipe to the users favorites
+ * @param id
+ */
+ async removeFavorite(id, slug) {
+ const response = await apiReq.delete(API_ROUTES.usersIdFavoritesSlug(id, slug));
+ return response.data;
+ },
};
const deleteErrorText = response => {
diff --git a/frontend/src/components/Login/LoginForm.vue b/frontend/src/components/Login/LoginForm.vue
index 63f9654fb9c1..fad4ea0e9139 100644
--- a/frontend/src/components/Login/LoginForm.vue
+++ b/frontend/src/components/Login/LoginForm.vue
@@ -87,8 +87,7 @@ export default {
this.clear();
this.$store.commit("setToken", response.data.access_token);
this.$emit("logged-in");
- let user = await api.users.self();
- this.$store.commit("setUserData", user);
+ this.$store.dispatch("requestUserData");
}
this.loading = false;
diff --git a/frontend/src/components/MealPlan/MealPlanCard.vue b/frontend/src/components/MealPlan/MealPlanCard.vue
index 7f7078865710..4521c8d3415b 100644
--- a/frontend/src/components/MealPlan/MealPlanCard.vue
+++ b/frontend/src/components/MealPlan/MealPlanCard.vue
@@ -106,14 +106,7 @@ export default {
},
};
},
- watch: {
- value(val) {
- console.log(val);
- },
- },
- mounted() {
- console.log(this.value);
- },
+
methods: {
getImage(slug) {
if (slug) {
@@ -161,7 +154,6 @@ export default {
this.setSide(this.customMeal.name, this.customMeal.slug, this.customMeal.description);
break;
}
- console.log("Hello World");
this.customMeal = { name: "", slug: null, description: "" };
},
},
diff --git a/frontend/src/components/MealPlan/MealPlanEditor.vue b/frontend/src/components/MealPlan/MealPlanEditor.vue
index cab725912a6f..80f0f0bef469 100644
--- a/frontend/src/components/MealPlan/MealPlanEditor.vue
+++ b/frontend/src/components/MealPlan/MealPlanEditor.vue
@@ -28,9 +28,7 @@ export default {
props: {
mealPlan: Object,
},
- mounted() {
- console.log(this.mealPlan);
- },
+
methods: {
formatDate(timestamp) {
let dateObject = new Date(timestamp);
diff --git a/frontend/src/components/Recipe/FavoriteBadge.vue b/frontend/src/components/Recipe/FavoriteBadge.vue
new file mode 100644
index 000000000000..458fc2916752
--- /dev/null
+++ b/frontend/src/components/Recipe/FavoriteBadge.vue
@@ -0,0 +1,54 @@
+
+
+
+ {{ isFavorite ? "mdi-heart" : "mdi-heart-outline" }}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/components/Recipe/MobileRecipeCard.vue b/frontend/src/components/Recipe/MobileRecipeCard.vue
index 6fd93a86c4e9..2c03c1758694 100644
--- a/frontend/src/components/Recipe/MobileRecipeCard.vue
+++ b/frontend/src/components/Recipe/MobileRecipeCard.vue
@@ -23,6 +23,7 @@
{{ name }}
{{ description }}
+
diff --git a/frontend/src/components/Recipe/RecipeCard.vue b/frontend/src/components/Recipe/RecipeCard.vue
index ed9d1d6c8a2e..1a7c0709d12f 100644
--- a/frontend/src/components/Recipe/RecipeCard.vue
+++ b/frontend/src/components/Recipe/RecipeCard.vue
@@ -23,6 +23,7 @@
+
@@ -33,18 +34,14 @@
+
+
diff --git a/frontend/src/routes/recipes.js b/frontend/src/routes/recipes.js
index d2dcf307f554..d21588772eaa 100644
--- a/frontend/src/routes/recipes.js
+++ b/frontend/src/routes/recipes.js
@@ -3,11 +3,13 @@ const NewRecipe = () => import(/* webpackChunkName: "recipes" */ "@/pages/Recipe
const CustomPage = () => import(/* webpackChunkName: "recipes" */ "@/pages/Recipes/CustomPage");
const AllRecipes = () => import(/* webpackChunkName: "recipes" */ "@/pages/Recipes/AllRecipes");
const CategoryTagPage = () => import(/* webpackChunkName: "recipes" */ "@/pages/Recipes/CategoryTagPage");
+const Favorites = () => import(/* webpackChunkName: "recipes" */ "@/pages/Recipes/Favorites");
import { api } from "@/api";
export const recipeRoutes = [
// Recipes
{ path: "/recipes/all", component: AllRecipes },
+ { path: "/user/:id/favorites", component: Favorites },
{ path: "/recipes/tag/:tag", component: CategoryTagPage },
{ path: "/recipes/tag", component: CategoryTagPage },
{ path: "/recipes/category", component: CategoryTagPage },
diff --git a/frontend/src/store/modules/recipes.js b/frontend/src/store/modules/recipes.js
index c9f9586bee4a..f2270eb941f2 100644
--- a/frontend/src/store/modules/recipes.js
+++ b/frontend/src/store/modules/recipes.js
@@ -41,7 +41,6 @@ const actions = {
this.commit("setRecentRecipes", hash);
},
async requestAllRecipes({ getters }) {
- console.log("All Recipes");
const all = getters.getAllRecipes;
const payload = await api.recipes.allSummary(all.length, 9999);
const hash = Object.fromEntries([...all, ...payload].map(e => [e.id, e]));
diff --git a/frontend/src/store/modules/userSettings.js b/frontend/src/store/modules/userSettings.js
index 1f2c56dbe0c4..906017f961aa 100644
--- a/frontend/src/store/modules/userSettings.js
+++ b/frontend/src/store/modules/userSettings.js
@@ -54,9 +54,11 @@ const mutations = {
};
const actions = {
- async requestUserData({ commit }) {
- const userData = await api.users.self();
- commit("setUserData", userData);
+ async requestUserData({ getters, commit }) {
+ if (getters.getIsLoggedIn) {
+ const userData = await api.users.self();
+ commit("setUserData", userData);
+ }
},
async resetTheme({ commit }) {
diff --git a/mealie/db/db_base.py b/mealie/db/db_base.py
index f58db24f237a..6e193da21b5f 100644
--- a/mealie/db/db_base.py
+++ b/mealie/db/db_base.py
@@ -78,7 +78,7 @@ class BaseDocument:
return session.query(self.sql_model).filter_by(**{match_key: match_value}).one()
def get(
- self, session: Session, match_value: str, match_key: str = None, limit=1, any_case=False
+ self, session: Session, match_value: str, match_key: str = None, limit=1, any_case=False, override_schema=None
) -> Union[BaseModel, list[BaseModel]]:
"""Retrieves an entry from the database by matching a key/value pair. If no
key is provided the class objects primary key will be used to match against.
@@ -91,6 +91,7 @@ class BaseDocument:
Returns:
dict or list[dict]:
+
"""
if match_key is None:
match_key = self.primary_key
@@ -103,12 +104,14 @@ class BaseDocument:
else:
result = session.query(self.sql_model).filter_by(**{match_key: match_value}).limit(limit).all()
+ eff_schema = override_schema or self.schema
+
if limit == 1:
try:
- return self.schema.from_orm(result[0])
+ return eff_schema.from_orm(result[0])
except IndexError:
return None
- return [self.schema.from_orm(x) for x in result]
+ return [eff_schema.from_orm(x) for x in result]
def create(self, session: Session, document: dict) -> BaseModel:
"""Creates a new database entry for the given SQL Alchemy Model.
diff --git a/mealie/db/models/event.py b/mealie/db/models/event.py
index 32819b929d23..cc68abdd16da 100644
--- a/mealie/db/models/event.py
+++ b/mealie/db/models/event.py
@@ -19,7 +19,7 @@ class EventNotification(SqlAlchemyBase, BaseMixins):
user = Column(Boolean, default=False)
def __init__(
- self, name, notification_url, type, general, recipe, backup, scheduled, migration, group, user, *args, **kwargs
+ self, name, notification_url, type, general, recipe, backup, scheduled, migration, group, user, **_
) -> None:
self.name = name
self.notification_url = notification_url
@@ -41,7 +41,7 @@ class Event(SqlAlchemyBase, BaseMixins):
time_stamp = Column(DateTime)
category = Column(String)
- def __init__(self, title, text, time_stamp, category, *args, **kwargs) -> None:
+ def __init__(self, title, text, time_stamp, category, **_) -> None:
self.title = title
self.text = text
self.time_stamp = time_stamp
diff --git a/mealie/db/models/model_base.py b/mealie/db/models/model_base.py
index 2eb385f8f1fb..c240f43f3cb1 100644
--- a/mealie/db/models/model_base.py
+++ b/mealie/db/models/model_base.py
@@ -1,4 +1,5 @@
import sqlalchemy.ext.declarative as dec
+from requests import Session
SqlAlchemyBase = dec.declarative_base()
@@ -6,3 +7,7 @@ SqlAlchemyBase = dec.declarative_base()
class BaseMixins:
def update(self, *args, **kwarg):
self.__init__(*args, **kwarg)
+
+ def get_ref(cls_type, session: Session, match_value: str, match_attr: str = "id"):
+ eff_ref = getattr(cls_type, match_attr)
+ return session.query(cls_type).filter(eff_ref == match_value).one_or_none()
diff --git a/mealie/db/models/recipe/recipe.py b/mealie/db/models/recipe/recipe.py
index 10ae5e7b7583..2812b6249042 100644
--- a/mealie/db/models/recipe/recipe.py
+++ b/mealie/db/models/recipe/recipe.py
@@ -68,6 +68,10 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
date_added = sa.Column(sa.Date, default=date.today)
date_updated = sa.Column(sa.DateTime)
+ # Favorited By
+ favorited_by_id = sa.Column(sa.Integer, sa.ForeignKey("users.id"))
+ favorited_by = orm.relationship("User", back_populates="favorite_recipes")
+
@validates("name")
def validate_name(self, key, name):
assert name != ""
@@ -99,8 +103,7 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
extras: dict = None,
assets: list = None,
settings: dict = None,
- *args,
- **kwargs
+ **_
) -> None:
self.name = name
self.description = description
@@ -138,6 +141,6 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
self.date_added = date_added
self.date_updated = datetime.datetime.now()
- def update(self, *args, **kwargs):
+ def update(self, **_):
"""Updated a database entry by removing nested rows and rebuilds the row through the __init__ functions"""
- self.__init__(*args, **kwargs)
+ self.__init__(**_)
diff --git a/mealie/db/models/settings.py b/mealie/db/models/settings.py
index 6d06ac29bfb9..efaacfefd247 100644
--- a/mealie/db/models/settings.py
+++ b/mealie/db/models/settings.py
@@ -42,7 +42,7 @@ class CustomPage(SqlAlchemyBase, BaseMixins):
slug = sa.Column(sa.String, nullable=False)
categories = orm.relationship("Category", secondary=custom_pages2categories, single_parent=True)
- def __init__(self, session=None, name=None, slug=None, position=0, categories=[], *args, **kwargs) -> None:
+ def __init__(self, session=None, name=None, slug=None, position=0, categories=[], **_) -> None:
self.name = name
self.slug = slug
self.position = position
diff --git a/mealie/db/models/theme.py b/mealie/db/models/theme.py
index 7a9771dc6f5a..275afd41bc80 100644
--- a/mealie/db/models/theme.py
+++ b/mealie/db/models/theme.py
@@ -9,7 +9,7 @@ class SiteThemeModel(SqlAlchemyBase, BaseMixins):
name = Column(String, nullable=False, unique=True)
colors = orm.relationship("ThemeColorsModel", uselist=False, single_parent=True, cascade="all, delete-orphan")
- def __init__(self, name: str, colors: dict, *arg, **kwargs) -> None:
+ def __init__(self, name: str, colors: dict, **_) -> None:
self.name = name
self.colors = ThemeColorsModel(**colors)
diff --git a/mealie/db/models/users.py b/mealie/db/models/users.py
index 5ab7d715c57f..43cf42a7497a 100644
--- a/mealie/db/models/users.py
+++ b/mealie/db/models/users.py
@@ -1,6 +1,7 @@
from mealie.core.config import settings
from mealie.db.models.group import Group
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
+from mealie.db.models.recipe.recipe import RecipeModel
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, orm
@@ -22,11 +23,7 @@ class User(SqlAlchemyBase, BaseMixins):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
full_name = Column(String, index=True)
- username = Column(
- String,
- index=True,
- unique=True,
- )
+ username = Column(String, index=True, unique=True)
email = Column(String, unique=True, index=True)
password = Column(String)
group_id = Column(Integer, ForeignKey("groups.id"))
@@ -36,21 +33,38 @@ class User(SqlAlchemyBase, BaseMixins):
LongLiveToken, back_populates="user", cascade="all, delete, delete-orphan", single_parent=True
)
+ favorite_recipes: list[RecipeModel] = orm.relationship(RecipeModel, back_populates="favorited_by")
+
def __init__(
- self, session, full_name, email, password, group: str = settings.DEFAULT_GROUP, admin=False, **_
+ self,
+ session,
+ full_name,
+ email,
+ password,
+ favorite_recipes: list[str] = None,
+ group: str = settings.DEFAULT_GROUP,
+ admin=False,
+ **_
) -> None:
group = group or settings.DEFAULT_GROUP
+ favorite_recipes = favorite_recipes or []
self.full_name = full_name
self.email = email
self.group = Group.get_ref(session, group)
self.admin = admin
self.password = password
+ self.favorite_recipes = [
+ RecipeModel.get_ref(RecipeModel, session=session, match_value=x, match_attr="slug")
+ for x in favorite_recipes
+ ]
+
if self.username is None:
self.username = full_name
- def update(self, full_name, email, group, admin, username, session=None, id=None, password=None, *args, **kwargs):
+ def update(self, full_name, email, group, admin, username, session=None, favorite_recipes=None, password=None, **_):
+ favorite_recipes = favorite_recipes or []
self.username = username
self.full_name = full_name
self.email = email
@@ -63,6 +77,11 @@ class User(SqlAlchemyBase, BaseMixins):
if password:
self.password = password
+ self.favorite_recipes = [
+ RecipeModel.get_ref(RecipeModel, session=session, match_value=x, match_attr="slug")
+ for x in favorite_recipes
+ ]
+
def update_password(self, password):
self.password = password
diff --git a/mealie/routes/users/crud.py b/mealie/routes/users/crud.py
index 8fe60bac5508..8b405d25f559 100644
--- a/mealie/routes/users/crud.py
+++ b/mealie/routes/users/crud.py
@@ -8,7 +8,7 @@ from mealie.core.security import get_password_hash, verify_password
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.user import ChangePassword, UserBase, UserIn, UserInDB, UserOut
+from mealie.schema.user import ChangePassword, UserBase, UserFavorites, UserIn, UserInDB, UserOut
from mealie.services.events import create_user_event
from sqlalchemy.orm.session import Session
@@ -19,7 +19,7 @@ router = APIRouter(prefix="/api/users", tags=["Users"])
async def create_user(
background_tasks: BackgroundTasks,
new_user: UserIn,
- current_user=Depends(get_current_user),
+ current_user: UserInDB = Depends(get_current_user),
session: Session = Depends(generate_session),
):
@@ -45,24 +45,21 @@ async def get_all_users(
@router.get("/self", response_model=UserOut)
async def get_logged_in_user(
current_user: UserInDB = Depends(get_current_user),
- session: Session = Depends(generate_session),
):
return current_user.dict()
-@router.get("/{id}", response_model=UserOut)
+@router.get("/{id}", response_model=UserOut, dependencies=[Depends(get_current_user)])
async def get_user_by_id(
id: int,
- current_user: UserInDB = Depends(get_current_user),
session: Session = Depends(generate_session),
):
return db.users.get(session, id)
-@router.put("/{id}/reset-password")
+@router.put("/{id}/reset-password", dependencies=[Depends(get_current_user)])
async def reset_user_password(
id: int,
- current_user: UserInDB = Depends(get_current_user),
session: Session = Depends(generate_session),
):
@@ -97,11 +94,10 @@ async def get_user_image(id: str):
return False
-@router.post("/{id}/image")
+@router.post("/{id}/image", dependencies=[Depends(get_current_user)])
async def update_user_image(
id: str,
profile_image: UploadFile = File(...),
- current_user: UserInDB = Depends(get_current_user),
):
""" Updates a User Image """
@@ -139,6 +135,41 @@ async def update_password(
db.users.update_password(session, id, new_password)
+@router.get("/{id}/favorites", response_model=UserFavorites)
+async def get_favorites(id: str, session: Session = Depends(generate_session)):
+ """ Adds a Recipe to the users favorites """
+
+ return db.users.get(session, id, override_schema=UserFavorites)
+
+
+@router.post("/{id}/favorites/{slug}")
+async def add_favorite(
+ slug: str,
+ current_user: UserInDB = Depends(get_current_user),
+ session: Session = Depends(generate_session),
+):
+ """ Adds a Recipe to the users favorites """
+
+ current_user.favorite_recipes.append(slug)
+
+ db.users.update(session, current_user.id, current_user)
+
+
+@router.delete("/{id}/favorites/{slug}")
+async def remove_favorite(
+ slug: str,
+ current_user: UserInDB = Depends(get_current_user),
+ session: Session = Depends(generate_session),
+):
+ """ Adds a Recipe to the users favorites """
+
+ current_user.favorite_recipes = [x for x in current_user.favorite_recipes if x != slug]
+
+ db.users.update(session, current_user.id, current_user)
+
+ return
+
+
@router.delete("/{id}")
async def delete_user(
background_tasks: BackgroundTasks,
diff --git a/mealie/schema/helpers.py b/mealie/schema/helpers.py
new file mode 100644
index 000000000000..85e55e91a408
--- /dev/null
+++ b/mealie/schema/helpers.py
@@ -0,0 +1,5 @@
+from fastapi_camelcase import CamelModel
+
+
+class RecipeSlug(CamelModel):
+ slug: str
diff --git a/mealie/schema/user.py b/mealie/schema/user.py
index 9ee1b0b8fbf9..c18ce7aa9f37 100644
--- a/mealie/schema/user.py
+++ b/mealie/schema/user.py
@@ -6,6 +6,7 @@ from mealie.db.models.group import Group
from mealie.db.models.users import User
from mealie.schema.category import CategoryBase
from mealie.schema.meal import MealPlanOut
+from mealie.schema.recipe import RecipeSummary
from mealie.schema.shopping_list import ShoppingListOut
from pydantic.types import constr
from pydantic.utils import GetterDict
@@ -48,6 +49,7 @@ class UserBase(CamelModel):
email: constr(to_lower=True, strip_whitespace=True)
admin: bool
group: Optional[str]
+ favorite_recipes: Optional[list[str]] = []
class Config:
orm_mode = True
@@ -76,6 +78,22 @@ class UserOut(UserBase):
id: int
group: str
tokens: Optional[list[LongLiveTokenOut]]
+ favorite_recipes: Optional[list[str]] = []
+
+ class Config:
+ orm_mode = True
+
+ @classmethod
+ def getter_dict(cls, ormModel: User):
+ return {
+ **GetterDict(ormModel),
+ "group": ormModel.group.name,
+ "favorite_recipes": [x.slug for x in ormModel.favorite_recipes],
+ }
+
+
+class UserFavorites(UserBase):
+ favorite_recipes: list[RecipeSummary] = []
class Config:
orm_mode = True
@@ -90,7 +108,6 @@ class UserOut(UserBase):
class UserInDB(UserOut):
password: str
- pass
class Config:
orm_mode = True
diff --git a/scratch.json b/scratch.json
deleted file mode 100644
index b7cdad46a21f..000000000000
--- a/scratch.json
+++ /dev/null
@@ -1 +0,0 @@
-{"openapi": "3.0.2", "info": {"title": "Mealie", "description": "A place for all your recipes", "version": "v0.5.0beta"}, "paths": {"/api/auth/token": {"post": {"tags": ["Authentication"], "summary": "Get Token", "operationId": "get_token_api_auth_token_post", "requestBody": {"content": {"application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/Body_get_token_api_auth_token_post"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/auth/token/long": {"post": {"tags": ["Authentication"], "summary": "Get Token", "operationId": "get_token_api_auth_token_long_post", "requestBody": {"content": {"application/x-www-form-urlencoded": {"schema": {"$ref": "#/components/schemas/Body_get_token_api_auth_token_long_post"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/auth/refresh": {"get": {"tags": ["Authentication"], "summary": "Refresh Token", "description": "Use a valid token to get another token", "operationId": "refresh_token_api_auth_refresh_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/users/sign-ups": {"get": {"tags": ["User Signup"], "summary": "Get All Open Sign Ups", "description": "Returns a list of open sign up links ", "operationId": "get_all_open_sign_ups_api_users_sign_ups_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"title": "Response Get All Open Sign Ups Api Users Sign Ups Get", "type": "array", "items": {"$ref": "#/components/schemas/SignUpOut"}}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "post": {"tags": ["User Signup"], "summary": "Create User Sign Up Key", "description": "Generates a Random Token that a new user can sign up with ", "operationId": "create_user_sign_up_key_api_users_sign_ups_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SignUpIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/SignUpToken"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/users/sign-ups/{token}": {"post": {"tags": ["User Signup"], "summary": "Create User With Token", "description": "Creates a user with a valid sign up token ", "operationId": "create_user_with_token_api_users_sign_ups__token__post", "parameters": [{"required": true, "schema": {"title": "Token", "type": "string"}, "name": "token", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "delete": {"tags": ["User Signup"], "summary": "Delete Token", "description": "Removed a token from the database ", "operationId": "delete_token_api_users_sign_ups__token__delete", "parameters": [{"required": true, "schema": {"title": "Token", "type": "string"}, "name": "token", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/users": {"get": {"tags": ["Users"], "summary": "Get All Users", "operationId": "get_all_users_api_users_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"title": "Response Get All Users Api Users Get", "type": "array", "items": {"$ref": "#/components/schemas/UserOut"}}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "post": {"tags": ["Users"], "summary": "Create User", "operationId": "create_user_api_users_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserIn"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserOut"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/users/self": {"get": {"tags": ["Users"], "summary": "Get Logged In User", "operationId": "get_logged_in_user_api_users_self_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserOut"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/users/{id}": {"get": {"tags": ["Users"], "summary": "Get User By Id", "operationId": "get_user_by_id_api_users__id__get", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserOut"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "put": {"tags": ["Users"], "summary": "Update User", "operationId": "update_user_api_users__id__put", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserBase"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["Users"], "summary": "Delete User", "description": "Removes a user from the database. Must be the current user or a super user", "operationId": "delete_user_api_users__id__delete", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/users/{id}/reset-password": {"put": {"tags": ["Users"], "summary": "Reset User Password", "operationId": "reset_user_password_api_users__id__reset_password_put", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/users/{id}/image": {"get": {"tags": ["Users"], "summary": "Get User Image", "description": "Returns a users profile picture ", "operationId": "get_user_image_api_users__id__image_get", "parameters": [{"required": true, "schema": {"title": "Id", "type": "string"}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "post": {"tags": ["Users"], "summary": "Update User Image", "description": "Updates a User Image ", "operationId": "update_user_image_api_users__id__image_post", "parameters": [{"required": true, "schema": {"title": "Id", "type": "string"}, "name": "id", "in": "path"}], "requestBody": {"content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_update_user_image_api_users__id__image_post"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/users/{id}/password": {"put": {"tags": ["Users"], "summary": "Update Password", "description": "Resets the User Password", "operationId": "update_password_api_users__id__password_put", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ChangePassword"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/users/api-tokens": {"post": {"tags": ["User API Tokens"], "summary": "Create Api Token", "description": "Create api_token in the Database ", "operationId": "create_api_token_api_users_api_tokens_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/LoingLiveTokenIn"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/users/api-tokens/{token_id}": {"delete": {"tags": ["User API Tokens"], "summary": "Delete Api Token", "description": "Delete api_token from the Database ", "operationId": "delete_api_token_api_users_api_tokens__token_id__delete", "parameters": [{"required": true, "schema": {"title": "Token Id", "type": "integer"}, "name": "token_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/groups": {"get": {"tags": ["Groups"], "summary": "Get All Groups", "description": "Returns a list of all groups in the database ", "operationId": "get_all_groups_api_groups_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"title": "Response Get All Groups Api Groups Get", "type": "array", "items": {"$ref": "#/components/schemas/GroupInDB"}}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "post": {"tags": ["Groups"], "summary": "Create Group", "description": "Creates a Group in the Database ", "operationId": "create_group_api_groups_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/GroupBase"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/groups/self": {"get": {"tags": ["Groups"], "summary": "Get Current User Group", "description": "Returns the Group Data for the Current User ", "operationId": "get_current_user_group_api_groups_self_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/GroupInDB"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/groups/{id}": {"put": {"tags": ["Groups"], "summary": "Update Group Data", "description": "Updates a User Group ", "operationId": "update_group_data_api_groups__id__put", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UpdateGroup"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["Groups"], "summary": "Delete User Group", "description": "Removes a user group from the database ", "operationId": "delete_user_group_api_groups__id__delete", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/shopping-lists": {"post": {"tags": ["Shopping Lists"], "summary": "Create Shopping List", "description": "Create Shopping List in the Database ", "operationId": "create_shopping_list_api_shopping_lists_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ShoppingListIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ShoppingListOut"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/shopping-lists/{id}": {"get": {"tags": ["Shopping Lists"], "summary": "Get Shopping List", "description": "Get Shopping List from the Database ", "operationId": "get_shopping_list_api_shopping_lists__id__get", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ShoppingListOut"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"tags": ["Shopping Lists"], "summary": "Update Shopping List", "description": "Update Shopping List in the Database ", "operationId": "update_shopping_list_api_shopping_lists__id__put", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ShoppingListOut"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["Shopping Lists"], "summary": "Delete Shopping List", "description": "Delete Shopping List from the Database ", "operationId": "delete_shopping_list_api_shopping_lists__id__delete", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/recipes/summary": {"get": {"tags": ["Query All Recipes"], "summary": "Get Recipe Summary", "description": "Returns key the recipe summary data for recipes in the database. You can perform\nslice operations to set the skip/end amounts for recipes. All recipes are sorted by the added date.\n\n**Query Parameters**\n- skip: The database entry to start at. (0 Indexed)\n- end: The number of entries to return.\n\nskip=2, end=10 will return entries", "operationId": "get_recipe_summary_api_recipes_summary_get", "parameters": [{"required": false, "schema": {"title": "Start", "default": 0}, "name": "start", "in": "query"}, {"required": false, "schema": {"title": "Limit", "default": 9999}, "name": "limit", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"title": "Response Get Recipe Summary Api Recipes Summary Get", "type": "array", "items": {"$ref": "#/components/schemas/RecipeSummary"}}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/recipes/summary/untagged": {"get": {"tags": ["Query All Recipes"], "summary": "Get Untagged Recipes", "operationId": "get_untagged_recipes_api_recipes_summary_untagged_get", "parameters": [{"required": false, "schema": {"title": "Count", "type": "boolean", "default": false}, "name": "count", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"title": "Response Get Untagged Recipes Api Recipes Summary Untagged Get", "type": "array", "items": {"$ref": "#/components/schemas/RecipeSummary"}}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/recipes/summary/uncategorized": {"get": {"tags": ["Query All Recipes"], "summary": "Get Uncategorized Recipes", "operationId": "get_uncategorized_recipes_api_recipes_summary_uncategorized_get", "parameters": [{"required": false, "schema": {"title": "Count", "type": "boolean", "default": false}, "name": "count", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"title": "Response Get Uncategorized Recipes Api Recipes Summary Uncategorized Get", "type": "array", "items": {"$ref": "#/components/schemas/RecipeSummary"}}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/recipes/category": {"post": {"tags": ["Query All Recipes"], "summary": "Filter By Category", "description": "pass a list of categories and get a list of recipes associated with those categories ", "operationId": "filter_by_category_api_recipes_category_post", "requestBody": {"content": {"application/json": {"schema": {"title": "Categories", "type": "array", "items": {}}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/recipes/tag": {"post": {"tags": ["Query All Recipes"], "summary": "Filter By Tags", "description": "pass a list of tags and get a list of recipes associated with those tags", "operationId": "filter_by_tags_api_recipes_tag_post", "requestBody": {"content": {"application/json": {"schema": {"title": "Tags", "type": "array", "items": {}}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/recipes/create": {"post": {"tags": ["Recipe CRUD"], "summary": "Create From Json", "description": "Takes in a JSON string and loads data into the database as a new entry", "operationId": "create_from_json_api_recipes_create_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Recipe"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"title": "Response Create From Json Api Recipes Create Post", "type": "string"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/recipes/create-url": {"post": {"tags": ["Recipe CRUD"], "summary": "Parse Recipe Url", "description": "Takes in a URL and attempts to scrape data and load it into the database ", "operationId": "parse_recipe_url_api_recipes_create_url_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RecipeURLIn"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {"title": "Response Parse Recipe Url Api Recipes Create Url Post", "type": "string"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/recipes/{recipe_slug}": {"get": {"tags": ["Recipe CRUD"], "summary": "Get Recipe", "description": "Takes in a recipe slug, returns all data for a recipe ", "operationId": "get_recipe_api_recipes__recipe_slug__get", "parameters": [{"required": true, "schema": {"title": "Recipe Slug", "type": "string"}, "name": "recipe_slug", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Recipe"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"tags": ["Recipe CRUD"], "summary": "Update Recipe", "description": "Updates a recipe by existing slug and data. ", "operationId": "update_recipe_api_recipes__recipe_slug__put", "parameters": [{"required": true, "schema": {"title": "Recipe Slug", "type": "string"}, "name": "recipe_slug", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Recipe"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["Recipe CRUD"], "summary": "Delete Recipe", "description": "Deletes a recipe by slug ", "operationId": "delete_recipe_api_recipes__recipe_slug__delete", "parameters": [{"required": true, "schema": {"title": "Recipe Slug", "type": "string"}, "name": "recipe_slug", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "patch": {"tags": ["Recipe CRUD"], "summary": "Patch Recipe", "description": "Updates a recipe by existing slug and data. ", "operationId": "patch_recipe_api_recipes__recipe_slug__patch", "parameters": [{"required": true, "schema": {"title": "Recipe Slug", "type": "string"}, "name": "recipe_slug", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Recipe"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/recipes/{recipe_slug}/image": {"put": {"tags": ["Recipe CRUD"], "summary": "Update Recipe Image", "description": "Removes an existing image and replaces it with the incoming file. ", "operationId": "update_recipe_image_api_recipes__recipe_slug__image_put", "parameters": [{"required": true, "schema": {"title": "Recipe Slug", "type": "string"}, "name": "recipe_slug", "in": "path"}], "requestBody": {"content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_update_recipe_image_api_recipes__recipe_slug__image_put"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "post": {"tags": ["Recipe CRUD"], "summary": "Scrape Image Url", "description": "Removes an existing image and replaces it with the incoming file. ", "operationId": "scrape_image_url_api_recipes__recipe_slug__image_post", "parameters": [{"required": true, "schema": {"title": "Recipe Slug", "type": "string"}, "name": "recipe_slug", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/RecipeURLIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/recipes/{recipe_slug}/assets": {"post": {"tags": ["Recipe CRUD"], "summary": "Upload Recipe Asset", "description": "Upload a file to store as a recipe asset ", "operationId": "upload_recipe_asset_api_recipes__recipe_slug__assets_post", "parameters": [{"required": true, "schema": {"title": "Recipe Slug", "type": "string"}, "name": "recipe_slug", "in": "path"}], "requestBody": {"content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_upload_recipe_asset_api_recipes__recipe_slug__assets_post"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RecipeAsset"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/categories": {"get": {"tags": ["Recipe Categories"], "summary": "Get All Recipe Categories", "description": "Returns a list of available categories in the database ", "operationId": "get_all_recipe_categories_api_categories_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}, "post": {"tags": ["Recipe Categories"], "summary": "Create Recipe Category", "description": "Creates a Category in the database ", "operationId": "create_recipe_category_api_categories_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CategoryIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/categories/empty": {"get": {"tags": ["Recipe Categories"], "summary": "Get Empty Categories", "description": "Returns a list of categories that do not contain any recipes", "operationId": "get_empty_categories_api_categories_empty_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/api/categories/{category}": {"get": {"tags": ["Recipe Categories"], "summary": "Get All Recipes By Category", "description": "Returns a list of recipes associated with the provided category. ", "operationId": "get_all_recipes_by_category_api_categories__category__get", "parameters": [{"required": true, "schema": {"title": "Category", "type": "string"}, "name": "category", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RecipeCategoryResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"tags": ["Recipe Categories"], "summary": "Update Recipe Category", "description": "Updates an existing Tag in the database ", "operationId": "update_recipe_category_api_categories__category__put", "parameters": [{"required": true, "schema": {"title": "Category", "type": "string"}, "name": "category", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CategoryIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RecipeCategoryResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["Recipe Categories"], "summary": "Delete Recipe Category", "description": "Removes a recipe category from the database. Deleting a\ncategory does not impact a recipe. The category will be removed\nfrom any recipes that contain it", "operationId": "delete_recipe_category_api_categories__category__delete", "parameters": [{"required": true, "schema": {"title": "Category", "type": "string"}, "name": "category", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/tags": {"get": {"tags": ["Recipe Tags"], "summary": "Get All Recipe Tags", "description": "Returns a list of available tags in the database ", "operationId": "get_all_recipe_tags_api_tags_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}, "post": {"tags": ["Recipe Tags"], "summary": "Create Recipe Tag", "description": "Creates a Tag in the database ", "operationId": "create_recipe_tag_api_tags_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/TagIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/tags/empty": {"get": {"tags": ["Recipe Tags"], "summary": "Get Empty Tags", "description": "Returns a list of tags that do not contain any recipes", "operationId": "get_empty_tags_api_tags_empty_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/api/tags/{tag}": {"get": {"tags": ["Recipe Tags"], "summary": "Get All Recipes By Tag", "description": "Returns a list of recipes associated with the provided tag. ", "operationId": "get_all_recipes_by_tag_api_tags__tag__get", "parameters": [{"required": true, "schema": {"title": "Tag", "type": "string"}, "name": "tag", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RecipeTagResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"tags": ["Recipe Tags"], "summary": "Update Recipe Tag", "description": "Updates an existing Tag in the database ", "operationId": "update_recipe_tag_api_tags__tag__put", "parameters": [{"required": true, "schema": {"title": "Tag", "type": "string"}, "name": "tag", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/TagIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/RecipeTagResponse"}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["Recipe Tags"], "summary": "Delete Recipe Tag", "description": "Removes a recipe tag from the database. Deleting a\ntag does not impact a recipe. The tag will be removed\nfrom any recipes that contain it", "operationId": "delete_recipe_tag_api_tags__tag__delete", "parameters": [{"required": true, "schema": {"title": "Tag", "type": "string"}, "name": "tag", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/media/recipes/{recipe_slug}/images/{file_name}": {"get": {"tags": ["Site Media"], "summary": "Get Recipe Img", "description": "Takes in a recipe slug, returns the static image. This route is proxied in the docker image\nand should not hit the API in production", "operationId": "get_recipe_img_api_media_recipes__recipe_slug__images__file_name__get", "parameters": [{"required": true, "schema": {"title": "Recipe Slug", "type": "string"}, "name": "recipe_slug", "in": "path"}, {"required": true, "schema": {"$ref": "#/components/schemas/ImageType"}, "name": "file_name", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/media/recipes/{recipe_slug}/assets/{file_name}": {"get": {"tags": ["Site Media"], "summary": "Get Recipe Asset", "description": "Returns a recipe asset ", "operationId": "get_recipe_asset_api_media_recipes__recipe_slug__assets__file_name__get", "parameters": [{"required": true, "schema": {"title": "Recipe Slug", "type": "string"}, "name": "recipe_slug", "in": "path"}, {"required": true, "schema": {"title": "File Name", "type": "string"}, "name": "file_name", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/about/events": {"get": {"tags": ["App Events"], "summary": "Get Events", "description": "Get event from the Database ", "operationId": "get_events_api_about_events_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/EventsOut"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["App Events"], "summary": "Delete Events", "description": "Get event from the Database ", "operationId": "delete_events_api_about_events_delete", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/about/events/{id}": {"delete": {"tags": ["App Events"], "summary": "Delete Event", "description": "Delete event from the Database ", "operationId": "delete_event_api_about_events__id__delete", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/about/events/notifications": {"get": {"tags": ["App Events"], "summary": "Get All Event Notification", "description": "Get all event_notification from the Database ", "operationId": "get_all_event_notification_api_about_events_notifications_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"title": "Response Get All Event Notification Api About Events Notifications Get", "type": "array", "items": {"$ref": "#/components/schemas/EventNotificationOut"}}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "post": {"tags": ["App Events"], "summary": "Create Event Notification", "description": "Create event_notification in the Database ", "operationId": "create_event_notification_api_about_events_notifications_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/EventNotificationIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/about/events/notifications/test": {"post": {"tags": ["App Events"], "summary": "Test Notification Route", "description": "Create event_notification in the Database ", "operationId": "test_notification_route_api_about_events_notifications_test_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/TestEvent"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/about/events/notifications/{id}": {"put": {"tags": ["App Events"], "summary": "Update Event Notification", "description": "Update event_notification in the Database ", "operationId": "update_event_notification_api_about_events_notifications__id__put", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["App Events"], "summary": "Delete Event Notification", "description": "Delete event_notification from the Database ", "operationId": "delete_event_notification_api_about_events_notifications__id__delete", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/meal-plans/all": {"get": {"tags": ["Meal Plan"], "summary": "Get All Meals", "description": "Returns a list of all available Meal Plan ", "operationId": "get_all_meals_api_meal_plans_all_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"title": "Response Get All Meals Api Meal Plans All Get", "type": "array", "items": {"$ref": "#/components/schemas/MealPlanOut"}}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/meal-plans/create": {"post": {"tags": ["Meal Plan"], "summary": "Create Meal Plan", "description": "Creates a meal plan database entry ", "operationId": "create_meal_plan_api_meal_plans_create_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/MealPlanIn"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/meal-plans/{plan_id}": {"put": {"tags": ["Meal Plan"], "summary": "Update Meal Plan", "description": "Updates a meal plan based off ID ", "operationId": "update_meal_plan_api_meal_plans__plan_id__put", "parameters": [{"required": true, "schema": {"title": "Plan Id", "type": "string"}, "name": "plan_id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/MealPlanIn"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["Meal Plan"], "summary": "Delete Meal Plan", "description": "Removes a meal plan from the database ", "operationId": "delete_meal_plan_api_meal_plans__plan_id__delete", "parameters": [{"required": true, "schema": {"title": "Plan Id"}, "name": "plan_id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/meal-plans/this-week": {"get": {"tags": ["Meal Plan"], "summary": "Get This Week", "description": "Returns the meal plan data for this week ", "operationId": "get_this_week_api_meal_plans_this_week_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MealPlanOut"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/meal-plans/today": {"get": {"tags": ["Meal Plan", "Meal Plan"], "summary": "Get Today", "description": "Returns the recipe slug for the meal scheduled for today.\nIf no meal is scheduled nothing is returned", "operationId": "get_today_api_meal_plans_today_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/meal-plans/today/image": {"get": {"tags": ["Meal Plan", "Meal Plan"], "summary": "Get Todays Image", "description": "Returns the image for todays meal-plan.", "operationId": "get_todays_image_api_meal_plans_today_image_get", "parameters": [{"required": false, "schema": {"title": "Group Name", "type": "string", "default": "Home"}, "name": "group_name", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}, "/api/meal-plans/{id}/shopping-list": {"get": {"tags": ["Meal Plan"], "summary": "Get Shopping List", "operationId": "get_shopping_list_api_meal_plans__id__shopping_list_get", "parameters": [{"required": true, "schema": {"title": "Id", "type": "string"}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/site-settings/custom-pages": {"get": {"tags": ["Settings"], "summary": "Get Custom Pages", "description": "Returns the sites custom pages ", "operationId": "get_custom_pages_api_site_settings_custom_pages_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}, "put": {"tags": ["Settings"], "summary": "Update Multiple Pages", "description": "Update multiple custom pages ", "operationId": "update_multiple_pages_api_site_settings_custom_pages_put", "requestBody": {"content": {"application/json": {"schema": {"title": "Pages", "type": "array", "items": {"$ref": "#/components/schemas/CustomPageOut"}}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "post": {"tags": ["Settings"], "summary": "Create New Page", "description": "Creates a new Custom Page ", "operationId": "create_new_page_api_site_settings_custom_pages_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CustomPageBase"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/site-settings/custom-pages/{id}": {"get": {"tags": ["Settings"], "summary": "Get Single Page", "description": "Removes a custom page from the database ", "operationId": "get_single_page_api_site_settings_custom_pages__id__get", "parameters": [{"required": true, "schema": {"title": "Id", "anyOf": [{"type": "integer"}, {"type": "string"}]}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"tags": ["Settings"], "summary": "Update Single Page", "description": "Removes a custom page from the database ", "operationId": "update_single_page_api_site_settings_custom_pages__id__put", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/CustomPageOut"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["Settings"], "summary": "Delete Custom Page", "description": "Removes a custom page from the database ", "operationId": "delete_custom_page_api_site_settings_custom_pages__id__delete", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/site-settings": {"get": {"tags": ["Settings"], "summary": "Get Main Settings", "description": "Returns basic site settings ", "operationId": "get_main_settings_api_site_settings_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}, "put": {"tags": ["Settings"], "summary": "Update Settings", "description": "Returns Site Settings ", "operationId": "update_settings_api_site_settings_put", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SiteSettings"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/site-settings/webhooks/test": {"post": {"tags": ["Settings"], "summary": "Test Webhooks", "description": "Run the function to test your webhooks ", "operationId": "test_webhooks_api_site_settings_webhooks_test_post", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/themes": {"get": {"tags": ["Themes"], "summary": "Get All Themes", "description": "Returns all site themes ", "operationId": "get_all_themes_api_themes_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/api/themes/create": {"post": {"tags": ["Themes"], "summary": "Create Theme", "description": "Creates a site color theme database entry ", "operationId": "create_theme_api_themes_create_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SiteTheme"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/themes/{id}": {"get": {"tags": ["Themes"], "summary": "Get Single Theme", "description": "Returns a named theme ", "operationId": "get_single_theme_api_themes__id__get", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}, "put": {"tags": ["Themes"], "summary": "Update Theme", "description": "Update a theme database entry ", "operationId": "update_theme_api_themes__id__put", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/SiteTheme"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}, "delete": {"tags": ["Themes"], "summary": "Delete Theme", "description": "Deletes theme from the database ", "operationId": "delete_theme_api_themes__id__delete", "parameters": [{"required": true, "schema": {"title": "Id", "type": "integer"}, "name": "id", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/backups/available": {"get": {"tags": ["Backups"], "summary": "Available Imports", "description": "Returns a list of avaiable .zip files for import into Mealie.", "operationId": "available_imports_api_backups_available_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Imports"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/backups/export/database": {"post": {"tags": ["Backups"], "summary": "Export Database", "description": "Generates a backup of the recipe database in json format.", "operationId": "export_database_api_backups_export_database_post", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/BackupJob"}}}, "required": true}, "responses": {"201": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/backups/upload": {"post": {"tags": ["Backups"], "summary": "Upload Backup File", "description": "Upload a .zip File to later be imported into Mealie ", "operationId": "upload_backup_file_api_backups_upload_post", "requestBody": {"content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_upload_backup_file_api_backups_upload_post"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/backups/{file_name}/download": {"get": {"tags": ["Backups"], "summary": "Download Backup File", "description": "Returns a token to download a file ", "operationId": "download_backup_file_api_backups__file_name__download_get", "parameters": [{"required": true, "schema": {"title": "File Name", "type": "string"}, "name": "file_name", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/backups/{file_name}/import": {"post": {"tags": ["Backups"], "summary": "Import Database", "description": "Import a database backup file generated from Mealie. ", "operationId": "import_database_api_backups__file_name__import_post", "parameters": [{"required": true, "schema": {"title": "File Name", "type": "string"}, "name": "file_name", "in": "path"}], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ImportJob"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/backups/{file_name}/delete": {"delete": {"tags": ["Backups"], "summary": "Delete Backup", "description": "Removes a database backup from the file system ", "operationId": "delete_backup_api_backups__file_name__delete_delete", "parameters": [{"required": true, "schema": {"title": "File Name", "type": "string"}, "name": "file_name", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/migrations": {"get": {"tags": ["Migration"], "summary": "Get All Migration Options", "description": "Returns a list of avaiable directories that can be imported into Mealie ", "operationId": "get_all_migration_options_api_migrations_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {"title": "Response Get All Migration Options Api Migrations Get", "type": "array", "items": {"$ref": "#/components/schemas/Migrations"}}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/migrations/{import_type}/{file_name}/import": {"post": {"tags": ["Migration"], "summary": "Import Migration", "description": "Imports all the recipes in a given directory ", "operationId": "import_migration_api_migrations__import_type___file_name__import_post", "parameters": [{"required": true, "schema": {"$ref": "#/components/schemas/Migration"}, "name": "import_type", "in": "path"}, {"required": true, "schema": {"title": "File Name", "type": "string"}, "name": "file_name", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/migrations/{import_type}/{file_name}/delete": {"delete": {"tags": ["Migration"], "summary": "Delete Migration Data", "description": "Removes migration data from the file system ", "operationId": "delete_migration_data_api_migrations__import_type___file_name__delete_delete", "parameters": [{"required": true, "schema": {"$ref": "#/components/schemas/Migration"}, "name": "import_type", "in": "path"}, {"required": true, "schema": {"title": "File Name", "type": "string"}, "name": "file_name", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/migrations/{import_type}/upload": {"post": {"tags": ["Migration"], "summary": "Upload Nextcloud Zipfile", "description": "Upload a .zip File to later be imported into Mealie ", "operationId": "upload_nextcloud_zipfile_api_migrations__import_type__upload_post", "parameters": [{"required": true, "schema": {"$ref": "#/components/schemas/Migration"}, "name": "import_type", "in": "path"}], "requestBody": {"content": {"multipart/form-data": {"schema": {"$ref": "#/components/schemas/Body_upload_nextcloud_zipfile_api_migrations__import_type__upload_post"}}}, "required": true}, "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/debug": {"get": {"tags": ["Debug"], "summary": "Get Debug Info", "description": "Returns general information about the application for debugging ", "operationId": "get_debug_info_api_debug_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/debug/statistics": {"get": {"tags": ["Debug"], "summary": "Get App Statistics", "operationId": "get_app_statistics_api_debug_statistics_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/api/debug/version": {"get": {"tags": ["Debug"], "summary": "Get Mealie Version", "description": "Returns the current version of mealie", "operationId": "get_mealie_version_api_debug_version_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/api/debug/last-recipe-json": {"get": {"tags": ["Debug"], "summary": "Get Last Recipe Json", "description": "Returns a token to download a file ", "operationId": "get_last_recipe_json_api_debug_last_recipe_json_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/debug/log/{num}": {"get": {"tags": ["Debug"], "summary": "Get Log", "description": "Doc Str ", "operationId": "get_log_api_debug_log__num__get", "parameters": [{"required": true, "schema": {"title": "Num", "type": "integer"}, "name": "num", "in": "path"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}, "security": [{"OAuth2PasswordBearer": []}]}}, "/api/debug/log": {"get": {"tags": ["Debug"], "summary": "Get Log File", "description": "Returns a token to download a file ", "operationId": "get_log_file_api_debug_log_get", "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}}}}, "/api/utils/download": {"get": {"tags": ["Utils"], "summary": "Download File", "description": "Uses a file token obtained by an active user to retrieve a file from the operating\nsystem.", "operationId": "download_file_api_utils_download_get", "parameters": [{"required": false, "schema": {"title": "Token", "type": "string"}, "name": "token", "in": "query"}], "responses": {"200": {"description": "Successful Response", "content": {"application/json": {"schema": {}}}}, "422": {"description": "Validation Error", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HTTPValidationError"}}}}}}}}, "components": {"schemas": {"BackupJob": {"title": "BackupJob", "required": ["options"], "type": "object", "properties": {"tag": {"title": "Tag", "type": "string"}, "options": {"$ref": "#/components/schemas/BackupOptions"}, "templates": {"title": "Templates", "type": "array", "items": {"type": "string"}}}, "example": {"tag": "July 23rd 2021", "options": {"recipes": true, "settings": true, "pages": true, "themes": true, "groups": true, "users": true, "notifications": true}, "template": ["recipes.md"]}}, "BackupOptions": {"title": "BackupOptions", "type": "object", "properties": {"recipes": {"title": "Recipes", "type": "boolean", "default": true}, "settings": {"title": "Settings", "type": "boolean", "default": true}, "pages": {"title": "Pages", "type": "boolean", "default": true}, "themes": {"title": "Themes", "type": "boolean", "default": true}, "groups": {"title": "Groups", "type": "boolean", "default": true}, "users": {"title": "Users", "type": "boolean", "default": true}, "notifications": {"title": "Notifications", "type": "boolean", "default": true}}, "example": {"recipes": true, "settings": true, "themes": true, "groups": true, "users": true}}, "Body_get_token_api_auth_token_long_post": {"title": "Body_get_token_api_auth_token_long_post", "required": ["username", "password"], "type": "object", "properties": {"grant_type": {"title": "Grant Type", "pattern": "password", "type": "string"}, "username": {"title": "Username", "type": "string"}, "password": {"title": "Password", "type": "string"}, "scope": {"title": "Scope", "type": "string", "default": ""}, "client_id": {"title": "Client Id", "type": "string"}, "client_secret": {"title": "Client Secret", "type": "string"}}}, "Body_get_token_api_auth_token_post": {"title": "Body_get_token_api_auth_token_post", "required": ["username", "password"], "type": "object", "properties": {"grant_type": {"title": "Grant Type", "pattern": "password", "type": "string"}, "username": {"title": "Username", "type": "string"}, "password": {"title": "Password", "type": "string"}, "scope": {"title": "Scope", "type": "string", "default": ""}, "client_id": {"title": "Client Id", "type": "string"}, "client_secret": {"title": "Client Secret", "type": "string"}}}, "Body_update_recipe_image_api_recipes__recipe_slug__image_put": {"title": "Body_update_recipe_image_api_recipes__recipe_slug__image_put", "required": ["image", "extension"], "type": "object", "properties": {"image": {"title": "Image", "type": "string", "format": "binary"}, "extension": {"title": "Extension", "type": "string"}}}, "Body_update_user_image_api_users__id__image_post": {"title": "Body_update_user_image_api_users__id__image_post", "required": ["profile_image"], "type": "object", "properties": {"profile_image": {"title": "Profile Image", "type": "string", "format": "binary"}}}, "Body_upload_backup_file_api_backups_upload_post": {"title": "Body_upload_backup_file_api_backups_upload_post", "required": ["archive"], "type": "object", "properties": {"archive": {"title": "Archive", "type": "string", "format": "binary"}}}, "Body_upload_nextcloud_zipfile_api_migrations__import_type__upload_post": {"title": "Body_upload_nextcloud_zipfile_api_migrations__import_type__upload_post", "required": ["archive"], "type": "object", "properties": {"archive": {"title": "Archive", "type": "string", "format": "binary"}}}, "Body_upload_recipe_asset_api_recipes__recipe_slug__assets_post": {"title": "Body_upload_recipe_asset_api_recipes__recipe_slug__assets_post", "required": ["name", "icon", "extension", "file"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "icon": {"title": "Icon", "type": "string"}, "extension": {"title": "Extension", "type": "string"}, "file": {"title": "File", "type": "string", "format": "binary"}}}, "CategoryBase": {"title": "CategoryBase", "required": ["name", "id", "slug"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "id": {"title": "Id", "type": "integer"}, "slug": {"title": "Slug", "type": "string"}}}, "CategoryIn": {"title": "CategoryIn", "required": ["name"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}}}, "ChangePassword": {"title": "ChangePassword", "required": ["currentPassword", "newPassword"], "type": "object", "properties": {"currentPassword": {"title": "Currentpassword", "type": "string"}, "newPassword": {"title": "Newpassword", "type": "string"}}}, "Colors": {"title": "Colors", "type": "object", "properties": {"primary": {"title": "Primary", "type": "string", "default": "#E58325"}, "accent": {"title": "Accent", "type": "string", "default": "#00457A"}, "secondary": {"title": "Secondary", "type": "string", "default": "#973542"}, "success": {"title": "Success", "type": "string", "default": "#43A047"}, "info": {"title": "Info", "type": "string", "default": "#1976D2"}, "warning": {"title": "Warning", "type": "string", "default": "#FF6F00"}, "error": {"title": "Error", "type": "string", "default": "#EF5350"}}}, "CustomPageBase": {"title": "CustomPageBase", "required": ["name", "position"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "slug": {"title": "Slug", "type": "string"}, "position": {"title": "Position", "type": "integer"}, "categories": {"title": "Categories", "type": "array", "items": {"$ref": "#/components/schemas/RecipeCategoryResponse"}, "default": []}}}, "CustomPageOut": {"title": "CustomPageOut", "required": ["name", "position", "id"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "slug": {"title": "Slug", "type": "string"}, "position": {"title": "Position", "type": "integer"}, "categories": {"title": "Categories", "type": "array", "items": {"$ref": "#/components/schemas/RecipeCategoryResponse"}, "default": []}, "id": {"title": "Id", "type": "integer"}}}, "DeclaredTypes": {"title": "DeclaredTypes", "enum": ["General", "Discord", "Gotify", "Pushover", "Home Assistant"], "type": "string", "description": "An enumeration."}, "Event": {"title": "Event", "required": ["title", "text"], "type": "object", "properties": {"id": {"title": "Id", "type": "integer"}, "title": {"title": "Title", "type": "string"}, "text": {"title": "Text", "type": "string"}, "timeStamp": {"title": "Timestamp", "type": "string", "format": "date-time"}, "category": {"allOf": [{"$ref": "#/components/schemas/EventCategory"}], "default": "general"}}}, "EventCategory": {"title": "EventCategory", "enum": ["general", "recipe", "backup", "scheduled", "migration", "group", "user"], "type": "string", "description": "An enumeration."}, "EventNotificationIn": {"title": "EventNotificationIn", "type": "object", "properties": {"id": {"title": "Id", "type": "integer"}, "name": {"title": "Name", "type": "string", "default": ""}, "type": {"allOf": [{"$ref": "#/components/schemas/DeclaredTypes"}], "default": "General"}, "general": {"title": "General", "type": "boolean", "default": true}, "recipe": {"title": "Recipe", "type": "boolean", "default": true}, "backup": {"title": "Backup", "type": "boolean", "default": true}, "scheduled": {"title": "Scheduled", "type": "boolean", "default": true}, "migration": {"title": "Migration", "type": "boolean", "default": true}, "group": {"title": "Group", "type": "boolean", "default": true}, "user": {"title": "User", "type": "boolean", "default": true}, "notificationUrl": {"title": "Notificationurl", "type": "string", "default": ""}}}, "EventNotificationOut": {"title": "EventNotificationOut", "type": "object", "properties": {"id": {"title": "Id", "type": "integer"}, "name": {"title": "Name", "type": "string", "default": ""}, "type": {"allOf": [{"$ref": "#/components/schemas/DeclaredTypes"}], "default": "General"}, "general": {"title": "General", "type": "boolean", "default": true}, "recipe": {"title": "Recipe", "type": "boolean", "default": true}, "backup": {"title": "Backup", "type": "boolean", "default": true}, "scheduled": {"title": "Scheduled", "type": "boolean", "default": true}, "migration": {"title": "Migration", "type": "boolean", "default": true}, "group": {"title": "Group", "type": "boolean", "default": true}, "user": {"title": "User", "type": "boolean", "default": true}}}, "EventsOut": {"title": "EventsOut", "required": ["total", "events"], "type": "object", "properties": {"total": {"title": "Total", "type": "integer"}, "events": {"title": "Events", "type": "array", "items": {"$ref": "#/components/schemas/Event"}}}}, "GroupBase": {"title": "GroupBase", "required": ["name"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}}}, "GroupInDB": {"title": "GroupInDB", "required": ["name", "id", "webhookEnable"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "id": {"title": "Id", "type": "integer"}, "categories": {"title": "Categories", "type": "array", "items": {"$ref": "#/components/schemas/CategoryBase"}, "default": []}, "webhookUrls": {"title": "Webhookurls", "type": "array", "items": {"type": "string"}, "default": []}, "webhookTime": {"title": "Webhooktime", "type": "string", "default": "00:00"}, "webhookEnable": {"title": "Webhookenable", "type": "boolean"}, "users": {"title": "Users", "type": "array", "items": {"$ref": "#/components/schemas/UserOut"}}, "mealplans": {"title": "Mealplans", "type": "array", "items": {"$ref": "#/components/schemas/MealPlanOut"}}, "shoppingLists": {"title": "Shoppinglists", "type": "array", "items": {"$ref": "#/components/schemas/ShoppingListOut"}}}}, "HTTPValidationError": {"title": "HTTPValidationError", "type": "object", "properties": {"detail": {"title": "Detail", "type": "array", "items": {"$ref": "#/components/schemas/ValidationError"}}}}, "ImageType": {"title": "ImageType", "enum": ["original.webp", "min-original.webp", "tiny-original.webp"], "type": "string", "description": "An enumeration."}, "ImportJob": {"title": "ImportJob", "required": ["name"], "type": "object", "properties": {"recipes": {"title": "Recipes", "type": "boolean", "default": true}, "settings": {"title": "Settings", "type": "boolean", "default": true}, "pages": {"title": "Pages", "type": "boolean", "default": true}, "themes": {"title": "Themes", "type": "boolean", "default": true}, "groups": {"title": "Groups", "type": "boolean", "default": true}, "users": {"title": "Users", "type": "boolean", "default": true}, "notifications": {"title": "Notifications", "type": "boolean", "default": true}, "name": {"title": "Name", "type": "string"}, "force": {"title": "Force", "type": "boolean", "default": false}, "rebase": {"title": "Rebase", "type": "boolean", "default": false}}, "example": {"name": "my_local_backup.zip", "recipes": true, "settings": true, "themes": true, "groups": true, "users": true}}, "Imports": {"title": "Imports", "required": ["imports", "templates"], "type": "object", "properties": {"imports": {"title": "Imports", "type": "array", "items": {"$ref": "#/components/schemas/LocalBackup"}}, "templates": {"title": "Templates", "type": "array", "items": {"type": "string"}}}, "example": {"imports": [{"name": "AutoBackup_12-1-2020.zip", "date": "2021-05-22T14:40:41.656959"}], "templates": ["recipes.md", "custom_template.md"]}}, "ListItem": {"title": "ListItem", "type": "object", "properties": {"title": {"title": "Title", "type": "string"}, "text": {"title": "Text", "type": "string", "default": ""}, "quantity": {"title": "Quantity", "type": "integer", "default": 1}, "checked": {"title": "Checked", "type": "boolean", "default": false}}}, "LocalBackup": {"title": "LocalBackup", "required": ["name", "date"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "date": {"title": "Date", "type": "string", "format": "date-time"}}}, "LoingLiveTokenIn": {"title": "LoingLiveTokenIn", "required": ["name"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}}}, "LongLiveTokenOut": {"title": "LongLiveTokenOut", "required": ["name", "id"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "id": {"title": "Id", "type": "integer"}}}, "MealDayIn": {"title": "MealDayIn", "required": ["meals"], "type": "object", "properties": {"date": {"title": "Date", "type": "string", "format": "date"}, "meals": {"title": "Meals", "type": "array", "items": {"$ref": "#/components/schemas/MealIn"}}}}, "MealIn": {"title": "MealIn", "type": "object", "properties": {"slug": {"title": "Slug", "type": "string"}, "name": {"title": "Name", "type": "string"}, "description": {"title": "Description", "type": "string"}}}, "MealPlanIn": {"title": "MealPlanIn", "required": ["group", "startDate", "endDate", "planDays"], "type": "object", "properties": {"group": {"title": "Group", "type": "string"}, "startDate": {"title": "Startdate", "type": "string", "format": "date"}, "endDate": {"title": "Enddate", "type": "string", "format": "date"}, "planDays": {"title": "Plandays", "type": "array", "items": {"$ref": "#/components/schemas/MealDayIn"}}}}, "MealPlanOut": {"title": "MealPlanOut", "required": ["group", "startDate", "endDate", "planDays", "uid"], "type": "object", "properties": {"group": {"title": "Group", "type": "string"}, "startDate": {"title": "Startdate", "type": "string", "format": "date"}, "endDate": {"title": "Enddate", "type": "string", "format": "date"}, "planDays": {"title": "Plandays", "type": "array", "items": {"$ref": "#/components/schemas/MealDayIn"}}, "uid": {"title": "Uid", "type": "integer"}}}, "Migration": {"title": "Migration", "enum": ["nextcloud", "chowdown"], "type": "string", "description": "The class defining the supported types of migrations for Mealie. Pass the\nclass attribute of the class instead of the string when using."}, "MigrationFile": {"title": "MigrationFile", "required": ["name", "date"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "date": {"title": "Date", "type": "string", "format": "date-time"}}}, "Migrations": {"title": "Migrations", "required": ["type"], "type": "object", "properties": {"type": {"title": "Type", "type": "string"}, "files": {"title": "Files", "type": "array", "items": {"$ref": "#/components/schemas/MigrationFile"}, "default": []}}}, "Nutrition": {"title": "Nutrition", "type": "object", "properties": {"calories": {"title": "Calories", "type": "string"}, "fatContent": {"title": "Fatcontent", "type": "string"}, "proteinContent": {"title": "Proteincontent", "type": "string"}, "carbohydrateContent": {"title": "Carbohydratecontent", "type": "string"}, "fiberContent": {"title": "Fibercontent", "type": "string"}, "sodiumContent": {"title": "Sodiumcontent", "type": "string"}, "sugarContent": {"title": "Sugarcontent", "type": "string"}}}, "Recipe": {"title": "Recipe", "type": "object", "properties": {"id": {"title": "Id", "type": "integer"}, "name": {"title": "Name", "type": "string"}, "slug": {"title": "Slug", "type": "string", "default": ""}, "image": {"title": "Image"}, "description": {"title": "Description", "type": "string"}, "recipeCategory": {"title": "Recipecategory", "type": "array", "items": {"type": "string"}, "default": []}, "tags": {"title": "Tags", "type": "array", "items": {"type": "string"}, "default": []}, "rating": {"title": "Rating", "type": "integer"}, "dateAdded": {"title": "Dateadded", "type": "string", "format": "date"}, "dateUpdated": {"title": "Dateupdated", "type": "string", "format": "date-time"}, "recipeYield": {"title": "Recipeyield", "type": "string"}, "recipeIngredient": {"title": "Recipeingredient", "type": "array", "items": {"type": "string"}}, "recipeInstructions": {"title": "Recipeinstructions", "type": "array", "items": {"$ref": "#/components/schemas/RecipeStep"}}, "nutrition": {"$ref": "#/components/schemas/Nutrition"}, "tools": {"title": "Tools", "type": "array", "items": {"type": "string"}, "default": []}, "totalTime": {"title": "Totaltime", "type": "string"}, "prepTime": {"title": "Preptime", "type": "string"}, "performTime": {"title": "Performtime", "type": "string"}, "settings": {"$ref": "#/components/schemas/RecipeSettings"}, "assets": {"title": "Assets", "type": "array", "items": {"$ref": "#/components/schemas/RecipeAsset"}, "default": []}, "notes": {"title": "Notes", "type": "array", "items": {"$ref": "#/components/schemas/RecipeNote"}, "default": []}, "orgURL": {"title": "Orgurl", "type": "string"}, "extras": {"title": "Extras", "type": "object", "default": {}}}, "example": {"name": "Chicken and Rice With Leeks and Salsa Verde", "description": "This one-skillet dinner gets deep oniony flavor from lots of leeks cooked down to jammy tenderness.", "image": "chicken-and-rice-with-leeks-and-salsa-verde.jpg", "recipe_yield": "4 Servings", "recipe_ingredient": ["1 1/2 lb. skinless, boneless chicken thighs (4-8 depending on size)", "Kosher salt, freshly ground pepper", "3 Tbsp. unsalted butter, divided"], "recipe_instructions": [{"text": "Season chicken with salt and pepper."}], "slug": "chicken-and-rice-with-leeks-and-salsa-verde", "tags": ["favorite", "yummy!"], "recipe_category": ["Dinner", "Pasta"], "notes": [{"title": "Watch Out!", "text": "Prep the day before!"}], "org_url": "https://www.bonappetit.com/recipe/chicken-and-rice-with-leeks-and-salsa-verde", "rating": 3, "extras": {"message": "Don't forget to defrost the chicken!"}}}, "RecipeAsset": {"title": "RecipeAsset", "required": ["name", "icon"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "icon": {"title": "Icon", "type": "string"}, "fileName": {"title": "Filename", "type": "string"}}}, "RecipeCategoryResponse": {"title": "RecipeCategoryResponse", "required": ["name", "id", "slug"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "id": {"title": "Id", "type": "integer"}, "slug": {"title": "Slug", "type": "string"}, "recipes": {"title": "Recipes", "type": "array", "items": {"$ref": "#/components/schemas/Recipe"}}}, "example": {"id": 1, "name": "dinner", "recipes": [{}]}}, "RecipeNote": {"title": "RecipeNote", "required": ["title", "text"], "type": "object", "properties": {"title": {"title": "Title", "type": "string"}, "text": {"title": "Text", "type": "string"}}}, "RecipeSettings": {"title": "RecipeSettings", "type": "object", "properties": {"public": {"title": "Public", "type": "boolean", "default": true}, "showNutrition": {"title": "Shownutrition", "type": "boolean", "default": true}, "showAssets": {"title": "Showassets", "type": "boolean", "default": true}, "landscapeView": {"title": "Landscapeview", "type": "boolean", "default": true}}}, "RecipeStep": {"title": "RecipeStep", "required": ["text"], "type": "object", "properties": {"title": {"title": "Title", "type": "string", "default": ""}, "text": {"title": "Text", "type": "string"}}}, "RecipeSummary": {"title": "RecipeSummary", "type": "object", "properties": {"id": {"title": "Id", "type": "integer"}, "name": {"title": "Name", "type": "string"}, "slug": {"title": "Slug", "type": "string", "default": ""}, "image": {"title": "Image"}, "description": {"title": "Description", "type": "string"}, "recipeCategory": {"title": "Recipecategory", "type": "array", "items": {"type": "string"}, "default": []}, "tags": {"title": "Tags", "type": "array", "items": {"type": "string"}, "default": []}, "rating": {"title": "Rating", "type": "integer"}, "dateAdded": {"title": "Dateadded", "type": "string", "format": "date"}, "dateUpdated": {"title": "Dateupdated", "type": "string", "format": "date-time"}}}, "RecipeTagResponse": {"title": "RecipeTagResponse", "required": ["name", "id", "slug"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "id": {"title": "Id", "type": "integer"}, "slug": {"title": "Slug", "type": "string"}, "recipes": {"title": "Recipes", "type": "array", "items": {"$ref": "#/components/schemas/Recipe"}}}, "example": {"id": 1, "name": "dinner", "recipes": [{}]}}, "RecipeURLIn": {"title": "RecipeURLIn", "required": ["url"], "type": "object", "properties": {"url": {"title": "Url", "type": "string"}}, "example": {"url": "https://myfavoriterecipes.com/recipes"}}, "ShoppingListIn": {"title": "ShoppingListIn", "required": ["name", "items"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "group": {"title": "Group", "type": "string"}, "items": {"title": "Items", "type": "array", "items": {"$ref": "#/components/schemas/ListItem"}}}}, "ShoppingListOut": {"title": "ShoppingListOut", "required": ["name", "items", "id"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "group": {"title": "Group", "type": "string"}, "items": {"title": "Items", "type": "array", "items": {"$ref": "#/components/schemas/ListItem"}}, "id": {"title": "Id", "type": "integer"}}}, "SignUpIn": {"title": "SignUpIn", "required": ["name", "admin"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "admin": {"title": "Admin", "type": "boolean"}}}, "SignUpOut": {"title": "SignUpOut", "required": ["name", "admin", "token", "id"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "admin": {"title": "Admin", "type": "boolean"}, "token": {"title": "Token", "type": "string"}, "id": {"title": "Id", "type": "integer"}}}, "SignUpToken": {"title": "SignUpToken", "required": ["name", "admin", "token"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "admin": {"title": "Admin", "type": "boolean"}, "token": {"title": "Token", "type": "string"}}}, "SiteSettings": {"title": "SiteSettings", "type": "object", "properties": {"language": {"title": "Language", "type": "string", "default": "en-US"}, "firstDayOfWeek": {"title": "Firstdayofweek", "type": "integer", "default": 0}, "showRecent": {"title": "Showrecent", "type": "boolean", "default": true}, "cardsPerSection": {"title": "Cardspersection", "type": "integer", "default": 9}, "categories": {"title": "Categories", "type": "array", "items": {"$ref": "#/components/schemas/CategoryBase"}, "default": []}}, "example": {"language": "en", "firstDayOfWeek": 0, "showRecent": true, "categories": [{"id": 1, "name": "thanksgiving", "slug": "thanksgiving"}, {"id": 2, "name": "homechef", "slug": "homechef"}, {"id": 3, "name": "potatoes", "slug": "potatoes"}]}}, "SiteTheme": {"title": "SiteTheme", "type": "object", "properties": {"id": {"title": "Id", "type": "integer"}, "name": {"title": "Name", "type": "string", "default": "default"}, "colors": {"title": "Colors", "allOf": [{"$ref": "#/components/schemas/Colors"}], "default": {"primary": "#E58325", "accent": "#00457A", "secondary": "#973542", "success": "#43A047", "info": "#1976D2", "warning": "#FF6F00", "error": "#EF5350"}}}, "example": {"name": "default", "colors": {"primary": "#E58325", "accent": "#00457A", "secondary": "#973542", "success": "#5AB1BB", "info": "#4990BA", "warning": "#FF4081", "error": "#EF5350"}}}, "TagIn": {"title": "TagIn", "required": ["name"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}}}, "TestEvent": {"title": "TestEvent", "type": "object", "properties": {"id": {"title": "Id", "type": "integer"}, "testUrl": {"title": "Testurl", "type": "string"}}}, "UpdateGroup": {"title": "UpdateGroup", "required": ["name", "id", "webhookEnable"], "type": "object", "properties": {"name": {"title": "Name", "type": "string"}, "id": {"title": "Id", "type": "integer"}, "categories": {"title": "Categories", "type": "array", "items": {"$ref": "#/components/schemas/CategoryBase"}, "default": []}, "webhookUrls": {"title": "Webhookurls", "type": "array", "items": {"type": "string"}, "default": []}, "webhookTime": {"title": "Webhooktime", "type": "string", "default": "00:00"}, "webhookEnable": {"title": "Webhookenable", "type": "boolean"}}}, "UserBase": {"title": "UserBase", "required": ["email", "admin"], "type": "object", "properties": {"fullName": {"title": "Fullname", "type": "string"}, "email": {"title": "Email", "type": "string"}, "admin": {"title": "Admin", "type": "boolean"}, "group": {"title": "Group", "type": "string"}}}, "UserIn": {"title": "UserIn", "required": ["email", "admin", "password"], "type": "object", "properties": {"fullName": {"title": "Fullname", "type": "string"}, "email": {"title": "Email", "type": "string"}, "admin": {"title": "Admin", "type": "boolean"}, "group": {"title": "Group", "type": "string"}, "password": {"title": "Password", "type": "string"}}}, "UserOut": {"title": "UserOut", "required": ["email", "admin", "group", "id"], "type": "object", "properties": {"fullName": {"title": "Fullname", "type": "string"}, "email": {"title": "Email", "type": "string"}, "admin": {"title": "Admin", "type": "boolean"}, "group": {"title": "Group", "type": "string"}, "id": {"title": "Id", "type": "integer"}, "tokens": {"title": "Tokens", "type": "array", "items": {"$ref": "#/components/schemas/LongLiveTokenOut"}}}}, "ValidationError": {"title": "ValidationError", "required": ["loc", "msg", "type"], "type": "object", "properties": {"loc": {"title": "Location", "type": "array", "items": {"type": "string"}}, "msg": {"title": "Message", "type": "string"}, "type": {"title": "Error Type", "type": "string"}}}}, "securitySchemes": {"OAuth2PasswordBearer": {"type": "oauth2", "flows": {"password": {"scopes": {}, "tokenUrl": "/api/auth/token"}}}}}}
\ No newline at end of file