From b6ce756a44ecfc614499ccd4dda58e4ddcd447bf Mon Sep 17 00:00:00 2001 From: shenshuo <191715030@qq.com> Date: Mon, 30 Dec 2024 20:30:41 +0800 Subject: [PATCH] =?UTF-8?q?2024=E5=B9=B412=E6=9C=8830=E6=97=A5=20=20=20?= =?UTF-8?q?=E6=95=B4=E7=90=86SQLAlchemy=E5=92=8Cpydantic=20=E5=A4=A7?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8D=87=E7=BA=A7=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 45 ------ db_sync.py | 16 +- get_user.py | 2 +- libs/feature_model_utils.py | 29 +--- libs/feature_pydantic_utils.py | 22 ++- libs/sync_notice_user.py | 146 ----------------- libs/sync_user_verift_v4.py | 2 +- mg/handlers/configs_init.py | 32 ---- mg/handlers/login_handler.py | 270 ------------------------------- mg/handlers/sys_mg_v4_handler.py | 2 +- models/notice_model.py | 108 ------------- models/notice_schemas.py | 69 -------- services/app_service.py | 2 - services/index_service.py | 4 +- 14 files changed, 26 insertions(+), 723 deletions(-) delete mode 100644 libs/sync_notice_user.py delete mode 100644 mg/handlers/configs_init.py delete mode 100644 mg/handlers/login_handler.py delete mode 100644 models/notice_model.py delete mode 100644 models/notice_schemas.py diff --git a/README.md b/README.md index 01845b5..9e7eb72 100644 --- a/README.md +++ b/README.md @@ -39,51 +39,6 @@ - 系统日志 (从API网关获取日志,当然也可以自行从基类获取) -### 结构 - -```shell -├── doc -│   ├── data.sql -│   ├── deployment.md -│   ├── nginx_ops.conf -│   ├── requirements.txt -│   └── supervisor_ops.conf -├── docker-compose.yml -├── Dockerfile -├── __init__.py -├── libs -│   ├── base_handler.py -│   ├── __init__.py -│   ├── my_verify.py -│   └── utils.py -├── mg -│   ├── applications.py -│   ├── handlers -│   │   ├── app_mg_handler.py -│   │   ├── app_settings_handler.py -│   │   ├── components_v4_handler.py -│   │   ├── configs_init.py -│   │   ├── functions_v4_handler.py -│   │   ├── __init__.py -│   │   ├── login_handler.py -│   │   ├── menus_v4_handler.py -│   │   ├── notifications_handler.py -│   │   ├── roles_handler.py -│   │   ├── users_v4_handler.py -│   │   └── verify_handler.py -│   ├── __init__.py -│   └── subscribe.py -├── models -│   ├── admin.py -│   ├── app_config.py -│   ├── __init__.py -├── README.md -├── settings.py -└── startup.py -``` - -### 展示 - ### 用户管理 > 这部分文档主要用来介绍用户管理,它可以很精细的管理你的用户权限 diff --git a/db_sync.py b/db_sync.py index 6ff0008..e87f2e8 100644 --- a/db_sync.py +++ b/db_sync.py @@ -8,6 +8,7 @@ """ from sqlalchemy import create_engine +from sqlalchemy.engine.url import URL from websdk2.consts import const from settings import settings as app_settings from models.paas_model import Base as AppsBase @@ -17,13 +18,16 @@ default_configs = app_settings[const.DB_CONFIG_ITEM][const.DEFAULT_DB_KEY] -engine = create_engine( - f'mysql+pymysql://{default_configs.get(const.DBUSER_KEY)}:' - f'{default_configs.get(const.DBPWD_KEY)}@{default_configs.get(const.DBHOST_KEY)}:' - f'{default_configs.get(const.DBPORT_KEY)}/{default_configs.get(const.DBNAME_KEY)}' - f'?charset=utf8mb4', - echo=True +url_object = URL.create( + drivername='mysql+pymysql', + username=default_configs.get(const.DBUSER_KEY), + password=default_configs.get(const.DBPWD_KEY), + host=default_configs.get(const.DBHOST_KEY), + port=int(default_configs.get(const.DBPORT_KEY)), + database=default_configs.get(const.DBNAME_KEY), + query={'charset': 'utf8mb4'} ) +engine = create_engine(url_object, echo=True) def create(): diff --git a/get_user.py b/get_user.py index 2b06382..4e16487 100644 --- a/get_user.py +++ b/get_user.py @@ -13,7 +13,7 @@ import requests from websdk2.db_context import DBContextV2 as DBContext -from websdk2.model_utils import insert_or_update +from libs.feature_model_utils import insert_or_update from models.authority import Users from settings import settings diff --git a/libs/feature_model_utils.py b/libs/feature_model_utils.py index fc2436f..8e32941 100644 --- a/libs/feature_model_utils.py +++ b/libs/feature_model_utils.py @@ -1,8 +1,9 @@ #!/usr/bin/env python # -*-coding:utf-8-*- """ -Author : shenshuo -Date : 2019年12月11日 +Contact : 191715030@qq.com +Author : shenshuo +Date : 2024/12/30 20:28 Desc : models类 """ @@ -35,30 +36,6 @@ def queryset_to_list(queryset, **kwargs) -> list: return [model_to_dict(q) for q in queryset] -def GetInsertOrUpdateObj(cls: Type, str_filter: str, **kw) -> classmethod: - """ - cls: Model 类名 - str_filter: filter的参数.eg:"name='name-14'" 必须设置唯一 支持 and or - **kw: 【属性、值】字典,用于构建新实例,或修改存在的记录 - session.add(GetInsertOrUpdateObj(TableTest, "name='name-114'", age=33114, height=123.14, name='name-114')) - """ - with DBContext('r') as session: - existing = session.query(cls).filter(text(str_filter)).first() - if not existing: - res = cls() - for k, v in kw.items(): - if hasattr(res, k): - setattr(res, k, v) - return res - else: - res = existing - for k, v in kw.items(): - if hasattr(res, k): - setattr(res, k, v) - - return res - - def insert_or_update(cls: Type[DeclarativeMeta], str_filter: str, **kw) -> Union[None, DeclarativeMeta]: """ cls: Model 类名 diff --git a/libs/feature_pydantic_utils.py b/libs/feature_pydantic_utils.py index e743a72..b18c291 100644 --- a/libs/feature_pydantic_utils.py +++ b/libs/feature_pydantic_utils.py @@ -1,11 +1,11 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- """ -Version : 0.0.8 +Version : 0.0.9 Contact : 191715030@qq.com Author : shenshuo -Date : 2021/1/26 20:28 -Desc : https://github.com/tiangolo/pydantic-sqlalchemy +Date : 2024/12/30 20:28 +Desc : https://github.com/tiangolo/pydantic-sqlalchemy """ #### @@ -13,10 +13,6 @@ from pydantic import BaseModel, create_model, ValidationError, ConfigDict -# from sqlalchemy.inspection import inspect -# from sqlalchemy.orm.properties import ColumnProperty - - # 删除的时候一般只有id class PydanticDel(BaseModel): id: int @@ -26,7 +22,7 @@ class PydanticDelList(BaseModel): id_list: list[int] -def sqlalchemy_to_pydantic(db_model: Type, *, exclude: Container[str] = []) -> Type[BaseModel]: +def sqlalchemy_to_pydantic(db_model: Type, *, exclude: Container[str] = ()) -> Type[BaseModel]: table = db_model.metadata.tables[db_model.__tablename__] fields = {} config = ConfigDict(from_attributes=True) @@ -41,9 +37,9 @@ def sqlalchemy_to_pydantic(db_model: Type, *, exclude: Container[str] = []) -> T elif hasattr(column.type, "python_type"): python_type = column.type.python_type assert python_type, f"Could not infer python_type for {column}" - default = None - if column.default is None and not column.nullable: - default = ... + + default = ... if column.default is None and not column.nullable else None + fields[name] = (python_type, default) - pydantic_model = create_model(db_model.__name__, __config__=config, **fields) - return pydantic_model + + return create_model(db_model.__name__, __config__=config, **fields) diff --git a/libs/sync_notice_user.py b/libs/sync_notice_user.py deleted file mode 100644 index 6409ee8..0000000 --- a/libs/sync_notice_user.py +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Version : 0.0.1 -Contact : 191715030@qq.com -Author : shenshuo -Date : 2021/1/14 15:46 -Desc : 解释一下吧 -""" - -import json -import datetime -from websdk2.cache_context import cache_conn -from models.authority import Users -from models.notice_model import NoticeTemplate, NoticeGroup -from websdk2.jwt_token import gen_md5 -from websdk2.consts import const -from websdk2.tools import RedisLock -from websdk2.db_context import DBContextV2 as DBContext -from websdk2.model_utils import model_to_dict - - -def deco(cls, release=False): - def _deco(func): - def __deco(*args, **kwargs): - if not cls.get_lock(cls, key_timeout=90, func_timeout=1): return False - try: - return func(*args, **kwargs) - finally: - ### 执行完就释放key,默认不释放 - if release: cls.release(cls) - - return __deco - - return _deco - - -def deco1(cls, release=False): - ### 180 - def _deco(func): - def __deco(*args, **kwargs): - if not cls.get_lock(cls, key_timeout=120, func_timeout=1): return False - try: - return func(*args, **kwargs) - finally: - ### 执行完就释放key,默认不释放 - if release: cls.release(cls) - - return __deco - - return _deco - - -class NoticeUserInfo: - def __init__(self, **kwargs): - pass - - @deco(RedisLock("async__user_info_redis_lock_key")) - def cache_user(self): - redis_conn = cache_conn() - # ins_log.read_log('info', f'async__user_info_to_redis, {datetime.datetime.now()}') - with DBContext('r') as session: - all_user = session.query(Users).filter(Users.status == '0').all() - try: - with redis_conn.pipeline(transaction=False) as p: - p.delete(const.USERS_INFO) - for msg in all_user: - data_dict = model_to_dict(msg) - if 'password' in data_dict: data_dict.pop('password') - if 'google_key' in data_dict: data_dict.pop('google_key') - # nickname = data_dict.get('nickname') - # nickname_key = f"{gen_md5(nickname)}__contact" - # p.hmset(nickname_key, {"tel": data_dict.get('tel'), "email": data_dict.get('email')}) - p.rpush(const.USERS_INFO, json.dumps(data_dict)) - p.execute() - except Exception as err: - pass - - def sync(self): - with DBContext('r') as session: - __info = session.query(NoticeTemplate.id, NoticeTemplate.user_list, NoticeTemplate.notice_group).all() - - all_info = [] - for i in __info: - tel_list = [] - email_list = [] - ddid_list = [] ### 钉钉ID - manager_list = [] ### 上级领导 - - notice_id = i[0] - notice_group_list = i[2] - notice_user = [] - - ### 处理通知组 - if notice_group_list and isinstance(notice_group_list, list): - group_info = session.query(NoticeGroup.user_list).filter(NoticeGroup.name.in_(notice_group_list)).all() - for group in group_info: - if group[0]: notice_user = notice_user + group[0] - - ### 处理通知用户 - user_list = i[1] - if user_list and isinstance(user_list, list): - notice_user = notice_user + user_list - - nickname_list = list(set(notice_user)) - with DBContext('r') as session: - notice_user_info = session.query(Users.tel, Users.email, Users.dd_id, Users.manager).filter( - Users.nickname.in_(nickname_list)).all() - - for u in notice_user_info: - if u[0]: tel_list.append(u[0]) - if u[1]: email_list.append(u[1]) - if u[2]: ddid_list.append(u[2]) - if u[3]: manager_list.append(u[3]) - - user_info = {'tel': tel_list, 'email': email_list, 'dd_id': ddid_list} - - ##处理用户上级的逻辑 - try: - manager_tel_list = [] - manager_email_list = [] - manager_ddid_list = [] ### 钉钉ID - - manager_list2 = [] - for m in manager_list: - manager_list2.extend(m.split(',')) - manager_list3 = [m2.split('(')[0] for m2 in manager_list2] - with DBContext('r') as session: - notice_manager_info = session.query(Users.tel, Users.email, Users.dd_id).filter( - Users.username.in_(manager_list3)).all() - for u in notice_manager_info: - if u[0]: manager_tel_list.append(u[0]) - if u[1]: manager_email_list.append(u[1]) - if u[2]: manager_ddid_list.append(u[2]) - manager_info = {'tel': manager_tel_list, 'email': manager_email_list, 'dd_id': manager_ddid_list} - except: - manager_info = {} - - all_info.append({"id": notice_id, "user_info": user_info, "manager_info": manager_info}) - with DBContext('w', None, True) as session: - session.bulk_update_mappings(NoticeTemplate, all_info) - - @deco1(RedisLock("async_notice_user_info_redis_lock_key")) - def index(self): - # ins_log.read_log('info', f'async_notice_user_info, {datetime.datetime.now()}') - self.sync() diff --git a/libs/sync_user_verift_v4.py b/libs/sync_user_verift_v4.py index df7795a..8a1ade5 100644 --- a/libs/sync_user_verift_v4.py +++ b/libs/sync_user_verift_v4.py @@ -19,7 +19,7 @@ from websdk2.consts import const from websdk2.db_context import DBContextV2 as DBContext from websdk2.jwt_token import gen_md5 -from websdk2.model_utils import insert_or_update +from libs.feature_model_utils import insert_or_update from websdk2.tools import RedisLock, now_timestamp, convert from libs.etcd import Etcd3Client diff --git a/mg/handlers/configs_init.py b/mg/handlers/configs_init.py deleted file mode 100644 index 52b073e..0000000 --- a/mg/handlers/configs_init.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Contact : 191715030@qq.com -Author : shenshuo -Date : 2018/12/11 -Desc : -""" - -from models.notice_model import AppSettings -from websdk2.model_utils import model_to_dict -from websdk2.db_context import DBContext -from websdk2.consts import const -from websdk2.cache_context import cache_conn - - -def configs_init(setting_key): - new_dict = {} - """返回所有数据""" - with DBContext('r') as session: - if setting_key == 'all': - conf_info = session.query(AppSettings).all() - else: - conf_info = session.query(AppSettings).filter(AppSettings.name.like(setting_key + '%')).all() - - for msg in conf_info: - data_dict = model_to_dict(msg) - new_dict[data_dict.get('name')] = data_dict.get('value') - if new_dict: - redis_conn = cache_conn() - redis_conn.hmset(const.APP_SETTINGS, new_dict) - return dict(code=0, msg='获取配置成功', data=new_dict) diff --git a/mg/handlers/login_handler.py b/mg/handlers/login_handler.py deleted file mode 100644 index 2d8649e..0000000 --- a/mg/handlers/login_handler.py +++ /dev/null @@ -1,270 +0,0 @@ -#!/usr/bin/env python -# -*-coding:utf-8-*- -""" -author : shenshuo -date : 2017年11月21日 -role : 用户登录 -""" - -import json -import base64 -from libs.base_handler import BaseHandler -from tornado.web import RequestHandler, HTTPError -from websdk2.jwt_token import AuthToken, gen_md5 -from websdk2.tools import is_mail -from websdk2.utils import mail_login -from websdk2.model_utils import queryset_to_list, model_to_dict -import pyotp -from websdk2.db_context import DBContextV2 as DBContext -from models.authority import Users, Components, RolesComponents, Menus, RoleMenus, UserRoles, Apps, RoleApps -from .configs_init import configs_init -from websdk2.consts import const -from websdk2.cache_context import cache_conn -from websdk2.tools import convert -from websdk2.ldap import LdapApi - -from concurrent.futures import ThreadPoolExecutor -from tornado.concurrent import run_on_executor -from tornado import gen - - -class LoginHandler(RequestHandler): - def check_xsrf_cookie(self): - pass - - _thread_pool = ThreadPoolExecutor(2) - - @run_on_executor(executor='_thread_pool') - def other_authentication(self, **kwargs): - from libs.login_by_other import OtherAuthV2 - return OtherAuthV2(**kwargs)() - - @run_on_executor(executor='_thread_pool') - def mail_authentication(self, username, password, user_info): - login_mail = self.redis_conn.hget(const.APP_SETTINGS, const.EMAILLOGIN_DOMAIN) - if isinstance(login_mail, bytes): login_mail = login_mail.decode('utf-8') - - if login_mail: - if is_mail(username, login_mail): - email = username - username = email.split("@")[0] - email_server = self.redis_conn.hget(const.APP_SETTINGS, const.EMAILLOGIN_SERVER).decode('utf-8') - if not email_server: return dict(code=-9, msg='请配置邮箱服务的SMTP服务地址') - mail_login_state = mail_login(email, password, email_server) - # print(mail_login_state) - if not mail_login_state: return dict(code=-2, msg='邮箱登陆认证失败') - if not user_info: return dict(code=-3, msg='邮箱认证通过,请根据邮箱完善用户信息', username=username, - email=email) - - return True - - @run_on_executor(executor='_thread_pool') - def LDAP_authentication(self, username, password): - config_info = self.redis_conn.hgetall(const.APP_SETTINGS) - config_info = convert(config_info) - ldap_ssl = True if config_info.get(const.LDAP_USE_SSL) == '1' else False - - obj = LdapApi(config_info.get(const.LDAP_SERVER_HOST), config_info.get(const.LDAP_ADMIN_DN), - config_info.get(const.LDAP_ADMIN_PASSWORD), - int(config_info.get(const.LDAP_SERVER_PORT, 389)), ldap_ssl) - - ldap_pass_info = obj.ldap_auth_v2(username, password, config_info.get(const.LDAP_SEARCH_BASE), - config_info.get(const.LDAP_SEARCH_FILTER)) - - if not ldap_pass_info[0]: return dict(code=-4, msg='账号密码错误') - - with DBContext('r') as session: - user_info = session.query(Users).filter(Users.username == username, Users.status != '10').first() - - if not user_info: return dict(code=-6, msg='LDAP认证通过,完善用户信息', username=ldap_pass_info[1], - email=ldap_pass_info[2]) - return user_info - - @staticmethod - def update_login_ip(user_id, login_ip_list): - try: - login_ip = login_ip_list.split(",")[0] - with DBContext('w', None, True) as session: - session.query(Users).filter(Users.user_id == user_id).update({Users.last_ip: login_ip}) - session.commit() - except Exception as err: - print(err) - - @gen.coroutine - def post(self, *args, **kwargs): - data = json.loads(self.request.body.decode("utf-8")) - username = data.get('username', None) - password = data.get('password', None) - dynamic = data.get('dynamic', None) - c_url = data.get('c_url', None) - - if not username or not password: return self.write(dict(code=-1, msg='账号密码不能为空')) - - password = base64.b64decode(password).decode("utf-8") - password = base64.b64decode(password).decode("utf-8") - - self.redis_conn = cache_conn() - - configs_init('all') - uc_conf = self.settings.get('uc_conf') - login_mail = self.redis_conn.hget(const.APP_SETTINGS, const.EMAILLOGIN_DOMAIN) - - with DBContext('r') as session: - - if is_mail(username) and login_mail: - user_info = session.query(Users).filter(Users.email == username, Users.status != '10').first() - else: - user_info = session.query(Users).filter(Users.username == username, Users.password == gen_md5(password), - Users.status != '10').first() - - ## 通过第三方SSO登录 - if uc_conf and not user_info: - login_dict = dict(username=username, password=password, uc_conf=uc_conf) - login_state = yield self.other_authentication(**login_dict) - if login_state is False: return self.write(dict(code=-14, msg='第三方登录失败')) - with DBContext('r') as session: - user_info = session.query(Users).filter(Users.username == username, Users.status != '10').first() - - - ###通过邮箱登录 - elif is_mail(username) and login_mail: - mail_login_data = yield self.mail_authentication(username, password, user_info) - if mail_login_data is not True: return self.write(mail_login_data) - - ### 通过LDAP登录 - elif not user_info: - """如果没有用户信息则使用LDAP""" - ldap_login = self.redis_conn.hget(const.APP_SETTINGS, const.LDAP_ENABLE) - if ldap_login not in ['1', b'1']: return self.write(dict(code=-4, msg='账号密码错误')) - ### 如果开启了LDAP认证 则进行LDAP认证 - ldap_login_data = yield self.LDAP_authentication(username, password) - if isinstance(ldap_login_data, dict): - return self.write(ldap_login_data) - else: - user_info = ldap_login_data - - if 'user_info' not in dir(): return self.write(dict(code=-4, msg='账号异常')) - if not user_info: return self.write(dict(code=-4, msg='账号异常')) - if user_info.status != '0': return self.write(dict(code=-4, msg='账号被禁用')) - - is_superuser = True if user_info.superuser == '0' else False - - ### 如果被标记为必须动态验证切没有输入动态密钥,则跳转到二维码添加密钥的地方 - if user_info.google_key: - ### 第一次不带MFA的认证 - if not dynamic: return self.write(dict(code=1, msg='跳转二次认证')) - ### 二次认证 - if pyotp.TOTP(user_info.google_key).now() != str(dynamic): return self.write(dict(code=-5, msg='MFA错误')) - - user_id = str(user_info.user_id) - - ### 生成token 并写入cookie - token_info = dict(user_id=user_id, username=user_info.username, nickname=user_info.nickname, - email=user_info.email, is_superuser=is_superuser) - - auth_token = AuthToken() - auth_key = auth_token.encode_auth_token_v2(**token_info) - if isinstance(auth_key, bytes): auth_key = auth_key.decode() - - self.set_secure_cookie("nickname", user_info.nickname) - self.set_secure_cookie("username", user_info.username) - self.set_secure_cookie("user_id", str(user_info.user_id)) - self.set_cookie('auth_key', auth_key, expires_days=1) - - ###更新登录IP 和登录时间 - self.update_login_ip(user_id, self.request.headers.get("X-Forwarded-For")) - real_login_dict = dict(code=0, auth_key=auth_key, username=user_info.username, nickname=user_info.nickname, - avatar=user_info.avatar, c_url=c_url, msg='登录成功') - - # if other_sso_data and isinstance(other_sso_data, dict): - # real_login_dict = {**other_sso_data, **real_login_dict} - # for k, v in other_sso_data.items(): - # self.set_cookie(k, v, expires_days=1) - - return self.write(real_login_dict) - - -class LogoutHandler(BaseHandler): - def get(self): - self.clear_all_cookies() - raise HTTPError(401, 'logout') - - def post(self): - self.clear_all_cookies() - raise HTTPError(401, 'logout') - - -class AuthorizationHandler(BaseHandler): - async def get(self, *args, **kwargs): - app_code = self.get_argument('app_code', default=None, strip=True) - - app_data, page_data, component_data = [], {'all': False}, {'all': False} - - with DBContext('r') as session: - - all_app = session.query(Apps).filter(Apps.status == '0').all() - - if self.request_is_superuser: - components_info = session.query(Components.component_name).filter(Components.status == '0').all() - page_data['all'] = True - for msg in components_info: component_data[msg[0]] = True - app_data = queryset_to_list(all_app) - - elif app_code and app_code != 'all': - this_menus = session.query(Menus.menu_name).outerjoin( - RoleMenus, Menus.menu_id == RoleMenus.menu_id).outerjoin( - UserRoles, RoleMenus.role_id == UserRoles.role_id).filter( - UserRoles.user_id == self.request_user_id, UserRoles.status == '0', Menus.app_code == app_code, - Menus.status == '0').all() - - this_components = session.query(Components.component_name).outerjoin( - RolesComponents, Components.comp_id == RolesComponents.comp_id).outerjoin( - UserRoles, RolesComponents.role_id == UserRoles.role_id).filter( - UserRoles.user_id == self.request_user_id, UserRoles.status == '0', - Components.app_code == app_code, Components.status == '0').all() - - for p in this_menus: page_data[p[0]] = True - for c in this_components: component_data[c[0]] = True - - else: - this_menus = session.query(Menus.menu_name).outerjoin( - RoleMenus, Menus.menu_id == RoleMenus.menu_id).outerjoin( - UserRoles, RoleMenus.role_id == UserRoles.role_id).filter( - UserRoles.user_id == self.request_user_id, UserRoles.status == '0', Menus.status == '0').all() - - this_components = session.query(Components.component_name).outerjoin( - RolesComponents, Components.comp_id == RolesComponents.comp_id).outerjoin( - UserRoles, RolesComponents.role_id == UserRoles.role_id).filter( - UserRoles.user_id == self.request_user_id, UserRoles.status == '0', - Components.status == '0').all() - - for p in this_menus: page_data[p[0]] = True - for c in this_components: component_data[c[0]] = True - - if not self.request_is_superuser: - this_app = session.query(Apps).outerjoin(RoleApps, Apps.app_id == RoleApps.app_id).outerjoin( - UserRoles, RoleApps.role_id == UserRoles.role_id).filter( - UserRoles.user_id == self.request_user_id, UserRoles.status == '0', Apps.status == '0').all() - - this_app_id_list = [i.app_id for i in this_app] - for a in all_app: - app_dict = model_to_dict(a) - if a.app_id not in this_app_id_list: - app_dict['power'] = 'no' - app_data.append(app_dict) - - ### - __user = session.query(Users.avatar).filter(Users.user_id == self.request_user_id).first() - data = dict(rules=dict(page=page_data, component=component_data), app=app_data, username=self.request_username, - nickname=self.request_nickname, avatar="") - return self.write(dict(data=data, code=0, msg='获取前端权限成功')) - - -login_urls = [ - (r"/accounts/login/", LoginHandler), - (r"/accounts/logout/", LogoutHandler), - (r"/accounts/authorization/", AuthorizationHandler), -] - -if __name__ == "__main__": - pass diff --git a/mg/handlers/sys_mg_v4_handler.py b/mg/handlers/sys_mg_v4_handler.py index 2a552d2..28b26de 100644 --- a/mg/handlers/sys_mg_v4_handler.py +++ b/mg/handlers/sys_mg_v4_handler.py @@ -23,7 +23,7 @@ from websdk2.db_context import DBContext from websdk2.jwt_token import gen_md5 from websdk2.ldap import LdapApi -from websdk2.model_utils import insert_or_update +from libs.feature_model_utils import insert_or_update from websdk2.tools import check_password from libs.base_handler import BaseHandler diff --git a/models/notice_model.py b/models/notice_model.py deleted file mode 100644 index d32a76a..0000000 --- a/models/notice_model.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Contact : 191715030@qq.com -Author : shenshuo -Date : 2018/12/7 -Desc : 系统配置项 -""" - -import json -import base64 -from sqlalchemy import Column, String, Integer, DateTime, Text, JSON -from sqlalchemy.ext.declarative import declarative_base -from datetime import datetime -from sqlalchemy import TypeDecorator - -Base = declarative_base() - - -class TimeBaseModel(object): - """模型基类,为模型补充创建时间与更新时间""" - create_time = Column(DateTime, nullable=False, default=datetime.now) # 记录的创建时间 - update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now) # 记录的更新时间 - - -class AppSettings(TimeBaseModel, Base): - __tablename__ = 'mg_app_settings' - id = Column(Integer, primary_key=True, autoincrement=True) - name = Column(String(50), unique=True, nullable=False) # key - value = Column(Text(), default="") # value - is_secret = Column(String(5), default="n") # 加密 - - -class JsonColumn(TypeDecorator): - impl = Text - - def process_bind_param(self, value, dialect): - if value is not None: - value = json.dumps(value) - return value - - def process_result_value(self, value, dialect): - if value is not None: - value = json.loads(value) - return value - - -class JsonSecret(TypeDecorator): - impl = Text - - def process_bind_param(self, value, dialect): - if value is not None: - value = json.dumps(value) - value = base64.b64encode(value.encode()) - return value - - def process_result_value(self, value, dialect): - if value is not None: - value = base64.b64decode(value) - value = json.loads(value) - return value - - -class NoticeTemplate(TimeBaseModel, Base): - ### 通知模板 - __tablename__ = 'mg_notice_template' - - id = Column(Integer, primary_key=True, autoincrement=True) - name = Column('name', String(50), unique=True, nullable=False) # 通知模板名称 - user_list = Column('user_list', JSON(), default="") # 通知用户 - notice_group = Column('notice_group', JSON(), default="") # 通知组 - user_info = Column('user_info', JsonColumn(), default="") # 用户信息,定时同步用户列表的内容 - manager_info = Column('manager_info', JsonColumn(), default="") # 通知用户的上级信息,用来通知升级 - - way = Column('way', String(30), index=True, default="sms") # 通知类型 - silence = Column('silence', Integer, index=True, default=1) # 静默事件 分钟单位 - notice_conf = Column('notice_conf', String(255), default="") # '钉钉/微信/短信/短信调用地址 和信息 - msg_template = Column('msg_template', Text(), default="") # 通知模板 - test_msg = Column('test_msg', JSON(), default="{}") # 测试数据 - status = Column('status', String(1), default='0') ###状态(0正常 1停用) - remark = Column('remark', String(128), default="") # 备注说明 - extra = Column('extra', JSON(), default="{}") # 额外字段 - - -class NoticeGroup(TimeBaseModel, Base): - ### 通知组 - __tablename__ = 'mg_notice_group' - - id = Column(Integer, primary_key=True, autoincrement=True) - name = Column('name', String(50), unique=True, nullable=False) # 通知模板名称 - user_list = Column('user_list', JSON(), default="") # 用户列表 - user_info = Column('user_info', JsonColumn(), default="") # 用户信息,定时同步用户列表的内容 - - remark = Column('remark', String(128), default="") # 备注说明 - - -class NoticeConfig(TimeBaseModel, Base): - ### 通知配置 - __tablename__ = 'mg_notice_config' - - id = Column(Integer, primary_key=True, autoincrement=True) - name = Column('name', String(20), unique=True, nullable=False) # 配置名称 - key = Column('key', String(20), unique=True, nullable=False) # 配置索引key - status = Column('status', String(5), default='0', index=True) - conf_map = Column('conf_map', JsonSecret(), default="") # 配置文件 - - remark = Column('remark', String(128), default="") # 备注说明 - diff --git a/models/notice_schemas.py b/models/notice_schemas.py deleted file mode 100644 index d21540f..0000000 --- a/models/notice_schemas.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Version : 0.0.1 -Contact : 191715030@qq.com -Author : shenshuo -Date : 2021/1/27 11:02 -Desc : 解释一下吧 -""" - -from sqlalchemy import or_ -from sqlalchemy.exc import IntegrityError -from websdk2.model_utils import sqlalchemy_to_pydantic, ValidationError -from .notice_model import NoticeConfig, NoticeTemplate -from websdk2.db_context import DBContextV2 as DBContext -from websdk2.sqlalchemy_pagination import paginate - -PydanticNoticeConfig = sqlalchemy_to_pydantic(NoticeConfig, exclude=['id']) -PydanticNoticeConfigUP = sqlalchemy_to_pydantic(NoticeConfig) - - -### 模板查询 -def get_notice_template(**params): - value = params.get('searchValue') if "searchValue" in params else params.get('value') - filter_map = params.pop('filter_map') if "filter_map" in params else {} - if 'resource_group' in filter_map: filter_map.pop('resource_group') ### 暂时不隔离 - if 'page_size' not in params: params['page_size'] = 300 ### 默认获取到全部数据 - with DBContext('r') as session: - if value: - page = paginate(session.query(NoticeTemplate).filter( - or_(NoticeTemplate.name.like(f'%{value}%'), NoticeTemplate.way.like(f'{value}%'), - NoticeTemplate.msg_template.like(f'{value}%'), NoticeTemplate.id == value, - NoticeTemplate.remark.like(f'%{value}%'))).filter_by(**filter_map), **params) - else: - page = paginate(session.query(NoticeTemplate).filter_by(**filter_map), **params) - - return page.total, page.items - - -### 添加 -def add_notice_config(data: dict): - try: - PydanticNoticeConfig(**data) - except ValidationError as e: - return dict(code=-1, msg=str(e)) - - try: - with DBContext('w', None, True) as db: - db.add(NoticeConfig(**data)) - except IntegrityError as e: - return dict(code=-2, msg='不要重复添加相同的配置') - - return dict(code=0, msg="配置创建成功") - - -### 修改 -def update_notice_config(data: dict): - try: - valid_data = PydanticNoticeConfigUP(**data) - except ValidationError as e: - return dict(code=-1, msg=str(e)) - - try: - with DBContext('w', None, True) as db: - db.query(NoticeConfig).filter(NoticeConfig.id == valid_data.id).update(data) - except Exception as err: - return dict(code=-2, msg='修改失败, {}'.format(str(err))) - - return dict(code=0, msg="修改成功") diff --git a/services/app_service.py b/services/app_service.py index b3d84d9..cadf81c 100644 --- a/services/app_service.py +++ b/services/app_service.py @@ -11,8 +11,6 @@ from sqlalchemy import or_ from websdk2.db_context import DBContextV2 as DBContext from websdk2.sqlalchemy_pagination import paginate - -# from websdk2.model_utils import CommonOptView, queryset_to_list from libs.feature_model_utils import CommonOptView, queryset_to_list, model_to_dict from models.authority import RoleApps from models.paas_model import AppsModel diff --git a/services/index_service.py b/services/index_service.py index 8048f3b..4894c5c 100644 --- a/services/index_service.py +++ b/services/index_service.py @@ -7,12 +7,10 @@ Desc : 首页卡片 """ -import json -from collections import defaultdict from sqlalchemy import or_ from websdk2.sqlalchemy_pagination import paginate from websdk2.db_context import DBContextV2 as DBContext -from websdk2.model_utils import queryset_to_list, CommonOptView +from libs.feature_model_utils import queryset_to_list, CommonOptView from libs.feature_pydantic_utils import sqlalchemy_to_pydantic, ValidationError, PydanticDel from models.paas_model import IndexStepModel, ServiceCategoriesModel, IndexServiceModel