From 51620a34d93a9745d6e356f77eb99fd43c91d283 Mon Sep 17 00:00:00 2001 From: tomtjes Date: Fri, 14 Jan 2022 15:10:22 -0500 Subject: [PATCH 01/26] add swag config example --- docs/install/docker.md | 2 + docs/install/swag.md | 118 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 docs/install/swag.md diff --git a/docs/install/docker.md b/docs/install/docker.md index 8ffb5a22e..484085640 100644 --- a/docs/install/docker.md +++ b/docs/install/docker.md @@ -138,6 +138,8 @@ In both cases, also make sure to mount `/media/` in your swag container to point Please refer to the [appropriate documentation](https://github.com/linuxserver/docker-swag#usage) for the container setup. +For step-by-step instructions to set this up from scratch, see [this example](swag.md). + ### Others If you use none of the above mentioned reverse proxies or want to use an existing one on your host machine (like a local nginx or Caddy), simply use the [PLAIN](https://docs.tandoor.dev/install/docker/#plain) setup above and change the outbound port to one of your liking. diff --git a/docs/install/swag.md b/docs/install/swag.md new file mode 100644 index 000000000..3beeb112b --- /dev/null +++ b/docs/install/swag.md @@ -0,0 +1,118 @@ +!!! danger + Please refer to the [official documentation](https://github.com/linuxserver/docker-swag#usage) for the container setup. This example shows just one setup that may or may not differ from yours in significant ways. This tutorial does not cover security measures, backups, and many other things that you might want to consider. + +## Prerequisites + +- You have a newly spun-up Ubuntu server with docker (pre-)installed. +- At least one `mydomain.com` and one `mysubdomain.mydomain.com` are pointing to the server's IP. (This tutorial does not cover subfolder installation.) +- You have an ssh terminal session open. + +## Installation + +### Download and edit Tandoor configuration + +``` +cd /opt +mkdir recipes +cd recipes +wget https://raw.githubusercontent.com/vabene1111/recipes/develop/.env.template -O .env +base64 /dev/urandom | head -c50 +``` +Copy the response from that last command and paste the key into the `.env` file: +``` +nano .env +``` +You'll also need to enter a Postgres password into the `.env` file. Then, save the file and exit the editor. + +### Install and configure Docker Compose + +In keeping with [these instructions](https://docs.linuxserver.io/general/docker-compose): +``` +cd /opt +curl -L --fail https://raw.githubusercontent.com/linuxserver/docker-docker-compose/master/run.sh -o /usr/local/bin/docker-compose +chmod +x /usr/local/bin/docker-compose +``` + +Next, create and edit the docker compose file. + +``` +nano docker-compose.yml +``` + +Paste the following and adjust your domains, subdomains and time zone. + +``` +--- +version: "2.1" +services: + swag: + image: ghcr.io/linuxserver/swag + container_name: swag + cap_add: + - NET_ADMIN + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/Berlin # <---- EDIT THIS <---- <---- + - URL=mydomain.com # <---- EDIT THIS <---- <---- + - SUBDOMAINS=mysubdomain,myothersubdomain # <---- EDIT THIS <---- <---- + - EXTRA_DOMAINS=myotherdomain.com # <---- EDIT THIS <---- <---- + - VALIDATION=http + volumes: + - ./swag:/config + - ./recipes/media:/media + ports: + - 443:443 + - 80:80 + restart: unless-stopped + + db_recipes: + restart: always + container_name: db_recipes + image: postgres:11-alpine + volumes: + - ./recipes/db:/var/lib/postgresql/data + env_file: + - ./recipes/.env + + recipes: + image: vabene1111/recipes + container_name: recipes + restart: unless-stopped + env_file: + - ./recipes/.env + environment: + - UID=1000 + - GID=1000 + - TZ=Europe/Berlin # <---- EDIT THIS <---- <---- + volumes: + - ./recipes/static:/opt/recipes/staticfiles + - ./recipes/media:/opt/recipes/mediafiles + depends_on: + - db_recipes +``` + +Save and exit. + +### Create containers and configure swag reverse proxy + +``` +docker-compose up -d +``` + +``` +cd /opt/swag/nginx/proxy-confs +cp recipes.subdomain.conf.sample recipes.subdomain.conf +nano recipes.subdomain.conf +``` + +Change the line `server_name recipes.*;` to `server_name mysubdomain.*;`, save and exit. + +### Finalize + +``` +cd /opt +docker restart swag recipes +``` + +Go to `https://mysubdomain.mydomain.com`. (If you get a "502 Bad Gateway" error, be patient. It might take a short while until it's functional.) \ No newline at end of file From 4af6de74254690a3fd7bf8acc748f8d1a0e5963c Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Mon, 17 Jan 2022 16:22:11 +0100 Subject: [PATCH 02/26] Revert "Merge pull request #1280 from MarcusWolschon/feature1275_readable_export_file_names" This reverts commit c4f40b96391f9f8d2ffa7ade6d2d26743c8f1668, reversing changes made to 93b868bc698cb096726f992687a72ece35739348. --- cookbook/integration/default.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cookbook/integration/default.py b/cookbook/integration/default.py index 7adec0508..39c0bc666 100644 --- a/cookbook/integration/default.py +++ b/cookbook/integration/default.py @@ -2,7 +2,6 @@ import json from io import BytesIO, StringIO from re import match from zipfile import ZipFile -from django.utils.text import get_valid_filename from rest_framework.renderers import JSONRenderer @@ -57,8 +56,7 @@ class Default(Integration): pass recipe_zip_obj.close() - - export_zip_obj.writestr(get_valid_filename(r.name) + '.zip', recipe_zip_stream.getvalue()) + export_zip_obj.writestr(str(r.pk) + '.zip', recipe_zip_stream.getvalue()) export_zip_obj.close() return [[ 'export.zip', export_zip_stream.getvalue() ]] \ No newline at end of file From 306f90aa98020c6620bb9e11cd8b12ac31abbc39 Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Mon, 17 Jan 2022 16:27:10 +0100 Subject: [PATCH 03/26] recipe editor decimal fixes --- cookbook/serializer.py | 5 +++++ vue/src/apps/RecipeEditView/RecipeEditView.vue | 2 ++ 2 files changed, 7 insertions(+) diff --git a/cookbook/serializer.py b/cookbook/serializer.py index fb1c3a224..06d09c216 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -496,6 +496,11 @@ class StepRecipeSerializer(WritableNestedModelSerializer): class NutritionInformationSerializer(serializers.ModelSerializer): + carbohydrates = CustomDecimalField() + fats = CustomDecimalField() + proteins = CustomDecimalField() + calories = CustomDecimalField() + def create(self, validated_data): validated_data['space'] = self.context['request'].space diff --git a/vue/src/apps/RecipeEditView/RecipeEditView.vue b/vue/src/apps/RecipeEditView/RecipeEditView.vue index 09ceb6e07..9b8f081d6 100644 --- a/vue/src/apps/RecipeEditView/RecipeEditView.vue +++ b/vue/src/apps/RecipeEditView/RecipeEditView.vue @@ -586,6 +586,8 @@ export default { if (this.recipe.working_time === "" || isNaN(this.recipe.working_time)) { this.recipe.working_time = 0 } + + this.recipe.servings = Math.floor(this.recipe.servings) // temporary fix until a proper framework for frontend input validation is established if (this.recipe.servings === "" || isNaN(this.recipe.servings)) { this.recipe.servings = 0 } From a37672812005fe74914d68ada33175e80e04ea59 Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Mon, 17 Jan 2022 16:29:29 +0100 Subject: [PATCH 04/26] fixed keyword creation in exporter #1213 --- cookbook/integration/integration.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cookbook/integration/integration.py b/cookbook/integration/integration.py index 3b8034e37..6fee602c6 100644 --- a/cookbook/integration/integration.py +++ b/cookbook/integration/integration.py @@ -42,7 +42,7 @@ class Integration: try: last_kw = Keyword.objects.filter(name__regex=r'^(Import [0-9]+)', space=request.space).latest('created_at') name = f'Import {int(last_kw.name.replace("Import ", "")) + 1}' - except ObjectDoesNotExist: + except (ObjectDoesNotExist, ValueError): name = 'Import 1' parent, created = Keyword.objects.get_or_create(name='Import', space=request.space) @@ -53,7 +53,7 @@ class Integration: icon=icon, space=request.space ) - except IntegrityError: # in case, for whatever reason, the name does exist append UUID to it. Not nice but works for now. + except (IntegrityError, ValueError): # in case, for whatever reason, the name does exist append UUID to it. Not nice but works for now. self.keyword = parent.add_child( name=f'{name} {str(uuid.uuid4())[0:8]}', description=description, @@ -86,12 +86,10 @@ class Integration: export_obj.close() export_file = export_stream.getvalue() - response = HttpResponse(export_file, content_type='application/force-download') - response['Content-Disposition'] = 'attachment; filename="'+export_filename+'"' + 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 @@ -262,7 +260,6 @@ class Integration: """ raise NotImplementedError('Method not implemented in integration') - def get_files_from_recipes(self, recipes, cookie): """ Takes a list of recipe object and converts it to a array containing each file. From ddb9e70d31ea5201d56e2b3d066d0f7e4b65495d Mon Sep 17 00:00:00 2001 From: smilerz Date: Mon, 17 Jan 2022 09:46:26 -0600 Subject: [PATCH 05/26] fix url_import --- cookbook/templates/url_import.html | 119 +++++++++++++++-------------- 1 file changed, 60 insertions(+), 59 deletions(-) diff --git a/cookbook/templates/url_import.html b/cookbook/templates/url_import.html index baf4f67df..df03abf03 100644 --- a/cookbook/templates/url_import.html +++ b/cookbook/templates/url_import.html @@ -660,13 +660,14 @@ - + {% endblock %} \ No newline at end of file diff --git a/cookbook/templates/account/signup.html b/cookbook/templates/account/signup.html index 2750af973..baceb2cb1 100644 --- a/cookbook/templates/account/signup.html +++ b/cookbook/templates/account/signup.html @@ -71,4 +71,8 @@ + + {% endblock %} \ No newline at end of file From e0b8d6fcc395fcbfee705c4a431c7544bbeb09d1 Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Mon, 17 Jan 2022 17:00:08 +0100 Subject: [PATCH 07/26] added exception catch to nextcloud importer to handle empty folders in sync --- cookbook/provider/nextcloud.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cookbook/provider/nextcloud.py b/cookbook/provider/nextcloud.py index d67c02446..743ad8214 100644 --- a/cookbook/provider/nextcloud.py +++ b/cookbook/provider/nextcloud.py @@ -29,7 +29,11 @@ class Nextcloud(Provider): client = Nextcloud.get_client(monitor.storage) files = client.list(monitor.path) - files.pop(0) # remove first element because its the folder itself + + try: + files.pop(0) # remove first element because its the folder itself + except IndexError: + pass # folder is emtpy, no recipes will be imported import_count = 0 for file in files: From 85ecac3a17439de3d42262be3d6f8a1b507aaec2 Mon Sep 17 00:00:00 2001 From: smilerz Date: Mon, 17 Jan 2022 10:10:38 -0600 Subject: [PATCH 08/26] Update recipe_search.py --- cookbook/helper/recipe_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/helper/recipe_search.py b/cookbook/helper/recipe_search.py index 673b7d0d4..5c5412de1 100644 --- a/cookbook/helper/recipe_search.py +++ b/cookbook/helper/recipe_search.py @@ -490,7 +490,7 @@ class RecipeFacet(): 'space': self._request.space, } elif self.hash_key is not None: - self._recipe_list = self._cache.get('recipe_list', None) + self._recipe_list = self._cache.get('recipe_list', []) self._search_params = { 'keyword_list': self._cache.get('keyword_list', None), 'food_list': self._cache.get('food_list', None), From 8b1e80efebc3092d7d296b348337f471903aa6cd Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Mon, 17 Jan 2022 17:51:29 +0100 Subject: [PATCH 09/26] wip --- vue/src/components/Buttons/RecipeSwitcher.vue | 40 ++++++++--- vue/src/components/RecipeContextMenu.vue | 70 ++++++++++++++----- vue/src/locales/en.json | 7 +- 3 files changed, 84 insertions(+), 33 deletions(-) diff --git a/vue/src/components/Buttons/RecipeSwitcher.vue b/vue/src/components/Buttons/RecipeSwitcher.vue index be8b0e9e7..922ce208e 100644 --- a/vue/src/components/Buttons/RecipeSwitcher.vue +++ b/vue/src/components/Buttons/RecipeSwitcher.vue @@ -25,7 +25,7 @@ {{ r.name }} + ">{{ r.name }} x
@@ -38,6 +38,16 @@ ">{{ r.name }} + +
TEST
+ +
+ {{ r.name }} + +
@@ -60,7 +70,8 @@ export default { related_recipes: [], planned_recipes: [], pinned_recipes: [], - recipes: {} + recipes: {}, + test : [] } }, computed: { @@ -84,7 +95,7 @@ export default { navRecipe: function (recipe) { if (this.is_recipe_view) { - this.$emit("switch", this.recipes[recipe.id]) + this.$emit("switch", recipe) } else { window.location.href = this.resolveDjangoUrl("view_recipe", recipe.id) } @@ -93,16 +104,23 @@ export default { let apiClient = new ApiApiFactory() let recipe_list = [...this.related_recipes, ...this.planned_recipes, ...this.pinned_recipes] + let recipe_ids = [] recipe_list.forEach((recipe) => { - if (!recipe_ids.includes(recipe.id)) { - recipe_ids.push(recipe.id) + let id = recipe.id + if (id === undefined){ + id = recipe + } + + if (!recipe_ids.includes(id)) { + recipe_ids.push(id) } }) - + console.log(recipe_list, recipe_ids) recipe_ids.forEach((id) => { apiClient.retrieveRecipe(id).then((result) => { this.recipes[id] = result.data + this.test.push(result.data) }) }) @@ -111,12 +129,14 @@ export default { let apiClient = new ApiApiFactory() // get related recipes and save them for later - return apiClient.relatedRecipe(this.recipe, {query: {levels: 2}}).then((result) => { - this.related_recipes = result.data - }) + if (this.recipe){ + return apiClient.relatedRecipe(this.recipe, {query: {levels: 2}}).then((result) => { + this.related_recipes = result.data + }) + } }, loadPinnedRecipes: function () { - let pinned_recipe_ids = localStorage.getItem('pinned_recipes') || [] + let pinned_recipe_ids = JSON.parse(localStorage.getItem('pinned_recipes')) || [] this.pinned_recipes = pinned_recipe_ids }, loadMealPlans: function () { diff --git a/vue/src/components/RecipeContextMenu.vue b/vue/src/components/RecipeContextMenu.vue index 7cd24e5e3..11b75b582 100644 --- a/vue/src/components/RecipeContextMenu.vue +++ b/vue/src/components/RecipeContextMenu.vue @@ -1,38 +1,60 @@ From 5724ef951132379e6326122f3637957cdf2d8fef Mon Sep 17 00:00:00 2001 From: smilerz Date: Mon, 17 Jan 2022 14:02:58 -0600 Subject: [PATCH 19/26] fix boolean directive --- vue/src/components/GenericHorizontalCard.vue | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/vue/src/components/GenericHorizontalCard.vue b/vue/src/components/GenericHorizontalCard.vue index 8f130b474..b12cf6a08 100644 --- a/vue/src/components/GenericHorizontalCard.vue +++ b/vue/src/components/GenericHorizontalCard.vue @@ -8,12 +8,12 @@ :class="{ 'border border-primary': over, shake: isError }" :style="{ 'cursor:grab': useDrag }" :draggable="useDrag" - @[useDrag&&`dragover`].prevent - @[useDrag&&`dragenter`].prevent - @[useDrag&&`dragstart`]="handleDragStart($event)" - @[useDrag&&`dragenter`]="handleDragEnter($event)" - @[useDrag&&`dragleave`]="handleDragLeave($event)" - @[useDrag&&`drop`]="handleDragDrop($event)" + @[useDrag&&`dragover`||``].prevent + @[useDrag&&`dragenter`||``].prevent + @[useDrag&&`dragstart`||``]="handleDragStart($event)" + @[useDrag&&`dragenter`||``]="handleDragEnter($event)" + @[useDrag&&`dragleave`||``]="handleDragLeave($event)" + @[useDrag&&`drop`||``]="handleDragDrop($event)" > @@ -27,6 +27,7 @@
{{ getFullname }}
+ +
{{ item[child_count] }} {{ itemName }}
From c8c29e1b5a7db269c486a9fc9d6ec5cbf29b8e58 Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Mon, 17 Jan 2022 21:14:22 +0100 Subject: [PATCH 20/26] fixed performance issue --- cookbook/helper/recipe_search.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cookbook/helper/recipe_search.py b/cookbook/helper/recipe_search.py index 2e46bd77d..35581b59b 100644 --- a/cookbook/helper/recipe_search.py +++ b/cookbook/helper/recipe_search.py @@ -647,7 +647,7 @@ class RecipeFacet(): depth = getattr(keyword, 'depth', 0) + 1 steplen = depth * Keyword.steplen - return queryset.annotate(count=Coalesce(Subquery(self._recipe_count_queryset('keywords', depth, steplen)), 0) + return queryset.annotate(count=Coalesce(1, 0) ).filter(depth=depth, count__gt=0 ).values('id', 'name', 'count', 'numchild').order_by('name') @@ -655,7 +655,7 @@ class RecipeFacet(): depth = getattr(food, 'depth', 0) + 1 steplen = depth * Food.steplen - return queryset.annotate(count=Coalesce(Subquery(self._recipe_count_queryset('steps__ingredients__food', depth, steplen)), 0) + return queryset.annotate(count=Coalesce(1, 0) ).filter(depth__lte=depth, count__gt=0 ).values('id', 'name', 'count', 'numchild').order_by('name') From b9065f7052188bbbd24930008a7df4cc157ba6ef Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Mon, 17 Jan 2022 22:03:57 +0100 Subject: [PATCH 21/26] added space deletion feature --- cookbook/admin.py | 49 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/cookbook/admin.py b/cookbook/admin.py index 73e86ecf5..a252185f5 100644 --- a/cookbook/admin.py +++ b/cookbook/admin.py @@ -15,7 +15,7 @@ from .models import (BookmarkletImport, Comment, CookLog, Food, FoodInheritField Recipe, RecipeBook, RecipeBookEntry, RecipeImport, SearchPreference, ShareLink, ShoppingList, ShoppingListEntry, ShoppingListRecipe, Space, Step, Storage, Supermarket, SupermarketCategory, SupermarketCategoryRelation, Sync, SyncLog, - TelegramBot, Unit, UserFile, UserPreference, ViewLog) + TelegramBot, Unit, UserFile, UserPreference, ViewLog, Automation) class CustomUserAdmin(UserAdmin): @@ -29,11 +29,52 @@ admin.site.register(User, CustomUserAdmin) admin.site.unregister(Group) +@admin.action(description='Delete all data from a space') +def delete_space_action(modeladmin, request, queryset): + for space in queryset: + CookLog.objects.filter(space=space).delete() + ViewLog.objects.filter(space=space).delete() + ImportLog.objects.filter(space=space).delete() + BookmarkletImport.objects.filter(space=space).delete() + + Comment.objects.filter(recipe__space=space).delete() + Keyword.objects.filter(space=space).delete() + Food.objects.filter(space=space).delete() + Unit.objects.filter(space=space).delete() + Ingredient.objects.filter(space=space).delete() + Step.objects.filter(space=space).delete() + NutritionInformation.objects.filter(space=space).delete() + RecipeBookEntry.objects.filter(book__space=space).delete() + RecipeBook.objects.filter(space=space).delete() + MealType.objects.filter(space=space).delete() + MealPlan.objects.filter(space=space).delete() + ShareLink.objects.filter(space=space).delete() + Recipe.objects.filter(space=space).delete() + + RecipeImport.objects.filter(space=space).delete() + SyncLog.objects.filter(sync__space=space).delete() + Sync.objects.filter(space=space).delete() + Storage.objects.filter(space=space).delete() + + ShoppingListEntry.objects.filter(shoppinglist__space=space).delete() + ShoppingListRecipe.objects.filter(shoppinglist__space=space).delete() + ShoppingList.objects.filter(space=space).delete() + + SupermarketCategoryRelation.objects.filter(supermarket__space=space).delete() + SupermarketCategory.objects.filter(space=space).delete() + Supermarket.objects.filter(space=space).delete() + + InviteLink.objects.filter(space=space).delete() + UserFile.objects.filter(space=space).delete() + Automation.objects.filter(space=space).delete() + + class SpaceAdmin(admin.ModelAdmin): list_display = ('name', 'created_by', 'max_recipes', 'max_users', 'max_file_storage_mb', 'allow_sharing') search_fields = ('name', 'created_by__username') list_filter = ('max_recipes', 'max_users', 'max_file_storage_mb', 'allow_sharing') date_hierarchy = 'created_at' + actions = [delete_space_action] admin.site.register(Space, SpaceAdmin) @@ -128,7 +169,7 @@ def sort_tree(modeladmin, request, queryset): class KeywordAdmin(TreeAdmin): form = movenodeform_factory(Keyword) ordering = ('space', 'path',) - search_fields = ('name', ) + search_fields = ('name',) actions = [sort_tree, enable_tree_sorting, disable_tree_sorting] @@ -171,13 +212,15 @@ class RecipeAdmin(admin.ModelAdmin): admin.site.register(Recipe, RecipeAdmin) admin.site.register(Unit) + + # admin.site.register(FoodInheritField) class FoodAdmin(TreeAdmin): form = movenodeform_factory(Keyword) ordering = ('space', 'path',) - search_fields = ('name', ) + search_fields = ('name',) actions = [sort_tree, enable_tree_sorting, disable_tree_sorting] From d04e9518cbb77c5fcc1d7d9bd225ea82f4e5001c Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Mon, 17 Jan 2022 22:13:36 +0100 Subject: [PATCH 22/26] fixed telegram shopping bot --- cookbook/views/telegram.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/cookbook/views/telegram.py b/cookbook/views/telegram.py index 9c73ba7bd..d816bc92b 100644 --- a/cookbook/views/telegram.py +++ b/cookbook/views/telegram.py @@ -45,21 +45,17 @@ def hook(request, token): tb.save() if tb.chat_id == str(data['message']['chat']['id']): - sl = ShoppingList.objects.filter(Q(created_by=tb.created_by)).filter(finished=False, space=tb.space).order_by('-created_at').first() - if not sl: - sl = ShoppingList.objects.create(created_by=tb.created_by, space=tb.space) - request.space = tb.space # TODO this is likely a bad idea. Verify and test request.user = tb.created_by ingredient_parser = IngredientParser(request, False) amount, unit, ingredient, note = ingredient_parser.parse(data['message']['text']) f = ingredient_parser.get_food(ingredient) u = ingredient_parser.get_unit(unit) - sl.entries.add( - ShoppingListEntry.objects.create( - food=f, unit=u, amount=amount - ) + + ShoppingListEntry.objects.create( + food=f, unit=u, amount=amount, created_by=request.user ) + return JsonResponse({'data': data['message']['text']}) except Exception: pass From c27933548d23372653a92a69df463bd405a1686f Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Mon, 17 Jan 2022 22:28:02 +0100 Subject: [PATCH 23/26] fixed order of delete --- cookbook/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/admin.py b/cookbook/admin.py index a252185f5..625b2a6bc 100644 --- a/cookbook/admin.py +++ b/cookbook/admin.py @@ -39,9 +39,9 @@ def delete_space_action(modeladmin, request, queryset): Comment.objects.filter(recipe__space=space).delete() Keyword.objects.filter(space=space).delete() + Ingredient.objects.filter(space=space).delete() Food.objects.filter(space=space).delete() Unit.objects.filter(space=space).delete() - Ingredient.objects.filter(space=space).delete() Step.objects.filter(space=space).delete() NutritionInformation.objects.filter(space=space).delete() RecipeBookEntry.objects.filter(book__space=space).delete() From 54721a0a62315bc656fe89011e74376ff6da7611 Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Mon, 17 Jan 2022 22:37:14 +0100 Subject: [PATCH 24/26] also added space to bot --- cookbook/views/telegram.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cookbook/views/telegram.py b/cookbook/views/telegram.py index d816bc92b..6c98bdf08 100644 --- a/cookbook/views/telegram.py +++ b/cookbook/views/telegram.py @@ -52,9 +52,7 @@ def hook(request, token): f = ingredient_parser.get_food(ingredient) u = ingredient_parser.get_unit(unit) - ShoppingListEntry.objects.create( - food=f, unit=u, amount=amount, created_by=request.user - ) + ShoppingListEntry.objects.create(food=f, unit=u, amount=amount, created_by=request.user, space=request.space) return JsonResponse({'data': data['message']['text']}) except Exception: From 532d32c194d9fa3ef4b39c79d95379e48a40fe8c Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Mon, 17 Jan 2022 22:41:38 +0100 Subject: [PATCH 25/26] fixed shopping user save setting would not work --- cookbook/serializer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cookbook/serializer.py b/cookbook/serializer.py index ce8d48de9..3584138c2 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -165,9 +165,10 @@ class FoodInheritFieldSerializer(WritableNestedModelSerializer): read_only_fields = ['id'] -class UserPreferenceSerializer(serializers.ModelSerializer): +class UserPreferenceSerializer(WritableNestedModelSerializer): food_inherit_default = FoodInheritFieldSerializer(source='space.food_inherit', many=True, allow_null=True, required=False, read_only=True) plan_share = UserNameSerializer(many=True, allow_null=True, required=False, read_only=True) + shopping_share = UserNameSerializer(many=True, allow_null=True, required=False) def create(self, validated_data): if not validated_data.get('user', None): From d8d76ae9e0863cf11842871cf5c35759fc2ba7fb Mon Sep 17 00:00:00 2001 From: smilerz Date: Mon, 17 Jan 2022 16:12:54 -0600 Subject: [PATCH 26/26] fix missing label supermarket category --- vue/src/components/Modals/LookupInput.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vue/src/components/Modals/LookupInput.vue b/vue/src/components/Modals/LookupInput.vue index 24dde7540..5d6dd7c78 100644 --- a/vue/src/components/Modals/LookupInput.vue +++ b/vue/src/components/Modals/LookupInput.vue @@ -82,7 +82,7 @@ export default { } else { arrayValues = [{ id: -1, name: this_value }] } - if (this.form?.ordered && this.first_run && arrayValues.length > 0) { + if (this.form?.ordered && this.first_run) { return this.flattenItems(arrayValues) } else { return arrayValues