valar 1.3.17__tar.gz → 1.3.24__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.
- {valar-1.3.17/src/valar.egg-info → valar-1.3.24}/PKG-INFO +41 -18
- {valar-1.3.17 → valar-1.3.24}/README.md +39 -17
- {valar-1.3.17 → valar-1.3.24}/setup.py +19 -5
- {valar-1.3.17 → valar-1.3.24}/src/valar/auth/Authentication.py +2 -1
- {valar-1.3.17 → valar-1.3.24}/src/valar/channels/consumer.py +11 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/channels/executer.py +8 -2
- {valar-1.3.17 → valar-1.3.24}/src/valar/channels/sender.py +14 -8
- {valar-1.3.17 → valar-1.3.24}/src/valar/dao/defaults/field_keys_default.py +1 -1
- {valar-1.3.17 → valar-1.3.24}/src/valar/dao/defaults/field_values_default.py +5 -7
- {valar-1.3.17 → valar-1.3.24}/src/valar/dao/meta.py +1 -17
- {valar-1.3.17 → valar-1.3.24}/src/valar/dao/orm_dao.py +6 -4
- {valar-1.3.17 → valar-1.3.24}/src/valar/migrations/0001_initial.py +20 -2
- {valar-1.3.17 → valar-1.3.24}/src/valar/models/core.py +2 -3
- {valar-1.3.17 → valar-1.3.24}/src/valar/models/meta.py +0 -1
- {valar-1.3.17 → valar-1.3.24}/src/valar/urls.py +4 -1
- {valar-1.3.17 → valar-1.3.24}/src/valar/views/auth.py +7 -8
- valar-1.3.24/src/valar/views/handler.py +48 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/views/meta.py +24 -12
- {valar-1.3.17 → valar-1.3.24}/src/valar/views/password.py +1 -1
- {valar-1.3.17 → valar-1.3.24}/src/valar/views/rest.py +22 -2
- {valar-1.3.17 → valar-1.3.24/src/valar.egg-info}/PKG-INFO +41 -18
- {valar-1.3.17 → valar-1.3.24}/src/valar.egg-info/SOURCES.txt +0 -3
- {valar-1.3.17 → valar-1.3.24}/src/valar.egg-info/requires.txt +1 -0
- valar-1.3.17/src/valar/migrations/0002_location.py +0 -32
- valar-1.3.17/src/valar/migrations/0003_location_code_location_name_cn_location_name_en.py +0 -28
- valar-1.3.17/src/valar/migrations/0004_remove_location_icon_remove_location_isleaf_and_more.py +0 -25
- valar-1.3.17/src/valar/views/handler.py +0 -53
- {valar-1.3.17 → valar-1.3.24}/LICENSE +0 -0
- {valar-1.3.17 → valar-1.3.24}/MANIFEST.in +0 -0
- {valar-1.3.17 → valar-1.3.24}/setup.cfg +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/__init__.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/apps.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/auth/Middleware.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/auth/__init__.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/channels/__init__.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/channels/counter.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/channels/mapping.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/channels/views.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/classes/__init__.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/classes/app_mixins/__init__.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/classes/app_mixins/auto_migration_mixin.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/classes/app_mixins/auto_urlpatterns_mixin.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/classes/singleton_meta.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/classes/valar_minio.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/classes/valar_response.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/dao/__init__.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/dao/abstract.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/dao/defaults/__init__.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/dao/defaults/view_defaults.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/dao/engine.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/dao/frame.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/dao/mon_dao.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/dao/mon_field.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/dao/orm_field.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/dao/query.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/migrations/__init__.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/models/__init__.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/models/auth.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/models/frame.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/models/indicator.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/models/test.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/views/__init__.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar/views/file.py +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar.egg-info/dependency_links.txt +0 -0
- {valar-1.3.17 → valar-1.3.24}/src/valar.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: valar
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.24
|
|
4
4
|
Summary: valar for morghulis
|
|
5
5
|
Home-page: https://gitee.com/GRIFFIN120/valar_dev
|
|
6
6
|
Author: LYP
|
|
@@ -8,6 +8,7 @@ Author-email: liuyinpeng@buaa.edu.cn
|
|
|
8
8
|
Requires-Python: >=3.9
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE
|
|
11
|
+
Requires-Dist: autobahn==24.4.2
|
|
11
12
|
Requires-Dist: channels==3.0.3
|
|
12
13
|
Requires-Dist: pymongo~=4.11.2
|
|
13
14
|
Requires-Dist: asgiref~=3.8.1
|
|
@@ -45,7 +46,7 @@ pip install valar
|
|
|
45
46
|
- asgi.py
|
|
46
47
|
- urls.py
|
|
47
48
|
|
|
48
|
-
## 2.1 settings.py
|
|
49
|
+
## 2.1 settings.py and ___init__.py
|
|
49
50
|
|
|
50
51
|
```python
|
|
51
52
|
from pathlib import Path
|
|
@@ -61,8 +62,16 @@ SECRET_KEY = 'django-insecure-of@tfouoq^_f$l!yki#m=6j7)@&kjri$1_$!mca-=%7=+@f@5^
|
|
|
61
62
|
|
|
62
63
|
DATABASES = {
|
|
63
64
|
'default': {
|
|
64
|
-
'ENGINE': 'django.db.backends.
|
|
65
|
-
'NAME':
|
|
65
|
+
'ENGINE': 'django.db.backends.mysql', # 使用 MySQL
|
|
66
|
+
'NAME': 'vm_ets', # 数据库名
|
|
67
|
+
'USER': 'root', # 用户名
|
|
68
|
+
'PASSWORD': password, # 密码
|
|
69
|
+
'HOST': 'localhost', # 数据库地址,本机用127.0.0.1
|
|
70
|
+
'PORT': '3306', # MySQL端口,默认3306
|
|
71
|
+
'OPTIONS': {
|
|
72
|
+
'connect_timeout': 5, # 默认10秒,可以缩短
|
|
73
|
+
'charset': 'utf8mb4',
|
|
74
|
+
}
|
|
66
75
|
}
|
|
67
76
|
}
|
|
68
77
|
|
|
@@ -105,44 +114,58 @@ DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 * 100
|
|
|
105
114
|
""" Valar Options """
|
|
106
115
|
|
|
107
116
|
HANDLER_MAPPING = "%s.urls.channel_mapping" % BASE_APP
|
|
108
|
-
MONGO_URI = 'mongodb://
|
|
109
|
-
MINIO_URL = "s3://
|
|
110
|
-
MINIO_ROOT = "
|
|
117
|
+
MONGO_URI = f'mongodb://root:{password}@{host}:27017/'
|
|
118
|
+
MINIO_URL = f"s3://admin:{password}@{host}:9001"
|
|
119
|
+
MINIO_ROOT = f"http://{host}:9001"
|
|
111
120
|
|
|
112
121
|
""" Email Options """
|
|
122
|
+
|
|
113
123
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
|
114
|
-
EMAIL_HOST = '
|
|
115
|
-
EMAIL_PORT =
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
124
|
+
EMAIL_HOST = 'smtp.126.com'
|
|
125
|
+
EMAIL_PORT = 25
|
|
126
|
+
EMAIL_HOST_USER = "xxxx@126.com"
|
|
127
|
+
EMAIL_HOST_PASSWORD = 'CGiKQh5FyQyupQYA'
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
import pymysql
|
|
132
|
+
|
|
133
|
+
pymysql.install_as_MySQLdb()
|
|
134
|
+
|
|
121
135
|
```
|
|
122
136
|
|
|
123
137
|
## 2.2 asgi.py
|
|
124
138
|
|
|
125
139
|
```python
|
|
140
|
+
import os
|
|
141
|
+
from pathlib import Path
|
|
142
|
+
|
|
126
143
|
from django.core.asgi import get_asgi_application
|
|
127
144
|
from channels.routing import ProtocolTypeRouter, URLRouter
|
|
128
145
|
from django.urls import re_path
|
|
129
146
|
|
|
130
147
|
from valar.channels.consumer import ValarConsumer
|
|
131
148
|
|
|
149
|
+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', '%s.settings' % Path(__file__).resolve().parent.parent.name)
|
|
132
150
|
application = ProtocolTypeRouter({
|
|
133
151
|
'http': get_asgi_application(),
|
|
134
152
|
'websocket': URLRouter([
|
|
135
153
|
re_path(r'(?P<client>\w+)/$', ValarConsumer.as_asgi()),
|
|
136
154
|
])
|
|
137
155
|
})
|
|
138
|
-
|
|
139
|
-
|
|
140
156
|
```
|
|
141
157
|
|
|
142
158
|
## 2.3 urls.py
|
|
143
159
|
|
|
144
|
-
|
|
145
|
-
|
|
160
|
+
```python
|
|
161
|
+
from django.urls import path, include
|
|
162
|
+
|
|
163
|
+
urlpatterns = [
|
|
164
|
+
path('valar/', include('valar.urls')),
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
|
|
146
169
|
- go to section 4 to see how to register channel handlers (a Vue - Django async communication tool) in urls.
|
|
147
170
|
|
|
148
171
|
# 3. migrate
|
|
@@ -15,7 +15,7 @@ pip install valar
|
|
|
15
15
|
- asgi.py
|
|
16
16
|
- urls.py
|
|
17
17
|
|
|
18
|
-
## 2.1 settings.py
|
|
18
|
+
## 2.1 settings.py and ___init__.py
|
|
19
19
|
|
|
20
20
|
```python
|
|
21
21
|
from pathlib import Path
|
|
@@ -31,8 +31,16 @@ SECRET_KEY = 'django-insecure-of@tfouoq^_f$l!yki#m=6j7)@&kjri$1_$!mca-=%7=+@f@5^
|
|
|
31
31
|
|
|
32
32
|
DATABASES = {
|
|
33
33
|
'default': {
|
|
34
|
-
'ENGINE': 'django.db.backends.
|
|
35
|
-
'NAME':
|
|
34
|
+
'ENGINE': 'django.db.backends.mysql', # 使用 MySQL
|
|
35
|
+
'NAME': 'vm_ets', # 数据库名
|
|
36
|
+
'USER': 'root', # 用户名
|
|
37
|
+
'PASSWORD': password, # 密码
|
|
38
|
+
'HOST': 'localhost', # 数据库地址,本机用127.0.0.1
|
|
39
|
+
'PORT': '3306', # MySQL端口,默认3306
|
|
40
|
+
'OPTIONS': {
|
|
41
|
+
'connect_timeout': 5, # 默认10秒,可以缩短
|
|
42
|
+
'charset': 'utf8mb4',
|
|
43
|
+
}
|
|
36
44
|
}
|
|
37
45
|
}
|
|
38
46
|
|
|
@@ -75,44 +83,58 @@ DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 * 100
|
|
|
75
83
|
""" Valar Options """
|
|
76
84
|
|
|
77
85
|
HANDLER_MAPPING = "%s.urls.channel_mapping" % BASE_APP
|
|
78
|
-
MONGO_URI = 'mongodb://
|
|
79
|
-
MINIO_URL = "s3://
|
|
80
|
-
MINIO_ROOT = "
|
|
86
|
+
MONGO_URI = f'mongodb://root:{password}@{host}:27017/'
|
|
87
|
+
MINIO_URL = f"s3://admin:{password}@{host}:9001"
|
|
88
|
+
MINIO_ROOT = f"http://{host}:9001"
|
|
81
89
|
|
|
82
90
|
""" Email Options """
|
|
91
|
+
|
|
83
92
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
|
84
|
-
EMAIL_HOST = '
|
|
85
|
-
EMAIL_PORT =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
93
|
+
EMAIL_HOST = 'smtp.126.com'
|
|
94
|
+
EMAIL_PORT = 25
|
|
95
|
+
EMAIL_HOST_USER = "xxxx@126.com"
|
|
96
|
+
EMAIL_HOST_PASSWORD = 'CGiKQh5FyQyupQYA'
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
import pymysql
|
|
101
|
+
|
|
102
|
+
pymysql.install_as_MySQLdb()
|
|
103
|
+
|
|
91
104
|
```
|
|
92
105
|
|
|
93
106
|
## 2.2 asgi.py
|
|
94
107
|
|
|
95
108
|
```python
|
|
109
|
+
import os
|
|
110
|
+
from pathlib import Path
|
|
111
|
+
|
|
96
112
|
from django.core.asgi import get_asgi_application
|
|
97
113
|
from channels.routing import ProtocolTypeRouter, URLRouter
|
|
98
114
|
from django.urls import re_path
|
|
99
115
|
|
|
100
116
|
from valar.channels.consumer import ValarConsumer
|
|
101
117
|
|
|
118
|
+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', '%s.settings' % Path(__file__).resolve().parent.parent.name)
|
|
102
119
|
application = ProtocolTypeRouter({
|
|
103
120
|
'http': get_asgi_application(),
|
|
104
121
|
'websocket': URLRouter([
|
|
105
122
|
re_path(r'(?P<client>\w+)/$', ValarConsumer.as_asgi()),
|
|
106
123
|
])
|
|
107
124
|
})
|
|
108
|
-
|
|
109
|
-
|
|
110
125
|
```
|
|
111
126
|
|
|
112
127
|
## 2.3 urls.py
|
|
113
128
|
|
|
114
|
-
|
|
115
|
-
|
|
129
|
+
```python
|
|
130
|
+
from django.urls import path, include
|
|
131
|
+
|
|
132
|
+
urlpatterns = [
|
|
133
|
+
path('valar/', include('valar.urls')),
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
|
|
116
138
|
- go to section 4 to see how to register channel handlers (a Vue - Django async communication tool) in urls.
|
|
117
139
|
|
|
118
140
|
# 3. migrate
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
from setuptools import setup, find_packages
|
|
2
|
+
from setuptools.command.build_py import build_py as _build_py
|
|
3
|
+
import pathlib, os
|
|
4
|
+
from setuptools import Command
|
|
5
|
+
from typing import Dict, Type
|
|
2
6
|
|
|
3
7
|
with open("README.md", "r", encoding="utf-8") as f:
|
|
4
8
|
long_description = f.read()
|
|
5
9
|
|
|
6
|
-
version = "1.3.
|
|
10
|
+
version = "1.3.24"
|
|
7
11
|
|
|
8
12
|
requires = [
|
|
13
|
+
'autobahn==24.4.2',
|
|
9
14
|
'channels==3.0.3',
|
|
10
15
|
'pymongo~=4.11.2',
|
|
11
16
|
'asgiref~=3.8.1',
|
|
@@ -18,6 +23,17 @@ requires = [
|
|
|
18
23
|
'PyMySQL~=1.1.2'
|
|
19
24
|
]
|
|
20
25
|
|
|
26
|
+
|
|
27
|
+
class BuildBy(_build_py, Command):
|
|
28
|
+
def run(self):
|
|
29
|
+
base = pathlib.Path("src")
|
|
30
|
+
for path in base.rglob("migrations/*.py"):
|
|
31
|
+
if path.name != "__init__.py":
|
|
32
|
+
print(f"🧹 Removing migration file: {path}")
|
|
33
|
+
os.remove(path)
|
|
34
|
+
super().run()
|
|
35
|
+
|
|
36
|
+
|
|
21
37
|
setup(
|
|
22
38
|
name="valar", # 包名
|
|
23
39
|
version=version, # 版本号
|
|
@@ -31,9 +47,7 @@ setup(
|
|
|
31
47
|
package_dir={"": "src"}, # 设置src目录为根目录
|
|
32
48
|
python_requires=">=3.9", # 项目支持的Python版本
|
|
33
49
|
install_requires=requires, # 项目必须的依赖
|
|
34
|
-
include_package_data=
|
|
35
|
-
|
|
36
|
-
"": ["migrations/*.py", "*/migrations/*.py"], # 排除所有迁移脚本
|
|
37
|
-
},
|
|
50
|
+
include_package_data=False,
|
|
51
|
+
cmdclass={"build_py": BuildBy},
|
|
38
52
|
|
|
39
53
|
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import jwt
|
|
2
2
|
from django.conf import settings
|
|
3
|
+
from django.http import HttpRequest
|
|
3
4
|
|
|
4
5
|
from ..classes.valar_response import ValarResponse
|
|
5
6
|
|
|
@@ -11,7 +12,7 @@ class ValaAuthError(Exception):
|
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
def auth_required(view_func):
|
|
14
|
-
def wrapper(request, *args, **kwargs):
|
|
15
|
+
def wrapper(request: HttpRequest, *args, **kwargs):
|
|
15
16
|
try:
|
|
16
17
|
payload = valid_request_token(request)
|
|
17
18
|
request.user_id = payload["user_id"]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from channels.generic.websocket import AsyncJsonWebsocketConsumer
|
|
2
|
+
from django.conf import settings
|
|
2
3
|
|
|
3
4
|
VALAR_CHANNEL_GROUP = 'VALAR'
|
|
4
5
|
|
|
@@ -15,6 +16,10 @@ class ValarConsumer(AsyncJsonWebsocketConsumer):
|
|
|
15
16
|
self.client = params.get('client')
|
|
16
17
|
await self.channel_layer.group_add(VALAR_CHANNEL_GROUP, self.channel_name)
|
|
17
18
|
await self.accept()
|
|
19
|
+
await self.send_json({
|
|
20
|
+
"tag": 'system',
|
|
21
|
+
"minio": getattr(settings, 'MINIO_ROOT') if hasattr(settings, 'MINIO_ROOT') else '/minio'
|
|
22
|
+
})
|
|
18
23
|
|
|
19
24
|
async def disconnect(self, code):
|
|
20
25
|
await self.channel_layer.group_discard(VALAR_CHANNEL_GROUP, self.channel_name)
|
|
@@ -30,17 +35,23 @@ class ValarConsumer(AsyncJsonWebsocketConsumer):
|
|
|
30
35
|
async def user_emit(self, event):
|
|
31
36
|
users: list = event.get('users', [])
|
|
32
37
|
data = event.get('data', {})
|
|
38
|
+
tag = event.get('tag')
|
|
39
|
+
data.update({'tag': tag})
|
|
33
40
|
if self.uid in users:
|
|
34
41
|
await self.send_json(data)
|
|
35
42
|
|
|
36
43
|
async def client_emit(self, event):
|
|
37
44
|
clients: list = event.get('clients', [])
|
|
38
45
|
data = event.get('data', {})
|
|
46
|
+
tag = event.get('tag')
|
|
47
|
+
data.update({'tag': tag})
|
|
39
48
|
if self.client in clients:
|
|
40
49
|
await self.send_json(data)
|
|
41
50
|
|
|
42
51
|
async def broadcast_emit(self, event):
|
|
43
52
|
data = event.get('data', {})
|
|
53
|
+
tag = event.get('tag')
|
|
54
|
+
data.update({'tag': tag})
|
|
44
55
|
await self.send_json(data)
|
|
45
56
|
|
|
46
57
|
async def register_emit(self, event):
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
|
|
3
3
|
from ..channels.sender import ValarChannelSender
|
|
4
|
+
import traceback
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
async def execute_channel(method, sender: ValarChannelSender):
|
|
@@ -10,5 +11,10 @@ async def execute_channel(method, sender: ValarChannelSender):
|
|
|
10
11
|
|
|
11
12
|
def __execute__(method, sender: ValarChannelSender):
|
|
12
13
|
sender.start()
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
try:
|
|
15
|
+
response = method(sender)
|
|
16
|
+
sender.done(response)
|
|
17
|
+
sender.stop()
|
|
18
|
+
except Exception as e:
|
|
19
|
+
traceback.print_exc()
|
|
20
|
+
sender.error(str(e))
|
|
@@ -18,20 +18,21 @@ class Channel:
|
|
|
18
18
|
self.url = body.get('url')
|
|
19
19
|
self.auth = body.get('auth')
|
|
20
20
|
self.broadcast = body.get('broadcast')
|
|
21
|
+
|
|
21
22
|
self.data = body.get('data')
|
|
22
|
-
self.
|
|
23
|
+
self.token = body.get('token')
|
|
23
24
|
|
|
24
|
-
def to_dict(self,
|
|
25
|
+
def to_dict(self, resolver, payload):
|
|
25
26
|
data = {
|
|
26
27
|
'handler': self.handler,
|
|
27
28
|
'url': self.url,
|
|
28
29
|
'auth': self.auth,
|
|
29
30
|
'broadcast': self.broadcast,
|
|
30
|
-
'
|
|
31
|
+
'token': self.token,
|
|
31
32
|
'timestamp': datetime.now().timestamp()
|
|
32
33
|
}
|
|
33
|
-
if
|
|
34
|
-
data.update({'
|
|
34
|
+
if resolver:
|
|
35
|
+
data.update({'resolver': resolver})
|
|
35
36
|
if payload:
|
|
36
37
|
data.update({'payload': payload})
|
|
37
38
|
return data
|
|
@@ -86,17 +87,22 @@ class ValarChannelSender(Sender):
|
|
|
86
87
|
with self.__lock__:
|
|
87
88
|
self.__payload__ = payload
|
|
88
89
|
|
|
89
|
-
def done(self,
|
|
90
|
-
self.__emit__('done',
|
|
90
|
+
def done(self, response):
|
|
91
|
+
self.__emit__('done', response)
|
|
91
92
|
|
|
92
93
|
def error(self, payload):
|
|
93
94
|
self.__emit__('error', payload)
|
|
95
|
+
if self.__thread__:
|
|
96
|
+
self.__thread__.join()
|
|
97
|
+
self.__thread__ = None
|
|
94
98
|
|
|
95
99
|
def __emit__(self, status='proceed', data=None):
|
|
96
100
|
scope = 'broadcast' if self.__channel__.broadcast else 'client'
|
|
101
|
+
pay = self.__payload__ if status == 'proceed' else data
|
|
97
102
|
body = {
|
|
98
103
|
'type': f'{scope}.emit',
|
|
99
|
-
'
|
|
104
|
+
'tag': 'batch',
|
|
105
|
+
'data': self.__channel__.to_dict(status, pay),
|
|
100
106
|
'clients': [self.client],
|
|
101
107
|
'users': []
|
|
102
108
|
}
|
|
@@ -4,7 +4,7 @@ meta_field_key_defaults = {
|
|
|
4
4
|
},
|
|
5
5
|
'valar.MetaView': {
|
|
6
6
|
'list': ('pick', ['code', 'name']),
|
|
7
|
-
'core': ('pick', ['name', 'enable', 'lock'
|
|
7
|
+
'core': ('pick', ['name', 'enable', 'lock']),
|
|
8
8
|
'style': ('pick', ['form_width', 'form_height', 'table_width', 'table_height']),
|
|
9
9
|
'rest': ('pick',
|
|
10
10
|
['allow_search', 'allow_order', 'allow_insert', 'allow_remove', 'allow_download', 'allow_upload']),
|
|
@@ -27,11 +27,8 @@ meta_field_value_defaults = {
|
|
|
27
27
|
},
|
|
28
28
|
"core": {
|
|
29
29
|
"name": {
|
|
30
|
-
'span':
|
|
30
|
+
'span': 24
|
|
31
31
|
},
|
|
32
|
-
"enable": {
|
|
33
|
-
"span": 8
|
|
34
|
-
}
|
|
35
32
|
}
|
|
36
33
|
},
|
|
37
34
|
'valar.MetaFieldDomain': {
|
|
@@ -104,7 +101,6 @@ meta_field_value_defaults = {
|
|
|
104
101
|
},
|
|
105
102
|
"tool": {
|
|
106
103
|
'column_width': 100,
|
|
107
|
-
'span': 24,
|
|
108
104
|
'tool': 'tree',
|
|
109
105
|
'refer': {
|
|
110
106
|
'entity': 'valar.MetaFieldTool',
|
|
@@ -119,11 +115,13 @@ meta_field_value_defaults = {
|
|
|
119
115
|
},
|
|
120
116
|
"refer": {
|
|
121
117
|
'allow_edit': False,
|
|
122
|
-
'column_width': 80
|
|
118
|
+
'column_width': 80,
|
|
119
|
+
"hide_on_form": True
|
|
123
120
|
},
|
|
124
121
|
"format": {
|
|
125
122
|
'allow_edit': False,
|
|
126
|
-
'column_width': 80
|
|
123
|
+
'column_width': 80,
|
|
124
|
+
"hide_on_form": True
|
|
127
125
|
},
|
|
128
126
|
'header_color': {
|
|
129
127
|
'tool': 'color',
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import copy
|
|
2
2
|
|
|
3
3
|
from deepmerge import always_merger
|
|
4
|
-
from django.conf import settings
|
|
5
4
|
|
|
6
5
|
from ..dao.defaults.field_keys_default import meta_field_key_defaults
|
|
7
6
|
from ..dao.defaults.field_values_default import meta_field_value_defaults
|
|
@@ -11,7 +10,6 @@ from ..dao.frame import meta_field_tool_mapping
|
|
|
11
10
|
from ..dao.mon_dao import MonDao
|
|
12
11
|
from ..dao.orm_dao import OrmDao
|
|
13
12
|
from ..dao.orm_field import column_width
|
|
14
|
-
from ..models.frame import MetaFieldDomain
|
|
15
13
|
from ..models.meta import Meta, MetaView
|
|
16
14
|
|
|
17
15
|
|
|
@@ -56,18 +54,15 @@ class ValarMeta:
|
|
|
56
54
|
name, entity = meta['name'], meta['entity']
|
|
57
55
|
fields = self.view.metafield_set.all().order_by('-sort')
|
|
58
56
|
_fields = {}
|
|
59
|
-
_minio = settings.MINIO_ROOT if hasattr(settings, 'MINIO_ROOT') else '/minio'
|
|
60
57
|
for field in fields:
|
|
61
|
-
_field = field.json(entity=entity, code=self.code, db='orm'
|
|
58
|
+
_field = field.json(entity=entity, code=self.code, db='orm')
|
|
62
59
|
align, tool, width, domain = _field['align'], _field['tool'], _field['column_width'], _field['domain']
|
|
63
60
|
_field['align'] = align if align else meta_field_tool_mapping.get(tool, 'left')
|
|
64
61
|
_field['column_width'] = width if width else column_width(domain, tool)
|
|
65
62
|
|
|
66
63
|
_fields[field.prop] = _field
|
|
67
64
|
|
|
68
|
-
_minio = settings.MINIO_ROOT if hasattr(settings, 'MINIO_ROOT') else '/minio'
|
|
69
65
|
_view.update({
|
|
70
|
-
'$minio': _minio,
|
|
71
66
|
'$db': 'orm',
|
|
72
67
|
'$entity': entity,
|
|
73
68
|
'$code': self.code,
|
|
@@ -87,17 +82,6 @@ class ValarMeta:
|
|
|
87
82
|
view_item.update({
|
|
88
83
|
"name": self.code.upper(),
|
|
89
84
|
"saved": True,
|
|
90
|
-
"property": {
|
|
91
|
-
"value": "id",
|
|
92
|
-
"label": "name",
|
|
93
|
-
"display": "id",
|
|
94
|
-
"sort": "sort",
|
|
95
|
-
"disabled": "disabled",
|
|
96
|
-
"isLeaf": "isLeaf",
|
|
97
|
-
"icon": "icon",
|
|
98
|
-
"children": "children",
|
|
99
|
-
"pid": "pid",
|
|
100
|
-
}
|
|
101
85
|
})
|
|
102
86
|
values = always_merger.merge(default_values, code_values)
|
|
103
87
|
view_item.update(values)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import datetime
|
|
2
2
|
import json
|
|
3
|
+
from urllib.parse import quote
|
|
3
4
|
|
|
4
|
-
from django.conf import settings
|
|
5
5
|
from django.core.paginator import Paginator
|
|
6
6
|
from django.db.models.options import Options
|
|
7
7
|
|
|
@@ -15,7 +15,6 @@ from django.db.models.fields.files import FieldFile
|
|
|
15
15
|
from django.forms import FileField
|
|
16
16
|
|
|
17
17
|
from ..dao.orm_field import OrmField
|
|
18
|
-
from ..models.auth import Account
|
|
19
18
|
from ..models.core import VTree, VModel
|
|
20
19
|
from ..models.meta import MetaField
|
|
21
20
|
|
|
@@ -52,7 +51,6 @@ class OrmDao(AbstractDao):
|
|
|
52
51
|
return list(query_set.values(*props))
|
|
53
52
|
|
|
54
53
|
def insert_one(self, item):
|
|
55
|
-
print(item)
|
|
56
54
|
return self.__save__(item)
|
|
57
55
|
|
|
58
56
|
def update_one(self, item):
|
|
@@ -320,6 +318,7 @@ def __get_custom_props__(entity, code='default'):
|
|
|
320
318
|
def __set_simple_values__(fields, values):
|
|
321
319
|
date_props_mapping = {}
|
|
322
320
|
json_props = []
|
|
321
|
+
file_props = []
|
|
323
322
|
for field in fields:
|
|
324
323
|
if isinstance(field, OrmField):
|
|
325
324
|
prop = field.prop
|
|
@@ -331,13 +330,16 @@ def __set_simple_values__(fields, values):
|
|
|
331
330
|
date_props_mapping[prop] = __data_props_formatting__[domain]
|
|
332
331
|
elif domain == 'JSONField':
|
|
333
332
|
json_props.append(prop)
|
|
333
|
+
elif domain == 'FileField':
|
|
334
|
+
file_props.append(prop)
|
|
334
335
|
for row in values:
|
|
335
|
-
row['$minio'] = settings.MINIO_ROOT
|
|
336
336
|
for prop, formating in date_props_mapping.items():
|
|
337
337
|
if row.get(prop):
|
|
338
338
|
row[prop] = row[prop].strftime(formating)
|
|
339
339
|
for prop in json_props:
|
|
340
340
|
row[prop] = json.loads(row[prop]) if type(row[prop]) is str else row[prop]
|
|
341
|
+
for prop in file_props:
|
|
342
|
+
row[prop] = quote(row[prop], safe=":/")
|
|
341
343
|
|
|
342
344
|
# def fun(field): return type(field).__name__ not in __referred_domains__ and field.name not in __omit_field_props__
|
|
343
345
|
#
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Generated by Django 4.2.24 on 2025-
|
|
1
|
+
# Generated by Django 4.2.24 on 2025-10-19 15:26
|
|
2
2
|
|
|
3
3
|
from django.db import migrations, models
|
|
4
4
|
import django.db.models.deletion
|
|
@@ -30,6 +30,25 @@ class Migration(migrations.Migration):
|
|
|
30
30
|
'verbose_name': '指标集',
|
|
31
31
|
},
|
|
32
32
|
),
|
|
33
|
+
migrations.CreateModel(
|
|
34
|
+
name='Location',
|
|
35
|
+
fields=[
|
|
36
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
37
|
+
('sort', models.BigIntegerField(null=True, verbose_name='序号')),
|
|
38
|
+
('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
|
|
39
|
+
('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
|
|
40
|
+
('disabled', models.BooleanField(default=False, verbose_name='禁用')),
|
|
41
|
+
('saved', models.BooleanField(default=False, verbose_name='已保存')),
|
|
42
|
+
('scope', models.CharField(max_length=100, null=True)),
|
|
43
|
+
('code', models.CharField(max_length=100, null=True)),
|
|
44
|
+
('name', models.CharField(max_length=100, null=True)),
|
|
45
|
+
('name_cn', models.CharField(max_length=100, null=True)),
|
|
46
|
+
('name_en', models.CharField(max_length=100, null=True)),
|
|
47
|
+
],
|
|
48
|
+
options={
|
|
49
|
+
'verbose_name': '指标集',
|
|
50
|
+
},
|
|
51
|
+
),
|
|
33
52
|
migrations.CreateModel(
|
|
34
53
|
name='Meta',
|
|
35
54
|
fields=[
|
|
@@ -184,7 +203,6 @@ class Migration(migrations.Migration):
|
|
|
184
203
|
('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
|
|
185
204
|
('disabled', models.BooleanField(default=False, verbose_name='禁用')),
|
|
186
205
|
('saved', models.BooleanField(default=False, verbose_name='已保存')),
|
|
187
|
-
('property', models.JSONField(default=dict, verbose_name='属性')),
|
|
188
206
|
('code', models.CharField(default='default ', max_length=50, verbose_name='类视图')),
|
|
189
207
|
('name', models.CharField(max_length=50, null=True, verbose_name='视图名称')),
|
|
190
208
|
('lock', models.BooleanField(default=False, verbose_name='锁定元数据')),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
|
+
from urllib.parse import quote
|
|
2
3
|
|
|
3
4
|
from django.apps import AppConfig
|
|
4
|
-
from django.conf import settings
|
|
5
5
|
from django.db import models
|
|
6
6
|
from django.db.models import ManyToOneRel, OneToOneRel, ManyToManyRel, ManyToManyField, UUIDField, FileField, \
|
|
7
7
|
ForeignKey, OneToOneField, DateField, TimeField, DateTimeField, BigAutoField, JSONField
|
|
@@ -49,7 +49,7 @@ class VModel(models.Model):
|
|
|
49
49
|
elif domain in [TimeField]:
|
|
50
50
|
value = value.strftime('%H:%M:%S')
|
|
51
51
|
elif domain in [FileField]:
|
|
52
|
-
value = value.name
|
|
52
|
+
value = quote(value.name, safe=":/")
|
|
53
53
|
elif domain in [BigAutoField]:
|
|
54
54
|
value = value
|
|
55
55
|
data[prop] = value
|
|
@@ -76,7 +76,6 @@ class VModel(models.Model):
|
|
|
76
76
|
_set = getattr(self, accessor).all().order_by('-sort')
|
|
77
77
|
data[prop] = [item.id for item in _set]
|
|
78
78
|
data[f'{prop}_set'] = [item.json() for item in _set]
|
|
79
|
-
data['$minio'] = settings.MINIO_ROOT
|
|
80
79
|
return data
|
|
81
80
|
|
|
82
81
|
|
|
@@ -15,7 +15,6 @@ class Meta(VModel):
|
|
|
15
15
|
|
|
16
16
|
class MetaView(VModel):
|
|
17
17
|
meta = models.ForeignKey('Meta', on_delete=models.CASCADE, verbose_name='元数据')
|
|
18
|
-
property = models.JSONField(default=dict, verbose_name='属性')
|
|
19
18
|
|
|
20
19
|
code = models.CharField(max_length=50, verbose_name='类视图', default='default ')
|
|
21
20
|
name = models.CharField(max_length=50, verbose_name='视图名称', null=True)
|
|
@@ -5,6 +5,9 @@ from django.urls import path, re_path
|
|
|
5
5
|
urlpatterns = [
|
|
6
6
|
path('socket/<str:handler>', handel_channel),
|
|
7
7
|
path('batch', rest.batch),
|
|
8
|
+
|
|
9
|
+
path('<str:db>/<str:entity>/save_many', rest.save_many),
|
|
10
|
+
path('<str:db>/<str:entity>/delete_many', rest.delete_many),
|
|
8
11
|
path('<str:db>/<str:entity>/save_one', rest.save_one),
|
|
9
12
|
path('<str:db>/<str:entity>/insert_one', rest.insert_one),
|
|
10
13
|
path('<str:db>/<str:entity>/delete_one', rest.delete_one),
|
|
@@ -20,7 +23,7 @@ urlpatterns = [
|
|
|
20
23
|
path('load_customs', meta.load_customs),
|
|
21
24
|
path('get_fields', meta.get_fields),
|
|
22
25
|
path('save_custom', meta.save_custom),
|
|
23
|
-
path('
|
|
26
|
+
path('upload_frame', meta.upload_frame),
|
|
24
27
|
|
|
25
28
|
path('<str:db>/<str:entity>/save_file', file.save_file),
|
|
26
29
|
path('<str:db>/<str:entity>/remove_file', file.remove_file),
|
|
@@ -14,24 +14,23 @@ from ..models.auth import Account, AbstractUser, Menu
|
|
|
14
14
|
|
|
15
15
|
def sign_in(request):
|
|
16
16
|
body = json.loads(request.body)
|
|
17
|
-
|
|
18
|
-
email = body.get(
|
|
19
|
-
password = body.get("password")
|
|
20
|
-
signin = body.get("signin")
|
|
17
|
+
keys = ['username', 'email', 'password', 'signin']
|
|
18
|
+
username, email, password, signin = [body.get(k) for k in keys]
|
|
21
19
|
dao = Dao('valar.Account')
|
|
22
20
|
account = dao.search({"username": username}).first()
|
|
21
|
+
|
|
23
22
|
if account is not None:
|
|
24
23
|
if signin:
|
|
25
24
|
if not account.is_auth(password):
|
|
26
|
-
return ValarResponse(False, '密码错误', 'warning'
|
|
25
|
+
return ValarResponse(False, '密码错误', 'warning')
|
|
27
26
|
else:
|
|
28
|
-
return ValarResponse(False, f"{username}已被占用", 'warning'
|
|
27
|
+
return ValarResponse(False, f"{username}已被占用", 'warning')
|
|
29
28
|
else:
|
|
30
29
|
if signin:
|
|
31
|
-
return ValarResponse(False, f"{username}不存在", 'warning'
|
|
30
|
+
return ValarResponse(False, f"{username}不存在", 'warning')
|
|
32
31
|
else:
|
|
33
32
|
if username == 'admin' and password != settings.SECRET_KEY:
|
|
34
|
-
return ValarResponse(False, "请输入正确的admin密码", 'warning'
|
|
33
|
+
return ValarResponse(False, "请输入正确的admin密码", 'warning')
|
|
35
34
|
else:
|
|
36
35
|
account = dao.save_one({
|
|
37
36
|
"username": username,
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import traceback
|
|
2
|
+
|
|
3
|
+
from ..channels.counter import Counter
|
|
4
|
+
from ..channels.sender import ValarChannelSender
|
|
5
|
+
from ..dao import Dao
|
|
6
|
+
from ..dao.engine import ValarEngine
|
|
7
|
+
|
|
8
|
+
import time
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def valar_test_handler(sender: ValarChannelSender):
|
|
12
|
+
data = sender.data
|
|
13
|
+
length = data.get('length', 100)
|
|
14
|
+
counter = Counter(length)
|
|
15
|
+
for i in range(length):
|
|
16
|
+
time.sleep(0.1)
|
|
17
|
+
tick = counter.tick()
|
|
18
|
+
tick.update({'name': 'test1'})
|
|
19
|
+
sender.load(tick)
|
|
20
|
+
return "aba"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def batch_handler(sender: ValarChannelSender):
|
|
24
|
+
data = sender.data
|
|
25
|
+
entity, db, method = data.get("entity"), data.get("db"), data.get("method")
|
|
26
|
+
print(entity, db, method)
|
|
27
|
+
dao = Dao(entity, db)
|
|
28
|
+
if method == 'save_many':
|
|
29
|
+
array = data.get("data", [])
|
|
30
|
+
counter = Counter(array)
|
|
31
|
+
keys = []
|
|
32
|
+
for item in array:
|
|
33
|
+
item.update({'saved': True})
|
|
34
|
+
bean = dao.save_one(item)
|
|
35
|
+
keys.append(bean.id)
|
|
36
|
+
payload = counter.tick()
|
|
37
|
+
sender.load(payload)
|
|
38
|
+
return keys
|
|
39
|
+
elif method == 'delete_many':
|
|
40
|
+
conditions = data.get("data", [])
|
|
41
|
+
paths = dao.delete(conditions)
|
|
42
|
+
counter = Counter(len(paths))
|
|
43
|
+
minio = ValarEngine().get_minio_bucket(entity)
|
|
44
|
+
for path in paths:
|
|
45
|
+
minio.remove(path)
|
|
46
|
+
# payload = counter.tick()
|
|
47
|
+
# sender.load(payload)
|
|
48
|
+
return []
|
|
@@ -10,7 +10,7 @@ from ..dao.meta import ValarMeta
|
|
|
10
10
|
from ..models.meta import MetaView, Meta, MetaField
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def
|
|
13
|
+
def upload_frame(request):
|
|
14
14
|
body = json.loads(request.body)
|
|
15
15
|
db = body.get('db')
|
|
16
16
|
entity = body.get('entity')
|
|
@@ -19,9 +19,17 @@ def upload_mapping(request):
|
|
|
19
19
|
view__meta__db=db,
|
|
20
20
|
view__meta__entity=entity,
|
|
21
21
|
view__code=code,
|
|
22
|
-
domain__in=[
|
|
22
|
+
domain__in=[
|
|
23
|
+
'ManyToManyField',
|
|
24
|
+
'ManyToManyRel',
|
|
25
|
+
'ManyToOneRel',
|
|
26
|
+
'OneToOneField',
|
|
27
|
+
'OneToOneRel',
|
|
28
|
+
'ForeignKey',
|
|
29
|
+
'CharField'
|
|
30
|
+
]
|
|
23
31
|
).filter(Q(allow_upload=True) | Q(allow_update=True))
|
|
24
|
-
|
|
32
|
+
frame = {}
|
|
25
33
|
for field in fields:
|
|
26
34
|
prop = field.prop
|
|
27
35
|
refer = field.refer
|
|
@@ -29,14 +37,18 @@ def upload_mapping(request):
|
|
|
29
37
|
entity = refer['entity']
|
|
30
38
|
value = refer['value']
|
|
31
39
|
label = refer['label']
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
try:
|
|
41
|
+
includes = {prop: refer['includes'][prop] for prop in refer['includes'] if not prop.startswith('$')}
|
|
42
|
+
excludes = {prop: refer['excludes'][prop] for prop in refer['excludes'] if not prop.startswith('$')}
|
|
43
|
+
values = Dao(entity, db).manager.filter(**includes).exclude(**excludes).values(*[value, label])
|
|
44
|
+
frame[prop] = [
|
|
45
|
+
{"value": row[value], "label": row[label]}
|
|
46
|
+
for row in values if row[value]
|
|
47
|
+
]
|
|
48
|
+
except Exception:
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
return ValarResponse(frame)
|
|
40
52
|
|
|
41
53
|
|
|
42
54
|
def meta_view(request, db, entity):
|
|
@@ -121,7 +133,7 @@ def add_fields(request):
|
|
|
121
133
|
|
|
122
134
|
|
|
123
135
|
def metas(request):
|
|
124
|
-
values = Meta.objects.all().values('db', 'entity', 'name', 'tree'
|
|
136
|
+
values = Meta.objects.all().values('db', 'entity', 'name', 'tree')
|
|
125
137
|
mapping = {'orm': {'valar': []}, 'mon': []}
|
|
126
138
|
for row in values:
|
|
127
139
|
db = row['db']
|
|
@@ -57,4 +57,4 @@ def __send__(account):
|
|
|
57
57
|
return ValarResponse(False, '该账户未登记邮箱信息', code='error')
|
|
58
58
|
content = f'Your temporary password is {token}, please change it as soon as possible.'
|
|
59
59
|
ValarEngine().send_email('Retrieve Password', content, email)
|
|
60
|
-
return ValarResponse(
|
|
60
|
+
return ValarResponse(f'临时密码已发送至{email}')
|
|
@@ -8,6 +8,7 @@ from ..channels.executer import execute_channel
|
|
|
8
8
|
from ..channels.sender import ValarChannelSender
|
|
9
9
|
from ..classes.valar_response import ValarResponse
|
|
10
10
|
from ..dao import Dao
|
|
11
|
+
from ..dao.engine import ValarEngine
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
async def batch(request):
|
|
@@ -16,10 +17,30 @@ async def batch(request):
|
|
|
16
17
|
return ValarResponse(True)
|
|
17
18
|
|
|
18
19
|
|
|
20
|
+
def save_many(request, db, entity):
|
|
21
|
+
array = json.loads(request.body)
|
|
22
|
+
dao = Dao(entity, db)
|
|
23
|
+
keys = []
|
|
24
|
+
for item in array:
|
|
25
|
+
item.update({'saved': True})
|
|
26
|
+
bean = dao.save_one(item)
|
|
27
|
+
keys.append(bean.id)
|
|
28
|
+
return ValarResponse(keys)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def delete_many(request, db, entity):
|
|
32
|
+
conditions = json.loads(request.body)
|
|
33
|
+
dao = Dao(entity, db)
|
|
34
|
+
paths = dao.delete(conditions)
|
|
35
|
+
minio = ValarEngine().get_minio_bucket(entity)
|
|
36
|
+
for path in paths:
|
|
37
|
+
minio.remove(path)
|
|
38
|
+
return ValarResponse(True)
|
|
39
|
+
|
|
40
|
+
|
|
19
41
|
def insert_one(request, db, entity):
|
|
20
42
|
item = json.loads(request.body)
|
|
21
43
|
dao = Dao(entity, db)
|
|
22
|
-
print(item)
|
|
23
44
|
bean = dao.insert_one(item)
|
|
24
45
|
item = dao.serialize(bean)
|
|
25
46
|
return ValarResponse(item)
|
|
@@ -56,7 +77,6 @@ def find_one(request, db, entity):
|
|
|
56
77
|
dao = Dao(entity, db)
|
|
57
78
|
bean = dao.find_one(_id)
|
|
58
79
|
item = dao.serialize(bean)
|
|
59
|
-
item['$minio'] = settings.MINIO_ROOT
|
|
60
80
|
return ValarResponse(item)
|
|
61
81
|
|
|
62
82
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: valar
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.24
|
|
4
4
|
Summary: valar for morghulis
|
|
5
5
|
Home-page: https://gitee.com/GRIFFIN120/valar_dev
|
|
6
6
|
Author: LYP
|
|
@@ -8,6 +8,7 @@ Author-email: liuyinpeng@buaa.edu.cn
|
|
|
8
8
|
Requires-Python: >=3.9
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE
|
|
11
|
+
Requires-Dist: autobahn==24.4.2
|
|
11
12
|
Requires-Dist: channels==3.0.3
|
|
12
13
|
Requires-Dist: pymongo~=4.11.2
|
|
13
14
|
Requires-Dist: asgiref~=3.8.1
|
|
@@ -45,7 +46,7 @@ pip install valar
|
|
|
45
46
|
- asgi.py
|
|
46
47
|
- urls.py
|
|
47
48
|
|
|
48
|
-
## 2.1 settings.py
|
|
49
|
+
## 2.1 settings.py and ___init__.py
|
|
49
50
|
|
|
50
51
|
```python
|
|
51
52
|
from pathlib import Path
|
|
@@ -61,8 +62,16 @@ SECRET_KEY = 'django-insecure-of@tfouoq^_f$l!yki#m=6j7)@&kjri$1_$!mca-=%7=+@f@5^
|
|
|
61
62
|
|
|
62
63
|
DATABASES = {
|
|
63
64
|
'default': {
|
|
64
|
-
'ENGINE': 'django.db.backends.
|
|
65
|
-
'NAME':
|
|
65
|
+
'ENGINE': 'django.db.backends.mysql', # 使用 MySQL
|
|
66
|
+
'NAME': 'vm_ets', # 数据库名
|
|
67
|
+
'USER': 'root', # 用户名
|
|
68
|
+
'PASSWORD': password, # 密码
|
|
69
|
+
'HOST': 'localhost', # 数据库地址,本机用127.0.0.1
|
|
70
|
+
'PORT': '3306', # MySQL端口,默认3306
|
|
71
|
+
'OPTIONS': {
|
|
72
|
+
'connect_timeout': 5, # 默认10秒,可以缩短
|
|
73
|
+
'charset': 'utf8mb4',
|
|
74
|
+
}
|
|
66
75
|
}
|
|
67
76
|
}
|
|
68
77
|
|
|
@@ -105,44 +114,58 @@ DATA_UPLOAD_MAX_MEMORY_SIZE = 1024 * 1024 * 100
|
|
|
105
114
|
""" Valar Options """
|
|
106
115
|
|
|
107
116
|
HANDLER_MAPPING = "%s.urls.channel_mapping" % BASE_APP
|
|
108
|
-
MONGO_URI = 'mongodb://
|
|
109
|
-
MINIO_URL = "s3://
|
|
110
|
-
MINIO_ROOT = "
|
|
117
|
+
MONGO_URI = f'mongodb://root:{password}@{host}:27017/'
|
|
118
|
+
MINIO_URL = f"s3://admin:{password}@{host}:9001"
|
|
119
|
+
MINIO_ROOT = f"http://{host}:9001"
|
|
111
120
|
|
|
112
121
|
""" Email Options """
|
|
122
|
+
|
|
113
123
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
|
114
|
-
EMAIL_HOST = '
|
|
115
|
-
EMAIL_PORT =
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
124
|
+
EMAIL_HOST = 'smtp.126.com'
|
|
125
|
+
EMAIL_PORT = 25
|
|
126
|
+
EMAIL_HOST_USER = "xxxx@126.com"
|
|
127
|
+
EMAIL_HOST_PASSWORD = 'CGiKQh5FyQyupQYA'
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
import pymysql
|
|
132
|
+
|
|
133
|
+
pymysql.install_as_MySQLdb()
|
|
134
|
+
|
|
121
135
|
```
|
|
122
136
|
|
|
123
137
|
## 2.2 asgi.py
|
|
124
138
|
|
|
125
139
|
```python
|
|
140
|
+
import os
|
|
141
|
+
from pathlib import Path
|
|
142
|
+
|
|
126
143
|
from django.core.asgi import get_asgi_application
|
|
127
144
|
from channels.routing import ProtocolTypeRouter, URLRouter
|
|
128
145
|
from django.urls import re_path
|
|
129
146
|
|
|
130
147
|
from valar.channels.consumer import ValarConsumer
|
|
131
148
|
|
|
149
|
+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', '%s.settings' % Path(__file__).resolve().parent.parent.name)
|
|
132
150
|
application = ProtocolTypeRouter({
|
|
133
151
|
'http': get_asgi_application(),
|
|
134
152
|
'websocket': URLRouter([
|
|
135
153
|
re_path(r'(?P<client>\w+)/$', ValarConsumer.as_asgi()),
|
|
136
154
|
])
|
|
137
155
|
})
|
|
138
|
-
|
|
139
|
-
|
|
140
156
|
```
|
|
141
157
|
|
|
142
158
|
## 2.3 urls.py
|
|
143
159
|
|
|
144
|
-
|
|
145
|
-
|
|
160
|
+
```python
|
|
161
|
+
from django.urls import path, include
|
|
162
|
+
|
|
163
|
+
urlpatterns = [
|
|
164
|
+
path('valar/', include('valar.urls')),
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
|
|
146
169
|
- go to section 4 to see how to register channel handlers (a Vue - Django async communication tool) in urls.
|
|
147
170
|
|
|
148
171
|
# 3. migrate
|
|
@@ -42,9 +42,6 @@ src/valar/dao/defaults/field_keys_default.py
|
|
|
42
42
|
src/valar/dao/defaults/field_values_default.py
|
|
43
43
|
src/valar/dao/defaults/view_defaults.py
|
|
44
44
|
src/valar/migrations/0001_initial.py
|
|
45
|
-
src/valar/migrations/0002_location.py
|
|
46
|
-
src/valar/migrations/0003_location_code_location_name_cn_location_name_en.py
|
|
47
|
-
src/valar/migrations/0004_remove_location_icon_remove_location_isleaf_and_more.py
|
|
48
45
|
src/valar/migrations/__init__.py
|
|
49
46
|
src/valar/models/__init__.py
|
|
50
47
|
src/valar/models/auth.py
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# Generated by Django 4.2.24 on 2025-09-22 11:51
|
|
2
|
-
|
|
3
|
-
from django.db import migrations, models
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Migration(migrations.Migration):
|
|
7
|
-
|
|
8
|
-
dependencies = [
|
|
9
|
-
('valar', '0001_initial'),
|
|
10
|
-
]
|
|
11
|
-
|
|
12
|
-
operations = [
|
|
13
|
-
migrations.CreateModel(
|
|
14
|
-
name='Location',
|
|
15
|
-
fields=[
|
|
16
|
-
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
17
|
-
('sort', models.BigIntegerField(null=True, verbose_name='序号')),
|
|
18
|
-
('create_time', models.DateTimeField(auto_now_add=True, null=True, verbose_name='创建时间')),
|
|
19
|
-
('modify_time', models.DateTimeField(auto_now=True, null=True, verbose_name='修改时间')),
|
|
20
|
-
('disabled', models.BooleanField(default=False, verbose_name='禁用')),
|
|
21
|
-
('saved', models.BooleanField(default=False, verbose_name='已保存')),
|
|
22
|
-
('pid', models.IntegerField(default=0, verbose_name='父节点')),
|
|
23
|
-
('isLeaf', models.BooleanField(default=False, verbose_name='叶子节点')),
|
|
24
|
-
('icon', models.CharField(max_length=255, null=True, verbose_name='图标')),
|
|
25
|
-
('scope', models.CharField(max_length=100, null=True)),
|
|
26
|
-
('name', models.CharField(max_length=100, null=True)),
|
|
27
|
-
],
|
|
28
|
-
options={
|
|
29
|
-
'verbose_name': '指标集',
|
|
30
|
-
},
|
|
31
|
-
),
|
|
32
|
-
]
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# Generated by Django 4.2.24 on 2025-09-22 11:51
|
|
2
|
-
|
|
3
|
-
from django.db import migrations, models
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Migration(migrations.Migration):
|
|
7
|
-
|
|
8
|
-
dependencies = [
|
|
9
|
-
('valar', '0002_location'),
|
|
10
|
-
]
|
|
11
|
-
|
|
12
|
-
operations = [
|
|
13
|
-
migrations.AddField(
|
|
14
|
-
model_name='location',
|
|
15
|
-
name='code',
|
|
16
|
-
field=models.CharField(max_length=100, null=True),
|
|
17
|
-
),
|
|
18
|
-
migrations.AddField(
|
|
19
|
-
model_name='location',
|
|
20
|
-
name='name_cn',
|
|
21
|
-
field=models.CharField(max_length=100, null=True),
|
|
22
|
-
),
|
|
23
|
-
migrations.AddField(
|
|
24
|
-
model_name='location',
|
|
25
|
-
name='name_en',
|
|
26
|
-
field=models.CharField(max_length=100, null=True),
|
|
27
|
-
),
|
|
28
|
-
]
|
valar-1.3.17/src/valar/migrations/0004_remove_location_icon_remove_location_isleaf_and_more.py
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# Generated by Django 4.2.24 on 2025-09-22 11:52
|
|
2
|
-
|
|
3
|
-
from django.db import migrations
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Migration(migrations.Migration):
|
|
7
|
-
|
|
8
|
-
dependencies = [
|
|
9
|
-
('valar', '0003_location_code_location_name_cn_location_name_en'),
|
|
10
|
-
]
|
|
11
|
-
|
|
12
|
-
operations = [
|
|
13
|
-
migrations.RemoveField(
|
|
14
|
-
model_name='location',
|
|
15
|
-
name='icon',
|
|
16
|
-
),
|
|
17
|
-
migrations.RemoveField(
|
|
18
|
-
model_name='location',
|
|
19
|
-
name='isLeaf',
|
|
20
|
-
),
|
|
21
|
-
migrations.RemoveField(
|
|
22
|
-
model_name='location',
|
|
23
|
-
name='pid',
|
|
24
|
-
),
|
|
25
|
-
]
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import traceback
|
|
2
|
-
|
|
3
|
-
from ..channels.counter import Counter
|
|
4
|
-
from ..channels.sender import ValarChannelSender
|
|
5
|
-
from ..dao import Dao
|
|
6
|
-
from ..dao.engine import ValarEngine
|
|
7
|
-
|
|
8
|
-
import time
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def valar_test_handler(sender: ValarChannelSender):
|
|
12
|
-
data = sender.data
|
|
13
|
-
length = data.get('length', 100)
|
|
14
|
-
counter = Counter(length)
|
|
15
|
-
for i in range(length):
|
|
16
|
-
time.sleep(0.1)
|
|
17
|
-
tick = counter.tick()
|
|
18
|
-
tick.update({'name': 'test1'})
|
|
19
|
-
sender.load(tick)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def batch_handler(sender: ValarChannelSender):
|
|
23
|
-
data = sender.data
|
|
24
|
-
entity, db, method = data.get("entity"), data.get("db"), data.get("method")
|
|
25
|
-
dao = Dao(entity, db)
|
|
26
|
-
body = {"method": method}
|
|
27
|
-
|
|
28
|
-
try:
|
|
29
|
-
if method == 'save_many':
|
|
30
|
-
array = data.get("array", [])
|
|
31
|
-
counter = Counter(array)
|
|
32
|
-
keys = []
|
|
33
|
-
for item in array:
|
|
34
|
-
item.update({'saved': True})
|
|
35
|
-
bean = dao.save_one(item)
|
|
36
|
-
keys.append(bean.id)
|
|
37
|
-
payload = counter.tick()
|
|
38
|
-
sender.load(payload)
|
|
39
|
-
body.update({'keys': keys})
|
|
40
|
-
sender.done(body)
|
|
41
|
-
elif method == 'delete_many':
|
|
42
|
-
conditions = data.get("conditions", [])
|
|
43
|
-
paths = dao.delete(conditions)
|
|
44
|
-
counter = Counter(len(paths))
|
|
45
|
-
minio = ValarEngine().get_minio_bucket(entity)
|
|
46
|
-
for path in paths:
|
|
47
|
-
minio.remove(path)
|
|
48
|
-
payload = counter.tick()
|
|
49
|
-
sender.load(payload)
|
|
50
|
-
sender.done(body)
|
|
51
|
-
except Exception as e:
|
|
52
|
-
traceback.print_exc()
|
|
53
|
-
sender.error(str(e))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|