Merge branch 'feature/export-progress' of https://github.com/vabene1111/recipes into feature/export-progress

This commit is contained in:
vabene1111 2022-02-03 15:59:18 +01:00
commit a3fa01d8d3
26 changed files with 1240 additions and 100 deletions

3
.directory Normal file
View File

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

View File

@ -151,3 +151,7 @@ REVERSE_PROXY_AUTH=0
# Enables exporting PDF (see export docs)
# Disabled by default, uncomment to enable
# ENABLE_PDF_EXPORT=1
# Duration to keep the cached export file (in seconds)
EXPORT_FILE_CACHE_DURATION=300

View File

@ -32,11 +32,12 @@ class Default(Integration):
return None
def get_file_from_recipe(self, recipe):
export = RecipeExportSerializer(recipe).data
return 'recipe.json', JSONRenderer().render(export).decode("utf-8")
def get_files_from_recipes(self, recipes, cookie):
def get_files_from_recipes(self, recipes, el, cookie):
export_zip_stream = BytesIO()
export_zip_obj = ZipFile(export_zip_stream, 'w')
@ -50,13 +51,20 @@ class Default(Integration):
recipe_stream.write(data)
recipe_zip_obj.writestr(filename, recipe_stream.getvalue())
recipe_stream.close()
try:
recipe_zip_obj.writestr(f'image{get_filetype(r.image.file.name)}', r.image.file.read())
except ValueError:
pass
recipe_zip_obj.close()
export_zip_obj.writestr(str(r.pk) + '.zip', recipe_zip_stream.getvalue())
el.exported_recipes += 1
el.msg += self.get_recipe_processed_msg(r)
el.save()
export_zip_obj.close()
return [[ 'export.zip', export_zip_stream.getvalue() ]]
return [[ self.get_export_file_name(), export_zip_stream.getvalue() ]]

View File

@ -1,9 +1,12 @@
import time
import datetime
import json
import traceback
import uuid
from io import BytesIO, StringIO
from zipfile import BadZipFile, ZipFile
from django.core.cache import cache
import datetime
from bs4 import Tag
from django.core.exceptions import ObjectDoesNotExist
@ -18,6 +21,7 @@ from cookbook.forms import ImportExportBase
from cookbook.helper.image_processing import get_filetype, handle_image
from cookbook.models import Keyword, Recipe
from recipes.settings import DEBUG
from recipes.settings import EXPORT_FILE_CACHE_DURATION
class Integration:
@ -61,35 +65,44 @@ class Integration:
space=request.space
)
def do_export(self, recipes):
"""
Perform the export based on a list of recipes
:param recipes: list of recipe objects
:return: HttpResponse with the file of the requested export format that is directly downloaded (When that format involve multiple files they are zipped together)
"""
files = self.get_files_from_recipes(recipes, self.request.COOKIES)
if len(files) == 1:
filename, file = files[0]
export_filename = filename
export_file = file
def do_export(self, recipes, el):
else:
export_filename = "export.zip"
export_stream = BytesIO()
export_obj = ZipFile(export_stream, 'w')
with scope(space=self.request.space):
el.total_recipes = len(recipes)
el.cache_duration = EXPORT_FILE_CACHE_DURATION
el.save()
for filename, file in files:
export_obj.writestr(filename, file)
files = self.get_files_from_recipes(recipes, el, self.request.COOKIES)
export_obj.close()
export_file = export_stream.getvalue()
if len(files) == 1:
filename, file = files[0]
export_filename = filename
export_file = file
else:
#zip the files if there is more then one file
export_filename = self.get_export_file_name()
export_stream = BytesIO()
export_obj = ZipFile(export_stream, 'w')
for filename, file in files:
export_obj.writestr(filename, file)
export_obj.close()
export_file = export_stream.getvalue()
cache.set('export_file_'+str(el.pk), {'filename': export_filename, 'file': export_file}, EXPORT_FILE_CACHE_DURATION)
el.running = False
el.save()
response = HttpResponse(export_file, content_type='application/force-download')
response['Content-Disposition'] = 'attachment; filename="' + export_filename + '"'
return response
def import_file_name_filter(self, zip_info_object):
"""
Since zipfile.namelist() returns all files in all subdirectories this function allows filtering of files
@ -126,7 +139,7 @@ class Integration:
for d in data_list:
recipe = self.get_recipe_from_file(d)
recipe.keywords.add(self.keyword)
il.msg += f'{recipe.pk} - {recipe.name} \n'
il.msg += self.get_recipe_processed_msg(recipe)
self.handle_duplicates(recipe, import_duplicates)
il.imported_recipes += 1
il.save()
@ -151,7 +164,7 @@ class Integration:
else:
recipe = self.get_recipe_from_file(BytesIO(import_zip.read(z.filename)))
recipe.keywords.add(self.keyword)
il.msg += f'{recipe.pk} - {recipe.name} \n'
il.msg += self.get_recipe_processed_msg(recipe)
self.handle_duplicates(recipe, import_duplicates)
il.imported_recipes += 1
il.save()
@ -166,7 +179,7 @@ class Integration:
try:
recipe = self.get_recipe_from_file(d)
recipe.keywords.add(self.keyword)
il.msg += f'{recipe.pk} - {recipe.name} \n'
il.msg += self.get_recipe_processed_msg(recipe)
self.handle_duplicates(recipe, import_duplicates)
il.imported_recipes += 1
il.save()
@ -183,7 +196,7 @@ class Integration:
try:
recipe = self.get_recipe_from_file(d)
recipe.keywords.add(self.keyword)
il.msg += f'{recipe.pk} - {recipe.name} \n'
il.msg += self.get_recipe_processed_msg(recipe)
self.handle_duplicates(recipe, import_duplicates)
il.imported_recipes += 1
il.save()
@ -193,7 +206,7 @@ class Integration:
else:
recipe = self.get_recipe_from_file(f['file'])
recipe.keywords.add(self.keyword)
il.msg += f'{recipe.pk} - {recipe.name} \n'
il.msg += self.get_recipe_processed_msg(recipe)
self.handle_duplicates(recipe, import_duplicates)
except BadZipFile:
il.msg += 'ERROR ' + _(
@ -260,7 +273,7 @@ class Integration:
"""
raise NotImplementedError('Method not implemented in integration')
def get_files_from_recipes(self, recipes, cookie):
def get_files_from_recipes(self, recipes, el, cookie):
"""
Takes a list of recipe object and converts it to a array containing each file.
Each file is represented as an array [filename, data] where data is a string of the content of the file.
@ -279,3 +292,10 @@ class Integration:
log.msg += exception.msg
if DEBUG:
traceback.print_exc()
def get_export_file_name(self, format='zip'):
return "export_{}.{}".format(datetime.datetime.now().strftime("%Y-%m-%d"), format)
def get_recipe_processed_msg(self, recipe):
return f'{recipe.pk} - {recipe.name} \n'

View File

@ -11,22 +11,25 @@ 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
from cookbook.models import ExportLog
from asgiref.sync import sync_to_async
import django.core.management.commands.runserver as runserver
import logging
class PDFexport(Integration):
def get_recipe_from_file(self, file):
raise NotImplementedError('Method not implemented in storage integration')
async def get_files_from_recipes_async(self, recipes, cookie):
async def get_files_from_recipes_async(self, recipes, el, cookie):
cmd = runserver.Command()
browser = await launch(
handleSIGINT=False,
handleSIGTERM=False,
handleSIGHUP=False,
ignoreHTTPSErrors=True
ignoreHTTPSErrors=True,
)
cookies = {'domain': cmd.default_addr, 'name': 'sessionid', 'value': cookie['sessionid'], }
@ -39,17 +42,28 @@ class PDFexport(Integration):
}
}
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', })
page = await browser.newPage()
await page.emulateMedia('print')
await page.setCookie(cookies)
await page.goto('http://'+cmd.default_addr+':'+cmd.default_port+'/view/recipe/'+str(recipe.id), {'waitUntil': 'domcontentloaded'})
await page.waitForSelector('#printReady');
files.append([recipe.name + '.pdf', await page.pdf(options)])
await page.close();
el.exported_recipes += 1
el.msg += self.get_recipe_processed_msg(recipe)
await sync_to_async(el.save, thread_sensitive=True)()
await browser.close()
return files
def get_files_from_recipes(self, recipes, cookie):
return asyncio.run(self.get_files_from_recipes_async(recipes, cookie))
def get_files_from_recipes(self, recipes, el, cookie):
return asyncio.run(self.get_files_from_recipes_async(recipes, el, cookie))

View File

@ -88,12 +88,16 @@ class RecipeSage(Integration):
return data
def get_files_from_recipes(self, recipes, cookie):
def get_files_from_recipes(self, recipes, el, cookie):
json_list = []
for r in recipes:
json_list.append(self.get_file_from_recipe(r))
return [['export.json', json.dumps(json_list)]]
el.exported_recipes += 1
el.msg += self.get_recipe_processed_msg(r)
el.save()
return [[self.get_export_file_name('json'), json.dumps(json_list)]]
def split_recipe_file(self, file):
return json.loads(file.read().decode("utf-8"))

View File

@ -87,10 +87,14 @@ class Saffron(Integration):
return recipe.name+'.txt', data
def get_files_from_recipes(self, recipes, cookie):
def get_files_from_recipes(self, recipes, el, cookie):
files = []
for r in recipes:
filename, data = self.get_file_from_recipe(r)
files.append([ filename, data ])
el.exported_recipes += 1
el.msg += self.get_recipe_processed_msg(r)
el.save()
return files

View File

@ -0,0 +1,32 @@
# Generated by Django 3.2.11 on 2022-01-07 20:29
import cookbook.models
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('cookbook', '0163_auto_20220105_0758'),
]
operations = [
migrations.CreateModel(
name='ExportLog',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('type', models.CharField(max_length=32)),
('running', models.BooleanField(default=True)),
('msg', models.TextField(default='')),
('total_recipes', models.IntegerField(default=0)),
('exported_recipes', models.IntegerField(default=0)),
('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')),
],
bases=(models.Model, cookbook.models.PermissionModelMixin),
),
]

View File

@ -0,0 +1,18 @@
# 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

@ -0,0 +1,18 @@
# 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

@ -1002,6 +1002,25 @@ class ImportLog(models.Model, PermissionModelMixin):
def __str__(self):
return f"{self.created_at}:{self.type}"
class ExportLog(models.Model, PermissionModelMixin):
type = models.CharField(max_length=32)
running = models.BooleanField(default=True)
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(User, on_delete=models.CASCADE)
objects = ScopedManager(space='space')
space = models.ForeignKey(Space, on_delete=models.CASCADE)
def __str__(self):
return f"{self.created_at}:{self.type}"
class BookmarkletImport(ExportModelOperationsMixin('bookmarklet_import'), models.Model, PermissionModelMixin):
html = models.TextField()

View File

@ -15,7 +15,7 @@ from rest_framework.fields import empty
from cookbook.helper.HelperFunctions import str2bool
from cookbook.helper.shopping_helper import RecipeShoppingEditor
from cookbook.models import (Automation, BookmarkletImport, Comment, CookLog, Food,
FoodInheritField, ImportLog, Ingredient, Keyword, MealPlan, MealType,
FoodInheritField, ImportLog, ExportLog, Ingredient, Keyword, MealPlan, MealType,
NutritionInformation, Recipe, RecipeBook, RecipeBookEntry,
RecipeImport, ShareLink, ShoppingList, ShoppingListEntry,
ShoppingListRecipe, Step, Storage, Supermarket, SupermarketCategory,
@ -850,6 +850,20 @@ class ImportLogSerializer(serializers.ModelSerializer):
read_only_fields = ('created_by',)
class ExportLogSerializer(serializers.ModelSerializer):
def create(self, validated_data):
validated_data['created_by'] = self.context['request'].user
validated_data['space'] = self.context['request'].space
return super().create(validated_data)
class Meta:
model = ExportLog
fields = ('id', 'type', 'msg', 'running', 'total_recipes', 'exported_recipes', 'cache_duration', 'possibly_not_expired', 'created_by', 'created_at')
read_only_fields = ('created_by',)
class AutomationSerializer(serializers.ModelSerializer):
def create(self, validated_data):

View File

@ -1140,3 +1140,10 @@
min-width: 28rem;
}
}
@media print{
#switcher{
display: none;
}
}

View File

@ -1,25 +1,33 @@
{% extends "base.html" %}
{% load crispy_forms_filters %}
{% load i18n %}
{% load render_bundle from webpack_loader %}
{% load static %}
{% load i18n %}
{% load l10n %}
{% block title %}{% trans 'Export Recipes' %}{% endblock %}
{% block extra_head %}
{{ form.media }}
{% block content %}
<div id="app">
<export-view></export-view>
</div>
{% endblock %}
{% block script %}
{% if debug %}
<script src="{% url 'js_reverse' %}"></script>
{% else %}
<script src="{% static 'django_js_reverse/reverse.js' %}"></script>
{% endif %}
<script type="application/javascript">
window.EXPORT_ID = {{pk}};
window.CUSTOM_LOCALE = '{{ request.LANGUAGE_CODE }}';
</script>
{% render_bundle 'export_view' %}
{% endblock %}
{% block content %}
<h2>{% trans 'Export' %}</h2>
<div class="row">
<div class="col col-md-12">
<form action="." method="post">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-success" type="submit"><i class="fas fa-file-export"></i> {% trans 'Export' %}
</button>
</form>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,32 @@
{% extends "base.html" %}
{% load render_bundle from webpack_loader %}
{% load static %}
{% load i18n %}
{% load l10n %}
{% block title %}{% trans 'Export' %}{% endblock %}
{% block content %}
<div id="app">
<export-response-view></export-response-view>
</div>
{% endblock %}
{% block script %}
{% if debug %}
<script src="{% url 'js_reverse' %}"></script>
{% else %}
<script src="{% static 'django_js_reverse/reverse.js' %}"></script>
{% endif %}
<script type="application/javascript">
window.EXPORT_ID = {{pk}};
window.CUSTOM_LOCALE = '{{ request.LANGUAGE_CODE }}'
</script>
{% render_bundle 'export_response_view' %}
{% endblock %}

View File

@ -21,6 +21,7 @@ router.register(r'cook-log', api.CookLogViewSet)
router.register(r'food', api.FoodViewSet)
router.register(r'food-inherit-field', api.FoodInheritFieldViewSet)
router.register(r'import-log', api.ImportLogViewSet)
router.register(r'export-log', api.ExportLogViewSet)
router.register(r'ingredient', api.IngredientViewSet)
router.register(r'keyword', api.KeywordViewSet)
router.register(r'meal-plan', api.MealPlanViewSet)
@ -72,8 +73,10 @@ 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'),
path('view/recipe/<int:pk>', views.recipe_view, name='view_recipe'),
path('view/recipe/<int:pk>/<slug:share>', views.recipe_view, name='view_recipe'),

View File

@ -43,7 +43,7 @@ from cookbook.helper.recipe_search import RecipeFacet, RecipeSearch, old_search
from cookbook.helper.recipe_url_import import get_from_scraper
from cookbook.helper.shopping_helper import RecipeShoppingEditor, shopping_helper
from cookbook.models import (Automation, BookmarkletImport, CookLog, Food, FoodInheritField,
ImportLog, Ingredient, Keyword, MealPlan, MealType, Recipe, RecipeBook,
ImportLog, ExportLog, Ingredient, Keyword, MealPlan, MealType, Recipe, RecipeBook,
RecipeBookEntry, ShareLink, ShoppingList, ShoppingListEntry,
ShoppingListRecipe, Step, Storage, Supermarket, SupermarketCategory,
SupermarketCategoryRelation, Sync, SyncLog, Unit, UserFile,
@ -54,7 +54,7 @@ from cookbook.provider.nextcloud import Nextcloud
from cookbook.schemas import FilterSchema, QueryParam, QueryParamAutoSchema, TreeSchema
from cookbook.serializer import (AutomationSerializer, BookmarkletImportSerializer,
CookLogSerializer, FoodInheritFieldSerializer, FoodSerializer,
FoodShoppingUpdateSerializer, ImportLogSerializer,
FoodShoppingUpdateSerializer, ImportLogSerializer, ExportLogSerializer,
IngredientSerializer, KeywordSerializer, MealPlanSerializer,
MealTypeSerializer, RecipeBookEntrySerializer,
RecipeBookSerializer, RecipeImageSerializer,
@ -861,6 +861,17 @@ class ImportLogViewSet(viewsets.ModelViewSet):
return self.queryset.filter(space=self.request.space)
class ExportLogViewSet(viewsets.ModelViewSet):
queryset = ExportLog.objects
serializer_class = ExportLogSerializer
permission_classes = [CustomIsUser]
pagination_class = DefaultPagination
def get_queryset(self):
return self.queryset.filter(space=self.request.space)
class BookmarkletImportViewSet(viewsets.ModelViewSet):
queryset = BookmarkletImport.objects
serializer_class = BookmarkletImportSerializer

View File

@ -1,9 +1,10 @@
import re
import threading
from io import BytesIO
from django.core.cache import cache
from django.contrib import messages
from django.http import HttpResponseRedirect, JsonResponse
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
from django.shortcuts import render
from django.urls import reverse
from django.utils.translation import gettext as _
@ -29,7 +30,7 @@ from cookbook.integration.recipesage import RecipeSage
from cookbook.integration.rezkonv import RezKonv
from cookbook.integration.saffron import Saffron
from cookbook.integration.pdfexport import PDFexport
from cookbook.models import Recipe, ImportLog, UserPreference
from cookbook.models import Recipe, ImportLog, ExportLog, UserPreference
from recipes import settings
@ -123,25 +124,55 @@ def export_recipe(request):
if form.cleaned_data['all']:
recipes = Recipe.objects.filter(space=request.space, internal=True).all()
if form.cleaned_data['type'] == ImportExportBase.PDF and not settings.ENABLE_PDF_EXPORT:
messages.add_message(request, messages.ERROR, _('The PDF Exporter is not enabled on this instance as it is still in an experimental state.'))
return render(request, 'export.html', {'form': form})
integration = get_integration(request, form.cleaned_data['type'])
return integration.do_export(recipes)
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])
t.setDaemon(True)
t.start()
return JsonResponse({'export_id': el.pk})
except NotImplementedError:
messages.add_message(request, messages.ERROR, _('Exporting is not implemented for this provider'))
return JsonResponse(
{
'error': True,
'msg': _('Importing is not implemented for this provider')
},
status=400
)
else:
form = ExportForm(space=request.space)
pk = ''
recipe = request.GET.get('r')
if recipe:
if re.match(r'^([0-9])+$', recipe):
if recipe := Recipe.objects.filter(pk=int(recipe), space=request.space).first():
form = ExportForm(initial={'recipes': recipe}, space=request.space)
pk = Recipe.objects.filter(pk=int(recipe), space=request.space).first().pk
return render(request, 'export.html', {'form': form})
return render(request, 'export.html', {'pk': pk})
@group_required('user')
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})
@group_required('user')
def export_file(request, pk):
cacheData = cache.get('export_file_'+str(pk))
if cacheData is None:
el = ExportLog.objects.get(pk=pk)
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']+'"'
return response

View File

@ -138,6 +138,7 @@ ENABLE_SIGNUP = bool(int(os.getenv('ENABLE_SIGNUP', False)))
ENABLE_METRICS = bool(int(os.getenv('ENABLE_METRICS', False)))
ENABLE_PDF_EXPORT = bool(int(os.getenv('ENABLE_PDF_EXPORT', False)))
EXPORT_FILE_CACHE_DURATION = int(os.getenv('EXPORT_FILE_CACHE_DURATION', 600))
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
@ -427,3 +428,4 @@ EMAIL_USE_TLS = bool(int(os.getenv('EMAIL_USE_TLS', False)))
EMAIL_USE_SSL = bool(int(os.getenv('EMAIL_USE_SSL', False)))
DEFAULT_FROM_EMAIL = os.getenv('DEFAULT_FROM_EMAIL', 'webmaster@localhost')
ACCOUNT_EMAIL_SUBJECT_PREFIX = os.getenv('ACCOUNT_EMAIL_SUBJECT_PREFIX', '[Tandoor Recipes] ') # allauth sender prefix

View File

@ -0,0 +1,145 @@
<template>
<div id="app">
<br/>
<template v-if="export_info !== undefined">
<template v-if="export_info.running">
<h5 style="text-align: center">{{ $t('Exporting') }}...</h5>
<b-progress :max="export_info.total_recipes">
<b-progress-bar :value="export_info.exported_recipes" :label="`${export_info.exported_recipes}/${export_info.total_recipes}`"></b-progress-bar>
</b-progress>
<loading-spinner :size="25"></loading-spinner>
</template>
<div class="row">
<div class="col col-md-12" v-if="!export_info.running">
<span>{{ $t('Export_finished') }}! </span> <a :href="`${resolveDjangoUrl('viewExport') }`">{{ $t('Return to export') }} </a><br><br>
{{ $t('If download did not start automatically: ') }}
<template v-if="export_info.expired">
<a disabled><del>{{ $t('Download') }}</del></a> ({{ $t('Expired') }})
</template>
<a v-else :href="`/export-file/${export_id}/`" ref="downloadAnchor" >{{ $t('Download') }}</a>
<br>
{{ $t('The link will remain active for') }}
<template v-if="export_info.cache_duration > 3600">
{{ export_info.cache_duration/3600 }}{{ $t('hr') }}
</template>
<template v-else-if="export_info.cache_duration > 60">
{{ export_info.cache_duration/60 }}{{ $t('min') }}
</template>
<template v-else>
{{ export_info.cache_duration }}{{ $t('sec') }}
</template>
<br>
</div>
</div>
<br/>
<div class="row">
<div class="col col-md-12">
<label for="id_textarea">{{ $t('Information') }}</label>
<textarea id="id_textarea" ref="output_text" class="form-control" style="height: 50vh"
v-html="export_info.msg"
disabled></textarea>
</div>
</div>
<br/>
<br/>
</template>
</div>
</template>
<script>
import Vue from 'vue'
import {BootstrapVue} from 'bootstrap-vue'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import {ResolveUrlMixin, makeToast, ToastMixin} from "@/utils/utils";
import LoadingSpinner from "@/components/LoadingSpinner";
import {ApiApiFactory} from "@/utils/openapi/api.ts";
Vue.use(BootstrapVue)
export default {
name: 'ExportResponseView',
mixins: [
ResolveUrlMixin,
ToastMixin,
],
components: {
LoadingSpinner
},
data() {
return {
export_id: window.EXPORT_ID,
export_info: undefined,
}
},
mounted() {
this.refreshData()
this.$i18n.locale = window.CUSTOM_LOCALE
this.dynamicIntervalTimeout = 250 //initial refresh rate
this.run = setTimeout(this.dynamicInterval.bind(this), this.dynamicIntervalTimeout)
},
methods: {
dynamicInterval: function(){
//update frequently at start but slowdown as it takes longer
this.dynamicIntervalTimeout = Math.round(this.dynamicIntervalTimeout*((1+Math.sqrt(5))/2))
if(this.dynamicIntervalTimeout > 5000) this.dynamicIntervalTimeout = 5000
clearInterval(this.run);
this.run = setInterval(this.dynamicInterval.bind(this), this.dynamicIntervalTimeout);
if ((this.export_id !== null) && window.navigator.onLine && this.export_info.running) {
this.refreshData()
let el = this.$refs.output_text
el.scrollTop = el.scrollHeight;
if(this.export_info.expired)
makeToast(this.$t("Error"), this.$t("The download link is expired!"), "danger")
}
},
startDownload: function(){
this.$refs['downloadAnchor'].click()
},
refreshData: function () {
let apiClient = new ApiApiFactory()
apiClient.retrieveExportLog(this.export_id).then(result => {
this.export_info = result.data
this.export_info.expired = !this.export_info.possibly_not_expired
if(!this.export_info.running)
this.$nextTick(()=>{ this.startDownload(); } )
})
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,18 @@
import Vue from 'vue'
import App from './ExportResponseView.vue'
import i18n from '@/i18n'
Vue.config.productionTip = false
// TODO move this and other default stuff to centralized JS file (verify nothing breaks)
let publicPath = localStorage.STATIC_URL + 'vue/'
if (process.env.NODE_ENV === 'development') {
publicPath = 'http://localhost:8080/'
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
new Vue({
i18n,
render: h => h(App),
}).$mount('#app')

View File

@ -0,0 +1,188 @@
<template>
<div id="app">
<h2>{{ $t('Export') }}</h2>
<div class="row">
<div class="col col-md-12">
<br/>
<!-- 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>
</select>
<br/>
<b-form-checkbox v-model="export_all" @change="disabled_multiselect=$event" name="check-button" switch style="margin-top: 1vh">
{{ $t('All recipes') }}
</b-form-checkbox>
<multiselect
:searchable="true"
:disabled="disabled_multiselect"
v-model="recipe_list"
:options="recipes"
:close-on-select="false"
:clear-on-select="true"
:hide-selected="true"
:preserve-search="true"
placeholder="Select Recipes"
:taggable="false"
label="name"
track-by="id"
id="id_recipes"
:multiple="true"
:loading="recipes_loading"
@search-change="searchRecipes">
</multiselect>
<br/>
<button @click="exportRecipe()" class="btn btn-primary shadow-none"><i class="fas fa-file-export"></i> {{ $t('Export') }}
</button>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue'
import {BootstrapVue} from 'bootstrap-vue'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import LoadingSpinner from "@/components/LoadingSpinner";
import {StandardToasts, makeToast, resolveDjangoUrl} from "@/utils/utils";
import Multiselect from "vue-multiselect";
import {ApiApiFactory} from "@/utils/openapi/api.ts";
import axios from "axios";
Vue.use(BootstrapVue)
export default {
name: 'ExportView',
/*mixins: [
ResolveUrlMixin,
ToastMixin,
],*/
components: {Multiselect},
data() {
return {
export_id: window.EXPORT_ID,
loading: false,
disabled_multiselect: false,
recipe_app: 'DEFAULT',
recipe_list: [],
recipes_loading: false,
recipes: [],
export_all: false,
}
},
mounted() {
if(this.export_id)
this.insertRequested()
else
this.searchRecipes('')
},
methods: {
insertRequested: function(){
let apiFactory = new ApiApiFactory()
this.recipes_loading = true
apiFactory.retrieveRecipe(this.export_id).then((response) => {
this.recipes_loading = false
this.recipe_list.push(response.data)
}).catch((err) => {
console.log(err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH)
}).then(e => this.searchRecipes(''))
},
searchRecipes: function (query) {
let apiFactory = new ApiApiFactory()
this.recipes_loading = true
let maxResultLenght = 1000
apiFactory.listRecipes(query, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, 1, maxResultLenght).then((response) => {
this.recipes = response.data.results;
this.recipes_loading = false
}).catch((err) => {
console.log(err)
StandardToasts.makeStandardToast(StandardToasts.FAIL_FETCH)
})
},
exportRecipe: function () {
if (this.recipe_list.length < 1 && this.export_all == false) {
makeToast(this.$t("Error"), this.$t("Select at least one recipe"), "danger")
return;
}
this.error = undefined
this.loading = true
let formData = new FormData();
formData.append('type', this.recipe_app);
formData.append('all', this.export_all)
for (var i = 0; i < this.recipe_list.length; i++) {
formData.append('recipes', this.recipe_list[i].id);
}
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'])
}).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")
})
},
}
}
</script>
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
<style>
</style>

View File

@ -0,0 +1,18 @@
import Vue from 'vue'
import App from './ExportView.vue'
import i18n from '@/i18n'
Vue.config.productionTip = false
// TODO move this and other default stuff to centralized JS file (verify nothing breaks)
let publicPath = localStorage.STATIC_URL + 'vue/'
if (process.env.NODE_ENV === 'development') {
publicPath = 'http://localhost:8080/'
}
export default __webpack_public_path__ = publicPath // eslint-disable-line
new Vue({
i18n,
render: h => h(App),
}).$mount('#app')

View File

@ -100,7 +100,7 @@
<div class="col-12 order-1 col-sm-12 order-sm-1 col-md-6 order-md-2">
<div class="row">
<div class="col-12">
<img class="img img-fluid rounded" :src="recipe.image" style="max-height: 30vh" :alt="$t('Recipe_Image')" v-if="recipe.image !== null" />
<img class="img img-fluid rounded" :src="recipe.image" style="max-height: 30vh" :alt="$t('Recipe_Image')" v-if="recipe.image !== null" @load="onImgLoad" />
</div>
</div>
@ -241,6 +241,9 @@ export default {
this.start_time = moment().format("yyyy-MM-DDTHH:mm")
}
if(recipe.image === null) this.printReady()
this.recipe = this.rootrecipe = recipe
this.servings = this.servings_cache[this.rootrecipe.id] = recipe.servings
this.loading = false
@ -267,6 +270,14 @@ export default {
this.servings = this.servings_cache?.[e.id] ?? e.servings
}
},
printReady: function(){
const template = document.createElement("template");
template.id = "printReady";
document.body.appendChild(template);
},
onImgLoad: function(){
this.printReady()
},
},
}
</script>

View File

@ -173,6 +173,73 @@ export interface CookLog {
*/
created_at?: string;
}
/**
*
* @export
* @interface ExportLog
*/
export interface ExportLog {
/**
*
* @type {number}
* @memberof ExportLog
*/
id?: number;
/**
*
* @type {string}
* @memberof ExportLog
*/
type: string;
/**
*
* @type {string}
* @memberof ExportLog
*/
msg?: string;
/**
*
* @type {boolean}
* @memberof ExportLog
*/
running?: boolean;
/**
*
* @type {number}
* @memberof ExportLog
*/
total_recipes?: number;
/**
*
* @type {number}
* @memberof ExportLog
*/
exported_recipes?: number;
/**
*
* @type {number}
* @memberof ExportLog
*/
cache_duration?: number;
/**
*
* @type {boolean}
* @memberof ExportLog
*/
possibly_not_expired?: boolean;
/**
*
* @type {string}
* @memberof ExportLog
*/
created_by?: string;
/**
*
* @type {string}
* @memberof ExportLog
*/
created_at?: string;
}
/**
*
* @export
@ -716,6 +783,37 @@ export interface InlineResponse2001 {
*/
results?: Array<Food>;
}
/**
*
* @export
* @interface InlineResponse20010
*/
export interface InlineResponse20010 {
/**
*
* @type {number}
* @memberof InlineResponse20010
*/
count?: number;
/**
*
* @type {string}
* @memberof InlineResponse20010
*/
next?: string | null;
/**
*
* @type {string}
* @memberof InlineResponse20010
*/
previous?: string | null;
/**
*
* @type {Array<ViewLog>}
* @memberof InlineResponse20010
*/
results?: Array<ViewLog>;
}
/**
*
* @export
@ -773,10 +871,10 @@ export interface InlineResponse2003 {
previous?: string | null;
/**
*
* @type {Array<Keyword>}
* @type {Array<ExportLog>}
* @memberof InlineResponse2003
*/
results?: Array<Keyword>;
results?: Array<ExportLog>;
}
/**
*
@ -804,10 +902,10 @@ export interface InlineResponse2004 {
previous?: string | null;
/**
*
* @type {Array<RecipeOverview>}
* @type {Array<Keyword>}
* @memberof InlineResponse2004
*/
results?: Array<RecipeOverview>;
results?: Array<Keyword>;
}
/**
*
@ -835,10 +933,10 @@ export interface InlineResponse2005 {
previous?: string | null;
/**
*
* @type {Array<Step>}
* @type {Array<RecipeOverview>}
* @memberof InlineResponse2005
*/
results?: Array<Step>;
results?: Array<RecipeOverview>;
}
/**
*
@ -866,10 +964,10 @@ export interface InlineResponse2006 {
previous?: string | null;
/**
*
* @type {Array<SupermarketCategoryRelation>}
* @type {Array<Step>}
* @memberof InlineResponse2006
*/
results?: Array<SupermarketCategoryRelation>;
results?: Array<Step>;
}
/**
*
@ -897,10 +995,10 @@ export interface InlineResponse2007 {
previous?: string | null;
/**
*
* @type {Array<SyncLog>}
* @type {Array<SupermarketCategoryRelation>}
* @memberof InlineResponse2007
*/
results?: Array<SyncLog>;
results?: Array<SupermarketCategoryRelation>;
}
/**
*
@ -928,10 +1026,10 @@ export interface InlineResponse2008 {
previous?: string | null;
/**
*
* @type {Array<Unit>}
* @type {Array<SyncLog>}
* @memberof InlineResponse2008
*/
results?: Array<Unit>;
results?: Array<SyncLog>;
}
/**
*
@ -959,10 +1057,10 @@ export interface InlineResponse2009 {
previous?: string | null;
/**
*
* @type {Array<ViewLog>}
* @type {Array<Unit>}
* @memberof InlineResponse2009
*/
results?: Array<ViewLog>;
results?: Array<Unit>;
}
/**
*
@ -3054,6 +3152,7 @@ export interface UserPreference {
* @memberof UserPreference
*/
shopping_add_onhand?: boolean;
/**
*
* @type {boolean}
@ -3243,6 +3342,39 @@ export const ApiApiAxiosParamCreator = function (configuration?: Configuration)
options: localVarRequestOptions,
};
},
/**
*
* @param {ExportLog} [exportLog]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
createExportLog: async (exportLog?: ExportLog, options: any = {}): Promise<RequestArgs> => {
const localVarPath = `/api/export-log/`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
localVarHeaderParameter['Content-Type'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter, options.query);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(exportLog, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @param {Food} [food]
@ -4081,6 +4213,39 @@ export const ApiApiAxiosParamCreator = function (configuration?: Configuration)
setSearchParams(localVarUrlObj, localVarQueryParameter, options.query);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
destroyExportLog: async (id: string, options: any = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('destroyExportLog', 'id', id)
const localVarPath = `/api/export-log/{id}/`
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'DELETE', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
setSearchParams(localVarUrlObj, localVarQueryParameter, options.query);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
@ -4946,6 +5111,45 @@ export const ApiApiAxiosParamCreator = function (configuration?: Configuration)
setSearchParams(localVarUrlObj, localVarQueryParameter, options.query);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @param {number} [page] A page number within the paginated result set.
* @param {number} [pageSize] Number of results to return per page.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listExportLogs: async (page?: number, pageSize?: number, options: any = {}): Promise<RequestArgs> => {
const localVarPath = `/api/export-log/`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
if (page !== undefined) {
localVarQueryParameter['page'] = page;
}
if (pageSize !== undefined) {
localVarQueryParameter['page_size'] = pageSize;
}
setSearchParams(localVarUrlObj, localVarQueryParameter, options.query);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
@ -6206,6 +6410,43 @@ export const ApiApiAxiosParamCreator = function (configuration?: Configuration)
options: localVarRequestOptions,
};
},
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {ExportLog} [exportLog]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
partialUpdateExportLog: async (id: string, exportLog?: ExportLog, options: any = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('partialUpdateExportLog', 'id', id)
const localVarPath = `/api/export-log/{id}/`
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'PATCH', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
localVarHeaderParameter['Content-Type'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter, options.query);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(exportLog, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @param {string} id A unique integer value identifying this food.
@ -7165,6 +7406,39 @@ export const ApiApiAxiosParamCreator = function (configuration?: Configuration)
setSearchParams(localVarUrlObj, localVarQueryParameter, options.query);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
retrieveExportLog: async (id: string, options: any = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('retrieveExportLog', 'id', id)
const localVarPath = `/api/export-log/{id}/`
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
setSearchParams(localVarUrlObj, localVarQueryParameter, options.query);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
@ -8184,6 +8458,43 @@ export const ApiApiAxiosParamCreator = function (configuration?: Configuration)
options: localVarRequestOptions,
};
},
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {ExportLog} [exportLog]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
updateExportLog: async (id: string, exportLog?: ExportLog, options: any = {}): Promise<RequestArgs> => {
// verify required parameter 'id' is not null or undefined
assertParamExists('updateExportLog', 'id', id)
const localVarPath = `/api/export-log/{id}/`
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'PUT', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
localVarHeaderParameter['Content-Type'] = 'application/json';
setSearchParams(localVarUrlObj, localVarQueryParameter, options.query);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(exportLog, localVarRequestOptions, configuration)
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
*
* @param {string} id A unique integer value identifying this food.
@ -9060,6 +9371,16 @@ export const ApiApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.createCookLog(cookLog, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {ExportLog} [exportLog]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async createExportLog(exportLog?: ExportLog, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ExportLog>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.createExportLog(exportLog, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {Food} [food]
@ -9313,6 +9634,16 @@ export const ApiApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.destroyCookLog(id, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async destroyExportLog(id: string, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<void>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.destroyExportLog(id, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {string} id A unique integer value identifying this food.
@ -9573,6 +9904,17 @@ export const ApiApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.listCookLogs(page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {number} [page] A page number within the paginated result set.
* @param {number} [pageSize] Number of results to return per page.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async listExportLogs(page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2003>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listExportLogs(page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {*} [options] Override http request option.
@ -9626,7 +9968,7 @@ export const ApiApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async listKeywords(query?: string, root?: number, tree?: number, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2003>> {
async listKeywords(query?: string, root?: number, tree?: number, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2004>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listKeywords(query, root, tree, page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
@ -9685,7 +10027,7 @@ export const ApiApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async listRecipes(query?: string, keywords?: number, foods?: number, units?: number, rating?: number, books?: string, keywordsOr?: string, foodsOr?: string, booksOr?: string, internal?: string, random?: string, _new?: string, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2004>> {
async listRecipes(query?: string, keywords?: number, foods?: number, units?: number, rating?: number, books?: string, keywordsOr?: string, foodsOr?: string, booksOr?: string, internal?: string, random?: string, _new?: string, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2005>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listRecipes(query, keywords, foods, units, rating, books, keywordsOr, foodsOr, booksOr, internal, random, _new, page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
@ -9728,7 +10070,7 @@ export const ApiApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async listSteps(recipe?: number, query?: string, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2005>> {
async listSteps(recipe?: number, query?: string, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2006>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listSteps(recipe, query, page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
@ -9748,7 +10090,7 @@ export const ApiApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async listSupermarketCategoryRelations(page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2006>> {
async listSupermarketCategoryRelations(page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2007>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listSupermarketCategoryRelations(page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
@ -9777,7 +10119,7 @@ export const ApiApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async listSyncLogs(page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2007>> {
async listSyncLogs(page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2008>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listSyncLogs(page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
@ -9798,7 +10140,7 @@ export const ApiApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async listUnits(query?: string, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2008>> {
async listUnits(query?: string, page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2009>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listUnits(query, page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
@ -9836,7 +10178,7 @@ export const ApiApiFp = function(configuration?: Configuration) {
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async listViewLogs(page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse2009>> {
async listViewLogs(page?: number, pageSize?: number, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<InlineResponse20010>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listViewLogs(page, pageSize, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
@ -9933,6 +10275,17 @@ export const ApiApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.partialUpdateCookLog(id, cookLog, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {ExportLog} [exportLog]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async partialUpdateExportLog(id: string, exportLog?: ExportLog, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ExportLog>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.partialUpdateExportLog(id, exportLog, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {string} id A unique integer value identifying this food.
@ -10218,6 +10571,16 @@ export const ApiApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.retrieveCookLog(id, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async retrieveExportLog(id: string, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ExportLog>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.retrieveExportLog(id, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {string} id A unique integer value identifying this food.
@ -10523,6 +10886,17 @@ export const ApiApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.updateCookLog(id, cookLog, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {ExportLog} [exportLog]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async updateExportLog(id: string, exportLog?: ExportLog, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ExportLog>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.updateExportLog(id, exportLog, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
/**
*
* @param {string} id A unique integer value identifying this food.
@ -10805,6 +11179,15 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
createCookLog(cookLog?: CookLog, options?: any): AxiosPromise<CookLog> {
return localVarFp.createCookLog(cookLog, options).then((request) => request(axios, basePath));
},
/**
*
* @param {ExportLog} [exportLog]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
createExportLog(exportLog?: ExportLog, options?: any): AxiosPromise<ExportLog> {
return localVarFp.createExportLog(exportLog, options).then((request) => request(axios, basePath));
},
/**
*
* @param {Food} [food]
@ -11033,6 +11416,15 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
destroyCookLog(id: string, options?: any): AxiosPromise<void> {
return localVarFp.destroyCookLog(id, options).then((request) => request(axios, basePath));
},
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
destroyExportLog(id: string, options?: any): AxiosPromise<void> {
return localVarFp.destroyExportLog(id, options).then((request) => request(axios, basePath));
},
/**
*
* @param {string} id A unique integer value identifying this food.
@ -11267,6 +11659,16 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
listCookLogs(page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse200> {
return localVarFp.listCookLogs(page, pageSize, options).then((request) => request(axios, basePath));
},
/**
*
* @param {number} [page] A page number within the paginated result set.
* @param {number} [pageSize] Number of results to return per page.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listExportLogs(page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2003> {
return localVarFp.listExportLogs(page, pageSize, options).then((request) => request(axios, basePath));
},
/**
*
* @param {*} [options] Override http request option.
@ -11316,7 +11718,7 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listKeywords(query?: string, root?: number, tree?: number, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2003> {
listKeywords(query?: string, root?: number, tree?: number, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2004> {
return localVarFp.listKeywords(query, root, tree, page, pageSize, options).then((request) => request(axios, basePath));
},
/**
@ -11370,7 +11772,7 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listRecipes(query?: string, keywords?: number, foods?: number, units?: number, rating?: number, books?: string, keywordsOr?: string, foodsOr?: string, booksOr?: string, internal?: string, random?: string, _new?: string, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2004> {
listRecipes(query?: string, keywords?: number, foods?: number, units?: number, rating?: number, books?: string, keywordsOr?: string, foodsOr?: string, booksOr?: string, internal?: string, random?: string, _new?: string, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2005> {
return localVarFp.listRecipes(query, keywords, foods, units, rating, books, keywordsOr, foodsOr, booksOr, internal, random, _new, page, pageSize, options).then((request) => request(axios, basePath));
},
/**
@ -11409,7 +11811,7 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listSteps(recipe?: number, query?: string, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2005> {
listSteps(recipe?: number, query?: string, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2006> {
return localVarFp.listSteps(recipe, query, page, pageSize, options).then((request) => request(axios, basePath));
},
/**
@ -11427,7 +11829,7 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listSupermarketCategoryRelations(page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2006> {
listSupermarketCategoryRelations(page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2007> {
return localVarFp.listSupermarketCategoryRelations(page, pageSize, options).then((request) => request(axios, basePath));
},
/**
@ -11453,7 +11855,7 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listSyncLogs(page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2007> {
listSyncLogs(page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2008> {
return localVarFp.listSyncLogs(page, pageSize, options).then((request) => request(axios, basePath));
},
/**
@ -11472,7 +11874,7 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listUnits(query?: string, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2008> {
listUnits(query?: string, page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2009> {
return localVarFp.listUnits(query, page, pageSize, options).then((request) => request(axios, basePath));
},
/**
@ -11506,7 +11908,7 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
listViewLogs(page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse2009> {
listViewLogs(page?: number, pageSize?: number, options?: any): AxiosPromise<InlineResponse20010> {
return localVarFp.listViewLogs(page, pageSize, options).then((request) => request(axios, basePath));
},
/**
@ -11594,6 +11996,16 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
partialUpdateCookLog(id: string, cookLog?: CookLog, options?: any): AxiosPromise<CookLog> {
return localVarFp.partialUpdateCookLog(id, cookLog, options).then((request) => request(axios, basePath));
},
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {ExportLog} [exportLog]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
partialUpdateExportLog(id: string, exportLog?: ExportLog, options?: any): AxiosPromise<ExportLog> {
return localVarFp.partialUpdateExportLog(id, exportLog, options).then((request) => request(axios, basePath));
},
/**
*
* @param {string} id A unique integer value identifying this food.
@ -11853,6 +12265,15 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
retrieveCookLog(id: string, options?: any): AxiosPromise<CookLog> {
return localVarFp.retrieveCookLog(id, options).then((request) => request(axios, basePath));
},
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
retrieveExportLog(id: string, options?: any): AxiosPromise<ExportLog> {
return localVarFp.retrieveExportLog(id, options).then((request) => request(axios, basePath));
},
/**
*
* @param {string} id A unique integer value identifying this food.
@ -12128,6 +12549,16 @@ export const ApiApiFactory = function (configuration?: Configuration, basePath?:
updateCookLog(id: string, cookLog?: CookLog, options?: any): AxiosPromise<CookLog> {
return localVarFp.updateCookLog(id, cookLog, options).then((request) => request(axios, basePath));
},
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {ExportLog} [exportLog]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
updateExportLog(id: string, exportLog?: ExportLog, options?: any): AxiosPromise<ExportLog> {
return localVarFp.updateExportLog(id, exportLog, options).then((request) => request(axios, basePath));
},
/**
*
* @param {string} id A unique integer value identifying this food.
@ -12394,6 +12825,17 @@ export class ApiApi extends BaseAPI {
return ApiApiFp(this.configuration).createCookLog(cookLog, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {ExportLog} [exportLog]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof ApiApi
*/
public createExportLog(exportLog?: ExportLog, options?: any) {
return ApiApiFp(this.configuration).createExportLog(exportLog, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {Food} [food]
@ -12672,6 +13114,17 @@ export class ApiApi extends BaseAPI {
return ApiApiFp(this.configuration).destroyCookLog(id, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof ApiApi
*/
public destroyExportLog(id: string, options?: any) {
return ApiApiFp(this.configuration).destroyExportLog(id, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {string} id A unique integer value identifying this food.
@ -12958,6 +13411,18 @@ export class ApiApi extends BaseAPI {
return ApiApiFp(this.configuration).listCookLogs(page, pageSize, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {number} [page] A page number within the paginated result set.
* @param {number} [pageSize] Number of results to return per page.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof ApiApi
*/
public listExportLogs(page?: number, pageSize?: number, options?: any) {
return ApiApiFp(this.configuration).listExportLogs(page, pageSize, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {*} [options] Override http request option.
@ -13351,6 +13816,18 @@ export class ApiApi extends BaseAPI {
return ApiApiFp(this.configuration).partialUpdateCookLog(id, cookLog, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {ExportLog} [exportLog]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof ApiApi
*/
public partialUpdateExportLog(id: string, exportLog?: ExportLog, options?: any) {
return ApiApiFp(this.configuration).partialUpdateExportLog(id, exportLog, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {string} id A unique integer value identifying this food.
@ -13662,6 +14139,17 @@ export class ApiApi extends BaseAPI {
return ApiApiFp(this.configuration).retrieveCookLog(id, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof ApiApi
*/
public retrieveExportLog(id: string, options?: any) {
return ApiApiFp(this.configuration).retrieveExportLog(id, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {string} id A unique integer value identifying this food.
@ -13997,6 +14485,18 @@ export class ApiApi extends BaseAPI {
return ApiApiFp(this.configuration).updateCookLog(id, cookLog, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {string} id A unique integer value identifying this export log.
* @param {ExportLog} [exportLog]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof ApiApi
*/
public updateExportLog(id: string, exportLog?: ExportLog, options?: any) {
return ApiApiFp(this.configuration).updateExportLog(id, exportLog, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @param {string} id A unique integer value identifying this food.

View File

@ -17,6 +17,14 @@ const pages = {
entry: "./src/apps/ImportResponseView/main.js",
chunks: ["chunk-vendors"],
},
export_response_view: {
entry: "./src/apps/ExportResponseView/main.js",
chunks: ["chunk-vendors"],
},
export_view: {
entry: "./src/apps/ExportView/main.js",
chunks: ["chunk-vendors"],
},
supermarket_view: {
entry: "./src/apps/SupermarketView/main.js",
chunks: ["chunk-vendors"],