diff --git a/cookbook/integration/default.py b/cookbook/integration/default.py index bc219995e..7140290e8 100644 --- a/cookbook/integration/default.py +++ b/cookbook/integration/default.py @@ -1,14 +1,7 @@ import json -import os -import uuid -from io import StringIO, BytesIO -from os.path import basename +from io import BytesIO from zipfile import ZipFile -from PIL import Image -from django.core.files import File -from django.http import HttpResponse, HttpResponseRedirect -from django.urls import reverse from rest_framework.renderers import JSONRenderer from cookbook.integration.integration import Integration @@ -17,51 +10,16 @@ from cookbook.serializer import RecipeExportSerializer class Default(Integration): - def do_export(self, recipes): - export_zip_stream = BytesIO() - export_zip_obj = ZipFile(export_zip_stream, 'w') + def get_recipe_from_file(self, file): + recipe_zip = ZipFile(file) - for r in recipes: - if r.internal: - recipe_zip_stream = BytesIO() - recipe_zip_obj = ZipFile(recipe_zip_stream, 'w') - - recipe_json_stream = StringIO() - recipe_json_stream.write(self.get_export(r)) - recipe_zip_obj.writestr('recipe.json', recipe_json_stream.getvalue()) - recipe_json_stream.close() - - try: - recipe_zip_obj.write(r.image.path, 'image.png') - except ValueError: - pass - - recipe_zip_obj.close() - export_zip_obj.writestr(str(r.pk) + '.zip', recipe_zip_stream.getvalue()) - - export_zip_obj.close() - - response = HttpResponse(export_zip_stream.getvalue(), content_type='application/force-download') - response['Content-Disposition'] = 'attachment; filename="export.zip"' - return response - - def do_import(self, files): - for f in files: - zip = ZipFile(f.file) - for z in zip.namelist(): - self.get_recipe_from_zip(ZipFile(BytesIO(zip.read(z)))) - - return HttpResponseRedirect(reverse('view_search') + '?keywords=' + str(self.keyword.pk)) - - def get_recipe_from_zip(self, recipe_zip): recipe_string = recipe_zip.read('recipe.json').decode("utf-8") - recipe = self.get_recipe(recipe_string) + recipe = self.decode_recipe(recipe_string) if 'image.png' in recipe_zip.namelist(): - recipe.image = File(BytesIO(recipe_zip.read('image.png')), name=f'{uuid.uuid4()}_{recipe.pk}.png') - recipe.save() - recipe.keywords.add(self.keyword) + self.import_recipe_image(recipe, BytesIO(recipe_zip.read('image.png'))) + return recipe - def get_recipe(self, string): + def decode_recipe(self, string): data = json.loads(string) serialized_recipe = RecipeExportSerializer(data=data, context={'request': self.request}) if serialized_recipe.is_valid(): @@ -70,7 +28,7 @@ class Default(Integration): return None - def get_export(self, recipe): + def get_file_from_recipe(self, recipe): export = RecipeExportSerializer(recipe).data - return JSONRenderer().render(export).decode("utf-8") + return 'recipe.json', JSONRenderer().render(export).decode("utf-8") diff --git a/cookbook/integration/integration.py b/cookbook/integration/integration.py index d151f50e8..219e138aa 100644 --- a/cookbook/integration/integration.py +++ b/cookbook/integration/integration.py @@ -1,4 +1,12 @@ import datetime +import uuid + +from io import BytesIO, StringIO +from zipfile import ZipFile + +from django.core.files import File +from django.http import HttpResponseRedirect, HttpResponse +from django.urls import reverse from cookbook.models import Keyword @@ -16,20 +24,50 @@ class Integration: ) def do_export(self, recipes): - raise Exception('Method not implemented in storage integration') + export_zip_stream = BytesIO() + export_zip_obj = ZipFile(export_zip_stream, 'w') + + for r in recipes: + if r.internal: + recipe_zip_stream = BytesIO() + recipe_zip_obj = ZipFile(recipe_zip_stream, 'w') + + recipe_stream = StringIO() + filename, data = self.get_file_from_recipe(r) + recipe_stream.write(data) + recipe_zip_obj.writestr(filename, recipe_stream.getvalue()) + recipe_stream.close() + + try: + recipe_zip_obj.write(r.image.path, 'image.png') + except ValueError: + pass + + recipe_zip_obj.close() + export_zip_obj.writestr(str(r.pk) + '.zip', recipe_zip_stream.getvalue()) + + export_zip_obj.close() + + response = HttpResponse(export_zip_stream.getvalue(), content_type='application/force-download') + response['Content-Disposition'] = 'attachment; filename="export.zip"' + return response def do_import(self, files): + for f in files: + 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) + + return HttpResponseRedirect(reverse('view_search') + '?keywords=' + str(self.keyword.pk)) + + @staticmethod + def import_recipe_image(recipe, image_file): + recipe.image = File(image_file, name=f'{uuid.uuid4()}_{recipe.pk}.png') + recipe.save() + + def get_recipe_from_file(self, file): raise Exception('Method not implemented in storage integration') - def get_recipe(self, string): + def get_file_from_recipe(self, recipe): raise Exception('Method not implemented in storage integration') - - def get_export(self, recipe): - raise Exception('Method not implemented in storage integration') - - def get_export_file(self, recipe): - try: - with open(recipe.image.path, 'rb') as img_f: - return img_f - except: - return None