added paprika import

This commit is contained in:
vabene1111 2021-02-08 13:47:06 +01:00
parent ec842aa657
commit 79da8db889
7 changed files with 94 additions and 26 deletions

View File

@ -132,9 +132,10 @@ class ShoppingForm(forms.Form):
class ImportExportBase(forms.Form):
DEFAULT = 'Default'
DEFAULT = 'DEFAULT'
PAPRIKA = 'PAPRIKA'
type = forms.ChoiceField(choices=((DEFAULT, _('Default')),))
type = forms.ChoiceField(choices=((DEFAULT, _('Default')), (PAPRIKA, _('Paprika')),))
class ImportForm(ImportExportBase):

View File

@ -31,7 +31,7 @@ def get_from_html(html_text, url):
if ('@type' in ld_json_item
and ld_json_item['@type'] == 'Recipe'):
return find_recipe_json(ld_json_item, url)
return JsonResponse(find_recipe_json(ld_json_item, url))
except JSONDecodeError:
return JsonResponse(
{
@ -45,7 +45,7 @@ def get_from_html(html_text, url):
for i in items:
md_json = json.loads(i.json())
if 'schema.org/Recipe' in str(md_json['type']):
return find_recipe_json(md_json['properties'], url)
return JsonResponse(find_recipe_json(md_json['properties'], url))
return JsonResponse(
{
@ -173,7 +173,8 @@ def find_recipe_json(ld_json, url):
else:
ld_json['recipeInstructions'] = ''
ld_json['recipeInstructions'] += '\n\n' + _('Imported from') + ' ' + url
if url != '':
ld_json['recipeInstructions'] += '\n\n' + _('Imported from') + ' ' + url
if 'image' in ld_json:
# check if list of images is returned, take first if so
@ -232,4 +233,4 @@ def find_recipe_json(ld_json, url):
]:
ld_json.pop(key, None)
return JsonResponse(ld_json)
return ld_json

View File

@ -2,12 +2,14 @@ import datetime
import uuid
from io import BytesIO, StringIO
from zipfile import ZipFile
from zipfile import ZipFile, BadZipFile
from django.contrib import messages
from django.core.files import File
from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse
from django.utils.formats import date_format
from django.utils.translation import gettext as _
from cookbook.models import Keyword
@ -22,8 +24,8 @@ class Integration:
"""
self.request = request
self.keyword = Keyword.objects.create(
name=f'Import {datetime.datetime.now()}',
description=f'Imported by {request.user.get_user_name()} on {datetime.datetime.now()}',
name=f'Import {date_format(datetime.datetime.now(), "DATETIME_FORMAT")}.{datetime.datetime.now().strftime("%S")}',
description=f'Imported by {request.user.get_user_name()} at {date_format(datetime.datetime.now(), "DATETIME_FORMAT")}',
icon='📥'
)
@ -67,11 +69,18 @@ class Integration:
:param files: List of in memory files
:return: HttpResponseRedirect to the recipe search showing all imported recipes
"""
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)
try:
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)
else:
recipe = self.get_recipe_from_file(f.file)
recipe.keywords.add(self.keyword)
except BadZipFile:
messages.add_message(self.request, messages.ERROR, _('Importer expected a .zip file. Did you choose the correct importer type for your data ?'))
return HttpResponseRedirect(reverse('view_search') + '?keywords=' + str(self.keyword.pk))

View File

@ -0,0 +1,36 @@
import json
import microdata
from cookbook.helper.recipe_url_import import find_recipe_json
from cookbook.integration.integration import Integration
from cookbook.models import Recipe, Step, Food, Ingredient, Unit
class Paprika(Integration):
def get_file_from_recipe(self, recipe):
raise NotImplementedError('Method not implemented in storage integration')
def get_recipe_from_file(self, file):
html_text = file.getvalue().decode("utf-8")
items = microdata.get_items(html_text)
for i in items:
md_json = json.loads(i.json())
if 'schema.org/Recipe' in str(md_json['type']):
recipe_json = find_recipe_json(md_json['properties'], '')
recipe = Recipe.objects.create(name=recipe_json['name'].strip(), created_by=self.request.user, internal=True)
step = Step.objects.create(
instruction=recipe_json['recipeInstructions']
)
for ingredient in recipe_json['recipeIngredient']:
f, created = Food.objects.get_or_create(name=ingredient['ingredient']['text'])
u, created = Unit.objects.get_or_create(name=ingredient['unit']['text'])
step.ingredients.add(Ingredient.objects.create(
food=f, unit=u, amount=ingredient['amount'], note=ingredient['note']
))
recipe.steps.add(step)
return recipe

View File

@ -1,15 +1,21 @@
import re
from django.contrib import messages
from django.shortcuts import render
from django.utils.translation import gettext as _
from cookbook.forms import ExportForm, ExportForm, ImportForm
from cookbook.forms import ExportForm, ImportForm, ImportExportBase
from cookbook.helper.permission_helper import group_required
from cookbook.integration.default import Default
from cookbook.integration.paprika import Paprika
from cookbook.models import Recipe
def get_integration(request, export_type):
return Default(request)
if export_type == ImportExportBase.DEFAULT:
return Default(request)
if export_type == ImportExportBase.PAPRIKA:
return Paprika(request)
@group_required('user')
@ -17,8 +23,11 @@ def import_recipe(request):
if request.method == "POST":
form = ImportForm(request.POST, request.FILES)
if form.is_valid():
integration = Default(request)
return integration.do_import(request.FILES.getlist('files'))
try:
integration = get_integration(request, form.cleaned_data['type'])
return integration.do_import(request.FILES.getlist('files'))
except NotImplementedError:
messages.add_message(request, messages.ERROR, _('Importing is not implemented for this provider'))
else:
form = ImportForm()
@ -30,8 +39,12 @@ def export_recipe(request):
if request.method == "POST":
form = ExportForm(request.POST)
if form.is_valid():
integration = Default(request)
return integration.do_export(form.cleaned_data['recipes'])
try:
integration = get_integration(request, form.cleaned_data['type'])
return integration.do_export(form.cleaned_data['recipes'])
except NotImplementedError:
messages.add_message(request, messages.ERROR, _('Exporting is not implemented for this provider'))
else:
form = ExportForm()
recipe = request.GET.get('r')

View File

@ -1,6 +1,6 @@
import os
import re
from datetime import datetime, timedelta
from datetime import datetime
from uuid import UUID
from django.conf import settings
@ -11,7 +11,7 @@ from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
from django.db import IntegrityError
from django.db.models import Avg, Q
from django.http import HttpResponseRedirect, FileResponse, HttpResponse
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render, redirect
from django.urls import reverse, reverse_lazy
from django.utils import timezone
@ -22,9 +22,8 @@ from rest_framework.authtoken.models import Token
from cookbook.filters import RecipeFilter
from cookbook.forms import (CommentForm, Recipe, RecipeBookEntryForm, User,
UserCreateForm, UserNameForm, UserPreference,
UserPreferenceForm, ImportForm, ImportForm, ExportForm)
UserPreferenceForm)
from cookbook.helper.permission_helper import group_required, share_link_valid, has_group_permission
from cookbook.integration.default import Default
from cookbook.models import (Comment, CookLog, InviteLink, MealPlan,
RecipeBook, RecipeBookEntry, ViewLog, ShoppingList)
from cookbook.tables import (CookLogTable, RecipeTable, RecipeTableSmall,

View File

@ -20,3 +20,12 @@ It is maintained with new fields added and contains all data to transfer your re
It is also one of the few recipe formats that is actually structured in a way that allows for
easy machine readability if you want to use the data for any other purpose.
## Paprika
Paprika can create two types of export. The first is a proprietary `.paprikarecipes` file in some kind of binarized format.
The second one is HTML files containing at least a bit of microdata.
If you want to import your Paprika recipes create a html export. Then import the individual recipes HTML files.
Due to the lack of structure not all fields can be imported.
Even tough images are present in the export they cannot be imported atm. This is technically possible and might be
added in the future.