Compare commits

...

10 Commits

@ -21,7 +21,8 @@
├── ...
```
## Dockerfile
## 配置信息
### Dockerfile
```bash
# generalai:v1是镜像名192.168.10.94:5000是镜像仓库docker registry本地地址
@ -87,7 +88,7 @@ docker build -t lemon:latest .
docker images 查看生成的镜像 lemon:latest
```
## docker-compose.yml
### docker-compose.yml
```shell
version: "3.3"
@ -108,6 +109,8 @@ services:
# - /data/app/lemon:/app/lemon # 如果由相同的设置则会覆盖Dockfile中COPY的文件
- /data/app/log:/app/log
- /data/app/fileupload:/app/fileupload
- /usr/sbin/dmidecode:/usr/sbin/dmidecode # dmidecode命令需要root权限否则会报错
- /dev/mem:/dev/mem # /dev/mem需要root权限否则会报错
environment:
- TZ=Asia/Shanghai
networks: # 配置网络
@ -167,7 +170,7 @@ networks:
driver: bridge # 如果不设置则默认使用bridge
```
## entrypoint.sh
### entrypoint.sh
```bash
#!/bin/bash
@ -236,14 +239,14 @@ function print_dir_structure() {
echo "启动完成"
```
## mysql初始化
### mysql初始化
```
mysql_app.sql, 数据库的结构,以及默认账号的初始化
mysql_auth.sql 修改密码加密规格,修改密码
```
## nginx
### nginx
```
server {
@ -266,7 +269,7 @@ server {
}
```
## supervisor
### supervisor
```
[program:lemon]
@ -286,10 +289,43 @@ command 可以使用动态参数,例如:--port=88%(process_num)02d默认
多进程则修改numproc的值如numproc=2则第一个进程使用8800端口第二个进程使用8801端口。
```
## 启动
## 启动项目
### 本地编译启动
```
1. 修改配置文件
2. 编译docker build -t lemon .
3. docker-compose up -d
```
### 镜像打包
```
Dockerfile中首行配置 FROM 192.168.10.94:5000/generalai:v1使用的是开发环境的docker registry镜像
这个image中包含工程运行需要的基础环境包括各种包supervisor
镜像制作:
docker build -t lemon .
镜像导出:
export:
docker export lemon_web lemon.tar # lemon_web是docker-compose.yml中的container name, 或者使用container id
或者save:
docker save -o lemon.tar lemon:latest # 导出为tar文件方便传输
```
### 导入docker镜像包
```
import: docker import lemon.tar lemon:latest
或者load: docker load < lemon.tar
docker-compose up -d
```
### 查看日志
```
docker logs -f lemon_web
```

@ -16,8 +16,19 @@ services:
# - /data/app/lemon:/app/lemon
- /data/app/log:/app/log
- /data/app/fileupload:/app/fileupload
- ./private_key.pem:/app/lemon/private_key.pem
- /usr/sbin/dmidecode:/usr/sbin/dmidecode
- /dev/mem:/dev/mem
environment:
- TZ=Asia/Shanghai
- MYSQL_DATABASE=aiplatform
- MYSQL_USER=root
- MYSQL_PASSWORD=SghjdA887#
- MYSQL_HOST=lemon_mysql
- MYSQL_PORT=3306
- REDIS_HOST=lemon_redis
- REDIS_PORT=6379
- REDIS_PASSWORD=hgkiYY87
networks:
- lemon_network
depends_on:
@ -29,8 +40,11 @@ services:
image: nginx:latest
container_name: lemon_nginx
ports:
- "80:80"
- "443:443"
# - "80:80"
# - "443:443"
- "8989:8989"
environment:
TZ: Asia/Shanghai
volumes:
- ./nginx.conf:/etc/nginx/conf.d/lemon.conf
- ./dist:/app/lemon/dist
@ -47,6 +61,7 @@ services:
environment:
MYSQL_ROOT_PASSWORD: SghjdA887#
MYSQL_DATABASE: aiplatform
TZ: Asia/Shanghai
volumes:
- /data/mysql_data:/var/lib/mysql
- ./mysql_auth.sql:/docker-entrypoint-initdb.d/auth.sql

@ -22,15 +22,26 @@
if [ ! -f "/app/lemon/website/settings_local.py" ];then
echo "@@init settings_local file"
cat > /app/lemon/website/settings_local.py << EOF
import os
mysql_app = {
"host": "lemon_mysql:3306",
"database": "aiplatform",
"user": "root",
"password": "SghjdA887#",
"host": "{}:{}".format(os.environ.get("MYSQL_HOST"), os.environ.get("MYSQL_PORT")),
"database": os.environ.get("MYSQL_DATABASE"),
"user": os.environ.get("MYSQL_USER"),
"password": os.environ.get("MYSQL_PASSWORD"),
"time_zone": "+8:00"
}
redis_app = ("lemon_redis", 6379, 0, "hgkiYY87")
redis_app = (
os.environ.get("REDIS_HOST"),
os.environ.get("REDIS_PORT"),
0,
os.environ.get("REDIS_PASSWORD"),
)
file_upload_dir = "/app/fileupload"
rsa_private_file = "/app/lemon/private_key.pem"
rsa_license_file = "/app/lemon/license"
EOF
fi

@ -48,7 +48,7 @@ CREATE TABLE `enterprise` (
`industry` int NOT NULL,
`contact` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`phone` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
`summary` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`summary` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL,
`logo` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL,
`account` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`pwd` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,

@ -1,7 +1,8 @@
server {
listen 80;
listen 8989;
server_name 192.168.10.94;
client_max_body_size 300M;
root /app/lemon/dist;
location ^~ /api {

@ -0,0 +1,10 @@
aiofiles==24.1.0
M2Crypto==0.41.0
pandas==2.2.2
Pillow==10.4.0
pycryptodome==3.20.0
redis==5.0.7
requests==2.27.1
SQLAlchemy==2.0.31
tornado==6.4.1
xlwt==1.3.0

@ -40,4 +40,36 @@ device_status_map = {
1002: u"离线",
1003: u"运行中",
1004: u"故障",
}
}
# 系统状态
system_status_not_active = 9000 # 未激活
system_status_activated = 9001 # 已激活
system_status_expire_atall = 9003 # 完全过期
op_type_add = 1001 # 新增
op_type_add_str = u"新增"
op_type_edit = 1002 # 编辑
op_type_edit_str = u"编辑"
op_type_list = 1003 # 查询
op_type_list_str = u"查询"
op_type_delete = 1004 # 删除
op_type_delete_str = u"删除"
op_type_upload = 1005 # 上传
op_type_upload_str = u"上传"
op_type_login_logout = 1006
op_type_login_logout_str = u"登录/登出"
op_type_map = {
op_type_add: op_type_add_str,
op_type_edit: op_type_edit_str,
op_type_list: op_type_list_str,
op_type_delete: op_type_delete_str,
op_type_upload: op_type_upload_str,
op_type_login_logout: op_type_login_logout_str,
}

@ -97,4 +97,4 @@ class ModelRepositry(object):
def get_model_count(self) -> int:
with get_session() as session:
return session.query(Model).count()
return session.query(Model).filter(Model.delete == 0).count()

@ -1,13 +1,13 @@
from website.handler import BaseHandler
from sqlalchemy import text
import json
from typing import Any
from sqlalchemy import text
from website.db_mysql import get_session, get_async_session, to_json, to_json_list
import json
# 获取企业模型数量
def get_enterprise_model_count(id: int) -> int:
return 0
@ -19,7 +19,7 @@ def get_enterprise_device_count(id: int) -> int:
# 获取所有企业实体数量
def get_enterprise_entity_count(engine: Any) -> int:
with engine.connect() as conn:
count_sql_text = "select count(*) from enterprise "
count_sql_text = "select count(*) from enterprise where del=0 "
count = conn.execute(text(count_sql_text)).fetchone()
if count:
return count[0]
@ -68,7 +68,7 @@ def get_enterprise_device_count(entity_id: int = 0, entity_suid: str = "") -> in
async def get_enterprise_model_and_device_count(
entity_id: int = 0, entity_suid: str = ""
entity_id: int = 0, entity_suid: str = ""
) -> (int, int):
model_count = 0
device_count = 0
@ -103,8 +103,6 @@ async def get_enterprise_model_and_device_count(
# if res_device:
# device_count = res_device["device_count"]
sql_device_count = "SELECT COUNT(*) AS device_count FROM enterprise_device WHERE {where_clause} "
sql_base_model = "SELECT base_models FROM enterprise_busi_model WHERE {where_clause} "

@ -5,13 +5,13 @@ import logging
from typing import Any, Dict, List, Optional
from sqlalchemy import Column, Integer, String, DateTime, func
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import text
from sqlalchemy.ext.declarative import declarative_base
from website.db.alg_model import alg_model as DB_alg_model
from website.db.enterprise_entity.enterprise_entity import EnterpriseEntityRepository
from website.db.enterprise_node import enterprise_node as DB_Node
from website.db_mysql import get_session, to_json_list, to_json, Row, dict_to_obj
from website.db_mysql import get_session, to_json_list, Row, dict_to_obj
from website.util import shortuuid
Base = declarative_base()
@ -73,6 +73,7 @@ class EnterpriseBusiModel(Base):
filtered_data = {key: value for key, value in kwargs.items() if key in valid_columns}
super().__init__(**filtered_data)
class EnterpriseBusiModelRepository(object):
def get_by_id(self, id: int) -> Optional[EnterpriseBusiModel]:
@ -161,7 +162,7 @@ class EnterpriseBusiModelRepository(object):
"""
with get_session() as session:
total_count = session.query(func.count(EnterpriseBusiModel.id)).filter(
EnterpriseBusiModel.entity_id == entity_id).scalar()
EnterpriseBusiModel.entity_id == entity_id).filter(EnterpriseBusiModel.delete == 0).scalar()
models = (
session.query(
@ -170,6 +171,7 @@ class EnterpriseBusiModelRepository(object):
EnterpriseBusiModel.create_time
)
.filter(EnterpriseBusiModel.entity_id == entity_id)
.filter(EnterpriseBusiModel.delete == 0)
.offset((page_no - 1) * page_size)
.limit(page_size)
.all()
@ -204,6 +206,7 @@ class EnterpriseBusiModelRepository(object):
session.commit()
return
class EnterpriseBusiModelNode(Base):
__tablename__ = 'enterprise_busi_model_node'
@ -277,19 +280,18 @@ class EnterpriseBusiModelNodeRepository(object):
.offset((page_no - 1) * page_size)
.limit(page_size)
.all()
)
)
total_count = session.query(func.count(EnterpriseBusiModelNode.id)).filter(
EnterpriseBusiModelNode.node_id == node_id).scalar()
return {
"count": total_count,
"count": total_count,
"data": [
{
"busi_model_id": model.busi_model_id,
"busi_model_name": model.busi_model_name,
"create_time": model.create_time.strftime("%Y-%m-%d %H:%M:%S"),
"busi_model_id": model.busi_model_id,
"busi_model_name": model.busi_model_name,
"create_time": model.create_time.strftime("%Y-%m-%d %H:%M:%S"),
} for model in models
]
}

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
import logging
from typing import List, Dict, Any, Union
from sqlalchemy import text
@ -71,15 +71,18 @@ class EnterpriseNodeRepository(object):
n.id, n.name, n.parent, p.name AS parent_name, n.suid
FROM enterprise_node n
LEFT JOIN enterprise_node p ON n.parent = p.id
WHERE n.entity_id=:entity_id AND n.del=0 and n.parent=0
WHERE n.entity_id=:entity_id AND n.del=0
"""
)
if name == "":
sql += " and n.parent=0"
param = {"entity_id": entity_id}
if name:
sql += " and n.name like :name"
param["name"] = f"%{name}%"
# logging.info(f"############################# sql: {sql}, param: {param}")
res = session.execute(text(sql), param)
node_list = to_json_list(res)
node_list = node_list and node_list or []
@ -115,9 +118,9 @@ class EnterpriseNodeRepository(object):
param = {"parent": node["id"]}
if name:
sql += " and n.name like :name"
param["name"] = f"%{name}%"
# if name:
# sql += " and n.name like :name"
# param["name"] = f"%{name}%"
res = session.execute(text(sql), param)
node_list = to_json_list(res)

@ -53,7 +53,7 @@ class FileRepository(object):
for file in files:
obj_dict = file.__dict__
del obj_dict['_sa_instance_state']
print(obj_dict)
# print(obj_dict)
resp.append(dict_to_obj(obj_dict))
# return session.query(File).filter(File.md5_str.in_(md5_list)).all()

@ -496,7 +496,7 @@ def authenticated_admin(method):
return wrapper
def operation_log(primary_menu, sub_menu, ope_type, content, comment):
def operation_log(primary_menu, sub_menu, ope_type, content, comment=""):
"""
Add logging to a function. level is the logging
level, name is the logger name, and message is the
@ -507,22 +507,25 @@ def operation_log(primary_menu, sub_menu, ope_type, content, comment):
def decorate(func):
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
with self.app_mysql.connect() as conn:
conn.execute(text(
"insert into sys_log(user, ip, primary_menu, sub_menu, op_type, content, comment) "
"values(:user, :ip, :primary_menu, :sub_menu, :op_type, :content, :comment)"
),
{"user": self.current_user.name,
"ip": self.request.headers[
"X-Forwarded-For"] if "X-Forwarded-For" in self.request.headers else self.request.remote_ip,
"primary_menu": primary_menu,
"sub_menu": sub_menu,
"op_type": ope_type,
"content": content,
"comment": comment
}
)
conn.commit()
try:
with self.app_mysql.connect() as conn:
conn.execute(text(
"insert into sys_log(user, ip, primary_menu, sub_menu, op_type, content, comment) "
"values(:user, :ip, :primary_menu, :sub_menu, :op_type, :content, :comment)"
),
{"user": self.current_user.name,
"ip": self.request.headers[
"X-Forwarded-For"] if "X-Forwarded-For" in self.request.headers else self.request.remote_ip,
"primary_menu": primary_menu,
"sub_menu": sub_menu,
"op_type": ope_type,
"content": content,
"comment": comment
}
)
conn.commit()
except Exception as e:
logging.info("operation log error: %s" % e)
return func(self, *args, **kwargs)

@ -8,7 +8,7 @@ from website import consts
from website import db_mysql
from website import errors
from website import settings
from website.handler import APIHandler, authenticated
from website.handler import APIHandler, authenticated, operation_log
from website.util import md5, shortuuid
@ -19,6 +19,7 @@ class ClassificationAddHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型列表", consts.op_type_add_str, "添加模型分类", "")
def post(self):
name = self.get_escaped_argument("name", "")
if not name:
@ -53,6 +54,7 @@ class ClassificationEditHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型列表", consts.op_type_edit_str, "编辑模型分类", "")
def post(self):
classification_id = self.get_int_argument("id")
name = self.get_escaped_argument("name", "")
@ -75,6 +77,7 @@ class ClassificationListHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型列表", consts.op_type_list_str, "查询模型分类", "")
def post(self):
with self.app_mysql.connect() as conn:
cur = conn.execute(text("""select id, name from model_classification"""))
@ -89,6 +92,7 @@ class ClassificationDeleteHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型列表", consts.op_type_delete_str, "删除模型分类", "")
def post(self):
classification_id = self.get_int_argument("id")
if not classification_id:
@ -104,12 +108,35 @@ class ClassificationDeleteHandler(APIHandler):
self.finish()
class ClassificationEditHandler(APIHandler):
"""
编辑模型分类
"""
@authenticated
@operation_log("模型管理", "模型列表", consts.op_type_edit_str, "编辑模型分类", "")
def post(self):
classification_id = self.get_int_argument("id")
name = self.get_escaped_argument("name", "")
if not classification_id or not name:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "参数缺失")
with self.app_mysql.connect() as conn:
conn.execute(
text("""update model_classification set name=:name where id=:id"""),
{"name": name, "id": classification_id},
)
conn.commit()
self.finish()
class ListHandler(APIHandler):
"""
模型列表
"""
@authenticated
@operation_log("模型管理", "模型列表", consts.op_type_list_str, "查询模型列表", "")
def post(self):
pageNo = self.get_int_argument("pageNo", 1)
pageSize = self.get_int_argument("pageSize", consts.PAGE_SIZE)
@ -124,7 +151,7 @@ class ListHandler(APIHandler):
param = {}
sql_count = "select count(id) from model where del=0 "
sql_count = "select count(id) from model m where m.del=0 "
param_count = {}
if name:
@ -161,6 +188,7 @@ class ListHandler(APIHandler):
class ListSimpleHandler(APIHandler):
@authenticated
@operation_log("模型管理", "模型列表", consts.op_type_list_str, "查询模型列表", "")
def post(self):
with self.app_mysql.connect() as conn:
sql = "select id, name from model where del=0"
@ -176,6 +204,7 @@ class AddHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "添加模型", consts.op_type_add_str, "添加模型", "")
def post(self):
name = self.get_escaped_argument("name", "")
model_type = self.get_int_argument(
@ -218,6 +247,7 @@ class EditHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "编辑模型", consts.op_type_edit_str, "编辑模型", "")
def post(self):
mid = self.get_int_argument("id")
name = self.get_escaped_argument("name", "")
@ -258,6 +288,7 @@ class InfoHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型信息", consts.op_type_list_str, "查询模型信息", "")
def post(self):
mid = self.get_int_argument("id")
if not mid:
@ -270,8 +301,10 @@ class InfoHandler(APIHandler):
select
m.name, m.model_type, m.default_version, m.comment, m.update_time,
mc.id as classification_id, mc.name as classification_name
from model m, model_classification mc
where m.id=:id and m.classification=mc.id
from model m
left join model_classification mc
on m.classification=mc.id
where m.id=:id
"""
),
{"id": mid},
@ -300,6 +333,7 @@ class DeleteHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型列表", consts.op_type_delete_str, "删除模型", "")
def post(self):
mid = self.get_int_argument("id")
if not mid:
@ -329,6 +363,7 @@ class VersionAddHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型版本", consts.op_type_add_str, "添加模型版本", "")
def post(self):
mid = self.get_int_argument("model_id")
version = self.get_escaped_argument("version", "")
@ -382,6 +417,7 @@ class VersionEditHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型版本", consts.op_type_edit_str, "编辑模型版本", "")
def post(self):
version_id = self.get_int_argument("version_id")
version = self.get_escaped_argument("version", "")
@ -445,6 +481,7 @@ class VersionListHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型版本", consts.op_type_list_str, "模型版本列表", "")
def post(self):
model_id = self.get_int_argument("model_id")
pageNo = self.get_int_argument("pageNo", 1)
@ -524,6 +561,7 @@ class VersionInfoHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型版本", consts.op_type_list_str, "查询模型版本详情", "")
def post(self):
version_id = self.get_int_argument("version_id")
response = {
@ -606,6 +644,7 @@ class VersionSetDefaultHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型版本", consts.op_type_edit_str, "设置模型版本为默认版本", "")
def post(self):
version_id = self.get_int_argument("version_id")
model_id = self.get_int_argument("model_id")
@ -644,6 +683,7 @@ class VersionDeleteHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型版本", consts.op_type_delete_str, "删除模型版本", "")
def post(self):
version_id = self.get_int_argument("version_id")
if not version_id:

@ -5,6 +5,7 @@ handlers = [
("/model/classification/add", handler.ClassificationAddHandler),
("/model/classification/list", handler.ClassificationListHandler),
("/model/classification/delete", handler.ClassificationDeleteHandler),
("/model/classification/edit", handler.ClassificationEditHandler),
("/model/list", handler.ListHandler),
("/model/list/simple", handler.ListSimpleHandler),

@ -9,7 +9,7 @@ from website import consts
from website import db_mysql
from website import errors
from website import settings
from website.handler import APIHandler, authenticated
from website.handler import APIHandler, authenticated, operation_log
class ListHandler(APIHandler):
@ -38,6 +38,7 @@ class ListHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型运行库", consts.op_type_list_str, "查询模型运行库列表", "")
def post(self):
pageNo = self.get_int_argument("pageNo", 1)
pageSize = self.get_int_argument("pageSize", consts.PAGE_SIZE)
@ -104,6 +105,7 @@ class SyncHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型运行库", consts.op_type_list_str, "查询模型运行库镜像", "")
def post(self):
host = self.get_escaped_argument("host", "")
port = self.get_int_argument("port")
@ -142,6 +144,7 @@ class AddHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型运行库", consts.op_type_add_str, "新建模型运行库", "")
def post(self):
name = self.get_escaped_argument("name", "")
host = self.get_escaped_argument("host", "")
@ -173,7 +176,7 @@ class AddHandler(APIHandler):
self.finish()
class EditHandler(APIHandler):
class EditHandler(APIHandler):
"""
- 描述 编辑模型运行库
- 请求方式post
@ -188,6 +191,7 @@ class EditHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型运行库", consts.op_type_edit_str, "编辑模型运行库", "")
def post(self):
id = self.get_int_argument("id")
name = self.get_escaped_argument("name", "")
@ -195,7 +199,7 @@ class EditHandler(APIHandler):
port = self.get_int_argument("port")
path = self.get_escaped_argument("path", "")
comment = self.get_escaped_argument("comment", "")
if not id or not name or not host or not port or path:
if not id or not name or not host or not port or not path:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "parameter error")
with self.app_mysql.connect() as conn:
conn.execute(
@ -235,6 +239,7 @@ class InfoHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型运行库", consts.op_type_list_str, "查询模型运行库信息", "")
def post(self):
hid = self.get_int_argument("id")
if not id:
@ -266,6 +271,7 @@ class DeleteHandler(APIHandler):
"""
@authenticated
@operation_log("模型管理", "模型运行库", consts.op_type_delete_str, "删除模型运行库", "")
def post(self):
hid = self.get_int_argument("id")
if not id:

@ -3,8 +3,8 @@ import json
import logging
from sqlalchemy import text
from website import db_mysql, errors
from website.handler import APIHandler, authenticated
from website import db_mysql, errors, consts
from website.handler import APIHandler, authenticated, operation_log
from website.util import shortuuid
from website.db.enterprise_busi_model import enterprise_busi_model as DB_BusiModel
from website.db.enterprise_busi_model import enterprise_busi_model_node_device as DB_BusiModelNodeDevice
@ -35,6 +35,7 @@ class ListHandler(APIHandler):
```
"""
@authenticated
@operation_log("企业管理", "业务模型", consts.op_type_list_str, "查询企业部署的业务模型列表", "")
def post(self):
pageNo = self.get_int_argument("pageNo", 1)
pageSize = self.get_int_argument("pageSize", 10)
@ -63,6 +64,7 @@ class AddHandler(APIHandler):
- 返回值
"""
@authenticated
@operation_log("企业管理", "业务模型", consts.op_type_add_str, "添加企业部署的业务模型", "")
def post(self):
entity_id = self.get_int_argument("entity_id")
name = self.get_escaped_argument("name", "")
@ -131,6 +133,7 @@ class InfoHandler(APIHandler):
```
"""
@authenticated
@operation_log("企业管理", "业务模型", consts.op_type_list_str, "查询企业部署的业务模型详情")
def post(self):
busimodel_id = self.get_int_argument("id")
@ -145,11 +148,14 @@ class InfoHandler(APIHandler):
db_file = DB_File.FileRepository()
files = db_file.get_file_by_md5([busi_model_data.business_conf_file, busi_model_data.business_logic])
business_conf_name = files[0].filename
business_logic_name = files[1].filename
business_logic_name = ""
business_conf_name = ""
for item in files:
if item.md5_str == busi_model_data.business_logic:
business_logic_name = item.filename
else:
business_conf_name = item.filename
# business_conf_name = db_file.get_file_by_md5(busi_model_data.business_conf_file)
# business_logic_name = db_file.get_file_by_md5(busi_model_data.business_logic)
basemodel_list = json.loads(busi_model_data.base_models)
entity_suid = busi_model_data.entity_suid
@ -189,6 +195,7 @@ class EditHandler(APIHandler):
- 返回值
"""
@authenticated
@operation_log("企业管理", "业务模型", consts.op_type_edit_str, "编辑企业部署的业务模型")
def post(self):
busimodel_id = self.get_int_argument("id")
@ -255,6 +262,7 @@ class EditHandler(APIHandler):
class DeleteHandler(APIHandler):
@authenticated
@operation_log("企业管理", "业务模型", consts.op_type_delete_str, "删除企业部署的业务模型")
def post(self):
busimodel_id = self.get_int_argument("id")
if not busimodel_id:

@ -16,7 +16,7 @@ from website.db.enterprise_busi_model import enterprise_busi_model_node_device a
from website.db.enterprise_device import enterprise_device as DB_Device
from website.db.enterprise_node import enterprise_node as DB_Node
from website.db.enterprise_node import enterprise_node_base_model_conf as DB_NodeBaseModelConf
from website.handler import APIHandler, authenticated
from website.handler import APIHandler, authenticated, operation_log
from website.util import date_util
from website.util import shortuuid
@ -37,6 +37,7 @@ class DeviceClassificationAddHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "设备管理", consts.op_type_add_str, "添加设备分类")
def post(self):
name = self.get_escaped_argument("name", "")
with self.app_mysql.connect() as conn:
@ -82,6 +83,7 @@ class DeviceClassificationHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "设备管理", consts.op_type_list_str, "设备分类列表")
def post(self):
with self.app_mysql.connect() as conn:
cur = conn.execute(
@ -105,6 +107,7 @@ class DeviceClassificationDeleteHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "设备管理", consts.op_type_delete_str, "删除设备分类")
def post(self):
did = self.get_int_argument("id")
@ -131,6 +134,30 @@ class DeviceClassificationDeleteHandler(APIHandler):
self.finish()
class DeviceClassificationEditHandler(APIHandler):
"""
- 描述编辑设备分类
- 请求方式post
- 请求参数
>- id
>- name
- 返回值
"""
@authenticated
@operation_log("企业管理", "设备管理", consts.op_type_edit_str, "编辑设备分类")
def post(self):
did = self.get_int_argument("id")
name = self.get_escaped_argument("name", "")
with self.app_mysql.connect() as conn:
conn.execute(
text("update device_classification set name=:name WHERE id=:id"),
{"id": did, "name": name},
)
conn.commit()
self.finish()
class DeviceAddHandler(APIHandler):
"""
- 描述企业节点添加设备
@ -151,6 +178,7 @@ class DeviceAddHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "设备管理", consts.op_type_add_str, "企业节点,添加设备")
def post(self):
entity_id = self.get_int_argument("entity_id")
node_id = self.get_int_argument("node_id")
@ -204,6 +232,7 @@ class DeviceEditHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "设备管理", consts.op_type_edit_str, "企业节点,编辑设备")
def post(self):
device_id = self.get_int_argument("device_id")
name = self.get_escaped_argument("name", "")
@ -243,6 +272,7 @@ class DeviceDeleteHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "设备管理", consts.op_type_delete_str, "企业节点,删除设备")
def post(self):
# node_id = self.get_int_argument('node_id')
device_id = self.get_int_argument("device_id")
@ -281,6 +311,7 @@ class DeviceListHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "设备管理", consts.op_type_list_str, "企业节点,设备列表")
def post(self):
node_id = self.get_int_argument("node_id")
pageNo = self.get_int_argument("pageNo", 1)
@ -329,7 +360,8 @@ class DeviceInfoHandler(APIHandler):
}
```
"""
@authenticated
@operation_log("企业管理", "设备管理", consts.op_type_list_str, "企业节点,设备信息")
def post(self):
device_id = self.get_int_argument("device_id")
if not device_id:
@ -374,6 +406,7 @@ class DeviceBasemodelListHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "节点设置", consts.op_type_list_str, "企业节点,节点信息 -> 设备列表 -> 基础模型配置 -> 模型列表")
def post(self):
device_id = self.get_int_argument("device_id")
if not device_id:
@ -395,9 +428,6 @@ class DeviceBasemodelListHandler(APIHandler):
busi_model_id = item["busi_model_id"]
busi_model_name = item["name"]
base_model_list = json.loads(item["base_models"])
logging.info("##############################################################")
logging.info(base_model_list)
logging.info("##############################################################")
base_models = []
for base_model in base_model_list:
base_model_id = base_model["id"]
@ -448,6 +478,8 @@ class DeviceBaseModelCustomConfigHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "节点设置", consts.op_type_add_str,
"企业节点,节点信息 -> 设备列表 -> 基础模型配置 -> 基础模型参数配置")
def post(self):
device_id = self.get_int_argument("device_id")
node_id = self.get_int_argument("node_id")
@ -533,6 +565,7 @@ class StatusListHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "设备状态", consts.op_type_list_str,"设备状态列表")
def post(self):
entity_id = self.get_int_argument("entity_id")
group = self.get_int_argument("group")
@ -599,6 +632,7 @@ class StatusInfoHandler(APIHandler):
""" """
@authenticated
@operation_log("企业管理", "设备状态", consts.op_type_list_str, "设备信息")
def post(self):
device_id = self.get_int_argument("id")
if not device_id:

@ -5,10 +5,8 @@ from website.handlers.enterprise_device import handler
handlers = [
("/enterprise/device/classification/add", handler.DeviceClassificationAddHandler),
("/enterprise/device/classification", handler.DeviceClassificationHandler),
(
"/enterprise/device/classification/delete",
handler.DeviceClassificationDeleteHandler,
),
("/enterprise/device/classification/delete", handler.DeviceClassificationDeleteHandler),
("/enterprise/device/classification/edit", handler.DeviceClassificationEditHandler),
("/enterprise/entity/nodes/device/add", handler.DeviceAddHandler),
("/enterprise/entity/nodes/device/edit", handler.DeviceEditHandler),
("/enterprise/entity/nodes/device/delete", handler.DeviceDeleteHandler),

@ -12,7 +12,7 @@ from website import settings
from website.db.alg_model.alg_model import ModelRepositry
from website.db.enterprise import enterprise
from website.db.enterprise_device.enterprise_device import EnterpriseDeviceRepository
from website.handler import APIHandler, authenticated
from website.handler import APIHandler, authenticated, operation_log
from website.util import shortuuid, aes
@ -24,6 +24,7 @@ class EntityIndexHandler(APIHandler):
"""首页"""
@authenticated
@operation_log("首页", "企业列表", consts.op_type_list_str, "企业列表")
async def post(self):
pageNo = self.get_int_argument("pageNo", 1)
pageSize = self.get_int_argument("pageSize", 10)
@ -104,7 +105,7 @@ class EntityIndexHandler(APIHandler):
"industry": consts.industry_map[item["industry"]],
"modelCount": model_count,
"deviceCount": device_count,
"logo": item["logo"],
"logo": str(item["logo"]),
"createTime": str(item["create_time"]),
}
for item, model_count, device_count in zip(
@ -119,6 +120,7 @@ class EntityIndexBasecountHandler(APIHandler):
"""首页基础统计书记"""
@authenticated
@operation_log("首页", "企业列表", consts.op_type_list_str, "基础统计数据")
def post(self):
entity_count = enterprise.get_enterprise_entity_count(self.app_mysql)
model_repository = ModelRepositry()
@ -133,6 +135,7 @@ class EntityAddHandler(APIHandler):
"""添加企业"""
@authenticated
@operation_log("首页", "企业列表", consts.op_type_add_str, "添加企业项目")
def post(self):
name = self.tostr(self.get_escaped_argument("name", ""))
province = self.get_escaped_argument("province", "")
@ -203,6 +206,7 @@ class EntityEditHandler(APIHandler):
"""编辑企业"""
@authenticated
@operation_log("首页", "企业列表", consts.op_type_edit_str, "编辑企业项目")
def post(self):
eid = self.get_int_argument("id")
name = self.tostr(self.get_escaped_argument("name", ""))
@ -267,6 +271,7 @@ class EntityInfoHandler(APIHandler):
"""企业信息"""
@authenticated
@operation_log("企业管理", "企业信息", consts.op_type_list_str, "企业信息")
def post(self):
eid = self.get_int_argument("id")
@ -293,12 +298,13 @@ class EntityInfoHandler(APIHandler):
"province": row["province"],
"city": row["city"],
"addr": row["addr"],
"industry": consts.industry_map[row["industry"]],
"industry": row["industry"],
"industry_name": consts.industry_map[row["industry"]],
"expire_at": "",
"contact": row["contact"],
"phone": row["phone"],
"summary": row["summary"],
"logo": row["logo"],
"logo": str(row["logo"]),
"createTime": str(row["create_time"]),
"account": row["account"], # 企业账号
}
@ -310,42 +316,45 @@ class ModelsHandler(APIHandler):
"""企业模型"""
@authenticated
@operation_log("企业管理", "企业模型", consts.op_type_list_str, "企业模型")
def post(self):
eid = self.get_int_argument("id")
model_ids = []
with self.app_mysql.connect() as conn:
cur = conn.execute(
cur_modelid = conn.execute(
text("select base_models from enterprise_busi_model where entity_id=:eid"), {"eid": eid}
)
rows = db_mysql.to_json_list(cur)
rows = db_mysql.to_json_list(cur_modelid)
for row in rows:
base_models = json.loads(row["base_models"])
model_ids.extend([item["id"] for item in base_models])
cur.close()
cur_modelid.close()
model_ids = list(set(model_ids))
cur = conn.execute(text(
"""
select m.name, m.model_type, mc.name as classification_name, m.default_version
from model m, model_classification mc
where m.classification=mc.id and m.id in :model_ids
"""
), {"model_ids": model_ids})
rows = db_mysql.to_json_list(cur)
cur.close()
data = []
for row in rows:
data.append({
"name": row["name"],
"model_type": consts.model_type_map[row["model_type"]],
"classification_name": row["classification_name"],
"default_version": row["default_version"]
})
if len(model_ids) > 0:
cur = conn.execute(text(
"""
select m.name, m.model_type, mc.name as classification_name, m.default_version
from model m, model_classification mc
where m.classification=mc.id and m.id in :model_ids
"""
), {"model_ids": model_ids})
rows = db_mysql.to_json_list(cur)
cur.close()
for row in rows:
data.append({
"name": row["name"],
"model_type": consts.model_type_map[row["model_type"]],
"classification_name": row["classification_name"],
"default_version": row["default_version"]
})
self.finish({"count": len(model_ids), "data": data})
@ -354,6 +363,7 @@ class EntityDeleteHandler(APIHandler):
"""删除企业"""
@authenticated
@operation_log("首页", "企业列表", consts.op_type_delete_str, "删除企业")
def post(self):
eid = self.get_int_argument("id")
@ -369,6 +379,7 @@ class EntityPwdcheckHandler(APIHandler):
"""查看企业密码"""
@authenticated
@operation_log("企业管理", "企业信息", consts.op_type_list_str, "查看企业密码")
def post(self):
eid = self.get_int_argument("id")

@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-
import json
import logging
from website import errors
from website import errors, consts
from website.db.enterprise_busi_model import enterprise_busi_model as DB_BusiModel
from website.db.enterprise_busi_model import (
enterprise_busi_model_node_device as DB_BusiModelNodeDevice,
@ -10,7 +11,7 @@ from website.db.enterprise_device import enterprise_device as DB_Device
from website.db.enterprise_entity import enterprise_entity as DB_Entity
from website.db.enterprise_node import enterprise_node as DB_Node
from website.db.enterprise_node import enterprise_node_alert as DB_NodeAlert
from website.handler import APIHandler, authenticated
from website.handler import APIHandler, authenticated, operation_log
from website.util import shortuuid
@ -30,7 +31,8 @@ class AddHandler(APIHandler):
- 返回值
"""
# @authenticated
@authenticated
@operation_log("企业管理", "节点设置", consts.op_type_add_str, "添加企业节点")
def post(self):
entity_id = self.get_int_argument("entity_id")
entity_suid = self.get_escaped_argument("entity_suid", "")
@ -83,7 +85,8 @@ class EditHandler(APIHandler):
- 返回值
"""
# @authenticated
@authenticated
@operation_log("企业管理", "节点设置", consts.op_type_edit_str, "更新企业节点")
def post(self):
node_id = self.get_int_argument("node_id", 0)
name = self.get_escaped_argument("name", "")
@ -151,9 +154,11 @@ class TreeHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "节点设置", consts.op_type_list_str, "企业节点树")
def post(self):
entity_id = self.get_escaped_argument("entity_id", "")
name = self.get_escaped_argument("name", "")
# logging.info(f"name is {name}")
if not entity_id:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "参数错误")
@ -183,6 +188,7 @@ class InfoHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "节点设置", consts.op_type_list_str, "企业节点信息")
def post(self):
node_id = self.get_int_argument("node_id")
@ -198,6 +204,7 @@ class InfoHandler(APIHandler):
class DeleteHandler(APIHandler):
@authenticated
@operation_log("企业管理", "节点设置", consts.op_type_list_str, "删除节点")
def post(self):
node_id = self.get_int_argument("node_id")
if not node_id:
@ -233,6 +240,7 @@ class BusimodelHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "节点设置", consts.op_type_list_str, "业务模型部署列表")
def post(self):
node_id = self.get_int_argument("node_id")
pageNo = self.get_int_argument("pageNo", 1)
@ -284,6 +292,7 @@ class BusimodelInfoHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "节点设置", consts.op_type_list_str, "业务模型部署 -> 业务模型信息")
def post(self):
node_id = self.get_int_argument("node_id")
busi_model_id = self.get_int_argument("busi_model_id")
@ -332,6 +341,7 @@ class BusimodelDeployHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "节点设置", consts.op_type_add_str, "业务模型部署 -> 业务模型配置")
def post(self):
node_id = self.get_int_argument("node_id")
busi_model_id = self.get_int_argument("busi_model_id")
@ -403,6 +413,7 @@ class AlertHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "节点设置", consts.op_type_list_str, "节点信息 -> 设备列表 -> 告警设置信息")
def post(self):
node_id = self.get_int_argument("node_id")
if not node_id:
@ -452,6 +463,7 @@ class AlertConfigHandler(APIHandler):
"""
@authenticated
@operation_log("企业管理", "节点设置", consts.op_type_edit_str, "节点信息 -> 设备列表 -> 告警设置,更新配置")
def post(self):
node_id = self.get_int_argument("node_id")
is_sms = self.get_int_argument("is_sms", 0)

@ -30,7 +30,7 @@ class UploadHandler(APIHandler):
logging.info("file_size: %s", file_size)
if file_size > 300 * 1024 * 1024:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, 'Exceed 300M size limit')
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, '超出300M限定大小')
filetype = filename.split(".") and filename.split(".")[-1] or ""

@ -1,21 +1,19 @@
# -*- coding: utf-8 -*-
"""系统信息"""
import datetime
import json
import logging
import uuid
import time
import re
import os
import json
import hashlib
import time
import datetime
from sqlalchemy import text
from website import consts
from website import errors
from website import settings
from website.handler import APIHandler, WebHandler, authenticated, operation_log, permission
from website.db_mysql import to_json_list
from website.util import sysinfo, rsa
from sqlalchemy import text
from website.handler import APIHandler, authenticated
from website.util import sysinfo, rsa_oaep
class VersionHandler(APIHandler):
@ -24,8 +22,12 @@ class VersionHandler(APIHandler):
def post(self):
self.finish()
class IdentifycodeHandler(APIHandler):
@authenticated
"""系统识别码"""
# @authenticated
# @permission([100014, 100015])
# @operation_log("资产管理中心", "系统激活", "查询", "查询本地识别码", "查询本地识别码")
def post(self):
@ -33,6 +35,7 @@ class IdentifycodeHandler(APIHandler):
self.finish({"result": code})
class LicenseUploadHandler(APIHandler):
@authenticated
# @permission([100014, 100015])
@ -55,45 +58,44 @@ class LicenseUploadHandler(APIHandler):
if file_size > 10 * 1024 * 1024:
raise errors.HTTPAPIError(errors.ERROR_METHOD_NOT_ALLOWED, 'Exceed 10M size limit')
md5_str = hashlib.md5(file.body).hexdigest()
filepath = settings.rsa_license_file
try:
body = file['body']
public_key = rsa.load_pub_key_string(open(settings.rsa_public_file).read().strip('\n').encode('utf-8'))
plaintext = rsa.decrypt(public_key, body)
plaintext = rsa_oaep.decrypt_message_pri(
open(settings.rsa_private_file).read().strip('\n').encode('utf-8'), body)
plaintext_json = json.loads(self.tostr(plaintext))
syscode = plaintext_json["syscode"]
expireat = plaintext_json["expireat"]
syscode = plaintext_json["sys_code"]
expireat = plaintext_json["expire_at"]
current_syscode = sysinfo.get_identify_code()
current_syscode = sysinfo.get_idntify_code_v2()
if syscode != current_syscode:
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "license激活失败请重新激活")
row = self.db_app.get("select id from license where syscode=%s", syscode)
if row:
self.db_app.update(
"update license set expireat=%s where syscode=%s", str(expireat), syscode
)
else:
self.db_app.insert(
"insert into license(syscode, expireat) values(%s, %s)",
syscode, expireat
)
self.r_app.set("system:license", json.dumps({"syscode":syscode, "expireat":expireat}))
with self.app_mysql.connect() as conn:
conn.execute(text(
"update sys_license set syscode=:syscode, expireat=:expireat, status=:status",
{
"syscode": syscode,
"expireat": expireat,
"status": consts.system_status_activated
}
))
conn.commit()
self.r_app.set("system:license", json.dumps({"syscode": syscode, "expireat": expireat}))
with open(filepath, 'wb') as f:
f.write(file['body'])
logging.info(plaintext_json)
except Exception as e:
logging.info(e)
raise errors.HTTPAPIError(errors.ERROR_BAD_REQUEST, "license激活失败请重新激活")
self.finish()
class ActivateInfoHandler(APIHandler):
@authenticated
# @permission([100014, 100015])
@ -116,11 +118,11 @@ class ActivateInfoHandler(APIHandler):
date_remain = delta if delta > 0 else 0
data = {
"system": settings.system_info[settings.system_type]["name"],
"license": license_str,
"activate_at": activate_at,
"expire_at": expire_at,
"date_remain": date_remain
# "system": settings.system_info[settings.system_type]["name"],
# "license": license_str,
# "activate_at": activate_at,
# "expire_at": expire_at,
# "date_remain": date_remain
}
self.finish(data)
@ -128,7 +130,6 @@ class ActivateInfoHandler(APIHandler):
class InfoHandler(APIHandler):
def post(self):
self.finish()
@ -141,15 +142,15 @@ class LogHandler(APIHandler):
pageNo = self.get_int_argument("pageNo", 1)
pageSize = self.get_int_argument("pageSize", 20)
users = user.split(",")
user_list = user.split(",") if user else []
with self.app_mysql.connect() as conn:
sql = "select user, ip, content, op_type, content from sys_log where 1=1"
sql = "select user, ip, content, op_type, content, create_time from sys_log where 1=1"
sql_count = "select count(*) from sys_log where 1=1"
p = {}
if users:
if user_list:
sql += " and user in :users"
sql_count += " and user in :users"
p["users"] = users
p["users"] = user_list
if start:
sql += " and date_format(create_time, '%Y-%m-%d') >= :start"
sql_count += " and date_format(create_time, '%Y-%m-%d') >= :start"
@ -166,5 +167,7 @@ class LogHandler(APIHandler):
p["pageSize"] = pageSize
res = conn.execute(text(sql), p)
data = to_json_list(res)
for item in data:
item["create_time"] = str(item["create_time"])
self.finish({"count": count, "data": data})
self.finish({"count": count, "data": data})

@ -8,7 +8,6 @@ handlers = [
("/system/license/upload", handler.LicenseUploadHandler),
("/system/activate/info", handler.ActivateInfoHandler),
("/system/info", handler.InfoHandler),
("/system/log", handler.LogHandler),
]

@ -4,11 +4,13 @@ import json
import logging
import uuid
from io import BytesIO
from typing import Optional, Awaitable
from sqlalchemy import text
from website import db_mysql
from website import errors
from website import consts
from website import settings
from website.handler import APIHandler, authenticated
from website.util import aes
@ -17,6 +19,7 @@ from website.util.captcha import create_validate_code
class CaptchaHandler(APIHandler):
def get(self):
self.set_header("Content-Type", "image/png")
image, image_str = create_validate_code()
@ -44,6 +47,23 @@ class LogoutHandler(APIHandler):
# self.current_user.name, self.request.remote_ip, "平台管理中心", "账号管理", "登出", "系统登出", "系统登出"
# )
with self.app_mysql.connect() as conn:
conn.execute(text(
"insert into sys_log(user, ip, primary_menu, sub_menu, op_type, content, comment) "
"values(:user, :ip, :primary_menu, :sub_menu, :op_type, :content, :comment)"
),
{"user": self.current_user.name,
"ip": self.request.headers[
"X-Forwarded-For"] if "X-Forwarded-For" in self.request.headers else self.request.remote_ip,
"primary_menu": "系统操作",
"sub_menu": "登录/登出",
"op_type": consts.op_type_login_logout_str,
"content": "退出登录",
"comment": ""
}
)
conn.commit()
self.r_app.delete(settings.session_key_prefix % self.current_user.uuid)
self.finish()
@ -162,6 +182,23 @@ class LoginHandler(APIHandler):
# "system_status": system_status, # 9000/未激活, 9001/已激活, 9002/过期可查看, 9003/完全过期
}
with self.app_mysql.connect() as conn:
conn.execute(text(
"insert into sys_log(user, ip, primary_menu, sub_menu, op_type, content, comment) "
"values(:user, :ip, :primary_menu, :sub_menu, :op_type, :content, :comment)"
),
{"user": username,
"ip": self.request.headers[
"X-Forwarded-For"] if "X-Forwarded-For" in self.request.headers else self.request.remote_ip,
"primary_menu": "系统操作",
"sub_menu": "登录/登出",
"op_type": consts.op_type_login_logout_str,
"content": "登录成功",
"comment": ""
}
)
conn.commit()
self.finish(render_data)

@ -78,8 +78,11 @@ enterprise_aes_key = "FquMBlcVoIkTAmL7"
file_upload_dir = "/data/fileupload"
rsa_public_file = "/home/app/public"
system_salt = "5bVQmI0ATh+QITf75WgVchT6TPN1DEOasSmrtMcTsPQ="
# rsa_public_file = "/home/app/public"
rsa_license_file = "/home/app/license"
rsa_private_file = "/home/app/private_key.pem"
# hashlib.sha256(base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes)).hexdigest()

@ -1,22 +1,60 @@
# -*- coding: utf-8 -*-
from M2Crypto import RSA
from M2Crypto import BIO
from binascii import a2b_hex, b2a_hex
from M2Crypto import BIO
from M2Crypto import RSA
def load_pub_key_string(string):
bio = BIO.MemoryBuffer(string)
return RSA.load_pub_key_bio(bio)
def block_data(texts, block_size):
for i in range(0, len(texts), block_size):
yield texts[i:i + block_size]
def decrypt(publick_key, texts):
def encrypt(texts):
ciphertext = b""
block_size = 256 - 11
for text in block_data(texts.encode('utf-8'), block_size):
current_text = pri_key.private_encrypt(text, RSA.pkcs1_padding)
ciphertext += current_text
return b2a_hex(ciphertext)
def decrypt(texts):
plaintext = b""
block_size = 256
for text in block_data(a2b_hex(texts), block_size):
current_text = publick_key.public_decrypt(text, RSA.pkcs1_padding)
current_text = pub_key.public_decrypt(text, RSA.pkcs1_padding)
plaintext += current_text
return plaintext
return plaintext
if __name__ == '__main__':
# 2048代表生成密钥的位数65537代表公钥的指数
key = RSA.gen_key(2048, 65537)
key.save_key("private_key", None)
key.save_pub_key("public_key")
prikey = open("private_key").read()
pubkey = open("public_key").read()
pri_key = RSA.load_key_string(prikey.strip('\n').encode('utf-8'))
pub_key = load_pub_key_string(pubkey.strip('\n').encode('utf-8'))
texts = "hellohellohellohellohellohellohellohellohellohellohellohellohello" \
"hellohellohellohellohellohellohellohellohellohellohellohellohello" \
"hellohellohellohellohellohellohellohellohellohellohellohellohello" \
"hellohellohellohellohellohellohellohellohellohellohello"
ciphertext = encrypt(texts)
print(ciphertext)
plaintext = decrypt(ciphertext)
print(plaintext)

@ -1,75 +0,0 @@
# -*- coding: utf-8 -*-
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import base64
"""
RSA 加密中,有两种常见的填充方式:PKCS1_v1_5 PKCS1_OAEP这两种填充方式在安全性和性能方面都有一些差异
PKCS1_v1_5 填充方式:
这是较早的 RSA 填充方式,相对简单且性能较好
但是它存在一些安全隐患,比如可能会受到选择密文攻击(Chosen Ciphertext Attack, CCA)
PKCS1_OAEP 填充方式:
PKCS1_OAEP 是一种更加安全的填充方式,它使用了随机填充来提高安全性
PKCS1_OAEP 可以抵御选择密文攻击(CCA)和其他一些攻击方式,因此被认为更加安全
但是,PKCS1_OAEP 的性能略低于 PKCS1_v1_5,因为它需要进行更多的计算
"""
# 生成密钥对
def generate_keys():
key = RSA.generate(2048)
private_key = key.export_key()
public_key = key.publickey().export_key()
return private_key, public_key
# 加密消息message为bytes类型
def encrypt_message(public_key, message):
cipher = PKCS1_OAEP.new(RSA.import_key(public_key))
encrypted_message = base64.b64encode(cipher.encrypt(message))
print("Encrypted message:", encrypted_message.decode())
return encrypted_message
# 解密消息
def decrypt_message(private_key, encrypted_message):
decipher = PKCS1_OAEP.new(RSA.import_key(private_key))
decrypted_message = decipher.decrypt(base64.b64decode(encrypted_message))
print("Decrypted message:", decrypted_message.decode())
return decrypted_message.decode()
# 主程序
if __name__ == "__main__":
# 生成密钥对
private_key, public_key = generate_keys()
print(private_key)
print(public_key)
# 序列化公钥和私钥
# private_pem = private_key.private_bytes(
# encoding=serialization.Encoding.PEM,
# format=serialization.PrivateFormat.PKCS8,
# encryption_algorithm=serialization.NoEncryption()
# )
# public_pem = public_key.public_bytes(
# encoding=serialization.Encoding.PEM,
# format=serialization.PublicFormat.SubjectPublicKeyInfo
# )
# 打印公钥和私钥
print("Private Key:")
print(private_key.decode())
print("Public Key:")
print(public_key.decode())
# 待加密消息
message = b"Hello, RSA!"
# 加密消息
encrypted_message = encrypt_message(public_key, message)
print("Encrypted Message:")
print(encrypted_message)
# 解密消息
decrypted_message = decrypt_message(private_key, encrypted_message)
print("Decrypted Message:")
print(decrypted_message)

@ -0,0 +1,124 @@
# -*- coding: utf-8 -*-
import argparse
import base64
import json
import sys
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
"""
RSA 加密中,有两种常见的填充方式:PKCS1_v1_5 PKCS1_OAEP这两种填充方式在安全性和性能方面都有一些差异
PKCS1_v1_5 填充方式:
这是较早的 RSA 填充方式,相对简单且性能较好
但是它存在一些安全隐患,比如可能会受到选择密文攻击(Chosen Ciphertext Attack, CCA)
PKCS1_OAEP 填充方式:
PKCS1_OAEP 是一种更加安全的填充方式,它使用了随机填充来提高安全性
PKCS1_OAEP 可以抵御选择密文攻击(CCA)和其他一些攻击方式,因此被认为更加安全
但是,PKCS1_OAEP 的性能略低于 PKCS1_v1_5,因为它需要进行更多的计算
"""
# 生成密钥对
def generate_keys():
key = RSA.generate(2048)
private_key = key.export_key()
public_key = key.publickey().export_key()
return private_key, public_key
# 公钥加密消息message为bytes类型
def encrypt_message_pub(public_key, message):
cipher = PKCS1_OAEP.new(RSA.import_key(public_key))
encrypted_message = base64.b64encode(cipher.encrypt(message))
# print("Encrypted message:", encrypted_message.decode())
return encrypted_message
# 私钥解密消息
def decrypt_message_pri(private_key, encrypted_message):
decipher = PKCS1_OAEP.new(RSA.import_key(private_key))
decrypted_message = decipher.decrypt(base64.b64decode(encrypted_message))
# print("Decrypted message:", decrypted_message.decode())
return decrypted_message.decode()
def test():
# 生成密钥对
private_key, public_key = generate_keys()
print(private_key)
print(public_key)
# 打印公钥和私钥
print("Private Key:")
print(private_key.decode())
print("Public Key:")
print(public_key.decode())
# 待加密消息
# message = b"Hello, RSA!"
message = "Hello, RSA!".encode()
# 加密消息
encrypted_message = encrypt_message_pub(public_key, message)
print("Encrypted Message:")
print(encrypted_message)
# 解密消息
decrypted_message = decrypt_message_pri(private_key, encrypted_message)
print("Decrypted Message:")
print(decrypted_message)
def save_keys():
private_key, public_key = generate_keys()
with open("private_key.pem", "wb") as f:
f.write(private_key)
with open("public_key.pem", "wb") as f:
f.write(public_key)
# 主程序
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='manual to sign enterprise license')
parser.add_argument("-o", type=str,
help="operation type, "
"'t' is for function test, "
"'s' is to sign and save license, "
"'g' is to generate keys and save them, "
"'d' is to decrypt license",
required=True) # name, t/test, s/sign, g/generate key, d/decrypt
parser.add_argument("-c", type=str, help="enterprise's sys code, its something code like MD5") # code
parser.add_argument("-e", type=str, help="expire date, eg: 2035-01-01") # expire
args = parser.parse_args()
operation = args.o
if operation == "t": # test
test()
elif operation == "g": # generate keys and save
save_keys()
elif operation == "s": # sign and save license
code = args.c
expire = args.e
if not code or not expire:
print("sys code and expire date are required")
sys.exit(1)
pub_key = open("public_key.pem", "r").read()
license = encrypt_message_pub(pub_key.strip('\n').encode('utf-8'),
json.dumps({"sys_code": code, "expire_at": expire}).encode("utf-8"))
with open("license", "wb") as f:
f.write(license)
elif operation == "d": # decrypt license
private_key = open("private_key.pem", "r").read()
with open("license", "rb") as f:
license = f.read()
# 解密消息
body = decrypt_message_pri(private_key.strip('\n').encode('utf-8'), license)
json_body = json.loads(body)
print(json_body)

@ -4,10 +4,10 @@ import os
import socket
import subprocess
import uuid
from website import settings
def get_cpu_id():
p = subprocess.Popen(["dmidecode -t 4 | grep ID"],
p = subprocess.Popen(["dmidecode -t 4 | grep ID | tail -1"],
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
data = p.stdout
lines = []
@ -23,6 +23,75 @@ def get_cpu_id():
return lines
def get_system_uuid():
p = subprocess.Popen(["dmidecode -s system-uuid"],
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
data = p.stdout
lines = []
while True:
line = str(data.readline(), encoding="utf-8")
if line == '\n':
break
if line:
lines.append(line)
else:
break
print("system uuid {}".format(lines))
return lines
def get_system_manufacture():
p = subprocess.Popen(["dmidecode -s processor-manufacturer | tail -1"],
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
data = p.stdout
lines = []
while True:
line = str(data.readline(), encoding="utf-8")
if line == '\n':
break
if line:
lines.append(line)
else:
break
return lines
def get_board_manufacturer():
p = subprocess.Popen(["dmidecode -s baseboard-manufacturer"],
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
data = p.stdout
lines = []
while True:
line = str(data.readline(), encoding="utf-8")
if line == '\n':
break
if line:
lines.append(line)
else:
break
return lines
def get_board_serial_number():
p = subprocess.Popen(["dmidecode -s baseboard-serial-number"],
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
data = p.stdout
lines = []
while True:
line = str(data.readline(), encoding="utf-8")
if line == '\n':
break
if line:
lines.append(line)
else:
break
return lines
def get_board_serialnumber():
p = subprocess.Popen(["dmidecode -t 2 | grep Serial"],
shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@ -40,6 +109,37 @@ def get_board_serialnumber():
return lines
def get_idntify_code_v2():
cpuid = get_cpu_id()
system_uuid = get_system_uuid()
system_manufacture = get_system_manufacture()
board_manufacturer = get_board_manufacturer()
board_serial_number = get_board_serial_number()
s = ""
if cpuid:
s += cpuid[0]["ID"]
print("cpuid: ", cpuid[0]["ID"])
if system_uuid:
print(system_uuid)
s += system_uuid[0].strip()
if system_manufacture:
print(system_manufacture)
s += system_manufacture[0].strip()
if board_manufacturer:
print(board_manufacturer)
s += board_manufacturer[0].strip()
if board_serial_number:
print(board_serial_number)
s += board_serial_number[0].strip()
s += settings.system_salt
# system_salt = "5bVQmI0ATh+QITf75WgVchT6TPN1DEOasSmrtMcTsPQ="
# s += system_salt
code = hashlib.sha256(s.encode("utf8")).hexdigest()
return code
def get_identify_code():
mac = uuid.UUID(int=uuid.getnode()).hex[-12:]
mac_addr = ":".join([mac[e:e + 2] for e in range(0, 11, 2)])
@ -65,14 +165,6 @@ def get_identify_code():
return code
def get_system_uuid():
# 获取系统uuid
# 这个 UUID 是与硬件相关的,因此即使在 Docker 容器中,它也应该是唯一的,可以用来标识宿主机,而不是容器本身。
with open("/sys/class/dmi/id/product_uuid", "r") as f:
host_uuid = f.read().strip()
return host_uuid
def get_docker_container_id():
# 获取当前 Docker 容器的 ID
cmd = "cat /proc/self/cgroup"
@ -84,3 +176,7 @@ def get_docker_container_id():
else:
container_id = container_message.strip().split("docker/")[-1]
return container_id
if __name__ == "__main__":
print(get_idntify_code_v2())
Loading…
Cancel
Save