fixed import export

This commit is contained in:
vabene1111 2020-06-29 19:09:15 +02:00
parent 38e5882376
commit 577af85d38
3 changed files with 54 additions and 70 deletions

View File

@ -42,7 +42,7 @@ class UserPreferenceSerializer(serializers.ModelSerializer):
class StorageSerializer(serializers.ModelSerializer): class StorageSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Storage model = Storage
fields = ('name', 'method', 'username', 'created_by') fields = ('id', 'name', 'method', 'username', 'created_by')
class SyncSerializer(serializers.ModelSerializer): class SyncSerializer(serializers.ModelSerializer):
@ -58,9 +58,16 @@ class SyncLogSerializer(serializers.ModelSerializer):
class KeywordSerializer(UniqueFieldsMixin, serializers.ModelSerializer): class KeywordSerializer(UniqueFieldsMixin, serializers.ModelSerializer):
def create(self, validated_data):
# since multi select tags dont have id's duplicate names might be routed to create
obj, created = Keyword.objects.get_or_create(**validated_data)
return obj
class Meta: class Meta:
model = Keyword model = Keyword
fields = '__all__' fields = ('id', 'name', 'icon', 'description', 'created_by', 'created_at', 'updated_at')
read_only_fields = ('id',)
class UnitSerializer(UniqueFieldsMixin, serializers.ModelSerializer): class UnitSerializer(UniqueFieldsMixin, serializers.ModelSerializer):

View File

@ -314,7 +314,9 @@
addIngredient: function (step) { //TODO see if default can be generated from options request addIngredient: function (step) { //TODO see if default can be generated from options request
step.ingredients.push({ step.ingredients.push({
'food': undefined, 'food': undefined,
'unit': undefined, 'unit': {
'name': '{{request.user.userpreference.default_unit}}'
},
'amount': 0, 'amount': 0,
'note': '', 'note': '',
'order': 0, 'order': 0,
@ -355,10 +357,13 @@
this.units_loading = true this.units_loading = true
this.$http.get("{% url 'api:unit-list' %}" + '?query=' + query + '&limit=10').then((response) => { this.$http.get("{% url 'api:unit-list' %}" + '?query=' + query + '&limit=10').then((response) => {
this.units = response.data; this.units = response.data;
for (let s of this.recipe.steps){
for (let i of s.ingredients) { if (this.recipe !== undefined) {
if (i.unit.id === undefined) { for (let s of this.recipe.steps) {
this.units.push(i.unit) for (let i of s.ingredients) {
if (i.unit.id === undefined) {
this.units.push(i.unit)
}
} }
} }
} }
@ -372,10 +377,12 @@
this.$http.get("{% url 'api:food-list' %}" + '?query=' + query + '&limit=10').then((response) => { this.$http.get("{% url 'api:food-list' %}" + '?query=' + query + '&limit=10').then((response) => {
this.foods = response.data this.foods = response.data
for (let s of this.recipe.steps){ if (this.recipe !== undefined) {
for (let i of s.ingredients) { for (let s of this.recipe.steps) {
if (i.food.id === undefined) { for (let i of s.ingredients) {
this.foods.push(i.food) if (i.food.id === undefined) {
this.foods.push(i.food)
}
} }
} }
} }

View File

@ -1,18 +1,20 @@
import base64 import base64
import json import json
import re import re
from json import JSONDecodeError
from django.contrib import messages from django.contrib import messages
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from django.db import IntegrityError from django.http import HttpResponseRedirect, HttpResponse
from django.http import HttpResponseRedirect, JsonResponse, HttpResponse
from django.shortcuts import render from django.shortcuts import render
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from rest_framework.renderers import JSONRenderer
from cookbook.forms import ExportForm, ImportForm from cookbook.forms import ExportForm, ImportForm
from cookbook.helper.permission_helper import group_required from cookbook.helper.permission_helper import group_required
from cookbook.models import Ingredient, Recipe, Unit, Food, Keyword, Food from cookbook.models import Recipe
from cookbook.serializer import RecipeSerializer
@group_required('user') @group_required('user')
@ -20,44 +22,28 @@ def import_recipe(request):
if request.method == "POST": if request.method == "POST":
form = ImportForm(request.POST) form = ImportForm(request.POST)
if form.is_valid(): if form.is_valid():
data = json.loads(form.cleaned_data['recipe']) try:
data = json.loads(form.cleaned_data['recipe'])
recipe = Recipe.objects.create(name=data['recipe']['name'], instructions=data['recipe']['instructions'], sr = RecipeSerializer(data=data)
working_time=data['recipe']['working_time'], waiting_time=data['recipe']['waiting_time'], if sr.is_valid():
created_by=request.user, internal=True) sr.validated_data['created_by'] = request.user
recipe = sr.save()
for k in data['keywords']: if data['image']:
try: fmt, img = data['image'].split(';base64,')
Keyword.objects.create(name=k['name'], icon=k['icon'], description=k['description']).save() ext = fmt.split('/')[-1]
except IntegrityError: recipe.image = ContentFile(base64.b64decode(img), name=f'{recipe.pk}.{ext}') # TODO possible security risk, maybe some checks needed
pass recipe.save()
recipe.keywords.add(Keyword.objects.get(name=k['name'])) messages.add_message(request, messages.SUCCESS, _('Recipe imported successfully!'))
return HttpResponseRedirect(reverse_lazy('view_recipe', args=[recipe.pk]))
else:
messages.add_message(request, messages.ERROR, _('Something went wrong during the import!'))
messages.add_message(request, messages.WARNING, sr.errors)
except JSONDecodeError:
messages.add_message(request, messages.ERROR, _('Could not parse the supplied JSON!'))
for u in data['units']:
try:
Unit.objects.create(name=u['name'], description=u['description']).save()
except IntegrityError:
pass
for i in data['ingredients']:
try:
Food.objects.create(name=i['name']).save()
except IntegrityError:
pass
for ri in data['recipe_ingredients']:
Ingredient.objects.create(recipe=recipe, ingredient=Food.objects.get(name=ri['food']),
unit=Unit.objects.get(name=ri['unit']), amount=ri['amount'], note=ri['note'])
if data['image']:
fmt, img = data['image'].split(';base64,')
ext = fmt.split('/')[-1]
recipe.image = ContentFile(base64.b64decode(img), name=f'{recipe.pk}.{ext}')
recipe.save()
messages.add_message(request, messages.SUCCESS, _('Recipe imported successfully!'))
return HttpResponseRedirect(reverse_lazy('view_recipe', args=[recipe.pk]))
else: else:
form = ImportForm() form = ImportForm()
@ -72,36 +58,20 @@ def export_recipe(request):
if form.is_valid(): if form.is_valid():
recipe = form.cleaned_data['recipe'] recipe = form.cleaned_data['recipe']
if recipe.internal: if recipe.internal:
export = { export = RecipeSerializer(recipe).data
'recipe': {'name': recipe.name, 'instructions': recipe.instructions, 'working_time': recipe.working_time, 'waiting_time': recipe.working_time},
'units': [],
'ingredients': [],
'recipe_ingredients': [],
'keywords': [],
'image': None
}
for k in recipe.keywords.all():
export['keywords'].append({'name': k.name, 'icon': k.icon, 'description': k.description})
for ri in Ingredient.objects.filter(recipe=recipe).all():
if ri.unit not in export['units']:
export['units'].append({'name': ri.unit.name, 'description': ri.unit.description})
if ri.ingredient not in export['ingredients']:
export['ingredients'].append({'name': ri.ingredient.name})
export['recipe_ingredients'].append({'food': ri.ingredient.name, 'unit': ri.unit.name, 'amount': float(ri.amount), 'note': ri.note})
if recipe.image and form.cleaned_data['image']: if recipe.image and form.cleaned_data['image']:
with open(recipe.image.path, 'rb') as img_f: with open(recipe.image.path, 'rb') as img_f:
export['image'] = f'data:image/png;base64,{base64.b64encode(img_f.read()).decode("utf-8")}' export['image'] = f'data:image/png;base64,{base64.b64encode(img_f.read()).decode("utf-8")}'
json_string = JSONRenderer().render(export).decode("utf-8")
if form.cleaned_data['download']: if form.cleaned_data['download']:
response = HttpResponse(json.dumps(export), content_type='text/plain') response = HttpResponse(json_string, content_type='text/plain')
response['Content-Disposition'] = f'attachment; filename={recipe.name}.json' response['Content-Disposition'] = f'attachment; filename={recipe.name}.json'
return response return response
context['export'] = json.dumps(export, indent=4) context['export'] = re.sub(r'"id":([0-9])+,', '', json_string)
else: else:
form.add_error('recipe', _('External recipes cannot be exported, please share the file directly or select an internal recipe.')) form.add_error('recipe', _('External recipes cannot be exported, please share the file directly or select an internal recipe.'))
else: else: