refactor(backend): 🔥 Remove Backend Theme Support
This commit is contained in:
parent
dd1b1ad067
commit
161618808e
15 changed files with 11 additions and 252 deletions
|
@ -4,7 +4,7 @@ from fastapi.middleware.gzip import GZipMiddleware
|
|||
|
||||
from mealie.core.config import APP_VERSION, settings
|
||||
from mealie.core.root_logger import get_logger
|
||||
from mealie.routes import backup_routes, debug_routes, migration_routes, router, theme_routes, utility_routes
|
||||
from mealie.routes import backup_routes, debug_routes, migration_routes, router, utility_routes
|
||||
from mealie.routes.about import about_router
|
||||
from mealie.routes.mealplans import meal_plan_router
|
||||
from mealie.routes.media import media_router
|
||||
|
@ -39,8 +39,6 @@ def api_routers():
|
|||
app.include_router(meal_plan_router)
|
||||
# Settings Routes
|
||||
app.include_router(settings_router)
|
||||
app.include_router(theme_routes.public_router)
|
||||
app.include_router(theme_routes.user_router)
|
||||
# Backups/Imports Routes
|
||||
app.include_router(backup_routes.router)
|
||||
# Migration Routes
|
||||
|
|
|
@ -11,11 +11,9 @@ from mealie.db.models.recipe.recipe import RecipeModel, Tag
|
|||
from mealie.db.models.settings import CustomPage, SiteSettings
|
||||
from mealie.db.models.shopping_list import ShoppingList
|
||||
from mealie.db.models.sign_up import SignUp
|
||||
from mealie.db.models.theme import SiteThemeModel
|
||||
from mealie.db.models.users import LongLiveToken, User
|
||||
from mealie.schema.admin import CustomPageOut
|
||||
from mealie.schema.admin import SiteSettings as SiteSettingsSchema
|
||||
from mealie.schema.admin import SiteTheme
|
||||
from mealie.schema.events import Event as EventSchema
|
||||
from mealie.schema.events import EventNotificationIn
|
||||
from mealie.schema.meal_plan import MealPlanOut, ShoppingListOut
|
||||
|
@ -73,7 +71,6 @@ class DatabaseAccessLayer:
|
|||
|
||||
# Site
|
||||
self.settings = BaseAccessModel(DEFAULT_PK, SiteSettings, SiteSettingsSchema)
|
||||
self.themes = BaseAccessModel(DEFAULT_PK, SiteThemeModel, SiteTheme)
|
||||
self.sign_ups = BaseAccessModel("token", SignUp, SignUpOut)
|
||||
self.custom_pages = BaseAccessModel(DEFAULT_PK, CustomPage, CustomPageOut)
|
||||
self.event_notifications = BaseAccessModel(DEFAULT_PK, EventNotification, EventNotificationIn)
|
||||
|
|
|
@ -5,5 +5,4 @@ from .recipe.recipe import *
|
|||
from .settings import *
|
||||
from .shopping_list import *
|
||||
from .sign_up import *
|
||||
from .theme import *
|
||||
from .users import *
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
import sqlalchemy.orm as orm
|
||||
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
|
||||
from sqlalchemy import Column, ForeignKey, Integer, String
|
||||
|
||||
|
||||
class SiteThemeModel(SqlAlchemyBase, BaseMixins):
|
||||
__tablename__ = "site_theme"
|
||||
id = Column(Integer, primary_key=True, unique=True)
|
||||
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, **_) -> None:
|
||||
self.name = name
|
||||
self.colors = ThemeColorsModel(**colors)
|
||||
|
||||
|
||||
class ThemeColorsModel(SqlAlchemyBase, BaseMixins):
|
||||
__tablename__ = "theme_colors"
|
||||
id = Column(Integer, primary_key=True)
|
||||
parent_id = Column(Integer, ForeignKey("site_theme.id"))
|
||||
primary = Column(String)
|
||||
accent = Column(String)
|
||||
secondary = Column(String)
|
||||
success = Column(String)
|
||||
info = Column(String)
|
||||
warning = Column(String)
|
||||
error = Column(String)
|
|
@ -44,7 +44,6 @@ def export_database(background_tasks: BackgroundTasks, data: BackupJob, session:
|
|||
export_recipes=data.options.recipes,
|
||||
export_settings=data.options.settings,
|
||||
export_pages=data.options.pages,
|
||||
export_themes=data.options.themes,
|
||||
export_users=data.options.users,
|
||||
export_groups=data.options.groups,
|
||||
export_notifications=data.options.notifications,
|
||||
|
@ -93,7 +92,6 @@ def import_database(
|
|||
import_recipes=import_data.recipes,
|
||||
import_settings=import_data.settings,
|
||||
import_pages=import_data.pages,
|
||||
import_themes=import_data.themes,
|
||||
import_users=import_data.users,
|
||||
import_groups=import_data.groups,
|
||||
force_import=import_data.force,
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
from fastapi import Depends, HTTPException, status
|
||||
from fastapi.routing import APIRouter
|
||||
from mealie.db.database import db
|
||||
from mealie.db.db_setup import generate_session
|
||||
from mealie.routes.routers import UserAPIRouter
|
||||
from mealie.schema.admin import SiteTheme
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
user_router = UserAPIRouter(prefix="/api", tags=["Themes"])
|
||||
public_router = APIRouter(prefix="/api", tags=["Themes"])
|
||||
|
||||
|
||||
@public_router.get("/themes")
|
||||
def get_all_themes(session: Session = Depends(generate_session)):
|
||||
""" Returns all site themes """
|
||||
|
||||
return db.themes.get_all(session)
|
||||
|
||||
|
||||
@user_router.post("/themes/create", status_code=status.HTTP_201_CREATED)
|
||||
def create_theme(data: SiteTheme, session: Session = Depends(generate_session)):
|
||||
""" Creates a site color theme database entry """
|
||||
db.themes.create(session, data.dict())
|
||||
|
||||
|
||||
@public_router.get("/themes/{id}")
|
||||
def get_single_theme(id: int, session: Session = Depends(generate_session)):
|
||||
""" Returns a named theme """
|
||||
return db.themes.get(session, id)
|
||||
|
||||
|
||||
@user_router.put("/themes/{id}", status_code=status.HTTP_200_OK)
|
||||
def update_theme(
|
||||
id: int,
|
||||
data: SiteTheme,
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Update a theme database entry """
|
||||
db.themes.update(session, id, data.dict())
|
||||
|
||||
|
||||
@user_router.delete("/themes/{id}", status_code=status.HTTP_200_OK)
|
||||
def delete_theme(id: int, session: Session = Depends(generate_session)):
|
||||
""" Deletes theme from the database """
|
||||
try:
|
||||
db.themes.delete(session, id)
|
||||
except Exception:
|
||||
raise HTTPException(status.HTTP_400_BAD_REQUEST)
|
|
@ -3,4 +3,3 @@ from .backup import *
|
|||
from .migration import *
|
||||
from .restore import *
|
||||
from .settings import *
|
||||
from .theme import *
|
||||
|
|
|
@ -13,7 +13,7 @@ class RecipeImport(ImportBase):
|
|||
slug: Optional[str]
|
||||
|
||||
|
||||
class ThemeImport(ImportBase):
|
||||
class CommentImport(ImportBase):
|
||||
pass
|
||||
|
||||
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Colors(BaseModel):
|
||||
primary: str = "#E58325"
|
||||
accent: str = "#00457A"
|
||||
secondary: str = "#973542"
|
||||
success: str = "#43A047"
|
||||
info: str = "#1976D2"
|
||||
warning: str = "#FF6F00"
|
||||
error: str = "#EF5350"
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
class SiteTheme(BaseModel):
|
||||
id: Optional[int]
|
||||
name: str = "default"
|
||||
colors: Colors = Colors()
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
schema_extra = {
|
||||
"example": {
|
||||
"name": "default",
|
||||
"colors": {
|
||||
"primary": "#E58325",
|
||||
"accent": "#00457A",
|
||||
"secondary": "#973542",
|
||||
"success": "#5AB1BB",
|
||||
"info": "#4990BA",
|
||||
"warning": "#FF4081",
|
||||
"error": "#EF5350",
|
||||
},
|
||||
}
|
||||
}
|
|
@ -108,7 +108,6 @@ def backup_all(
|
|||
export_recipes=True,
|
||||
export_settings=True,
|
||||
export_pages=True,
|
||||
export_themes=True,
|
||||
export_users=True,
|
||||
export_groups=True,
|
||||
export_notifications=True,
|
||||
|
@ -140,10 +139,6 @@ def backup_all(
|
|||
all_pages = db.custom_pages.get_all(session)
|
||||
db_export.export_items(all_pages, "pages")
|
||||
|
||||
if export_themes:
|
||||
all_themes = db.themes.get_all(session)
|
||||
db_export.export_items(all_themes, "themes")
|
||||
|
||||
if export_notifications:
|
||||
all_notifications = db.event_notifications.get_all(session)
|
||||
db_export.export_items(all_notifications, "notifications")
|
||||
|
|
|
@ -7,6 +7,7 @@ from typing import Callable
|
|||
from mealie.core.config import app_dirs
|
||||
from mealie.db.database import db
|
||||
from mealie.schema.admin import (
|
||||
CommentImport,
|
||||
CustomPageImport,
|
||||
CustomPageOut,
|
||||
GroupImport,
|
||||
|
@ -14,8 +15,6 @@ from mealie.schema.admin import (
|
|||
RecipeImport,
|
||||
SettingsImport,
|
||||
SiteSettings,
|
||||
SiteTheme,
|
||||
ThemeImport,
|
||||
UserImport,
|
||||
)
|
||||
from mealie.schema.events import EventNotificationIn
|
||||
|
@ -100,7 +99,7 @@ class ImportDatabase:
|
|||
self.import_model(
|
||||
db_table=db.comments,
|
||||
model=comment,
|
||||
return_model=ThemeImport,
|
||||
return_model=CommentImport,
|
||||
name_attr="uuid",
|
||||
search_key="uuid",
|
||||
)
|
||||
|
@ -156,27 +155,6 @@ class ImportDatabase:
|
|||
|
||||
minify.migrate_images()
|
||||
|
||||
def import_themes(self):
|
||||
themes_file = self.import_dir.joinpath("themes", "themes.json")
|
||||
themes = ImportDatabase.read_models_file(themes_file, SiteTheme)
|
||||
theme_imports = []
|
||||
|
||||
for theme in themes:
|
||||
if theme.name == "default":
|
||||
continue
|
||||
|
||||
import_status = self.import_model(
|
||||
db_table=db.themes,
|
||||
model=theme,
|
||||
return_model=ThemeImport,
|
||||
name_attr="name",
|
||||
search_key="name",
|
||||
)
|
||||
|
||||
theme_imports.append(import_status)
|
||||
|
||||
return theme_imports
|
||||
|
||||
def import_notifications(self):
|
||||
notify_file = self.import_dir.joinpath("notifications", "notifications.json")
|
||||
notifications = ImportDatabase.read_models_file(notify_file, EventNotificationIn)
|
||||
|
@ -348,7 +326,6 @@ def import_database(
|
|||
import_recipes=True,
|
||||
import_settings=True,
|
||||
import_pages=True,
|
||||
import_themes=True,
|
||||
import_users=True,
|
||||
import_groups=True,
|
||||
import_notifications=True,
|
||||
|
@ -365,10 +342,6 @@ def import_database(
|
|||
if import_settings:
|
||||
settings_report = import_session.import_settings()
|
||||
|
||||
theme_report = []
|
||||
if import_themes:
|
||||
theme_report = import_session.import_themes()
|
||||
|
||||
page_report = []
|
||||
if import_pages:
|
||||
page_report = import_session.import_pages()
|
||||
|
@ -393,7 +366,6 @@ def import_database(
|
|||
return {
|
||||
"recipeImports": recipe_report,
|
||||
"settingsImports": settings_report,
|
||||
"themeImports": theme_report,
|
||||
"pageImports": page_report,
|
||||
"groupImports": group_report,
|
||||
"userImports": user_report,
|
||||
|
|
|
@ -75,6 +75,7 @@ def user_token(admin_token, api_client: requests, api_routes: AppRoutes):
|
|||
}
|
||||
|
||||
response = api_client.post(api_routes.users, json=create_data, headers=admin_token)
|
||||
|
||||
assert response.status_code == 201
|
||||
|
||||
# Log in as this user
|
||||
|
|
|
@ -12,7 +12,6 @@ def backup_data():
|
|||
"force": True,
|
||||
"recipes": True,
|
||||
"settings": False, # ! Broken
|
||||
"themes": True,
|
||||
"groups": True,
|
||||
"users": True,
|
||||
"pages": True,
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
import json
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
from mealie.schema.admin import SiteTheme
|
||||
from tests.app_routes import AppRoutes
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def default_theme():
|
||||
return SiteTheme(id=1).dict()
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def new_theme():
|
||||
return {
|
||||
"id": 3,
|
||||
"name": "myTestTheme",
|
||||
"colors": {
|
||||
"primary": "#E58325",
|
||||
"accent": "#00457A",
|
||||
"secondary": "#973542",
|
||||
"success": "#43A047",
|
||||
"info": "#4990BA",
|
||||
"warning": "#FF4081",
|
||||
"error": "#EF5350",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_default_theme(api_client: TestClient, api_routes: AppRoutes, default_theme, user_token):
|
||||
response = api_client.get(api_routes.themes_id(1), headers=user_token)
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.content) == default_theme
|
||||
|
||||
|
||||
def test_create_theme(api_client: TestClient, api_routes: AppRoutes, new_theme, user_token):
|
||||
|
||||
response = api_client.post(api_routes.themes_create, json=new_theme, headers=user_token)
|
||||
assert response.status_code == 201
|
||||
|
||||
response = api_client.get(api_routes.themes_id(new_theme.get("id")), headers=user_token)
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.content) == new_theme
|
||||
|
||||
|
||||
def test_read_all_themes(api_client: TestClient, api_routes: AppRoutes, default_theme, new_theme, user_token):
|
||||
response = api_client.get(api_routes.themes, headers=user_token)
|
||||
assert response.status_code == 200
|
||||
response_dict = json.loads(response.content)
|
||||
assert default_theme in response_dict
|
||||
assert new_theme in response_dict
|
||||
|
||||
|
||||
def test_read_theme(api_client: TestClient, api_routes: AppRoutes, default_theme, new_theme, user_token):
|
||||
for theme in [default_theme, new_theme]:
|
||||
response = api_client.get(api_routes.themes_id(theme.get("id")), headers=user_token)
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.content) == theme
|
||||
|
||||
|
||||
def test_update_theme(api_client: TestClient, api_routes: AppRoutes, user_token, new_theme):
|
||||
theme_colors = {
|
||||
"primary": "#E12345",
|
||||
"accent": "#012345",
|
||||
"secondary": "#973542",
|
||||
"success": "#5AB1BB",
|
||||
"info": "#4990BA",
|
||||
"warning": "#FF4081",
|
||||
"error": "#EF4432",
|
||||
}
|
||||
|
||||
new_theme["colors"] = theme_colors
|
||||
new_theme["name"] = "New Theme Name"
|
||||
response = api_client.put(api_routes.themes_id(new_theme.get("id")), json=new_theme, headers=user_token)
|
||||
assert response.status_code == 200
|
||||
response = api_client.get(api_routes.themes_id(new_theme.get("id")), headers=user_token)
|
||||
assert json.loads(response.content) == new_theme
|
||||
|
||||
|
||||
def test_delete_theme(api_client: TestClient, api_routes: AppRoutes, default_theme, new_theme, user_token):
|
||||
for theme in [default_theme, new_theme]:
|
||||
response = api_client.delete(api_routes.themes_id(theme.get("id")), headers=user_token)
|
||||
|
||||
assert response.status_code == 200
|
|
@ -24,7 +24,7 @@ def admin_user():
|
|||
@fixture(scope="session")
|
||||
def new_user():
|
||||
return UserOut(
|
||||
id=4,
|
||||
id=3,
|
||||
fullName="My New User",
|
||||
username="My New User",
|
||||
email="newuser@email.com",
|
||||
|
@ -117,14 +117,14 @@ def test_update_other_user_as_not_admin(api_client: TestClient, api_routes: AppR
|
|||
|
||||
|
||||
def test_update_self_as_not_admin(api_client: TestClient, api_routes: AppRoutes, user_token):
|
||||
update_data = {"id": 3, "fullName": "User fullname", "email": "user@email.com", "group": "Home", "admin": False}
|
||||
response = api_client.put(api_routes.users_id(3), headers=user_token, json=update_data)
|
||||
update_data = {"fullName": "User fullname", "email": "user@email.com", "group": "Home", "admin": False}
|
||||
response = api_client.put(api_routes.users_id(4), headers=user_token, json=update_data)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_self_demote_admin(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
update_data = {"id": 1, "fullName": "Updated Name", "email": "changeme@email.com", "group": "Home", "admin": False}
|
||||
update_data = {"fullName": "Updated Name", "email": "changeme@email.com", "group": "Home", "admin": False}
|
||||
response = api_client.put(api_routes.users_id(1), headers=admin_token, json=update_data)
|
||||
|
||||
assert response.status_code == 403
|
||||
|
@ -132,13 +132,13 @@ def test_self_demote_admin(api_client: TestClient, api_routes: AppRoutes, admin_
|
|||
|
||||
def test_self_promote_admin(api_client: TestClient, api_routes: AppRoutes, user_token):
|
||||
update_data = {"id": 3, "fullName": "Updated Name", "email": "user@email.com", "group": "Home", "admin": True}
|
||||
response = api_client.put(api_routes.users_id(3), headers=user_token, json=update_data)
|
||||
response = api_client.put(api_routes.users_id(2), headers=user_token, json=update_data)
|
||||
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
def test_reset_user_password(api_client: TestClient, api_routes: AppRoutes, admin_token):
|
||||
response = api_client.put(api_routes.users_id_reset_password(4), headers=admin_token)
|
||||
response = api_client.put(api_routes.users_id_reset_password(3), headers=admin_token)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
|
Loading…
Reference in a new issue