diff --git a/cookbook/forms.py b/cookbook/forms.py index 37a32638..5cca6c40 100644 --- a/cookbook/forms.py +++ b/cookbook/forms.py @@ -153,13 +153,14 @@ class ImportExportBase(forms.Form): PLANTOEAT = 'PLANTOEAT' COOKBOOKAPP = 'COOKBOOKAPP' COPYMETHAT = 'COPYMETHAT' + PDF = 'PDF' type = forms.ChoiceField(choices=( (DEFAULT, _('Default')), (PAPRIKA, 'Paprika'), (NEXTCLOUD, 'Nextcloud Cookbook'), (MEALIE, 'Mealie'), (CHOWDOWN, 'Chowdown'), (SAFRON, 'Safron'), (CHEFTAP, 'ChefTap'), (PEPPERPLATE, 'Pepperplate'), (RECETTETEK, 'RecetteTek'), (RECIPESAGE, 'Recipe Sage'), (DOMESTICA, 'Domestica'), (MEALMASTER, 'MealMaster'), (REZKONV, 'RezKonv'), (OPENEATS, 'Openeats'), (RECIPEKEEPER, 'Recipe Keeper'), - (PLANTOEAT, 'Plantoeat'), (COOKBOOKAPP, 'CookBookApp'), (COPYMETHAT, 'CopyMeThat'), + (PLANTOEAT, 'Plantoeat'), (COOKBOOKAPP, 'CookBookApp'), (COPYMETHAT, 'CopyMeThat'), (PDF, 'PDF'), )) diff --git a/cookbook/integration/integration.py b/cookbook/integration/integration.py index 2e5ac851..28379f04 100644 --- a/cookbook/integration/integration.py +++ b/cookbook/integration/integration.py @@ -67,9 +67,23 @@ class Integration: :param recipes: list of recipe objects :return: HttpResponse with a ZIP file that is directly downloaded """ - # TODO this is temporary, find a better solution for different export formats when doing other exporters - if self.export_type != ImportExportBase.RECIPESAGE: + if self.export_type == ImportExportBase.PDF: + + export_zip_stream = BytesIO() + export_zip_obj = ZipFile(export_zip_stream, 'w') + + files = self.get_files_from_recipes(recipes, self.request.COOKIES) + for filename, data in files: + export_zip_obj.writestr(filename, data) + + export_zip_obj.close() + + response = HttpResponse(export_zip_stream.getvalue(), content_type='application/force-download') + response['Content-Disposition'] = 'attachment; filename="export.zip"' + return response + + elif self.export_type != ImportExportBase.RECIPESAGE: export_zip_stream = BytesIO() export_zip_obj = ZipFile(export_zip_stream, 'w') diff --git a/cookbook/integration/pdfexport.py b/cookbook/integration/pdfexport.py new file mode 100644 index 00000000..5bc118d1 --- /dev/null +++ b/cookbook/integration/pdfexport.py @@ -0,0 +1,62 @@ +import json +from io import BytesIO +from re import match +from zipfile import ZipFile +import asyncio +from pyppeteer import launch + +from rest_framework.renderers import JSONRenderer + +from cookbook.helper.image_processing import get_filetype +from cookbook.integration.integration import Integration +from cookbook.serializer import RecipeExportSerializer + +import django.core.management.commands.runserver as runserver + + +class PDFexport(Integration): + + def get_recipe_from_file(self, file): + raise NotImplementedError('Method not implemented in storage integration') + + + + + + async def gen_pdf(self, recipes, sessionid): + cmd = runserver.Command() + + browser = await launch( + handleSIGINT=False, + handleSIGTERM=False, + handleSIGHUP=False, + ignoreHTTPSErrors=True + ) + + cookies = {'domain': cmd.default_addr, 'name': 'sessionid', 'value': sessionid,} + options = { 'format': 'letter', + 'margin': { + 'top': '0.75in', + 'bottom': '0.75in', + 'left': '0.75in', + 'right': '0.75in', + } + } + + page = await browser.newPage() + await page.emulateMedia('print') + await page.setCookie(cookies) + + files = [] + for recipe in recipes: + await page.goto('http://'+cmd.default_addr+':'+cmd.default_port+'/view/recipe/'+str(recipe.id), {'waitUntil': 'networkidle0',}) + files.append([ recipe.name+'.pdf', await page.pdf(options) ]) + + + await browser.close() + return files + + + + def get_files_from_recipes(self, recipes, cookie): + return asyncio.run(self.gen_pdf(recipes, cookie['sessionid'])) diff --git a/cookbook/views/import_export.py b/cookbook/views/import_export.py index ebbef836..28012efd 100644 --- a/cookbook/views/import_export.py +++ b/cookbook/views/import_export.py @@ -28,6 +28,7 @@ from cookbook.integration.recettetek import RecetteTek from cookbook.integration.recipesage import RecipeSage from cookbook.integration.rezkonv import RezKonv from cookbook.integration.safron import Safron +from cookbook.integration.pdfexport import PDFexport from cookbook.models import Recipe, ImportLog, UserPreference @@ -68,6 +69,8 @@ def get_integration(request, export_type): return CookBookApp(request, export_type) if export_type == ImportExportBase.COPYMETHAT: return CopyMeThat(request, export_type) + if export_type == ImportExportBase.PDF: + return PDFexport(request, export_type) @group_required('user') diff --git a/example.pdf b/example.pdf new file mode 100644 index 00000000..1d7506f3 Binary files /dev/null and b/example.pdf differ diff --git a/requirements.txt b/requirements.txt index 64c3b7d1..64fbb60b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -41,4 +41,5 @@ boto3==1.20.19 django-prometheus==2.1.0 django-hCaptcha==0.1.0 python-ldap==3.4.0 -django-auth-ldap==3.0.0 \ No newline at end of file +django-auth-ldap==3.0.0 +pyppeteer==0.2.6