mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-06-11 11:30:12 -04:00
* fix links * actually fix #238 * Feature/mkdocs version bump (#240) * fix links (#239) Co-authored-by: hay-kot <hay-kot@pm.me> * fix #238 * bump mkdocs version * light/dark toggle * light/dark mode css * API_DOCS defaults to True * disable build on push for master Co-authored-by: hay-kot <hay-kot@pm.me> * Feature/recipe viewer (#244) * fix dialog placement * markdown support in ingredients * fix line render issue * fix tag rendering bug * change ingredients to text area * no slug error * add tag pages * remove console.logs Co-authored-by: hay-kot <hay-kot@pm.me> * changelog v0.4.1 * bug/backup-download (#245) * fix blocked download * + download blocked Co-authored-by: hay-kot <hay-kot@pm.me> * Feature/meal planner (#246) * fixes duplicate recipes in meal-plan #221 * add quick week option * scope css * add mealplanner info Co-authored-by: hay-kot <hay-kot@pm.me> * Nextcloud Import Bugs - #248 (#250) * parses datetime properly + clean category - #248 * add default credentials to docs Co-authored-by: hay-kot <hay-kot@pm.me> * Add bulk import examples to docs. (#252) * Add bulk import examples to docs. * Update api-usage.md * Add Python example for bulk import. * Change IP address in API example. * Refactor/app settings (#251) * fix env setup bugs * remove unused import * fix layout issues * changelog Co-authored-by: hay-kot <hay-kot@pm.me> * env setup fixes * Feature/about api (#253) * fix settings * app info cleanup Co-authored-by: hay-kot <hay-kot@pm.me> * Feature/image minify (#256) * fix settings * app info cleanup * bottom-bar experiment * remove dup key * type hints * add dependency * updated image with query parameters * read image options * add image minification * add image minification step * alt image routes * add image minification * set mobile bar to top Co-authored-by: hay-kot <hay-kot@pm.me> * Feature/additional endpoints (#257) * new recipe summary route * add categories to cards * add pillow * show tags instead of categories * additional debug info * add todays meal image url * about page * fix reactive tag * changelog + docs * bump version Co-authored-by: hay-kot <hay-kot@pm.me> * add pillow dependencies (#258) Co-authored-by: hay-kot <hay-kot@pm.me> * Feature/search page (#259) * add pillow dependencies * advanced search page * advanced search apge * remove extra dependencies * add pre-run script Co-authored-by: hay-kot <hay-kot@pm.me> * no image assignment * advanced search * fix docker dev build * Do not force theme settings on login form (#260) * Fix docker dev db persistence (#264) * Fix docker dev db persistence * Make run.sh the only startup script for prod + dev Credits to @hay-kot for run.sh script logic * Restore dev backend initialization in non-docker setup * Make run.sh POSIX-friendly * Allow dev backend to auto-reload in Docker * Frontend Refactor + Bug Fixes * merge category and tag selector * unifiy category selector * add hint * spacing * fix nextcloud migration * simplify email validator #261 * formatting * cleanup * auto-gen * format * update run script * unified category/tag selector * rename component * Add advanced search link * remove old code * convert keywords to tags * add proper behavior on rename * proper image name association on rename * fix test cleanup * changelog * set docker comppand * minify on migration Co-authored-by: hay-kot <hay-kot@pm.me> * bug-fixes/category-tag-creator (#266) * fix category labels * set loader for migration * v0.4.1 Co-authored-by: hay-kot <hay-kot@pm.me> Co-authored-by: hay-kot <hay-kot@pm.me> Co-authored-by: Nat <nathanynath@yahoo.fr> Co-authored-by: sephrat <34862846+sephrat@users.noreply.github.com>
147 lines
4.7 KiB
Python
147 lines
4.7 KiB
Python
import json
|
|
import shutil
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from typing import Union
|
|
|
|
from fastapi.logger import logger
|
|
from jinja2 import Template
|
|
from mealie.core.config import app_dirs
|
|
from mealie.db.database import db
|
|
from mealie.db.db_setup import create_session
|
|
from pydantic.main import BaseModel
|
|
|
|
|
|
class ExportDatabase:
|
|
def __init__(self, tag=None, templates=None) -> None:
|
|
"""Export a Mealie database. Export interacts directly with class objects and can be used
|
|
with any supported backend database platform. By default tags are timestamps, and no
|
|
Jinja2 templates are rendered
|
|
|
|
|
|
Args:
|
|
tag ([str], optional): A str to be used as a file tag. Defaults to None.
|
|
templates (list, optional): A list of template file names. Defaults to None.
|
|
"""
|
|
if tag:
|
|
export_tag = tag + "_" + datetime.now().strftime("%Y-%b-%d")
|
|
else:
|
|
export_tag = datetime.now().strftime("%Y-%b-%d")
|
|
|
|
self.main_dir = app_dirs.TEMP_DIR.joinpath(export_tag)
|
|
self.img_dir = self.main_dir.joinpath("images")
|
|
self.templates_dir = self.main_dir.joinpath("templates")
|
|
|
|
try:
|
|
self.templates = [app_dirs.TEMPLATE_DIR.joinpath(x) for x in templates]
|
|
except:
|
|
self.templates = False
|
|
logger.info("No Jinja2 Templates Registered for Export")
|
|
|
|
required_dirs = [
|
|
self.main_dir,
|
|
self.img_dir,
|
|
self.templates_dir,
|
|
]
|
|
|
|
for dir in required_dirs:
|
|
dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
def export_templates(self, recipe_list: list[BaseModel]):
|
|
for template_path in self.templates:
|
|
out_dir = self.templates_dir.joinpath(template_path.name)
|
|
out_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
with open(template_path, "r") as f:
|
|
template = Template(f.read())
|
|
|
|
for recipe in recipe_list:
|
|
filename = recipe.slug + template_path.suffix
|
|
out_file = out_dir.joinpath(filename)
|
|
|
|
content = template.render(recipe=recipe)
|
|
|
|
with open(out_file, "w") as f:
|
|
f.write(content)
|
|
|
|
def export_images(self):
|
|
shutil.copytree(app_dirs.IMG_DIR, self.img_dir, dirs_exist_ok=True)
|
|
|
|
def export_items(self, items: list[BaseModel], folder_name: str, export_list=True):
|
|
items = [x.dict() for x in items]
|
|
out_dir = self.main_dir.joinpath(folder_name)
|
|
out_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
if export_list:
|
|
ExportDatabase._write_json_file(items, out_dir.joinpath(f"{folder_name}.json"))
|
|
else:
|
|
for item in items:
|
|
ExportDatabase._write_json_file(item, out_dir.joinpath(f"{item.get('name')}.json"))
|
|
|
|
@staticmethod
|
|
def _write_json_file(data: Union[dict, list], out_file: Path):
|
|
json_data = json.dumps(data, indent=4, default=str)
|
|
|
|
with open(out_file, "w") as f:
|
|
f.write(json_data)
|
|
|
|
def finish_export(self):
|
|
zip_path = app_dirs.BACKUP_DIR.joinpath(f"{self.main_dir.name}")
|
|
shutil.make_archive(zip_path, "zip", self.main_dir)
|
|
|
|
shutil.rmtree(app_dirs.TEMP_DIR)
|
|
|
|
return str(zip_path.absolute()) + ".zip"
|
|
|
|
|
|
def backup_all(
|
|
session,
|
|
tag=None,
|
|
templates=None,
|
|
export_recipes=True,
|
|
export_settings=True,
|
|
export_pages=True,
|
|
export_themes=True,
|
|
export_users=True,
|
|
export_groups=True,
|
|
):
|
|
db_export = ExportDatabase(tag=tag, templates=templates)
|
|
|
|
if export_users:
|
|
all_users = db.users.get_all(session)
|
|
db_export.export_items(all_users, "users")
|
|
|
|
if export_groups:
|
|
all_groups = db.groups.get_all(session)
|
|
db_export.export_items(all_groups, "groups")
|
|
|
|
if export_recipes:
|
|
all_recipes = db.recipes.get_all(session)
|
|
db_export.export_items(all_recipes, "recipes", export_list=False)
|
|
db_export.export_templates(all_recipes)
|
|
db_export.export_images()
|
|
|
|
if export_settings:
|
|
all_settings = db.settings.get_all(session)
|
|
db_export.export_items(all_settings, "settings")
|
|
|
|
if export_pages:
|
|
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")
|
|
|
|
return db_export.finish_export()
|
|
|
|
|
|
def auto_backup_job():
|
|
for backup in app_dirs.BACKUP_DIR.glob("Auto*.zip"):
|
|
backup.unlink()
|
|
|
|
templates = [template for template in app_dirs.TEMPLATE_DIR.iterdir()]
|
|
session = create_session()
|
|
backup_all(session=session, tag="Auto", templates=templates)
|
|
logger.info("Auto Backup Called")
|