1
0
Fork 0
mirror of https://github.com/mealie-recipes/mealie.git synced 2025-07-24 15:49:42 +02:00
mealie/mealie/services/migrations/_migration_base.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

170 lines
5 KiB
Python

from pathlib import Path
from typing import Tuple
from uuid import UUID
from mealie.core import root_logger
from mealie.db.database import Database
from mealie.schema.recipe import Recipe
from mealie.schema.reports.reports import (
ReportCategory,
ReportCreate,
ReportEntryCreate,
ReportOut,
ReportSummary,
ReportSummaryStatus,
)
from mealie.services.scraper import cleaner
from .._base_service import BaseService
from .utils.migration_alias import MigrationAlias
class BaseMigrator(BaseService):
key_aliases: list[MigrationAlias]
report_entries: list[ReportEntryCreate]
report_id: int
report: ReportOut
def __init__(self, archive: Path, db: Database, session, user_id: int, group_id: UUID):
self.archive = archive
self.db = db
self.session = session
self.user_id = user_id
self.group_id = group_id
self.report_entries = []
self.logger = root_logger.get_logger()
super().__init__()
def _migrate(self) -> None:
raise NotImplementedError
def _create_report(self, report_name: str) -> None:
report_to_save = ReportCreate(
name=report_name,
category=ReportCategory.migration,
status=ReportSummaryStatus.in_progress,
group_id=self.group_id,
)
self.report = self.db.group_reports.create(report_to_save)
self.report_id = self.report.id
def _save_all_entries(self) -> None:
is_success = True
is_failure = True
for entry in self.report_entries:
if is_failure and entry.success:
is_failure = False
if is_success and not entry.success:
is_success = False
self.db.group_report_entries.create(entry)
if is_success:
self.report.status = ReportSummaryStatus.success
if is_failure:
self.report.status = ReportSummaryStatus.failure
if not is_success and not is_failure:
self.report.status = ReportSummaryStatus.partial
self.db.group_reports.update(self.report.id, self.report)
def migrate(self, report_name: str) -> ReportSummary:
self._create_report(report_name)
self._migrate()
self._save_all_entries()
return self.db.group_reports.get(self.report_id)
def import_recipes_to_database(self, validated_recipes: list[Recipe]) -> list[Tuple[str, bool]]:
"""
Used as a single access point to process a list of Recipe objects into the
database in a predictable way. If an error occurs the session is rolled back
and the process will continue. All import information is appended to the
'migration_report' attribute to be returned to the frontend for display.
Args:
validated_recipes (list[Recipe]):
"""
return_vars = []
for recipe in validated_recipes:
recipe.user_id = self.user_id
recipe.group_id = self.group_id
exception = ""
status = False
try:
self.db.recipes.create(recipe)
status = True
except Exception as inst:
exception = inst
self.logger.exception(inst)
self.session.rollback()
if status:
message = f"Imported {recipe.name} successfully"
else:
message = f"Failed to import {recipe.name}"
return_vars.append((recipe.slug, status))
self.report_entries.append(
ReportEntryCreate(
report_id=self.report_id,
success=status,
message=message,
exception=str(exception),
)
)
return return_vars
def rewrite_alias(self, recipe_dict: dict) -> dict:
"""A helper function to reassign attributes by an alias using a list
of MigrationAlias objects to rewrite the alias attribute found in the recipe_dict
to a
Args:
recipe_dict (dict): [description]
key_aliases (list[MigrationAlias]): [description]
Returns:
dict: [description]
"""
if not self.key_aliases:
return recipe_dict
for alias in self.key_aliases:
try:
prop_value = recipe_dict.pop(alias.alias)
except KeyError:
continue
if alias.func:
prop_value = alias.func(prop_value)
recipe_dict[alias.key] = prop_value
return recipe_dict
def clean_recipe_dictionary(self, recipe_dict: dict) -> Recipe:
"""
Calls the rewrite_alias function and the Cleaner.clean function on a
dictionary and returns the result unpacked into a Recipe object
"""
recipe_dict = self.rewrite_alias(recipe_dict)
recipe_dict = cleaner.clean(recipe_dict, url=recipe_dict.get("org_url", None))
return Recipe(**recipe_dict)