Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Recipe Keeper Errors and Other Safari Issues #3712

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 24 additions & 24 deletions frontend/pages/group/migrations.vue
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,14 @@ export default defineComponent({
text: i18n.tc("migration.plantoeat.title"),
value: MIGRATIONS.plantoeat,
},
{
text: i18n.tc("migration.tandoor.title"),
value: MIGRATIONS.tandoor,
},
{
text: i18n.tc("migration.recipekeeper.title"),
value: MIGRATIONS.recipekeeper,
},
{
text: i18n.tc("migration.tandoor.title"),
value: MIGRATIONS.tandoor,
},
];
const _content = {
[MIGRATIONS.mealie]: {
Expand Down Expand Up @@ -312,6 +312,26 @@ export default defineComponent({
}
],
},
[MIGRATIONS.recipekeeper]: {
text: i18n.tc("migration.recipekeeper.description-long"),
acceptedFileType: ".zip",
tree: [
{
id: 1,
icon: $globals.icons.zip,
name: "recipekeeperhtml.zip",
children: [
{ id: 2, name: "recipes.html", icon: $globals.icons.codeJson },
{ id: 3, name: "images", icon: $globals.icons.folderOutline,
children: [
{ id: 4, name: "image1.jpg", icon: $globals.icons.fileImage },
{ id: 5, name: "image2.jpg", icon: $globals.icons.fileImage },
]
},
],
}
],
},
[MIGRATIONS.tandoor]: {
text: i18n.tc("migration.tandoor.description-long"),
acceptedFileType: ".zip",
Expand Down Expand Up @@ -352,26 +372,6 @@ export default defineComponent({
}
],
},
[MIGRATIONS.recipekeeper]: {
text: i18n.tc("migration.recipekeeper.description-long"),
acceptedFileType: ".zip",
tree: [
{
id: 1,
icon: $globals.icons.zip,
name: "recipekeeperhtml.zip",
children: [
{ id: 2, name: "recipes.html", icon: $globals.icons.codeJson },
{ id: 3, name: "images", icon: $globals.icons.folderOutline,
children: [
{ id: 4, name: "image1.jpeg", icon: $globals.icons.fileImage },
{ id: 5, name: "image2.jpeg", icon: $globals.icons.fileImage },
]
},
],
}
],
},
};

function setFileObject(fileObject: File) {
Expand Down
22 changes: 22 additions & 0 deletions mealie/services/migrations/_migration_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,28 @@ def __init__(

super().__init__()

@classmethod
def get_zip_base_path(cls, path: Path) -> Path:
# Safari mangles our ZIP structure and adds a "__MACOSX" directory at the root along with
# an arbitrarily-named directory containing the actual contents. So, if we find a dunder directory
# at the root (i.e. __MACOSX) we traverse down the first non-dunder directory and assume this is the base.
# We assume migration exports never contain a directory that starts with "__".
normal_dirs: list[Path] = []
dunder_dirs: list[Path] = []
for dir in path.iterdir():
if not dir.is_dir():
continue

if dir.name.startswith("__"):
dunder_dirs.append(dir)
else:
normal_dirs.append(dir)

if len(normal_dirs) == 1 and len(dunder_dirs) == 1:
return normal_dirs[0]
else:
return path

def _migrate(self) -> None:
raise NotImplementedError

Expand Down
14 changes: 13 additions & 1 deletion mealie/services/migrations/chowdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,24 @@ def __init__(self, **kwargs):
MigrationAlias(key="tags", alias="tags", func=split_by_comma),
]

@classmethod
def get_zip_base_path(cls, path: Path) -> Path:
potential_path = super().get_zip_base_path(path)
if path == potential_path:
return path

# make sure we didn't accidentally open a recipe dir
if (potential_path / "recipe.json").exists():
return path
else:
return potential_path

def _migrate(self) -> None:
with tempfile.TemporaryDirectory() as tmpdir:
with zipfile.ZipFile(self.archive) as zip_file:
zip_file.extractall(tmpdir)

temp_path = Path(tmpdir)
temp_path = self.get_zip_base_path(Path(tmpdir))

chow_dir = next(temp_path.iterdir())
image_dir = temp_path.joinpath(chow_dir, "images")
Expand Down
2 changes: 1 addition & 1 deletion mealie/services/migrations/copymethat.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def _migrate(self) -> None:
with zipfile.ZipFile(self.archive) as zip_file:
zip_file.extractall(tmpdir)

source_dir = Path(tmpdir)
source_dir = self.get_zip_base_path(Path(tmpdir))

recipes_as_dicts: list[dict] = []
for recipes_data_file in source_dir.glob("*.html"):
Expand Down
14 changes: 13 additions & 1 deletion mealie/services/migrations/mealie_alpha.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ def __init__(self, **kwargs):
MigrationAlias(key="tags", alias="tags", func=split_by_comma),
]

@classmethod
def get_zip_base_path(cls, path: Path) -> Path:
potential_path = super().get_zip_base_path(path)
if path == potential_path:
return path

# make sure we didn't accidentally open the "recipes" dir
if potential_path.name == "recipes":
return path
else:
return potential_path

def _convert_to_new_schema(self, recipe: dict) -> Recipe:
if recipe.get("categories", False):
recipe["recipeCategory"] = recipe.get("categories")
Expand Down Expand Up @@ -55,7 +67,7 @@ def _migrate(self) -> None:
with zipfile.ZipFile(self.archive) as zip_file:
zip_file.extractall(tmpdir)

temp_path = Path(tmpdir)
temp_path = self.get_zip_base_path(Path(tmpdir))
recipe_lookup: dict[str, Path] = {}

recipes: list[Recipe] = []
Expand Down
15 changes: 14 additions & 1 deletion mealie/services/migrations/nextcloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ def __init__(self, **kwargs):
MigrationAlias(key="performTime", alias="cookTime", func=parse_iso8601_duration),
]

@classmethod
def get_zip_base_path(cls, path: Path) -> Path:
potential_path = super().get_zip_base_path(path)
if path == potential_path:
return path

# make sure we didn't accidentally open a recipe dir
if (potential_path / "recipe.json").exists():
return path
else:
return potential_path

def _migrate(self) -> None:
# Unzip File into temp directory

Expand All @@ -65,7 +77,8 @@ def _migrate(self) -> None:
with zipfile.ZipFile(self.archive) as zip_file:
zip_file.extractall(tmpdir)

potential_recipe_dirs = glob_walker(Path(tmpdir), glob_str="**/[!.]*.json", return_parent=True)
base_dir = self.get_zip_base_path(Path(tmpdir))
potential_recipe_dirs = glob_walker(base_dir, glob_str="**/[!.]*.json", return_parent=True)
nextcloud_dirs = {y.slug: y for x in potential_recipe_dirs if (y := NextcloudDir.from_dir(x))}

all_recipes = []
Expand Down
15 changes: 13 additions & 2 deletions mealie/services/migrations/recipekeeper.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@
from .utils.migration_helpers import import_image, parse_iso8601_duration


def clean_instructions(instructions: list[str]) -> list[str]:
try:
for i, instruction in enumerate(instructions):
if instruction.startswith(f"{i + 1}. "):
instructions[i] = instruction.removeprefix(f"{i + 1}. ")

return instructions
except Exception:
return instructions


def parse_recipe_div(recipe, image_path):
meta = {}
for item in recipe.find_all(lambda x: x.has_attr("itemprop")):
Expand Down Expand Up @@ -59,7 +70,7 @@ def __init__(self, **kwargs):
key="recipeIngredient",
alias="recipeIngredients",
),
MigrationAlias(key="recipeInstructions", alias="recipeDirections"),
MigrationAlias(key="recipeInstructions", alias="recipeDirections", func=clean_instructions),
MigrationAlias(key="performTime", alias="cookTime", func=parse_iso8601_duration),
MigrationAlias(key="prepTime", alias="prepTime", func=parse_iso8601_duration),
MigrationAlias(key="image", alias="photo0"),
Expand All @@ -77,7 +88,7 @@ def _migrate(self) -> None:
with zipfile.ZipFile(self.archive) as zip_file:
zip_file.extractall(tmpdir)

source_dir = Path(tmpdir) / "recipekeeperhtml"
source_dir = self.get_zip_base_path(Path(tmpdir))

recipes_as_dicts: list[dict] = []
with open(source_dir / "recipes.html") as fp:
Expand Down
2 changes: 1 addition & 1 deletion mealie/services/migrations/tandoor.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def _migrate(self) -> None:
with zipfile.ZipFile(self.archive) as zip_file:
zip_file.extractall(tmpdir)

source_dir = Path(tmpdir)
source_dir = self.get_zip_base_path(Path(tmpdir))

recipes_as_dicts: list[dict] = []
for i, recipe_zip_file in enumerate(source_dir.glob("*.zip")):
Expand Down
Binary file modified tests/data/migrations/recipekeeper.zip
Binary file not shown.
Loading