some tweaks for new exporter

This commit is contained in:
vabene1111 2022-02-03 18:00:02 +01:00
parent a3fa01d8d3
commit d45e3b8e60
10 changed files with 69 additions and 93 deletions

View File

@ -1,3 +0,0 @@
[Dolphin]
Timestamp=2022,1,7,19,23,46.14
Version=4

View File

@ -152,6 +152,6 @@ REVERSE_PROXY_AUTH=0
# Disabled by default, uncomment to enable
# ENABLE_PDF_EXPORT=1
# Duration to keep the cached export file (in seconds)
EXPORT_FILE_CACHE_DURATION=300
# Recipe exports are cached for a certain time by default, adjust time if needed
# EXPORT_FILE_CACHE_DURATION=600

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.11 on 2022-01-08 00:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0164_exportlog'),
]
operations = [
migrations.AddField(
model_name='exportlog',
name='cache_duration',
field=models.IntegerField(default=0),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.11 on 2022-01-08 00:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cookbook', '0165_exportlog_cache_duration'),
]
operations = [
migrations.AddField(
model_name='exportlog',
name='possibly_not_expired',
field=models.BooleanField(default=True),
),
]

View File

@ -1,4 +1,4 @@
# Generated by Django 3.2.11 on 2022-01-07 20:29
# Generated by Django 3.2.11 on 2022-02-03 15:03
import cookbook.models
from django.conf import settings
@ -10,7 +10,7 @@ class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('cookbook', '0163_auto_20220105_0758'),
('cookbook', '0168_add_unit_searchfields'),
]
operations = [
@ -23,6 +23,8 @@ class Migration(migrations.Migration):
('msg', models.TextField(default='')),
('total_recipes', models.IntegerField(default=0)),
('exported_recipes', models.IntegerField(default=0)),
('cache_duration', models.IntegerField(default=0)),
('possibly_not_expired', models.BooleanField(default=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cookbook.space')),

View File

@ -0,0 +1,25 @@
import pytest
from django.contrib import auth
from django.urls import reverse
from cookbook.forms import ImportExportBase
from cookbook.helper.ingredient_parser import IngredientParser
from cookbook.models import ExportLog
@pytest.fixture
def obj_1(space_1, u1_s1):
return ExportLog.objects.create(type=ImportExportBase.DEFAULT, running=False, created_by=auth.get_user(u1_s1), space=space_1, exported_recipes=10, total_recipes=10)
@pytest.mark.parametrize("arg", [
['a_u', 302],
['g1_s1', 302],
['u1_s1', 200],
['a1_s1', 200],
['u1_s2', 404],
['a1_s2', 404],
])
def test_export_file_cache(arg, request, obj_1):
c = request.getfixturevalue(arg[0])
assert c.get(reverse('view_export_file', args=[obj_1.pk])).status_code == arg[1]

View File

@ -73,7 +73,7 @@ urlpatterns = [
path('abuse/<slug:token>', views.report_share_abuse, name='view_report_share_abuse'),
path('import/', import_export.import_recipe, name='view_import'),
path('import-response/<int:pk>/', import_export.import_response, name='view_import_response'),\
path('import-response/<int:pk>/', import_export.import_response, name='view_import_response'),
path('export/', import_export.export_recipe, name='view_export'),
path('export-response/<int:pk>/', import_export.export_response, name='view_export_response'),
path('export-file/<int:pk>/', import_export.export_file, name='view_export_file'),

View File

@ -5,7 +5,7 @@ from django.core.cache import cache
from django.contrib import messages
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
from django.shortcuts import render
from django.shortcuts import render, get_object_or_404
from django.urls import reverse
from django.utils.translation import gettext as _
@ -125,7 +125,10 @@ def export_recipe(request):
recipes = Recipe.objects.filter(space=request.space, internal=True).all()
integration = get_integration(request, form.cleaned_data['type'])
if form.cleaned_data['type'] == ImportExportBase.PDF and not settings.ENABLE_PDF_EXPORT:
return JsonResponse({'error': _('The PDF Exporter is not enabled on this instance as it is still in an experimental state.')})
el = ExportLog.objects.create(type=form.cleaned_data['type'], created_by=request.user, space=request.space)
t = threading.Thread(target=integration.do_export, args=[recipes, el])
@ -141,7 +144,6 @@ def export_recipe(request):
},
status=400
)
else:
pk = ''
recipe = request.GET.get('r')
@ -156,6 +158,7 @@ def export_recipe(request):
def import_response(request, pk):
return render(request, 'import_response.html', {'pk': pk})
@group_required('user')
def export_response(request, pk):
return render(request, 'export_response.html', {'pk': pk})
@ -163,16 +166,15 @@ def export_response(request, pk):
@group_required('user')
def export_file(request, pk):
cacheData = cache.get('export_file_'+str(pk))
el = get_object_or_404(ExportLog, pk=pk, space=request.space)
cacheData = cache.get(f'export_file_{el.pk}')
if cacheData is None:
el = ExportLog.objects.get(pk=pk)
el.possibly_not_expired = False;
el.possibly_not_expired = False
el.save()
return render(request, 'export_response.html', {'pk': pk})
response = HttpResponse(cacheData['file'], content_type='application/force-download')
response['Content-Disposition'] = 'attachment; filename="'+cacheData['filename']+'"'
response['Content-Disposition'] = 'attachment; filename="' + cacheData['filename'] + '"'
return response

View File

@ -21,26 +21,26 @@ if your favorite one is missing.
Overview of the capabilities of the different integrations.
| Integration | Import | Export | Images |
|--------------------| ------ | ------ | ------ |
| Default | ✔️ | ✔️ | ✔️ |
| Nextcloud | ✔️ | ⌚ | ✔️ |
| Mealie | ✔️ | ⌚ | ✔️ |
| Chowdown | ✔️ | ⌚ | ✔️ |
| Safron | ✔️ | ✔ | ❌ |
| Paprika | ✔️ | ⌚ | ✔️ |
| ChefTap | ✔️ | ❌ | ❌ |
| Pepperplate | ✔️ | ⌚ | ❌ |
| RecipeSage | ✔️ | ✔️ | ✔️ |
| Domestica | ✔️ | ⌚ | ✔️ |
| MealMaster | ✔️ | ❌ | ❌ |
| RezKonv | ✔️ | ❌ | ❌ |
| OpenEats | ✔️ | ❌ | ⌚ |
| Plantoeat | ✔️ | ❌ | ✔ |
| CookBookApp | ✔️ | ⌚ | ✔️ |
| CopyMeThat | ✔️ | ❌ | ✔️ |
| PDF (experimental) | ⌚️ | ✔ | ✔️ |
|--------------------| ------ | -- | ------ |
| Default | ✔️ | ✔️ | ✔️ |
| Nextcloud | ✔️ | ⌚ | ✔️ |
| Mealie | ✔️ | ⌚ | ✔️ |
| Chowdown | ✔️ | ⌚ | ✔️ |
| Safron | ✔️ | ✔ | ❌ |
| Paprika | ✔️ | ⌚ | ✔️ |
| ChefTap | ✔️ | ❌ | ❌ |
| Pepperplate | ✔️ | ⌚ | ❌ |
| RecipeSage | ✔️ | ✔️ | ✔️ |
| Domestica | ✔️ | ⌚ | ✔️ |
| MealMaster | ✔️ | ❌ | ❌ |
| RezKonv | ✔️ | ❌ | ❌ |
| OpenEats | ✔️ | ❌ | ⌚ |
| Plantoeat | ✔️ | ❌ | ✔ |
| CookBookApp | ✔️ | ⌚ | ✔️ |
| CopyMeThat | ✔️ | ❌ | ✔️ |
| PDF (experimental) | ⌚️ | ✔ | ✔️ |
✔ = implemented, ❌ = not implemented and not possible/planned, ⌚ = not yet implemented
= implemented, ❌ = not implemented and not possible/planned, ⌚ = not yet implemented
## Default
The default integration is the built in (and preferred) way to import and export recipes.

View File

@ -9,24 +9,9 @@
<!-- TODO get option dynamicaly -->
<select class="form-control" v-model="recipe_app">
<option value="DEFAULT">Default</option>
<option value="PAPRIKA">Paprika</option>
<option value="NEXTCLOUD">Nextcloud Cookbook</option>
<option value="MEALIE">Mealie</option>
<option value="CHOWDOWN">Chowdown</option>
<option value="SAFFRON">Saffron</option>
<option value="CHEFTAP">ChefTap</option>
<option value="PEPPERPLATE">Pepperplate</option>
<option value="RECETTETEK">RecetteTek</option>
<option value="RECIPESAGE">Recipe Sage</option>
<option value="DOMESTICA">Domestica</option>
<option value="MEALMASTER">MealMaster</option>
<option value="REZKONV">RezKonv</option>
<option value="OPENEATS">Openeats</option>
<option value="RECIPEKEEPER">Recipe Keeper</option>
<option value="PLANTOEAT">Plantoeat</option>
<option value="COOKBOOKAPP">CookBookApp</option>
<option value="COPYMETHAT">CopyMeThat</option>
<option value="PDF">PDF</option>
<option value="PDF">PDF (experimental)</option>
</select>
<br/>
@ -53,8 +38,6 @@
@search-change="searchRecipes">
</multiselect>
<br/>
<button @click="exportRecipe()" class="btn btn-primary shadow-none"><i class="fas fa-file-export"></i> {{ $t('Export') }}
</button>
@ -164,14 +147,17 @@ export default {
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
axios.post(resolveDjangoUrl('view_export',), formData).then((response) => {
window.location.href = resolveDjangoUrl('view_export_response', response.data['export_id'])
if (response.data['error'] !== undefined){
makeToast(this.$t("Error"), response.data['error'],"warning")
}else{
window.location.href = resolveDjangoUrl('view_export_response', response.data['export_id'])
}
}).catch((err) => {
this.error = err.data
this.loading = false
console.log(err)
makeToast(this.$t("Error"), this.$t("There was an error loading a resource!"), "danger")
makeToast(this.$t("Error"), this.$t("There was an error loading a resource!"), "warning")
})
},