mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-01 04:10:06 -05:00
add new unit/food from shopping list
This commit is contained in:
@@ -227,6 +227,7 @@ class StorageForm(forms.ModelForm):
|
||||
}
|
||||
|
||||
|
||||
# TODO: Deprecate
|
||||
class RecipeBookEntryForm(forms.ModelForm):
|
||||
prefix = 'bookmark'
|
||||
|
||||
@@ -479,7 +480,7 @@ class ShoppingPreferenceForm(forms.ModelForm):
|
||||
|
||||
fields = (
|
||||
'shopping_share', 'shopping_auto_sync', 'mealplan_autoadd_shopping', 'mealplan_autoexclude_onhand',
|
||||
'mealplan_autoinclude_related', 'default_delay', 'filter_to_supermarket'
|
||||
'mealplan_autoinclude_related', 'default_delay', 'filter_to_supermarket', 'shopping_recent_days'
|
||||
)
|
||||
|
||||
help_texts = {
|
||||
@@ -493,6 +494,7 @@ class ShoppingPreferenceForm(forms.ModelForm):
|
||||
'mealplan_autoexclude_onhand': _('When adding a meal plan to the shopping list (manually or automatically), exclude ingredients that are on hand.'),
|
||||
'default_delay': _('Default number of hours to delay a shopping list entry.'),
|
||||
'filter_to_supermarket': _('Filter shopping list to only include supermarket categories.'),
|
||||
'shopping_recent_days': _('Days of recent shopping list entries to display.'),
|
||||
}
|
||||
labels = {
|
||||
'shopping_share': _('Share Shopping List'),
|
||||
@@ -502,6 +504,7 @@ class ShoppingPreferenceForm(forms.ModelForm):
|
||||
'mealplan_autoinclude_related': _('Include Related'),
|
||||
'default_delay': _('Default Delay Hours'),
|
||||
'filter_to_supermarket': _('Filter to Supermarket'),
|
||||
'shopping_recent_days': _('Recent Days')
|
||||
}
|
||||
|
||||
widgets = {
|
||||
|
||||
@@ -79,9 +79,6 @@ def is_object_shared(user, obj):
|
||||
# share checks for relevant objects
|
||||
if not user.is_authenticated:
|
||||
return False
|
||||
if obj.__class__.__name__ == 'ShoppingListEntry':
|
||||
# shopping lists are shared all or none and stored in user preferences
|
||||
return obj.created_by in user.get_shopping_share()
|
||||
else:
|
||||
return user in obj.get_shared()
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ def search_recipes(request, queryset, params):
|
||||
search_steps = params.getlist('steps', [])
|
||||
search_units = params.get('units', None)
|
||||
|
||||
# TODO I think default behavior should be 'AND' which is how most sites operate with facet/filters based on results
|
||||
search_keywords_or = str2bool(params.get('keywords_or', True))
|
||||
search_foods_or = str2bool(params.get('foods_or', True))
|
||||
search_books_or = str2bool(params.get('books_or', True))
|
||||
@@ -202,20 +201,13 @@ def get_facet(qs=None, request=None, use_cache=True, hash_key=None):
|
||||
"""
|
||||
Gets an annotated list from a queryset.
|
||||
:param qs:
|
||||
|
||||
recipe queryset to build facets from
|
||||
|
||||
:param request:
|
||||
|
||||
the web request that contains the necessary query parameters
|
||||
|
||||
:param use_cache:
|
||||
|
||||
will find results in cache, if any, and return them or empty list.
|
||||
will save the list of recipes IDs in the cache for future processing
|
||||
|
||||
:param hash_key:
|
||||
|
||||
the cache key of the recipe list to process
|
||||
only evaluated if the use_cache parameter is false
|
||||
"""
|
||||
@@ -290,7 +282,6 @@ def get_facet(qs=None, request=None, use_cache=True, hash_key=None):
|
||||
foods = Food.objects.filter(ingredient__step__recipe__in=recipe_list, space=request.space).annotate(recipe_count=Count('ingredient'))
|
||||
food_a = annotated_qs(foods, root=True, fill=True)
|
||||
|
||||
# TODO add rating facet
|
||||
facets['Keywords'] = fill_annotated_parents(kw_a, keyword_list)
|
||||
facets['Foods'] = fill_annotated_parents(food_a, food_list)
|
||||
# TODO add book facet
|
||||
@@ -363,8 +354,6 @@ def annotated_qs(qs, root=False, fill=False):
|
||||
dirty = False
|
||||
current_node = node_queue[-1]
|
||||
depth = current_node.get_depth()
|
||||
# TODO if node is at the wrong depth for some reason this fails
|
||||
# either create a 'fix node' page, or automatically move the node to the root
|
||||
parent_id = current_node.parent
|
||||
if root and depth > 1 and parent_id not in nodes_list:
|
||||
parent_id = current_node.parent
|
||||
|
||||
@@ -15,14 +15,12 @@ from recipes import settings
|
||||
def shopping_helper(qs, request):
|
||||
supermarket = request.query_params.get('supermarket', None)
|
||||
checked = request.query_params.get('checked', 'recent')
|
||||
user = request.user
|
||||
|
||||
supermarket_order = ['food__supermarket_category__name', 'food__name']
|
||||
|
||||
# TODO created either scheduled task or startup task to delete very old shopping list entries
|
||||
# TODO create user preference to define 'very old'
|
||||
|
||||
# qs = qs.annotate(supermarket_category=Coalesce(F('food__supermarket_category__name'), Value(_('Undefined'))))
|
||||
# TODO add supermarket to API - order by category order
|
||||
if supermarket:
|
||||
supermarket_categories = SupermarketCategoryRelation.objects.filter(supermarket=supermarket, category=OuterRef('food__supermarket_category'))
|
||||
qs = qs.annotate(supermarket_order=Coalesce(Subquery(supermarket_categories.values('order')), Value(9999)))
|
||||
@@ -33,8 +31,7 @@ def shopping_helper(qs, request):
|
||||
qs = qs.filter(checked=True)
|
||||
elif checked in ['recent']:
|
||||
today_start = timezone.now().replace(hour=0, minute=0, second=0)
|
||||
# TODO make recent a user setting
|
||||
week_ago = today_start - timedelta(days=7)
|
||||
week_ago = today_start - timedelta(days=user.userpreference.shopping_recent_days)
|
||||
qs = qs.filter(Q(checked=False) | Q(completed_at__gte=week_ago))
|
||||
supermarket_order = ['checked'] + supermarket_order
|
||||
|
||||
@@ -51,7 +48,6 @@ def list_from_recipe(list_recipe=None, recipe=None, mealplan=None, servings=None
|
||||
:param ingredients: Ingredients, list of ingredient IDs to include on the shopping list. When not provided all ingredients will be used
|
||||
:param append: If False will remove any entries not included with ingredients, when True will append ingredients to the shopping list
|
||||
"""
|
||||
# TODO cascade to related recipes
|
||||
r = recipe or getattr(mealplan, 'recipe', None) or getattr(list_recipe, 'recipe', None)
|
||||
if not r:
|
||||
raise ValueError(_("You must supply a recipe or mealplan"))
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
import annoying.fields
|
||||
from django.conf import settings
|
||||
from django.contrib.postgres.indexes import GinIndex
|
||||
from django.contrib.postgres.search import SearchVectorField, SearchVector
|
||||
from django.contrib.postgres.search import SearchVector, SearchVectorField
|
||||
from django.db import migrations, models
|
||||
from django.db.models import deletion
|
||||
from django_scopes import scopes_disabled
|
||||
from django.utils import translation
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
from cookbook.managers import DICTIONARY
|
||||
from cookbook.models import Recipe, Step, Index, PermissionModelMixin, nameSearchField, allSearchFields
|
||||
from cookbook.models import (Index, PermissionModelMixin, Recipe, Step, allSearchFields,
|
||||
nameSearchField)
|
||||
|
||||
|
||||
def set_default_search_vector(apps, schema_editor):
|
||||
@@ -16,8 +18,6 @@ def set_default_search_vector(apps, schema_editor):
|
||||
return
|
||||
language = DICTIONARY.get(translation.get_language(), 'simple')
|
||||
with scopes_disabled():
|
||||
# TODO this approach doesn't work terribly well if multiple languages are in use
|
||||
# I'm also uncertain about forcing unaccent here
|
||||
Recipe.objects.all().update(
|
||||
name_search_vector=SearchVector('name__unaccent', weight='A', config=language),
|
||||
desc_search_vector=SearchVector('description__unaccent', weight='B', config=language)
|
||||
|
||||
@@ -157,5 +157,10 @@ class Migration(migrations.Migration):
|
||||
name='filter_to_supermarket',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='userpreference',
|
||||
name='shopping_recent_days',
|
||||
field=models.PositiveIntegerField(default=7),
|
||||
),
|
||||
migrations.RunPython(copy_values_to_sle),
|
||||
]
|
||||
|
||||
@@ -330,7 +330,8 @@ class UserPreference(models.Model, PermissionModelMixin):
|
||||
mealplan_autoexclude_onhand = models.BooleanField(default=True)
|
||||
mealplan_autoinclude_related = models.BooleanField(default=True)
|
||||
filter_to_supermarket = models.BooleanField(default=False)
|
||||
default_delay = models.IntegerField(default=4)
|
||||
default_delay = models.DecimalField(default=4, max_digits=8, decimal_places=4)
|
||||
shopping_recent_days = models.PositiveIntegerField(default=7)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
space = models.ForeignKey(Space, on_delete=models.CASCADE, null=True)
|
||||
|
||||
@@ -164,7 +164,7 @@ class UserPreferenceSerializer(serializers.ModelSerializer):
|
||||
'user', 'theme', 'nav_color', 'default_unit', 'default_page',
|
||||
'search_style', 'show_recent', 'plan_share', 'ingredient_decimals',
|
||||
'comments', 'shopping_auto_sync', 'mealplan_autoadd_shopping', 'food_ignore_default', 'default_delay',
|
||||
'mealplan_autoinclude_related', 'mealplan_autoexclude_onhand', 'shopping_share'
|
||||
'mealplan_autoinclude_related', 'mealplan_autoexclude_onhand', 'shopping_share', 'shopping_recent_days'
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ def skip_signal(signal_func):
|
||||
return _decorator
|
||||
|
||||
|
||||
# TODO there is probably a way to generalize this
|
||||
@receiver(post_save, sender=Recipe)
|
||||
@skip_signal
|
||||
def update_recipe_search_vector(sender, instance=None, created=False, **kwargs):
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -387,6 +387,7 @@ def user_settings(request):
|
||||
up.shopping_auto_sync = shopping_form.cleaned_data['shopping_auto_sync']
|
||||
up.filter_to_supermarket = shopping_form.cleaned_data['filter_to_supermarket']
|
||||
up.default_delay = shopping_form.cleaned_data['default_delay']
|
||||
up.shopping_recent_days = shopping_form.cleaned_data['shopping_recent_days']
|
||||
if up.shopping_auto_sync < settings.SHOPPING_MIN_AUTOSYNC_INTERVAL:
|
||||
up.shopping_auto_sync = settings.SHOPPING_MIN_AUTOSYNC_INTERVAL
|
||||
up.save()
|
||||
|
||||
Reference in New Issue
Block a user