From 7d051336d34ce590caf8f555d4e76ab56c6eaebb Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Mon, 8 Feb 2021 19:09:45 +0100 Subject: [PATCH] basic nextcloud import --- cookbook/forms.py | 3 +- cookbook/integration/integration.py | 17 +++++-- cookbook/integration/nextcloud_cookbook.py | 52 ++++++++++++++++++++++ cookbook/views/import_export.py | 3 ++ 4 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 cookbook/integration/nextcloud_cookbook.py diff --git a/cookbook/forms.py b/cookbook/forms.py index 81fa057f1..1e22b070d 100644 --- a/cookbook/forms.py +++ b/cookbook/forms.py @@ -134,8 +134,9 @@ class ShoppingForm(forms.Form): class ImportExportBase(forms.Form): DEFAULT = 'DEFAULT' PAPRIKA = 'PAPRIKA' + NEXTCLOUD = 'NEXTCLOUD' - type = forms.ChoiceField(choices=((DEFAULT, _('Default')), (PAPRIKA, _('Paprika')),)) + type = forms.ChoiceField(choices=((DEFAULT, _('Default')), (PAPRIKA, _('Paprika')), (NEXTCLOUD, _('Nextcloud Cookbook')),)) class ImportForm(ImportExportBase): diff --git a/cookbook/integration/integration.py b/cookbook/integration/integration.py index 014bd3d99..5e412b253 100644 --- a/cookbook/integration/integration.py +++ b/cookbook/integration/integration.py @@ -63,6 +63,16 @@ class Integration: response['Content-Disposition'] = 'attachment; filename="export.zip"' return response + def import_file_name_filter(self, zip_info_object): + """ + Since zipfile.namelist() returns all files in all subdirectories this function allows filtering of files + If false is returned the file will be ignored + By default all files are included + :param zip_info_object: ZipInfo object + :return: Boolean if object should be included + """ + return True + def do_import(self, files): """ Imports given files @@ -73,9 +83,10 @@ class Integration: for f in files: if '.zip' in f.name: import_zip = ZipFile(f.file) - for z in import_zip.namelist(): - recipe = self.get_recipe_from_file(BytesIO(import_zip.read(z))) - recipe.keywords.add(self.keyword) + for z in import_zip.filelist: + if self.import_file_name_filter(z): + recipe = self.get_recipe_from_file(BytesIO(import_zip.read(z.filename))) + recipe.keywords.add(self.keyword) else: recipe = self.get_recipe_from_file(f.file) recipe.keywords.add(self.keyword) diff --git a/cookbook/integration/nextcloud_cookbook.py b/cookbook/integration/nextcloud_cookbook.py new file mode 100644 index 000000000..61909c872 --- /dev/null +++ b/cookbook/integration/nextcloud_cookbook.py @@ -0,0 +1,52 @@ +import json +import re +from io import BytesIO +from zipfile import ZipFile + +from rest_framework.renderers import JSONRenderer + +from cookbook.helper.ingredient_parser import parse +from cookbook.integration.integration import Integration +from cookbook.models import Recipe, Step, Food, Unit, Ingredient +from cookbook.serializer import RecipeExportSerializer + + +class NextcloudCookbook(Integration): + + def import_file_name_filter(self, zip_info_object): + print("testing", zip_info_object.filename) + return re.match(r'^Recipes/([A-Za-z\d\s])+/recipe.json$', zip_info_object.filename) + + def get_recipe_from_file(self, file): + recipe_json = json.loads(file.getvalue().decode("utf-8")) + + recipe = Recipe.objects.create( + name=recipe_json['name'].strip(), description=recipe_json['description'].strip(), + created_by=self.request.user, internal=True, + servings=recipe_json['recipeYield']) + + #TODO parse times (given in PT2H3M ) + + ingredients_added = False + for s in recipe_json['recipeInstructions']: + step = Step.objects.create( + instruction=s + ) + if not ingredients_added: + ingredients_added = True + + for ingredient in recipe_json['recipeIngredient']: + amount, unit, ingredient, note = parse(ingredient) + f, created = Food.objects.get_or_create(name=ingredient) + u, created = Unit.objects.get_or_create(name=unit) + step.ingredients.add(Ingredient.objects.create( + food=f, unit=u, amount=amount, note=note + )) + recipe.steps.add(step) + + return recipe + + def get_file_from_recipe(self, recipe): + export = RecipeExportSerializer(recipe).data + + return 'recipe.json', JSONRenderer().render(export).decode("utf-8") diff --git a/cookbook/views/import_export.py b/cookbook/views/import_export.py index b668970a7..f58cc2583 100644 --- a/cookbook/views/import_export.py +++ b/cookbook/views/import_export.py @@ -7,6 +7,7 @@ from django.utils.translation import gettext as _ from cookbook.forms import ExportForm, ImportForm, ImportExportBase from cookbook.helper.permission_helper import group_required from cookbook.integration.default import Default +from cookbook.integration.nextcloud_cookbook import NextcloudCookbook from cookbook.integration.paprika import Paprika from cookbook.models import Recipe @@ -16,6 +17,8 @@ def get_integration(request, export_type): return Default(request) if export_type == ImportExportBase.PAPRIKA: return Paprika(request) + if export_type == ImportExportBase.NEXTCLOUD: + return NextcloudCookbook(request) @group_required('user')