mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 14:33:33 -07:00
custom pages starter
This commit is contained in:
parent
318cbceee6
commit
341faace21
20 changed files with 447 additions and 81 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,6 +1,6 @@
|
|||
# Byte-compiled / optimized / DLL files
|
||||
.env
|
||||
__pycache__/
|
||||
*__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
# frontend/.env.development
|
||||
|
|
|
@ -76,8 +76,6 @@ export default {
|
|||
mounted() {
|
||||
this.$store.dispatch("initTheme");
|
||||
this.$store.dispatch("requestRecentRecipes");
|
||||
this.$store.dispatch("requestHomePageSettings");
|
||||
this.$store.dispatch("requestSiteSettings");
|
||||
this.$store.dispatch("refreshToken");
|
||||
this.$store.dispatch("requestCurrentGroup");
|
||||
this.darkModeSystemCheck();
|
||||
|
|
138
frontend/src/components/Admin/General/CustomPageCreator.vue
Normal file
138
frontend/src/components/Admin/General/CustomPageCreator.vue
Normal file
|
@ -0,0 +1,138 @@
|
|||
<template>
|
||||
<v-card flat>
|
||||
<v-card-text>
|
||||
<h2 class="mt-1 mb-1 ">
|
||||
Custom Pages
|
||||
<span>
|
||||
<v-btn color="success" small class="ml-3">
|
||||
New
|
||||
</v-btn>
|
||||
</span>
|
||||
</h2>
|
||||
<v-row class="mt-1">
|
||||
<v-col
|
||||
:sm="6"
|
||||
:md="6"
|
||||
:lg="4"
|
||||
:xl="3"
|
||||
v-for="item in customPages"
|
||||
:key="item + item.id"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="headline">{{ item.name }}</v-card-title>
|
||||
<v-divider></v-divider>
|
||||
|
||||
<v-card-text>
|
||||
Card Position: {{ item.position }}
|
||||
<div>
|
||||
<v-chip
|
||||
v-for="cat in item.categories"
|
||||
:key="cat.slug + cat.id"
|
||||
class="my-2 mr-2"
|
||||
label
|
||||
small
|
||||
color="accent lighten-1"
|
||||
>
|
||||
{{ cat.name }}
|
||||
</v-chip>
|
||||
</div>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-btn text small color="error">
|
||||
Delete
|
||||
</v-btn>
|
||||
<v-spacer> </v-spacer>
|
||||
<v-btn small text color="success">
|
||||
Edit
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
customPages: [
|
||||
{
|
||||
id: 0,
|
||||
name: "My Page Name",
|
||||
slug: "my-page-name",
|
||||
position: 0,
|
||||
categories: [
|
||||
{
|
||||
id: 2,
|
||||
slug: "brownie",
|
||||
name: "brownie",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
slug: "dessert",
|
||||
name: "dessert",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
slug: "drink",
|
||||
name: "Drink",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "My Page Name 1",
|
||||
slug: "my-page-name",
|
||||
position: 1,
|
||||
categories: [
|
||||
{
|
||||
id: 2,
|
||||
slug: "brownie",
|
||||
name: "brownie",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
slug: "dessert",
|
||||
name: "dessert",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
slug: "drink",
|
||||
name: "Drink",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "My Page Name 2",
|
||||
slug: "my-page-name",
|
||||
position: 2,
|
||||
categories: [
|
||||
{
|
||||
id: 2,
|
||||
slug: "brownie",
|
||||
name: "brownie",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
slug: "dessert",
|
||||
name: "dessert",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
slug: "drink",
|
||||
name: "Drink",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<div class="mt-n5">
|
||||
<div class="mt-n5" v-if="recipes">
|
||||
<v-card flat class="transparent" height="60px">
|
||||
<v-card-text>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-row v-if="title != null">
|
||||
<v-col >
|
||||
<v-btn-toggle group>
|
||||
<v-btn text :to="`/recipes/${title.toLowerCase()}`">
|
||||
{{ title.toUpperCase() }}
|
||||
|
@ -15,15 +15,21 @@
|
|||
<v-menu offset-y v-if="sortable">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn-toggle group>
|
||||
<v-btn text v-bind="attrs" v-on="on">{{$t('general.sort')}}</v-btn>
|
||||
<v-btn text v-bind="attrs" v-on="on">{{
|
||||
$t("general.sort")
|
||||
}}</v-btn>
|
||||
</v-btn-toggle>
|
||||
</template>
|
||||
<v-list>
|
||||
<v-list-item @click="$emit('sort-recent')">
|
||||
<v-list-item-title>{{$t('general.recent')}}</v-list-item-title>
|
||||
<v-list-item-title>{{
|
||||
$t("general.recent")
|
||||
}}</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item @click="$emit('sort')">
|
||||
<v-list-item-title>{{$t('general.sort-alphabetically')}}</v-list-item-title>
|
||||
<v-list-item-title>{{
|
||||
$t("general.sort-alphabetically")
|
||||
}}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
@ -31,44 +37,45 @@
|
|||
</v-row>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<v-row v-if="!viewScale">
|
||||
<v-col
|
||||
:sm="6"
|
||||
:md="6"
|
||||
:lg="4"
|
||||
:xl="3"
|
||||
v-for="recipe in recipes.slice(0, cardLimit)"
|
||||
:key="recipe.name"
|
||||
>
|
||||
<RecipeCard
|
||||
:name="recipe.name"
|
||||
:description="recipe.description"
|
||||
:slug="recipe.slug"
|
||||
:rating="recipe.rating"
|
||||
:image="recipe.image"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-else dense>
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="12"
|
||||
md="6"
|
||||
lg="4"
|
||||
xl="3"
|
||||
v-for="recipe in recipes.slice(0, cardLimit)"
|
||||
:key="recipe.name"
|
||||
|
||||
>
|
||||
<MobileRecipeCard
|
||||
:name="recipe.name"
|
||||
:description="recipe.description"
|
||||
:slug="recipe.slug"
|
||||
:rating="recipe.rating"
|
||||
:image="recipe.image"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<div v-if="recipes">
|
||||
<v-row v-if="!viewScale">
|
||||
<v-col
|
||||
:sm="6"
|
||||
:md="6"
|
||||
:lg="4"
|
||||
:xl="3"
|
||||
v-for="recipe in recipes.slice(0, cardLimit)"
|
||||
:key="recipe.name"
|
||||
>
|
||||
<RecipeCard
|
||||
:name="recipe.name"
|
||||
:description="recipe.description"
|
||||
:slug="recipe.slug"
|
||||
:rating="recipe.rating"
|
||||
:image="recipe.image"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row v-else dense>
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="12"
|
||||
md="6"
|
||||
lg="4"
|
||||
xl="3"
|
||||
v-for="recipe in recipes.slice(0, cardLimit)"
|
||||
:key="recipe.name"
|
||||
>
|
||||
<MobileRecipeCard
|
||||
:name="recipe.name"
|
||||
:description="recipe.description"
|
||||
:slug="recipe.slug"
|
||||
:rating="recipe.rating"
|
||||
:image="recipe.image"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -84,12 +91,19 @@ export default {
|
|||
sortable: {
|
||||
default: false,
|
||||
},
|
||||
title: String,
|
||||
title: {
|
||||
default: null
|
||||
},
|
||||
recipes: Array,
|
||||
cardLimit: {
|
||||
default: 6,
|
||||
default: 999,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
recipes(val) {
|
||||
console.log(val)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
viewScale() {
|
||||
switch (this.$vuetify.breakpoint.name) {
|
||||
|
|
|
@ -14,15 +14,19 @@
|
|||
<v-divider></v-divider>
|
||||
<HomePageSettings />
|
||||
<v-divider></v-divider>
|
||||
<CustomPageCreator />
|
||||
<v-divider></v-divider>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HomePageSettings from "@/components/Admin/General/HomePageSettings";
|
||||
import CustomPageCreator from "@/components/Admin/General/CustomPageCreator";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HomePageSettings,
|
||||
CustomPageCreator,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
<v-container>
|
||||
<CategorySidebar />
|
||||
<CardSection
|
||||
v-if="showRecent"
|
||||
v-if="siteSettings.showRecent"
|
||||
:title="$t('page.recent')"
|
||||
:recipes="recentRecipes"
|
||||
:card-limit="showLimit"
|
||||
:card-limit="siteSettings.cardsPerSection"
|
||||
/>
|
||||
<CardSection
|
||||
:sortable="true"
|
||||
|
@ -13,7 +13,7 @@
|
|||
:key="section.name + section.position"
|
||||
:title="section.name"
|
||||
:recipes="section.recipes"
|
||||
:card-limit="showLimit"
|
||||
:card-limit="siteSettings.cardsPerSection"
|
||||
@sort="sortAZ(index)"
|
||||
@sort-recent="sortRecent(index)"
|
||||
/>
|
||||
|
@ -35,14 +35,9 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
showRecent() {
|
||||
return this.$store.getters.getShowRecent;
|
||||
},
|
||||
showLimit() {
|
||||
return this.$store.getters.getShowLimit;
|
||||
},
|
||||
homeCategories() {
|
||||
return this.$store.getters.getHomeCategories;
|
||||
siteSettings() {
|
||||
console.log(this.$store.getters.getSiteSettings);
|
||||
return this.$store.getters.getSiteSettings;
|
||||
},
|
||||
recentRecipes() {
|
||||
let recipes = this.$store.getters.getRecentRecipes;
|
||||
|
@ -55,9 +50,11 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
async buildPage() {
|
||||
this.homeCategories.forEach(async element => {
|
||||
await this.$store.dispatch("requestSiteSettings");
|
||||
this.siteSettings.categories.forEach(async element => {
|
||||
let recipes = await this.getRecipeByCategory(element.slug);
|
||||
recipes.position = element.position;
|
||||
if (recipes.recipes.length < 0 ) recipes.recipes = []
|
||||
console.log(recipes)
|
||||
this.recipeByCategory.push(recipes);
|
||||
});
|
||||
},
|
||||
|
|
93
frontend/src/pages/Recipes/CustomPage.vue
Normal file
93
frontend/src/pages/Recipes/CustomPage.vue
Normal file
|
@ -0,0 +1,93 @@
|
|||
<template>
|
||||
<v-container>
|
||||
<CategorySidebar />
|
||||
<v-card flat height="100%">
|
||||
<v-card-title class="text-center justify-center py-6 headline">
|
||||
Category Section
|
||||
</v-card-title>
|
||||
<div v-if="render">
|
||||
<v-tabs v-model="tab" background-color="transparent" grow>
|
||||
<v-tab v-for="item in categories" :key="item.slug">
|
||||
{{ item.name }}
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
|
||||
<v-tabs-items v-model="tab">
|
||||
<v-tab-item
|
||||
v-for="(item, index) in categories"
|
||||
:key="item.slug + index"
|
||||
>
|
||||
<CardSection class="mb-5 mx-1" :recipes="filterRecipe(item.slug)" />
|
||||
</v-tab-item>
|
||||
</v-tabs-items>
|
||||
</div>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CardSection from "@/components/UI/CardSection";
|
||||
import CategorySidebar from "@/components/UI/CategorySidebar";
|
||||
import api from "@/api";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CardSection,
|
||||
CategorySidebar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tab: null,
|
||||
render: false,
|
||||
recipeStore: [],
|
||||
categories: [
|
||||
{
|
||||
id: 2,
|
||||
slug: "brownie",
|
||||
name: "brownie",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
slug: "dessert",
|
||||
name: "dessert",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
slug: "drink",
|
||||
name: "Drink",
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
tab(val) {
|
||||
console.log(val);
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
await this.buildPage();
|
||||
this.render = true;
|
||||
},
|
||||
methods: {
|
||||
async buildPage() {
|
||||
this.categories.forEach(async element => {
|
||||
let categoryRecipes = await this.getRecipeByCategory(element.slug);
|
||||
this.recipeStore.push(categoryRecipes);
|
||||
});
|
||||
},
|
||||
async getRecipeByCategory(category) {
|
||||
return await api.categories.get_recipes_in_category(category);
|
||||
},
|
||||
filterRecipe(slug) {
|
||||
const storeCategory = this.recipeStore.find(
|
||||
element => element.slug === slug
|
||||
);
|
||||
return storeCategory ? storeCategory.recipes : [];
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
|
@ -3,6 +3,7 @@ import Page404 from "@/pages/404Page";
|
|||
import SearchPage from "@/pages/SearchPage";
|
||||
import ViewRecipe from "@/pages/Recipe/ViewRecipe";
|
||||
import NewRecipe from "@/pages/Recipe/NewRecipe";
|
||||
import CustomPage from "@/pages/Recipes/CustomPage";
|
||||
import AllRecipes from "@/pages/Recipes/AllRecipes";
|
||||
import CategoryPage from "@/pages/Recipes/CategoryPage";
|
||||
import Planner from "@/pages/MealPlan/Planner";
|
||||
|
@ -31,6 +32,7 @@ export const routes = [
|
|||
{ path: "/debug", component: Debug },
|
||||
{ path: "/search", component: SearchPage },
|
||||
{ path: "/recipes/all", component: AllRecipes },
|
||||
{ path: "/recipes/test-page", component: CustomPage },
|
||||
{ path: "/recipes/:category", component: CategoryPage },
|
||||
{ path: "/recipe/:recipe", component: ViewRecipe },
|
||||
{ path: "/new/", component: NewRecipe },
|
||||
|
|
|
@ -4,7 +4,6 @@ import api from "@/api";
|
|||
import createPersistedState from "vuex-persistedstate";
|
||||
import userSettings from "./modules/userSettings";
|
||||
import language from "./modules/language";
|
||||
import homePage from "./modules/homePage";
|
||||
import siteSettings from "./modules/siteSettings";
|
||||
import groups from "./modules/groups";
|
||||
|
||||
|
@ -13,13 +12,12 @@ Vue.use(Vuex);
|
|||
const store = new Vuex.Store({
|
||||
plugins: [
|
||||
createPersistedState({
|
||||
paths: ["userSettings", "language", "homePage", "SideSettings"],
|
||||
paths: ["userSettings", "language", "SideSettings"],
|
||||
}),
|
||||
],
|
||||
modules: {
|
||||
userSettings,
|
||||
language,
|
||||
homePage,
|
||||
siteSettings,
|
||||
groups,
|
||||
},
|
||||
|
|
|
@ -11,7 +11,7 @@ const state = {
|
|||
|
||||
const mutations = {
|
||||
setSettings(state, payload) {
|
||||
state.settings = payload;
|
||||
state.siteSettings = payload;
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@ from fastapi.logger import logger
|
|||
|
||||
# import utils.startup as startup
|
||||
from mealie.core.config import APP_VERSION, PORT, docs_url, redoc_url
|
||||
from mealie.routes import backup_routes, debug_routes, migration_routes, setting_routes, theme_routes
|
||||
from mealie.routes import backup_routes, debug_routes, migration_routes, theme_routes
|
||||
from mealie.routes.site_settings import all_settings
|
||||
from mealie.routes.groups import groups
|
||||
from mealie.routes.mealplans import mealplans
|
||||
from mealie.routes.recipe import all_recipe_routes, category_routes, recipe_crud_routes, tag_routes
|
||||
|
@ -36,7 +37,7 @@ def api_routers():
|
|||
# Meal Routes
|
||||
app.include_router(mealplans.router)
|
||||
# Settings Routes
|
||||
app.include_router(setting_routes.router)
|
||||
app.include_router(all_settings.router)
|
||||
app.include_router(theme_routes.router)
|
||||
# Backups/Imports Routes
|
||||
app.include_router(backup_routes.router)
|
||||
|
|
|
@ -2,14 +2,14 @@ from mealie.db.db_base import BaseDocument
|
|||
from mealie.db.models.group import Group
|
||||
from mealie.db.models.mealplan import MealPlanModel
|
||||
from mealie.db.models.recipe.recipe import Category, RecipeModel, Tag
|
||||
from mealie.db.models.settings import SiteSettings
|
||||
from mealie.db.models.settings import CustomPage, SiteSettings
|
||||
from mealie.db.models.sign_up import SignUp
|
||||
from mealie.db.models.theme import SiteThemeModel
|
||||
from mealie.db.models.users import User
|
||||
from mealie.schema.category import RecipeCategoryResponse, RecipeTagResponse
|
||||
from mealie.schema.meal import MealPlanInDB
|
||||
from mealie.schema.recipe import Recipe
|
||||
from mealie.schema.settings import SiteSettings as SiteSettingsSchema
|
||||
from mealie.schema.settings import CustomPageOut, SiteSettings as SiteSettingsSchema
|
||||
from mealie.schema.sign_up import SignUpOut
|
||||
from mealie.schema.theme import SiteTheme
|
||||
from mealie.schema.user import GroupInDB, UserInDB
|
||||
|
@ -118,6 +118,13 @@ class _SignUps(BaseDocument):
|
|||
self.orm_mode = True
|
||||
self.schema = SignUpOut
|
||||
|
||||
class _CustomPages(BaseDocument):
|
||||
def __init__(self) -> None:
|
||||
self.primary_key = "id"
|
||||
self.sql_model = CustomPage
|
||||
self.orm_mode = True
|
||||
self.schema = CustomPageOut
|
||||
|
||||
|
||||
class Database:
|
||||
def __init__(self) -> None:
|
||||
|
@ -130,6 +137,7 @@ class Database:
|
|||
self.users = _Users()
|
||||
self.sign_ups = _SignUps()
|
||||
self.groups = _Groups()
|
||||
self.custom_pages = _CustomPages()
|
||||
|
||||
|
||||
db = Database()
|
||||
|
|
|
@ -26,6 +26,13 @@ recipes2categories = sa.Table(
|
|||
sa.Column("category_slug", sa.String, sa.ForeignKey("categories.slug")),
|
||||
)
|
||||
|
||||
custom_pages2categories = sa.Table(
|
||||
"custom_pages2categories",
|
||||
SqlAlchemyBase.metadata,
|
||||
sa.Column("custom_page_id", sa.Integer, sa.ForeignKey("custom_pages.id")),
|
||||
sa.Column("category_slug", sa.String, sa.ForeignKey("categories.slug")),
|
||||
)
|
||||
|
||||
|
||||
class Category(SqlAlchemyBase):
|
||||
__tablename__ = "categories"
|
||||
|
@ -36,7 +43,7 @@ class Category(SqlAlchemyBase):
|
|||
|
||||
@validates("name")
|
||||
def validate_name(self, key, name):
|
||||
assert not name == ""
|
||||
assert name != ""
|
||||
return name
|
||||
|
||||
def __init__(self, name) -> None:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import sqlalchemy as sa
|
||||
import sqlalchemy.orm as orm
|
||||
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
|
||||
from mealie.db.models.recipe.category import Category, site_settings2categories
|
||||
from mealie.db.models.recipe.category import Category, custom_pages2categories, site_settings2categories
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
|
||||
|
@ -29,7 +29,29 @@ class SiteSettings(SqlAlchemyBase, BaseMixins):
|
|||
self.language = language
|
||||
self.cards_per_section = cards_per_section
|
||||
self.show_recent = show_recent
|
||||
self.categories = [Category.get_ref(session=session, name=cat.get("slug")) for cat in categories]
|
||||
self.categories = [Category.get_ref(session=session, slug=cat.get("slug")) for cat in categories]
|
||||
|
||||
def update(self, *args, **kwarg):
|
||||
self.__init__(*args, **kwarg)
|
||||
|
||||
|
||||
class CustomPage(SqlAlchemyBase, BaseMixins):
|
||||
__tablename__ = "custom_pages"
|
||||
id = sa.Column(sa.Integer, primary_key=True)
|
||||
position = sa.Column(sa.Integer, nullable=False)
|
||||
name = sa.Column(sa.String, nullable=False)
|
||||
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=[]) -> None:
|
||||
self.name = name
|
||||
self.slug = slug
|
||||
self.position = position
|
||||
self.categories = [Category.get_ref(session=session, slug=cat.get("slug")) for cat in categories]
|
||||
|
||||
def update(self, *args, **kwarg):
|
||||
self.__init__(*args, **kwarg)
|
||||
|
|
7
mealie/routes/site_settings/all_settings.py
Normal file
7
mealie/routes/site_settings/all_settings.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
from fastapi import APIRouter
|
||||
from mealie.routes.site_settings import custom_pages, site_settings
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
router.include_router(custom_pages.router)
|
||||
router.include_router(site_settings.router)
|
52
mealie/routes/site_settings/custom_pages.py
Normal file
52
mealie/routes/site_settings/custom_pages.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
from fastapi import APIRouter, Depends
|
||||
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.settings import CustomPageBase
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.schema.user import UserInDB
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
router = APIRouter(prefix="/api/site-settings/custom-pages", tags=["Settings"])
|
||||
|
||||
|
||||
@router.get("")
|
||||
def get_custom_pages(session: Session = Depends(generate_session)):
|
||||
""" Returns the sites custom pages """
|
||||
|
||||
return db.custom_pages.get_all(session)
|
||||
|
||||
|
||||
@router.post("")
|
||||
async def create_new_page(
|
||||
new_page: CustomPageBase,
|
||||
session: Session = Depends(generate_session),
|
||||
current_user: UserInDB = Depends(get_current_user),
|
||||
):
|
||||
""" Creates a new Custom Page """
|
||||
|
||||
db.custom_pages.create(session, new_page.dict())
|
||||
|
||||
return SnackResponse.success("New Page Created")
|
||||
|
||||
|
||||
@router.get("/{id}")
|
||||
async def delete_custom_page(
|
||||
id: int,
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Removes a custom page from the database """
|
||||
|
||||
return db.custom_pages.get(session, id)
|
||||
|
||||
|
||||
@router.delete("/{id}")
|
||||
async def delete_custom_page(
|
||||
id: int,
|
||||
session: Session = Depends(generate_session),
|
||||
current_user: UserInDB = Depends(get_current_user),
|
||||
):
|
||||
""" Removes a custom page from the database """
|
||||
|
||||
db.custom_pages.delete(session, id)
|
||||
return
|
|
@ -16,9 +16,7 @@ router = APIRouter(prefix="/api/site-settings", tags=["Settings"])
|
|||
def get_main_settings(session: Session = Depends(generate_session)):
|
||||
""" Returns basic site settings """
|
||||
|
||||
data = db.settings.get(session, 1)
|
||||
|
||||
return data
|
||||
return db.settings.get(session, 1)
|
||||
|
||||
|
||||
@router.put("")
|
|
@ -101,11 +101,10 @@ class Recipe(BaseModel):
|
|||
name: str = values["name"]
|
||||
calc_slug: str = slugify(name)
|
||||
|
||||
if slug == calc_slug:
|
||||
return slug
|
||||
else:
|
||||
if slug != calc_slug:
|
||||
slug = calc_slug
|
||||
return slug
|
||||
|
||||
return slug
|
||||
|
||||
|
||||
class AllRecipeRequest(BaseModel):
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
from typing import Optional
|
||||
|
||||
from fastapi_camelcase import CamelModel
|
||||
|
||||
from mealie.schema.category import CategoryBase
|
||||
from pydantic import validator
|
||||
from slugify import slugify
|
||||
|
||||
|
||||
class SiteSettings(CamelModel):
|
||||
|
@ -25,3 +26,30 @@ class SiteSettings(CamelModel):
|
|||
],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CustomPageBase(CamelModel):
|
||||
name: str
|
||||
slug: Optional[str]
|
||||
position: int
|
||||
categories: list[CategoryBase] = []
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
@validator("slug", always=True, pre=True)
|
||||
def validate_slug(slug: str, values):
|
||||
name: str = values["name"]
|
||||
calc_slug: str = slugify(name)
|
||||
|
||||
if slug != calc_slug:
|
||||
slug = calc_slug
|
||||
|
||||
return slug
|
||||
|
||||
|
||||
class CustomPageOut(CustomPageBase):
|
||||
id: int
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue