Files
mealie/mealie/services/exporter/_abc_exporter.py
Hayden c32d7d7486 feat: add user recipe export functionality (#845)
* feat(frontend):  add user recipe export functionality

* remove depreciated folders

* change/remove depreciated folders

* add testing variable in config

* add GUID support for group_id

* improve testing feedback on 422 errors

* remove/cleanup files/folders

* initial user export support

* delete unused css

* update backup page UI

* remove depreciated settings

* feat:  export download links

* fix #813

* remove top level statements

* show footer

* add export purger to scheduler

* update purge glob

* fix meal-planner lockout

* feat:  add bulk delete/purge exports

* style(frontend): 💄 update UI for site settings

* feat:  add version checker

* update documentation

Co-authored-by: hay-kot <hay-kot@pm.me>
2021-12-04 14:18:46 -09:00

92 lines
2.7 KiB
Python

import zipfile
from abc import abstractmethod, abstractproperty
from dataclasses import dataclass
from pathlib import Path
from typing import Callable, Iterator, Optional
from uuid import UUID
from pydantic import BaseModel
from mealie.core.root_logger import get_logger
from mealie.db.database import Database
from mealie.schema.reports.reports import ReportEntryCreate
from .._base_service import BaseService
@dataclass
class ExportedItem:
"""
Exported items are the items provided by items() call in an concrete exporter class
Where the items are used to write data to the zip file. Models should derive from the
BaseModel class OR provide a .json method that returns a json string.
"""
model: BaseModel
name: str
class ABCExporter(BaseService):
write_dir_to_zip: Callable[[Path, str, Optional[list[str]]], None]
def __init__(self, db: Database, group_id: UUID) -> None:
self.logger = get_logger()
self.db = db
self.group_id = group_id
super().__init__()
@abstractproperty
def destination_dir(self) -> str:
...
@abstractmethod
def items(self) -> Iterator[ExportedItem]:
...
def _post_export_hook(self, _: BaseModel) -> None:
pass
@abstractmethod
def export(self, zip: zipfile.ZipFile) -> list[ReportEntryCreate]:
"""
Export takes in a zip file and exports the recipes to it. Note that the zip
file open/close is NOT handled by this method. You must handle it yourself.
Args:
zip (zipfile.ZipFile): Zip file destination
Returns:
list[ReportEntryCreate]: [description] ???!?!
"""
self.write_dir_to_zip = self.write_dir_to_zip_func(zip)
for item in self.items():
if item is None:
self.logger.error("Failed to export item. no item found")
continue
zip.writestr(f"{self.destination_dir}/{item.name}/{item.name}.json", item.model.json())
self._post_export_hook(item.model)
self.write_dir_to_zip = None
def write_dir_to_zip_func(self, zip: zipfile.ZipFile):
"""Returns a recursive function that writes a directory to a zip file.
Args:
zip (zipfile.ZipFile):
"""
def func(source_dir: Path, dest_dir: str, ignore_ext: set[str] = None) -> None:
ignore_ext = ignore_ext or set()
for source_file in source_dir.iterdir():
if source_file.is_dir():
func(source_file, f"{dest_dir}/{source_file.name}")
elif source_file.suffix not in ignore_ext:
zip.write(source_file, f"{dest_dir}/{source_file.name}")
return func