fastcodedog 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastcodedog-0.1.0/PKG-INFO +31 -0
- fastcodedog-0.1.0/README.md +3 -0
- fastcodedog-0.1.0/fastcodedog/__init__.py +1 -0
- fastcodedog-0.1.0/fastcodedog/api/__init__.py +1 -0
- fastcodedog-0.1.0/fastcodedog/api/api.py +177 -0
- fastcodedog-0.1.0/fastcodedog/api/api_package.py +49 -0
- fastcodedog-0.1.0/fastcodedog/api/app_function.py +22 -0
- fastcodedog-0.1.0/fastcodedog/api/config.py +68 -0
- fastcodedog-0.1.0/fastcodedog/api/db.py +31 -0
- fastcodedog-0.1.0/fastcodedog/api/main.py +60 -0
- fastcodedog-0.1.0/fastcodedog/api/oauth.py +120 -0
- fastcodedog-0.1.0/fastcodedog/cli.py +37 -0
- fastcodedog-0.1.0/fastcodedog/context/__init__.py +1 -0
- fastcodedog-0.1.0/fastcodedog/context/base.py +9 -0
- fastcodedog-0.1.0/fastcodedog/context/context.py +32 -0
- fastcodedog-0.1.0/fastcodedog/context/context_instance.py +52 -0
- fastcodedog-0.1.0/fastcodedog/context/contextbase.py +37 -0
- fastcodedog-0.1.0/fastcodedog/context/modules.py +12 -0
- fastcodedog-0.1.0/fastcodedog/context/oauth2.py +11 -0
- fastcodedog-0.1.0/fastcodedog/context/query.py +25 -0
- fastcodedog-0.1.0/fastcodedog/context/schema.py +32 -0
- fastcodedog-0.1.0/fastcodedog/context/tenant.py +11 -0
- fastcodedog-0.1.0/fastcodedog/crud/__init__.py +1 -0
- fastcodedog-0.1.0/fastcodedog/crud/_crud.py +168 -0
- fastcodedog-0.1.0/fastcodedog/crud/crud.py +78 -0
- fastcodedog-0.1.0/fastcodedog/crud/crud_package.py +26 -0
- fastcodedog-0.1.0/fastcodedog/crud/method_block.py +14 -0
- fastcodedog-0.1.0/fastcodedog/crud/param.py +13 -0
- fastcodedog-0.1.0/fastcodedog/diagram/README.MD +3 -0
- fastcodedog-0.1.0/fastcodedog/diagram/__init__.py +1 -0
- fastcodedog-0.1.0/fastcodedog/diagram/column.py +64 -0
- fastcodedog-0.1.0/fastcodedog/diagram/diagram.py +188 -0
- fastcodedog-0.1.0/fastcodedog/diagram/reference.xml +38 -0
- fastcodedog-0.1.0/fastcodedog/diagram/table.py +169 -0
- fastcodedog-0.1.0/fastcodedog/diagram/table.xml +130 -0
- fastcodedog-0.1.0/fastcodedog/generation/__init__.py +1 -0
- fastcodedog-0.1.0/fastcodedog/generation/classs_block.py +36 -0
- fastcodedog-0.1.0/fastcodedog/generation/file.py +90 -0
- fastcodedog-0.1.0/fastcodedog/generation/function_block.py +23 -0
- fastcodedog-0.1.0/fastcodedog/generation/generationbase.py +4 -0
- fastcodedog-0.1.0/fastcodedog/generation/import_stmt.py +62 -0
- fastcodedog-0.1.0/fastcodedog/generation/package.py +18 -0
- fastcodedog-0.1.0/fastcodedog/generation/param.py +15 -0
- fastcodedog-0.1.0/fastcodedog/generation/variable.py +35 -0
- fastcodedog-0.1.0/fastcodedog/model/__init__.py +1 -0
- fastcodedog-0.1.0/fastcodedog/model/_base.py +12 -0
- fastcodedog-0.1.0/fastcodedog/model/attribute.py +34 -0
- fastcodedog-0.1.0/fastcodedog/model/init.py +19 -0
- fastcodedog-0.1.0/fastcodedog/model/model.py +76 -0
- fastcodedog-0.1.0/fastcodedog/model/model_package.py +52 -0
- fastcodedog-0.1.0/fastcodedog/model/relation_object.py +39 -0
- fastcodedog-0.1.0/fastcodedog/model/sub_object.py +100 -0
- fastcodedog-0.1.0/fastcodedog/model/unique_stmt.py +16 -0
- fastcodedog-0.1.0/fastcodedog/schema/__init__.py +1 -0
- fastcodedog-0.1.0/fastcodedog/schema/attribute.py +29 -0
- fastcodedog-0.1.0/fastcodedog/schema/schema.py +119 -0
- fastcodedog-0.1.0/fastcodedog/schema/schema_additional.py +62 -0
- fastcodedog-0.1.0/fastcodedog/schema/schema_additional_class_block.py +92 -0
- fastcodedog-0.1.0/fastcodedog/schema/schema_additional_package.py +27 -0
- fastcodedog-0.1.0/fastcodedog/schema/schema_class_block.py +16 -0
- fastcodedog-0.1.0/fastcodedog/schema/schema_package.py +44 -0
- fastcodedog-0.1.0/fastcodedog/test/__init__.py +1 -0
- fastcodedog-0.1.0/fastcodedog/test/codes/__init__.py +1 -0
- fastcodedog-0.1.0/fastcodedog/test/codes/hello.py +9 -0
- fastcodedog-0.1.0/fastcodedog/test/codes/test_import.py +13 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/api/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/api/admin/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/api/admin/menu.py +48 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/api/admin/organization.py +48 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/api/admin/position.py +58 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/api/admin/tenant.py +38 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/api/admin/user.py +102 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/api/define/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/api/define/attribute.py +38 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/api/define/attribute_select_item.py +52 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/api/define/attribute_verification.py +38 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/api/oauth/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/api/oauth/oauth.py +53 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/api/operation/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/api/operation/api_log.py +38 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/config/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/config/config.ini +5 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/config/config.py +28 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/crud/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/crud/admin/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/crud/admin/menu.py +60 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/crud/admin/organization.py +60 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/crud/admin/position.py +83 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/crud/admin/tenant.py +37 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/crud/admin/user.py +113 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/crud/define/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/crud/define/attribute.py +37 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/crud/define/attribute_select_item.py +40 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/crud/define/attribute_verification.py +40 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/crud/operation/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/crud/operation/api_log.py +37 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/db.py +21 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/main.py +49 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/__init__.py +20 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/admin/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/admin/menu.py +30 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/admin/organization.py +29 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/admin/position.py +25 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/admin/position_menu.py +17 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/admin/tenant.py +20 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/admin/user.py +29 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/admin/user_organization.py +17 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/admin/user_position.py +17 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/base.py +12 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/define/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/define/attribute.py +31 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/define/attribute_select_item.py +25 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/define/attribute_verification.py +23 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/operation/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/model/operation/api_log.py +28 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/admin/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/admin/menu.py +38 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/admin/organization.py +37 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/admin/position.py +35 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/admin/tenant.py +40 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/admin/user.py +40 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/admin/user_additional.py +51 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/callback/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/callback/get_dynamic_attributes.py +15 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/define/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/define/attribute.py +39 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/define/attribute_select_item.py +37 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/define/attribute_select_item_additional.py +14 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/define/attribute_verification.py +35 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/operation/__init__.py +0 -0
- fastcodedog-0.1.0/fastcodedog/test/fakeapp/schema/operation/api_log.py +45 -0
- fastcodedog-0.1.0/fastcodedog/test/fastcodedog.api.oauth.json5 +21 -0
- fastcodedog-0.1.0/fastcodedog/test/fastcodedog.base.json5 +11 -0
- fastcodedog-0.1.0/fastcodedog/test/fastcodedog.crud.user.json5 +63 -0
- fastcodedog-0.1.0/fastcodedog/test/fastcodedog.diagram.json5 +43 -0
- fastcodedog-0.1.0/fastcodedog/test/fastcodedog.model.json5 +7 -0
- fastcodedog-0.1.0/fastcodedog/test/fastcodedog.schema.json5 +49 -0
- fastcodedog-0.1.0/fastcodedog/test/fastcodedog.schema.select_item.json5 +11 -0
- fastcodedog-0.1.0/fastcodedog/test/fastcodedog.schema.user.json5 +50 -0
- fastcodedog-0.1.0/fastcodedog/test/test_context.py +8 -0
- fastcodedog-0.1.0/fastcodedog/test/test_generate_all.py +57 -0
- fastcodedog-0.1.0/fastcodedog/test/test_generated_model.py +99 -0
- fastcodedog-0.1.0/fastcodedog/test/test_generated_model_with_tenant.py +109 -0
- fastcodedog-0.1.0/fastcodedog/todo.txt +5 -0
- fastcodedog-0.1.0/fastcodedog/util/__init__.py +1 -0
- fastcodedog-0.1.0/fastcodedog/util/case_converter.py +32 -0
- fastcodedog-0.1.0/fastcodedog/util/deep_update.py +35 -0
- fastcodedog-0.1.0/fastcodedog/util/find_file.py +15 -0
- fastcodedog-0.1.0/fastcodedog/util/indent.py +34 -0
- fastcodedog-0.1.0/fastcodedog/util/inflect_wrapper.py +22 -0
- fastcodedog-0.1.0/fastcodedog/util/make_dirs.py +27 -0
- fastcodedog-0.1.0/fastcodedog/util/singleton.py +15 -0
- fastcodedog-0.1.0/fastcodedog/util/type_converter.py +59 -0
- fastcodedog-0.1.0/fastcodedog/util/write_file.py +26 -0
- fastcodedog-0.1.0/pyproject.toml +36 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: fastcodedog
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary:
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: taohoo
|
|
7
|
+
Author-email: taohoo@163.com
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Requires-Dist: autopep8 (>=2.2.0)
|
|
15
|
+
Requires-Dist: fastapi (>=0.100.0)
|
|
16
|
+
Requires-Dist: fastoauth (>=0.1.0)
|
|
17
|
+
Requires-Dist: inflect (>=7.2.1)
|
|
18
|
+
Requires-Dist: json5 (>=0.9.25)
|
|
19
|
+
Requires-Dist: psycopg2[binary] (>=2.9.5)
|
|
20
|
+
Requires-Dist: pydantic (>=1.10.10)
|
|
21
|
+
Requires-Dist: pyopenssl (>=24.0.0)
|
|
22
|
+
Requires-Dist: python-jose (>=3.3.0)
|
|
23
|
+
Requires-Dist: python-multipart (>=0.0.9)
|
|
24
|
+
Requires-Dist: redis (>=5.0.5)
|
|
25
|
+
Requires-Dist: sqlalchemy (>=2.0.23)
|
|
26
|
+
Requires-Dist: uvicorn (>=0.30.0)
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
基于pdm文件,自动生成fastapi工程。
|
|
30
|
+
包括sqlalchemy的model,crud。
|
|
31
|
+
fastapi的schema,api。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from fastcodedog.context.context_instance import ctx_instance
|
|
3
|
+
from fastcodedog.crud.param import Param
|
|
4
|
+
from fastcodedog.generation.file import File
|
|
5
|
+
from fastcodedog.generation.function_block import FunctionBlock
|
|
6
|
+
from fastcodedog.generation.variable import Variable
|
|
7
|
+
from fastcodedog.util.case_converter import camel_to_snake
|
|
8
|
+
from .app_function import AppFunction
|
|
9
|
+
from .oauth import enable_api_oauth2
|
|
10
|
+
from ..util.inflect_wrapper import plural
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Api(File):
|
|
14
|
+
def __init__(self, crud, path, package, desc=None):
|
|
15
|
+
super().__init__(path, package, desc)
|
|
16
|
+
self.code = crud.code
|
|
17
|
+
self.crud = crud
|
|
18
|
+
self.schema = self.crud.schema
|
|
19
|
+
self.model = self.schema.model
|
|
20
|
+
self.schema_additional = ctx_instance.schema_additional_package.shcema_additionals.get(self.code)
|
|
21
|
+
|
|
22
|
+
# 需要计算属性
|
|
23
|
+
self.response_model = None
|
|
24
|
+
self.response_model_list = None
|
|
25
|
+
self.validate_response_function = None # 可用于判断是否有多个返回值
|
|
26
|
+
self.extra_function_params = {} # 额外请求参数,比如session,每个请求中都隐含
|
|
27
|
+
self.extra_function_params_when_get = {} # get请求的额外参数,比如response_model, session
|
|
28
|
+
self.extra_function_params_when_get_list = {} # get请求列表的额外参数,比如skip, limit, response_model, session
|
|
29
|
+
|
|
30
|
+
# 计算属性
|
|
31
|
+
self._init_import_stmt()
|
|
32
|
+
self._init_variable() # 会同步计算response_model、response_model_list和validate_response_model
|
|
33
|
+
self._init_properties()
|
|
34
|
+
# 检查是否启用oauth2
|
|
35
|
+
enable_api_oauth2(self)
|
|
36
|
+
self._init_method()
|
|
37
|
+
|
|
38
|
+
def _init_method(self):
|
|
39
|
+
for function_block in self.crud.function_blocks.values():
|
|
40
|
+
method = self.get_app_method(function_block.option)
|
|
41
|
+
model_id_name = camel_to_snake(self.model.class_name) + '_id'
|
|
42
|
+
url = f'/{plural(camel_to_snake(self.model.class_name))}' if function_block.return_list else f'/{camel_to_snake(self.model.class_name)}'
|
|
43
|
+
if not function_block.return_list and model_id_name in function_block.params.keys():
|
|
44
|
+
url += '/{' + model_id_name + '}'
|
|
45
|
+
if function_block.query_name:
|
|
46
|
+
url += '/' + camel_to_snake(function_block.query_name)
|
|
47
|
+
elif function_block.schema_additional_name:
|
|
48
|
+
url += '/' + camel_to_snake(function_block.schema_additional_name)
|
|
49
|
+
elif function_block.sub_object_name:
|
|
50
|
+
url += '/' + camel_to_snake(function_block.sub_object_name)
|
|
51
|
+
app_func = AppFunction(function_block.name, self, method, url)
|
|
52
|
+
app_func.params = {k: v for k, v in function_block.params.items() if
|
|
53
|
+
k not in self.extra_function_params.keys()}
|
|
54
|
+
for k, v in function_block.params.items():
|
|
55
|
+
if k in self.extra_function_params.keys():
|
|
56
|
+
continue
|
|
57
|
+
app_func.params[k] = Param(k, parent=self, default=v.default, nullable=v.nullable,
|
|
58
|
+
type=v.type if not v.schema_class_block else v.schema_class_block.name)
|
|
59
|
+
|
|
60
|
+
app_func.content = f'crud.{function_block.name}(' + ', '.join(
|
|
61
|
+
[f'{k}={v.code}' for k, v in function_block.params.items()]) + ')'
|
|
62
|
+
if function_block.return_list:
|
|
63
|
+
app_func.reponse_model = self.response_model_list
|
|
64
|
+
app_func.params.update(self.extra_function_params_when_get_list)
|
|
65
|
+
if self.validate_response_function:
|
|
66
|
+
app_func.content = f'return [response_model.from_orm({camel_to_snake(self.model.class_name)}) for {camel_to_snake(self.model.class_name)} in {app_func.content}]'
|
|
67
|
+
else:
|
|
68
|
+
app_func.content = f'return {app_func.content}'
|
|
69
|
+
elif method != 'delete':
|
|
70
|
+
app_func.reponse_model = self.response_model
|
|
71
|
+
app_func.params.update(self.extra_function_params_when_get)
|
|
72
|
+
if self.validate_response_function:
|
|
73
|
+
app_func.content = f'return response_model.from_orm({app_func.content})'
|
|
74
|
+
else:
|
|
75
|
+
app_func.content = f'return {app_func.content}'
|
|
76
|
+
else:
|
|
77
|
+
app_func.params.update(self.extra_function_params)
|
|
78
|
+
app_func.content += '\n'
|
|
79
|
+
self.function_blocks[app_func.name] = app_func
|
|
80
|
+
...
|
|
81
|
+
|
|
82
|
+
def get_app_method(self, option):
|
|
83
|
+
if option == 'get':
|
|
84
|
+
return 'get'
|
|
85
|
+
if option == 'create':
|
|
86
|
+
return 'post'
|
|
87
|
+
if option == 'update':
|
|
88
|
+
return 'put'
|
|
89
|
+
if option == 'delete':
|
|
90
|
+
return 'delete'
|
|
91
|
+
|
|
92
|
+
def _init_properties(self):
|
|
93
|
+
# 要先初始化_init_variable,确保validate_response_function已经被正确设置
|
|
94
|
+
self.extra_function_params['session'] = Param('session', parent=self, type='Session',
|
|
95
|
+
default='Depends(get_session)')
|
|
96
|
+
if self.validate_response_function:
|
|
97
|
+
self.extra_function_params_when_get['response_model'] = Param('response_model', parent=self,
|
|
98
|
+
type='BaseModel',
|
|
99
|
+
default=f'Depends({self.validate_response_function})')
|
|
100
|
+
self.extra_function_params_when_get.update(self.extra_function_params)
|
|
101
|
+
# self.extra_function_params_when_get_list['skip'] = Param('skip', parent=self, type='int', default=0)
|
|
102
|
+
# self.extra_function_params_when_get_list['limit'] = Param('limit', parent=self, type='int', default=50)
|
|
103
|
+
self.extra_function_params_when_get_list.update(self.extra_function_params_when_get)
|
|
104
|
+
|
|
105
|
+
def _init_variable(self):
|
|
106
|
+
self.variables['app'] = Variable('app', parent=self, default='FastAPI()')
|
|
107
|
+
response_class_blocks = []
|
|
108
|
+
for class_block in self.schema.class_blocks.values():
|
|
109
|
+
if class_block.method == 'response':
|
|
110
|
+
response_class_blocks.append(class_block)
|
|
111
|
+
# 所有的schema_additional
|
|
112
|
+
if self.schema_additional:
|
|
113
|
+
for class_block in self.schema_additional.class_blocks.values():
|
|
114
|
+
if class_block.method == 'response':
|
|
115
|
+
response_class_blocks.append(class_block)
|
|
116
|
+
if len(response_class_blocks) == 1:
|
|
117
|
+
self.response_model = response_class_blocks[0].name
|
|
118
|
+
self.response_model_list = f'list[{response_class_blocks[0].name}]'
|
|
119
|
+
elif len(response_class_blocks) > 1:
|
|
120
|
+
self.response_model = f'ALL_{self.model.class_name.upper()}_RESPONSE_MODEL'
|
|
121
|
+
self.response_model_list = f'ALL_{self.model.class_name.upper()}_LIST_RESPONSE_MODEL'
|
|
122
|
+
self.variables[self.response_model] = Variable(self.response_model, parent=self, type='Union',
|
|
123
|
+
default=f'Union[{", ".join([response_class_block.name for response_class_block in response_class_blocks])}]')
|
|
124
|
+
self.variables[self.response_model_list] = Variable(self.response_model_list, parent=self, type='Union',
|
|
125
|
+
default=f'Union[{", ".join(["list[" + response_class_block.name + "]" for response_class_block in response_class_blocks])}]')
|
|
126
|
+
self._add_validate_response_model_function(response_class_blocks)
|
|
127
|
+
|
|
128
|
+
def _add_validate_response_model_function(self, response_class_blocks):
|
|
129
|
+
function_name = f'validate_{self.model.class_name.lower()}_response_model'
|
|
130
|
+
function = FunctionBlock(function_name, parent=self)
|
|
131
|
+
request_allow = [f"'{camel_to_snake(response_class_block.name)}'" for response_class_block in
|
|
132
|
+
response_class_blocks]
|
|
133
|
+
param_default = f"Query(None, description=\"指定返回的数据类型,默认为'{camel_to_snake(self.model.class_name)}'\", enum=[{', '.join(request_allow)}])"
|
|
134
|
+
function.params['response_model'] = Param('response_model', parent=function, type='str', default=param_default)
|
|
135
|
+
function.content = f"""if response_model and response_model not in [{', '.join(request_allow)}]:
|
|
136
|
+
raise HTTPException(status_code=400,
|
|
137
|
+
detail="Invalid response_model. Must in {', '.join(request_allow)}.")
|
|
138
|
+
"""
|
|
139
|
+
for class_block in response_class_blocks:
|
|
140
|
+
function.content += f"if response_model == '{camel_to_snake(class_block.name)}':\n"
|
|
141
|
+
function.content += f" return {class_block.name}\n"
|
|
142
|
+
function.content += f"return {self.model.class_name}\n"
|
|
143
|
+
|
|
144
|
+
self.validate_response_function = function_name
|
|
145
|
+
self.function_blocks[function_name] = function
|
|
146
|
+
|
|
147
|
+
def _init_import_stmt(self):
|
|
148
|
+
self.import_stmt.add_import('fastapi', 'FastAPI')
|
|
149
|
+
self.import_stmt.add_import('fastapi', 'Depends')
|
|
150
|
+
self.import_stmt.add_import('pydantic', 'BaseModel')
|
|
151
|
+
self.import_stmt.add_import(ctx_instance.base.package, ctx_instance.base.class_name)
|
|
152
|
+
self.import_stmt.add_import(f'{ctx_instance.project_package}.db', 'Session')
|
|
153
|
+
self.import_stmt.add_import(f'{ctx_instance.project_package}.db', 'get_session')
|
|
154
|
+
self.import_stmt.add_import(from_=None, import_=self.crud.package, as_='crud')
|
|
155
|
+
response_model_count = 0
|
|
156
|
+
# 所有的schema
|
|
157
|
+
for class_block in self.schema.class_blocks.values():
|
|
158
|
+
if class_block.method in ['response', 'create', 'update']:
|
|
159
|
+
self.import_stmt.add_import(self.schema.package, class_block.name)
|
|
160
|
+
for attribute in class_block.attributes.values():
|
|
161
|
+
if attribute.nullable:
|
|
162
|
+
self.import_stmt.add_import('typing', 'Optional')
|
|
163
|
+
if class_block.method == 'response':
|
|
164
|
+
response_model_count += 1
|
|
165
|
+
# 所有的schema_additional
|
|
166
|
+
if self.schema_additional:
|
|
167
|
+
for class_block in self.schema_additional.class_blocks.values():
|
|
168
|
+
self.import_stmt.add_import(self.schema_additional.package, class_block.name)
|
|
169
|
+
for attribute in class_block.attributes.values():
|
|
170
|
+
if attribute.nullable:
|
|
171
|
+
self.import_stmt.add_import('typing', 'Optional')
|
|
172
|
+
if class_block.method == 'response':
|
|
173
|
+
response_model_count += 1
|
|
174
|
+
if response_model_count > 1:
|
|
175
|
+
self.import_stmt.add_import('typing', 'Union')
|
|
176
|
+
self.import_stmt.add_import('fastapi', 'Query')
|
|
177
|
+
self.import_stmt.add_import('fastapi', 'HTTPException')
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from fastcodedog.api.api import Api
|
|
5
|
+
from fastcodedog.api.config import Config
|
|
6
|
+
from fastcodedog.api.db import Db
|
|
7
|
+
from fastcodedog.api.main import Main
|
|
8
|
+
from fastcodedog.api.oauth import OAuth
|
|
9
|
+
from fastcodedog.context.context_instance import ctx_instance
|
|
10
|
+
from fastcodedog.generation.package import Package
|
|
11
|
+
from fastcodedog.util.case_converter import camel_to_snake
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ApiPackage(Package):
|
|
15
|
+
def __init__(self):
|
|
16
|
+
self.package = f'{ctx_instance.project_package}.api'
|
|
17
|
+
self.dir = os.path.join(ctx_instance.project_dir, 'api')
|
|
18
|
+
|
|
19
|
+
self.config_dir = os.path.join(ctx_instance.project_dir, 'config')
|
|
20
|
+
|
|
21
|
+
# 固定的文件
|
|
22
|
+
self.config = Config(os.path.join(self.config_dir, 'config.py'), f'{ctx_instance.project_package}.config')
|
|
23
|
+
self.db = Db(os.path.join(ctx_instance.project_dir, 'db.py'), f'{ctx_instance.project_package}.db')
|
|
24
|
+
self.main = Main(os.path.join(ctx_instance.project_dir, 'main.py'), f'{ctx_instance.project_package}.main')
|
|
25
|
+
self.oauth = OAuth(os.path.join(self.dir, 'oauth', 'oauth.py'),
|
|
26
|
+
f'{self.package}.oauth.oauth') if ctx_instance.oauth2.enabled else None
|
|
27
|
+
# 计算属性
|
|
28
|
+
self.apis = {}
|
|
29
|
+
|
|
30
|
+
for code, crud in ctx_instance.crud_package.cruds.items():
|
|
31
|
+
table = crud.schema.model.table
|
|
32
|
+
path = os.path.join(self.dir, table.module, self.get_file_name(table))
|
|
33
|
+
package = f'{self.package}.{table.module}.{camel_to_snake(self.get_class_name(table))}'
|
|
34
|
+
api = Api(crud, path, package)
|
|
35
|
+
self.apis[code] = api
|
|
36
|
+
|
|
37
|
+
for api in self.apis.values():
|
|
38
|
+
self.main.add_api(api)
|
|
39
|
+
if self.oauth:
|
|
40
|
+
self.main.add_api(self.oauth, as_='oauth_app')
|
|
41
|
+
|
|
42
|
+
def save(self):
|
|
43
|
+
self.config.save()
|
|
44
|
+
self.db.save()
|
|
45
|
+
for api in self.apis.values():
|
|
46
|
+
api.save()
|
|
47
|
+
self.main.save()
|
|
48
|
+
if self.oauth:
|
|
49
|
+
self.oauth.save()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from fastcodedog.generation.function_block import FunctionBlock
|
|
3
|
+
from fastcodedog.util.indent import add_indent
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AppFunction(FunctionBlock):
|
|
7
|
+
def __init__(self, name, parent, method, url, reponse_model=None, response_model_exclude_none=True, params=None):
|
|
8
|
+
super().__init__(name, parent, params)
|
|
9
|
+
self.method = method
|
|
10
|
+
self.url = url
|
|
11
|
+
self.reponse_model = reponse_model
|
|
12
|
+
self.response_model_exclude_none = response_model_exclude_none
|
|
13
|
+
|
|
14
|
+
def serialize(self, indent=''):
|
|
15
|
+
app_params = [f"'{self.url}'"]
|
|
16
|
+
if self.reponse_model:
|
|
17
|
+
app_params.append(f'response_model={self.reponse_model}')
|
|
18
|
+
if self.response_model_exclude_none:
|
|
19
|
+
app_params.append('response_model_exclude_none=True')
|
|
20
|
+
content = f'@app.{self.method}({", ".join(app_params)})\n'
|
|
21
|
+
content += super().serialize()
|
|
22
|
+
return add_indent(content, indent)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from fastcodedog.generation.file import File
|
|
4
|
+
from fastcodedog.generation.function_block import FunctionBlock
|
|
5
|
+
from fastcodedog.generation.variable import Variable
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Config(File):
|
|
9
|
+
def __init__(self, path, package, desc=None):
|
|
10
|
+
super().__init__(path, package, desc)
|
|
11
|
+
self.config_file = path[:-3] + '.ini'
|
|
12
|
+
self.config_content = self._get_config_content()
|
|
13
|
+
self._init_import_stmt()
|
|
14
|
+
self._init_funciton()
|
|
15
|
+
self._init_variables()
|
|
16
|
+
|
|
17
|
+
def _init_variables(self):
|
|
18
|
+
self.variables['_all_configs_'] = Variable('_all_configs_', self, type=dict, default={})
|
|
19
|
+
self.variables['listion_port'] = Variable('listion_port', self, type='function',
|
|
20
|
+
default="get_config('app', 'port', 8000)")
|
|
21
|
+
self.variables['db_url'] = Variable('db_url', self, type='function',
|
|
22
|
+
default="get_config('database', 'url', None)")
|
|
23
|
+
|
|
24
|
+
def _init_funciton(self):
|
|
25
|
+
func = FunctionBlock('get_config', self)
|
|
26
|
+
func.params['section'] = Variable('section', func)
|
|
27
|
+
func.params['key'] = Variable('key', func)
|
|
28
|
+
func.params['default'] = Variable('default', func, default=None)
|
|
29
|
+
func.content = f"""c_key = f'{{section}}.{{key}}'
|
|
30
|
+
if c_key not in _all_configs_:
|
|
31
|
+
confif_file = os.path.join(os.path.dirname(__file__), 'config.ini')
|
|
32
|
+
config = configparser.ConfigParser()
|
|
33
|
+
config.read(confif_file)
|
|
34
|
+
_all_configs_[c_key] = None
|
|
35
|
+
if section in config and config.get(section, key):
|
|
36
|
+
_all_configs_[c_key] = config.get(section, key)
|
|
37
|
+
if c_key in _all_configs_ and _all_configs_[c_key] is not None:
|
|
38
|
+
return _all_configs_[c_key]
|
|
39
|
+
return default
|
|
40
|
+
"""
|
|
41
|
+
self.function_blocks['get_config'] = func
|
|
42
|
+
|
|
43
|
+
def _init_import_stmt(self):
|
|
44
|
+
self.import_stmt.add_import(from_=None, import_='configparser')
|
|
45
|
+
self.import_stmt.add_import(from_=None, import_='os')
|
|
46
|
+
|
|
47
|
+
def _get_config_content(self):
|
|
48
|
+
return """[app]
|
|
49
|
+
port=8000
|
|
50
|
+
|
|
51
|
+
[database]
|
|
52
|
+
url=postgresql://ccuser:Cc_12345678@192.168.44.128:15432/ccdb
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def serialize(self):
|
|
56
|
+
content = self.annotation_stmt.serialize()
|
|
57
|
+
content += self.import_stmt.serialize()
|
|
58
|
+
content += '\n'
|
|
59
|
+
content += self.serialize_function_blocks()
|
|
60
|
+
content += self.serialize_variable_stmt()
|
|
61
|
+
content += self.serialize_class_blocks()
|
|
62
|
+
return content
|
|
63
|
+
|
|
64
|
+
def save(self):
|
|
65
|
+
super().save()
|
|
66
|
+
# 写一份配置文件
|
|
67
|
+
with open(self.config_file, 'w', encoding='utf-8') as f:
|
|
68
|
+
f.write(self.config_content)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from fastcodedog.generation.file import File
|
|
3
|
+
from fastcodedog.generation.function_block import FunctionBlock
|
|
4
|
+
from fastcodedog.generation.variable import Variable
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Db(File):
|
|
8
|
+
def __init__(self, path, package, desc=None):
|
|
9
|
+
super().__init__(path, package, desc)
|
|
10
|
+
self._init_import_stmt()
|
|
11
|
+
self._init_funciton()
|
|
12
|
+
self._init_variables()
|
|
13
|
+
|
|
14
|
+
def _init_import_stmt(self):
|
|
15
|
+
self.import_stmt.add_import('sqlalchemy', 'create_engine')
|
|
16
|
+
self.import_stmt.add_import('sqlalchemy.orm', 'sessionmaker')
|
|
17
|
+
self.import_stmt.add_import('.config.config', 'db_url')
|
|
18
|
+
|
|
19
|
+
def _init_variables(self):
|
|
20
|
+
self.variables['engine'] = Variable('engine', self, type='function', default="create_engine(db_url)")
|
|
21
|
+
self.variables['Session'] = Variable('Session', self, type='function', default="sessionmaker(bind=engine)")
|
|
22
|
+
|
|
23
|
+
def _init_funciton(self):
|
|
24
|
+
func = FunctionBlock('get_session', self)
|
|
25
|
+
func.content = f"""session = Session()
|
|
26
|
+
try:
|
|
27
|
+
yield session
|
|
28
|
+
finally:
|
|
29
|
+
session.close()
|
|
30
|
+
"""
|
|
31
|
+
self.function_blocks[func.name] = func
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from fastcodedog.context.context_instance import ctx_instance
|
|
3
|
+
from fastcodedog.generation.file import File
|
|
4
|
+
from fastcodedog.generation.variable import Variable
|
|
5
|
+
from fastcodedog.util.case_converter import camel_to_snake
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Main(File):
|
|
9
|
+
def __init__(self, path, package, desc=None):
|
|
10
|
+
super().__init__(path, package, desc)
|
|
11
|
+
|
|
12
|
+
self.script_lines = []
|
|
13
|
+
self.main_content = """if __name__ == "__main__":
|
|
14
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
15
|
+
"""
|
|
16
|
+
self._init_import_stmt()
|
|
17
|
+
self._init_variables()
|
|
18
|
+
self._init_script_lines()
|
|
19
|
+
self._init_extended_apps()
|
|
20
|
+
|
|
21
|
+
def _init_extended_apps(self):
|
|
22
|
+
for api_name, api_package in ctx_instance.extended_apps.items():
|
|
23
|
+
self.import_stmt.add_import(api_package, 'app', f'{api_name}_app')
|
|
24
|
+
self.script_lines.append(f'app.include_router({api_name}_app.router)')
|
|
25
|
+
|
|
26
|
+
def _init_script_lines(self):
|
|
27
|
+
self.script_lines.extend("""@app.exception_handler(SQLAlchemyError)
|
|
28
|
+
async def sqlalchemy_exception_handler(request, exc):
|
|
29
|
+
raise HTTPException(
|
|
30
|
+
status_code=HTTP_500_INTERNAL_SERVER_ERROR,
|
|
31
|
+
detail=f"Database operation failed: {exc}",
|
|
32
|
+
)
|
|
33
|
+
""".splitlines())
|
|
34
|
+
self.script_lines.append('logging.basicConfig()')
|
|
35
|
+
self.script_lines.append("logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)")
|
|
36
|
+
|
|
37
|
+
def _init_variables(self):
|
|
38
|
+
self.variables['app'] = Variable('app', self, default='FastAPI()')
|
|
39
|
+
|
|
40
|
+
def _init_import_stmt(self):
|
|
41
|
+
self.import_stmt.add_import(None, 'uvicorn')
|
|
42
|
+
self.import_stmt.add_import(None, 'logging')
|
|
43
|
+
self.import_stmt.add_import('fastapi', 'FastAPI')
|
|
44
|
+
self.import_stmt.add_import('fastapi', 'HTTPException')
|
|
45
|
+
self.import_stmt.add_import('sqlalchemy.exc', 'SQLAlchemyError')
|
|
46
|
+
self.import_stmt.add_import('starlette.status', 'HTTP_500_INTERNAL_SERVER_ERROR')
|
|
47
|
+
|
|
48
|
+
def add_api(self, api, as_=None):
|
|
49
|
+
if not as_:
|
|
50
|
+
as_ = f'{camel_to_snake(api.model.class_name)}_app'
|
|
51
|
+
self.import_stmt.add_import(api.package, 'app', as_)
|
|
52
|
+
self.script_lines.append(f'app.include_router({as_}.router)')
|
|
53
|
+
|
|
54
|
+
def serialize(self):
|
|
55
|
+
content = super().serialize()
|
|
56
|
+
for line in self.script_lines:
|
|
57
|
+
content += line + '\n'
|
|
58
|
+
content += '\n'
|
|
59
|
+
content += self.main_content
|
|
60
|
+
return content
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from fastcodedog.api.app_function import AppFunction
|
|
3
|
+
from fastcodedog.context.context_instance import ctx_instance
|
|
4
|
+
from fastcodedog.crud.param import Param
|
|
5
|
+
from fastcodedog.generation.file import File
|
|
6
|
+
from fastcodedog.generation.variable import Variable
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def enable_api_oauth2(cls):
|
|
10
|
+
if ctx_instance.oauth2.enabled:
|
|
11
|
+
cls.import_stmt.add_import('fastapi.security', 'OAuth2PasswordBearer')
|
|
12
|
+
cls.import_stmt.add_import('typing', 'Annotated')
|
|
13
|
+
cls.variables['oauth2_scheme '] = Variable('oauth2_scheme ', cls,
|
|
14
|
+
default="OAuth2PasswordBearer(tokenUrl='/oauth/token')")
|
|
15
|
+
cls.extra_function_params['token'] = Param('token', parent=cls, type='Annotated[str, Depends(oauth2_scheme)]',
|
|
16
|
+
nullable=False)
|
|
17
|
+
cls.extra_function_params_when_get['token'] = Param('token', parent=cls,
|
|
18
|
+
type='Annotated[str, Depends(oauth2_scheme)]',
|
|
19
|
+
nullable=False)
|
|
20
|
+
cls.extra_function_params_when_get_list['token'] = Param('token', parent=cls,
|
|
21
|
+
type='Annotated[str, Depends(oauth2_scheme)]',
|
|
22
|
+
nullable=False)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class OAuth(File):
|
|
26
|
+
def __init__(self, path, package, desc=None):
|
|
27
|
+
desc = """
|
|
28
|
+
OAuth2.SECRET_KEY =
|
|
29
|
+
OAuth2.EXPIRE_SECONDS = 60*60*2
|
|
30
|
+
OAuth2.REDIS_URL = 'redis://localhost:6379/oauth2'
|
|
31
|
+
"""
|
|
32
|
+
super().__init__(path, package, desc)
|
|
33
|
+
|
|
34
|
+
self.user_model = ctx_instance.model_package.models.get(ctx_instance.oauth2.user_table)
|
|
35
|
+
self.tenant_model = ctx_instance.model_package.models.get(
|
|
36
|
+
ctx_instance.tenant.tenant_table_code) if ctx_instance.tenant.enabled else None
|
|
37
|
+
self.param_session = Param('session', parent=self, type='Session', default='Depends(get_session)')
|
|
38
|
+
self.param_token = Param('token', parent=self, type='Annotated[str, Depends(oauth2_scheme)]', nullable=False)
|
|
39
|
+
self._init_import_stmt()
|
|
40
|
+
self._init_variables()
|
|
41
|
+
self._init_functions()
|
|
42
|
+
|
|
43
|
+
def _init_functions(self):
|
|
44
|
+
self._init_login_function()
|
|
45
|
+
self._init_remove_token_function()
|
|
46
|
+
self._init_refresh_token_function()
|
|
47
|
+
self._init_read_user_me_function()
|
|
48
|
+
|
|
49
|
+
def _init_read_user_me_function(self):
|
|
50
|
+
app_func = AppFunction('read_users_me', self, 'get', '/oauth/me')
|
|
51
|
+
app_func.params['token'] = self.param_token
|
|
52
|
+
app_func.content = 'return OAuth2.get_token_user(token)\n'
|
|
53
|
+
self.function_blocks[app_func.name] = app_func
|
|
54
|
+
|
|
55
|
+
def _init_refresh_token_function(self):
|
|
56
|
+
app_func = AppFunction('refresh_token', self, 'post', '/oauth/refresh_token', reponse_model='Token')
|
|
57
|
+
app_func.params['token'] = self.param_token
|
|
58
|
+
app_func.content = 'return OAuth2.refresh_token(token)\n'
|
|
59
|
+
self.function_blocks[app_func.name] = app_func
|
|
60
|
+
|
|
61
|
+
def _init_remove_token_function(self):
|
|
62
|
+
app_func = AppFunction('remove_token', self, 'post', '/oauth/logout')
|
|
63
|
+
app_func.params['token'] = self.param_token
|
|
64
|
+
app_func.content = 'OAuth2.remove_token(token)\n'
|
|
65
|
+
app_func.content += 'return {}\n'
|
|
66
|
+
self.function_blocks[app_func.name] = app_func
|
|
67
|
+
|
|
68
|
+
def _init_login_function(self):
|
|
69
|
+
app_func = AppFunction('login_for_access_token', self, 'post', '/oauth/token', reponse_model='Token')
|
|
70
|
+
app_func.params['form_data'] = Param('form_data', parent=self,
|
|
71
|
+
type='Annotated[OAuth2PasswordRequestForm, Depends()]', nullable=False)
|
|
72
|
+
app_func.params['session'] = self.param_session
|
|
73
|
+
app_func.content = 'username = form_data.username\n'
|
|
74
|
+
app_func.content += 'password = form_data.password\n'
|
|
75
|
+
if ctx_instance.tenant.enabled:
|
|
76
|
+
app_func.content += "if username.find('@') == -1:\n"
|
|
77
|
+
app_func.content += ' raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username. Must contain \'@\'")\n'
|
|
78
|
+
app_func.content += 'domain = username.split(\'@\')[1]\n'
|
|
79
|
+
app_func.content += 'username = username.split(\'@\')[0]\n'
|
|
80
|
+
app_func.content += (f'user = session.query({self.user_model.class_name})'
|
|
81
|
+
f'.join({self.tenant_model.class_name}, {self.user_model.class_name}.{ctx_instance.tenant.tenant_column}=={self.tenant_model.class_name}.id)'
|
|
82
|
+
f'.filter({self.user_model.class_name}.{ctx_instance.oauth2.user_name_field}==username)'
|
|
83
|
+
f'.filter({self.user_model.class_name}.{ctx_instance.oauth2.user_password_field}==password)'
|
|
84
|
+
f'.filter({self.tenant_model.class_name}.domain==domain)'
|
|
85
|
+
f'.first()\n')
|
|
86
|
+
else:
|
|
87
|
+
app_func.content += (f'user = session.query({self.user_model.class_name})'
|
|
88
|
+
f'.filter({self.user_model.class_name}.{ctx_instance.oauth2.user_name_field}==username)'
|
|
89
|
+
f'.filter({self.user_model.class_name}.{ctx_instance.oauth2.user_password_field}==password)'
|
|
90
|
+
f'.first()\n')
|
|
91
|
+
app_func.content += 'if user:\n'
|
|
92
|
+
token_content = ', '.join([f'"{k}": user.{k}' for k in self.user_model.table.get_primary_keys()])
|
|
93
|
+
token_content += f', "{ctx_instance.oauth2.user_name_field}": username'
|
|
94
|
+
if ctx_instance.tenant.enabled:
|
|
95
|
+
token_content += f', "{ctx_instance.tenant.tenant_column}": user.{ctx_instance.tenant.tenant_column}'
|
|
96
|
+
token_content = '{' + token_content + '}'
|
|
97
|
+
app_func.content += f' return OAuth2.create_access_token({token_content})\n'
|
|
98
|
+
app_func.content += 'raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username or password")\n'
|
|
99
|
+
self.function_blocks[app_func.name] = app_func
|
|
100
|
+
|
|
101
|
+
def _init_variables(self):
|
|
102
|
+
self.variables['app'] = Variable('app', self, default="FastAPI()")
|
|
103
|
+
self.variables['oauth2_scheme '] = Variable('oauth2_scheme ', self,
|
|
104
|
+
default="OAuth2PasswordBearer(tokenUrl='/oauth/token')")
|
|
105
|
+
|
|
106
|
+
def _init_import_stmt(self):
|
|
107
|
+
self.import_stmt.add_import('typing', 'Annotated')
|
|
108
|
+
self.import_stmt.add_import('fastoauth', 'OAuth2')
|
|
109
|
+
self.import_stmt.add_import('fastoauth', 'Token')
|
|
110
|
+
self.import_stmt.add_import('fastapi', 'Depends')
|
|
111
|
+
self.import_stmt.add_import('fastapi', 'FastAPI')
|
|
112
|
+
self.import_stmt.add_import('fastapi', 'HTTPException')
|
|
113
|
+
self.import_stmt.add_import('fastapi', 'status')
|
|
114
|
+
self.import_stmt.add_import('fastapi.security', 'OAuth2PasswordBearer')
|
|
115
|
+
self.import_stmt.add_import('fastapi.security', 'OAuth2PasswordRequestForm')
|
|
116
|
+
self.import_stmt.add_import(f'{ctx_instance.project_package}.db', 'Session')
|
|
117
|
+
self.import_stmt.add_import(f'{ctx_instance.project_package}.db', 'get_session')
|
|
118
|
+
self.import_stmt.add_import(self.user_model.package, self.user_model.class_name)
|
|
119
|
+
if self.tenant_model:
|
|
120
|
+
self.import_stmt.add_import(self.tenant_model.package, self.tenant_model.class_name)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from fastcodedog.api.api_package import ApiPackage
|
|
5
|
+
from fastcodedog.context.context_instance import ctx_instance
|
|
6
|
+
from fastcodedog.crud.crud_package import CrudPackage
|
|
7
|
+
from fastcodedog.diagram.diagram import Diagram
|
|
8
|
+
from fastcodedog.model.model_package import ModelPackage
|
|
9
|
+
from fastcodedog.schema.schema_additional_package import SchemaAdditionalPackage
|
|
10
|
+
from fastcodedog.schema.schema_package import SchemaPackage
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def main():
|
|
14
|
+
if len(sys.argv) == 1:
|
|
15
|
+
raise ValueError('缺少参数,请传入json5配置文件或者pdm文件')
|
|
16
|
+
ctx_instance.load_config(*(sys.argv[1:]))
|
|
17
|
+
ctx_instance.diagram = Diagram()
|
|
18
|
+
ctx_instance.diagram.load()
|
|
19
|
+
ctx_instance.model_package = ModelPackage()
|
|
20
|
+
ctx_instance.model_package.save()
|
|
21
|
+
ctx_instance.schema_package = SchemaPackage()
|
|
22
|
+
ctx_instance.schema_package.save()
|
|
23
|
+
ctx_instance.schema_additional_package = SchemaAdditionalPackage()
|
|
24
|
+
ctx_instance.schema_additional_package.save()
|
|
25
|
+
ctx_instance.crud_package = CrudPackage()
|
|
26
|
+
ctx_instance.crud_package.save()
|
|
27
|
+
ctx_instance.api_package = ApiPackage()
|
|
28
|
+
ctx_instance.api_package.save()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if __name__ == '__main__':
|
|
32
|
+
"""
|
|
33
|
+
$env:PYTHONPATH = "."
|
|
34
|
+
python fastcodedog/cli.py fastcodegen/test/fastframe.diagram.json5 fastcodegen/test/fastframe.model.json5
|
|
35
|
+
"""
|
|
36
|
+
main()
|
|
37
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from .base import Base
|
|
3
|
+
from .contextbase import ContextBase
|
|
4
|
+
from .modules import Modules
|
|
5
|
+
from .oauth2 import OAuth2
|
|
6
|
+
from .schema import Schema
|
|
7
|
+
from .tenant import Tenant
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Context(ContextBase):
|
|
11
|
+
def __init__(self):
|
|
12
|
+
super().__init__()
|
|
13
|
+
self.pdm_files = []
|
|
14
|
+
self.project_name = None
|
|
15
|
+
self.author = None
|
|
16
|
+
self.project_package = None
|
|
17
|
+
self.project_dir = None
|
|
18
|
+
# diagram的配置,这些配置也会在后续的生成代码中使用
|
|
19
|
+
self.modules = Modules()
|
|
20
|
+
self.tenant = Tenant()
|
|
21
|
+
# model的配置
|
|
22
|
+
self.base = Base()
|
|
23
|
+
# schema的配置
|
|
24
|
+
self.schema = Schema()
|
|
25
|
+
self.response_schemas = {}
|
|
26
|
+
self.create_schemas = {}
|
|
27
|
+
self.update_schemas = {}
|
|
28
|
+
# crud的配置
|
|
29
|
+
self.queries = {}
|
|
30
|
+
# api的配置
|
|
31
|
+
self.extended_apps = {}
|
|
32
|
+
self.oauth2 = OAuth2()
|