修改数据库初始化逻辑,完善权限,废弃flaskenv

This commit is contained in:
不胜舟
2023-04-06 16:09:49 +08:00
parent 269cc154ab
commit bced84f92d
27 changed files with 995 additions and 675 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
import os
from flask import Flask
from applications.common.script import init_script
from applications.common.script import admin_cli
from applications.extensions import init_plugs
from applications.view import init_view
from applications.configs import config
@@ -24,7 +24,7 @@ def create_app(config_name=None):
init_view(app)
# 注册命令
init_script(app)
app.cli.add_command(admin_cli)
if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
logo()
+3 -118
View File
@@ -1,49 +1,8 @@
import copy
from collections import OrderedDict
from io import BytesIO
from flask import session, make_response, current_app
from flask_login import current_user
from flask import session, make_response
from applications.common.utils.gen_captcha import vieCode
from applications.schemas import PowerOutSchema
# 生成菜单树
def make_menu_tree():
role = current_user.role
powers = []
for i in role:
# 如果角色没有被启用就直接跳过
if i.enable == 0:
continue
# 变量角色用户的权限
for p in i.power:
# 如果权限关闭了就直接跳过
if p.enable == 0:
continue
# 一二级菜单
if int(p.type) in [0, 1] and p not in powers:
powers.append(p)
power_schema = PowerOutSchema(many=True) # 用已继承 ma.ModelSchema 类的自定制类生成序列化类
power_dict = power_schema.dump(powers) # 生成可序列化对象
power_dict.sort(key=lambda x: (x['parent_id'], x['id']), reverse=True)
menu_dict = OrderedDict()
for _dict in power_dict:
if _dict['id'] in menu_dict:
# 当前节点添加子节点
_dict['children'] = copy.deepcopy(menu_dict[_dict['id']])
_dict['children'].sort(key=lambda item: item['sort'])
# 删除子节点
del menu_dict[_dict['id']]
if _dict['parent_id'] not in menu_dict:
menu_dict[_dict['parent_id']] = [_dict]
else:
menu_dict[_dict['parent_id']].append(_dict)
return sorted(menu_dict.get(0), key=lambda item: item['sort'])
# 生成验证码
@@ -56,78 +15,4 @@ def get_captcha():
out.seek(0)
resp = make_response(out.read())
resp.content_type = 'image/png'
return resp, code
def get_render_config():
# 网站配置
config = dict(logo={
# 网站名称
"title": current_app.config.get("SYSTEM_NAME"),
# 网站图标
"image": "/static/admin/admin/images/logo.png"
# 菜单配置
}, menu={
# 菜单数据来源
"data": "/rights/menu",
"collaspe": False,
# 是否同时只打开一个菜单目录
"accordion": True,
"method": "GET",
# 是否开启多系统菜单模式
"control": False,
# 顶部菜单宽度 PX
"controlWidth": 500,
# 默认选中的菜单项
"select": "0",
# 是否开启异步菜单,false 时 data 属性设置为菜单数据,false 时为 json 文件或后端接口
"async": True
}, tab={
# 是否开启多选项卡
"enable": True,
# 切换选项卡时,是否刷新页面状态
"keepState": True,
# 是否开启 Tab 记忆
"session": True,
# 最大可打开的选项卡数量
"max": 30,
"index": {
# 标识 ID , 建议与菜单项中的 ID 一致
"id": "10",
# 页面地址
"href": "/admin/welcome",
# 标题
"title": "首页"
}
}, theme={
# 默认主题色,对应 colors 配置中的 ID 标识
"defaultColor": "2",
# 默认的菜单主题 dark-theme 黑 / light-theme 白
"defaultMenu": "dark-theme",
# 是否允许用户切换主题,false 时关闭自定义主题面板
"allowCustom": True
}, colors=[{
"id": "1",
"color": "#2d8cf0"
},
{
"id": "2",
"color": "#5FB878"
},
{
"id": "3",
"color": "#1E9FFF"
}, {
"id": "4",
"color": "#FFB800"
}, {
"id": "5",
"color": "darkgray"
}
], links=current_app.config.get("SYSTEM_PANEL_LINKS"), other={
# 主页动画时长
"keepLoad": 1200,
# 布局顶部主题
"autoHead": False
}, header=False)
return config
return resp, code
+2 -25
View File
@@ -1,26 +1,3 @@
import os
import click
from applications.common.script.initdb import init_db
from applications.common.script.newmodular.new import NewViewModular
def init_script(app):
@app.cli.command()
def init():
init_db()
@app.cli.command()
@click.option('--type', prompt="请输入类型", help='新增的类型')
@click.option('--name', prompt="请输入新增的名称", help='新增的名称')
def new(type,name):
if type == 'view':
if name.count('/') > 1:
print("目前只支持二级目录,多级目录需要蓝图嵌套,本命令暂不支持,请手动创建")
quit()
if type == "view" and os.path.exists(f"applications/view/{name}.py"):
print(f'已经存在视图模块{name}.py')
quit()
NewViewModular(name=name).new_view()
from flask.cli import AppGroup
admin_cli = AppGroup("admin")
+689
View File
@@ -0,0 +1,689 @@
import datetime
from . import admin_cli
from applications.extensions import db
from applications.models import User, Role, Dept, Power
now_time = datetime.datetime.now()
userdata = [
User(
id=1,
username='admin',
password_hash='pbkdf2:sha256:150000$raM7mDSr$58fe069c3eac01531fc8af85e6fc200655dd2588090530084d182e6ec9d52c85',
create_at=now_time,
enable=1,
realname='超级管理',
remark='要是不能把握时机,就要终身蹭蹬,一事无成!',
avatar='http://127.0.0.1:5000/_uploads/photos/1617291580000.jpg',
dept_id=1,
),
User(
id=2,
username='test',
password_hash='pbkdf2:sha256:150000$cRS8bYNh$adb57e64d929863cf159f924f74d0634f1fecc46dba749f1bfaca03da6d2e3ac',
create_at=now_time,
enable=1,
realname='测试',
remark='要是不能把握时机,就要终身蹭蹬,一事无成!',
avatar='http://127.0.0.1:5000/_uploads/photos/1617291580000.jpg',
dept_id=1,
),
User(
id='3',
username='wind',
password_hash='pbkdf2:sha256:150000$skME1obT$6a2c20cd29f89d7d2f21d9e373a7e3445f70ebce3ef1c3a555e42a7d17170b37',
create_at=now_time,
enable=1,
realname='',
remark='要是不能把握时机,就要终身蹭蹬,一事无成!',
avatar='http://127.0.0.1:5000/_uploads/photos/1617291580000.jpg',
dept_id=7,
),
]
roledata = [
Role(
id=1,
code='admin',
name='管理员',
enable=1,
details='管理员',
sort=1,
create_time=now_time,
),
Role(
id=2,
code='common',
name='普通用户',
enable=1,
details='只有查看,没有增删改权限',
sort=2,
create_time=now_time,
)
]
deptdata = [
Dept(
id=1,
parent_id=0,
dept_name='总公司',
sort=1,
leader='就眠仪式',
phone='12312345679',
email='123qq.com',
status=1,
remark='这是总公司',
create_at=now_time
),
Dept(
id=4,
parent_id=1,
dept_name='济南分公司',
sort=2,
leader='就眠仪式',
phone='12312345679',
email='123qq.com',
status=1,
remark='这是济南',
create_at=now_time
),
Dept(
id=5,
parent_id=1,
dept_name='唐山分公司',
sort=4,
leader='mkg',
phone='12312345679',
email='123qq.com',
status=1,
remark='这是唐山',
create_at=now_time
),
Dept(
id=7,
parent_id=4,
dept_name='济南分公司开发部',
sort=5,
leader='就眠仪式',
phone='12312345679',
email='123qq.com',
status=1,
remark='测试',
create_at=now_time
),
Dept(
id=8,
parent_id=5,
dept_name='唐山测试部',
sort=5,
leader='mkg',
phone='12312345679',
email='123qq.com',
status=1,
remark='测试部',
create_at=now_time
)
]
powerdata = [
Power(
id=1,
name='系统管理',
type='0',
code='',
url=None,
open_type=None,
parent_id='0',
icon='layui-icon layui-icon-set-fill',
sort=1,
create_time=now_time,
enable=1,
), Power(
id=3,
name='用户管理',
type='1',
code='admin:user:main',
url='/admin/user/',
open_type='_iframe',
parent_id='1',
icon='layui-icon layui-icon layui-icon layui-icon layui-icon-rate',
sort=1,
create_time=now_time,
enable=1,
), Power(
id=4,
name='权限管理',
type='1',
code='admin:power:main',
url='/admin/power/',
open_type='_iframe',
parent_id='1',
icon=None,
sort=2,
create_time=now_time,
enable=1,
), Power(
id=9,
name='角色管理',
type='1',
code='admin:role:main',
url='/admin/role',
open_type='_iframe',
parent_id='1',
icon='layui-icon layui-icon-username',
sort=2,
create_time=now_time,
enable=1,
), Power(
id=12,
name='系统监控',
type='1',
code='admin:monitor:main',
url='/admin/monitor',
open_type='_iframe',
parent_id='1',
icon='layui-icon layui-icon-vercode',
sort=5,
create_time=now_time,
enable=1,
), Power(
id=13,
name='日志管理',
type='1',
code='admin:log:main',
url='/admin/log',
open_type='_iframe',
parent_id='1',
icon='layui-icon layui-icon-read',
sort=4,
create_time=now_time,
enable=1,
), Power(
id=17,
name='文件管理',
type='0',
code='',
url='',
open_type='',
parent_id='0',
icon='layui-icon layui-icon-camera',
sort=2,
create_time=now_time,
enable=1,
), Power(
id=18,
name='图片上传',
type='1',
code='admin:file:main',
url='/admin/file',
open_type='_iframe',
parent_id='17',
icon='layui-icon layui-icon-camera',
sort=5,
create_time=now_time,
enable=1,
), Power(
id=21,
name='权限增加',
type='2',
code='admin:power:add',
url='',
open_type='',
parent_id='4',
icon='layui-icon layui-icon-add-circle',
sort=1,
create_time=now_time,
enable=1,
), Power(
id=22,
name='用户增加',
type='2',
code='admin:user:add',
url='',
open_type='',
parent_id='3',
icon='layui-icon layui-icon-add-circle',
sort=1,
create_time=now_time,
enable=1,
), Power(
id=23,
name='用户编辑',
type='2',
code='admin:user:edit',
url='',
open_type='',
parent_id='3',
icon='layui-icon layui-icon-rate',
sort=2,
create_time=now_time,
enable=1,
), Power(
id=24,
name='用户删除',
type='2',
code='admin:user:remove',
url='',
open_type='',
parent_id='3',
icon='',
sort=3,
create_time=now_time,
enable=1,
), Power(
id=25,
name='权限编辑',
type='2',
code='admin:power:edit',
url='',
open_type='',
parent_id='4',
icon='',
sort=2,
create_time=now_time,
enable=1,
), Power(
id=26,
name='用户删除',
type='2',
code='admin:power:remove',
url='',
open_type='',
parent_id='4',
icon='',
sort=3,
create_time=now_time,
enable=1,
), Power(
id=27,
name='用户增加',
type='2',
code='admin:role:add',
url='',
open_type='',
parent_id='9',
icon='',
sort=1,
create_time=now_time,
enable=1,
), Power(
id=28,
name='角色编辑',
type='2',
code='admin:role:edit',
url='',
open_type='',
parent_id='9',
icon='',
sort=2,
create_time=now_time,
enable=1,
), Power(
id=29,
name='角色删除',
type='2',
code='admin:role:remove',
url='',
open_type='',
parent_id='9',
icon='',
sort=3,
create_time=now_time,
enable=1,
), Power(
id=30,
name='角色授权',
type='2',
code='admin:role:power',
url='',
open_type='',
parent_id='9',
icon='',
sort=4,
create_time=now_time,
enable=1,
), Power(
id=31,
name='图片增加',
type='2',
code='admin:file:add',
url='',
open_type='',
parent_id='18',
icon='',
sort=1,
create_time=now_time,
enable=1,
), Power(
id=32,
name='图片删除',
type='2',
code='admin:file:delete',
url='',
open_type='',
parent_id='18',
icon='',
sort=2,
create_time=now_time,
enable=1,
), Power(
id=44,
name='数据字典',
type='1',
code='admin:dict:main',
url='/admin/dict',
open_type='_iframe',
parent_id='1',
icon='layui-icon layui-icon-console',
sort=6,
create_time=now_time,
enable=1,
), Power(
id=45,
name='字典增加',
type='2',
code='admin:dict:add',
url='',
open_type='',
parent_id='44',
icon='',
sort=1,
create_time=now_time,
enable=1,
), Power(
id=46,
name='字典修改',
type='2',
code='admin:dict:edit',
url='',
open_type='',
parent_id='44',
icon='',
sort=2,
create_time=now_time,
enable=1,
), Power(
id=47,
name='字典删除',
type='2',
code='admin:dict:remove',
url='',
open_type='',
parent_id='44',
icon='',
sort=3,
create_time=now_time,
enable=1,
), Power(
id=48,
name='部门管理',
type='1',
code='admin:dept:main',
url='/dept',
open_type='_iframe',
parent_id='1',
icon='layui-icon layui-icon-group',
sort=3,
create_time=now_time,
enable=1,
), Power(
id=49,
name='部门增加',
type='2',
code='admin:dept:add',
url='',
open_type='',
parent_id='48',
icon='',
sort=1,
create_time=now_time,
enable=1,
), Power(
id=50,
name='部门编辑',
type='2',
code='admin:dept:edit',
url='',
open_type='',
parent_id='48',
icon='',
sort=2,
create_time=now_time,
enable=1,
), Power(
id=51,
name='部门删除',
type='2',
code='admin:dept:remove',
url='',
open_type='',
parent_id='48',
icon='',
sort=3,
create_time=now_time,
enable=1,
), Power(
id=52,
name='定时任务',
type='0',
code='',
url='',
open_type='',
parent_id='0',
icon='layui-icon layui-icon-log',
sort=3,
create_time=now_time,
enable=1,
), Power(
id=53,
name='任务管理',
type='1',
code='admin:task:main',
url='/admin/task',
open_type='_iframe',
parent_id='52',
icon='layui-icon ',
sort=1,
create_time=now_time,
enable=1,
), Power(
id=54,
name='任务增加',
type='2',
code='admin:task:add',
url='',
open_type='',
parent_id='53',
icon='layui-icon ',
sort=1,
create_time=now_time,
enable=1,
), Power(
id=55,
name='任务修改',
type='2',
code='admin:task:edit',
url='',
open_type='',
parent_id='53',
icon='layui-icon ',
sort=2,
create_time=now_time,
enable=1,
), Power(
id=56,
name='任务删除',
type='2',
code='admin:task:remove',
url='',
open_type='',
parent_id='53',
icon='layui-icon ',
sort=23,
create_time=now_time,
enable=1,
), Power(
id=57,
name='邮件管理',
type='1',
code='admin:mail:main',
url='/admin/mail',
open_type='_iframe',
parent_id='1',
icon='layui-icon ',
sort=7,
create_time=now_time,
enable=1,
), Power(
id=58,
name='邮件发送',
type='2',
code='admin:mail:add',
url='',
open_type='',
parent_id='57',
icon='layui-icon layui-icon-ok-circle',
sort=1,
create_time=now_time,
enable=1,
), Power(
id=59,
name='邮件删除',
type='2',
code='admin:mail:remove',
url='',
open_type='',
parent_id='57',
icon='',
sort=2,
create_time=now_time,
enable=1,
), Power(
id=60,
name='拓展插件',
type='0',
code='',
url='',
open_type='',
parent_id='0',
icon='layui-icon layui-icon-senior',
sort=2,
create_time=now_time,
enable=1,
), Power(
id=61,
name='插件管理',
type='1',
code='admin:plugin:main',
url='/plugin',
open_type='_iframe',
parent_id='60',
icon='layui-icon layui-icon',
sort=2,
create_time=now_time,
enable=1,
), Power(
id=62,
name='启禁插件',
type='2',
code='admin:plugin:enable',
url='',
open_type='',
parent_id='61',
icon='layui-icon layui-icon',
sort=1,
create_time=now_time,
enable=1,
), Power(
id=63,
name='删除插件',
type='2',
code='admin:plugin:remove',
url='',
open_type='',
parent_id='61',
icon='layui-icon layui-icon',
sort=2,
create_time=now_time,
enable=1,
)
]
def add_user_role():
admin_role = Role.query.filter_by(id=1).first()
admin_user = User.query.filter_by(id=1).first()
admin_user.role.append(admin_role)
test_role = Role.query.filter_by(id=2).first()
test_user = User.query.filter_by(id=2).first()
test_user.role.append(test_role)
db.session.commit()
def add_role_power():
admin_powers = Power.query.filter(Power.id.in_([1, 3, 4, 9, 12, 13, 17, 18, 44, 48])).all()
admin_user = Role.query.filter_by(id=2).first()
for i in admin_powers:
admin_user.power.append(i)
db.session.commit()
@admin_cli.command("init")
def init_db():
db.session.add_all(userdata)
print("加载系统必须用户数据")
db.session.add_all(roledata)
print("加载系统必须角色数据")
db.session.add_all(deptdata)
print("加载系统必须部门数据")
db.session.add_all(powerdata)
print("加载系统必须权限数据")
db.session.commit()
print("基础数据存入")
add_user_role()
print("用户角色数据存入")
add_role_power()
print("角色权限数据存入")
print("数据初始化完成,请使用flask run命令运行")
-60
View File
@@ -1,60 +0,0 @@
from dotenv import dotenv_values
import sqlparse
import pymysql
config = dotenv_values('.flaskenv')
# MySql配置信息
HOST = config.get('MYSQL_HOST') or '127.0.0.1'
PORT = config.get('MYSQL_PORT') or 3306
DATABASE = config.get('MYSQL_DATABASE') or 'PearAdminFlask'
USERNAME = config.get('MYSQL_USERNAME') or 'root'
PASSWORD = config.get('MYSQL_PASSWORD') or '123456'
def is_exist_database():
db = pymysql.connect(host=HOST, port=int(PORT), user=USERNAME, password=PASSWORD, charset='utf8mb4')
cursor1 = db.cursor()
sql = "select * from information_schema.SCHEMATA WHERE SCHEMA_NAME = '%s' ; " % DATABASE
res = cursor1.execute(sql)
db.close()
return res
def init_database():
db = pymysql.connect(host=HOST, port=int(PORT), user=USERNAME, password=PASSWORD, charset='utf8mb4')
cursor1 = db.cursor()
sql = "CREATE DATABASE IF NOT EXISTS %s CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;" % DATABASE
res = cursor1.execute(sql)
db.close()
return res
def execute_fromfile(filename):
db = pymysql.connect(host=HOST, port=int(PORT), user=USERNAME, password=PASSWORD, database=DATABASE,
charset='utf8mb4')
fd = open(filename, 'r', encoding='utf-8')
cursor = db.cursor()
sqlfile = fd.read()
sqlfile = sqlparse.format(sqlfile, strip_comments=True).strip()
sqlcommamds = sqlfile.split(';')
for command in sqlcommamds:
try:
cursor.execute(command)
db.commit()
except Exception as msg:
db.rollback()
db.close()
def init_db():
if is_exist_database():
print('数据库已经存在,为防止误初始化,请手动删除 %s 数据库' % str(DATABASE))
return
if init_database():
print('数据库%s创建成功' % str(DATABASE))
execute_fromfile('pear.sql')
print('表创建成功')
print('欢迎使用pear-admin-flask,请使用 flask run 命令启动程序')
+18
View File
@@ -0,0 +1,18 @@
import click
from applications import admin_cli
from applications.common.script.newmodular.new import NewViewModular
@admin_cli.command()
@click.option('--type', prompt="请输入类型", help='新增的类型')
@click.option('--name', prompt="请输入新增的名称", help='新增的名称')
def new(type, name):
if type == 'view':
if name.count('/') > 1:
print("目前只支持二级目录,多级目录需要蓝图嵌套,本命令暂不支持,请手动创建")
quit()
if type == "view" and os.path.exists(f"applications/view/{name}.py"):
print(f'已经存在视图模块{name}.py')
quit()
NewViewModular(name=name).new_view()
+3 -3
View File
@@ -1,6 +1,6 @@
from functools import wraps
from flask import abort, request, jsonify, session
from flask_login import login_required
from flask import abort, request, jsonify, session, current_app
from flask_login import login_required, current_user
from applications.common.admin_log import admin_log
@@ -17,7 +17,7 @@ def authorize(power: str, log: bool = False):
@wraps(func)
def wrapper(*args, **kwargs):
# 定义管理员的id为1
if 1 in session.get('role')[0]:
if current_user.username == current_app.config.get("SUPERADMIN"):
return func(*args, **kwargs)
if not power in session.get('permissions'):
if log:
+26 -34
View File
@@ -5,22 +5,15 @@ from urllib.parse import quote_plus as urlquote
from apscheduler.executors.pool import ThreadPoolExecutor
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
# 强制读入 flaskenv 中的环境变量
with open(".flaskenv", "r", encoding='utf-8') as f:
for line in f.read().split("\n"):
pos = line.find("#")
if pos != -1:
line = line[:pos]
line = line.strip()
if line == "":
continue
_ = line.split("=")
key, value = _[0], '='.join(_[1:])
os.environ[key.strip()] = value.strip()
class BaseConfig:
DEBUG = True
HOST = '127.0.0.1'
PORT = 5000
SYSTEM_NAME = os.getenv('SYSTEM_NAME', 'Pear Admin')
SUPERADMIN = 'admin'
SYSTEM_NAME = 'Pear Admin'
# 主题面板的链接列表配置
SYSTEM_PANEL_LINKS = [
{
@@ -47,18 +40,18 @@ class BaseConfig:
# JSON配置
JSON_AS_ASCII = False
SECRET_KEY = os.getenv('SECRET_KEY', 'dev key')
SECRET_KEY = "pear-admin-flask"
# redis配置
REDIS_HOST = os.getenv('REDIS_HOST') or "127.0.0.1"
REDIS_PORT = int(os.getenv('REDIS_PORT') or 6379)
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
# mysql 配置
MYSQL_USERNAME = os.getenv('MYSQL_USERNAME') or "root"
MYSQL_PASSWORD = os.getenv('MYSQL_PASSWORD') or "123456"
MYSQL_HOST = os.getenv('MYSQL_HOST') or "127.0.0.1"
MYSQL_PORT = int(os.getenv('MYSQL_PORT') or 3306)
MYSQL_DATABASE = os.getenv('MYSQL_DATABASE') or "PearAdminFlask"
MYSQL_USERNAME = "root"
MYSQL_PASSWORD = "123456"
MYSQL_HOST = "127.0.0.1"
MYSQL_PORT = 3306
MYSQL_DATABASE = "PearAdminFlask1"
# mysql 数据库的配置信息
SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{MYSQL_USERNAME}:{urlquote(MYSQL_PASSWORD)}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}?charset=utf8mb4"
@@ -66,19 +59,19 @@ class BaseConfig:
# 默认日志等级
LOG_LEVEL = logging.WARN
#
MAIL_SERVER = os.getenv('MAIL_SERVER') or 'smtp.qq.com'
MAIL_SERVER = 'smtp.qq.com'
MAIL_USE_TLS = False
MAIL_USE_SSL = True
MAIL_PORT = 465
MAIL_USERNAME = os.getenv('MAIL_USERNAME') or '123@qq.com'
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD') or 'XXXXX' # 生成的授权码
# 默认发件人的邮箱,这里填写和MAIL_USERNAME一致即可
MAIL_DEFAULT_SENDER = ('pear admin', os.getenv('MAIL_USERNAME') or '123@qq.com')
MAIL_USERNAME = '123@qq.com'
MAIL_PASSWORD = 'XXXXX' # 生成的授权码
MAIL_DEFAULT_SENDER = MAIL_USERNAME
# 設置 APSCHEDULER 參數
SCHEDULER_API_ENABLED = os.getenv('SCHEDULER_API_ENABLED') or False
SCHEDULER_API_ENABLED = False
SCHEDULER_JOBSTORES: dict = {
'default': SQLAlchemyJobStore(url=f'mysql+pymysql://{MYSQL_USERNAME}:{MYSQL_PASSWORD}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}')
'default': SQLAlchemyJobStore(
url=f'mysql+pymysql://{MYSQL_USERNAME}:{MYSQL_PASSWORD}@{MYSQL_HOST}:{MYSQL_PORT}/{MYSQL_DATABASE}')
}
SCHEDULER_EXECUTORS: dict = {
'default': ThreadPoolExecutor(20)
@@ -87,11 +80,11 @@ class BaseConfig:
'coalesce': False,
'max_instances': 3
}
# 插件配置
PLUGIN_ENABLE_FOLDERS = os.getenv('PLUGIN_ENABLE_FOLDERS')
# 配置多个数据库连接的连接串写法示例
PLUGIN_ENABLE_FOLDERS = ["helloworld"]
# 配置多个数据库连接的连接串写法示例
# HOSTNAME: 指数据库的IP地址、USERNAME:指数据库登录的用户名、PASSWORD:指数据库登录密码、PORT:指数据库开放的端口、DATABASE:指需要连接的数据库名称
# MSSQL: f"mssql+pymssql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=cp936"
# MySQL: f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8"
@@ -109,8 +102,7 @@ class BaseConfig:
# 'testMsSQL': 'mssql+pymssql://test:123456@192.168.1.1:1433/test?charset=cp936',
# 'testOracle': 'oracle+cx_oracle://test:123456@192.168.1.1:1521/test',
# 'testSQLite': 'sqlite:///database.db
#}
# }
class TestingConfig(BaseConfig):
+2 -2
View File
@@ -7,7 +7,7 @@ from .init_error_views import init_error_views
from .init_mail import init_mail, mail as flask_mail
from .init_apscheduler import init_scheduler
from .init_upload import init_upload
from .init_dotenv import init_dotenv
from .init_migrate import init_migrate
def init_plugs(app: Flask) -> None:
@@ -18,4 +18,4 @@ def init_plugs(app: Flask) -> None:
init_mail(app)
init_scheduler(app)
init_upload(app)
init_dotenv()
init_migrate(app)
-14
View File
@@ -1,14 +0,0 @@
import os
from dotenv import load_dotenv
root_path = os.path.abspath(os.path.dirname(__file__)).split('applications')[0]
# dot_env_path = os.path.join(root_path, '.env')
flask_env_path = os.path.join(root_path, '.flaskenv')
# if os.path.exists(dot_env_path):
# load_dotenv(dot_env_path)
def init_dotenv():
if os.path.exists(flask_env_path):
load_dotenv(flask_env_path)
+11
View File
@@ -0,0 +1,11 @@
from flask import Flask
from applications.extensions.init_sqlalchemy import db
from flask_migrate import Migrate
from applications.models import *
migrate = Migrate()
def init_migrate(app: Flask):
migrate.init_app(app, db)
@@ -1,7 +1,11 @@
from flask import session
from flask import session, current_app
from flask_login import current_user
def init_template_directives(app):
@app.template_global()
def authorize(power):
return bool(power in session.get('permissions'))
if current_user.username != current_app.config.get("SUPERADMIN"):
return bool(power in session.get('permissions'))
else:
return True
+1 -1
View File
@@ -11,4 +11,4 @@ def init_view(app):
register_rights_view(app)
register_passport_views(app)
register_dept_views(app)
register_plugin_views(app)
# register_plugin_views(app)
+5 -5
View File
@@ -71,11 +71,11 @@ def login_post():
continue
user_power.append(p.code)
session['permissions'] = user_power
# 角色存入session
roles = []
for role in current_user.role.all():
roles.append(role.id)
session['role'] = [roles]
# # 角色存入session
# roles = []
# for role in current_user.role.all():
# roles.append(role.id)
# session['role'] = [roles]
return success_api(msg="登录成功")
login_log(request, uid=user.id, is_access=False)
+2 -4
View File
@@ -1,8 +1,6 @@
from flask import Blueprint, Flask
from flask import Flask
rights_bp = Blueprint('rights', __name__, url_prefix='/rights')
from . import routes
from .routes import rights_bp
def register_rights_view(app: Flask):
+134 -7
View File
@@ -1,20 +1,147 @@
# 渲染配置
from flask import jsonify
from flask_login import login_required
import copy
from collections import OrderedDict
from . import rights_bp
from ...common import admin
from flask import jsonify, current_app, Blueprint
from flask_login import login_required, current_user
from ...models import Power
from ...schemas import PowerOutSchema
rights_bp = Blueprint('rights', __name__, url_prefix='/rights')
@rights_bp.get('/configs')
@login_required
def configs():
return admin.get_render_config()
# 网站配置
config = dict(logo={
# 网站名称
"title": current_app.config.get("SYSTEM_NAME"),
# 网站图标
"image": "/static/admin/admin/images/logo.png"
# 菜单配置
}, menu={
# 菜单数据来源
"data": "/rights/menu",
"collaspe": False,
# 是否同时只打开一个菜单目录
"accordion": True,
"method": "GET",
# 是否开启多系统菜单模式
"control": False,
# 顶部菜单宽度 PX
"controlWidth": 500,
# 默认选中的菜单项
"select": "0",
# 是否开启异步菜单,false 时 data 属性设置为菜单数据,false 时为 json 文件或后端接口
"async": True
}, tab={
# 是否开启多选项卡
"enable": True,
# 切换选项卡时,是否刷新页面状态
"keepState": True,
# 是否开启 Tab 记忆
"session": True,
# 最大可打开的选项卡数量
"max": 30,
"index": {
# 标识 ID , 建议与菜单项中的 ID 一致
"id": "10",
# 页面地址
"href": "/admin/welcome",
# 标题
"title": "首页"
}
}, theme={
# 默认主题色,对应 colors 配置中的 ID 标识
"defaultColor": "2",
# 默认的菜单主题 dark-theme 黑 / light-theme 白
"defaultMenu": "dark-theme",
# 是否允许用户切换主题,false 时关闭自定义主题面板
"allowCustom": True
}, colors=[{
"id": "1",
"color": "#2d8cf0"
},
{
"id": "2",
"color": "#5FB878"
},
{
"id": "3",
"color": "#1E9FFF"
}, {
"id": "4",
"color": "#FFB800"
}, {
"id": "5",
"color": "darkgray"
}
], links=current_app.config.get("SYSTEM_PANEL_LINKS"), other={
# 主页动画时长
"keepLoad": 1200,
# 布局顶部主题
"autoHead": False
}, header=False)
return jsonify(config)
# 菜单
@rights_bp.get('/menu')
@login_required
def menu():
menu_tree = admin.make_menu_tree()
return jsonify(menu_tree)
if current_user.username != current_app.config.get("SUPERADMIN"):
role = current_user.role
powers = []
for i in role:
# 如果角色没有被启用就直接跳过
if i.enable == 0:
continue
# 变量角色用户的权限
for p in i.power:
# 如果权限关闭了就直接跳过
if p.enable == 0:
continue
# 一二级菜单
if int(p.type) in [0, 1] and p not in powers:
powers.append(p)
power_schema = PowerOutSchema(many=True) # 用已继承 ma.ModelSchema 类的自定制类生成序列化类
power_dict = power_schema.dump(powers) # 生成可序列化对象
power_dict.sort(key=lambda x: (x['parent_id'], x['id']), reverse=True)
menu_dict = OrderedDict()
for _dict in power_dict:
if _dict['id'] in menu_dict:
# 当前节点添加子节点
_dict['children'] = copy.deepcopy(menu_dict[_dict['id']])
_dict['children'].sort(key=lambda item: item['sort'])
# 删除子节点
del menu_dict[_dict['id']]
if _dict['parent_id'] not in menu_dict:
menu_dict[_dict['parent_id']] = [_dict]
else:
menu_dict[_dict['parent_id']].append(_dict)
return jsonify(sorted(menu_dict.get(0), key=lambda item: item['sort']))
else:
powers = Power.query.all()
power_schema = PowerOutSchema(many=True) # 用已继承 ma.ModelSchema 类的自定制类生成序列化类
power_dict = power_schema.dump(powers) # 生成可序列化对象
power_dict.sort(key=lambda x: (x['parent_id'], x['id']), reverse=True)
menu_dict = OrderedDict()
for _dict in power_dict:
if _dict['id'] in menu_dict:
# 当前节点添加子节点
_dict['children'] = copy.deepcopy(menu_dict[_dict['id']])
_dict['children'].sort(key=lambda item: item['sort'])
# 删除子节点
del menu_dict[_dict['id']]
if _dict['parent_id'] not in menu_dict:
menu_dict[_dict['parent_id']] = [_dict]
else:
menu_dict[_dict['parent_id']].append(_dict)
return jsonify(sorted(menu_dict.get(0), key=lambda item: item['sort']))