add ability to generate legacy API with legacy naming scheme

regenerate legacy API
This commit is contained in:
smilerz 2024-04-26 12:21:34 -05:00
parent 4fa7155fc3
commit 4771f890cb
No known key found for this signature in database
GPG key ID: 39444C7606D47126
11 changed files with 21299 additions and 13370 deletions

View file

@ -7,6 +7,7 @@
# WARNING: COMPONENT_SPLIT_REQUEST must be enabled, if not schemas might be wrong
def custom_postprocessing_hook(result, generator, request, public):
for c in result['components']['schemas'].keys():
# handle schemas used by the client to do requests on the server
@ -36,4 +37,90 @@ def custom_postprocessing_hook(result, generator, request, public):
else:
result['components']['schemas'][c]['required'].append('id')
return result
return result
# TODO remove below once legacy API has been fully deprecated
from drf_spectacular.openapi import AutoSchema # noqa: E402 isort: skip
import functools # noqa: E402 isort: skip
import re # noqa: E402 isort: skip
class LegacySchema(AutoSchema):
operation_id_base = None
@functools.cached_property
def path(self):
path = re.sub(pattern=self.path_prefix, repl='', string=self.path, flags=re.IGNORECASE)
# remove path variables
return re.sub(pattern=r'\{[\w\-]+\}', repl='', string=path)
def get_operation_id(self):
"""
Compute an operation ID from the view type and get_operation_id_base method.
"""
method_name = getattr(self.view, 'action', self.method.lower())
if self._is_list_view():
action = 'list'
elif method_name not in self.method_mapping:
action = self._to_camel_case(method_name)
else:
action = self.method_mapping[self.method.lower()]
name = self.get_operation_id_base(action)
return action + name
def get_operation_id_base(self, action):
"""
Compute the base part for operation ID from the model, serializer or view name.
"""
model = getattr(getattr(self.view, 'queryset', None), 'model', None)
if self.operation_id_base is not None:
name = self.operation_id_base
# Try to deduce the ID from the view's model
elif model is not None:
name = model.__name__
# Try with the serializer class name
elif self.get_serializer() is not None:
name = self.get_serializer().__class__.__name__
if name.endswith('Serializer'):
name = name[:-10]
# Fallback to the view name
else:
name = self.view.__class__.__name__
if name.endswith('APIView'):
name = name[:-7]
elif name.endswith('View'):
name = name[:-4]
# Due to camel-casing of classes and `action` being lowercase, apply title in order to find if action truly
# comes at the end of the name
if name.endswith(action.title()): # ListView, UpdateAPIView, ThingDelete ...
name = name[:-len(action)]
if action == 'list' and not name.endswith('s'): # listThings instead of listThing
name += 's'
return name
def get_serializer(self):
view = self.view
if not hasattr(view, 'get_serializer'):
return None
try:
return view.get_serializer()
except Exception:
return None
def _to_camel_case(self, snake_str):
components = snake_str.split('_')
# We capitalize the first letter of each component except the first one
# with the 'title' method and join them together.
return components[0] + ''.join(x.title() for x in components[1:])

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -52,11 +52,12 @@
"src": "node_modules/mavon-editor/dist/font/fontello.woff2"
},
"src/apps/tandoor/main.ts": {
"file": "assets/main-CnbWi3Kc.js",
"file": "assets/main-MtGxR7il.js",
"name": "main",
"src": "src/apps/tandoor/main.ts",
"isEntry": true,
"css": [
"assets/main-BiQ-D_PZ.css"
"assets/main-CNHK5kQT.css"
],
"assets": [
"assets/brand_logo-B3nCJMk0.svg",

View file

@ -40,7 +40,7 @@ from recipe_scrapers._exceptions import NoSchemaFoundInWildMode
from requests.exceptions import MissingSchema
from rest_framework import decorators, status, viewsets
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.decorators import action, api_view, permission_classes
from rest_framework.decorators import api_view, permission_classes
from rest_framework.exceptions import APIException, PermissionDenied
from rest_framework.pagination import PageNumberPagination
from rest_framework.parsers import MultiPartParser
@ -784,7 +784,7 @@ class MealPlanViewSet(viewsets.ModelViewSet):
return queryset
@action(detail=False)
@decorators.action(detail=False)
def ical(self, request):
from_date = self.request.query_params.get('from_date', None)
to_date = self.request.query_params.get('to_date', None)

View file

@ -13,14 +13,14 @@ PyCharm can be configured to format and lint on save. Doing so requires some man
2. Click the '+' to add a new watcher.
3. Configure the watcher as below.
![flake8_watcher](assets/flake8_watcher.png)
![flake8_watcher](assets/flake8_watcher.png)
4. Navigate to File -> Settings -> Editor -> Inspections -> File watcher problems
5. Under Severity select 'Edit Severities'
6. Click the '+' to add a severity calling it 'Linting Error'
7. Configure a background and effect as below.
![linting error](assets/linting_error.png)
![linting error](assets/linting_error.png)
## Setup isort
@ -28,7 +28,7 @@ PyCharm can be configured to format and lint on save. Doing so requires some man
2. Click the '+' to add a new watcher.
3. Configure the watcher as below.
![yapf_watcher](assets/isort_watcher.png)
![yapf_watcher](assets/isort_watcher.png)
## Setup yapf
@ -36,12 +36,16 @@ PyCharm can be configured to format and lint on save. Doing so requires some man
2. Click the '+' to add a new watcher.
3. Configure the watcher as below.
![yapf_watcher](assets/yapf_watcher.png)
![yapf_watcher](assets/yapf_watcher.png)
<!-- prettier-ignore -->
!!! hint
Adding a comma at the end of a list will trigger yapf to put each element of the list on a new line
<!-- prettier-ignore -->
!!! note
In order to debug vue yarn and vite servers must be started before starting the django server.
## Setup prettier
1. Navigate to File -> Settings -> Tools -> File Watchers
@ -50,13 +54,11 @@ PyCharm can be configured to format and lint on save. Doing so requires some man
4. Click the three dots next to 'Scope' to create a custom scope.
5. Click '+' to add a new scope
- Name: prettier
- Pattern: `file:vue/src//*||file:vue3/src//*||file:docs//*`
- Name: prettier
- Pattern: `file:vue/src//*||file:vue3/src//*||file:docs//*`
6. Configure the watcher as below.
![perttier_watcher](assets/prettier_watcher.png)
![perttier_watcher](assets/prettier_watcher.png)
- Arguments: `--cwd $ProjectFileDir$\vue prettier -w --config $ProjectFileDir$\.prettierrc $FilePath$`
## Setup Volar??
- Arguments: `--cwd $ProjectFileDir$\vue prettier -w --config $ProjectFileDir$\.prettierrc $FilePath$`

View file

@ -31,6 +31,10 @@ VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=esbenp.
## VSCode Tasks
<!-- prettier-ignore -->
!!! note
In order to debug vue yarn and vite servers must be started before starting the django server.
There are a number of built in tasks that are available. Here are a few of the key ones:
- `Setup Dev Server` - Runs all the prerequisite steps so that the dev server can be run inside VSCode.

View file

@ -5,6 +5,9 @@ DISABLE_ENDING_COMMA_HEURISTIC = false
COALESCE_BRACKETS = true
DEDENT_CLOSING_BRACKETS = true
FORCE_MULTILINE_DICT = false
INDENT_DICTIONARY_VALUE = true
SPLIT_BEFORE_DOT = true
ALLOW_SPLIT_BEFORE_DICT_VALUE = false
[tool.isort]
multi_line_output = 5

View file

@ -224,14 +224,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',
@ -271,13 +271,13 @@ if LDAP_AUTH:
"disable_existing_loggers": False,
"handlers": {
"console": {
"class": "logging.StreamHandler"
"class": "logging.StreamHandler",
}
},
"loggers": {
"django_auth_ldap": {
"level": "DEBUG",
"handlers": ["console"]
"handlers": ["console"],
}
},
}
@ -301,16 +301,16 @@ if REMOTE_USER_AUTH:
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'
},
]
@ -320,18 +320,23 @@ OAUTH2_PROVIDER = {'SCOPES': {'read': 'Read scope', 'write': 'Write scope', 'boo
READ_SCOPE = 'read'
WRITE_SCOPE = 'write'
##################################################################
####### change DEFAULT_SCHEMA_CLASS below to regenerate legacy API
##################################################################
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':
('rest_framework.authentication.SessionAuthentication', 'oauth2_provider.contrib.rest_framework.OAuth2Authentication', 'rest_framework.authentication.BasicAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.IsAuthenticated', ],
'DEFAULT_AUTHENTICATION_CLASSES': (
'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',
# 'DEFAULT_SCHEMA_CLASS': 'cookbook.helper.drf_spectacular_hooks.LegacySchema',
'COERCE_DECIMAL_TO_STRING': False,
}
##################################################################
####### change DEFAULT_SCHEMA_CLASS above to regenerate legacy API
##################################################################
SPECTACULAR_SETTINGS = {
'TITLE': 'Tandoor',
@ -349,7 +354,9 @@ SPECTACULAR_SETTINGS = {
}
}
},
"SECURITY": [{"ApiKeyAuth": []}],
"SECURITY": [{
"ApiKeyAuth": []
}],
'SWAGGER_UI_DIST': 'SIDECAR',
'SWAGGER_UI_FAVICON_HREF': 'SIDECAR',
'REDOC_DIST': 'SIDECAR',
@ -369,10 +376,7 @@ SPECTACULAR_SETTINGS = {
'schemaExpansionLevel': 'all',
'showExtensions': True
},
'POSTPROCESSING_HOOKS': [
'drf_spectacular.hooks.postprocess_schema_enums',
'cookbook.helper.drf_spectacular_hooks.custom_postprocessing_hook'
]
'POSTPROCESSING_HOOKS': ['drf_spectacular.hooks.postprocess_schema_enums', 'cookbook.helper.drf_spectacular_hooks.custom_postprocessing_hook']
}
ROOT_URLCONF = 'recipes.urls'
@ -620,10 +624,7 @@ 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 = {

View file

@ -243,7 +243,7 @@ export default {
"shared": autoPlan.shared,
"addshopping": autoPlan.addshopping
}
return apiClient.createAutoPlanViewSet(data)
return apiClient.createAutoPlan(data)
},
refreshEntries() { //TODO move properly to MealPLanStore (save period for default refresh)

File diff suppressed because it is too large Load diff