mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 14:33:33 -07:00
potentially fix #217
This commit is contained in:
parent
e25266c089
commit
802633a060
6 changed files with 68 additions and 117 deletions
|
@ -13,43 +13,13 @@
|
|||
</v-app-bar>
|
||||
<v-card-text class="mb-n4">
|
||||
<v-row>
|
||||
<div>
|
||||
<div v-for="values in allNumbers" :key="values.title">
|
||||
<v-card-text>
|
||||
<div>
|
||||
<h3>Recipes</h3>
|
||||
</div>
|
||||
<div class="success--text">
|
||||
Success: {{ recipeNumbers.success }}
|
||||
</div>
|
||||
<div class="error--text">
|
||||
Failed: {{ recipeNumbers.failure }}
|
||||
</div>
|
||||
</v-card-text>
|
||||
</div>
|
||||
<div>
|
||||
<v-card-text>
|
||||
<div>
|
||||
<h3>Themes</h3>
|
||||
</div>
|
||||
<div class="success--text">
|
||||
Success: {{ themeNumbers.success }}
|
||||
</div>
|
||||
<div class="error--text">
|
||||
Failed: {{ themeNumbers.failure }}
|
||||
</div>
|
||||
</v-card-text>
|
||||
</div>
|
||||
<div>
|
||||
<v-card-text>
|
||||
<div>
|
||||
<h3>Settings</h3>
|
||||
</div>
|
||||
<div class="success--text">
|
||||
Success: {{ settingsNumbers.success }}
|
||||
</div>
|
||||
<div class="error--text">
|
||||
Failed: {{ settingsNumbers.failure }}
|
||||
<h3>{{ values.title }}</h3>
|
||||
</div>
|
||||
<div class="success--text">Success: {{ values.success }}</div>
|
||||
<div class="error--text">Failed: {{ values.failure }}</div>
|
||||
</v-card-text>
|
||||
</div>
|
||||
</v-row>
|
||||
|
@ -131,26 +101,35 @@ export default {
|
|||
|
||||
computed: {
|
||||
recipeNumbers() {
|
||||
return this.calculateNumbers(this.recipeData);
|
||||
return this.calculateNumbers("Recipes", this.recipeData);
|
||||
},
|
||||
settingsNumbers() {
|
||||
return this.calculateNumbers(this.settingsData);
|
||||
return this.calculateNumbers("Settings", this.settingsData);
|
||||
},
|
||||
themeNumbers() {
|
||||
return this.calculateNumbers(this.themeData);
|
||||
return this.calculateNumbers("Theme", this.themeData);
|
||||
},
|
||||
userNumbers() {
|
||||
return this.calculateNumbers(this.userData);
|
||||
return this.calculateNumbers("Users", this.userData);
|
||||
},
|
||||
groupNumbers() {
|
||||
return this.calculateNumbers(this.groupData);
|
||||
return this.calculateNumbers("Groups", this.groupData);
|
||||
},
|
||||
allNumbers() {
|
||||
return [
|
||||
this.recipeNumbers,
|
||||
this.settingsNumbers,
|
||||
this.themeNumbers,
|
||||
this.userNumbers,
|
||||
this.groupNumbers,
|
||||
];
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
calculateNumbers(list_array) {
|
||||
calculateNumbers(title, list_array) {
|
||||
if (!list_array) return;
|
||||
let numbers = { success: 0, failure: 0 };
|
||||
let numbers = { title: title, success: 0, failure: 0 };
|
||||
list_array.forEach(element => {
|
||||
if (element.status) {
|
||||
numbers.success++;
|
||||
|
|
11
makefile
11
makefile
|
@ -4,10 +4,9 @@ setup:
|
|||
npm install && \
|
||||
cd ..
|
||||
|
||||
backend:
|
||||
source ./.venv/bin/activate && \
|
||||
python mealie/db/init_db.py && \
|
||||
python mealie/app.py
|
||||
backend:
|
||||
poetry run python mealie/db/init_db.py && \
|
||||
poetry run python mealie/app.py
|
||||
|
||||
.PHONY: frontend
|
||||
frontend:
|
||||
|
@ -15,9 +14,7 @@ frontend:
|
|||
|
||||
.PHONY: docs
|
||||
docs:
|
||||
source ./.venv/bin/activate && \
|
||||
cd docs && \
|
||||
mkdocs serve
|
||||
cd docs && poetry run python -m mkdocs serve
|
||||
|
||||
docker-dev:
|
||||
docker-compose -f docker-compose.dev.yml -p dev-mealie up --build
|
||||
|
|
|
@ -76,7 +76,7 @@ class BaseDocument:
|
|||
|
||||
return result
|
||||
|
||||
def get(self, session: Session, match_value: str, match_key: str = None, limit=1) -> dict or List[dict]:
|
||||
def get(self, session: Session, match_value: str, match_key: str = None, limit=1) -> BaseModel or List[BaseModel]:
|
||||
"""Retrieves an entry from the database by matching a key/value pair. If no
|
||||
key is provided the class objects primary key will be used to match against.
|
||||
|
||||
|
@ -101,7 +101,7 @@ class BaseDocument:
|
|||
return None
|
||||
return [self.schema.from_orm(x) for x in result]
|
||||
|
||||
def create(self, session: Session, document: dict) -> dict:
|
||||
def create(self, session: Session, document: dict) -> BaseModel:
|
||||
"""Creates a new database entry for the given SQL Alchemy Model.
|
||||
|
||||
Args: \n
|
||||
|
@ -121,7 +121,7 @@ class BaseDocument:
|
|||
return_data = new_document.dict()
|
||||
return return_data
|
||||
|
||||
def update(self, session: Session, match_value: str, new_data: str) -> dict:
|
||||
def update(self, session: Session, match_value: str, new_data: str) -> BaseModel:
|
||||
"""Update a database entry.
|
||||
|
||||
Args: \n
|
||||
|
|
|
@ -7,7 +7,6 @@ from typing import List
|
|||
from fastapi.logger import logger
|
||||
from mealie.core.config import BACKUP_DIR, IMG_DIR, TEMP_DIR
|
||||
from mealie.db.database import db
|
||||
from mealie.db.db_setup import create_session
|
||||
from mealie.schema.recipe import Recipe
|
||||
from mealie.schema.restore import GroupImport, RecipeImport, SettingsImport, ThemeImport, UserImport
|
||||
from mealie.schema.theme import SiteTheme
|
||||
|
@ -47,38 +46,41 @@ class ImportDatabase:
|
|||
raise Exception("Import file does not exist")
|
||||
|
||||
def import_recipes(self):
|
||||
session = create_session()
|
||||
recipe_dir: Path = self.import_dir.joinpath("recipes")
|
||||
|
||||
imports = []
|
||||
successful_imports = []
|
||||
|
||||
for recipe in recipe_dir.glob("*.json"):
|
||||
with open(recipe, "r") as f:
|
||||
recipe_dict = json.loads(f.read())
|
||||
recipe_dict = ImportDatabase._recipe_migration(recipe_dict)
|
||||
try:
|
||||
if recipe_dict.get("categories", False):
|
||||
recipe_dict["recipeCategory"] = recipe_dict.get("categories")
|
||||
del recipe_dict["categories"]
|
||||
def read_recipe_file(file_path: Path):
|
||||
with open(file_path, "r") as f:
|
||||
try:
|
||||
recipe_dict = json.loads(f.read())
|
||||
recipe_dict = ImportDatabase._recipe_migration(recipe_dict)
|
||||
return Recipe(**recipe_dict)
|
||||
except:
|
||||
import_status = RecipeImport(name=file_path.stem, slug=file_path.stem, status=False)
|
||||
imports.append(import_status)
|
||||
|
||||
recipe_obj = Recipe(**recipe_dict)
|
||||
db.recipes.create(session, recipe_obj.dict())
|
||||
import_status = RecipeImport(name=recipe_obj.name, slug=recipe_obj.slug, status=True)
|
||||
imports.append(import_status)
|
||||
successful_imports.append(recipe.stem)
|
||||
logger.info(f"Imported: {recipe.stem}")
|
||||
recipes = [read_recipe_file(r) for r in recipe_dir.glob("*.json")]
|
||||
|
||||
for recipe in recipes:
|
||||
try:
|
||||
db.recipes.create(self.session, recipe.dict())
|
||||
import_status = RecipeImport(name=recipe.name, slug=recipe.slug, status=True)
|
||||
successful_imports.append(recipe.slug)
|
||||
logger.info(f"Imported: {recipe.slug}")
|
||||
|
||||
except Exception as inst:
|
||||
self.session.rollback()
|
||||
logger.error(inst)
|
||||
logger.info(f"Failed Import: {recipe.stem}")
|
||||
logger.info(f"Failed Import: {recipe.slug}")
|
||||
import_status = RecipeImport(
|
||||
name=recipe.stem,
|
||||
slug=recipe.stem,
|
||||
name=recipe.name,
|
||||
slug=recipe.slug,
|
||||
status=False,
|
||||
exception=str(inst),
|
||||
)
|
||||
imports.append(import_status)
|
||||
|
||||
imports.append(import_status)
|
||||
|
||||
self._import_images(successful_imports)
|
||||
|
||||
|
@ -86,6 +88,9 @@ class ImportDatabase:
|
|||
|
||||
@staticmethod
|
||||
def _recipe_migration(recipe_dict: dict) -> dict:
|
||||
if recipe_dict.get("categories", False):
|
||||
recipe_dict["recipeCategory"] = recipe_dict.get("categories")
|
||||
del recipe_dict["categories"]
|
||||
try:
|
||||
del recipe_dict["_id"]
|
||||
del recipe_dict["dateAdded"]
|
||||
|
@ -117,6 +122,9 @@ class ImportDatabase:
|
|||
|
||||
def import_themes(self):
|
||||
themes_file = self.import_dir.joinpath("themes", "themes.json")
|
||||
if not themes_file.exists():
|
||||
return []
|
||||
|
||||
theme_imports = []
|
||||
with open(themes_file, "r") as f:
|
||||
themes: list[dict] = json.loads(f.read())
|
||||
|
@ -141,6 +149,9 @@ class ImportDatabase:
|
|||
|
||||
def import_settings(self):
|
||||
settings_file = self.import_dir.joinpath("settings", "settings.json")
|
||||
if not settings_file.exists():
|
||||
return []
|
||||
|
||||
settings_imports = []
|
||||
|
||||
with open(settings_file, "r") as f:
|
||||
|
@ -153,6 +164,7 @@ class ImportDatabase:
|
|||
import_status = SettingsImport(name=name, status=True)
|
||||
|
||||
except Exception as inst:
|
||||
self.session.rollback()
|
||||
import_status = SettingsImport(name=name, status=False, exception=str(inst))
|
||||
|
||||
settings_imports.append(import_status)
|
||||
|
@ -160,6 +172,9 @@ class ImportDatabase:
|
|||
|
||||
def import_groups(self):
|
||||
groups_file = self.import_dir.joinpath("groups", "groups.json")
|
||||
if not groups_file.exists():
|
||||
return []
|
||||
|
||||
group_imports = []
|
||||
|
||||
with open(groups_file, "r") as f:
|
||||
|
@ -176,6 +191,7 @@ class ImportDatabase:
|
|||
import_status = GroupImport(name=group.name, status=True)
|
||||
|
||||
except Exception as inst:
|
||||
self.session.rollback()
|
||||
import_status = GroupImport(name=group.name, status=False, exception=str(inst))
|
||||
|
||||
group_imports.append(import_status)
|
||||
|
@ -184,6 +200,9 @@ class ImportDatabase:
|
|||
|
||||
def import_users(self):
|
||||
users_file = self.import_dir.joinpath("users", "users.json")
|
||||
if not users_file.exists():
|
||||
return []
|
||||
|
||||
user_imports = []
|
||||
|
||||
with open(users_file, "r") as f:
|
||||
|
@ -207,6 +226,7 @@ class ImportDatabase:
|
|||
import_status = UserImport(name=user.full_name, status=True)
|
||||
|
||||
except Exception as inst:
|
||||
self.session.rollback()
|
||||
import_status = UserImport(name=user.full_name, status=False, exception=str(inst))
|
||||
|
||||
user_imports.append(import_status)
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from mealie.core.config import TEMP_DIR
|
||||
from mealie.schema.recipe import Recipe
|
||||
from mealie.services.image_services import IMG_DIR
|
||||
from mealie.services.migrations.nextcloud import (
|
||||
cleanup,
|
||||
import_recipes,
|
||||
prep,
|
||||
process_selection,
|
||||
)
|
||||
from tests.test_config import TEST_NEXTCLOUD_DIR
|
||||
|
||||
CWD = Path(__file__).parent
|
||||
TEST_NEXTCLOUD_DIR
|
||||
TEMP_NEXTCLOUD = TEMP_DIR.joinpath("nextcloud")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"file_name,final_path",
|
||||
[("nextcloud.zip", TEMP_NEXTCLOUD)],
|
||||
)
|
||||
def test_zip_extraction(file_name: str, final_path: Path):
|
||||
prep()
|
||||
zip = TEST_NEXTCLOUD_DIR.joinpath(file_name)
|
||||
dir = process_selection(zip)
|
||||
|
||||
assert dir == final_path
|
||||
cleanup()
|
||||
assert dir.exists() == False
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"recipe_dir",
|
||||
[
|
||||
TEST_NEXTCLOUD_DIR.joinpath("Air Fryer Shrimp"),
|
||||
TEST_NEXTCLOUD_DIR.joinpath("Chicken Parmigiana"),
|
||||
TEST_NEXTCLOUD_DIR.joinpath("Skillet Shepherd's Pie"),
|
||||
],
|
||||
)
|
||||
def test_nextcloud_migration(recipe_dir: Path):
|
||||
recipe = import_recipes(recipe_dir)
|
||||
assert isinstance(recipe, Recipe)
|
||||
IMG_DIR.joinpath(recipe.image).unlink(missing_ok=True)
|
Loading…
Add table
Add a link
Reference in a new issue