Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
vabene1111 committed Dec 29, 2024
2 parents da49280 + fd42366 commit 79abb8b
Show file tree
Hide file tree
Showing 14 changed files with 99 additions and 48 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,5 @@ vue3/.vite
# Configs
vetur.config.js
venv/
.idea/easy-i18n.xml
cookbook/static/vue3
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ RUN apk add --no-cache --virtual .build-deps gcc musl-dev postgresql-dev zlib-de
#Copy project and execute it.
COPY . ./

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
Expand Down
38 changes: 25 additions & 13 deletions cookbook/forms.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -14,15 +16,13 @@


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
Expand Down Expand Up @@ -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}), }
Expand All @@ -161,7 +161,6 @@ class Meta:
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",
Expand Down Expand Up @@ -315,6 +314,18 @@ def signup(self, request, user):
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()

Expand Down Expand Up @@ -345,12 +356,13 @@ class Meta:

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 = {
Expand All @@ -360,5 +372,5 @@ class Meta:

widgets = {
'search': SelectWidget, 'unaccent': MultiSelectWidget, 'icontains': MultiSelectWidget, 'istartswith': MultiSelectWidget, 'trigram': MultiSelectWidget, 'fulltext':
MultiSelectWidget,
MultiSelectWidget,
}
17 changes: 9 additions & 8 deletions cookbook/locale/it/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -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 <[email protected]>\n"
"Language-Team: Italian <http://translate.tandoor.dev/projects/tandoor/"
"recipes-backend/it/>\n"
Expand All @@ -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 ""
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion cookbook/templates/account/signup.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{% extends "base.html" %}
{% load crispy_forms_filters %}
{% load crispy_forms_filters %}
{% load i18n %}

{% block title %}{% trans 'Register' %}{% endblock %}
Expand Down
3 changes: 1 addition & 2 deletions cookbook/templates/socialaccount/signup.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ <h1>{% trans "Sign Up" %}</h1>
{% 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>
Expand All @@ -30,7 +29,7 @@ <h1>{% trans "Sign Up" %}</h1>
<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>
Expand Down
6 changes: 3 additions & 3 deletions cookbook/templates/system.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
13 changes: 11 additions & 2 deletions cookbook/views/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1455,13 +1455,21 @@ def post(self, request, *args, **kwargs):

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='
Expand All @@ -1476,7 +1484,7 @@ def post(self, request, *args, **kwargs):
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):
Expand Down Expand Up @@ -1511,6 +1519,7 @@ def post(self, request, *args, **kwargs):
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)

Expand Down
2 changes: 1 addition & 1 deletion docs/install/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
11 changes: 6 additions & 5 deletions recipes/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@
},
}


# allow djangos wsgi server to server mediafiles
GUNICORN_MEDIA = bool(int(os.getenv('GUNICORN_MEDIA', False)))

Expand Down Expand Up @@ -247,14 +246,14 @@
]

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',
Expand Down Expand Up @@ -294,7 +293,6 @@
"handlers": ["console"]
}


AUTHENTICATION_BACKENDS += [
'django.contrib.auth.backends.ModelBackend',
'allauth.account.auth_backends.AuthenticationBackend',
Expand Down Expand Up @@ -564,6 +562,9 @@ def setup_database(db_url=None, db_options=None, db_engine=None, pg_host=None, p

# 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 = {
Expand Down
12 changes: 6 additions & 6 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
Django==4.2.16
Django==4.2.17
cryptography===43.0.1
django-annoying==0.10.6
django-cleanup==8.0.0
django-crispy-forms==2.3
crispy-bootstrap4==2024.1
crispy-bootstrap4==2024.10
django-tables2==2.7.0
djangorestframework==3.15.2
drf-writable-nested==0.7.0
Expand All @@ -20,13 +20,13 @@ requests==2.32.3
six==1.16.0
webdavclient3==3.14.6
whitenoise==6.7.0
icalendar==5.0.11
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
Expand All @@ -48,9 +48,9 @@ redis==5.2.0

# 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
Expand Down
22 changes: 22 additions & 0 deletions vue/src/apps/ImportView/ImportView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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'];
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion vue/src/components/ShoppingLineItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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 ? '..' : ''))
}
Expand Down
Loading

0 comments on commit 79abb8b

Please sign in to comment.