mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-03 21:37:49 -05:00
added permissions to docs/api
added swagger api view added authentication method to openapi schema added logo to docs/api fixed tree and merge schemas
This commit is contained in:
@@ -160,18 +160,15 @@ class GroupRequiredMixin(object):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not has_group_permission(request.user, self.groups_required):
|
||||
if not request.user.is_authenticated:
|
||||
messages.add_message(request, messages.ERROR,
|
||||
_('You are not logged in and therefore cannot view this page!'))
|
||||
messages.add_message(request, messages.ERROR, _('You are not logged in and therefore cannot view this page!'))
|
||||
return HttpResponseRedirect(reverse_lazy('account_login') + '?next=' + request.path)
|
||||
else:
|
||||
messages.add_message(request, messages.ERROR,
|
||||
_('You do not have the required permissions to view this page!'))
|
||||
messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!'))
|
||||
return HttpResponseRedirect(reverse_lazy('index'))
|
||||
try:
|
||||
obj = self.get_object()
|
||||
if obj.get_space() != request.space:
|
||||
messages.add_message(request, messages.ERROR,
|
||||
_('You do not have the required permissions to view this page!'))
|
||||
messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!'))
|
||||
return HttpResponseRedirect(reverse_lazy('index'))
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
@@ -417,7 +417,6 @@ class ConnectorConfig(models.Model, PermissionModelMixin):
|
||||
objects = ScopedManager(space='space')
|
||||
|
||||
|
||||
|
||||
class UserPreference(models.Model, PermissionModelMixin):
|
||||
# Themes
|
||||
BOOTSTRAP = 'BOOTSTRAP'
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,16 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "API Documentation" %}{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content_fluid %}
|
||||
|
||||
<redoc spec-url='{% url 'openapi-schema' %}'></redoc>
|
||||
<script src="{% static 'js/redoc.standalone.js' %}"></script>
|
||||
|
||||
{% endblock %}
|
||||
@@ -370,17 +370,13 @@
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="{% url 'docs_markdown' %}"><i
|
||||
class="fab fa-markdown fa-fw"></i> {% trans 'Markdown Guide' %}</a>
|
||||
<a class="dropdown-item" href="https://github.com/vabene1111/recipes"><i
|
||||
class="fab fa-github fa-fw"></i> {% trans 'GitHub' %}</a>
|
||||
<a class="dropdown-item" href="https://translate.tandoor.dev/projects/tandoor/"><i
|
||||
class="fas fa-language fa-fw"></i> {% trans 'Translate Tandoor' %}</a>
|
||||
<a class="dropdown-item" href="{% url 'docs_api' %}"><i
|
||||
class="fas fa-passport fa-fw"></i> {% trans 'API Documentation' %}</a>
|
||||
<a class="dropdown-item" href="{% url 'api:api-root' %}"><i
|
||||
class="fas fa-file-code fa-fw"></i> {% trans 'API Browser' %}</a>
|
||||
<a class="dropdown-item" href="https://github.com/vabene1111/recipes"><i class="fab fa-github fa-fw"></i> {% trans 'GitHub' %}</a>
|
||||
<a class="dropdown-item" href="https://translate.tandoor.dev/projects/tandoor/"><i class="fas fa-language fa-fw"></i> {% trans 'Translate Tandoor' %}</a>
|
||||
<a class="dropdown-item" href="{% url 'docs_api' %}"><i class="fas fa-passport fa-fw"></i> {% trans 'API ReDoc Documentation' %}</a>
|
||||
<a class="dropdown-item" href="{% url 'docs_swagger' %}"><i class="fas fa-passport fa-fw"></i> {% trans 'API Swagger Documentation' %}</a>
|
||||
<a class="dropdown-item" href="{% url 'api:api-root' %}"><i class="fas fa-file-code fa-fw"></i> {% trans 'API Browser' %}</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="{% url 'account_logout' %}"><i
|
||||
class="fas fa-sign-out-alt fa-fw"></i> {% trans 'Log out' %}</a>
|
||||
<a class="dropdown-item" href="{% url 'account_logout' %}"><i class="fas fa-sign-out-alt fa-fw"></i> {% trans 'Log out' %}</a>
|
||||
</div>
|
||||
</li>
|
||||
{% else %}
|
||||
|
||||
@@ -2,8 +2,8 @@ from django import template
|
||||
from django.templatetags.static import static
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
from cookbook.models import UserPreference, UserFile, Space
|
||||
from recipes.settings import STICKY_NAV_PREF_DEFAULT, UNAUTHENTICATED_THEME_FROM_SPACE, FORCE_THEME_FROM_SPACE
|
||||
from cookbook.models import UserPreference, Space
|
||||
from recipes.settings import UNAUTHENTICATED_THEME_FROM_SPACE, FORCE_THEME_FROM_SPACE
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@@ -119,3 +119,13 @@ def test_markdown_doc(arg, request, ext_recipe_1_s1):
|
||||
def test_api_info(arg, request, ext_recipe_1_s1):
|
||||
c = request.getfixturevalue(arg[0])
|
||||
assert c.get(reverse('docs_api')).status_code == arg[1]
|
||||
|
||||
@pytest.mark.parametrize("arg", [
|
||||
['a_u', 302],
|
||||
['g1_s1', 200],
|
||||
['u1_s1', 200],
|
||||
['a1_s1', 200],
|
||||
])
|
||||
def test_api_swagger(arg, request, ext_recipe_1_s1):
|
||||
c = request.getfixturevalue(arg[0])
|
||||
assert c.get(reverse('docs_api')).status_code == arg[1]
|
||||
|
||||
@@ -2,9 +2,8 @@ from pydoc import locate
|
||||
|
||||
from django.urls import include, path
|
||||
from django.views.generic import TemplateView
|
||||
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView
|
||||
from rest_framework import permissions, routers
|
||||
from rest_framework.schemas import get_schema_view
|
||||
from drf_spectacular.views import SpectacularAPIView
|
||||
from rest_framework import routers
|
||||
|
||||
from cookbook.version_info import TANDOOR_VERSION
|
||||
from recipes.settings import DEBUG, PLUGINS
|
||||
@@ -16,7 +15,7 @@ from .models import (Automation, Comment, CustomFilter, Food, InviteLink, Keywor
|
||||
|
||||
from .views import api, data, delete, edit, import_export, lists, new, telegram, views
|
||||
from .views.api import CustomAuthToken, ImportOpenData
|
||||
import datetime
|
||||
|
||||
|
||||
# extend DRF default router class to allow including additional routers
|
||||
class DefaultRouter(routers.DefaultRouter):
|
||||
@@ -137,15 +136,15 @@ urlpatterns = [
|
||||
path('telegram/hook/<slug:token>/', telegram.hook, name='telegram_hook'),
|
||||
path('docs/markdown/', views.markdown_info, name='docs_markdown'),
|
||||
path('docs/search/', views.search_info, name='docs_search'),
|
||||
path('docs/api/', SpectacularRedocView.as_view(url_name='openapi-schema'), name='docs_api'),
|
||||
path('docs/api/', views.Redoc.as_view(url_name='openapi-schema'), name='docs_api'),
|
||||
path('docs/swagger/', views.Swagger.as_view(url_name='openapi-schema'), name='docs_swagger'),
|
||||
path('openapi/', SpectacularAPIView.as_view(api_version=TANDOOR_VERSION), name='openapi-schema'),
|
||||
path('api/', include((router.urls, 'api'))),
|
||||
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||
path('api-token-auth/', CustomAuthToken.as_view()),
|
||||
path('api-import-open-data/', ImportOpenData.as_view(), name='api_import_open_data'),
|
||||
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('service-worker.js', (TemplateView.as_view(template_name="sw.js", content_type='application/javascript', )), name='service_worker'),
|
||||
path('manifest.json', views.web_manifest, name='web_manifest'),
|
||||
]
|
||||
|
||||
|
||||
@@ -183,8 +183,10 @@ class FuzzyFilterMixin(viewsets.ModelViewSet, ExtendedRecipeMixin):
|
||||
|
||||
if query is not None and query not in ["''", '']:
|
||||
if fuzzy and (settings.DATABASES['default']['ENGINE'] == 'django.db.backends.postgresql'):
|
||||
if self.request.user.is_authenticated and any(
|
||||
[self.model.__name__.lower() in x for x in self.request.user.searchpreference.unaccent.values_list('field', flat=True)]):
|
||||
if (
|
||||
self.request.user.is_authenticated
|
||||
and any([self.model.__name__.lower() in x for x in self.request.user.searchpreference.unaccent.values_list('field', flat=True)])
|
||||
):
|
||||
self.queryset = self.queryset.annotate(trigram=TrigramSimilarity('name__unaccent', query))
|
||||
else:
|
||||
self.queryset = self.queryset.annotate(trigram=TrigramSimilarity('name', query))
|
||||
|
||||
@@ -19,10 +19,11 @@ from django.urls import reverse, reverse_lazy
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext as _
|
||||
from django_scopes import scopes_disabled
|
||||
from drf_spectacular.views import SpectacularRedocView, SpectacularSwaggerView
|
||||
|
||||
from cookbook.forms import CommentForm, Recipe, SearchPreferenceForm, SpaceCreateForm, SpaceJoinForm, User, UserCreateForm, UserPreference
|
||||
from cookbook.helper.HelperFunctions import str2bool
|
||||
from cookbook.helper.permission_helper import group_required, has_group_permission, share_link_valid, switch_user_active_space
|
||||
from cookbook.helper.permission_helper import CustomIsGuest, GroupRequiredMixin, group_required, has_group_permission, share_link_valid, switch_user_active_space
|
||||
from cookbook.models import Comment, CookLog, InviteLink, SearchFields, SearchPreference, ShareLink, Space, UserSpace, ViewLog
|
||||
from cookbook.tables import CookLogTable, ViewLogTable
|
||||
from cookbook.templatetags.theming_tags import get_theming_values
|
||||
@@ -38,16 +39,20 @@ def index(request):
|
||||
return HttpResponseRedirect(reverse_lazy('view_search'))
|
||||
|
||||
try:
|
||||
page_map = {UserPreference.SEARCH: reverse_lazy('view_search'), UserPreference.PLAN: reverse_lazy('view_plan'), UserPreference.BOOKS: reverse_lazy('view_books'), UserPreference.SHOPPING: reverse_lazy('view_shopping'),}
|
||||
page_map = {
|
||||
UserPreference.SEARCH: reverse_lazy('view_search'),
|
||||
UserPreference.PLAN: reverse_lazy('view_plan'),
|
||||
UserPreference.BOOKS: reverse_lazy('view_books'),
|
||||
UserPreference.SHOPPING: reverse_lazy('view_shopping'),
|
||||
}
|
||||
|
||||
return HttpResponseRedirect(page_map.get(request.user.userpreference.default_page))
|
||||
except UserPreference.DoesNotExist:
|
||||
return HttpResponseRedirect(reverse('view_search'))
|
||||
|
||||
|
||||
# TODO need to deprecate
|
||||
def search(request):
|
||||
if has_group_permission(request.user, ('guest',)):
|
||||
if has_group_permission(request.user, ('guest', )):
|
||||
return render(request, 'search.html', {})
|
||||
else:
|
||||
if request.user.is_authenticated:
|
||||
@@ -127,7 +132,7 @@ def recipe_view(request, pk, share=None):
|
||||
messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!'))
|
||||
return HttpResponseRedirect(reverse('account_login') + '?next=' + request.path)
|
||||
|
||||
if not (has_group_permission(request.user, ('guest',)) and recipe.space == request.space) and not share_link_valid(recipe, share):
|
||||
if not (has_group_permission(request.user, ('guest', )) and recipe.space == request.space) and not share_link_valid(recipe, share):
|
||||
messages.add_message(request, messages.ERROR, _('You do not have the required permissions to view this page!'))
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
@@ -160,7 +165,6 @@ def recipe_view(request, pk, share=None):
|
||||
return render(request, 'recipe_view.html', {'recipe': recipe, 'comments': comments, 'comment_form': comment_form, 'share': share, 'servings': servings})
|
||||
|
||||
|
||||
|
||||
@group_required('user')
|
||||
def books(request):
|
||||
return render(request, 'books.html', {})
|
||||
@@ -346,8 +350,17 @@ def system(request):
|
||||
|
||||
return render(
|
||||
request, 'system.html', {
|
||||
'gunicorn_media': settings.GUNICORN_MEDIA, 'debug': settings.DEBUG, 'postgres': postgres, 'postgres_version': postgres_ver, 'postgres_status': database_status,
|
||||
'postgres_message': database_message, 'version_info': VERSION_INFO, 'plugins': PLUGINS, 'secret_key': secret_key, 'orphans': orphans, 'migration_info': migration_info,
|
||||
'gunicorn_media': settings.GUNICORN_MEDIA,
|
||||
'debug': settings.DEBUG,
|
||||
'postgres': postgres,
|
||||
'postgres_version': postgres_ver,
|
||||
'postgres_status': database_status,
|
||||
'postgres_message': database_message,
|
||||
'version_info': VERSION_INFO,
|
||||
'plugins': PLUGINS,
|
||||
'secret_key': secret_key,
|
||||
'orphans': orphans,
|
||||
'migration_info': migration_info,
|
||||
'missing_migration': missing_migration,
|
||||
})
|
||||
|
||||
@@ -358,8 +371,7 @@ def setup(request):
|
||||
messages.add_message(
|
||||
request, messages.ERROR,
|
||||
_('The setup page can only be used to create the first user! \
|
||||
If you have forgotten your superuser credentials please consult the django documentation on how to reset passwords.'
|
||||
))
|
||||
If you have forgotten your superuser credentials please consult the django documentation on how to reset passwords.'))
|
||||
return HttpResponseRedirect(reverse('account_login'))
|
||||
|
||||
if request.method == 'POST':
|
||||
@@ -441,24 +453,63 @@ def report_share_abuse(request, token):
|
||||
def web_manifest(request):
|
||||
theme_values = get_theming_values(request)
|
||||
|
||||
icons = [{"src": theme_values['logo_color_svg'], "sizes": "any"}, {"src": theme_values['logo_color_144'], "type": "image/png", "sizes": "144x144"},
|
||||
{"src": theme_values['logo_color_512'], "type": "image/png", "sizes": "512x512"}]
|
||||
icons = [{
|
||||
"src": theme_values['logo_color_svg'],
|
||||
"sizes": "any"
|
||||
}, {
|
||||
"src": theme_values['logo_color_144'],
|
||||
"type": "image/png",
|
||||
"sizes": "144x144"
|
||||
}, {
|
||||
"src": theme_values['logo_color_512'],
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}]
|
||||
|
||||
manifest_info = {
|
||||
"name":
|
||||
theme_values['app_name'], "short_name":
|
||||
theme_values['app_name'], "description":
|
||||
_("Manage recipes, shopping list, meal plans and more."), "icons":
|
||||
icons, "start_url":
|
||||
"./", "background_color":
|
||||
theme_values['nav_bg_color'], "display":
|
||||
"standalone", "scope":
|
||||
".", "theme_color":
|
||||
theme_values['nav_bg_color'], "shortcuts":
|
||||
[{"name": _("Plan"), "short_name": _("Plan"), "description": _("View your meal Plan"), "url":
|
||||
"./plan"}, {"name": _("Books"), "short_name": _("Books"), "description": _("View your cookbooks"), "url": "./books"},
|
||||
{"name": _("Shopping"), "short_name": _("Shopping"), "description": _("View your shopping lists"), "url":
|
||||
"./shopping/"}], "share_target": {"action": "/data/import/url", "method": "GET", "params": {"title": "title", "url": "url", "text": "text"}}
|
||||
theme_values['app_name'],
|
||||
"short_name":
|
||||
theme_values['app_name'],
|
||||
"description":
|
||||
_("Manage recipes, shopping list, meal plans and more."),
|
||||
"icons":
|
||||
icons,
|
||||
"start_url":
|
||||
"./",
|
||||
"background_color":
|
||||
theme_values['nav_bg_color'],
|
||||
"display":
|
||||
"standalone",
|
||||
"scope":
|
||||
".",
|
||||
"theme_color":
|
||||
theme_values['nav_bg_color'],
|
||||
"shortcuts": [{
|
||||
"name": _("Plan"),
|
||||
"short_name": _("Plan"),
|
||||
"description": _("View your meal Plan"),
|
||||
"url": "./plan"
|
||||
}, {
|
||||
"name": _("Books"),
|
||||
"short_name": _("Books"),
|
||||
"description": _("View your cookbooks"),
|
||||
"url": "./books"
|
||||
}, {
|
||||
"name": _("Shopping"),
|
||||
"short_name": _("Shopping"),
|
||||
"description": _("View your shopping lists"),
|
||||
"url": "./shopping/"
|
||||
}],
|
||||
"share_target": {
|
||||
"action": "/data/import/url",
|
||||
"method": "GET",
|
||||
"params": {
|
||||
"title": "title",
|
||||
"url": "url",
|
||||
"text": "text"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return JsonResponse(manifest_info, json_dumps_params={'indent': 4})
|
||||
@@ -472,9 +523,14 @@ def search_info(request):
|
||||
return render(request, 'search_info.html', {})
|
||||
|
||||
|
||||
@group_required('guest')
|
||||
def api_info(request):
|
||||
return render(request, 'api_info.html', {})
|
||||
class Redoc(GroupRequiredMixin, SpectacularRedocView):
|
||||
permission_classes = [CustomIsGuest]
|
||||
groups_required = ['guest']
|
||||
|
||||
|
||||
class Swagger(GroupRequiredMixin, SpectacularSwaggerView):
|
||||
permission_classes = [CustomIsGuest]
|
||||
groups_required = ['guest']
|
||||
|
||||
|
||||
def offline(request):
|
||||
|
||||
@@ -14,9 +14,9 @@ import json
|
||||
import mimetypes
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import sys
|
||||
import traceback
|
||||
import socket
|
||||
|
||||
from django.contrib import messages
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@@ -24,6 +24,13 @@ from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
SCRIPT_NAME = os.getenv('SCRIPT_NAME', '')
|
||||
# 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_SCRIPT_PREFIX = os.getenv('JS_REVERSE_SCRIPT_PREFIX', SCRIPT_NAME)
|
||||
|
||||
STATIC_URL = os.getenv('STATIC_URL', '/static/')
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
|
||||
|
||||
# Get vars from .env files
|
||||
SECRET_KEY = os.getenv('SECRET_KEY') if os.getenv('SECRET_KEY') else 'INSECURE_STANDARD_KEY_SET_IN_ENV'
|
||||
@@ -105,34 +112,10 @@ MESSAGE_TAGS = {messages.ERROR: 'danger'}
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.postgres',
|
||||
'oauth2_provider',
|
||||
'django_prometheus',
|
||||
'django_tables2',
|
||||
'corsheaders',
|
||||
'crispy_forms',
|
||||
'crispy_bootstrap4',
|
||||
'rest_framework',
|
||||
'rest_framework.authtoken',
|
||||
'drf_spectacular',
|
||||
'drf_spectacular_sidecar',
|
||||
'django_cleanup.apps.CleanupConfig',
|
||||
'webpack_loader',
|
||||
'django_vite',
|
||||
'django_js_reverse',
|
||||
'hcaptcha',
|
||||
'allauth',
|
||||
'allauth.account',
|
||||
'allauth.socialaccount',
|
||||
'cookbook.apps.CookbookConfig',
|
||||
'treebeard',
|
||||
'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.sites',
|
||||
'django.contrib.staticfiles', 'django.contrib.postgres', 'oauth2_provider', 'django_prometheus', 'django_tables2', 'corsheaders', 'crispy_forms', 'crispy_bootstrap4',
|
||||
'rest_framework', 'rest_framework.authtoken', 'drf_spectacular', 'drf_spectacular_sidecar', 'django_cleanup.apps.CleanupConfig', 'webpack_loader', 'django_vite',
|
||||
'django_js_reverse', 'hcaptcha', 'allauth', 'allauth.account', 'allauth.socialaccount', 'cookbook.apps.CookbookConfig', 'treebeard',
|
||||
]
|
||||
|
||||
PLUGINS_DIRECTORY = os.path.join(BASE_DIR, 'recipes', 'plugins')
|
||||
@@ -209,14 +192,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',
|
||||
@@ -295,11 +278,13 @@ WRITE_SCOPE = 'write'
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_AUTHENTICATION_CLASSES':
|
||||
('rest_framework.authentication.SessionAuthentication', 'oauth2_provider.contrib.rest_framework.OAuth2Authentication', 'rest_framework.authentication.BasicAuthentication',
|
||||
),
|
||||
('rest_framework.authentication.SessionAuthentication', 'oauth2_provider.contrib.rest_framework.OAuth2Authentication', 'rest_framework.authentication.BasicAuthentication',
|
||||
),
|
||||
'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.IsAuthenticated', ],
|
||||
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
|
||||
'COERCE_DECIMAL_TO_STRING': False,
|
||||
'DEFAULT_SCHEMA_CLASS':
|
||||
'drf_spectacular.openapi.AutoSchema',
|
||||
'COERCE_DECIMAL_TO_STRING':
|
||||
False,
|
||||
}
|
||||
|
||||
SPECTACULAR_SETTINGS = {
|
||||
@@ -307,6 +292,38 @@ SPECTACULAR_SETTINGS = {
|
||||
'DESCRIPTION': 'Tandoor API Docs',
|
||||
'SERVE_INCLUDE_SCHEMA': False,
|
||||
'ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE': False,
|
||||
"AUTHENTICATION_WHITELIST": [],
|
||||
"APPEND_COMPONENTS": {
|
||||
"securitySchemes": {
|
||||
"ApiKeyAuth": {
|
||||
"type": "apiKey",
|
||||
"in": "header",
|
||||
"name": "Authorization",
|
||||
}
|
||||
}
|
||||
},
|
||||
"SECURITY": [{
|
||||
"ApiKeyAuth": []
|
||||
}],
|
||||
'SWAGGER_UI_DIST': 'SIDECAR',
|
||||
'SWAGGER_UI_FAVICON_HREF': 'SIDECAR',
|
||||
'REDOC_DIST': 'SIDECAR',
|
||||
'EXTENSIONS_INFO': {
|
||||
"x-logo": {
|
||||
"url": f"{STATIC_URL}assets/brand_logo.svg",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"altText": "Tandoor logo",
|
||||
'href': '/'
|
||||
}
|
||||
},
|
||||
'CAMELIZE_NAMES': True,
|
||||
"SWAGGER_UI_SETTINGS": {
|
||||
"deepLinking": True,
|
||||
"persistAuthorization": True,
|
||||
"hideDownloadButton": False,
|
||||
'schemaExpansionLevel': 'all',
|
||||
'showExtensions': True
|
||||
},
|
||||
}
|
||||
|
||||
ROOT_URLCONF = 'recipes.urls'
|
||||
@@ -419,14 +436,7 @@ for p in PLUGINS:
|
||||
'IGNORE': [r'.+\.hot-update.js', r'.+\.map'],
|
||||
}
|
||||
|
||||
DJANGO_VITE = {
|
||||
"default": {
|
||||
"dev_mode": False,
|
||||
"static_url_prefix": 'vue3',
|
||||
"dev_server_port": 5173,
|
||||
"dev_server_host": os.getenv('DJANGO_VITE_DEV_SERVER_HOST', 'localhost'),
|
||||
},
|
||||
}
|
||||
DJANGO_VITE = {"default": {"dev_mode": False, "static_url_prefix": 'vue3', "dev_server_port": 5173, "dev_server_host": os.getenv('DJANGO_VITE_DEV_SERVER_HOST', 'localhost'), }, }
|
||||
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.settimeout(0.001)
|
||||
@@ -462,14 +472,6 @@ LANGUAGES = [('hy', _('Armenian ')), ('bg', _('Bulgarian')), ('ca', _('Catalan')
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/2.0/howto/static-files/
|
||||
|
||||
SCRIPT_NAME = os.getenv('SCRIPT_NAME', '')
|
||||
# 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_SCRIPT_PREFIX = os.getenv('JS_REVERSE_SCRIPT_PREFIX', SCRIPT_NAME)
|
||||
|
||||
STATIC_URL = os.getenv('STATIC_URL', '/static/')
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
|
||||
|
||||
AWS_ENABLED = True if os.getenv('S3_ACCESS_KEY', False) else False
|
||||
|
||||
if os.getenv('S3_ACCESS_KEY', ''):
|
||||
@@ -529,18 +531,9 @@ DISABLE_EXTERNAL_CONNECTORS = bool(int(os.getenv('DISABLE_EXTERNAL_CONNECTORS',
|
||||
EXTERNAL_CONNECTORS_QUEUE_SIZE = int(os.getenv('EXTERNAL_CONNECTORS_QUEUE_SIZE', 100))
|
||||
|
||||
# ACCOUNT_SIGNUP_FORM_CLASS = 'cookbook.forms.AllAuthSignupForm'
|
||||
ACCOUNT_FORMS = {
|
||||
'signup': 'cookbook.forms.AllAuthSignupForm',
|
||||
'reset_password': 'cookbook.forms.CustomPasswordResetForm'
|
||||
}
|
||||
ACCOUNT_FORMS = {'signup': 'cookbook.forms.AllAuthSignupForm', 'reset_password': 'cookbook.forms.CustomPasswordResetForm'}
|
||||
|
||||
ACCOUNT_EMAIL_UNKNOWN_ACCOUNTS = False
|
||||
ACCOUNT_RATE_LIMITS = {
|
||||
"change_password": "1/m/user",
|
||||
"reset_password": "1/m/ip,1/m/key",
|
||||
"reset_password_from_key": "1/m/ip",
|
||||
"signup": "5/m/ip",
|
||||
"login": "5/m/ip",
|
||||
}
|
||||
ACCOUNT_RATE_LIMITS = {"change_password": "1/m/user", "reset_password": "1/m/ip,1/m/key", "reset_password_from_key": "1/m/ip", "signup": "5/m/ip", "login": "5/m/ip", }
|
||||
|
||||
mimetypes.add_type("text/javascript", ".js", True)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,9 +27,10 @@ export class ApiImportOpenDataApi extends runtime.BaseAPI {
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
if (this.configuration && (this.configuration.username !== undefined || this.configuration.password !== undefined)) {
|
||||
headerParameters["Authorization"] = "Basic " + btoa(this.configuration.username + ":" + this.configuration.password);
|
||||
if (this.configuration && this.configuration.apiKey) {
|
||||
headerParameters["Authorization"] = await this.configuration.apiKey("Authorization"); // ApiKeyAuth authentication
|
||||
}
|
||||
|
||||
const response = await this.request({
|
||||
path: `/api-import-open-data/`,
|
||||
method: 'POST',
|
||||
@@ -53,9 +54,10 @@ export class ApiImportOpenDataApi extends runtime.BaseAPI {
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
if (this.configuration && (this.configuration.username !== undefined || this.configuration.password !== undefined)) {
|
||||
headerParameters["Authorization"] = "Basic " + btoa(this.configuration.username + ":" + this.configuration.password);
|
||||
if (this.configuration && this.configuration.apiKey) {
|
||||
headerParameters["Authorization"] = await this.configuration.apiKey("Authorization"); // ApiKeyAuth authentication
|
||||
}
|
||||
|
||||
const response = await this.request({
|
||||
path: `/api-import-open-data/`,
|
||||
method: 'GET',
|
||||
|
||||
@@ -61,9 +61,10 @@ export class ApiTokenAuthApi extends runtime.BaseAPI {
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
if (this.configuration && (this.configuration.username !== undefined || this.configuration.password !== undefined)) {
|
||||
headerParameters["Authorization"] = "Basic " + btoa(this.configuration.username + ":" + this.configuration.password);
|
||||
if (this.configuration && this.configuration.apiKey) {
|
||||
headerParameters["Authorization"] = await this.configuration.apiKey("Authorization"); // ApiKeyAuth authentication
|
||||
}
|
||||
|
||||
const consumes: runtime.Consume[] = [
|
||||
{ contentType: 'application/x-www-form-urlencoded' },
|
||||
{ contentType: 'multipart/form-data' },
|
||||
|
||||
Reference in New Issue
Block a user