diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3f81b1fb..f33ea1df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,31 +10,80 @@ jobs: max-parallel: 4 matrix: python-version: ['3.10'] + node-version: ['18'] steps: - - uses: actions/checkout@v4 - - name: Set up Python 3.10 + - uses: actions/checkout@v3 + - uses: awalsh128/cache-apt-pkgs-action@v1.3.1 + with: + packages: libsasl2-dev python3-dev libldap2-dev libssl-dev + version: 1.0 + + # Setup python & dependencies + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: - python-version: '3.10' - # Build Vue frontend - - uses: actions/setup-node@v4 - with: - node-version: '18' - - name: Install Vue dependencies - working-directory: ./vue - run: yarn install - - name: Build Vue dependencies - working-directory: ./vue - run: yarn build - - name: Install Django dependencies + python-version: ${{ matrix.python-version }} + cache: 'pip' + + - name: Install Python Dependencies run: | - sudo apt-get -y update - sudo apt-get install -y libsasl2-dev python3-dev libldap2-dev libssl-dev python -m pip install --upgrade pip pip install -r requirements.txt + + - name: Cache StaticFiles + uses: actions/cache@v3 + id: django_cache + with: + path: | + ./cookbook/static + ./vue/webpack-stats.json + ./staticfiles + key: | + ${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.node-version }}-collectstatic-${{ hashFiles('**/*.css', '**/*.js', 'vue/src/*') }} + + # Build Vue frontend & Dependencies + - name: Set up Node ${{ matrix.node-version }} + if: steps.django_cache.outputs.cache-hit != 'true' + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'yarn' + cache-dependency-path: ./vue/yarn.lock + + - name: Install Vue dependencies + if: steps.django_cache.outputs.cache-hit != 'true' + working-directory: ./vue + run: yarn install + + - name: Build Vue dependencies + if: steps.django_cache.outputs.cache-hit != 'true' + working-directory: ./vue + run: yarn build + + - name: Compile Django StatisFiles + if: steps.django_cache.outputs.cache-hit != 'true' + run: | python3 manage.py collectstatic --noinput python3 manage.py collectstatic_js_reverse + + - uses: actions/cache/save@v3 + if: steps.django_cache.outputs.cache-hit != 'true' + with: + path: | + ./cookbook/static + ./vue/webpack-stats.json + ./staticfiles + key: | + ${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.node-version }}-collectstatic-${{ hashFiles('**/*.css', '**/*.js', 'vue/src/*') }} + - name: Django Testing project - run: | - pytest + run: pytest --junitxml=junit/test-results-${{ matrix.python-version }}.xml + + - name: Publish Test Results + uses: EnricoMi/publish-unit-test-result-action@v2 + if: always() + with: + comment_mode: off + files: | + junit/test-results-${{ matrix.python-version }}.xml diff --git a/cookbook/admin.py b/cookbook/admin.py index fcc007bc..96ebad97 100644 --- a/cookbook/admin.py +++ b/cookbook/admin.py @@ -323,8 +323,8 @@ admin.site.register(MealPlan, MealPlanAdmin) class MealTypeAdmin(admin.ModelAdmin): - list_display = ('name', 'created_by', 'order') - search_fields = ('name', 'created_by__username') + list_display = ('name', 'space', 'created_by', 'order') + search_fields = ('name', 'space', 'created_by__username') admin.site.register(MealType, MealTypeAdmin) diff --git a/cookbook/locale/it/LC_MESSAGES/django.po b/cookbook/locale/it/LC_MESSAGES/django.po index 89bd5df8..6750519c 100644 --- a/cookbook/locale/it/LC_MESSAGES/django.po +++ b/cookbook/locale/it/LC_MESSAGES/django.po @@ -12,8 +12,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-05-18 14:28+0200\n" -"PO-Revision-Date: 2023-04-29 07:55+0000\n" -"Last-Translator: Oliver Cervera \n" +"PO-Revision-Date: 2024-02-01 17:22+0000\n" +"Last-Translator: Lorenzo \n" "Language-Team: Italian \n" "Language: it\n" @@ -536,27 +536,27 @@ msgstr "rotazione inversa" #: .\cookbook\helper\recipe_url_import.py:267 msgid "careful rotation" -msgstr "" +msgstr "rotazione con cura" #: .\cookbook\helper\recipe_url_import.py:268 msgid "knead" -msgstr "" +msgstr "impastare" #: .\cookbook\helper\recipe_url_import.py:269 msgid "thicken" -msgstr "" +msgstr "addensare" #: .\cookbook\helper\recipe_url_import.py:270 msgid "warm up" -msgstr "" +msgstr "riscaldare" #: .\cookbook\helper\recipe_url_import.py:271 msgid "ferment" -msgstr "" +msgstr "fermentare" #: .\cookbook\helper\recipe_url_import.py:272 msgid "sous-vide" -msgstr "" +msgstr "sottovuoto" #: .\cookbook\helper\shopping_helper.py:157 msgid "You must supply a servings size" @@ -1760,6 +1760,13 @@ msgid "" "selected for a full text search.\n" " " msgstr "" +" \n" +" Ricerche semplici ignorano la puteggiatura e parole comuni come " +"\"il\", \"un\", \"e\". E tratterà separatamente le parole come necessario.\n" +" Cercare \"mela o farina\" restituisce ogni ricetta che contiene " +"sia \"mele\" che \"farina\" ovunque nei campi che sono stati selezionati per " +"una ricerca completa di testo.\n" +" " #: .\cookbook\templates\search_info.html:34 msgid "" @@ -1771,6 +1778,13 @@ msgid "" "been selected for a full text search.\n" " " msgstr "" +" \n" +" Ricerche di frase ignorano la punteggiatura, ma cercano tutte " +"parole nell'esatto ordine indicato.\n" +" Cercare \"mele o farina\" restituisce una ricetta che contiene " +"l'esatta frase \"mele o farina\" in qualsiasi campo selezionato per una " +"ricerca completa di testo.\n" +" " #: .\cookbook\templates\search_info.html:39 msgid "" diff --git a/cookbook/management/commands/seed_basic_data.py b/cookbook/management/commands/seed_basic_data.py new file mode 100644 index 00000000..25e5ef98 --- /dev/null +++ b/cookbook/management/commands/seed_basic_data.py @@ -0,0 +1,25 @@ +from django.conf import settings +from django.contrib.auth.models import User +from django.contrib.postgres.search import SearchVector +from django.core.management.base import BaseCommand +from django.utils import translation +from django.utils.translation import gettext_lazy as _ +from django_scopes import scopes_disabled + +from cookbook.managers import DICTIONARY +from cookbook.models import Recipe, Step, Space + + +class Command(BaseCommand): + help = 'Seeds some basic data (space, account, food)' + + def handle(self, *args, **options): + with scopes_disabled(): + user = User.objects.get_or_create(username='test')[0] + user.set_password('test') + user.save() + + space = Space.objects.get_or_create( + name='Test Space', + created_by=user + )[0] diff --git a/cookbook/migrations/0200_alter_propertytype_options_remove_keyword_icon_and_more.py b/cookbook/migrations/0200_alter_propertytype_options_remove_keyword_icon_and_more.py index a57ad977..03f7aa6d 100644 --- a/cookbook/migrations/0200_alter_propertytype_options_remove_keyword_icon_and_more.py +++ b/cookbook/migrations/0200_alter_propertytype_options_remove_keyword_icon_and_more.py @@ -13,22 +13,22 @@ def migrate_icons(apps, schema_editor): PropertyType = apps.get_model('cookbook', 'PropertyType') RecipeBook = apps.get_model('cookbook', 'RecipeBook') - duplicate_meal_types = MealType.objects.values('name').annotate(name_count=Count('name')).exclude(name_count=1).all() + duplicate_meal_types = MealType.objects.values('space_id', 'name').annotate(name_count=Count('name')).exclude(name_count=1).all() if len(duplicate_meal_types) > 0: raise RuntimeError(f'Duplicate MealTypes found, please remove/rename them and run migrations again/restart the container. {duplicate_meal_types}') MealType.objects.update(name=Concat(F('icon'), Value(' '), F('name'))) - duplicate_meal_types = Keyword.objects.values('name').annotate(name_count=Count('name')).exclude(name_count=1).all() + duplicate_meal_types = Keyword.objects.values('space_id', 'name').annotate(name_count=Count('name')).exclude(name_count=1).all() if len(duplicate_meal_types) > 0: raise RuntimeError(f'Duplicate Keyword found, please remove/rename them and run migrations again/restart the container. {duplicate_meal_types}') Keyword.objects.update(name=Concat(F('icon'), Value(' '), F('name'))) - duplicate_meal_types = PropertyType.objects.values('name').annotate(name_count=Count('name')).exclude(name_count=1).all() + duplicate_meal_types = PropertyType.objects.values('space_id', 'name').annotate(name_count=Count('name')).exclude(name_count=1).all() if len(duplicate_meal_types) > 0: raise RuntimeError(f'Duplicate PropertyType found, please remove/rename them and run migrations again/restart the container. {duplicate_meal_types}') PropertyType.objects.update(name=Concat(F('icon'), Value(' '), F('name'))) - duplicate_meal_types = RecipeBook.objects.values('name').annotate(name_count=Count('name')).exclude(name_count=1).all() + duplicate_meal_types = RecipeBook.objects.values('space_id', 'name').annotate(name_count=Count('name')).exclude(name_count=1).all() if len(duplicate_meal_types) > 0: raise RuntimeError(f'Duplicate RecipeBook found, please remove/rename them and run migrations again/restart the container. {duplicate_meal_types}') RecipeBook.objects.update(name=Concat(F('icon'), Value(' '), F('name'))) @@ -40,7 +40,7 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython( migrate_icons), + migrations.RunPython(migrate_icons), migrations.AlterModelOptions( name='propertytype', options={'ordering': ('order',)}, diff --git a/cookbook/serializer.py b/cookbook/serializer.py index 6b7d7e5f..991e09ac 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -348,7 +348,7 @@ class MealTypeSerializer(SpacedModelSerializer, WritableNestedModelSerializer): validated_data['name'] = validated_data['name'].strip() space = validated_data.pop('space', self.context['request'].space) validated_data['created_by'] = self.context['request'].user - obj, created = MealType.objects.get_or_create(name__iexact=validated_data['name'], space=space, defaults=validated_data) + obj, created = MealType.objects.get_or_create(name__iexact=validated_data['name'], space=space, created_by=self.context['request'].user, defaults=validated_data) return obj class Meta: diff --git a/docs/install/docker/ipv6_plain/docker-compose.yml b/docs/install/docker/ipv6_plain/docker-compose.yml index 312b1400..e989fc09 100644 --- a/docs/install/docker/ipv6_plain/docker-compose.yml +++ b/docs/install/docker/ipv6_plain/docker-compose.yml @@ -2,7 +2,7 @@ version: "2.4" services: db_recipes: restart: always - image: postgres:15-alpine + image: postgres:16-alpine volumes: - ${POSTGRES_DATA_DIR:-./postgresql}:/var/lib/postgresql/data env_file: diff --git a/docs/install/docker/nginx-proxy/docker-compose.yml b/docs/install/docker/nginx-proxy/docker-compose.yml index 7040c566..2e408646 100644 --- a/docs/install/docker/nginx-proxy/docker-compose.yml +++ b/docs/install/docker/nginx-proxy/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: db_recipes: restart: always - image: postgres:15-alpine + image: postgres:16-alpine volumes: - ./postgresql:/var/lib/postgresql/data env_file: diff --git a/docs/install/docker/plain/docker-compose.yml b/docs/install/docker/plain/docker-compose.yml index 203217e4..089e72c5 100644 --- a/docs/install/docker/plain/docker-compose.yml +++ b/docs/install/docker/plain/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: db_recipes: restart: always - image: postgres:15-alpine + image: postgres:16-alpine volumes: - ./postgresql:/var/lib/postgresql/data env_file: diff --git a/docs/install/docker/traefik-nginx/docker-compose.yml b/docs/install/docker/traefik-nginx/docker-compose.yml index 9947c3a8..afe2fbfb 100644 --- a/docs/install/docker/traefik-nginx/docker-compose.yml +++ b/docs/install/docker/traefik-nginx/docker-compose.yml @@ -2,7 +2,7 @@ version: "3" services: db_recipes: restart: always - image: postgres:15-alpine + image: postgres:16-alpine volumes: - ./postgresql:/var/lib/postgresql/data env_file: diff --git a/docs/install/swag.md b/docs/install/swag.md index 3f1eda6a..15b2b9b6 100644 --- a/docs/install/swag.md +++ b/docs/install/swag.md @@ -69,7 +69,7 @@ services: db_recipes: restart: always container_name: db_recipes - image: postgres:15-alpine + image: postgres:16-alpine volumes: - ./recipes/db:/var/lib/postgresql/data env_file: diff --git a/docs/install/truenas_portainer.md b/docs/install/truenas_portainer.md index 7be57bf2..436fc595 100644 --- a/docs/install/truenas_portainer.md +++ b/docs/install/truenas_portainer.md @@ -81,7 +81,7 @@ version: "3" services: db_recipes: restart: always - image: postgres:15-alpine + image: postgres:16-alpine volumes: - ./postgresql:/var/lib/postgresql/data env_file: diff --git a/vue/src/locales/it.json b/vue/src/locales/it.json index 7489117b..445bebc5 100644 --- a/vue/src/locales/it.json +++ b/vue/src/locales/it.json @@ -470,5 +470,8 @@ "substitute_siblings_help": "Tutti gli alimenti che condividono un genitore di questo alimento sono considerati sostituti", "reset_children": "Reimposta l'eredità degli eredi", "substitute_siblings": "Sostituire prodotti eredi", - "ChildInheritFields": "Gli eredi ereditano i valori" + "ChildInheritFields": "Gli eredi ereditano i valori", + "recipe_property_info": "Puoi anche aggiungere proprietà ai cibi per calcolarli automaticamente in base alla tua ricetta!", + "err_importing_recipe": "Si è verificato un errore durante l'importazione della ricetta!", + "per_serving": "per porzioni" }