From 4a4dafd69c0b955b613d4132ba36d6d1bb5e2045 Mon Sep 17 00:00:00 2001 From: smilerz Date: Tue, 9 Feb 2021 11:17:31 -0600 Subject: [PATCH 1/8] add keyword during recipe edit --- .gitignore | 1 + cookbook/templates/forms/edit_internal_recipe.html | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/.gitignore b/.gitignore index 908033e19..337555831 100644 --- a/.gitignore +++ b/.gitignore @@ -78,3 +78,4 @@ postgresql/ /docker-compose.override.yml vue/node_modules +.vscode/ diff --git a/cookbook/templates/forms/edit_internal_recipe.html b/cookbook/templates/forms/edit_internal_recipe.html index 4151e6d29..84d4f7f72 100644 --- a/cookbook/templates/forms/edit_internal_recipe.html +++ b/cookbook/templates/forms/edit_internal_recipe.html @@ -77,6 +77,9 @@ :hide-selected="true" :preserve-search="true" placeholder="{% trans 'Select Keywords' %}" + tag-placeholder="{% trans 'Add Keyword' %}" + :taggable="true" + @tag="addKeyword" label="label" track-by="id" id="id_keywords" @@ -667,6 +670,10 @@ this.units.push(new_unit.unit) this.recipe.steps[step].ingredients[id] = new_unit }, + addKeyword: function (tag) { + let new_keyword = {'label':tag,'name':tag} + this.recipe.keywords.push(new_keyword) + }, searchKeywords: function (query) { this.keywords_loading = true this.$http.get("{% url 'api:keyword-list' %}" + '?query=' + query + '&limit=10').then((response) => { From e0a0eeeecc5daeb2820f720fa608bd74aeaa2574 Mon Sep 17 00:00:00 2001 From: smilerz Date: Tue, 9 Feb 2021 12:55:40 -0600 Subject: [PATCH 2/8] add keyword during url import --- cookbook/templates/url_import.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cookbook/templates/url_import.html b/cookbook/templates/url_import.html index 630b454d1..0fdc81141 100644 --- a/cookbook/templates/url_import.html +++ b/cookbook/templates/url_import.html @@ -190,6 +190,9 @@ :hide-selected="true" :preserve-search="true" placeholder="{% trans 'Select one' %}" + tag-placeholder="{% trans 'Add Keyword' %}" + :taggable="true" + @tag="addKeyword" label="text" track-by="id" id="id_keywords" @@ -357,6 +360,10 @@ this.units.push(new_unit.unit) this.recipe_data.recipeIngredient[index] = new_unit }, + addKeyword: function (tag) { + let new_keyword = {'text':tag,'id':null} + this.recipe_data.keywords.push(new_keyword) + }, openUnitSelect: function (id) { let index = id.replace('unit_', '') if (this.recipe_data.recipeIngredient[index].unit !== null) { From 35f3ecc7ebf4e087cae61748f0d94325e341bad3 Mon Sep 17 00:00:00 2001 From: smilerz Date: Tue, 16 Feb 2021 07:44:41 -0600 Subject: [PATCH 3/8] minor edit --- recipes/settings.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/recipes/settings.py b/recipes/settings.py index 80ab28d17..8cfe6faad 100644 --- a/recipes/settings.py +++ b/recipes/settings.py @@ -17,16 +17,19 @@ import string from django.contrib import messages from django.utils.translation import gettext_lazy as _ from dotenv import load_dotenv +load_dotenv() BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Get vars from .env files -SECRET_KEY = os.getenv('SECRET_KEY') if os.getenv('SECRET_KEY') else 'INSECURE_STANDARD_KEY_SET_IN_ENV' +SECRET_KEY = os.getenv('SECRET_KEY') if os.getenv( + 'SECRET_KEY') else 'INSECURE_STANDARD_KEY_SET_IN_ENV' DEBUG = bool(int(os.getenv('DEBUG', True))) DEMO = bool(int(os.getenv('DEMO', False))) -INTERNAL_IPS = os.getenv('INTERNAL_IPS').split(',') if os.getenv('INTERNAL_IPS') else ['127.0.0.1'] +INTERNAL_IPS = os.getenv('INTERNAL_IPS').split( + ',') if os.getenv('INTERNAL_IPS') else ['127.0.0.1'] # allow djangos wsgi server to server mediafiles GUNICORN_MEDIA = bool(int(os.getenv('GUNICORN_MEDIA', True))) @@ -39,9 +42,11 @@ FRACTION_PREF_DEFAULT = bool(int(os.getenv('FRACTION_PREF_DEFAULT', False))) STICKY_NAV_PREF_DEFAULT = bool(int(os.getenv('STICKY_NAV_PREF_DEFAULT', True))) # minimum interval that users can set for automatic sync of shopping lists -SHOPPING_MIN_AUTOSYNC_INTERVAL = int(os.getenv('SHOPPING_MIN_AUTOSYNC_INTERVAL', 5)) +SHOPPING_MIN_AUTOSYNC_INTERVAL = int( + os.getenv('SHOPPING_MIN_AUTOSYNC_INTERVAL', 5)) -ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS').split(',') if os.getenv('ALLOWED_HOSTS') else ['*'] +ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS').split( + ',') if os.getenv('ALLOWED_HOSTS') else ['*'] CORS_ORIGIN_ALLOW_ALL = True @@ -86,10 +91,12 @@ INSTALLED_APPS = [ 'cookbook.apps.CookbookConfig', ] -SOCIAL_PROVIDERS = os.getenv('SOCIAL_PROVIDERS').split(',') if os.getenv('SOCIAL_PROVIDERS') else [] +SOCIAL_PROVIDERS = os.getenv('SOCIAL_PROVIDERS').split( + ',') if os.getenv('SOCIAL_PROVIDERS') else [] INSTALLED_APPS = INSTALLED_APPS + SOCIAL_PROVIDERS -SOCIALACCOUNT_PROVIDERS = ast.literal_eval(os.getenv('SOCIALACCOUNT_PROVIDERS') if os.getenv('SOCIALACCOUNT_PROVIDERS') else '{}') +SOCIALACCOUNT_PROVIDERS = ast.literal_eval(os.getenv( + 'SOCIALACCOUNT_PROVIDERS') if os.getenv('SOCIALACCOUNT_PROVIDERS') else '{}') MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', @@ -116,7 +123,8 @@ ACCOUNT_ADAPTER = 'cookbook.helper.AllAuthCustomAdapter' if REVERSE_PROXY_AUTH: MIDDLEWARE.append('recipes.middleware.CustomRemoteUser') - AUTHENTICATION_BACKENDS.append('django.contrib.auth.backends.RemoteUserBackend') + AUTHENTICATION_BACKENDS.append( + 'django.contrib.auth.backends.RemoteUserBackend') # Password validation # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators @@ -225,7 +233,8 @@ LANGUAGES = [ # https://docs.djangoproject.com/en/2.0/howto/static-files/ # path for django_js_reverse to generate the javascript file containing all urls. Only done because the default command (collectstatic_js_reverse) fails to update the manifest -JS_REVERSE_OUTPUT_PATH = os.path.join(BASE_DIR, "cookbook/static/django_js_reverse") +JS_REVERSE_OUTPUT_PATH = os.path.join( + BASE_DIR, "cookbook/static/django_js_reverse") STATIC_URL = os.getenv('STATIC_URL', '/static/') STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles") From 6962b0e2185e58c18b732821c530e4e78c73ce48 Mon Sep 17 00:00:00 2001 From: smilerz Date: Wed, 17 Feb 2021 07:09:19 -0600 Subject: [PATCH 4/8] added new keyword management page --- cookbook/tables.py | 23 ++++ cookbook/templates/manage/keyword_table.html | 109 +++++++++++++++++++ cookbook/templates/manage/keywords.html | 22 ++++ cookbook/urls.py | 49 ++++++--- cookbook/views/__init__.py | 2 + cookbook/views/manage.py | 19 ++++ 6 files changed, 208 insertions(+), 16 deletions(-) create mode 100644 cookbook/templates/manage/keyword_table.html create mode 100644 cookbook/templates/manage/keywords.html create mode 100644 cookbook/views/manage.py diff --git a/cookbook/tables.py b/cookbook/tables.py index a5c1cca82..299cadb41 100644 --- a/cookbook/tables.py +++ b/cookbook/tables.py @@ -1,4 +1,5 @@ import django_tables2 as tables +from django.db.models.functions import Lower from django.utils.html import format_html from django.utils.translation import gettext as _ from django_tables2.utils import A @@ -61,6 +62,28 @@ class KeywordTable(tables.Table): fields = ('id', 'icon', 'name') +class ManageKeywordTable(tables.Table): + name = tables.LinkColumn('edit_keyword', args=[ + A('id')]) + + class Meta: + model = Keyword + template_name = 'manage/keyword_table.html' + fields = ('id', 'name') + + def render_name(self, value, record): + if record.icon != None: + return format_html("{} {}", record.icon, value) + else: + return value + + def order_name(self, queryset, is_descending): + queryset = queryset.annotate( + name_lower=Lower('name') + ).order_by(("-" if is_descending else "") + "name_lower") + return (queryset, True) + + class IngredientTable(tables.Table): id = tables.LinkColumn('edit_food', args=[A('id')]) diff --git a/cookbook/templates/manage/keyword_table.html b/cookbook/templates/manage/keyword_table.html new file mode 100644 index 000000000..a1e57d118 --- /dev/null +++ b/cookbook/templates/manage/keyword_table.html @@ -0,0 +1,109 @@ +{% load crispy_forms_tags %} +{% load i18n %} +{% load django_tables2 %} + + +{% block content %} + +
+ {% block table %} + + {% block table.thead %} + {% if table.show_header %} + + + {% for column in table.columns %} + + {% endfor %} + + + {% endif %} + {% endblock table.thead %} + {% block table.tbody %} + + {% for row in table.paginated_rows %} + {% block table.tbody.row %} + + {% for column, cell in row.items %} + + {% endfor %} + + {% endblock table.tbody.row %} + {% empty %} + {% if table.empty_text %} + {% block table.tbody.empty_text %} + + + + {% endblock table.tbody.empty_text %} + {% endif %} + {% endfor %} + + {% endblock table.tbody %} + {% block table.tfoot %} + {% if table.has_footer %} + + + {% for column in table.columns %} + + {% endfor %} + + + {% endif %} + {% endblock table.tfoot %} +
+ {% if column.orderable %} + {{ column.header }} + {% else %} + {{ column.header }} + {% endif %} +
+ {% if column.localize == None %}{{ cell }}{% else %}{% if column.localize %} + {{ cell|localize }}{% else %}{{ cell|unlocalize }} + {% endif %}{% endif %}
{{ table.empty_text }}
{{ column.footer }}
+ {% endblock table %} + + {% block pagination %} + {% if table.page and table.paginator.num_pages > 1 %} + + {% endif %} + {% endblock pagination %} +
+{% endblock content %} \ No newline at end of file diff --git a/cookbook/templates/manage/keywords.html b/cookbook/templates/manage/keywords.html new file mode 100644 index 000000000..efbdabe5a --- /dev/null +++ b/cookbook/templates/manage/keywords.html @@ -0,0 +1,22 @@ +{% extends "base.html" %} +{% load i18n %} +{% load django_tables2 %} + +{% block title %}{{ title }}{% endblock %} + + +{% block content %} + +
+

{% trans 'Manage Keywords' %} {% trans 'List' %} + {% if create_url %} + + + {% endif %} +

+ + {% render_table table %} + +
+ +{% endblock content %} \ No newline at end of file diff --git a/cookbook/urls.py b/cookbook/urls.py index ba9a8d75e..5d2a501db 100644 --- a/cookbook/urls.py +++ b/cookbook/urls.py @@ -11,7 +11,7 @@ from cookbook.helper import dal from .models import (Comment, Food, InviteLink, Keyword, MealPlan, Recipe, RecipeBook, RecipeBookEntry, RecipeImport, ShoppingList, Storage, Sync, SyncLog, get_model_name) -from .views import api, data, delete, edit, import_export, lists, new, views +from .views import api, data, delete, edit, import_export, lists, manage, new, views router = routers.DefaultRouter() router.register(r'user-name', api.UserNameViewSet, basename='username') @@ -48,7 +48,8 @@ urlpatterns = [ path('plan/entry/', views.meal_plan_entry, name='view_plan_entry'), path('shopping/', views.shopping_list, name='view_shopping'), path('shopping/', views.shopping_list, name='view_shopping'), - path('shopping/latest/', views.latest_shopping_list, name='view_shopping_latest'), + path('shopping/latest/', views.latest_shopping_list, + name='view_shopping_latest'), path('settings/', views.user_settings, name='view_settings'), path('history/', views.history, name='view_history'), path('test/', views.test, name='view_test'), @@ -58,22 +59,30 @@ urlpatterns = [ path('export/', import_export.export_recipe, name='view_export'), path('view/recipe/', views.recipe_view, name='view_recipe'), - path('view/recipe//', views.recipe_view, name='view_recipe'), + path('view/recipe//', + views.recipe_view, name='view_recipe'), - path('new/recipe-import//', new.create_new_external_recipe, name='new_recipe_import'), + path('new/recipe-import//', + new.create_new_external_recipe, name='new_recipe_import'), path('new/share-link//', new.share_link, name='new_share_link'), path('edit/recipe//', edit.switch_recipe, name='edit_recipe'), + path('manage/keywords/', manage.keywords, name='manage_keywords'), + # for internal use only - path('edit/recipe/internal//', edit.internal_recipe_update, name='edit_internal_recipe'), - path('edit/recipe/external//', edit.ExternalRecipeUpdate.as_view(), name='edit_external_recipe'), - path('edit/recipe/convert//', edit.convert_recipe, name='edit_convert_recipe'), + path('edit/recipe/internal//', + edit.internal_recipe_update, name='edit_internal_recipe'), + path('edit/recipe/external//', + edit.ExternalRecipeUpdate.as_view(), name='edit_external_recipe'), + path('edit/recipe/convert//', + edit.convert_recipe, name='edit_convert_recipe'), path('edit/storage//', edit.edit_storage, name='edit_storage'), path('edit/ingredient/', edit.edit_ingredients, name='edit_food'), - path('delete/recipe-source//', delete.delete_recipe_source, name='delete_recipe_source'), + path('delete/recipe-source//', + delete.delete_recipe_source, name='delete_recipe_source'), # TODO move to generic "new" view path('data/sync', data.sync, name='data_sync'), @@ -83,14 +92,19 @@ urlpatterns = [ path('data/statistics', data.statistics, name='data_stats'), path('data/import/url', data.import_url, name='data_import_url'), - path('api/get_external_file_link//', api.get_external_file_link, name='api_get_external_file_link'), - path('api/get_recipe_file//', api.get_recipe_file, name='api_get_recipe_file'), + path('api/get_external_file_link//', + api.get_external_file_link, name='api_get_external_file_link'), + path('api/get_recipe_file//', + api.get_recipe_file, name='api_get_recipe_file'), path('api/sync_all/', api.sync_all, name='api_sync'), - path('api/log_cooking//', api.log_cooking, name='api_log_cooking'), - path('api/plan-ical///', api.get_plan_ical, name='api_get_plan_ical'), + path('api/log_cooking//', + api.log_cooking, name='api_log_cooking'), + path('api/plan-ical///', + api.get_plan_ical, name='api_get_plan_ical'), path('api/recipe-from-url/', api.recipe_from_url, name='api_recipe_from_url'), path('api/backup/', api.get_backup, name='api_backup'), - path('api/ingredient-from-string/', api.ingredient_from_string, name='api_ingredient_from_string'), + path('api/ingredient-from-string/', api.ingredient_from_string, + name='api_ingredient_from_string'), path('dal/keyword/', dal.KeywordAutocomplete.as_view(), name='dal_keyword'), path('dal/food/', dal.IngredientsAutocomplete.as_view(), name='dal_food'), @@ -99,7 +113,8 @@ urlpatterns = [ path('docs/markdown/', views.markdown_info, name='docs_markdown'), path('docs/api/', views.api_info, name='docs_api'), - path('openapi', get_schema_view(title="Django Recipes", version=VERSION_NUMBER), name='openapi-schema'), + path('openapi', get_schema_view(title="Django Recipes", + version=VERSION_NUMBER), name='openapi-schema'), path('api/', include((router.urls, 'api'))), path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), @@ -107,8 +122,10 @@ urlpatterns = [ path('offline/', views.offline, name='view_offline'), - path('service-worker.js', (TemplateView.as_view(template_name="sw.js", content_type='application/javascript', )), name='service_worker'), - path('manifest.json', (TemplateView.as_view(template_name="manifest.json", content_type='application/json', )), name='web_manifest'), + path('service-worker.js', (TemplateView.as_view(template_name="sw.js", + content_type='application/javascript', )), name='service_worker'), + path('manifest.json', (TemplateView.as_view(template_name="manifest.json", + content_type='application/json', )), name='web_manifest'), ] generic_models = ( diff --git a/cookbook/views/__init__.py b/cookbook/views/__init__.py index ab37dad90..52127cb1a 100644 --- a/cookbook/views/__init__.py +++ b/cookbook/views/__init__.py @@ -6,6 +6,7 @@ import cookbook.views.import_export import cookbook.views.lists import cookbook.views.new import cookbook.views.views +import cookbook.views.manage __all__ = [ 'api', @@ -14,6 +15,7 @@ __all__ = [ 'edit', 'import_export', 'lists', + 'manage', 'new', 'views', ] diff --git a/cookbook/views/manage.py b/cookbook/views/manage.py new file mode 100644 index 000000000..db126cc4f --- /dev/null +++ b/cookbook/views/manage.py @@ -0,0 +1,19 @@ +from cookbook.helper.permission_helper import group_required +from cookbook.models import Keyword +from cookbook.tables import ManageKeywordTable +from django.views import generic +from django.shortcuts import render +from django_tables2 import RequestConfig +from django.utils.translation import gettext as _ + + +@group_required('user') +def keywords(request): + table = ManageKeywordTable(Keyword.objects.all()) + RequestConfig(request, paginate={'per_page': 25}).configure(table) + + return render( + request, + 'manage/keywords.html', + {'title': _("Keyword"), 'table': table, 'create_url': 'new_keyword'} + ) From c6dd55df4e96fef22c24540b445654cec9f2c9ef Mon Sep 17 00:00:00 2001 From: smilerz Date: Wed, 17 Feb 2021 10:45:31 -0600 Subject: [PATCH 5/8] add filter to new keywords page --- cookbook/filters.py | 8 ++++++++ cookbook/templates/manage/keyword_table.html | 1 - cookbook/templates/manage/keywords.html | 16 +++++++++++++++- cookbook/views/manage.py | 11 +++++++++-- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/cookbook/filters.py b/cookbook/filters.py index c1cc86463..2d473cf8c 100644 --- a/cookbook/filters.py +++ b/cookbook/filters.py @@ -66,6 +66,14 @@ class IngredientFilter(django_filters.FilterSet): fields = ['name'] +class KeywordFilter(django_filters.FilterSet): + name = django_filters.CharFilter(lookup_expr='icontains') + + class Meta: + model = Keyword + fields = ['name'] + + class ShoppingListFilter(django_filters.FilterSet): def __init__(self, data=None, *args, **kwargs): diff --git a/cookbook/templates/manage/keyword_table.html b/cookbook/templates/manage/keyword_table.html index a1e57d118..ea1eb90b5 100644 --- a/cookbook/templates/manage/keyword_table.html +++ b/cookbook/templates/manage/keyword_table.html @@ -1,4 +1,3 @@ -{% load crispy_forms_tags %} {% load i18n %} {% load django_tables2 %} diff --git a/cookbook/templates/manage/keywords.html b/cookbook/templates/manage/keywords.html index efbdabe5a..fab4415bf 100644 --- a/cookbook/templates/manage/keywords.html +++ b/cookbook/templates/manage/keywords.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% load crispy_forms_tags %} {% load i18n %} {% load django_tables2 %} @@ -8,13 +9,26 @@ {% block content %}
-

{% trans 'Manage Keywords' %} {% trans 'List' %} +

{% trans 'Manage Keywords' %} {% if create_url %} {% endif %}

+ {% if filter %} +
+
+
+ {% csrf_token %} + {{ filter.form|crispy }} + + {% trans 'Clear' %} +
+ {% endif %} + + {% render_table table %}
diff --git a/cookbook/views/manage.py b/cookbook/views/manage.py index db126cc4f..43ca4f8ca 100644 --- a/cookbook/views/manage.py +++ b/cookbook/views/manage.py @@ -1,3 +1,4 @@ +from cookbook.filters import KeywordFilter from cookbook.helper.permission_helper import group_required from cookbook.models import Keyword from cookbook.tables import ManageKeywordTable @@ -9,11 +10,17 @@ from django.utils.translation import gettext as _ @group_required('user') def keywords(request): - table = ManageKeywordTable(Keyword.objects.all()) + f = KeywordFilter( + request.GET, + queryset=Keyword.objects.all().order_by('pk') + ) + + table = ManageKeywordTable(f.qs) RequestConfig(request, paginate={'per_page': 25}).configure(table) return render( request, 'manage/keywords.html', - {'title': _("Keyword"), 'table': table, 'create_url': 'new_keyword'} + {'title': _("Keyword"), 'table': table, + 'create_url': 'new_keyword', 'filter': f} ) From 28d8f62af729cacc81c528d7b88c9275c9b21899 Mon Sep 17 00:00:00 2001 From: smilerz Date: Thu, 18 Feb 2021 07:25:31 -0600 Subject: [PATCH 6/8] Revert "add filter to new keywords page" This reverts commit c6dd55df4e96fef22c24540b445654cec9f2c9ef. --- cookbook/filters.py | 8 -------- cookbook/templates/manage/keyword_table.html | 1 + cookbook/templates/manage/keywords.html | 16 +--------------- cookbook/views/manage.py | 11 ++--------- 4 files changed, 4 insertions(+), 32 deletions(-) diff --git a/cookbook/filters.py b/cookbook/filters.py index 2d473cf8c..c1cc86463 100644 --- a/cookbook/filters.py +++ b/cookbook/filters.py @@ -66,14 +66,6 @@ class IngredientFilter(django_filters.FilterSet): fields = ['name'] -class KeywordFilter(django_filters.FilterSet): - name = django_filters.CharFilter(lookup_expr='icontains') - - class Meta: - model = Keyword - fields = ['name'] - - class ShoppingListFilter(django_filters.FilterSet): def __init__(self, data=None, *args, **kwargs): diff --git a/cookbook/templates/manage/keyword_table.html b/cookbook/templates/manage/keyword_table.html index ea1eb90b5..a1e57d118 100644 --- a/cookbook/templates/manage/keyword_table.html +++ b/cookbook/templates/manage/keyword_table.html @@ -1,3 +1,4 @@ +{% load crispy_forms_tags %} {% load i18n %} {% load django_tables2 %} diff --git a/cookbook/templates/manage/keywords.html b/cookbook/templates/manage/keywords.html index fab4415bf..efbdabe5a 100644 --- a/cookbook/templates/manage/keywords.html +++ b/cookbook/templates/manage/keywords.html @@ -1,5 +1,4 @@ {% extends "base.html" %} -{% load crispy_forms_tags %} {% load i18n %} {% load django_tables2 %} @@ -9,26 +8,13 @@ {% block content %}
-

{% trans 'Manage Keywords' %} +

{% trans 'Manage Keywords' %} {% trans 'List' %} {% if create_url %} {% endif %}

- {% if filter %} -
-
-
- {% csrf_token %} - {{ filter.form|crispy }} - - {% trans 'Clear' %} -
- {% endif %} - - {% render_table table %}
diff --git a/cookbook/views/manage.py b/cookbook/views/manage.py index 43ca4f8ca..db126cc4f 100644 --- a/cookbook/views/manage.py +++ b/cookbook/views/manage.py @@ -1,4 +1,3 @@ -from cookbook.filters import KeywordFilter from cookbook.helper.permission_helper import group_required from cookbook.models import Keyword from cookbook.tables import ManageKeywordTable @@ -10,17 +9,11 @@ from django.utils.translation import gettext as _ @group_required('user') def keywords(request): - f = KeywordFilter( - request.GET, - queryset=Keyword.objects.all().order_by('pk') - ) - - table = ManageKeywordTable(f.qs) + table = ManageKeywordTable(Keyword.objects.all()) RequestConfig(request, paginate={'per_page': 25}).configure(table) return render( request, 'manage/keywords.html', - {'title': _("Keyword"), 'table': table, - 'create_url': 'new_keyword', 'filter': f} + {'title': _("Keyword"), 'table': table, 'create_url': 'new_keyword'} ) From fc5455a0f2c3e4042c1512670f0a0d62d87985c8 Mon Sep 17 00:00:00 2001 From: smilerz Date: Thu, 18 Feb 2021 07:27:43 -0600 Subject: [PATCH 7/8] Revert "added new keyword management page" This reverts commit 6962b0e2185e58c18b732821c530e4e78c73ce48. --- cookbook/tables.py | 23 ---- cookbook/templates/manage/keyword_table.html | 109 ------------------- cookbook/templates/manage/keywords.html | 22 ---- cookbook/urls.py | 49 +++------ cookbook/views/__init__.py | 2 - cookbook/views/manage.py | 19 ---- 6 files changed, 16 insertions(+), 208 deletions(-) delete mode 100644 cookbook/templates/manage/keyword_table.html delete mode 100644 cookbook/templates/manage/keywords.html delete mode 100644 cookbook/views/manage.py diff --git a/cookbook/tables.py b/cookbook/tables.py index 299cadb41..a5c1cca82 100644 --- a/cookbook/tables.py +++ b/cookbook/tables.py @@ -1,5 +1,4 @@ import django_tables2 as tables -from django.db.models.functions import Lower from django.utils.html import format_html from django.utils.translation import gettext as _ from django_tables2.utils import A @@ -62,28 +61,6 @@ class KeywordTable(tables.Table): fields = ('id', 'icon', 'name') -class ManageKeywordTable(tables.Table): - name = tables.LinkColumn('edit_keyword', args=[ - A('id')]) - - class Meta: - model = Keyword - template_name = 'manage/keyword_table.html' - fields = ('id', 'name') - - def render_name(self, value, record): - if record.icon != None: - return format_html("{} {}", record.icon, value) - else: - return value - - def order_name(self, queryset, is_descending): - queryset = queryset.annotate( - name_lower=Lower('name') - ).order_by(("-" if is_descending else "") + "name_lower") - return (queryset, True) - - class IngredientTable(tables.Table): id = tables.LinkColumn('edit_food', args=[A('id')]) diff --git a/cookbook/templates/manage/keyword_table.html b/cookbook/templates/manage/keyword_table.html deleted file mode 100644 index a1e57d118..000000000 --- a/cookbook/templates/manage/keyword_table.html +++ /dev/null @@ -1,109 +0,0 @@ -{% load crispy_forms_tags %} -{% load i18n %} -{% load django_tables2 %} - - -{% block content %} - -
- {% block table %} - - {% block table.thead %} - {% if table.show_header %} - - - {% for column in table.columns %} - - {% endfor %} - - - {% endif %} - {% endblock table.thead %} - {% block table.tbody %} - - {% for row in table.paginated_rows %} - {% block table.tbody.row %} - - {% for column, cell in row.items %} - - {% endfor %} - - {% endblock table.tbody.row %} - {% empty %} - {% if table.empty_text %} - {% block table.tbody.empty_text %} - - - - {% endblock table.tbody.empty_text %} - {% endif %} - {% endfor %} - - {% endblock table.tbody %} - {% block table.tfoot %} - {% if table.has_footer %} - - - {% for column in table.columns %} - - {% endfor %} - - - {% endif %} - {% endblock table.tfoot %} -
- {% if column.orderable %} - {{ column.header }} - {% else %} - {{ column.header }} - {% endif %} -
- {% if column.localize == None %}{{ cell }}{% else %}{% if column.localize %} - {{ cell|localize }}{% else %}{{ cell|unlocalize }} - {% endif %}{% endif %}
{{ table.empty_text }}
{{ column.footer }}
- {% endblock table %} - - {% block pagination %} - {% if table.page and table.paginator.num_pages > 1 %} - - {% endif %} - {% endblock pagination %} -
-{% endblock content %} \ No newline at end of file diff --git a/cookbook/templates/manage/keywords.html b/cookbook/templates/manage/keywords.html deleted file mode 100644 index efbdabe5a..000000000 --- a/cookbook/templates/manage/keywords.html +++ /dev/null @@ -1,22 +0,0 @@ -{% extends "base.html" %} -{% load i18n %} -{% load django_tables2 %} - -{% block title %}{{ title }}{% endblock %} - - -{% block content %} - -
-

{% trans 'Manage Keywords' %} {% trans 'List' %} - {% if create_url %} - - - {% endif %} -

- - {% render_table table %} - -
- -{% endblock content %} \ No newline at end of file diff --git a/cookbook/urls.py b/cookbook/urls.py index 5d2a501db..ba9a8d75e 100644 --- a/cookbook/urls.py +++ b/cookbook/urls.py @@ -11,7 +11,7 @@ from cookbook.helper import dal from .models import (Comment, Food, InviteLink, Keyword, MealPlan, Recipe, RecipeBook, RecipeBookEntry, RecipeImport, ShoppingList, Storage, Sync, SyncLog, get_model_name) -from .views import api, data, delete, edit, import_export, lists, manage, new, views +from .views import api, data, delete, edit, import_export, lists, new, views router = routers.DefaultRouter() router.register(r'user-name', api.UserNameViewSet, basename='username') @@ -48,8 +48,7 @@ urlpatterns = [ path('plan/entry/', views.meal_plan_entry, name='view_plan_entry'), path('shopping/', views.shopping_list, name='view_shopping'), path('shopping/', views.shopping_list, name='view_shopping'), - path('shopping/latest/', views.latest_shopping_list, - name='view_shopping_latest'), + path('shopping/latest/', views.latest_shopping_list, name='view_shopping_latest'), path('settings/', views.user_settings, name='view_settings'), path('history/', views.history, name='view_history'), path('test/', views.test, name='view_test'), @@ -59,30 +58,22 @@ urlpatterns = [ path('export/', import_export.export_recipe, name='view_export'), path('view/recipe/', views.recipe_view, name='view_recipe'), - path('view/recipe//', - views.recipe_view, name='view_recipe'), + path('view/recipe//', views.recipe_view, name='view_recipe'), - path('new/recipe-import//', - new.create_new_external_recipe, name='new_recipe_import'), + path('new/recipe-import//', new.create_new_external_recipe, name='new_recipe_import'), path('new/share-link//', new.share_link, name='new_share_link'), path('edit/recipe//', edit.switch_recipe, name='edit_recipe'), - path('manage/keywords/', manage.keywords, name='manage_keywords'), - # for internal use only - path('edit/recipe/internal//', - edit.internal_recipe_update, name='edit_internal_recipe'), - path('edit/recipe/external//', - edit.ExternalRecipeUpdate.as_view(), name='edit_external_recipe'), - path('edit/recipe/convert//', - edit.convert_recipe, name='edit_convert_recipe'), + path('edit/recipe/internal//', edit.internal_recipe_update, name='edit_internal_recipe'), + path('edit/recipe/external//', edit.ExternalRecipeUpdate.as_view(), name='edit_external_recipe'), + path('edit/recipe/convert//', edit.convert_recipe, name='edit_convert_recipe'), path('edit/storage//', edit.edit_storage, name='edit_storage'), path('edit/ingredient/', edit.edit_ingredients, name='edit_food'), - path('delete/recipe-source//', - delete.delete_recipe_source, name='delete_recipe_source'), + path('delete/recipe-source//', delete.delete_recipe_source, name='delete_recipe_source'), # TODO move to generic "new" view path('data/sync', data.sync, name='data_sync'), @@ -92,19 +83,14 @@ urlpatterns = [ path('data/statistics', data.statistics, name='data_stats'), path('data/import/url', data.import_url, name='data_import_url'), - path('api/get_external_file_link//', - api.get_external_file_link, name='api_get_external_file_link'), - path('api/get_recipe_file//', - api.get_recipe_file, name='api_get_recipe_file'), + path('api/get_external_file_link//', api.get_external_file_link, name='api_get_external_file_link'), + path('api/get_recipe_file//', api.get_recipe_file, name='api_get_recipe_file'), path('api/sync_all/', api.sync_all, name='api_sync'), - path('api/log_cooking//', - api.log_cooking, name='api_log_cooking'), - path('api/plan-ical///', - api.get_plan_ical, name='api_get_plan_ical'), + path('api/log_cooking//', api.log_cooking, name='api_log_cooking'), + path('api/plan-ical///', api.get_plan_ical, name='api_get_plan_ical'), path('api/recipe-from-url/', api.recipe_from_url, name='api_recipe_from_url'), path('api/backup/', api.get_backup, name='api_backup'), - path('api/ingredient-from-string/', api.ingredient_from_string, - name='api_ingredient_from_string'), + path('api/ingredient-from-string/', api.ingredient_from_string, name='api_ingredient_from_string'), path('dal/keyword/', dal.KeywordAutocomplete.as_view(), name='dal_keyword'), path('dal/food/', dal.IngredientsAutocomplete.as_view(), name='dal_food'), @@ -113,8 +99,7 @@ urlpatterns = [ path('docs/markdown/', views.markdown_info, name='docs_markdown'), path('docs/api/', views.api_info, name='docs_api'), - path('openapi', get_schema_view(title="Django Recipes", - version=VERSION_NUMBER), name='openapi-schema'), + path('openapi', get_schema_view(title="Django Recipes", version=VERSION_NUMBER), name='openapi-schema'), path('api/', include((router.urls, 'api'))), path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), @@ -122,10 +107,8 @@ urlpatterns = [ path('offline/', views.offline, name='view_offline'), - path('service-worker.js', (TemplateView.as_view(template_name="sw.js", - content_type='application/javascript', )), name='service_worker'), - path('manifest.json', (TemplateView.as_view(template_name="manifest.json", - content_type='application/json', )), name='web_manifest'), + path('service-worker.js', (TemplateView.as_view(template_name="sw.js", content_type='application/javascript', )), name='service_worker'), + path('manifest.json', (TemplateView.as_view(template_name="manifest.json", content_type='application/json', )), name='web_manifest'), ] generic_models = ( diff --git a/cookbook/views/__init__.py b/cookbook/views/__init__.py index 52127cb1a..ab37dad90 100644 --- a/cookbook/views/__init__.py +++ b/cookbook/views/__init__.py @@ -6,7 +6,6 @@ import cookbook.views.import_export import cookbook.views.lists import cookbook.views.new import cookbook.views.views -import cookbook.views.manage __all__ = [ 'api', @@ -15,7 +14,6 @@ __all__ = [ 'edit', 'import_export', 'lists', - 'manage', 'new', 'views', ] diff --git a/cookbook/views/manage.py b/cookbook/views/manage.py deleted file mode 100644 index db126cc4f..000000000 --- a/cookbook/views/manage.py +++ /dev/null @@ -1,19 +0,0 @@ -from cookbook.helper.permission_helper import group_required -from cookbook.models import Keyword -from cookbook.tables import ManageKeywordTable -from django.views import generic -from django.shortcuts import render -from django_tables2 import RequestConfig -from django.utils.translation import gettext as _ - - -@group_required('user') -def keywords(request): - table = ManageKeywordTable(Keyword.objects.all()) - RequestConfig(request, paginate={'per_page': 25}).configure(table) - - return render( - request, - 'manage/keywords.html', - {'title': _("Keyword"), 'table': table, 'create_url': 'new_keyword'} - ) From c60c3f1876ed7c32d1ce840bba45bd469edefd30 Mon Sep 17 00:00:00 2001 From: smilerz Date: Thu, 18 Feb 2021 07:28:26 -0600 Subject: [PATCH 8/8] Revert "minor edit" This reverts commit 35f3ecc7ebf4e087cae61748f0d94325e341bad3. --- recipes/settings.py | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/recipes/settings.py b/recipes/settings.py index 61737bf1d..3105c67f1 100644 --- a/recipes/settings.py +++ b/recipes/settings.py @@ -17,19 +17,16 @@ import string from django.contrib import messages from django.utils.translation import gettext_lazy as _ from dotenv import load_dotenv -load_dotenv() BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Get vars from .env files -SECRET_KEY = os.getenv('SECRET_KEY') if os.getenv( - 'SECRET_KEY') else 'INSECURE_STANDARD_KEY_SET_IN_ENV' +SECRET_KEY = os.getenv('SECRET_KEY') if os.getenv('SECRET_KEY') else 'INSECURE_STANDARD_KEY_SET_IN_ENV' DEBUG = bool(int(os.getenv('DEBUG', True))) DEMO = bool(int(os.getenv('DEMO', False))) -INTERNAL_IPS = os.getenv('INTERNAL_IPS').split( - ',') if os.getenv('INTERNAL_IPS') else ['127.0.0.1'] +INTERNAL_IPS = os.getenv('INTERNAL_IPS').split(',') if os.getenv('INTERNAL_IPS') else ['127.0.0.1'] # allow djangos wsgi server to server mediafiles GUNICORN_MEDIA = bool(int(os.getenv('GUNICORN_MEDIA', True))) @@ -42,11 +39,9 @@ FRACTION_PREF_DEFAULT = bool(int(os.getenv('FRACTION_PREF_DEFAULT', False))) STICKY_NAV_PREF_DEFAULT = bool(int(os.getenv('STICKY_NAV_PREF_DEFAULT', True))) # minimum interval that users can set for automatic sync of shopping lists -SHOPPING_MIN_AUTOSYNC_INTERVAL = int( - os.getenv('SHOPPING_MIN_AUTOSYNC_INTERVAL', 5)) +SHOPPING_MIN_AUTOSYNC_INTERVAL = int(os.getenv('SHOPPING_MIN_AUTOSYNC_INTERVAL', 5)) -ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS').split( - ',') if os.getenv('ALLOWED_HOSTS') else ['*'] +ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS').split(',') if os.getenv('ALLOWED_HOSTS') else ['*'] CORS_ORIGIN_ALLOW_ALL = True @@ -91,12 +86,10 @@ INSTALLED_APPS = [ 'cookbook.apps.CookbookConfig', ] -SOCIAL_PROVIDERS = os.getenv('SOCIAL_PROVIDERS').split( - ',') if os.getenv('SOCIAL_PROVIDERS') else [] +SOCIAL_PROVIDERS = os.getenv('SOCIAL_PROVIDERS').split(',') if os.getenv('SOCIAL_PROVIDERS') else [] INSTALLED_APPS = INSTALLED_APPS + SOCIAL_PROVIDERS -SOCIALACCOUNT_PROVIDERS = ast.literal_eval(os.getenv( - 'SOCIALACCOUNT_PROVIDERS') if os.getenv('SOCIALACCOUNT_PROVIDERS') else '{}') +SOCIALACCOUNT_PROVIDERS = ast.literal_eval(os.getenv('SOCIALACCOUNT_PROVIDERS') if os.getenv('SOCIALACCOUNT_PROVIDERS') else '{}') MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', @@ -123,8 +116,7 @@ ACCOUNT_ADAPTER = 'cookbook.helper.AllAuthCustomAdapter' if REVERSE_PROXY_AUTH: MIDDLEWARE.append('recipes.middleware.CustomRemoteUser') - AUTHENTICATION_BACKENDS.append( - 'django.contrib.auth.backends.RemoteUserBackend') + AUTHENTICATION_BACKENDS.append('django.contrib.auth.backends.RemoteUserBackend') # Password validation # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators @@ -234,8 +226,7 @@ LANGUAGES = [ # https://docs.djangoproject.com/en/2.0/howto/static-files/ # path for django_js_reverse to generate the javascript file containing all urls. Only done because the default command (collectstatic_js_reverse) fails to update the manifest -JS_REVERSE_OUTPUT_PATH = os.path.join( - BASE_DIR, "cookbook/static/django_js_reverse") +JS_REVERSE_OUTPUT_PATH = os.path.join(BASE_DIR, "cookbook/static/django_js_reverse") STATIC_URL = os.getenv('STATIC_URL', '/static/') STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")