refactor(backend): 🔥 Remove Backend Theme Support

This commit is contained in:
hay-kot 2021-08-27 20:47:24 -08:00
parent dd1b1ad067
commit 161618808e
15 changed files with 11 additions and 252 deletions

View file

@ -4,7 +4,7 @@ from fastapi.middleware.gzip import GZipMiddleware
from mealie.core.config import APP_VERSION, settings from mealie.core.config import APP_VERSION, settings
from mealie.core.root_logger import get_logger 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.about import about_router
from mealie.routes.mealplans import meal_plan_router from mealie.routes.mealplans import meal_plan_router
from mealie.routes.media import media_router from mealie.routes.media import media_router
@ -39,8 +39,6 @@ def api_routers():
app.include_router(meal_plan_router) app.include_router(meal_plan_router)
# Settings Routes # Settings Routes
app.include_router(settings_router) app.include_router(settings_router)
app.include_router(theme_routes.public_router)
app.include_router(theme_routes.user_router)
# Backups/Imports Routes # Backups/Imports Routes
app.include_router(backup_routes.router) app.include_router(backup_routes.router)
# Migration Routes # Migration Routes

View file

@ -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.settings import CustomPage, SiteSettings
from mealie.db.models.shopping_list import ShoppingList from mealie.db.models.shopping_list import ShoppingList
from mealie.db.models.sign_up import SignUp 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.db.models.users import LongLiveToken, User
from mealie.schema.admin import CustomPageOut from mealie.schema.admin import CustomPageOut
from mealie.schema.admin import SiteSettings as SiteSettingsSchema 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 Event as EventSchema
from mealie.schema.events import EventNotificationIn from mealie.schema.events import EventNotificationIn
from mealie.schema.meal_plan import MealPlanOut, ShoppingListOut from mealie.schema.meal_plan import MealPlanOut, ShoppingListOut
@ -73,7 +71,6 @@ class DatabaseAccessLayer:
# Site # Site
self.settings = BaseAccessModel(DEFAULT_PK, SiteSettings, SiteSettingsSchema) self.settings = BaseAccessModel(DEFAULT_PK, SiteSettings, SiteSettingsSchema)
self.themes = BaseAccessModel(DEFAULT_PK, SiteThemeModel, SiteTheme)
self.sign_ups = BaseAccessModel("token", SignUp, SignUpOut) self.sign_ups = BaseAccessModel("token", SignUp, SignUpOut)
self.custom_pages = BaseAccessModel(DEFAULT_PK, CustomPage, CustomPageOut) self.custom_pages = BaseAccessModel(DEFAULT_PK, CustomPage, CustomPageOut)
self.event_notifications = BaseAccessModel(DEFAULT_PK, EventNotification, EventNotificationIn) self.event_notifications = BaseAccessModel(DEFAULT_PK, EventNotification, EventNotificationIn)

View file

@ -5,5 +5,4 @@ from .recipe.recipe import *
from .settings import * from .settings import *
from .shopping_list import * from .shopping_list import *
from .sign_up import * from .sign_up import *
from .theme import *
from .users import * from .users import *

View file

@ -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)

View file

@ -44,7 +44,6 @@ def export_database(background_tasks: BackgroundTasks, data: BackupJob, session:
export_recipes=data.options.recipes, export_recipes=data.options.recipes,
export_settings=data.options.settings, export_settings=data.options.settings,
export_pages=data.options.pages, export_pages=data.options.pages,
export_themes=data.options.themes,
export_users=data.options.users, export_users=data.options.users,
export_groups=data.options.groups, export_groups=data.options.groups,
export_notifications=data.options.notifications, export_notifications=data.options.notifications,
@ -93,7 +92,6 @@ def import_database(
import_recipes=import_data.recipes, import_recipes=import_data.recipes,
import_settings=import_data.settings, import_settings=import_data.settings,
import_pages=import_data.pages, import_pages=import_data.pages,
import_themes=import_data.themes,
import_users=import_data.users, import_users=import_data.users,
import_groups=import_data.groups, import_groups=import_data.groups,
force_import=import_data.force, force_import=import_data.force,

View file

@ -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)

View file

@ -3,4 +3,3 @@ from .backup import *
from .migration import * from .migration import *
from .restore import * from .restore import *
from .settings import * from .settings import *
from .theme import *

View file

@ -13,7 +13,7 @@ class RecipeImport(ImportBase):
slug: Optional[str] slug: Optional[str]
class ThemeImport(ImportBase): class CommentImport(ImportBase):
pass pass

View file

@ -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",
},
}
}

View file

@ -108,7 +108,6 @@ def backup_all(
export_recipes=True, export_recipes=True,
export_settings=True, export_settings=True,
export_pages=True, export_pages=True,
export_themes=True,
export_users=True, export_users=True,
export_groups=True, export_groups=True,
export_notifications=True, export_notifications=True,
@ -140,10 +139,6 @@ def backup_all(
all_pages = db.custom_pages.get_all(session) all_pages = db.custom_pages.get_all(session)
db_export.export_items(all_pages, "pages") 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: if export_notifications:
all_notifications = db.event_notifications.get_all(session) all_notifications = db.event_notifications.get_all(session)
db_export.export_items(all_notifications, "notifications") db_export.export_items(all_notifications, "notifications")

View file

@ -7,6 +7,7 @@ from typing import Callable
from mealie.core.config import app_dirs from mealie.core.config import app_dirs
from mealie.db.database import db from mealie.db.database import db
from mealie.schema.admin import ( from mealie.schema.admin import (
CommentImport,
CustomPageImport, CustomPageImport,
CustomPageOut, CustomPageOut,
GroupImport, GroupImport,
@ -14,8 +15,6 @@ from mealie.schema.admin import (
RecipeImport, RecipeImport,
SettingsImport, SettingsImport,
SiteSettings, SiteSettings,
SiteTheme,
ThemeImport,
UserImport, UserImport,
) )
from mealie.schema.events import EventNotificationIn from mealie.schema.events import EventNotificationIn
@ -100,7 +99,7 @@ class ImportDatabase:
self.import_model( self.import_model(
db_table=db.comments, db_table=db.comments,
model=comment, model=comment,
return_model=ThemeImport, return_model=CommentImport,
name_attr="uuid", name_attr="uuid",
search_key="uuid", search_key="uuid",
) )
@ -156,27 +155,6 @@ class ImportDatabase:
minify.migrate_images() 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): def import_notifications(self):
notify_file = self.import_dir.joinpath("notifications", "notifications.json") notify_file = self.import_dir.joinpath("notifications", "notifications.json")
notifications = ImportDatabase.read_models_file(notify_file, EventNotificationIn) notifications = ImportDatabase.read_models_file(notify_file, EventNotificationIn)
@ -348,7 +326,6 @@ def import_database(
import_recipes=True, import_recipes=True,
import_settings=True, import_settings=True,
import_pages=True, import_pages=True,
import_themes=True,
import_users=True, import_users=True,
import_groups=True, import_groups=True,
import_notifications=True, import_notifications=True,
@ -365,10 +342,6 @@ def import_database(
if import_settings: if import_settings:
settings_report = import_session.import_settings() settings_report = import_session.import_settings()
theme_report = []
if import_themes:
theme_report = import_session.import_themes()
page_report = [] page_report = []
if import_pages: if import_pages:
page_report = import_session.import_pages() page_report = import_session.import_pages()
@ -393,7 +366,6 @@ def import_database(
return { return {
"recipeImports": recipe_report, "recipeImports": recipe_report,
"settingsImports": settings_report, "settingsImports": settings_report,
"themeImports": theme_report,
"pageImports": page_report, "pageImports": page_report,
"groupImports": group_report, "groupImports": group_report,
"userImports": user_report, "userImports": user_report,

View file

@ -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) response = api_client.post(api_routes.users, json=create_data, headers=admin_token)
assert response.status_code == 201 assert response.status_code == 201
# Log in as this user # Log in as this user

View file

@ -12,7 +12,6 @@ def backup_data():
"force": True, "force": True,
"recipes": True, "recipes": True,
"settings": False, # ! Broken "settings": False, # ! Broken
"themes": True,
"groups": True, "groups": True,
"users": True, "users": True,
"pages": True, "pages": True,

View file

@ -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

View file

@ -24,7 +24,7 @@ def admin_user():
@fixture(scope="session") @fixture(scope="session")
def new_user(): def new_user():
return UserOut( return UserOut(
id=4, id=3,
fullName="My New User", fullName="My New User",
username="My New User", username="My New User",
email="newuser@email.com", 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): 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} update_data = {"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) response = api_client.put(api_routes.users_id(4), headers=user_token, json=update_data)
assert response.status_code == 200 assert response.status_code == 200
def test_self_demote_admin(api_client: TestClient, api_routes: AppRoutes, admin_token): 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) response = api_client.put(api_routes.users_id(1), headers=admin_token, json=update_data)
assert response.status_code == 403 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): 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} 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 assert response.status_code == 403
def test_reset_user_password(api_client: TestClient, api_routes: AppRoutes, admin_token): 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 assert response.status_code == 200