diff --git a/boot.sh b/boot.sh index 8cd2c22cc..7e2f05fa0 100644 --- a/boot.sh +++ b/boot.sh @@ -1,12 +1,35 @@ #!/bin/sh source venv/bin/activate -echo "Updating database" -python manage.py migrate +echo "Migrating database" + +attempt=0 +max_attempts=20 +while python manage.py migrate; \ + status=$?; \ + attempt=$((attempt+1)); \ + [ $status -eq 1 ] \ + && [ $attempt -le $max_attempts ]; do + echo -e "\n!!! Migration failed (error ${status}, attempt ${attempt}/${max_attempts})." + echo "!!! Database may not be ready yet or system is misconfigured." + echo -e "!!! Retrying in 5 seconds...\n" + sleep 5 +done + +if [ $attempt -gt $max_attempts ]; then + echo -e "\n!!! Migration failed. Maximum attempts exceeded." + echo "!!! Please check logs above - misconfiguration is very likely." + echo "!!! Shutting down container." + exit 1 # exit with error to make the container stop +fi + +echo "Generating static files" + python manage.py collectstatic_js_reverse python manage.py collectstatic --noinput + echo "Done" chmod -R 755 /opt/recipes/mediafiles -exec gunicorn -b :8080 --access-logfile - --error-logfile - --log-level INFO recipes.wsgi \ No newline at end of file +exec gunicorn -b :8080 --access-logfile - --error-logfile - --log-level INFO recipes.wsgi diff --git a/cookbook/helper/recipe_search.py b/cookbook/helper/recipe_search.py index ad37af6da..d9d2e8514 100644 --- a/cookbook/helper/recipe_search.py +++ b/cookbook/helper/recipe_search.py @@ -5,7 +5,7 @@ from datetime import timedelta from django.contrib.postgres.search import SearchQuery, SearchRank, TrigramSimilarity from django.core.cache import caches from django.db.models import Avg, Case, Count, F, Func, Max, OuterRef, Q, Subquery, Sum, Value, When -from django.db.models.functions import Coalesce, Substr +from django.db.models.functions import Coalesce, Lower, Substr from django.utils import timezone, translation from django.utils.translation import gettext as _ @@ -159,6 +159,8 @@ class RecipeSearch(): # otherwise sort by the remaining order_by attributes or favorite by default else: order += default_order + order[:] = [Lower('name').asc() if x == 'name' else x for x in order] + order[:] = [Lower('name').desc() if x == '-name' else x for x in order] self.orderby = order def string_filters(self, string=None): @@ -653,9 +655,9 @@ class RecipeFacet(): if not self._request.space.demo and self._request.space.show_facet_count: return queryset.annotate(count=Coalesce(Subquery(self._recipe_count_queryset('keywords', depth, steplen)), 0) ).filter(depth=depth, count__gt=0 - ).values('id', 'name', 'count', 'numchild').order_by('name')[:200] + ).values('id', 'name', 'count', 'numchild').order_by(Lower('name').asc())[:200] else: - return queryset.filter(depth=depth).values('id', 'name', 'numchild').order_by('name') + return queryset.filter(depth=depth).values('id', 'name', 'numchild').order_by(Lower('name').asc()) def _food_queryset(self, queryset, food=None): depth = getattr(food, 'depth', 0) + 1 @@ -664,9 +666,9 @@ class RecipeFacet(): if not self._request.space.demo and self._request.space.show_facet_count: return queryset.annotate(count=Coalesce(Subquery(self._recipe_count_queryset('steps__ingredients__food', depth, steplen)), 0) ).filter(depth__lte=depth, count__gt=0 - ).values('id', 'name', 'count', 'numchild').order_by('name')[:200] + ).values('id', 'name', 'count', 'numchild').order_by(Lower('name').asc())[:200] else: - return queryset.filter(depth__lte=depth).values('id', 'name', 'numchild').order_by('name') + return queryset.filter(depth__lte=depth).values('id', 'name', 'numchild').order_by(Lower('name').asc()) def old_search(request): @@ -674,6 +676,6 @@ def old_search(request): params = dict(request.GET) params['internal'] = None f = RecipeFilter(params, - queryset=Recipe.objects.filter(space=request.user.userpreference.space).all().order_by('name'), + queryset=Recipe.objects.filter(space=request.user.userpreference.space).all().order_by(Lower('name').asc()), space=request.space) return f.qs diff --git a/cookbook/helper/shopping_helper.py b/cookbook/helper/shopping_helper.py index 2bd641fe8..d8e8046e9 100644 --- a/cookbook/helper/shopping_helper.py +++ b/cookbook/helper/shopping_helper.py @@ -65,9 +65,13 @@ class RecipeShoppingEditor(): except (ValueError, TypeError): self.servings = getattr(self._shopping_list_recipe, 'servings', None) or getattr(self.mealplan, 'servings', None) or getattr(self.recipe, 'servings', None) + @property + def _recipe_servings(self): + return getattr(self.recipe, 'servings', None) or getattr(getattr(self.mealplan, 'recipe', None), 'servings', None) or getattr(getattr(self._shopping_list_recipe, 'recipe', None), 'servings', None) + @property def _servings_factor(self): - return self.servings / self.recipe.servings + return Decimal(self.servings)/Decimal(self._recipe_servings) @property def _shared_users(self): diff --git a/cookbook/serializer.py b/cookbook/serializer.py index 5dcbe5d03..d6dae4316 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -719,7 +719,6 @@ class MealPlanSerializer(SpacedModelSerializer, WritableNestedModelSerializer): read_only_fields = ('created_by',) -# TODO deprecate class ShoppingListRecipeSerializer(serializers.ModelSerializer): name = serializers.SerializerMethodField('get_name') # should this be done at the front end? recipe_name = serializers.ReadOnlyField(source='recipe.name') diff --git a/cookbook/templates/base.html b/cookbook/templates/base.html index ce70c6cfc..4b10cf766 100644 --- a/cookbook/templates/base.html +++ b/cookbook/templates/base.html @@ -75,7 +75,7 @@