using new import/export module

This commit is contained in:
vabene1111 2021-02-08 11:38:38 +01:00
parent d2783429a1
commit 086570ce90
7 changed files with 30 additions and 186 deletions

View File

@ -9,7 +9,7 @@ WORKDIR /opt/recipes
COPY . ./
RUN chmod +x boot.sh
RUN apk add --no-cache --virtual .build-deps gcc musl-dev postgresql-dev zlib-dev jpeg-dev libressl-dev libffi-dev && \
RUN apk add --no-cache --virtual .build-deps gcc musl-dev postgresql-dev zlib-dev jpeg-dev libressl-dev libffi-dev openssl-dev && \
python -m venv venv && \
venv/bin/pip install -r requirements.txt --no-cache-dir &&\
apk --purge del .build-deps

View File

@ -131,39 +131,17 @@ class ShoppingForm(forms.Form):
)
class ExportForm(forms.Form):
recipe = forms.ModelChoiceField(
queryset=Recipe.objects.filter(internal=True).all(),
widget=SelectWidget
)
image = forms.BooleanField(
help_text=_('Export Base64 encoded image?'),
required=False
)
download = forms.BooleanField(
help_text=_('Download export directly or show on page?'),
required=False
)
class ImportForm(forms.Form):
recipe = forms.CharField(
widget=forms.Textarea,
help_text=_('Simply paste a JSON export into this textarea and click import.') # noqa: E501
)
class ImportExportBase(forms.Form):
DEFAULT = 'Default'
type = forms.ChoiceField(choices=((DEFAULT, _('Default')),))
class NewImportForm(ImportExportBase):
class ImportForm(ImportExportBase):
files = forms.FileField(required=True, widget=forms.ClearableFileInput(attrs={'multiple': True}))
class NewExportForm(ImportExportBase):
class ExportForm(ImportExportBase):
recipes = forms.ModelMultipleChoiceField(queryset=Recipe.objects.filter(internal=True).all(), widget=MultiSelectWidget)

View File

@ -13,7 +13,7 @@ class BaseAutocomplete(autocomplete.Select2QuerySetView):
qs = self.model.objects.all()
if self.q:
qs = qs.filter(name__istartswith=self.q)
qs = qs.filter(name__icontains=self.q)
return qs

View File

@ -1,6 +1,6 @@
{% extends "base.html" %}
{% load i18n %}
{% load crispy_forms_filters %}
{% load i18n %}
{% load static %}
{% block title %}{% trans 'Export Recipes' %}{% endblock %}
@ -9,8 +9,9 @@
{{ form.media }}
{% endblock %}
{% block content %}
{% block content %}
<h2>{% trans 'Export' %}</h2>
<div class="row">
<div class="col col-md-12">
<form action="." method="post">
@ -21,50 +22,4 @@
</form>
</div>
</div>
{% if export %}
<br/>
<div class="row">
<div class="col col-md-12">
<label for="id_export">
{% trans 'Exported Recipe' %}</label>
<textarea id="id_export" class="form-control" rows="12">
{{ export }}
</textarea>
</div>
</div>
<br/>
<div class="row">
<div class="col col-md-12 text-center">
<button class="btn btn-success" onclick="copy()" style="width: 15vw" data-toggle="tooltip"
data-placement="right" title="{% trans 'Copy to clipboard' %}" id="id_btn_copy"
onmouseout="resetTooltip()"><i
class="far fa-copy"></i></button>
</div>
</div>
<script type="text/javascript">
function copy() {
let json = $('#id_export');
json.select();
$('#id_btn_copy').attr('data-original-title', '{% trans 'Copied!' %}').tooltip('show');
document.execCommand("copy");
}
function resetTooltip() {
setTimeout(function () {
$('#id_btn_copy').attr('data-original-title', '{% trans 'Copy list to clipboard' %}');
}, 300);
}
$(function () {
$('[data-toggle="tooltip"]').tooltip()
})
</script>
{% endif %}
{% endblock %}

View File

@ -1,14 +1,20 @@
{% extends "base.html" %}
{% load crispy_forms_filters %}
{% load i18n %}
{% load crispy_forms_tags %}
{% load static %}
{% block title %}{% trans 'Import Recipes' %}{% endblock %}
{% block extra_head %}
{{ form.media }}
{% endblock %}
{% block content %}
<h2>{% trans 'Import' %}</h2>
<div class="row">
<div class="col col-md-12">
<form action="." method="post">
<form action="." method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-success" type="submit"><i class="fas fa-file-import"></i> {% trans 'Import' %}
@ -16,4 +22,5 @@
</form>
</div>
</div>
{% endblock %}

View File

@ -1,76 +1,24 @@
import base64
import json
import re
from json import JSONDecodeError
from django.contrib import messages
from django.core.files.base import ContentFile
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse_lazy
from django.utils.translation import gettext as _
from rest_framework.renderers import JSONRenderer
from cookbook.forms import ExportForm, ImportForm
from cookbook.forms import ExportForm, ExportForm, ImportForm
from cookbook.helper.permission_helper import group_required
from cookbook.integration.default import Default
from cookbook.models import Recipe
from cookbook.serializer import RecipeSerializer, RecipeExportSerializer
def get_integration(request, export_type):
return Default(request)
@group_required('user')
def import_recipe(request):
if request.method == "POST":
form = ImportForm(request.POST)
form = ImportForm(request.POST, request.FILES)
if form.is_valid():
try:
data = json.loads(
re.sub(r'"id":([0-9]+),', '', re.sub(r',(\s)*"recipe":([0-9]+)', '', form.cleaned_data['recipe']))
)
sr = RecipeExportSerializer(data=data, context={'request': request})
if sr.is_valid():
sr.validated_data['created_by'] = request.user
recipe = sr.save()
if data['image']:
try:
fmt, img = data['image'].split(';base64,')
ext = fmt.split('/')[-1]
# TODO possible security risk,
# maybe some checks needed
recipe.image = (ContentFile(
base64.b64decode(img),
name=f'{recipe.pk}.{ext}')
)
recipe.save()
except ValueError:
pass
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 as e:
print(e)
messages.add_message(
request,
messages.ERROR,
_('Could not parse the supplied JSON!')
)
integration = Default(request)
return integration.do_import(request.FILES.getlist('files'))
else:
form = ImportForm()
@ -79,41 +27,17 @@ def import_recipe(request):
@group_required('user')
def export_recipe(request):
context = {}
if request.method == "POST":
form = ExportForm(request.POST)
if form.is_valid():
recipe = form.cleaned_data['recipe']
if recipe.internal:
export = RecipeExportSerializer(recipe).data
if recipe.image and form.cleaned_data['image']:
with open(recipe.image.path, 'rb') as img_f:
export['image'] = f'data:image/png;base64,{base64.b64encode(img_f.read()).decode("utf-8")}' # noqa: E501
json_string = JSONRenderer().render(export).decode("utf-8")
if form.cleaned_data['download']:
response = HttpResponse(
json_string, content_type='text/plain'
)
response['Content-Disposition'] = f'attachment; filename={recipe.name}.json' # noqa: E501
return response
context['export'] = re.sub(r'"id":([0-9])+,', '', json_string)
else:
form.add_error(
'recipe',
_('External recipes cannot be exported, please share the file directly or select an internal recipe.') # noqa: E501
)
integration = Default(request)
return integration.do_export(form.cleaned_data['recipes'])
else:
form = ExportForm()
recipe = request.GET.get('r')
if recipe:
if re.match(r'^([0-9])+$', recipe):
if recipe := Recipe.objects.filter(pk=int(recipe)).first():
form = ExportForm(initial={'recipe': recipe})
form = ExportForm(initial={'recipes': recipe})
context['form'] = form
return render(request, 'export.html', context)
return render(request, 'export.html', {'form': form})

View File

@ -22,7 +22,7 @@ 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, NewImportForm, NewExportForm)
UserPreferenceForm, ImportForm, ImportForm, ExportForm)
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,
@ -490,27 +490,7 @@ def test(request):
if not settings.DEBUG:
return HttpResponseRedirect(reverse('index'))
if request.method == "POST":
form = NewImportForm(request.POST, request.FILES)
if form.is_valid():
integration = Default(request)
return integration.do_import(request.FILES.getlist('files'))
else:
form = NewImportForm()
return render(request, 'test.html', {'form': form})
def test2(request):
if not settings.DEBUG:
return HttpResponseRedirect(reverse('index'))
if request.method == "POST":
form = NewExportForm(request.POST)
if form.is_valid():
integration = Default(request)
return integration.do_export(form.cleaned_data['recipes'])
else:
form = NewExportForm()
return render(request, 'test2.html', {'form': form})