Compare commits

...

71 Commits

Author SHA1 Message Date
vabene1111
1be2e9fbb2 Merge branch 'develop' 2025-01-21 16:34:26 +01:00
vabene1111
7c93eededf fixed RecipeImageSerializer 2025-01-20 09:43:43 +01:00
Yigit
1b17031523 Translated using Weblate (Turkish)
Currently translated at 100.0% (570 of 570 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/tr/
2025-01-20 05:20:47 +00:00
Yigit
2d76c3e84c Translated using Weblate (Turkish)
Currently translated at 13.7% (67 of 488 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/tr/
2025-01-20 05:20:47 +00:00
vabene1111
03dd4370b9 update nextcloud import docs 2025-01-19 18:44:09 +01:00
smilerz
157af15a2a added (',', ';', ':') to notes tokenization in ingredient_parser.py 2025-01-18 09:29:09 -06:00
vabene1111
b930ecdcd0 Merge branch 'develop' 2025-01-18 12:49:49 +01:00
vabene1111
100242f0a6 Merge pull request #3498 from TandoorRecipes/dependabot/pip/pytubefix-8.12.0
Bump pytubefix from 8.9.0 to 8.12.0
2025-01-18 12:48:23 +01:00
vabene1111
d695f71d36 Merge pull request #3497 from mitcdh/develop
Prevent paprika.py from importing empty image_url content
2025-01-18 12:47:53 +01:00
dependabot[bot]
5d60b7a67c Bump pytubefix from 8.9.0 to 8.12.0
Bumps [pytubefix](https://github.com/juanbindez/pytubefix) from 8.9.0 to 8.12.0.
- [Release notes](https://github.com/juanbindez/pytubefix/releases)
- [Commits](https://github.com/juanbindez/pytubefix/compare/v8.9.0...v8.12.0)

---
updated-dependencies:
- dependency-name: pytubefix
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-18 11:47:22 +00:00
vabene1111
5d5d89dab9 Merge pull request #3477 from TandoorRecipes/dependabot/pip/pytubefix-8.9.0
Bump pytubefix from 8.5.1 to 8.9.0
2025-01-18 12:46:53 +01:00
vabene1111
35a625e04b Merge pull request #3476 from TandoorRecipes/dependabot/pip/django-tables2-2.7.4
Bump django-tables2 from 2.7.0 to 2.7.4
2025-01-18 12:46:45 +01:00
vabene1111
1a2d3bb441 Merge pull request #3474 from TandoorRecipes/dependabot/pip/whitenoise-6.8.2
Bump whitenoise from 6.7.0 to 6.8.2
2025-01-18 12:46:35 +01:00
vabene1111
2e3ac02afb Merge pull request #3473 from TandoorRecipes/dependabot/pip/redis-5.2.1
Bump redis from 5.2.0 to 5.2.1
2025-01-18 12:46:29 +01:00
vabene1111
a5b8a65b7d actually fixed test 2025-01-18 11:33:51 +01:00
vabene1111
dc320f2e6d Merge branch 'develop' 2025-01-18 09:30:51 +01:00
vabene1111
acbca83553 fixed test to reflect new permission 2025-01-18 09:30:43 +01:00
vabene1111
cb26c5dfc8 allow gif 2025-01-18 09:23:56 +01:00
vabene1111
b5c4174700 default mediafiles content disposition header attatchement 2025-01-18 09:22:46 +01:00
vabene1111
3e37d11c6a restrict file upload to certain types 2025-01-18 09:22:29 +01:00
vabene1111
36e83a9d01 restrict local external recipes to superusers and restrict file path/type 2025-01-18 08:57:46 +01:00
vabene1111
efcd759869 Merge pull request #3496 from TandoorRecipes/dependabot/pip/django-4.2.18
Bump django from 4.2.17 to 4.2.18
2025-01-18 08:11:35 +01:00
Mitchell Hewes
9f8830b341 Prevent paprika.py from importing empty image_url content 2025-01-17 15:04:28 +01:00
dependabot[bot]
7c81396ec5 Bump django from 4.2.17 to 4.2.18
Bumps [django](https://github.com/django/django) from 4.2.17 to 4.2.18.
- [Commits](https://github.com/django/django/compare/4.2.17...4.2.18)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-17 13:58:22 +00:00
smilerz
9b50665375 bump recipe-scrapers
fixes #3495
2025-01-17 07:57:30 -06:00
Anton Shevtsov
83795581e6 Translated using Weblate (Ukrainian)
Currently translated at 44.3% (253 of 570 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/uk/
2025-01-16 18:58:38 +00:00
Anton Shevtsov
af51524109 Translated using Weblate (Ukrainian)
Currently translated at 2.8% (14 of 488 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/uk/
2025-01-16 18:58:38 +00:00
vabene1111
738aa12243 Merge branch 'develop' 2025-01-05 11:38:52 +01:00
vabene1111
f25de4b4ce remove healthcheck 2025-01-05 11:38:35 +01:00
vabene1111
698aa5a753 Merge branch 'develop' 2025-01-01 09:24:51 +01:00
vabene1111
6444680e06 Merge pull request #3475 from TandoorRecipes/dependabot/pip/cryptography-44.0.0
Bump cryptography from 43.0.1 to 44.0.0
2025-01-01 08:16:19 +01:00
dependabot[bot]
38e1db9c53 Bump pytubefix from 8.5.1 to 8.9.0
Bumps [pytubefix](https://github.com/juanbindez/pytubefix) from 8.5.1 to 8.9.0.
- [Release notes](https://github.com/juanbindez/pytubefix/releases)
- [Commits](https://github.com/juanbindez/pytubefix/compare/v8.5.1...v8.9.0)

---
updated-dependencies:
- dependency-name: pytubefix
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-01 00:33:54 +00:00
dependabot[bot]
d71c929ba8 Bump django-tables2 from 2.7.0 to 2.7.4
Bumps [django-tables2](https://github.com/jieter/django-tables2) from 2.7.0 to 2.7.4.
- [Changelog](https://github.com/jieter/django-tables2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jieter/django-tables2/compare/v2.7.0...v2.7.4)

---
updated-dependencies:
- dependency-name: django-tables2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-01 00:33:51 +00:00
dependabot[bot]
c604369e86 Bump cryptography from 43.0.1 to 44.0.0
Bumps [cryptography](https://github.com/pyca/cryptography) from 43.0.1 to 44.0.0.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/43.0.1...44.0.0)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-01 00:33:49 +00:00
dependabot[bot]
4865b742c7 Bump whitenoise from 6.7.0 to 6.8.2
Bumps [whitenoise](https://github.com/evansd/whitenoise) from 6.7.0 to 6.8.2.
- [Changelog](https://github.com/evansd/whitenoise/blob/main/docs/changelog.rst)
- [Commits](https://github.com/evansd/whitenoise/compare/6.7.0...6.8.2)

---
updated-dependencies:
- dependency-name: whitenoise
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-01 00:33:45 +00:00
dependabot[bot]
1246549f4b Bump redis from 5.2.0 to 5.2.1
Bumps [redis](https://github.com/redis/redis-py) from 5.2.0 to 5.2.1.
- [Release notes](https://github.com/redis/redis-py/releases)
- [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES)
- [Commits](https://github.com/redis/redis-py/compare/v5.2.0...v5.2.1)

---
updated-dependencies:
- dependency-name: redis
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-01 00:33:42 +00:00
vabene1111
79abb8bf8f Merge branch 'develop' 2024-12-29 13:46:24 +01:00
vabene1111
fd4236672e update gitignore like vue3 branch 2024-12-29 13:46:17 +01:00
vabene1111
00148a2993 made shopping list compatible with SLR entries without a recipe 2024-12-29 13:44:43 +01:00
vabene1111
359fcb24cf fixed social signup form 2024-12-29 13:42:12 +01:00
vabene1111
f5d7919f72 Merge pull request #3448 from igorsantos07/patch-1
Update system.html: Django Recipes > Tandoor
2024-12-28 08:26:53 +01:00
vabene1111
86c4278553 Merge pull request #3454 from TandoorRecipes/dependabot/pip/jinja2-3.1.5
Bump jinja2 from 3.1.4 to 3.1.5
2024-12-28 08:26:44 +01:00
dependabot[bot]
2a5c0bb740 Bump jinja2 from 3.1.4 to 3.1.5
Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.4 to 3.1.5.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.1.4...3.1.5)

---
updated-dependencies:
- dependency-name: jinja2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-28 07:25:33 +00:00
Igor Santos
432dfa9e86 Update system.html: Django Recipes > Tandoor 2024-12-24 02:28:21 -03:00
vabene1111
f61a8371f4 Revert "added user filkes to recipe and added is_image flag to user file"
This reverts commit 0bcdf5e0a3.
2024-12-22 12:12:37 +01:00
vabene1111
0bcdf5e0a3 added user filkes to recipe and added is_image flag to user file 2024-12-22 12:05:47 +01:00
vabene1111
169f799a23 Merge pull request #3428 from hawthorc/develop
Add note about Python 3.12 dependency to manual.md
2024-12-11 15:19:59 +01:00
vabene1111
942d1130a1 Merge pull request #3416 from zodac/develop
Adding healthcheck to docker image
2024-12-11 15:17:28 +01:00
vabene1111
64cc20aed2 Merge pull request #3426 from TandoorRecipes/dependabot/pip/icalendar-6.1.0
Bump icalendar from 5.0.11 to 6.1.0
2024-12-11 15:12:09 +01:00
vabene1111
3a6731ec8d Merge pull request #3425 from TandoorRecipes/dependabot/pip/pytest-factoryboy-2.7.0
Bump pytest-factoryboy from 2.6.0 to 2.7.0
2024-12-11 15:11:32 +01:00
vabene1111
e6f11a17b9 Merge pull request #3423 from TandoorRecipes/dependabot/pip/pytest-django-4.9.0
Bump pytest-django from 4.8.0 to 4.9.0
2024-12-11 15:11:17 +01:00
vabene1111
cc1cd610e7 Merge pull request #3424 from TandoorRecipes/dependabot/pip/crispy-bootstrap4-2024.10
Bump crispy-bootstrap4 from 2024.1 to 2024.10
2024-12-11 15:10:19 +01:00
vabene1111
6a3b5ee844 Merge pull request #3431 from TandoorRecipes/dependabot/pip/django-4.2.17
Bump django from 4.2.16 to 4.2.17
2024-12-11 15:09:46 +01:00
Matjaž T
49b119571e Translated using Weblate (Slovenian)
Currently translated at 100.0% (570 of 570 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/sl/
2024-12-10 07:58:36 +00:00
Vincenzo Reale
e024e3deb0 Translated using Weblate (Italian)
Currently translated at 100.0% (488 of 488 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/it/
2024-12-09 00:58:36 +00:00
dependabot[bot]
7ccedb559d Bump django from 4.2.16 to 4.2.17
Bumps [django](https://github.com/django/django) from 4.2.16 to 4.2.17.
- [Commits](https://github.com/django/django/compare/4.2.16...4.2.17)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-06 18:57:23 +00:00
zodac
103daf000d Using --spider for healthcheck, which performs a HEAD request instead of a GET request 2024-12-02 20:44:12 +13:00
Vincenzo Reale
70df456307 Translated using Weblate (Italian)
Currently translated at 100.0% (488 of 488 strings)

Translation: Tandoor/Recipes Backend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-backend/it/
2024-12-02 04:53:51 +00:00
Carter Hawthorne
375174ee41 Add note about Python 3.12 dependency to manual.md 2024-12-01 18:38:38 -08:00
dependabot[bot]
f19beba014 Bump icalendar from 5.0.11 to 6.1.0
Bumps [icalendar](https://github.com/collective/icalendar) from 5.0.11 to 6.1.0.
- [Release notes](https://github.com/collective/icalendar/releases)
- [Changelog](https://github.com/collective/icalendar/blob/main/CHANGES.rst)
- [Commits](https://github.com/collective/icalendar/compare/v5.0.11...v6.1.0)

---
updated-dependencies:
- dependency-name: icalendar
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-01 00:39:31 +00:00
dependabot[bot]
865756e4b2 Bump pytest-factoryboy from 2.6.0 to 2.7.0
Bumps [pytest-factoryboy](https://github.com/pytest-dev/pytest-factoryboy) from 2.6.0 to 2.7.0.
- [Changelog](https://github.com/pytest-dev/pytest-factoryboy/blob/master/CHANGES.rst)
- [Commits](https://github.com/pytest-dev/pytest-factoryboy/compare/2.6.0...2.7.0)

---
updated-dependencies:
- dependency-name: pytest-factoryboy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-01 00:39:28 +00:00
dependabot[bot]
41f834db08 Bump crispy-bootstrap4 from 2024.1 to 2024.10
Bumps [crispy-bootstrap4](https://github.com/django-crispy-forms/crispy-bootstrap4) from 2024.1 to 2024.10.
- [Release notes](https://github.com/django-crispy-forms/crispy-bootstrap4/releases)
- [Changelog](https://github.com/django-crispy-forms/crispy-bootstrap4/blob/main/CHANGELOG.md)
- [Commits](https://github.com/django-crispy-forms/crispy-bootstrap4/compare/2024.1...2024.10)

---
updated-dependencies:
- dependency-name: crispy-bootstrap4
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-01 00:39:26 +00:00
dependabot[bot]
2c94753a5a Bump pytest-django from 4.8.0 to 4.9.0
Bumps [pytest-django](https://github.com/pytest-dev/pytest-django) from 4.8.0 to 4.9.0.
- [Release notes](https://github.com/pytest-dev/pytest-django/releases)
- [Changelog](https://github.com/pytest-dev/pytest-django/blob/main/docs/changelog.rst)
- [Commits](https://github.com/pytest-dev/pytest-django/compare/v4.8.0...v4.9.0)

---
updated-dependencies:
- dependency-name: pytest-django
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-01 00:39:23 +00:00
zodac
0e05c77fa7 Adding healthcheck to docker image 2024-11-29 14:15:24 +13:00
vabene1111
793c152b26 Merge pull request #3412 from lavanyamehn/duplicate_urls
Display a warning message when duplicate recipe is imported
2024-11-27 15:50:54 +01:00
Lavanya Mehndiratta
9df75f551c Changed functionality to only display a warning message 2024-11-26 18:09:55 -05:00
vabene1111
da49280ef2 Merge branch 'develop' 2024-11-26 17:29:57 +01:00
vabene1111
e6087d5129 use Sandbox Environment to render templates 2024-11-26 17:18:47 +01:00
vabene1111
4f9bff20c8 Merge pull request #3411 from bishtawi/bishtawi/secret-files
Support reading more secrets from files
2024-11-25 16:46:56 +01:00
Anders Obro
683f1ac10a Translated using Weblate (Danish)
Currently translated at 100.0% (570 of 570 strings)

Translation: Tandoor/Recipes Frontend
Translate-URL: http://translate.tandoor.dev/projects/tandoor/recipes-frontend/da/
2024-11-25 12:45:13 +00:00
Bishtawi
e844d2995a Support reading secrets from files 2024-11-24 12:31:17 -08:00
33 changed files with 322 additions and 154 deletions

2
.gitignore vendored
View File

@@ -84,3 +84,5 @@ vue3/.vite
# Configs
vetur.config.js
venv/
.idea/easy-i18n.xml
cookbook/static/vue3

View File

@@ -35,6 +35,13 @@ RUN apk add --no-cache --virtual .build-deps gcc musl-dev postgresql-dev zlib-de
#Copy project and execute it.
COPY . ./
# commented for now https://github.com/TandoorRecipes/recipes/issues/3478
#HEALTHCHECK --interval=30s \
# --timeout=5s \
# --start-period=10s \
# --retries=3 \
# CMD [ "/usr/bin/wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:8080/openapi" ]
# collect information from git repositories
RUN /opt/recipes/venv/bin/python version.py
# delete git repositories to reduce image size

14
boot.sh
View File

@@ -29,6 +29,18 @@ if [ -z "${SECRET_KEY}" ]; then
display_warning "The environment variable 'SECRET_KEY' (or 'SECRET_KEY_FILE' that points to an existing file) is not set but REQUIRED for running Tandoor!"
fi
if [ -f "${AUTH_LDAP_BIND_PASSWORD_FILE}" ]; then
export AUTH_LDAP_BIND_PASSWORD=$(cat "$AUTH_LDAP_BIND_PASSWORD_FILE")
fi
if [ -f "${EMAIL_HOST_PASSWORD_FILE}" ]; then
export EMAIL_HOST_PASSWORD=$(cat "$EMAIL_HOST_PASSWORD_FILE")
fi
if [ -f "${SOCIALACCOUNT_PROVIDERS_FILE}" ]; then
export SOCIALACCOUNT_PROVIDERS=$(cat "$SOCIALACCOUNT_PROVIDERS_FILE")
fi
echo "Waiting for database to be ready..."
@@ -83,4 +95,4 @@ if [ "$ipv6_disable" -eq 0 ]; then
exec gunicorn -b "[::]:$TANDOOR_PORT" --workers $GUNICORN_WORKERS --threads $GUNICORN_THREADS --access-logfile - --error-logfile - --log-level $GUNICORN_LOG_LEVEL recipes.wsgi
else
exec gunicorn -b ":$TANDOOR_PORT" --workers $GUNICORN_WORKERS --threads $GUNICORN_THREADS --access-logfile - --error-logfile - --log-level $GUNICORN_LOG_LEVEL recipes.wsgi
fi
fi

View File

@@ -1,6 +1,8 @@
from datetime import datetime
from allauth.account.forms import ResetPasswordForm, SignupForm
from allauth.socialaccount.forms import SignupForm as SocialSignupForm
from django import forms
from django.conf import settings
from django.core.exceptions import ValidationError
@@ -14,15 +16,13 @@ from .models import Comment, InviteLink, Keyword, Recipe, SearchPreference, Spac
class SelectWidget(widgets.Select):
class Media:
js = ('custom/js/form_select.js', )
js = ('custom/js/form_select.js',)
class MultiSelectWidget(widgets.SelectMultiple):
class Media:
js = ('custom/js/form_multiselect.js', )
js = ('custom/js/form_multiselect.js',)
# Yes there are some stupid browsers that still dont support this but
@@ -139,7 +139,7 @@ class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('text', )
fields = ('text',)
labels = {'text': _('Add your comment: '), }
widgets = {'text': forms.Textarea(attrs={'rows': 2, 'cols': 15}), }
@@ -161,7 +161,6 @@ class StorageForm(forms.ModelForm):
help_texts = {'url': _('Leave empty for dropbox and enter only base url for nextcloud (<code>/remote.php/webdav/</code> is added automatically)'), }
class ConnectorConfigForm(forms.ModelForm):
enabled = forms.BooleanField(
help_text="Is the connector enabled",
@@ -315,6 +314,18 @@ class AllAuthSignupForm(SignupForm):
pass
class AllAuthSocialSignupForm(SocialSignupForm):
terms = forms.BooleanField(label=_('Accept Terms and Privacy'))
def __init__(self, **kwargs):
super().__init__(**kwargs)
if settings.PRIVACY_URL == '' and settings.TERMS_URL == '':
self.fields.pop('terms')
def signup(self, request, user):
pass
class CustomPasswordResetForm(ResetPasswordForm):
captcha = hCaptchaField()
@@ -345,12 +356,13 @@ class SearchPreferenceForm(forms.ModelForm):
help_texts = {
'search': _('Select type method of search. Click <a href="/docs/search/">here</a> for full description of choices.'), 'lookup':
_('Use fuzzy matching on units, keywords and ingredients when editing and importing recipes.'), 'unaccent':
_('Fields to search ignoring accents. Selecting this option can improve or degrade search quality depending on language'), 'icontains':
_("Fields to search for partial matches. (e.g. searching for 'Pie' will return 'pie' and 'piece' and 'soapie')"), 'istartswith':
_("Fields to search for beginning of word matches. (e.g. searching for 'sa' will return 'salad' and 'sandwich')"), 'trigram':
_("Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) Note: this option will conflict with 'web' and 'raw' methods of search."), 'fulltext':
_("Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods only function with fulltext fields."),
_('Use fuzzy matching on units, keywords and ingredients when editing and importing recipes.'), 'unaccent':
_('Fields to search ignoring accents. Selecting this option can improve or degrade search quality depending on language'), 'icontains':
_("Fields to search for partial matches. (e.g. searching for 'Pie' will return 'pie' and 'piece' and 'soapie')"), 'istartswith':
_("Fields to search for beginning of word matches. (e.g. searching for 'sa' will return 'salad' and 'sandwich')"), 'trigram':
_("Fields to 'fuzzy' search. (e.g. searching for 'recpie' will find 'recipe'.) Note: this option will conflict with 'web' and 'raw' methods of search."),
'fulltext':
_("Fields to full text search. Note: 'web', 'phrase', and 'raw' search methods only function with fulltext fields."),
}
labels = {
@@ -360,5 +372,5 @@ class SearchPreferenceForm(forms.ModelForm):
widgets = {
'search': SelectWidget, 'unaccent': MultiSelectWidget, 'icontains': MultiSelectWidget, 'istartswith': MultiSelectWidget, 'trigram': MultiSelectWidget, 'fulltext':
MultiSelectWidget,
MultiSelectWidget,
}

View File

@@ -35,6 +35,20 @@ def get_filetype(name):
return '.jpeg'
def is_file_type_allowed(filename, image_only=False):
is_file_allowed = False
allowed_file_types = ['.pdf','.docx', '.xlsx']
allowed_image_types = ['.png', '.jpg', '.jpeg', '.gif']
check_list = allowed_image_types
if not image_only:
check_list += allowed_file_types
for file_type in check_list:
if filename.endswith(file_type):
is_file_allowed = True
return is_file_allowed
# TODO this whole file needs proper documentation, refactoring, and testing
# TODO also add env variable to define which images sizes should be compressed
# filetype argument can not be optional, otherwise this function will treat all images as if they were a jpeg

View File

@@ -118,7 +118,7 @@ class IngredientParser:
note = ''
start = 0
# search for first occurrence of an argument ending in a comma
while start < len(tokens) and not tokens[start].endswith(','):
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 food

View File

@@ -3,6 +3,8 @@ from gettext import gettext as _
import bleach
import markdown as md
from jinja2 import Template, TemplateSyntaxError, UndefinedError
from jinja2.exceptions import SecurityError
from jinja2.sandbox import SandboxedEnvironment
from markdown.extensions.tables import TableExtension
from cookbook.helper.mdx_attributes import MarkdownFormatExtension
@@ -89,11 +91,13 @@ def render_instructions(step): # TODO deduplicate markdown cleanup code
return f"<scalable-number v-bind:number='{bleach.clean(str(number))}' v-bind:factor='ingredient_factor'></scalable-number>"
try:
template = Template(instructions)
instructions = template.render(ingredients=ingredients, scale=scale)
env = SandboxedEnvironment()
instructions = env.from_string(instructions).render(ingredients=ingredients, scale=scale)
except TemplateSyntaxError:
return _('Could not parse template code.') + ' Error: Template Syntax broken'
except UndefinedError:
return _('Could not parse template code.') + ' Error: Undefined Error'
except SecurityError:
return _('Could not parse template code.') + ' Error: Security Error'
return instructions

View File

@@ -94,7 +94,8 @@ class Paprika(Integration):
url = recipe_json.get("image_url", None)
if validate_import_url(url):
response = requests.get(url)
self.import_recipe_image(recipe, BytesIO(response.content))
if response.status_code == 200 and len(response.content) > 0:
self.import_recipe_image(recipe, BytesIO(response.content))
except Exception:
pass

View File

@@ -12,7 +12,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-08-01 15:04+0200\n"
"PO-Revision-Date: 2024-11-01 06:58+0000\n"
"PO-Revision-Date: 2024-12-09 00:58+0000\n"
"Last-Translator: Vincenzo Reale <smart2128vr@gmail.com>\n"
"Language-Team: Italian <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/it/>\n"
@@ -21,7 +21,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.6.2\n"
"X-Generator: Weblate 5.8.4\n"
#: .\cookbook\forms.py:45
msgid ""
@@ -520,7 +520,7 @@ msgstr "Web"
#: .\cookbook\models.py:1411 .\cookbook\templates\search_info.html:47
msgid "Raw"
msgstr "Raw"
msgstr "Crudo"
#: .\cookbook\models.py:1467
msgid "Food Alias"
@@ -1440,8 +1440,9 @@ msgid ""
"\"noreferrer noopener\" target=\"_blank\">this one.</a>"
msgstr ""
"Le tabelle in markdown sono difficili da creare a mano. Si raccomanda "
"l'utilizzo di un editor di come <a href=\"https://www.tablesgenerator.com/"
"markdown_tables\" rel=\"noreferrer noopener\" target=\"_blank\">questo.</a>"
"l'utilizzo di un editor di tabelle come <a href=\"https://www.tablesgenerator"
".com/markdown_tables\" rel=\"noreferrer noopener\" target=\"_blank\""
">questo.</a>"
#: .\cookbook\templates\markdown_info.html:155
#: .\cookbook\templates\markdown_info.html:157
@@ -2203,8 +2204,8 @@ msgstr ""
" Le migrazioni non andate a buon fine probabilmente causeranno il "
"malfunzionamento di parti importanti dell'applicazione.\n"
" Se una migrazione non riesce, assicurati di avere la versione "
"più recente e, in tal caso, pubblica il registro della migrazione e la "
"panoramica di seguito in una segnalazione di problema su GitHub.\n"
"più recente e, in tal caso, pubblica il registro della migrazione e il "
"riepilogo che segue in una segnalazione di problema su GitHub.\n"
" "
#: .\cookbook\templates\system.html:182
@@ -2765,7 +2766,7 @@ msgid ""
"but not recommended as some features only work with postgres databases."
msgstr ""
"Questa applicazione non è in esecuzione con un database Postgres. Va bene, "
"ma non è consigliato perché alcune funzionalità sono disponibili solo con un "
"ma non è consigliato perché alcune funzionalità sono disponibili solo con "
"database Postgres."
#: .\cookbook\views\views.py:360

View File

@@ -11,8 +11,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-08-01 15:04+0200\n"
"PO-Revision-Date: 2024-07-03 16:38+0000\n"
"Last-Translator: Taylan TATLI <uyelik-tandoor@tatli.me>\n"
"PO-Revision-Date: 2025-01-20 05:20+0000\n"
"Last-Translator: Yigit <yigit.gungor@outlook.com>\n"
"Language-Team: Turkish <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/tr/>\n"
"Language: tr\n"
@@ -20,7 +20,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Weblate 5.4.2\n"
"X-Generator: Weblate 5.8.4\n"
#: .\cookbook\forms.py:45
msgid ""
@@ -199,7 +199,7 @@ msgstr ""
#: .\cookbook\forms.py:350
msgid "Search Method"
msgstr ""
msgstr "Arama Metodu"
#: .\cookbook\forms.py:350
msgid "Fuzzy Lookups"
@@ -207,15 +207,15 @@ msgstr ""
#: .\cookbook\forms.py:350
msgid "Ignore Accent"
msgstr ""
msgstr "Harflerdeki Vurguları Görmezden Gel"
#: .\cookbook\forms.py:350
msgid "Partial Match"
msgstr ""
msgstr "Kısmi Eşleşme"
#: .\cookbook\forms.py:350
msgid "Starts With"
msgstr ""
msgstr "İle başlayan"
#: .\cookbook\forms.py:351
msgid "Fuzzy Search"
@@ -223,18 +223,20 @@ msgstr ""
#: .\cookbook\forms.py:351
msgid "Full Text"
msgstr ""
msgstr "Tam Metin"
#: .\cookbook\helper\AllAuthCustomAdapter.py:41
msgid ""
"In order to prevent spam, the requested email was not send. Please wait a "
"few minutes and try again."
msgstr ""
"İstenmeyen e-postayı önlemek için istenen e-posta gönderilemedi. Lütfen "
"birkaç dakika bekleyin ve tekrar deneyin."
#: .\cookbook\helper\permission_helper.py:164
#: .\cookbook\helper\permission_helper.py:187 .\cookbook\views\views.py:117
msgid "You are not logged in and therefore cannot view this page!"
msgstr ""
msgstr "Giriş yapmadınız ve bu nedenle bu sayfayı görüntüleyemezsiniz!"
#: .\cookbook\helper\permission_helper.py:168
#: .\cookbook\helper\permission_helper.py:174
@@ -247,68 +249,68 @@ msgstr ""
#: .\cookbook\helper\permission_helper.py:341 .\cookbook\views\data.py:35
#: .\cookbook\views\views.py:127 .\cookbook\views\views.py:131
msgid "You do not have the required permissions to view this page!"
msgstr ""
msgstr "Bu sayfayı görüntülemek için gerekli izinlere sahip değilsiniz!"
#: .\cookbook\helper\permission_helper.py:192
#: .\cookbook\helper\permission_helper.py:215
#: .\cookbook\helper\permission_helper.py:237
#: .\cookbook\helper\permission_helper.py:252
msgid "You cannot interact with this object as it is not owned by you!"
msgstr ""
msgstr "Bu nesne size ait olmadığı için onunla etkileşime giremezsiniz!"
#: .\cookbook\helper\permission_helper.py:402
msgid "You have reached the maximum number of recipes for your space."
msgstr ""
msgstr "Alanınız için maksimum tarif sayısına ulaştınız."
#: .\cookbook\helper\permission_helper.py:414
msgid "You have more users than allowed in your space."
msgstr ""
msgstr "Alanınızda izin verilenden daha fazla kullanıcı var."
#: .\cookbook\helper\recipe_url_import.py:310
msgid "reverse rotation"
msgstr ""
msgstr "ters dönüş"
#: .\cookbook\helper\recipe_url_import.py:311
msgid "careful rotation"
msgstr ""
msgstr "dikkatli dönüş"
#: .\cookbook\helper\recipe_url_import.py:312
msgid "knead"
msgstr ""
msgstr "yoğur"
#: .\cookbook\helper\recipe_url_import.py:313
msgid "thicken"
msgstr ""
msgstr "kalınlaştır"
#: .\cookbook\helper\recipe_url_import.py:314
msgid "warm up"
msgstr ""
msgstr "ısıt"
#: .\cookbook\helper\recipe_url_import.py:315
msgid "ferment"
msgstr ""
msgstr "mayala"
#: .\cookbook\helper\recipe_url_import.py:316
msgid "sous-vide"
msgstr ""
msgstr "sous-vide"
#: .\cookbook\helper\shopping_helper.py:150
msgid "You must supply a servings size"
msgstr ""
msgstr "Bir porsiyon büyüklüğü vermelisiniz"
#: .\cookbook\helper\template_helper.py:95
#: .\cookbook\helper\template_helper.py:97
msgid "Could not parse template code."
msgstr ""
msgstr "Şablon kodu ayrıştırılamadı."
#: .\cookbook\integration\copymethat.py:44
#: .\cookbook\integration\melarecipes.py:37
msgid "Favorite"
msgstr ""
msgstr "Favori"
#: .\cookbook\integration\copymethat.py:50
msgid "I made this"
msgstr ""
msgstr "Bunu yaptım"
#: .\cookbook\integration\integration.py:209
msgid ""
@@ -324,28 +326,28 @@ msgstr ""
#: .\cookbook\integration\integration.py:217
msgid "The following recipes were ignored because they already existed:"
msgstr ""
msgstr "Aşağıdaki tarifler zaten mevcut olduğu için göz ardı edildi:"
#: .\cookbook\integration\integration.py:221
#, python-format
msgid "Imported %s recipes."
msgstr ""
msgstr "%s tarif içe aktarıldı."
#: .\cookbook\integration\openeats.py:28
msgid "Recipe source:"
msgstr ""
msgstr "Tarif kaynağı:"
#: .\cookbook\integration\paprika.py:49
msgid "Notes"
msgstr ""
msgstr "Notlar"
#: .\cookbook\integration\paprika.py:52
msgid "Nutritional Information"
msgstr ""
msgstr "Beslenme Bilgileri"
#: .\cookbook\integration\paprika.py:56
msgid "Source"
msgstr ""
msgstr "Kaynak"
#: .\cookbook\integration\recettetek.py:54
#: .\cookbook\integration\recipekeeper.py:70
@@ -354,23 +356,23 @@ msgstr ""
#: .\cookbook\integration\saffron.py:23
msgid "Servings"
msgstr ""
msgstr "Porsiyon"
#: .\cookbook\integration\saffron.py:25
msgid "Waiting time"
msgstr ""
msgstr "Bekleme süresi"
#: .\cookbook\integration\saffron.py:27
msgid "Preparation Time"
msgstr ""
msgstr "Hazırlık Süresi"
#: .\cookbook\integration\saffron.py:29 .\cookbook\templates\index.html:7
msgid "Cookbook"
msgstr ""
msgstr "Yemek kitabı"
#: .\cookbook\integration\saffron.py:31
msgid "Section"
msgstr ""
msgstr "Bölüm"
#: .\cookbook\management\commands\fix_duplicate_properties.py:15
msgid "Fixes foods with "
@@ -383,6 +385,8 @@ msgstr ""
#: .\cookbook\management\commands\rebuildindex.py:18
msgid "Only Postgresql databases use full text search, no index to rebuild"
msgstr ""
"Yalnızca Postgresql veritabanları tam metin araması kullanır, yeniden "
"oluşturulacak dizin yoktur"
#: .\cookbook\management\commands\rebuildindex.py:29
msgid "Recipe index rebuild complete."

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-08-01 15:04+0200\n"
"PO-Revision-Date: 2024-11-22 07:58+0000\n"
"Last-Translator: Oleh Hudyma <oleg.hudymaa@gmail.com>\n"
"PO-Revision-Date: 2025-01-16 18:58+0000\n"
"Last-Translator: Anton Shevtsov <ashevtsovs@gmail.com>\n"
"Language-Team: Ukrainian <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/uk/>\n"
"Language: uk\n"
@@ -18,7 +18,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 5.6.2\n"
"X-Generator: Weblate 5.8.4\n"
#: .\cookbook\forms.py:45
msgid ""
@@ -32,7 +32,7 @@ msgstr ""
#: .\cookbook\forms.py:62 .\cookbook\forms.py:246 .\cookbook\views\lists.py:103
msgid "Keywords"
msgstr ""
msgstr "Ключові слова"
#: .\cookbook\forms.py:62
msgid "Preparation time in minutes"
@@ -941,13 +941,13 @@ msgstr ""
#: .\cookbook\templates\ingredient_editor.html:7
#: .\cookbook\templates\ingredient_editor.html:13
msgid "Ingredient Editor"
msgstr ""
msgstr "Редактор Інгредієнтів"
#: .\cookbook\templates\base.html:275
#: .\cookbook\templates\export_response.html:7
#: .\cookbook\templates\test2.html:14 .\cookbook\templates\test2.html:20
msgid "Export"
msgstr ""
msgstr "Експорт"
#: .\cookbook\templates\base.html:287
msgid "Properties"

View File

@@ -12,21 +12,25 @@ class Local(Provider):
@staticmethod
def import_all(monitor):
if '/etc/' in monitor.path or '/root/' in monitor.path or '/mediafiles/' in monitor.path or '/usr/' in monitor.path:
return False
files = [f for f in listdir(monitor.path) if isfile(join(monitor.path, f))]
import_count = 0
for file in files:
path = monitor.path + '/' + file
if not Recipe.objects.filter(file_path__iexact=path, space=monitor.space).exists() and not RecipeImport.objects.filter(file_path=path, space=monitor.space).exists():
name = os.path.splitext(file)[0]
new_recipe = RecipeImport(
name=name,
file_path=path,
storage=monitor.storage,
space=monitor.space,
)
new_recipe.save()
import_count += 1
if file.endswith('.pdf') or file.endswith('.png') or file.endswith('.jpg') or file.endswith('.jpeg') or file.endswith('.gif'):
path = monitor.path + '/' + file
if not Recipe.objects.filter(file_path__iexact=path, space=monitor.space).exists() and not RecipeImport.objects.filter(file_path=path, space=monitor.space).exists():
name = os.path.splitext(file)[0]
new_recipe = RecipeImport(
name=name,
file_path=path,
storage=monitor.storage,
space=monitor.space,
)
new_recipe.save()
import_count += 1
log_entry = SyncLog(
status='SUCCESS',

View File

@@ -22,6 +22,7 @@ from rest_framework.fields import IntegerField
from cookbook.helper.CustomStorageClass import CachedS3Boto3Storage
from cookbook.helper.HelperFunctions import str2bool
from cookbook.helper.image_processing import is_file_type_allowed
from cookbook.helper.permission_helper import above_space_limit
from cookbook.helper.property_helper import FoodPropertyHelper
from cookbook.helper.shopping_helper import RecipeShoppingEditor
@@ -233,12 +234,17 @@ class UserFileSerializer(serializers.ModelSerializer):
raise ValidationError(_('You have reached your file upload limit.'))
def create(self, validated_data):
if not is_file_type_allowed(validated_data['file'].name):
return None
self.check_file_limit(validated_data)
validated_data['created_by'] = self.context['request'].user
validated_data['space'] = self.context['request'].space
return super().create(validated_data)
def update(self, instance, validated_data):
if not is_file_type_allowed(validated_data['file'].name):
return None
self.check_file_limit(validated_data)
return super().update(instance, validated_data)
@@ -958,6 +964,16 @@ class RecipeImageSerializer(WritableNestedModelSerializer):
image = serializers.ImageField(required=False, allow_null=True)
image_url = serializers.CharField(max_length=4096, required=False, allow_null=True)
def create(self, validated_data):
if 'image' in validated_data and not is_file_type_allowed(validated_data['image'].name, image_only=True):
return None
return super().create( validated_data)
def update(self, instance, validated_data):
if 'image' in validated_data and not is_file_type_allowed(validated_data['image'].name, image_only=True):
return None
return super().update(instance, validated_data)
class Meta:
model = Recipe
fields = ['image', 'image_url', ]

View File

@@ -1,6 +1,5 @@
{% extends "base.html" %}
{% load crispy_forms_filters %}
{% load crispy_forms_filters %}
{% load i18n %}
{% block title %}{% trans 'Register' %}{% endblock %}

View File

@@ -16,7 +16,6 @@
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}"/>
{% endif %}
<div class="form-group">
{{ form.username |as_crispy_field }}
</div>
@@ -30,7 +29,7 @@
<div class="form-group">
{{ form.terms |as_crispy_field }}
<small>
{% trans 'I accept the follwoing' %}
{% trans 'I accept the following' %}
{% if TERMS_URL != '' %}
<a href="{{ TERMS_URL }}" target="_blank"
rel="noreferrer nofollow">{% trans 'Terms and Conditions' %}</a>

View File

@@ -12,9 +12,9 @@
<h1>{% trans 'System' %}</h1>
{% blocktrans %}
Django Recipes is an open source free software application. It can be found on
<a href="https://github.com/vabene1111/recipes">GitHub</a>.
Changelogs can be found <a href="https://github.com/vabene1111/recipes/releases">here</a>.
Tandoor Recipes is an open source free software application. It can be found on
<a href="https://github.com/TandoorRecipes/recipes">GitHub</a>.
Changelogs can be found <a href="https://github.com/TandoorRecipes/recipes/releases">here</a>.
{% endblocktrans %}
<h3 class="mt-5">{% trans 'System Information' %}</h3>

View File

@@ -31,12 +31,12 @@ def test_edit_storage(storage_obj, a1_s1, a1_s2):
}
)
storage_obj.refresh_from_db()
assert r.status_code == 200
r_messages = [m for m in get_messages(r.wsgi_request)]
assert not any(m.level > messages.SUCCESS for m in r_messages)
assert r.status_code == 302
#r_messages = [m for m in get_messages(r.wsgi_request)]
#assert not any(m.level > messages.SUCCESS for m in r_messages)
assert storage_obj.password == '1234_pw'
assert storage_obj.token == '1234_token'
#assert storage_obj.password == '1234_pw'
#assert storage_obj.token == '1234_token'
r = a1_s2.post(
reverse('edit_storage', args={storage_obj.pk}),
@@ -54,7 +54,7 @@ def test_edit_storage(storage_obj, a1_s1, a1_s2):
['a_u', 302],
['g1_s1', 302],
['u1_s1', 302],
['a1_s1', 200],
['a1_s1', 302],
['g1_s2', 302],
['u1_s2', 302],
['a1_s2', 404],

View File

@@ -1455,13 +1455,21 @@ class RecipeUrlImportView(APIView):
url = serializer.validated_data.get('url', None)
data = unquote(serializer.validated_data.get('data', None))
duplicate = False
if url:
# Check for existing recipes with provided url
existing_recipe = Recipe.objects.filter(source_url=url).first()
if existing_recipe:
duplicate = True
if not url and not data:
return Response({'error': True, 'msg': _('Nothing to do.')}, status=status.HTTP_400_BAD_REQUEST)
elif url and not data:
if re.match('^(https?://)?(www\\.youtube\\.com|youtu\\.be)/.+$', url):
if validate_import_url(url):
return Response({'recipe_json': get_from_youtube_scraper(url, request), 'recipe_images': [], }, status=status.HTTP_200_OK)
return Response({'recipe_json': get_from_youtube_scraper(url, request), 'recipe_images': [], 'duplicate': duplicate}, status=status.HTTP_200_OK)
if re.match('^(.)*/view/recipe/[0-9]+/[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$', url):
recipe_json = requests.get(
url.replace('/view/recipe/', '/api/recipe/').replace(re.split('/view/recipe/[0-9]+', url)[1], '') + '?share='
@@ -1476,7 +1484,7 @@ class RecipeUrlImportView(APIView):
filetype=pathlib.Path(recipe_json['image']).suffix),
name=f'{uuid.uuid4()}_{recipe.pk}{pathlib.Path(recipe_json["image"]).suffix}')
recipe.save()
return Response({'link': request.build_absolute_uri(reverse('view_recipe', args={recipe.pk}))}, status=status.HTTP_201_CREATED)
return Response({'link': request.build_absolute_uri(reverse('view_recipe', args={recipe.pk})), 'duplicate': duplicate}, status=status.HTTP_201_CREATED)
else:
try:
if validate_import_url(url):
@@ -1511,6 +1519,7 @@ class RecipeUrlImportView(APIView):
return Response({
'recipe_json': helper.get_from_scraper(scrape, request),
'recipe_images': list(dict.fromkeys(get_images_from_soup(scrape.soup, url))),
'duplicate': duplicate
},
status=status.HTTP_200_OK)

View File

@@ -80,7 +80,7 @@ class SyncUpdate(GroupRequiredMixin, UpdateView, SpaceFormMixing):
def edit_storage(request, pk):
instance: Storage = get_object_or_404(Storage, pk=pk, space=request.space)
if not (instance.created_by == request.user or request.user.is_superuser):
if not request.user.is_superuser:
messages.add_message(request, messages.ERROR, _('You cannot edit this storage!'))
return HttpResponseRedirect(reverse('list_storage'))

View File

@@ -58,10 +58,16 @@ class StorageCreate(GroupRequiredMixin, CreateView):
obj = form.save(commit=False)
obj.created_by = self.request.user
obj.space = self.request.space
obj.save()
if self.request.space.demo or settings.HOSTED:
messages.add_message(self.request, messages.ERROR, _('This feature is not yet available in the hosted version of tandoor!'))
return redirect('index')
if not self.request.user.is_superuser:
messages.add_message(self.request, messages.ERROR, _('This feature is only available for the instance administrator (superuser)'))
return redirect('index')
obj.save()
return HttpResponseRedirect(reverse('edit_storage', kwargs={'pk': obj.pk}))
def get_context_data(self, **kwargs):

View File

@@ -1,8 +1,8 @@
Besides the normal django username and password authentication this application supports multiple
Besides the normal django username and password authentication this application supports multiple
methods of central account management and authentication.
## Allauth
[Django Allauth](https://django-allauth.readthedocs.io/en/latest/index.html) is an awesome project that
[Django Allauth](https://django-allauth.readthedocs.io/en/latest/index.html) is an awesome project that
allows you to use a [huge number](https://docs.allauth.org/en/latest/socialaccount/providers/index.html) of different
authentication providers.
@@ -11,8 +11,8 @@ They basically explain everything in their documentation, but the following is a
!!! warning "Public Providers"
If you choose Google, Github or any other publicly available service as your authentication provider anyone
with an account on that site can create an account on your installation.
A new account does not have any permission but it is still **not recommended** to give public access to
your installation.
A new account does not have any permission but it is still **not recommended** to give public access to
your installation.
Choose a provider from the [list](https://docs.allauth.org/en/latest/socialaccount/providers/index.html) and install it using the environment variable `SOCIAL_PROVIDERS` as shown
in the example below.
@@ -28,15 +28,15 @@ SOCIAL_PROVIDERS=allauth.socialaccount.providers.openid_connect,allauth.socialac
### Configuration, via environment
Depending on your authentication provider you **might need** to configure it.
This needs to be done through the settings system. To make the system flexible (allow multiple providers) and to
Depending on your authentication provider you **might need** to configure it.
This needs to be done through the settings system. To make the system flexible (allow multiple providers) and to
not require another file to be mounted into the container the configuration ins done through a single
environment variable. The downside of this approach is that the configuration needs to be put into a single line
as environment files loaded by docker compose don't support multiple lines for a single variable.
The line data needs to either be in json or as Python dictionary syntax.
Take the example configuration from the allauth docs, fill in your settings and then inline the whole object
Take the example configuration from the allauth docs, fill in your settings and then inline the whole object
(you can use a service like [www.freeformatter.com](https://www.freeformatter.com/json-formatter.html) for formatting).
Assign it to the additional `SOCIALACCOUNT_PROVIDERS` variable.
@@ -46,6 +46,13 @@ The example below is for a generic OIDC provider with PKCE enabled. Most values
SOCIALACCOUNT_PROVIDERS = "{ 'openid_connect': { 'OAUTH_PKCE_ENABLED': True, 'APPS': [ { 'provider_id': 'oidc', 'name': 'My-IDM', 'client_id': 'my_client_id', 'secret': 'my_client_secret', 'settings': { 'server_url': 'https://idm.example.com/oidc/recipes' } } ] } }"
```
Because this JSON contains sensitive data (client id and secret), you may instead choose to save the JSON in a file
and set the environment variable `SOCIALACCOUNT_PROVIDERS_FILE` to the path of the file containing the JSON.
```
SOCIALACCOUNT_PROVIDERS_FILE=/run/secrets/socialaccount_providers.txt
```
!!! success "Improvements ?"
There are most likely ways to achieve the same goal but with a cleaner or simpler system.
If you know such a way feel free to let me know.
@@ -81,7 +88,7 @@ SOCIALACCOUNT_PROVIDERS='{"openid_connect":{"APPS":[{"provider_id":"keycloak","n
You are now able to sign in using Keycloak after a restart of the service.
### Linking accounts
To link an account to an already existing normal user go to the settings page of the user and link it.
To link an account to an already existing normal user go to the settings page of the user and link it.
Here you can also unlink your account if you no longer want to use a social login method.
## LDAP
@@ -111,7 +118,7 @@ AUTH_LDAP_TLS_CACERTFILE=/etc/ssl/certs/own-ca.pem
If you just set `REMOTE_USER_AUTH=1` without any additional configuration, _anybody_ can authenticate with _any_ username!
!!! Info "Community Contributed Tutorial"
This tutorial was provided by a community member. We are not able to provide any support! Please only use, if you know what you are doing!
This tutorial was provided by a community member. We are not able to provide any support! Please only use, if you know what you are doing!
In order use external authentication (i.e. using a proxy auth like Authelia, Authentik, etc.) you will need to:

View File

@@ -75,24 +75,23 @@ structured information most of your recipe is going to be intact.
Follow these steps to import your recipes
1. Go to your Nextcloud Webinterface
2. Open the `Recipes` folder where your recipes are stored
3. Select the recipes you want to export or use the checkbox at the top of the list to select all of them
4. Click on the three dot **Actions** and press Download
2. Find the `Recipes` folder (usually located in the root directory of your account)
3. Download that folder to get your `Recipes.zip` which includes the folder `Recipes` and in that a folder for each recipe
4. Upload the `Recipes.zip` to Tandoor and import it
You will get a `Recipes.zip` file. Simply upload the file and choose the Nextcloud Cookbook type.
!!! WARNING "Folder Structure"
Importing only works if the folder structure is correct. If you do not use the standard path or create the
zip file in any other way make sure the structure is as follows
` Recipes.zip/
└── Recipes/
├── Recipe1/
│ ├── recipe.json
│ └── full.jpg
└── Recipe2/
├── recipe.json
└── full.jpg
`
Importing only works if the folder structure is correct. If you do not use the standard path or create the
zip file in any other way make sure the structure is as follows
` Recipes.zip/
└── Recipes/
├── Recipe1/
│ ├── recipe.json
│ └── full.jpg
└── Recipe2/
├── recipe.json
└── full.jpg
`
## Mealie
@@ -113,8 +112,7 @@ In order to import your Chowdown recipes simply create a `.zip` file from those
The folder structure should look as follows
!!! info "_recipes"
For some reason chowdown uses `_`before the`recipes`folder. To avoid confusion the import supports both
`\_recipes`and`recipes`
For some reason chowdown uses `_`before the`recipes`folder. To avoid confusion the import supports both `\_recipes`and`recipes`
```
Recipes.zip/

View File

@@ -3,7 +3,7 @@
These instructions are inspired from a standard django/gunicorn/postgresql instructions ([for example](https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-16-04))
!!! warning
Make sure to use Python 3.10 or higher, and ensure that `pip` is associated with Python 3. Depending on your system configuration, using `python` or `pip` might default to Python 2. Make sure your machine has at least 2048 MB of memory; otherwise, the `yarn build` process may fail with the error: `FATAL ERROR: Reached heap limit - Allocation failed: JavaScript heap out of memory`.
Make sure to use at least Python 3.10 (although 3.12 is preferred) or higher, and ensure that `pip` is associated with Python 3. Depending on your system configuration, using `python` or `pip` might default to Python 2. Make sure your machine has at least 2048 MB of memory; otherwise, the `yarn build` process may fail with the error: `FATAL ERROR: Reached heap limit - Allocation failed: JavaScript heap out of memory`.
## Prerequisites

View File

@@ -354,7 +354,7 @@ SOCIAL_PROVIDERS = allauth.socialaccount.providers.github, allauth.socialaccount
Allow authentication via the REMOTE-USER header (can be used for e.g. authelia).
!!! danger
Leave off if you don't know what you are doing! Enabling this without proper configuration will enable anybody
Leave off if you don't know what you are doing! Enabling this without proper configuration will enable anybody
to login with any username!
```
@@ -377,6 +377,14 @@ AUTH_LDAP_TLS_CACERTFILE=
AUTH_LDAP_START_TLS=
```
Instead of passing the LDAP password directly through the environment variable `AUTH_LDAP_BIND_PASSWORD`,
you can set the password in a file and set the environment variable `AUTH_LDAP_BIND_PASSWORD_FILE`
to the path of the file containing the ldap secret.
```
AUTH_LDAP_BIND_PASSWORD_FILE=/run/secrets/ldap_password.txt
```
### External Services
#### Email
@@ -396,6 +404,14 @@ EMAIL_USE_SSL=0
DEFAULT_FROM_EMAIL=
```
Instead of passing the email password directly through the environment variable `EMAIL_HOST_PASSWORD`,
you can set the password in a file and set the environment variable `EMAIL_HOST_PASSWORD_FILE`
to the path of the file containing the ldap secret.
```
EMAIL_HOST_PASSWORD_FILE=/run/secrets/email_password.txt
```
Optional settings (only copy the ones you need)
```
@@ -561,7 +577,7 @@ STICKY_NAV_PREF_DEFAULT=1
> default `100` - options: `0-X`
The default for the number of spaces a user can own. By setting to 0 space creation for users will be disabled.
The default for the number of spaces a user can own. By setting to 0 space creation for users will be disabled.
Superusers can always bypass this limit.
```
@@ -586,7 +602,7 @@ TZ=Europe/Berlin
#### Default Theme
> default `0` - options `1-X` (space ID)
Tandoors appearance can be changed on a user and space level but unauthenticated users always see the tandoor default style.
Tandoors appearance can be changed on a user and space level but unauthenticated users always see the tandoor default style.
With this setting you can specify the ID of a space of which the appearance settings should be applied if a user is not logged in.
```
@@ -633,7 +649,7 @@ DRF_THROTTLE_RECIPE_URL_IMPORT=60/hour
#### Default Space Limits
You might want to limit how many resources a user might create. The following settings apply automatically to newly
created spaces. These defaults can be changed in the admin view after a space has been created.
created spaces. These defaults can be changed in the admin view after a space has been created.
If unset, all settings default to unlimited/enabled

View File

@@ -8,6 +8,7 @@ server {
# serve media files
location /media/ {
alias /media/;
add_header Content-Disposition 'attachment; filename="$args"';
}
# pass requests for dynamic content to gunicorn
location / {

View File

@@ -66,7 +66,6 @@ LOGGING = {
},
}
# allow djangos wsgi server to server mediafiles
GUNICORN_MEDIA = bool(int(os.getenv('GUNICORN_MEDIA', False)))
@@ -247,14 +246,14 @@ MIDDLEWARE = [
]
if DEBUG_TOOLBAR:
MIDDLEWARE += ('debug_toolbar.middleware.DebugToolbarMiddleware', )
INSTALLED_APPS += ('debug_toolbar', )
MIDDLEWARE += ('debug_toolbar.middleware.DebugToolbarMiddleware',)
INSTALLED_APPS += ('debug_toolbar',)
SORT_TREE_BY_NAME = bool(int(os.getenv('SORT_TREE_BY_NAME', False)))
DISABLE_TREE_FIX_STARTUP = bool(int(os.getenv('DISABLE_TREE_FIX_STARTUP', False)))
if bool(int(os.getenv('SQL_DEBUG', False))):
MIDDLEWARE += ('recipes.middleware.SqlPrintingMiddleware', )
MIDDLEWARE += ('recipes.middleware.SqlPrintingMiddleware',)
if ENABLE_METRICS:
MIDDLEWARE += 'django_prometheus.middleware.PrometheusAfterMiddleware',
@@ -294,7 +293,6 @@ if LDAP_AUTH:
"handlers": ["console"]
}
AUTHENTICATION_BACKENDS += [
'django.contrib.auth.backends.ModelBackend',
'allauth.account.auth_backends.AuthenticationBackend',
@@ -564,6 +562,9 @@ ACCOUNT_EMAIL_SUBJECT_PREFIX = os.getenv('ACCOUNT_EMAIL_SUBJECT_PREFIX', '[Tando
# ACCOUNT_SIGNUP_FORM_CLASS = 'cookbook.forms.AllAuthSignupForm'
ACCOUNT_FORMS = {'signup': 'cookbook.forms.AllAuthSignupForm', 'reset_password': 'cookbook.forms.CustomPasswordResetForm'}
SOCIALACCOUNT_FORMS = {
'signup': 'cookbook.forms.AllAuthSocialSignupForm',
}
ACCOUNT_EMAIL_UNKNOWN_ACCOUNTS = False
ACCOUNT_RATE_LIMITS = {

View File

@@ -1,10 +1,10 @@
Django==4.2.16
cryptography===43.0.1
Django==4.2.18
cryptography===44.0.0
django-annoying==0.10.6
django-cleanup==8.0.0
django-crispy-forms==2.3
crispy-bootstrap4==2024.1
django-tables2==2.7.0
crispy-bootstrap4==2024.10
django-tables2==2.7.4
djangorestframework==3.15.2
drf-writable-nested==0.7.0
django-oauth-toolkit==2.4.0
@@ -19,18 +19,18 @@ python-dotenv==1.0.0
requests==2.32.3
six==1.16.0
webdavclient3==3.14.6
whitenoise==6.7.0
icalendar==5.0.11
whitenoise==6.8.2
icalendar==6.1.0
pyyaml==6.0.2
uritemplate==4.1.1
beautifulsoup4==4.12.3
microdata==0.8.0
mock==5.1.0
Jinja2==3.1.4
Jinja2==3.1.5
django-webpack-loader==3.0.1
git+https://github.com/BITSOLVER/django-js-reverse@071e304fd600107bc64bbde6f2491f1fe049ec82
django-allauth==0.61.1
recipe-scrapers==15.2.1
recipe-scrapers==15.4.0
django-scopes==2.0.0
django-treebeard==4.7
django-cors-headers==4.6.0
@@ -41,16 +41,16 @@ django-hCaptcha==0.2.0
python-ldap==3.4.4
django-auth-ldap==4.6.0
pyppeteer==2.0.0
pytubefix==8.5.1
pytubefix==8.12.0
aiohttp==3.10.11
inflection==0.5.1
redis==5.2.0
redis==5.2.1
# Development
pytest==8.0.0
pytest-django==4.8.0
pytest-django==4.9.0
pytest-cov===5.0.0
pytest-factoryboy==2.6.0
pytest-factoryboy==2.7.0
pytest-html==4.1.1
pytest-asyncio==0.23.5
pytest-xdist==3.6.1

View File

@@ -83,6 +83,11 @@
<loading-spinner></loading-spinner>
</b-card>
<!-- Warnings -->
<b-card no-body v-if="duplicateWarning" class="warning">
{{ duplicateWarning }}
</b-card>
<!-- OPTIONS -->
<b-card no-body v-if="recipe_json !== undefined">
<b-card-header header-tag="header" class="p-1" role="tab">
@@ -463,6 +468,7 @@ export default {
},
// URL import
LS_IMPORT_RECENT: 'import_recent_urls', //TODO use central helper to manage all local storage keys (and maybe even access)
duplicateWarning: '',
website_url: '',
website_url_list: '',
import_multiple: false,
@@ -643,6 +649,12 @@ export default {
return
}
if ('duplicate' in response.data && response.data['duplicate']) {
this.duplicateWarning = "A recipe with this URL already exists.";
} else {
this.duplicateWarning = "";
}
this.loading = false
this.recipe_json = response.data['recipe_json'];
@@ -763,6 +775,16 @@ export default {
<style>
.warning {
color: rgb(255, 149, 0);
align-items: center;
background-color: #fff4ec;
padding: 10px;
border: 1px solid rgb(255, 149, 0);
border-radius: 5px;
margin: 10px 0;
}
.bounce {
animation: bounce 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
transform: translate3d(0, 0, 0);

View File

@@ -238,7 +238,7 @@ export default {
if (e.recipe_mealplan !== null) {
let recipe_name = e.recipe_mealplan.recipe_name
if (recipes.indexOf(recipe_name) === -1) {
if (recipes.indexOf(recipe_name) === -1 && recipe_name !== undefined) {
recipes.push(recipe_name.substring(0, 14) + (recipe_name.length > 14 ? '..' : ''))
}

View File

@@ -539,5 +539,34 @@
"err_importing_recipe": "Der opstod en fejl under importeringen af opskriften!",
"Properties_Food_Amount": "Egenskaber Ingrediens Mængde",
"FDC_Search": "FDC søgning",
"Calculator": "Lommeregner"
"Calculator": "Lommeregner",
"Undo": "Fortryd",
"NoMoreUndo": "Ingen ændringer at fortryde.",
"Input": "Input",
"Delete_All": "Slet alle",
"CustomNavLogoHelp": "Upload et billede til brug som navigationsbarrelogo.",
"ShowRecentlyCompleted": "Vis nyligt gennemførte emner",
"ShoppingBackgroundSyncWarning": "Dårligt netværk, afventer synkronisering ...",
"CustomTheme": "Personaliseret tema",
"CustomThemeHelp": "Overskriv det valgte temas stil ved at uploade en personlig CSS-fil.",
"property_type_fdc_hint": "Kun egenskabstyper med et FDC ID kan automatisk trække data fra FDC databasen",
"Property_Editor": "Egenskabsredaktør",
"us_cup": "cup (US, volumen)",
"Show_Logo_Help": "Vis Tandoor eller område-logo i navigationsbarre.",
"Nav_Text_Mode": "Navigation textmodus",
"Nav_Text_Mode_Help": "Opfører sig forskelligt for hvert tema.",
"Shopping_input_placeholder": "Fx kartoffel/100 kartofler/100g kartofler",
"CustomImageHelp": "Upload et billede for at vise dets plade i område-oversigten.",
"CustomLogoHelp": "Upload kvadratiske billeder i forskellige størrelser for at ændre logoet i browser-faneblad og installeret web-app.",
"CustomLogos": "Personlige logoer",
"Updated": "Opdateret",
"Unchanged": "Uændret",
"Error": "Fejl",
"Logo": "Logo",
"Show_Logo": "Vis logo",
"Space_Cosmetic_Settings": "Visse kosmetiske indstillinger kan ændres af område-administratorer og vil overskrive klient-indstillinger for pågældende område.",
"Enable": "Aktiver",
"created_by": "Skabt af",
"Created": "Skabt",
"DefaultPage": "Startside"
}

View File

@@ -203,7 +203,7 @@
"Next_Day": "Naslednji Dan",
"Previous_Day": "Prejšnji Dan",
"Coming_Soon": "Kmalu",
"Auto_Planner": "Avto-planer",
"Auto_Planner": "Samodejni planer",
"New_Cookbook": "Nova kuharska knjiga",
"Hide_Keyword": "Skrij ključne besede",
"Clear": "Počisti",
@@ -215,7 +215,7 @@
"RemoveFoodFromShopping": "Odstrani {food} iz nakupovalnega listka",
"SupermarketCategoriesOnly": "Prikaži samo trgovinske kategorije",
"DelayFor": "Zamakni za {hours} ur",
"OfflineAlert": "Si v offline načinu, nakupovalni listek se mogoče ne bo sinhroniziral.",
"OfflineAlert": "Si v načinu brez povezave, nakupovalni listek se mogoče ne bo sinhroniziral.",
"shopping_share_desc": "Uporabniki bodo videli vse elemente, ki si jih dodal v nakupovalni listek. Morajo te dodati, da vidiš njihove elemente na listku.",
"shopping_auto_sync_desc": "Nastavitev na 0 bo onemogoča avtomatsko sinhronizacijo. Pri ogledu nakupovalnega seznama se seznam posodablja vsakih nekaj sekund za sinhronizacijo sprememb, ki jih je morda naredil nekdo drug. Uporabno pri nakupovanju z več ljudmi, vendar bo uporabljalo mobilne podatke.",
"filter_to_supermarket_desc": "Privzeto, razvrsti nakupovalni listek, da vključi samo označene trgovine.",
@@ -225,7 +225,7 @@
"success_moving_resource": "Premikanje vira je bilo uspešno!",
"success_merging_resource": "Združevanje vira je bilo uspešno!",
"Added_by": "Dodano s strani",
"AddToShopping": "Dodaj nakupovlanemu listku",
"AddToShopping": "Dodaj nakupovalnemu listku",
"NotInShopping": "{food} ni v tvojem nakupovalnem listku.",
"OnHand": "Trenutno imam v roki",
"FoodOnHand": "Imaš {food} v roki.",
@@ -247,8 +247,8 @@
"ShowDelayed": "Pokaži odložene elemente",
"Completed": "Končano",
"shopping_share": "Deli nakupovalni listek",
"shopping_auto_sync": "Avtomatska sinhronizacija",
"mealplan_autoadd_shopping": "Avtomatsko dodaj obrok v načrt",
"shopping_auto_sync": "Samodejna sinhronizacija",
"mealplan_autoadd_shopping": "Samodejno dodaj obrok v načrt",
"mealplan_autoexclude_onhand": "Izključi hrano v roki",
"mealplan_autoinclude_related": "Dodaj povezane recepte",
"default_delay": "Privzete ure za zamik",
@@ -275,7 +275,7 @@
"copy_markdown_table": "Kopiraj kot Markdown tabela",
"in_shopping": "V nakupovalnem listku",
"DelayUntil": "Zamakni do",
"shopping_add_onhand": "Avtomatsko v roki",
"shopping_add_onhand": "Samodejno v roki",
"related_recipes": "Povezani recepti",
"today_recipes": "Današnji recepti",
"mark_complete": "Označi končano",

View File

@@ -1,5 +1,5 @@
{
"warning_feature_beta": "Bu özellik şu anda BETA (test) durumundadır. Lütfen bu özelliği kullanırken hatalara ve muhtemelen gelecekte değişikliklere (muhtemelen özellikle ilgili verilerin kaybolmasına) hazırlıklı olun.",
"warning_feature_beta": "Bu özellik şu anda BETA (test) aşamasındadır. Lütfen bu özelliği kullanırken gelecekte hatalar ve muhtemelen kırıcı değişiklikler (muhtemelen özellikle ilgili verileri kaybetme) bekleyin",
"err_fetching_resource": "Kaynak alınırken bir hata oluştu!",
"err_creating_resource": "Kaynak oluşturulurken bir hata oluştu!",
"err_updating_resource": "Kaynak güncellenirken bir hata oluştu!",
@@ -567,5 +567,6 @@
"imperial_tbsp": "imperial tablespoon [imp tbsp] (Birleşik Krallık, hacim)",
"imperial_tsp": "imperial teaspoon [imp tsp] (Birleşik Krallık, hacim)",
"Back": "Geri",
"Use_Plural_Unit_Simple": "Birim için dinamik olarak çoğul biçimi kullanın"
"Use_Plural_Unit_Simple": "Birim için dinamik olarak çoğul biçimi kullanın",
"us_cup": "bardak (ABD, hacim)"
}

View File

@@ -20,7 +20,7 @@
"all_fields_optional": "Всі поля опціональні і можна залишити їх пустими.",
"convert_internal": "Конвертувати у внутрішній рецепт",
"show_only_internal": "Показати тільки внутрішні рецепти",
"show_split_screen": "",
"show_split_screen": "Розділений перегляд",
"Log_Recipe_Cooking": "",
"External_Recipe_Image": "Зображення Зовнішнього Рецепту",
"Add_to_Shopping": "Додати до Покупок",
@@ -437,5 +437,8 @@
"Use_Fractions_Help": "Автоматично конвертувати десятки в дроби, коли дивитесь рецепт.",
"Copy Link": "Скопіювати Посилання",
"Original_Text": "Оригінальний текст",
"Default_Unit": "Одиниця замовчуванням"
"Default_Unit": "Одиниця замовчуванням",
"recipe_property_info": "Ви також можете додати властивості до продуктів, щоб розрахувати їх автоматично на основі вашого рецепту!",
"per_serving": "на порцію",
"err_importing_recipe": "Виникла помилка при імпортуванні рецепту!"
}