diff --git a/cookbook/filters.py b/cookbook/filters.py
index 30d42cf7e..ac377abcb 100644
--- a/cookbook/filters.py
+++ b/cookbook/filters.py
@@ -6,7 +6,7 @@ from django.utils.translation import gettext as _
from django_scopes import scopes_disabled
from cookbook.forms import MultiSelectWidget
-from cookbook.models import Food, Keyword, Recipe, ShoppingList
+from cookbook.models import Food, Keyword, Recipe
with scopes_disabled():
class RecipeFilter(django_filters.FilterSet):
@@ -60,22 +60,3 @@ with scopes_disabled():
class Meta:
model = Recipe
fields = ['name', 'keywords', 'foods', 'internal']
-
- # class FoodFilter(django_filters.FilterSet):
- # name = django_filters.CharFilter(lookup_expr='icontains')
-
- # class Meta:
- # model = Food
- # fields = ['name']
-
- class ShoppingListFilter(django_filters.FilterSet):
-
- def __init__(self, data=None, *args, **kwargs):
- if data is not None:
- data = data.copy()
- data.setdefault("finished", False)
- super().__init__(data, *args, **kwargs)
-
- class Meta:
- model = ShoppingList
- fields = ['finished']
diff --git a/cookbook/helper/ingredient_parser.py b/cookbook/helper/ingredient_parser.py
index ee4b8d916..8c07635af 100644
--- a/cookbook/helper/ingredient_parser.py
+++ b/cookbook/helper/ingredient_parser.py
@@ -4,7 +4,7 @@ import unicodedata
from django.core.cache import caches
-from cookbook.models import Unit, Food, Automation
+from cookbook.models import Unit, Food, Automation, Ingredient
class IngredientParser:
@@ -46,7 +46,7 @@ class IngredientParser:
def apply_food_automation(self, food):
"""
- Apply food alias automations to passed foood
+ Apply food alias automations to passed food
:param food: unit as string
:return: food as string (possibly changed by automation)
"""
@@ -155,33 +155,36 @@ class IngredientParser:
except ValueError:
unit = x[end:]
+ if unit is not None and unit.strip() == '':
+ unit = None
+
if unit is not None and (unit.startswith('(') or unit.startswith('-')): # i dont know any unit that starts with ( or - so its likely an alternative like 1L (500ml) Water or 2-3
- unit = ''
+ unit = None
note = x
return amount, unit, note
- def parse_ingredient_with_comma(self, tokens):
- ingredient = ''
+ def parse_food_with_comma(self, tokens):
+ food = ''
note = ''
start = 0
# search for first occurrence of an argument ending in a comma
while start < len(tokens) and not tokens[start].endswith(','):
start += 1
if start == len(tokens):
- # no token ending in a comma found -> use everything as ingredient
- ingredient = ' '.join(tokens)
+ # no token ending in a comma found -> use everything as food
+ food = ' '.join(tokens)
else:
- ingredient = ' '.join(tokens[:start + 1])[:-1]
+ food = ' '.join(tokens[:start + 1])[:-1]
note = ' '.join(tokens[start + 1:])
- return ingredient, note
+ return food, note
- def parse_ingredient(self, tokens):
- ingredient = ''
+ def parse_food(self, tokens):
+ food = ''
note = ''
if tokens[-1].endswith(')'):
# Check if the matching opening bracket is in the same token
if (not tokens[-1].startswith('(')) and ('(' in tokens[-1]):
- return self.parse_ingredient_with_comma(tokens)
+ return self.parse_food_with_comma(tokens)
# last argument ends with closing bracket -> look for opening bracket
start = len(tokens) - 1
while not tokens[start].startswith('(') and not start == 0:
@@ -191,36 +194,48 @@ class IngredientParser:
raise ValueError
elif start < 0:
# no opening bracket anywhere -> just ignore the last bracket
- ingredient, note = self.parse_ingredient_with_comma(tokens)
+ food, note = self.parse_food_with_comma(tokens)
else:
- # opening bracket found -> split in ingredient and note, remove brackets from note # noqa: E501
+ # opening bracket found -> split in food and note, remove brackets from note # noqa: E501
note = ' '.join(tokens[start:])[1:-1]
- ingredient = ' '.join(tokens[:start])
+ food = ' '.join(tokens[:start])
else:
- ingredient, note = self.parse_ingredient_with_comma(tokens)
- return ingredient, note
+ food, note = self.parse_food_with_comma(tokens)
+ return food, note
- def parse(self, x):
+ def parse(self, ingredient):
+ """
+ Main parsing function, takes an ingredient string (e.g. '1 l Water') and extracts amount, unit, food, ...
+ :param ingredient: string ingredient
+ :return: amount, unit (can be None), food, note (can be empty)
+ """
# initialize default values
amount = 0
unit = None
- ingredient = ''
+ food = ''
note = ''
unit_note = ''
- if len(x) == 0:
+ if len(ingredient) == 0:
raise ValueError('string to parse cannot be empty')
+ # some people/languages put amount and unit at the end of the ingredient string
+ # if something like this is detected move it to the beginning so the parser can handle it
+ if re.search(r'^([A-z])+(.)*[1-9](\d)*\s([A-z])+', ingredient):
+ match = re.search(r'[1-9](\d)*\s([A-z])+', ingredient)
+ print(f'reording from {ingredient} to {ingredient[match.start():match.end()] + " " + ingredient.replace(ingredient[match.start():match.end()], "")}')
+ ingredient = ingredient[match.start():match.end()] + ' ' + ingredient.replace(ingredient[match.start():match.end()], '')
+
# if the string contains parenthesis early on remove it and place it at the end
# because its likely some kind of note
- if re.match('(.){1,6}\s\((.[^\(\)])+\)\s', x):
- match = re.search('\((.[^\(])+\)', x)
- x = x[:match.start()] + x[match.end():] + ' ' + x[match.start():match.end()]
+ if re.match('(.){1,6}\s\((.[^\(\)])+\)\s', ingredient):
+ match = re.search('\((.[^\(])+\)', ingredient)
+ ingredient = ingredient[:match.start()] + ingredient[match.end():] + ' ' + ingredient[match.start():match.end()]
- tokens = x.split()
+ tokens = ingredient.split() # split at each space into tokens
if len(tokens) == 1:
- # there only is one argument, that must be the ingredient
- ingredient = tokens[0]
+ # there only is one argument, that must be the food
+ food = tokens[0]
else:
try:
# try to parse first argument as amount
@@ -232,51 +247,60 @@ class IngredientParser:
try:
if unit is not None:
# a unit is already found, no need to try the second argument for a fraction
- # probably not the best method to do it, but I didn't want to make an if check and paste the exact same thing in the else as already is in the except # noqa: E501
+ # probably not the best method to do it, but I didn't want to make an if check and paste the exact same thing in the else as already is in the except
raise ValueError
# try to parse second argument as amount and add that, in case of '2 1/2' or '2 ½'
amount += self.parse_fraction(tokens[1])
# assume that units can't end with a comma
if len(tokens) > 3 and not tokens[2].endswith(','):
- # try to use third argument as unit and everything else as ingredient, use everything as ingredient if it fails # noqa: E501
+ # try to use third argument as unit and everything else as food, use everything as food if it fails
try:
- ingredient, note = self.parse_ingredient(tokens[3:])
+ food, note = self.parse_food(tokens[3:])
unit = tokens[2]
except ValueError:
- ingredient, note = self.parse_ingredient(tokens[2:])
+ food, note = self.parse_food(tokens[2:])
else:
- ingredient, note = self.parse_ingredient(tokens[2:])
+ food, note = self.parse_food(tokens[2:])
except ValueError:
# assume that units can't end with a comma
if not tokens[1].endswith(','):
- # try to use second argument as unit and everything else as ingredient, use everything as ingredient if it fails # noqa: E501
+ # try to use second argument as unit and everything else as food, use everything as food if it fails
try:
- ingredient, note = self.parse_ingredient(tokens[2:])
+ food, note = self.parse_food(tokens[2:])
if unit is None:
unit = tokens[1]
else:
note = tokens[1]
except ValueError:
- ingredient, note = self.parse_ingredient(tokens[1:])
+ food, note = self.parse_food(tokens[1:])
else:
- ingredient, note = self.parse_ingredient(tokens[1:])
+ food, note = self.parse_food(tokens[1:])
else:
# only two arguments, first one is the amount
- # which means this is the ingredient
- ingredient = tokens[1]
+ # which means this is the food
+ food = tokens[1]
except ValueError:
try:
# can't parse first argument as amount
- # -> no unit -> parse everything as ingredient
- ingredient, note = self.parse_ingredient(tokens)
+ # -> no unit -> parse everything as food
+ food, note = self.parse_food(tokens)
except ValueError:
- ingredient = ' '.join(tokens[1:])
+ food = ' '.join(tokens[1:])
if unit_note not in note:
note += ' ' + unit_note
- try:
- unit = self.apply_unit_automation(unit.strip())
- except Exception:
- pass
- return amount, unit, self.apply_food_automation(ingredient.strip()), note.strip()
+ if unit:
+ unit = self.apply_unit_automation(unit.strip())
+
+ food = self.apply_food_automation(food.strip())
+ if len(food) > Food._meta.get_field('name').max_length: # test if food name is to long
+ # try splitting it at a space and taking only the first arg
+ if len(food.split()) > 1 and len(food.split()[0]) < Food._meta.get_field('name').max_length:
+ note = ' '.join(food.split()[1:]) + ' ' + note
+ food = food.split()[0]
+ else:
+ note = food + ' ' + note
+ food = food[:Food._meta.get_field('name').max_length]
+
+ return amount, unit, food, note[:Ingredient._meta.get_field('note').max_length].strip()
diff --git a/cookbook/tables.py b/cookbook/tables.py
index 1829c6f58..2831c39dc 100644
--- a/cookbook/tables.py
+++ b/cookbook/tables.py
@@ -3,8 +3,8 @@ from django.utils.html import format_html
from django.utils.translation import gettext as _
from django_tables2.utils import A
-from .models import (CookLog, InviteLink, Keyword, Recipe, RecipeImport,
- ShoppingList, Storage, Sync, SyncLog, ViewLog)
+from .models import (CookLog, InviteLink, Recipe, RecipeImport,
+ Storage, Sync, SyncLog, ViewLog)
class ImageUrlColumn(tables.Column):
@@ -121,14 +121,6 @@ class RecipeImportTable(tables.Table):
fields = ('id', 'name', 'file_path')
-class ShoppingListTable(tables.Table):
- id = tables.LinkColumn('view_shopping', args=[A('id')])
-
- class Meta:
- model = ShoppingList
- template_name = 'generic/table_template.html'
- fields = ('id', 'finished', 'created_by', 'created_at')
-
class InviteLinkTable(tables.Table):
link = tables.TemplateColumn(
diff --git a/cookbook/templates/generic/list_template.html b/cookbook/templates/generic/list_template.html
index 7d4be443d..84605ce37 100644
--- a/cookbook/templates/generic/list_template.html
+++ b/cookbook/templates/generic/list_template.html
@@ -26,15 +26,6 @@
{% endif %}
- {% if request.resolver_match.url_name in 'list_shopping_list' %}
-
-
-
-
-
- {% endif %}
{% if filter %}
diff --git a/cookbook/templates/meal_plan_new.html b/cookbook/templates/meal_plan_new.html
deleted file mode 100644
index f835d72a9..000000000
--- a/cookbook/templates/meal_plan_new.html
+++ /dev/null
@@ -1,36 +0,0 @@
-{% extends "base.html" %}
-{% load render_bundle from webpack_loader %}
-{% load static %}
-{% load i18n %}
-{% load l10n %}
-
-{% block title %}{% trans 'Meal-Plan' %}{% endblock %}
-
-{% block content_fluid %}
-
-