diff --git a/cookbook/forms.py b/cookbook/forms.py index 60237ac7e..0ac423a42 100644 --- a/cookbook/forms.py +++ b/cookbook/forms.py @@ -179,6 +179,7 @@ class ImportForm(ImportExportBase): class ExportForm(ImportExportBase): recipes = forms.ModelMultipleChoiceField(widget=MultiSelectWidget, queryset=Recipe.objects.none(), required=False) all = forms.BooleanField(required=False) + filter = forms.IntegerField(required=False) def __init__(self, *args, **kwargs): space = kwargs.pop('space') diff --git a/cookbook/helper/recipe_search.py b/cookbook/helper/recipe_search.py index 1f82a2994..49845b75d 100644 --- a/cookbook/helper/recipe_search.py +++ b/cookbook/helper/recipe_search.py @@ -40,7 +40,7 @@ class RecipeSearch(): self._search_prefs = request.user.searchpreference else: self._search_prefs = SearchPreference() - self._string = params.get('query').strip() if params.get('query', None) else None + self._string = self._params.get('query').strip() if self._params.get('query', None) else None self._rating = self._params.get('rating', None) self._keywords = { 'or': self._params.get('keywords_or', None) or self._params.get('keywords', None), diff --git a/cookbook/serializer.py b/cookbook/serializer.py index b1b72d3e2..11967d435 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -421,9 +421,11 @@ class FoodSerializer(UniqueFieldsMixin, WritableNestedModelSerializer, ExtendedR space = validated_data.pop('space', self.context['request'].space) # supermarket category needs to be handled manually as food.get or create does not create nested serializers unlike a super.create of serializer if 'supermarket_category' in validated_data and validated_data['supermarket_category']: + sm_category = validated_data['supermarket_category'] + sc_name = sm_category.pop('name', None) validated_data['supermarket_category'], sc_created = SupermarketCategory.objects.get_or_create( - name__iexact=validated_data.pop('supermarket_category')['name'], - space=self.context['request'].space) + name=name, + space=space, defaults=sm_category) onhand = validated_data.pop('food_onhand', None) # assuming if on hand for user also onhand for shopping_share users @@ -678,7 +680,7 @@ class RecipeBookEntrySerializer(serializers.ModelSerializer): def create(self, validated_data): book = validated_data['book'] recipe = validated_data['recipe'] - if not book.get_owner() == self.context['request'].user and not self.context['request'].user in book.get_shared(): + if not book.get_owner() == self.context['request'].user and not self.context['request'].user in book.get_shared(): raise NotFound(detail=None, code=None) obj, created = RecipeBookEntry.objects.get_or_create(book=book, recipe=recipe) return obj @@ -733,11 +735,11 @@ class ShoppingListRecipeSerializer(serializers.ModelSerializer): value = Decimal(value) value = value.quantize(Decimal(1)) if value == value.to_integral() else value.normalize() # strips trailing zero return ( - obj.name - or getattr(obj.mealplan, 'title', None) - or (d := getattr(obj.mealplan, 'date', None)) and ': '.join([obj.mealplan.recipe.name, str(d)]) - or obj.recipe.name - ) + f' ({value:.2g})' + obj.name + or getattr(obj.mealplan, 'title', None) + or (d := getattr(obj.mealplan, 'date', None)) and ': '.join([obj.mealplan.recipe.name, str(d)]) + or obj.recipe.name + ) + f' ({value:.2g})' def update(self, instance, validated_data): # TODO remove once old shopping list diff --git a/cookbook/views/import_export.py b/cookbook/views/import_export.py index f4aea7c0f..19e1a53bf 100644 --- a/cookbook/views/import_export.py +++ b/cookbook/views/import_export.py @@ -11,6 +11,7 @@ from django.utils.translation import gettext as _ from cookbook.forms import ExportForm, ImportExportBase, ImportForm from cookbook.helper.permission_helper import group_required +from cookbook.helper.recipe_search import RecipeSearch from cookbook.integration.cheftap import ChefTap from cookbook.integration.chowdown import Chowdown from cookbook.integration.cookbookapp import CookBookApp @@ -123,6 +124,9 @@ def export_recipe(request): recipes = form.cleaned_data['recipes'] if form.cleaned_data['all']: recipes = Recipe.objects.filter(space=request.space, internal=True).all() + elif filter := form.cleaned_data['filter']: + search = RecipeSearch(request, filter=filter) + recipes = search.get_queryset(Recipe.objects.filter(space=request.space, internal=True)) integration = get_integration(request, form.cleaned_data['type']) diff --git a/vue/src/apps/ExportResponseView/ExportResponseView.vue b/vue/src/apps/ExportResponseView/ExportResponseView.vue index 913f4366d..46ff42cc1 100644 --- a/vue/src/apps/ExportResponseView/ExportResponseView.vue +++ b/vue/src/apps/ExportResponseView/ExportResponseView.vue @@ -1,145 +1,126 @@ - - + + - + + + {{ $t("Exporting") }}... - - {{ $t('Exporting') }}... + + + - - - + + - - + + + {{ $t("Export_finished") }}! {{ $t("Return to export") }} - - - {{ $t('Export_finished') }}! {{ $t('Return to export') }} + {{ $t("If download did not start automatically: ") }} - {{ $t('If download did not start automatically: ') }} - - - {{ $t('Download') }} ({{ $t('Expired') }}) - - {{ $t('Download') }} + + {{ $t("Download") }} + ({{ $t("Expired") }}) + + {{ $t("Download") }} - - {{ $t('The link will remain active for') }} - - - {{ export_info.cache_duration/3600 }}{{ $t('hr') }} - - - {{ export_info.cache_duration/60 }}{{ $t('min') }} - - - {{ export_info.cache_duration }}{{ $t('sec') }} - + + {{ $t("The link will remain active for") }} + {{ export_info.cache_duration / 3600 }}{{ $t("hr") }} + {{ export_info.cache_duration / 60 }}{{ $t("min") }} + {{ export_info.cache_duration }}{{ $t("sec") }} - - - - - - - - - - {{ $t('Information') }} - - - - - - - - + + + + + + + {{ $t("Information") }} + + + + + + + - + diff --git a/vue/src/apps/ExportView/ExportView.vue b/vue/src/apps/ExportView/ExportView.vue index ca55b7206..5a472ef94 100644 --- a/vue/src/apps/ExportView/ExportView.vue +++ b/vue/src/apps/ExportView/ExportView.vue @@ -1,174 +1,174 @@ - + + {{ $t("Export") }} + + + + + + Default + Saffron + Recipe Sage + PDF (experimental) + - {{ $t('Export') }} - - + + + {{ $t("All recipes") }} + - - - - Default - Saffron - Recipe Sage - PDF (experimental) - + + + - - - {{ $t('All recipes') }} - - - - - - - {{ $t('Export') }} - + + {{ $t("Export") }} + - - - - - + diff --git a/vue/src/apps/RecipeSearchView/RecipeSearchView.vue b/vue/src/apps/RecipeSearchView/RecipeSearchView.vue index 4e7d35901..467569152 100644 --- a/vue/src/apps/RecipeSearchView/RecipeSearchView.vue +++ b/vue/src/apps/RecipeSearchView/RecipeSearchView.vue @@ -1,6 +1,6 @@ - + @@ -8,21 +8,15 @@ - + - + - + - + @@ -32,18 +26,15 @@ - + - {{ $t("New_Recipe") }} + {{ $t("New_Recipe") }} - {{ $t("Import") }} + {{ $t("Import") }} - + - - + + - - + + - - + + - - + + - - + + - {{ - $t("Search Settings") - }} + {{ $t("Search Settings") }} - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - {{ $t("Close") }} - + {{ $t("Close") }} @@ -281,23 +185,18 @@ {{ $t("Keywords") }} - {{ - $t("warning_duplicate_filter") - }} + {{ + $t("warning_duplicate_filter") + }} - - + + - - + + - {{ - $t("or") - }} + {{ $t("or") }} {{ $t("and") }} - + {{ $t("not") }} @@ -360,23 +253,18 @@ {{ $t("Foods") }} - {{ - $t("warning_duplicate_filter") - }} + {{ + $t("warning_duplicate_filter") + }} - - + + - - + + - - {{ - $t("or") - }} + + {{ $t("or") }} {{ $t("and") }} - + {{ $t("not") }} @@ -435,23 +314,18 @@ {{ $t("Books") }} - {{ - $t("warning_duplicate_filter") - }} + {{ + $t("warning_duplicate_filter") + }} - - + + - - + + - - {{ - $t("or") - }} + + {{ $t("or") }} {{ $t("and") }} - + {{ $t("not") }} @@ -506,12 +371,8 @@ /> - - >= + + >= <= @@ -534,13 +395,8 @@ > - - {{ - $t("or") - }} + + {{ $t("or") }} {{ $t("and") }} @@ -550,23 +406,17 @@ - + {{ $t("times_cooked") }} - + - + >= <= @@ -585,10 +435,7 @@ @input="refreshData(false)" /> - + >= <= @@ -608,10 +455,7 @@ @input="refreshData(false)" /> - + >= <= @@ -629,10 +473,7 @@ @input="refreshData(false)" /> - + >= <= @@ -650,10 +491,7 @@ @input="refreshData(false)" /> - + >= <= @@ -662,9 +500,7 @@ {{ $t("make_now") }} - + @@ -674,16 +510,14 @@ - + {{ $t("explain") }} {{ $t("explain") }} - + {{ $t("expert_mode") }} @@ -706,21 +540,20 @@ Show all recipes that are matched - by {{ search.search_input }} + by {{ search.search_input }} - without any search term + without any search term - and are internal + and are internal and don't contain - anyall of the following keywords: + anyall of the following keywords: {{ k.items.flatMap((x) => x.name).join(", ") }} - + @@ -729,11 +562,9 @@ and don't contain - anyall of the following foods: + anyall of the following foods: {{ k.items.flatMap((x) => x.name).join(", ") }} - + @@ -742,48 +573,40 @@ and don't contain - anyall of the following books: + anyall of the following books: {{ k.items.flatMap((x) => x.name).join(", ") }} - + - and you can make right now (based on the on hand flag) + and you can make right now (based on the on hand flag) - and contain anyall of the following units: + and contain anyall of the following units: {{ search.search_units.flatMap((x) => x.name).join(", ") }} + > - and have a rating greater than less than or - equal to {{ search.search_rating }} + and have a rating greater than less than or + equal to {{ search.search_rating }} - and have been last cooked after before + and have been last cooked after before {{ search.lastcooked }} + > - and have been cooked at least less than or - equal to{{ search.timescooked }} times + and have been cooked at least less than or + equal to{{ search.timescooked }} times order by {{ search.sort_order.flatMap((x) => x.text).join(", ") }} - + @@ -797,14 +620,13 @@ - + {{ o.text }} @@ -812,35 +634,34 @@ - - {{ $t("Page") }} {{ search.pagination_page }}/{{ - Math.ceil(pagination_count / ui.page_size) - }} - {{ $t("Reset") }} - + + {{ $t("Page") }} {{ search.pagination_page }}/{{ Math.ceil(pagination_count / ui.page_size) }} + {{ $t("Reset") }} + - + - + - + - + @@ -848,9 +669,8 @@ - {{ $t('search_no_recipes') }} + {{ $t("search_no_recipes") }} - @@ -858,47 +678,41 @@ - {{ $t('search_import_help_text') }} + {{ $t("search_import_help_text") }} - {{ $t('Import') }} - + {{ $t("Import") }} - {{ $t('search_create_help_text') }} + {{ $t("search_create_help_text") }} - {{ $t('Create') }} - + {{ $t("Create") }} - -