Skip to content

Commit b42a444

Browse files
authored
Merge pull request #3126 from smilerz/feature/vue3
legacy API
2 parents 991ff88 + 4771f89 commit b42a444

File tree

11 files changed

+13107
-5178
lines changed

11 files changed

+13107
-5178
lines changed

cookbook/helper/drf_spectacular_hooks.py

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
# WARNING: COMPONENT_SPLIT_REQUEST must be enabled, if not schemas might be wrong
99

10+
1011
def custom_postprocessing_hook(result, generator, request, public):
1112
for c in result['components']['schemas'].keys():
1213
# handle schemas used by the client to do requests on the server
@@ -36,4 +37,90 @@ def custom_postprocessing_hook(result, generator, request, public):
3637
else:
3738
result['components']['schemas'][c]['required'].append('id')
3839

39-
return result
40+
return result
41+
42+
43+
# TODO remove below once legacy API has been fully deprecated
44+
from drf_spectacular.openapi import AutoSchema # noqa: E402 isort: skip
45+
import functools # noqa: E402 isort: skip
46+
import re # noqa: E402 isort: skip
47+
48+
49+
class LegacySchema(AutoSchema):
50+
operation_id_base = None
51+
52+
@functools.cached_property
53+
def path(self):
54+
path = re.sub(pattern=self.path_prefix, repl='', string=self.path, flags=re.IGNORECASE)
55+
# remove path variables
56+
return re.sub(pattern=r'\{[\w\-]+\}', repl='', string=path)
57+
58+
def get_operation_id(self):
59+
"""
60+
Compute an operation ID from the view type and get_operation_id_base method.
61+
"""
62+
method_name = getattr(self.view, 'action', self.method.lower())
63+
if self._is_list_view():
64+
action = 'list'
65+
elif method_name not in self.method_mapping:
66+
action = self._to_camel_case(method_name)
67+
else:
68+
action = self.method_mapping[self.method.lower()]
69+
70+
name = self.get_operation_id_base(action)
71+
72+
return action + name
73+
74+
def get_operation_id_base(self, action):
75+
"""
76+
Compute the base part for operation ID from the model, serializer or view name.
77+
"""
78+
model = getattr(getattr(self.view, 'queryset', None), 'model', None)
79+
80+
if self.operation_id_base is not None:
81+
name = self.operation_id_base
82+
83+
# Try to deduce the ID from the view's model
84+
elif model is not None:
85+
name = model.__name__
86+
87+
# Try with the serializer class name
88+
elif self.get_serializer() is not None:
89+
name = self.get_serializer().__class__.__name__
90+
if name.endswith('Serializer'):
91+
name = name[:-10]
92+
93+
# Fallback to the view name
94+
else:
95+
name = self.view.__class__.__name__
96+
if name.endswith('APIView'):
97+
name = name[:-7]
98+
elif name.endswith('View'):
99+
name = name[:-4]
100+
101+
# Due to camel-casing of classes and `action` being lowercase, apply title in order to find if action truly
102+
# comes at the end of the name
103+
if name.endswith(action.title()): # ListView, UpdateAPIView, ThingDelete ...
104+
name = name[:-len(action)]
105+
106+
if action == 'list' and not name.endswith('s'): # listThings instead of listThing
107+
name += 's'
108+
109+
return name
110+
111+
def get_serializer(self):
112+
view = self.view
113+
114+
if not hasattr(view, 'get_serializer'):
115+
return None
116+
117+
try:
118+
return view.get_serializer()
119+
except Exception:
120+
return None
121+
122+
def _to_camel_case(self, snake_str):
123+
components = snake_str.split('_')
124+
# We capitalize the first letter of each component except the first one
125+
# with the 'title' method and join them together.
126+
return components[0] + ''.join(x.title() for x in components[1:])

cookbook/static/vue3/assets/main-CNHK5kQT.css

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cookbook/static/vue3/assets/main-MtGxR7il.js

Lines changed: 7821 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cookbook/static/vue3/manifest.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,12 @@
5252
"src": "node_modules/mavon-editor/dist/font/fontello.woff2"
5353
},
5454
"src/apps/tandoor/main.ts": {
55-
"file": "assets/main-CnbWi3Kc.js",
55+
"file": "assets/main-MtGxR7il.js",
56+
"name": "main",
5657
"src": "src/apps/tandoor/main.ts",
5758
"isEntry": true,
5859
"css": [
59-
"assets/main-BiQ-D_PZ.css"
60+
"assets/main-CNHK5kQT.css"
6061
],
6162
"assets": [
6263
"assets/brand_logo-B3nCJMk0.svg",

cookbook/views/api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
from requests.exceptions import MissingSchema
4141
from rest_framework import decorators, status, viewsets
4242
from rest_framework.authtoken.views import ObtainAuthToken
43-
from rest_framework.decorators import action, api_view, permission_classes
43+
from rest_framework.decorators import api_view, permission_classes
4444
from rest_framework.exceptions import APIException, PermissionDenied
4545
from rest_framework.pagination import PageNumberPagination
4646
from rest_framework.parsers import MultiPartParser
@@ -784,7 +784,7 @@ def get_queryset(self):
784784

785785
return queryset
786786

787-
@action(detail=False)
787+
@decorators.action(detail=False)
788788
def ical(self, request):
789789
from_date = self.request.query_params.get('from_date', None)
790790
to_date = self.request.query_params.get('to_date', None)

docs/contribute/pycharm.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,35 +13,39 @@ PyCharm can be configured to format and lint on save. Doing so requires some man
1313
2. Click the '+' to add a new watcher.
1414
3. Configure the watcher as below.
1515

16-
![flake8_watcher](assets/flake8_watcher.png)
16+
![flake8_watcher](assets/flake8_watcher.png)
1717

1818
4. Navigate to File -> Settings -> Editor -> Inspections -> File watcher problems
1919
5. Under Severity select 'Edit Severities'
2020
6. Click the '+' to add a severity calling it 'Linting Error'
2121
7. Configure a background and effect as below.
2222

23-
![linting error](assets/linting_error.png)
23+
![linting error](assets/linting_error.png)
2424

2525
## Setup isort
2626

2727
1. Navigate to File -> Settings -> Tools -> File Watchers
2828
2. Click the '+' to add a new watcher.
2929
3. Configure the watcher as below.
3030

31-
![yapf_watcher](assets/isort_watcher.png)
31+
![yapf_watcher](assets/isort_watcher.png)
3232

3333
## Setup yapf
3434

3535
1. Navigate to File -> Settings -> Tools -> File Watchers
3636
2. Click the '+' to add a new watcher.
3737
3. Configure the watcher as below.
3838

39-
![yapf_watcher](assets/yapf_watcher.png)
39+
![yapf_watcher](assets/yapf_watcher.png)
4040

4141
<!-- prettier-ignore -->
4242
!!! hint
4343
Adding a comma at the end of a list will trigger yapf to put each element of the list on a new line
4444

45+
<!-- prettier-ignore -->
46+
!!! note
47+
In order to debug vue yarn and vite servers must be started before starting the django server.
48+
4549
## Setup prettier
4650

4751
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
5054
4. Click the three dots next to 'Scope' to create a custom scope.
5155
5. Click '+' to add a new scope
5256

53-
- Name: prettier
54-
- Pattern: `file:vue/src//*||file:vue3/src//*||file:docs//*`
57+
- Name: prettier
58+
- Pattern: `file:vue/src//*||file:vue3/src//*||file:docs//*`
5559

5660
6. Configure the watcher as below.
5761

58-
![perttier_watcher](assets/prettier_watcher.png)
59-
60-
- Arguments: `--cwd $ProjectFileDir$\vue prettier -w --config $ProjectFileDir$\.prettierrc $FilePath$`
62+
![perttier_watcher](assets/prettier_watcher.png)
6163

62-
## Setup Volar??
64+
- Arguments: `--cwd $ProjectFileDir$\vue prettier -w --config $ProjectFileDir$\.prettierrc $FilePath$`

docs/contribute/vscode.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=esbenp.
3131

3232
## VSCode Tasks
3333

34+
<!-- prettier-ignore -->
35+
!!! note
36+
In order to debug vue yarn and vite servers must be started before starting the django server.
37+
3438
There are a number of built in tasks that are available. Here are a few of the key ones:
3539

3640
- `Setup Dev Server` - Runs all the prerequisite steps so that the dev server can be run inside VSCode.

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ DISABLE_ENDING_COMMA_HEURISTIC = false
55
COALESCE_BRACKETS = true
66
DEDENT_CLOSING_BRACKETS = true
77
FORCE_MULTILINE_DICT = false
8+
INDENT_DICTIONARY_VALUE = true
9+
SPLIT_BEFORE_DOT = true
10+
ALLOW_SPLIT_BEFORE_DICT_VALUE = false
811

912
[tool.isort]
1013
multi_line_output = 5

recipes/settings.py

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -224,14 +224,14 @@
224224
]
225225

226226
if DEBUG_TOOLBAR:
227-
MIDDLEWARE += ('debug_toolbar.middleware.DebugToolbarMiddleware',)
228-
INSTALLED_APPS += ('debug_toolbar',)
227+
MIDDLEWARE += ('debug_toolbar.middleware.DebugToolbarMiddleware', )
228+
INSTALLED_APPS += ('debug_toolbar', )
229229

230230
SORT_TREE_BY_NAME = bool(int(os.getenv('SORT_TREE_BY_NAME', False)))
231231
DISABLE_TREE_FIX_STARTUP = bool(int(os.getenv('DISABLE_TREE_FIX_STARTUP', False)))
232232

233233
if bool(int(os.getenv('SQL_DEBUG', False))):
234-
MIDDLEWARE += ('recipes.middleware.SqlPrintingMiddleware',)
234+
MIDDLEWARE += ('recipes.middleware.SqlPrintingMiddleware', )
235235

236236
if ENABLE_METRICS:
237237
MIDDLEWARE += 'django_prometheus.middleware.PrometheusAfterMiddleware',
@@ -271,13 +271,13 @@
271271
"disable_existing_loggers": False,
272272
"handlers": {
273273
"console": {
274-
"class": "logging.StreamHandler"
274+
"class": "logging.StreamHandler",
275275
}
276276
},
277277
"loggers": {
278278
"django_auth_ldap": {
279279
"level": "DEBUG",
280-
"handlers": ["console"]
280+
"handlers": ["console"],
281281
}
282282
},
283283
}
@@ -301,16 +301,16 @@
301301

302302
AUTH_PASSWORD_VALIDATORS = [
303303
{
304-
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
304+
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'
305305
},
306306
{
307-
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
307+
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'
308308
},
309309
{
310-
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
310+
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'
311311
},
312312
{
313-
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
313+
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'
314314
},
315315
]
316316

@@ -320,18 +320,23 @@
320320
READ_SCOPE = 'read'
321321
WRITE_SCOPE = 'write'
322322

323+
##################################################################
324+
####### change DEFAULT_SCHEMA_CLASS below to regenerate legacy API
325+
##################################################################
326+
323327
REST_FRAMEWORK = {
324-
'DEFAULT_AUTHENTICATION_CLASSES':
325-
('rest_framework.authentication.SessionAuthentication', 'oauth2_provider.contrib.rest_framework.OAuth2Authentication', 'rest_framework.authentication.BasicAuthentication',
326-
),
327-
'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.IsAuthenticated', ],
328+
'DEFAULT_AUTHENTICATION_CLASSES': (
329+
'rest_framework.authentication.SessionAuthentication', 'oauth2_provider.contrib.rest_framework.OAuth2Authentication', 'rest_framework.authentication.BasicAuthentication'
330+
),
331+
'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.IsAuthenticated'],
328332
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
333+
# 'DEFAULT_SCHEMA_CLASS': 'cookbook.helper.drf_spectacular_hooks.LegacySchema',
329334
'COERCE_DECIMAL_TO_STRING': False,
330335
}
331336

332-
333-
334-
337+
##################################################################
338+
####### change DEFAULT_SCHEMA_CLASS above to regenerate legacy API
339+
##################################################################
335340

336341
SPECTACULAR_SETTINGS = {
337342
'TITLE': 'Tandoor',
@@ -349,7 +354,9 @@
349354
}
350355
}
351356
},
352-
"SECURITY": [{"ApiKeyAuth": []}],
357+
"SECURITY": [{
358+
"ApiKeyAuth": []
359+
}],
353360
'SWAGGER_UI_DIST': 'SIDECAR',
354361
'SWAGGER_UI_FAVICON_HREF': 'SIDECAR',
355362
'REDOC_DIST': 'SIDECAR',
@@ -369,10 +376,7 @@
369376
'schemaExpansionLevel': 'all',
370377
'showExtensions': True
371378
},
372-
'POSTPROCESSING_HOOKS': [
373-
'drf_spectacular.hooks.postprocess_schema_enums',
374-
'cookbook.helper.drf_spectacular_hooks.custom_postprocessing_hook'
375-
]
379+
'POSTPROCESSING_HOOKS': ['drf_spectacular.hooks.postprocess_schema_enums', 'cookbook.helper.drf_spectacular_hooks.custom_postprocessing_hook']
376380
}
377381

378382
ROOT_URLCONF = 'recipes.urls'
@@ -620,10 +624,7 @@ def setup_database(db_url=None, db_options=None, db_engine=None, pg_host=None, p
620624
EXTERNAL_CONNECTORS_QUEUE_SIZE = int(os.getenv('EXTERNAL_CONNECTORS_QUEUE_SIZE', 100))
621625

622626
# ACCOUNT_SIGNUP_FORM_CLASS = 'cookbook.forms.AllAuthSignupForm'
623-
ACCOUNT_FORMS = {
624-
'signup': 'cookbook.forms.AllAuthSignupForm',
625-
'reset_password': 'cookbook.forms.CustomPasswordResetForm'
626-
}
627+
ACCOUNT_FORMS = {'signup': 'cookbook.forms.AllAuthSignupForm', 'reset_password': 'cookbook.forms.CustomPasswordResetForm'}
627628

628629
ACCOUNT_EMAIL_UNKNOWN_ACCOUNTS = False
629630
ACCOUNT_RATE_LIMITS = {

vue/src/components/AutoMealPlanModal.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ export default {
243243
"shared": autoPlan.shared,
244244
"addshopping": autoPlan.addshopping
245245
}
246-
return apiClient.createAutoPlanViewSet(data)
246+
return apiClient.createAutoPlan(data)
247247
248248
},
249249
refreshEntries() { //TODO move properly to MealPLanStore (save period for default refresh)

0 commit comments

Comments
 (0)