diff --git a/.github/workflows/build-docker-open-data.yml b/.github/workflows/build-docker-open-data.yml index 09df1956..22b3af12 100644 --- a/.github/workflows/build-docker-open-data.yml +++ b/.github/workflows/build-docker-open-data.yml @@ -21,7 +21,7 @@ jobs: suffix: "" continue-on-error: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Get version number id: get_version @@ -43,7 +43,7 @@ jobs: path: ./recipes/plugins/open_data_plugin # Build Vue frontend - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: '18' cache: yarn diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 8c29b9fe..b61169d5 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -21,7 +21,7 @@ jobs: suffix: "" continue-on-error: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Get version number id: get_version @@ -35,7 +35,7 @@ jobs: fi # Build Vue frontend - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: '18' cache: yarn diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d5da9d82..3f81b1fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: python-version: ['3.10'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python 3.10 uses: actions/setup-python@v5 with: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 4166aae3..fcdd8926 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. @@ -25,7 +25,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 # Override language selection by uncommenting this and choosing your languages with: languages: python, javascript @@ -47,6 +47,6 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: languages: javascript, python diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 7a35555b..6956ee7f 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -9,8 +9,8 @@ jobs: if: github.repository_owner == 'TandoorRecipes' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: 3.x - run: pip install mkdocs-material mkdocs-include-markdown-plugin diff --git a/README.md b/README.md index 28dc83ed..4398c00f 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ Share some information on how you use Tandoor to help me improve the application Beginning with version 0.10.0 the code in this repository is licensed under the [GNU AGPL v3](https://www.gnu.org/licenses/agpl-3.0.de.html) license with a [common clause](https://commonsclause.com/) selling exception. See [LICENSE.md](https://github.com/vabene1111/recipes/blob/develop/LICENSE.md) for details. -> NOTE: There appears to be a whole range of legal issues with licensing anything else then the standard completely open licenses. +> NOTE: There appears to be a whole range of legal issues with licensing anything other than the standard completely open licenses. > I am in the process of getting some professional legal advice to sort out these issues. > Please also see [Issue 238](https://github.com/vabene1111/recipes/issues/238) for some discussion and **reasoning** regarding the topic. diff --git a/boot.sh b/boot.sh index 3faacad7..97a94f47 100644 --- a/boot.sh +++ b/boot.sh @@ -76,4 +76,4 @@ echo "Done" chmod -R 755 /opt/recipes/mediafiles -exec gunicorn -b :$TANDOOR_PORT --workers $GUNICORN_WORKERS --threads $GUNICORN_THREADS --access-logfile - --error-logfile - --log-level $GUNICORN_LOG_LEVEL recipes.wsgi +exec gunicorn -b "[::]:$TANDOOR_PORT" --workers $GUNICORN_WORKERS --threads $GUNICORN_THREADS --access-logfile - --error-logfile - --log-level $GUNICORN_LOG_LEVEL recipes.wsgi diff --git a/cookbook/forms.py b/cookbook/forms.py index 2244acad..401fc9a5 100644 --- a/cookbook/forms.py +++ b/cookbook/forms.py @@ -495,7 +495,7 @@ class SpacePreferenceForm(forms.ModelForm): class Meta: model = Space - fields = ('food_inherit', 'reset_food_inherit', 'use_plural') + fields = ('food_inherit', 'reset_food_inherit',) help_texts = { 'food_inherit': _('Fields on food that should be inherited by default.'), diff --git a/cookbook/helper/template_helper.py b/cookbook/helper/template_helper.py index 016779a7..4db1f5bc 100644 --- a/cookbook/helper/template_helper.py +++ b/cookbook/helper/template_helper.py @@ -14,12 +14,14 @@ class IngredientObject(object): unit = "" food = "" note = "" + numeric_amount = 0 def __init__(self, ingredient): if ingredient.no_amount: self.amount = "" else: self.amount = f"" + self.numeric_amount = float(ingredient.amount) if ingredient.unit: if ingredient.unit.plural_name in (None, ""): self.unit = bleach.clean(str(ingredient.unit)) @@ -83,9 +85,12 @@ def render_instructions(step): # TODO deduplicate markdown cleanup code for i in step.ingredients.all(): ingredients.append(IngredientObject(i)) + def scale(number): + return f"" + try: template = Template(instructions) - instructions = template.render(ingredients=ingredients) + instructions = template.render(ingredients=ingredients, scale=scale) except TemplateSyntaxError: return _('Could not parse template code.') + ' Error: Template Syntax broken' except UndefinedError: diff --git a/cookbook/migrations/0204_propertytype_fdc_id.py b/cookbook/migrations/0204_propertytype_fdc_id.py index 70598463..e57dea39 100644 --- a/cookbook/migrations/0204_propertytype_fdc_id.py +++ b/cookbook/migrations/0204_propertytype_fdc_id.py @@ -4,11 +4,6 @@ from django.db import migrations, models from django_scopes import scopes_disabled -def fix_fdc_ids(apps, schema_editor): - with scopes_disabled(): - # in case any food had a non digit fdc ID before this migration, remove it - Food = apps.get_model('cookbook', 'Food') - Food.objects.exclude(fdc_id__regex=r'^\d+$').exclude(fdc_id=None).update(fdc_id=None) class Migration(migrations.Migration): @@ -17,7 +12,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.RunPython(fix_fdc_ids), migrations.AddField( model_name='propertytype', name='fdc_id', diff --git a/cookbook/migrations/0205_alter_food_fdc_id_alter_propertytype_fdc_id.py b/cookbook/migrations/0205_alter_food_fdc_id_alter_propertytype_fdc_id.py index 9f57e443..96b19f26 100644 --- a/cookbook/migrations/0205_alter_food_fdc_id_alter_propertytype_fdc_id.py +++ b/cookbook/migrations/0205_alter_food_fdc_id_alter_propertytype_fdc_id.py @@ -1,15 +1,23 @@ # Generated by Django 4.2.7 on 2023-11-29 19:44 from django.db import migrations, models +from django_scopes import scopes_disabled + + +def fix_fdc_ids(apps, schema_editor): + with scopes_disabled(): + # in case any food had a non digit fdc ID before this migration, remove it + Food = apps.get_model('cookbook', 'Food') + Food.objects.exclude(fdc_id__regex=r'^\d+$').exclude(fdc_id=None).update(fdc_id=None) class Migration(migrations.Migration): - dependencies = [ ('cookbook', '0204_propertytype_fdc_id'), ] operations = [ + migrations.RunPython(fix_fdc_ids), migrations.AlterField( model_name='food', name='fdc_id', diff --git a/cookbook/migrations/0209_remove_space_use_plural.py b/cookbook/migrations/0209_remove_space_use_plural.py new file mode 100644 index 00000000..37a4b6fc --- /dev/null +++ b/cookbook/migrations/0209_remove_space_use_plural.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.7 on 2024-01-28 07:42 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('cookbook', '0208_space_app_name_userpreference_max_owned_spaces'), + ] + + operations = [ + migrations.RemoveField( + model_name='space', + name='use_plural', + ), + ] diff --git a/cookbook/models.py b/cookbook/models.py index 5cb6fa00..da927d50 100644 --- a/cookbook/models.py +++ b/cookbook/models.py @@ -303,7 +303,6 @@ class Space(ExportModelOperationsMixin('space'), models.Model): max_recipes = models.IntegerField(default=0) max_file_storage_mb = models.IntegerField(default=0, help_text=_('Maximum file storage for space in MB. 0 for unlimited, -1 to disable file upload.')) max_users = models.IntegerField(default=0) - use_plural = models.BooleanField(default=True) allow_sharing = models.BooleanField(default=True) no_sharing_limit = models.BooleanField(default=False) demo = models.BooleanField(default=False) diff --git a/cookbook/serializer.py b/cookbook/serializer.py index f883a3f2..6b7d7e5f 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -311,7 +311,7 @@ class SpaceSerializer(WritableNestedModelSerializer): fields = ( 'id', 'name', 'created_by', 'created_at', 'message', 'max_recipes', 'max_file_storage_mb', 'max_users', 'allow_sharing', 'demo', 'food_inherit', 'user_count', 'recipe_count', 'file_size_mb', - 'image', 'nav_logo', 'space_theme', 'custom_space_theme', 'nav_bg_color', 'nav_text_color', 'use_plural', + 'image', 'nav_logo', 'space_theme', 'custom_space_theme', 'nav_bg_color', 'nav_text_color', 'logo_color_32', 'logo_color_128', 'logo_color_144', 'logo_color_180', 'logo_color_192', 'logo_color_512', 'logo_color_svg',) read_only_fields = ( 'id', 'created_by', 'created_at', 'max_recipes', 'max_file_storage_mb', 'max_users', 'allow_sharing', diff --git a/cookbook/templates/base.html b/cookbook/templates/base.html index 6505b405..4cbc1544 100644 --- a/cookbook/templates/base.html +++ b/cookbook/templates/base.html @@ -10,7 +10,7 @@ {% block title %} {% endblock %} - + @@ -485,6 +485,14 @@ overflow-x: hidden; } } + + #id_base_container { + padding-bottom: env(safe-area-inset-bottom); + } + + .fixed-bottom { + padding-bottom: max(0.5rem, calc(env(safe-area-inset-bottom) - 0.5rem)) !important; + } diff --git a/cookbook/templatetags/theming_tags.py b/cookbook/templatetags/theming_tags.py index d69ae7b0..f2984b97 100644 --- a/cookbook/templatetags/theming_tags.py +++ b/cookbook/templatetags/theming_tags.py @@ -3,7 +3,7 @@ from django.templatetags.static import static from django_scopes import scopes_disabled from cookbook.models import UserPreference, UserFile, Space -from recipes.settings import STICKY_NAV_PREF_DEFAULT, UNAUTHENTICATED_THEME_FROM_SPACE +from recipes.settings import STICKY_NAV_PREF_DEFAULT, UNAUTHENTICATED_THEME_FROM_SPACE, FORCE_THEME_FROM_SPACE register = template.Library() @@ -15,11 +15,14 @@ def theme_values(request): def get_theming_values(request): space = None - if getattr(request,'space',None): + if getattr(request, 'space', None): space = request.space - if not request.user.is_authenticated and UNAUTHENTICATED_THEME_FROM_SPACE > 0: + if not request.user.is_authenticated and UNAUTHENTICATED_THEME_FROM_SPACE > 0 and FORCE_THEME_FROM_SPACE == 0: with scopes_disabled(): space = Space.objects.filter(id=UNAUTHENTICATED_THEME_FROM_SPACE).first() + if FORCE_THEME_FROM_SPACE: + with scopes_disabled(): + space = Space.objects.filter(id=FORCE_THEME_FROM_SPACE).first() themes = { UserPreference.BOOTSTRAP: 'themes/bootstrap.min.css', diff --git a/cookbook/views/api.py b/cookbook/views/api.py index 446f0b7f..5b44c2f8 100644 --- a/cookbook/views/api.py +++ b/cookbook/views/api.py @@ -1728,10 +1728,10 @@ def get_plan_ical(request, from_date, to_date): ).filter(space=request.user.userspace_set.filter(active=1).first().space).distinct().all() if from_date is not None: - queryset = queryset.filter(date__gte=from_date) + queryset = queryset.filter(from_date__gte=from_date) if to_date is not None: - queryset = queryset.filter(date__lte=to_date) + queryset = queryset.filter(to_date__lte=to_date) cal = Calendar() diff --git a/docs/faq.md b/docs/faq.md index 6c8e5aa5..1285b2ac 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -10,9 +10,12 @@ Tandoor can be installed as a progressive web app (PWA) on mobile and desktop de #### Safari (iPhone/iPad) Open Tandoor, click Safari's share button, select `Add to Home Screen` -### Chrome/Chromium +#### Chrome/Chromium Open Tandoor, click the `add Tandoor to the home screen` message that pops up at the bottom of the screen +#### Firefox for Android +Open Tandoor, click on the `⋮` menu icon, then on `Install` + ### Desktop browsers #### Google Chrome @@ -124,13 +127,13 @@ to your dream setup. ## How can I upgrade postgres (major versions)? Postgres requires manual intervention when updating from one major version to another. The steps are roughly -1. use `pg_dumpall` to dump your database into SQL (for Docker `docker-compose exec -T pg_dumpall -U -f /path/to/dump.sql`) +1. use `pg_dumpall` to dump your database into SQL (for Docker `docker-compose exec -T pg_dumpall -U -f /path/to/dump.sql`) 2. stop the DB / down the container 3. move your postgres directory in order to keep it as a backup (e.g. `mv postgres postgres_old`) 4. update postgres to the new major version (for Docker just change the version number and pull) 5. start the db / up the container (do not start tandoor as it will automatically perform the database migrations which will conflict with loading the dump) 6. if not using docker, you might need to create the same postgres user you had in the old database -7. load the postgres dump (for Docker `'/usr/local/bin/docker-compose exec -T psql -U postgres < /path/to/dump.sql`) +7. load the postgres dump (for Docker `'/usr/local/bin/docker-compose exec -T psql -U < /path/to/dump.sql`) If anything fails, go back to the old postgres version and data directory and try again. diff --git a/docs/features/automation.md b/docs/features/automation.md index b89a4a10..60a984c8 100644 --- a/docs/features/automation.md +++ b/docs/features/automation.md @@ -50,7 +50,7 @@ In order to prevent denial of service attacks on the RegEx engine the number of and the length of the inputs that are processed are limited. Those limits should never be reached during normal usage. -## Instructtion Replace, Title Replace, Food Replace & Unit Replace +## Instruction Replace, Title Replace, Food Replace & Unit Replace These work just like the Description Replace automation. Instruction, Food and Unit Replace will run against every iteration of the object in a recipe during import. diff --git a/docs/features/shopping.md b/docs/features/shopping.md index ca431dbb..cb1f1654 100644 --- a/docs/features/shopping.md +++ b/docs/features/shopping.md @@ -1,5 +1,5 @@ !!! info "WIP" - While being around for a while there are still a lot of features that i plan on adding to the shopping list. + While being around for a while there are still a lot of features that I plan on adding to the shopping list. You can see an overview of what is still planned on [this](https://github.com/vabene1111/recipes/issues/114) issue. @@ -41,4 +41,4 @@ There are a few more features worth pointing out 1. You can export recipes for use in other applications (Google Keep, etc.) by using the export button 2. In the export popup you can define a prefix to be put before each row in case an external app requires that -3. Marking a shopping list as finished will hide it from the shopping list page \ No newline at end of file +3. Marking a shopping list as finished will hide it from the shopping list page diff --git a/docs/install/docker.md b/docs/install/docker.md index 7d32ab4d..e02e28cc 100644 --- a/docs/install/docker.md +++ b/docs/install/docker.md @@ -204,6 +204,22 @@ server { } ``` +Tandoor does not support directly serving of images, as explained in the [Nginx vs Gunicorn"](#nginx-vs-gunicorn) section. If you are already using nginx to serve as a reverse proxy, you can configure it to serve images as well. + +Add the following directly after the `location /` context: + +``` + location /media/ { + root /media/; + index index.html index.htm; + } +``` + +Make sure you also update your `docker-compose.yml` file to mount the `mediafiles` directory. If you are using the [Plain](#plain) deployment, you do not need to make any changes. If you are using nginx to act as a reverse proxy for other apps, it may not be optimal to have `mediafiles` mounted to `/media`. In that case, adjust the directory declarations as needed, utilizing nginx's [`alias`](https://nginx.org/en/docs/http/ngx_http_core_module.html#alias) if needed. + +!!!note + Use `alias` if your mount point directory is not the same as the URL request path. Tandoor media files are requested from `$http_host/media/recipes/xxx.jpg`. This means if you are mounting to a directory that does **NOT** end in `./media`, you will need to use `alias`. + !!!note Don't forget to [download and configure](#docker-compose) your ```.env``` file! diff --git a/docs/install/other.md b/docs/install/other.md index a6db572e..b4829f3e 100644 --- a/docs/install/other.md +++ b/docs/install/other.md @@ -59,6 +59,155 @@ I used two paths `` and `` for simplicity. In my case I have I left out the TLS config in this example for simplicity. +## Docker + Apache + Sub-Path + +The following could prove to be useful if you are not using Traefik, but instead run Apache as your reverse proxy to route all calls for a shared (sub)domain to a sub path, e.g. https://mydomain.tld/tandoor + +As a side note, I am using [Blocky](https://0xerr0r.github.io/blocky/) + [Consul](https://hub.docker.com/r/hashicorp/consul) + [Registrator](https://hub.docker.com/r/gliderlabs/registrator) as a DNS solution. + +The relevant Apache config: +``` + + # in case you want to restrict access to specific IP addresses: + Require local + Require forward-dns [myhomedomain.useyourdomain.com] + Require ip [anylocalorremoteipyouwanttowhitelist] + + # The following assumes that tandoor.service.consul.local resolves to the IP address of the Docker container. + ProxyPass http://tandoor.service.consul.local:8080/tandoor + ProxyPassReverse http://tandoor.service.consul.local:8080/tandoor + RequestHeader add X-Script-Name /tandoor + RequestHeader set X-Forwarded-Proto "https" + ProxyPreserveHost On + + + Require local + Require forward-dns [myhomedomain.useyourdomain.com] + Require ip [anylocalorremoteipyouwanttowhitelist] + + ProxyPass http://tandoor.service.consul.local:8080/tandoor/tandoor/static + ProxyPassReverse http://tandoor.service.consul.local:8080/tandoor/static + RequestHeader add X-Script-Name /tandoor + RequestHeader set X-Forwarded-Proto "https" + ProxyPreserveHost On + +``` +and the relevant section from the docker-compose.yml: +``` + tandoor: + restart: always + container_name: tandoor + image: vabene1111/recipes + environment: + - SCRIPT_NAME=/tandoor + - JS_REVERSE_SCRIPT_PREFIX=/tandoor + - STATIC_URL=/tandoor/static/ + - MEDIA_URL=/tandoor/media/ + - GUNICORN_MEDIA=0 + - SECRET_KEY=${YOUR_TANDOOR_SECRET_KEY} + - POSTGRES_HOST=postgres.service.consul.local + - POSTGRES_PORT=${POSTGRES_PORT} + - POSTGRES_USER=${YOUR_TANDOOR_POSTGRES_USER} + - POSTGRES_PASSWORD=${YOUR_TANDOOR_POSTGRES_PASSWORD} + - POSTGRES_DB=${YOUR_TANDOOR_POSTGRES_DB} + labels: + # The following is relevant only if you are using Registrator and Consul + - "SERVICE_NAME=tandoor" + volumes: + - ${YOUR_DOCKER_VOLUME_BASE_DIR}/tandoor/static:/opt/recipes/staticfiles:rw + # Do not make this a bind mount, see https://docs.tandoor.dev/install/docker/#volumes- vs-bind-mounts + - tandoor_nginx_config:/opt/recipes/nginx/conf.d + - ${YOUR_DOCKER_VOLUME_BASE_DIR}}/tandoor/media:/opt/recipes/mediafiles:rw + depends_on: + # You will have to set up postgres accordingly + - postgres +``` + +The relevant docker-compose.yml for Registrator, Consul, and Blocky, and Autoheal: +``` + consul: + image: hashicorp/consul + container_name: consul + command: > + agent -server + -domain consul.local + -advertise=${YOUR_DOCKER_HOST_IP_ON_THE_LAN} + -client=0.0.0.0 + -encrypt=${SOME_SECRET_KEY} + -datacenter=${YOUR_DC_NAME} + -bootstrap-expect=1 + -ui + -log-level=info + environment: + - "CONSUL_LOCAL_CONFIG={\"skip_leave_on_interrupt\": true, \"dns_config\": { \"service_ttl\": { \"*\": \"0s\" } } }" + network_mode: "host" + restart: always + + registrator: + image: gliderlabs/registrator:latest + container_name: registrator + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + command: > + -internal + -cleanup=true + -deregister="always" + -resync=60 + consul://host.docker.internal:8500 + restart: always + + blocky: + image: spx01/blocky + container_name: blocky + restart: unless-stopped + healthcheck: + interval: 30s + timeout: 5s + start_period: 1m + labels: + # The following is only relevant if you use autoheal + autoheal: true + # Optional the instance hostname for logging purpose + hostname: blocky + extra_hosts: + - "host.docker.internal:host-gateway" + ports: + - "1153:53/tcp" + - "1153:53/udp" + - 4000:4000 + environment: + - TZ=YOUR_TIMEZONE # Optional to synchronize the log timestamp with host + volumes: + # Optional to synchronize the log timestamp with host + - /etc/localtime:/etc/localtime:ro + # config file + - ${YOUR_DOCKER_VOLUME_BASE_DIR}/blocky/config.yml:/app/config.yml + networks: + # in case you want to bind Blocky to an IP address + your-docker-network-name: + ipv4_address: 'some-ip-address-in-the-docker-network-subnet' + + autoheal: + image: willfarrell/autoheal + volumes: + - '/var/run/docker.sock:/var/run/docker.sock' + environment: + - AUTOHEAL_CONTAINER_LABEL=autoheal + restart: always + container_name: autoheal + +``` +as well as a snippet of the Blocky configuration: +``` +conditional: + fallbackUpstream: false + mapping: + consul.local: tcp+udp:host.docker.internal:8600 +``` + + ## WSL If you want to install Tandoor on the Windows Subsystem for Linux you can find a detailed post here: . diff --git a/docs/system/backup.md b/docs/system/backup.md index 308e3561..39f4a302 100644 --- a/docs/system/backup.md +++ b/docs/system/backup.md @@ -45,7 +45,7 @@ To restore: cat pgdump.sql | sudo docker exec -i docker_db_recipes_1 psql postgres -U djangouser ``` -This connects to the postgres table instead of the actual dgangodb table, as the import function needs to delete the table, which can't be dropped off you're connected to it. +This connects to the postgres table instead of the actual djangodb table, as the import function needs to delete the table, which can't be dropped off you're connected to it. ## Backup using export and import You can now export recipes from Tandoor using the export function. This method requires a working web interface. diff --git a/docs/system/configuration.md b/docs/system/configuration.md index dc64d41d..0eb1b783 100644 --- a/docs/system/configuration.md +++ b/docs/system/configuration.md @@ -570,6 +570,15 @@ With this setting you can specify the ID of a space of which the appearance sett UNAUTHENTICATED_THEME_FROM_SPACE= ``` +#### Force Theme +> default `0` - options `1-X` (space ID) + +Similar to the Default theme but forces the theme upon all users (authenticated/unauthenticated) and all spaces + +``` +FORCE_THEME_FROM_SPACE= +``` + ### Rate Limiting / Performance #### Shopping auto sync diff --git a/docs/system/updating.md b/docs/system/updating.md index b6d88588..404da607 100644 --- a/docs/system/updating.md +++ b/docs/system/updating.md @@ -81,7 +81,7 @@ sudo mv -R ~/.docker/compose/postgres ~/.docker/compose/postgres.old ``` 8. Install postgres extensions ``` bash - docker exec -it {{database_container}} psql + docker exec -it {{database_container}} psql postgres -U {{djangouser}} ``` then ``` psql diff --git a/nginx/conf.d/Recipes.conf b/nginx/conf.d/Recipes.conf index 22829720..9cda0f74 100644 --- a/nginx/conf.d/Recipes.conf +++ b/nginx/conf.d/Recipes.conf @@ -1,5 +1,6 @@ server { listen 80; + listen [::]:80 ipv6only=on; server_name localhost; client_max_body_size 128M; diff --git a/recipes/settings.py b/recipes/settings.py index 6439f727..009c6a5a 100644 --- a/recipes/settings.py +++ b/recipes/settings.py @@ -59,6 +59,7 @@ KJ_PREF_DEFAULT = bool(int(os.getenv('KJ_PREF_DEFAULT', False))) STICKY_NAV_PREF_DEFAULT = bool(int(os.getenv('STICKY_NAV_PREF_DEFAULT', True))) MAX_OWNED_SPACES_PREF_DEFAULT = int(os.getenv('MAX_OWNED_SPACES_PREF_DEFAULT', 100)) UNAUTHENTICATED_THEME_FROM_SPACE = int(os.getenv('UNAUTHENTICATED_THEME_FROM_SPACE', 0)) +FORCE_THEME_FROM_SPACE = int(os.getenv('FORCE_THEME_FROM_SPACE', 0)) # minimum interval that users can set for automatic sync of shopping lists SHOPPING_MIN_AUTOSYNC_INTERVAL = int( diff --git a/requirements.txt b/requirements.txt index 16fca731..7f08008a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ Django==4.2.7 -cryptography===41.0.6 +cryptography===41.0.7 django-annoying==0.10.6 -django-autocomplete-light==3.9.4 +django-autocomplete-light==3.9.7 django-cleanup==8.0.0 django-crispy-forms==2.0 crispy-bootstrap4==2022.1 @@ -14,7 +14,7 @@ bleach==6.0.0 gunicorn==20.1.0 lxml==4.9.3 Markdown==3.5.1 -Pillow==10.0.1 +Pillow==10.2.0 psycopg2-binary==2.9.5 python-dotenv==1.0.0 requests==2.31.0 @@ -27,7 +27,7 @@ uritemplate==4.1.1 beautifulsoup4==4.12.2 microdata==0.8.0 mock==5.1.0 -Jinja2==3.1.2 +Jinja2==3.1.3 django-webpack-loader==1.8.1 git+https://github.com/BITSOLVER/django-js-reverse@071e304fd600107bc64bbde6f2491f1fe049ec82 django-allauth==0.58.1 @@ -38,13 +38,13 @@ pytest-asyncio==0.23.3 pytest-django==4.6.0 django-treebeard==4.7 django-cors-headers==4.2.0 -django-storages==1.13.2 +django-storages==1.14.2 boto3==1.28.75 django-prometheus==2.2.0 django-hCaptcha==0.2.0 python-ldap==3.4.3 django-auth-ldap==4.4.0 -pytest-factoryboy==2.5.1 +pytest-factoryboy==2.6.0 pyppeteer==1.0.2 validators==0.20.0 pytube==15.0.0 diff --git a/vue/package.json b/vue/package.json index f90fbc7f..4f56ee31 100644 --- a/vue/package.json +++ b/vue/package.json @@ -45,8 +45,8 @@ "vue-template-compiler": "2.7.14", "vue2-touch-events": "^3.2.2", "vuedraggable": "^2.24.3", - "workbox-webpack-plugin": "^6.5.4", - "workbox-window": "^6.5.4" + "workbox-webpack-plugin": "^7.0.0", + "workbox-window": "^7.0.0" }, "devDependencies": { "@kazupon/vue-i18n-loader": "^0.5.0", @@ -65,11 +65,11 @@ "typescript": "~5.1.6", "vue-cli-plugin-i18n": "^2.3.2", "webpack-bundle-tracker": "1.8.1", - "workbox-background-sync": "^6.5.4", + "workbox-background-sync": "^7.0.0", "workbox-expiration": "^6.5.4", - "workbox-navigation-preload": "^6.5.4", + "workbox-navigation-preload": "^7.0.0", "workbox-precaching": "^6.5.4", - "workbox-routing": "^6.5.4", + "workbox-routing": "^7.0.0", "workbox-strategies": "^6.2.4" }, "eslintConfig": { diff --git a/vue/src/apps/ImportView/ImportViewStepEditor.vue b/vue/src/apps/ImportView/ImportViewStepEditor.vue index 0d0ff94e..cbf2432a 100644 --- a/vue/src/apps/ImportView/ImportViewStepEditor.vue +++ b/vue/src/apps/ImportView/ImportViewStepEditor.vue @@ -62,7 +62,7 @@ - +
@@ -88,8 +88,8 @@
- {{ $t('Ok') }} - {{ $t('Delete') }} + {{ $t('Ok') }} + {{ $t('Delete') }}
diff --git a/vue/src/apps/MealPlanView/MealPlanView.vue b/vue/src/apps/MealPlanView/MealPlanView.vue index f870ee96..58793c70 100644 --- a/vue/src/apps/MealPlanView/MealPlanView.vue +++ b/vue/src/apps/MealPlanView/MealPlanView.vue @@ -80,80 +80,73 @@
-
+
-
-
-
-
-
- - - - - - - - - - - - +
+
+ + + + + + + + + + + + +
+
+
+
+ + +
+
{{ day.date_label }}
+ +
+ +
-
-
-
- - -
-
{{ day.date_label }}
-
- -
-
- -
- -
-
- - -
-
+ + +
+
+ + +
+
{{ plan.entry.recipe.name }} {{ plan.entry.title }}
- + {{ plan.entry.note }}
- - - {{ plan.entry.meal_type_name }} - + + + {{ plan.entry.meal_type_name }} + - {{ plan.entry.recipe.working_time + plan.entry.recipe.waiting_time }} {{ $t('min') }} - -
-
- -
-
-
- - + +
+
+ +
-
+ -
+
@@ -364,7 +357,7 @@ export default { }, mobileSimpleGrid() { let grid = []; - let currentDate = moment(); + let currentDate = moment(this.showDate); for (let x = 0; x < 7; x++) { let moment_date = currentDate.clone().add(x, "d"); grid.push({ @@ -483,7 +476,7 @@ export default { this.setShowDate(ctx.selectedDate) }, setShowDate(d) { - this.showDate = d + this.showDate = d ?? new Date(); }, createEntryClick(data) { this.mealplan_default_date = moment(data).format("YYYY-MM-DD") diff --git a/vue/src/apps/RecipeEditView/RecipeEditView.vue b/vue/src/apps/RecipeEditView/RecipeEditView.vue index 7fd5dbe7..74ff16a4 100644 --- a/vue/src/apps/RecipeEditView/RecipeEditView.vue +++ b/vue/src/apps/RecipeEditView/RecipeEditView.vue @@ -1321,3 +1321,9 @@ textarea:not(.form-control) { border: 0 !important; } + + diff --git a/vue/src/components/BottomNavigationBar.vue b/vue/src/components/BottomNavigationBar.vue index 3801d9bd..23b0a244 100644 --- a/vue/src/components/BottomNavigationBar.vue +++ b/vue/src/components/BottomNavigationBar.vue @@ -108,4 +108,4 @@ export default { -o-transform: translate(-50%, 0); transform: translate(-50%, 0); } - \ No newline at end of file + diff --git a/vue/src/components/Buttons/RecipeSwitcher.vue b/vue/src/components/Buttons/RecipeSwitcher.vue index c724eadb..f001cc52 100644 --- a/vue/src/components/Buttons/RecipeSwitcher.vue +++ b/vue/src/components/Buttons/RecipeSwitcher.vue @@ -231,7 +231,7 @@ export default { font-size: 1.25rem; line-height: 1; background-color: transparent; - border: 1px solid rgba(46, 46, 46, 0.5); + border: 1px solid rgba(46, 46, 46, 0.1); border-radius: 0.1875rem; z-index: 1001; } diff --git a/vue/src/components/CookbookSlider.vue b/vue/src/components/CookbookSlider.vue index f2ccbb9a..71be6846 100644 --- a/vue/src/components/CookbookSlider.vue +++ b/vue/src/components/CookbookSlider.vue @@ -20,7 +20,7 @@ - +
@@ -57,10 +57,7 @@ export default { } }, mounted(){ - let apiClient = new ApiApiFactory() - apiClient.retrieveSpace(window.ACTIVE_SPACE_ID).then(r => { - this.use_plural = r.data.use_plural - }) + }, data() { return { @@ -69,7 +66,6 @@ export default { bounce_left: false, bounce_right: false, cookbook_editing: false, - use_plural: false, } }, methods: { diff --git a/vue/src/components/GenericHorizontalCard.vue b/vue/src/components/GenericHorizontalCard.vue index ed43a1a2..f65b2edc 100644 --- a/vue/src/components/GenericHorizontalCard.vue +++ b/vue/src/components/GenericHorizontalCard.vue @@ -76,8 +76,7 @@
@@ -160,7 +159,6 @@ export default { recipe_count: { type: String, default: "numrecipe" }, recipes: { type: String, default: "recipes" }, show_context_menu: { type: Boolean, default: true }, - use_plural: { type: Boolean, default: false}, }, data() { return { diff --git a/vue/src/components/IngredientComponent.vue b/vue/src/components/IngredientComponent.vue index eb26b87a..18876f06 100644 --- a/vue/src/components/IngredientComponent.vue +++ b/vue/src/components/IngredientComponent.vue @@ -7,7 +7,7 @@ - +