Initial YakPanel commit
This commit is contained in:
106
class/datalistModel/base.py
Normal file
106
class/datalistModel/base.py
Normal file
@@ -0,0 +1,106 @@
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# YakPanel
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel (https://www.yakpanel.com) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: cjxin <cjxin@yakpanel.com>
|
||||
# -------------------------------------------------------------------
|
||||
# 面板获取列表公共库
|
||||
# ------------------------------
|
||||
|
||||
import os,sys,time,json,db,re
|
||||
import public
|
||||
try:
|
||||
from YakPanel import session
|
||||
except:
|
||||
session = None
|
||||
|
||||
|
||||
class dataBase:
|
||||
|
||||
quota_conf = os.path.join(public.get_panel_path(), "config/quota_list.json")
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
"""
|
||||
@name 获取配额数据列表
|
||||
"""
|
||||
def get_quota_list(self):
|
||||
quota_dict = {}
|
||||
try:
|
||||
quota_dict = json.loads(public.readFile(self.quota_conf))
|
||||
except:
|
||||
pass
|
||||
return quota_dict
|
||||
|
||||
|
||||
"""
|
||||
@name 批量获取所有容量配额
|
||||
"""
|
||||
def get_all_quota(self,paths = []):
|
||||
n_paths = []
|
||||
confs = self.get_quota_list()
|
||||
|
||||
|
||||
for path in paths:
|
||||
if path in n_paths: continue
|
||||
if not path in confs: continue
|
||||
n_paths.append(path.strip())
|
||||
|
||||
res = public.get_size_total(n_paths)
|
||||
|
||||
n_data = {}
|
||||
for val in n_paths:
|
||||
n_data[val] = {"used":0,"size":0,"quota_push":{"size":0,"used":0},"quota_storage":{"size":0,"used":0}}
|
||||
if val in confs.keys():
|
||||
n_data[val] = confs[val]
|
||||
|
||||
n_data[val]['used'] = -1
|
||||
for key in res.keys():
|
||||
if key != val: continue
|
||||
|
||||
n_data[val]['used'] = res[val]
|
||||
n_data[val]['quota_storage']['used'] = res[val]
|
||||
n_data[val]['quota_push']['used'] = res[val]
|
||||
|
||||
# print(n_data)
|
||||
return n_data
|
||||
|
||||
|
||||
def _decrypt(self, data):
|
||||
import PluginLoader
|
||||
if not isinstance(data, str): return data
|
||||
if not data: return data
|
||||
for _pfx in ('YP-0x:', 'BT-0x:'):
|
||||
if data.startswith(_pfx):
|
||||
res = PluginLoader.db_decrypt(data[len(_pfx) :])['msg']
|
||||
return res
|
||||
return data
|
||||
|
||||
# 获取用户权限列表
|
||||
def get_user_power(self, get=None):
|
||||
user_Data = 'all'
|
||||
try:
|
||||
uid = session.get('uid')
|
||||
if uid != 1 and uid:
|
||||
plugin_path = '/www/server/panel/plugin/users'
|
||||
if os.path.exists(plugin_path):
|
||||
user_authority = os.path.join(plugin_path, 'authority')
|
||||
if os.path.exists(user_authority):
|
||||
if os.path.exists(os.path.join(user_authority, str(uid))):
|
||||
try:
|
||||
data = json.loads(self._decrypt(public.ReadFile(os.path.join(user_authority, str(uid)))))
|
||||
if data['role'] == 'administrator':
|
||||
user_Data = 'all'
|
||||
else:
|
||||
user_Data = json.loads(self._decrypt(public.ReadFile(os.path.join(user_authority, str(uid) + '.data'))))
|
||||
except:
|
||||
user_Data = {}
|
||||
else:
|
||||
user_Data = {}
|
||||
except:
|
||||
public.print_error()
|
||||
pass
|
||||
return user_Data
|
||||
322
class/datalistModel/dataModel.py
Normal file
322
class/datalistModel/dataModel.py
Normal file
@@ -0,0 +1,322 @@
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# YakPanel
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(https://www.yakpanel.com) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: cjxin <cjxin@yakpanel.com>
|
||||
# -------------------------------------------------------------------
|
||||
# 面板获取列表公共库
|
||||
# ------------------------------
|
||||
|
||||
import os,sys,time,json,db,re
|
||||
# from turtle import pu
|
||||
|
||||
import public
|
||||
panelPath = '/www/server/panel'
|
||||
os.chdir(panelPath)
|
||||
if not panelPath + "/class/" in sys.path:
|
||||
sys.path.insert(0, panelPath + "/class/")
|
||||
from datalistModel.base import dataBase
|
||||
class main(dataBase):
|
||||
|
||||
siteorder_path = None
|
||||
__panel_path = public.get_panel_path()
|
||||
__SORT_DATA = ['site_ssl', 'rname', 'php_version', 'backup_count', 'total_flow', '7_day_total_flow', 'one_day_total_flow',
|
||||
'one_hour_total_flow']
|
||||
|
||||
sort_file = None
|
||||
def __init__(self):
|
||||
self.limit_path = '{}/data/limit.pl'.format(self.__panel_path)
|
||||
self.siteorder_path = '{}/data/siteorder.pl'.format(self.__panel_path)
|
||||
self.sort_file = '{}/data/sort_list.json'.format(self.__panel_path)
|
||||
|
||||
|
||||
"""
|
||||
@name 获取表数据
|
||||
@param table 表名
|
||||
@param p 分页
|
||||
@param limit 条数
|
||||
@param search 搜索
|
||||
@param type 类型
|
||||
"""
|
||||
def get_data_list(self,get):
|
||||
if not hasattr(get,'table'):
|
||||
return public.returnMsg(False,'缺少参数table')
|
||||
get = self._get_args(get)
|
||||
try:
|
||||
s_list = self.func_models(get,'get_data_where')
|
||||
except:
|
||||
s_list = []
|
||||
|
||||
where_sql,params = self.get_where(get,s_list)
|
||||
table = get.table
|
||||
|
||||
data = self.get_page_data(get,where_sql,params)
|
||||
get.data_list = data['data']
|
||||
# 用户权限处理
|
||||
user_Data = self.get_user_power()
|
||||
if user_Data != 'all' and table in ['sites']:
|
||||
get.data_list = [i for i in get.data_list if str(i['id']) in user_Data.get(table, [])]
|
||||
# 用户权限处理结束
|
||||
|
||||
data['data'] = self.func_models(get,'get_data_list')
|
||||
data = self.get_sort_data(data)
|
||||
return data
|
||||
|
||||
|
||||
"""
|
||||
@name 清空排序字段
|
||||
"""
|
||||
def del_sorted(self,get):
|
||||
return self.func_models(get,'del_sorted')
|
||||
|
||||
"""
|
||||
@name 设置置顶
|
||||
"""
|
||||
def setSort(self,get):
|
||||
|
||||
return self.func_models(get,'setSort')
|
||||
|
||||
|
||||
"""
|
||||
@name 获取查询条件
|
||||
@param s_list 查询条件
|
||||
"""
|
||||
def get_where(self, get, s_list):
|
||||
|
||||
search = get.search.strip()
|
||||
where, param = self._get_search_where(get.table, search)
|
||||
|
||||
wheres = []
|
||||
params = list(param)
|
||||
if search:
|
||||
try:
|
||||
get.where = where
|
||||
get.params = params
|
||||
res = self.func_models(get, 'get_search_where')
|
||||
if not 'status' in res:
|
||||
where, params = res
|
||||
except:pass
|
||||
|
||||
if where:
|
||||
wheres = ['({})'.format(where)]
|
||||
|
||||
for val in s_list:
|
||||
if type(val) == str:
|
||||
wheres.append(val)
|
||||
else:
|
||||
wheres.append(val[0])
|
||||
if type(val[1]) == str:
|
||||
params.append(val[1])
|
||||
elif type(val[1]) == tuple:
|
||||
params += list(val[1])
|
||||
else:
|
||||
params += val[1]
|
||||
|
||||
where_sql = ' AND '.join(wheres)
|
||||
return where_sql, params
|
||||
|
||||
|
||||
|
||||
def get_page_data(self,get,where_sql,params,result='1,2,3,4,5,8'):
|
||||
|
||||
# 包含分页类
|
||||
import page
|
||||
# 实例化分页类
|
||||
page = page.Page()
|
||||
|
||||
db_obj = public.M(get.table)
|
||||
|
||||
if type(params) == list:
|
||||
params = tuple(params)
|
||||
info = {}
|
||||
info['p'] = get.p
|
||||
info['row'] = get.limit
|
||||
info['count'] = public.M(get.table).where(where_sql, params).count()
|
||||
|
||||
try:
|
||||
from flask import request
|
||||
info['uri'] = public.url_encode(request.full_path)
|
||||
except:
|
||||
info['uri'] = ''
|
||||
info['return_js'] = ''
|
||||
if hasattr(get, 'tojs'):
|
||||
if re.match(r"^[\w\.\-]+$", get.tojs):
|
||||
info['return_js'] = get.tojs
|
||||
|
||||
data = {}
|
||||
data['where'] = where_sql
|
||||
data['page'] = page.GetPage(info, result)
|
||||
|
||||
o_list = get.order.split(' ')
|
||||
if o_list[0] in self.__SORT_DATA:
|
||||
data['data'] = db_obj.table(get.table).where(where_sql, params).select()
|
||||
data['plist'] = {'shift': page.SHIFT, 'row': page.ROW, 'order': get.order}
|
||||
else:
|
||||
|
||||
if len(o_list) > 1:
|
||||
if not self.check_field_exists(db_obj,get.table, o_list[0]):
|
||||
o_list[0] = 'id'
|
||||
if not o_list[1] in ['asc', 'desc']:
|
||||
o_list[1] = 'desc'
|
||||
|
||||
get.order = ' '.join(o_list)
|
||||
data['data'] = db_obj.table(get.table).where(where_sql, params).order(get.order).limit(str(page.SHIFT) + ',' + str(page.ROW)).select()
|
||||
|
||||
try:
|
||||
if db_obj.ERR_INFO:
|
||||
data['error'] = db_obj.ERR_INFO
|
||||
except:pass
|
||||
|
||||
data['search_history'] = []
|
||||
if 'search_key' in get and get['search_key']:
|
||||
data['search_history'] = public.get_search_history(get.table, get['search_key'])
|
||||
return data
|
||||
|
||||
|
||||
def check_field_exists(self,db_obj,table_name, field_name ):
|
||||
"""
|
||||
@name 检查字段是否存在
|
||||
"""
|
||||
try:
|
||||
res = db_obj.query("PRAGMA table_info({})".format(table_name))
|
||||
for val in res:
|
||||
if field_name == val[1]:
|
||||
return True
|
||||
except:pass
|
||||
return False
|
||||
|
||||
def get_sort_data(self, data):
|
||||
"""
|
||||
@获取自定义排序数据
|
||||
@param data: 数据
|
||||
"""
|
||||
if 'plist' in data:
|
||||
plist = data['plist']
|
||||
o_list = plist['order'].split(' ')
|
||||
|
||||
reverse = False
|
||||
sort_key = o_list[0].strip()
|
||||
|
||||
if o_list[1].strip() == 'desc':
|
||||
reverse = True
|
||||
|
||||
if sort_key in ['site_ssl']:
|
||||
for info in data['data']:
|
||||
if type(info['ssl']) == int:
|
||||
info[sort_key] = info['ssl']
|
||||
else:
|
||||
try:
|
||||
info[sort_key] = info['ssl']['endtime']
|
||||
except:
|
||||
info[sort_key] = ''
|
||||
elif sort_key in ['total_flow', 'one_hour_total_flow', '7_day_total_flow', 'one_day_total_flow']:
|
||||
for info in data['data']:
|
||||
info[sort_key] = 0
|
||||
try:
|
||||
if 'net' in info and sort_key in info['net']:
|
||||
info[sort_key] = info['net'][sort_key]
|
||||
except:
|
||||
pass
|
||||
|
||||
sort_reverse = 1 if reverse is True else 0
|
||||
data['data'].sort(key=lambda x: (x.get('sort', 0) == sort_reverse, x[sort_key]), reverse=reverse)
|
||||
data['data'] = data['data'][plist['shift']: plist['shift'] + plist['row']]
|
||||
|
||||
return data
|
||||
|
||||
"""
|
||||
@name 设置备注
|
||||
"""
|
||||
def _setPs(self,table,id,ps):
|
||||
if public.M(table).where('id=?',(id,)).setField('ps',public.xssencode2(ps)):
|
||||
return public.returnMsg(True, 'Successfully modified')
|
||||
return public.returnMsg(False, 'Failed to modify')
|
||||
|
||||
|
||||
def _get_search_where(self,table,search):
|
||||
|
||||
where = ''
|
||||
params = ()
|
||||
|
||||
if search:
|
||||
try:
|
||||
search = re.search(r"[\w\x80-\xff\.\_\-]+", search).group()
|
||||
except:
|
||||
return where, params
|
||||
conditions = ''
|
||||
if '_' in search:
|
||||
search = str(search).replace("_", "/_")
|
||||
conditions = " escape '/'"
|
||||
wheres = {
|
||||
'sites': ("name LIKE ?{} OR ps LIKE ?{}".format(conditions, conditions), ('%' + search + '%', '%' + search + '%')),
|
||||
'ftps': ("name LIKE ?{} OR ps LIKE ?{}".format(conditions, conditions), ('%' + search + '%', '%' + search + '%')),
|
||||
'databases': ("(name LIKE ?{} OR ps LIKE ?{})".format(conditions, conditions), ("%" + search + "%", "%" + search + "%")),
|
||||
'crontab': ("name LIKE ?{}".format(conditions), ('%' + (search) + '%')),
|
||||
'logs': ("username=?{} OR type LIKE ?{} OR log{} LIKE ?{}".format(conditions, conditions, conditions, conditions), (search, '%' + search + '%', '%' + search + '%')),
|
||||
'backup': ("pid=?", (search,)),
|
||||
'users': ("id='?' OR username=?{}".format(conditions), (search, search)),
|
||||
'domain': ("pid=? OR name LIKE ?{}".format(conditions), (search, '%' + search + '%')),
|
||||
'tasks': ("status=? OR type=?", (search, search)),
|
||||
}
|
||||
|
||||
try:
|
||||
return wheres[table]
|
||||
except:
|
||||
return '', ()
|
||||
|
||||
"""
|
||||
@name 格式化公用参数
|
||||
"""
|
||||
def _get_args(self,get):
|
||||
try:
|
||||
if not 'p' in get:
|
||||
get.p = 1
|
||||
get.p = int(get.p)
|
||||
except: get.p = 1
|
||||
|
||||
try:
|
||||
if not 'limit' in get:
|
||||
get.limit = 20
|
||||
get.limit = int(get.limit)
|
||||
except: get.limit = 20
|
||||
|
||||
if not 'search' in get:
|
||||
get.search = ''
|
||||
|
||||
if '_' in get.search:
|
||||
get.search = get.search.replace("_", "/_")
|
||||
|
||||
if not 'order' in get or not get['order']:
|
||||
get.order = 'id desc'
|
||||
return get
|
||||
|
||||
|
||||
def get_objectModel(self):
|
||||
'''
|
||||
获取模型对象
|
||||
'''
|
||||
from panelController import Controller
|
||||
project_obj = Controller()
|
||||
|
||||
return project_obj
|
||||
|
||||
|
||||
def func_models(self,get,def_name):
|
||||
'''
|
||||
获取模型对象
|
||||
'''
|
||||
|
||||
sfile = '{}/class/datalistModel/{}Model.py'.format(self.__panel_path,get.table)
|
||||
if not os.path.exists(sfile):
|
||||
raise Exception('模块文件{}不存在'.format(sfile))
|
||||
obj_main = self.get_objectModel()
|
||||
|
||||
args = public.dict_obj()
|
||||
args['data'] = get
|
||||
args['mod_name'] = get.table
|
||||
args['def_name'] = def_name
|
||||
|
||||
return obj_main.model(args)
|
||||
|
||||
166
class/datalistModel/databasesModel.py
Normal file
166
class/datalistModel/databasesModel.py
Normal file
@@ -0,0 +1,166 @@
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# YakPanel
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(https://www.yakpanel.com) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: cjxin <cjxin@yakpanel.com>
|
||||
# -------------------------------------------------------------------
|
||||
#
|
||||
# ------------------------------
|
||||
|
||||
import os, sys, time, json, re
|
||||
|
||||
if '/www/server/panel/class/' not in sys.path:
|
||||
sys.path.insert(0, '/www/server/panel/class/')
|
||||
import public, db
|
||||
import panelSite
|
||||
from datalistModel.base import dataBase
|
||||
|
||||
|
||||
class main(dataBase):
|
||||
web_server = None
|
||||
site_obj = None
|
||||
|
||||
def __init__(self):
|
||||
self.site_obj = panelSite.panelSite()
|
||||
|
||||
"""
|
||||
@name 获取公共数据后,格式化为网站列表需要的数据
|
||||
"""
|
||||
|
||||
def get_data_list(self, get):
|
||||
try:
|
||||
get = self._get_site_args(get)
|
||||
data_list = get.data_list
|
||||
|
||||
# 获取前端需要的表头
|
||||
from config_v2 import config
|
||||
table_header = config().get_table_header(public.to_dict_obj({'table_name': 'mysqlTableColumn'}))
|
||||
if not table_header:
|
||||
if table_header['mysqlTableColumn'] == '': table_header['mysqlTableColumn'] = '{}'
|
||||
table_header["mysqlTableColumn"] = json.loads(table_header["mysqlTableColumn"])
|
||||
table_header = [i['title'] if 'title' in i else i['label'] for i in table_header["mysqlTableColumn"] if
|
||||
(i.get('value', False) == True or i.get('isCustom', True) == True) and ('label' in i.keys() or 'title' in i.keys())]
|
||||
else:
|
||||
table_header = ["容量", "备份"]
|
||||
default_quota = {
|
||||
"used": 0,
|
||||
"size": 0,
|
||||
"quota_push": {
|
||||
"size": 0,
|
||||
"used": 0,
|
||||
},
|
||||
"quota_storage": {
|
||||
"size": 0,
|
||||
"used": 0,
|
||||
}}
|
||||
# 按需加载
|
||||
custom_list = {"容量": "quota", "备份": "backup_count"}
|
||||
custom_conf = {'quota': {}, 'backup_count': {}}
|
||||
names = []
|
||||
ids = []
|
||||
|
||||
# 用户权限处理
|
||||
user_Data = self.get_user_power()
|
||||
if user_Data != 'all':
|
||||
data_list = [i for i in data_list if str(i['id']) in user_Data.get('databases', [])]
|
||||
# 用户权限处理结束
|
||||
|
||||
[ids.append(str(val['id'])) or names.append(val['name']) for val in data_list]
|
||||
for i, j in custom_list.items():
|
||||
if i in table_header:
|
||||
if j == 'quota':
|
||||
custom_conf[j] = self.get_database_quota(names)
|
||||
if j == 'backup_count':
|
||||
custom_conf[j] = self.get_database_backup_count(ids)
|
||||
|
||||
for i in data_list:
|
||||
i['conn_config'] = json.loads(i['conn_config'])
|
||||
i['quota'] = custom_conf['quota'].get(i['name'], default_quota)
|
||||
i['backup_count'] = custom_conf['backup_count'].get(i['id'], 0)
|
||||
return data_list
|
||||
except:
|
||||
public.print_error()
|
||||
pass
|
||||
|
||||
"""
|
||||
@name 初始化参数
|
||||
"""
|
||||
|
||||
def _get_site_args(self, get):
|
||||
|
||||
|
||||
|
||||
get.search_key=get.table
|
||||
if hasattr(get, 'search'):
|
||||
get.search_key=get.table
|
||||
public.set_search_history(get.table,get.search_key,get.search)
|
||||
|
||||
return get
|
||||
|
||||
"""
|
||||
@name 追加 or条件
|
||||
"""
|
||||
|
||||
def get_search_where(self, get):
|
||||
|
||||
return get.where, get.params
|
||||
|
||||
"""
|
||||
@获取网站查询条件,追加and查询条件
|
||||
"""
|
||||
|
||||
def get_data_where(self, get):
|
||||
get = self._get_site_args(get)
|
||||
wheres = ["LOWER(type) = LOWER('MySQL')"]
|
||||
if "sid" in get:
|
||||
sid = get.get("sid")
|
||||
wheres.append("sid = {}".format(sid))
|
||||
if "type_id" in get:
|
||||
type_id = get.get("type_id")
|
||||
wheres.append("type_id = {}".format(type_id))
|
||||
return wheres
|
||||
|
||||
def get_database_quota(self, names):
|
||||
'''
|
||||
@name 获取网站目录配额信息
|
||||
@author hwliang<2022-02-15>
|
||||
@param path<string> 网站目录
|
||||
@return dict
|
||||
'''
|
||||
res = {
|
||||
"used": 0,
|
||||
"size": 0,
|
||||
"quota_push": {
|
||||
"size": 0,
|
||||
"used": 0,
|
||||
},
|
||||
"quota_storage": {
|
||||
"size": 0,
|
||||
"used": 0,
|
||||
}
|
||||
}
|
||||
resutl = {}
|
||||
for name in names:
|
||||
content = res
|
||||
try:
|
||||
import PluginLoader
|
||||
quota_info = PluginLoader.module_run('quota', 'get_quota_mysql', name)
|
||||
if isinstance(quota_info, dict):
|
||||
quota_info["size"] = quota_info["quota_storage"]["size"]
|
||||
content = quota_info
|
||||
except:
|
||||
pass
|
||||
resutl[name] = content
|
||||
return resutl
|
||||
|
||||
def get_database_backup_count(self, ids):
|
||||
'''
|
||||
@name 获取网站目录备份数量信息
|
||||
'''
|
||||
try:
|
||||
res = public.M('backup').query("SELECT pid,COUNT(*) as count FROM backup WHERE pid in ({}) AND type='1' GROUP BY pid".format(','.join(ids)))
|
||||
return {i[0]: i[1] for i in res}
|
||||
except:
|
||||
return {}
|
||||
39
class/datalistModel/domainModel.py
Normal file
39
class/datalistModel/domainModel.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# YakPanel
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(https://www.yakpanel.com) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: cjxin <cjxin@yakpanel.com>
|
||||
# -------------------------------------------------------------------
|
||||
#
|
||||
# ------------------------------
|
||||
|
||||
import os, sys, time, json, re
|
||||
import traceback
|
||||
|
||||
if '/www/server/panel/class/' not in sys.path:
|
||||
sys.path.insert(0, '/www/server/panel/class/')
|
||||
import public, db
|
||||
from datalistModel.base import dataBase
|
||||
|
||||
|
||||
class main(dataBase):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
"""
|
||||
@name 获取公共数据后,格式化为网站列表需要的数据
|
||||
"""
|
||||
def get_data_list(self, get):
|
||||
return get.data_list
|
||||
|
||||
"""
|
||||
@追加and查询条件
|
||||
"""
|
||||
def get_data_where(self,get):
|
||||
wheres = []
|
||||
if 'pid' in get:
|
||||
wheres.append(("(pid = ?)", (get.pid)))
|
||||
return wheres
|
||||
146
class/datalistModel/ftpsModel.py
Normal file
146
class/datalistModel/ftpsModel.py
Normal file
@@ -0,0 +1,146 @@
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# YakPanel
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(https://www.yakpanel.com) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: cjxin <cjxin@yakpanel.com>
|
||||
# -------------------------------------------------------------------
|
||||
#
|
||||
# ------------------------------
|
||||
|
||||
import os, sys, time, json, re
|
||||
import traceback
|
||||
|
||||
if '/www/server/panel/class/' not in sys.path:
|
||||
sys.path.insert(0, '/www/server/panel/class/')
|
||||
import public, db
|
||||
import panelSite
|
||||
from datalistModel.base import dataBase
|
||||
|
||||
|
||||
class main(dataBase):
|
||||
web_server = None
|
||||
site_obj = None
|
||||
|
||||
def __init__(self):
|
||||
self.site_obj = panelSite.panelSite()
|
||||
|
||||
"""
|
||||
@name 获取公共数据后,格式化为网站列表需要的数据
|
||||
"""
|
||||
|
||||
def get_data_list(self, get):
|
||||
try:
|
||||
get = self._get_site_args(get)
|
||||
data_list = get.data_list
|
||||
# 获取前端需要的表头
|
||||
from config import config
|
||||
table_header = config().get_table_header(public.to_dict_obj({'table_name': 'ftpTableColumn'}))
|
||||
if table_header['ftpTableColumn'] == '':
|
||||
table_header = ['用户名', '密码', '状态', '复制快速连接信息', '根目录', '设置密码有效期', '容量', '备注', '操作']
|
||||
else:
|
||||
table_header["ftpTableColumn"] = json.loads(table_header["ftpTableColumn"])
|
||||
table_header = [i['title'] if 'title' in i else i['label'] for i in table_header["ftpTableColumn"] if
|
||||
(i.get('value', False) == True or i.get('isCustom', True) == True) and ('label' in i.keys() or 'title' in i.keys())]
|
||||
# 按需加载
|
||||
custom_list = {"容量": "quota", '设置密码有效期': 'end_time'}
|
||||
custom_conf = {'quota': {}, "end_time": {}}
|
||||
paths = []
|
||||
ids = []
|
||||
default_quota = {
|
||||
"used": 0,
|
||||
"size": 0,
|
||||
"quota_push": {
|
||||
"size": 0,
|
||||
"used": 0,
|
||||
},
|
||||
"quota_storage": {
|
||||
"size": 0,
|
||||
"used": 0,
|
||||
}}
|
||||
|
||||
# 用户权限处理
|
||||
user_Data = self.get_user_power()
|
||||
if user_Data != 'all':
|
||||
data_list = [i for i in data_list if str(i['id']) in user_Data.get('ftps', [])]
|
||||
# 用户权限处理结束
|
||||
|
||||
[paths.append(val['path']) or ids.append(val['id']) for val in data_list]
|
||||
for i, j in custom_list.items():
|
||||
if i in table_header:
|
||||
if j == 'quota':
|
||||
custom_conf[j] = self.get_all_quota(paths)
|
||||
if j == 'end_time':
|
||||
custom_conf[j] = self.get_all_ftp_end_time(ids)
|
||||
for i in data_list:
|
||||
i['quota'] = custom_conf['quota'].get(i['path'], default_quota)
|
||||
i['end_time'] = custom_conf['end_time'].get(i['id'], '0')
|
||||
return data_list
|
||||
except:
|
||||
pass
|
||||
|
||||
"""
|
||||
@name 初始化参数
|
||||
"""
|
||||
|
||||
def _get_site_args(self, get):
|
||||
try:
|
||||
if not 'type' in get:
|
||||
get.type = 0
|
||||
get.type = int(get.p)
|
||||
except:
|
||||
get.type = 0
|
||||
|
||||
# if not 'project_type' in get:
|
||||
# get.project_type = 'PHP'
|
||||
# get.search_key = get.project_type.lower()
|
||||
get.search_key = get.table.lower()
|
||||
if hasattr(get, 'search'):
|
||||
public.set_search_history(get.table,get.search_key,get.search)
|
||||
return get
|
||||
|
||||
"""
|
||||
@name 追加 or条件
|
||||
"""
|
||||
|
||||
def get_search_where(self, get):
|
||||
|
||||
where = ''
|
||||
params = get.search
|
||||
|
||||
conditions = ''
|
||||
if '_' in get.search:
|
||||
conditions = " escape '/'"
|
||||
if params:
|
||||
where = "name LIKE ? OR ps LIKE ? {}".format(conditions)
|
||||
params = ('%' + params + '%', '%' + params + '%')
|
||||
return where, params
|
||||
|
||||
|
||||
"""
|
||||
@获取ftp查询条件,追加and查询条件
|
||||
"""
|
||||
|
||||
def get_data_where(self, get):
|
||||
wheres = []
|
||||
get = self._get_site_args(get)
|
||||
if "type_id" in get and get.type_id:
|
||||
type_id = get.get("type_id")
|
||||
wheres.append("type_id = {}".format(type_id))
|
||||
return wheres
|
||||
|
||||
# 获取fto到期时间
|
||||
def get_all_ftp_end_time(self, ids):
|
||||
config_path = '/www/server/panel/data/ftp_push_config.json'
|
||||
if not os.path.exists(config_path):
|
||||
return {i: "0" for i in ids}
|
||||
config = json.loads(public.readFile(config_path))
|
||||
content = {}
|
||||
for _, i in config.items():
|
||||
if _ == 'channel':
|
||||
continue
|
||||
for j in i:
|
||||
content[j['id']] = j['end_time']
|
||||
return {i: content[i] if i in content.keys() else '0' for i in ids}
|
||||
|
||||
418
class/datalistModel/sitesModel.py
Normal file
418
class/datalistModel/sitesModel.py
Normal file
@@ -0,0 +1,418 @@
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# YakPanel
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(https://www.yakpanel.com) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: cjxin <cjxin@yakpanel.com>
|
||||
# -------------------------------------------------------------------
|
||||
#
|
||||
# ------------------------------
|
||||
|
||||
import os, sys, time, json, db, re
|
||||
import public
|
||||
import panelSite
|
||||
import idna
|
||||
from datalistModel.base import dataBase
|
||||
if '/www/server/panel' not in sys.path:
|
||||
sys.path.insert(0, '/www/server/panel')
|
||||
try:
|
||||
from mod.base.process.server import RealServer
|
||||
from mod.base.web_conf.proxy import Proxy
|
||||
except:
|
||||
pass
|
||||
class main(dataBase):
|
||||
web_server = None
|
||||
site_obj = None
|
||||
__panel_path = public.get_panel_path()
|
||||
|
||||
def __init__(self):
|
||||
self.limit_path = '{}/data/limit.pl'.format(self.__panel_path)
|
||||
self.siteorder_path = '{}/data/siteorder.pl'.format(self.__panel_path)
|
||||
self.site_obj = panelSite.panelSite()
|
||||
self.custom_list = {'WAF图标': 'waf', "容量限制": "quota", "日流量": "net","容量": "quota"}
|
||||
|
||||
self.default_quota = {"used": 0, "size": 0, "quota_push": {"size": 0, "used": 0}, "quota_storage": {"size": 0, "used": 0}}
|
||||
|
||||
"""
|
||||
@name 获取公共数据后,格式化为网站列表需要的数据
|
||||
"""
|
||||
|
||||
def get_data_list(self, get):
|
||||
get = self._get_site_args(get)
|
||||
data_list = get.data_list
|
||||
names = []
|
||||
paths = []
|
||||
custom_conf = {"waf":{}}
|
||||
|
||||
[paths.append(val['path']) or names.append(val['name']) for val in data_list]
|
||||
|
||||
table_headers = self.get_header_list(get)
|
||||
for val, key in self.custom_list.items():
|
||||
if not val in table_headers:
|
||||
continue
|
||||
if key == 'quota':
|
||||
custom_conf[key] = self.get_all_quota(paths)
|
||||
if key == 'waf':
|
||||
custom_conf[key] = self.get_waf_status_all(names)
|
||||
if key == 'net':
|
||||
site_netinfo = self.new_get_site_netinfo(names)
|
||||
custom_conf[key] = {i: self.get_site_net(site_netinfo, i) for i in names}
|
||||
realserver = RealServer()
|
||||
db_obj = public.M(get.table)
|
||||
domain_obj = public.M('domain')
|
||||
for val in data_list:
|
||||
if 'project_config' in val.keys():
|
||||
val['project_config'] = json.loads(val['project_config'])
|
||||
if 'type' in val["project_config"].keys() and 'PHPMOD' == val["project_config"]["type"]:
|
||||
val = self.get_php_mod_status(val)
|
||||
val['status'] = 1 if realserver.daemon_status(val['name'])['status'] else 0
|
||||
public.M(get.table).where("id=?", (val['id'],)).setField('status', val['status'])
|
||||
val['backup_count'] = public.M('backup').where("pid=? and type=?", (val['id'],'0')).count()
|
||||
val['domain'] = domain_obj.where("pid=?", (val['id'],)).count()
|
||||
val['ssl'] = self.get_site_ssl_info(val['name'])
|
||||
val['php_version'],val['php_version_status'] = self.get_php_version(val['name'])
|
||||
if 'project_config' in val.keys() and 'type' in val["project_config"].keys() and 'PHPMOD' == val["project_config"]["type"]:
|
||||
if "php_version" in val['project_config'].keys() and len(val['project_config']['php_version']) > 1:
|
||||
val['php_version'] = val['project_config']['php_version'][0] + '.' + val['project_config']['php_version'][1]
|
||||
val['php_version_status'] = os.path.exists('/www/server/php/{}/bin/php'.format(val['project_config']['php_version']))
|
||||
if val['project_type'] == 'WP2':
|
||||
import one_key_wp_v2
|
||||
from wp_toolkit import wpbackup
|
||||
one_key_wp = one_key_wp_v2.one_key_wp()
|
||||
val['wp_version'] = one_key_wp.get_wp_version(val['id'])
|
||||
val['cache_status'] = one_key_wp.get_cache_status(val['id'])
|
||||
val['backup_count'] = wpbackup(val['id']).backup_count()
|
||||
if not val['status'] in ['0', '1', 0, 1]:
|
||||
val['status'] = '1'
|
||||
|
||||
if not 'rname' in val or not val['rname']:
|
||||
val['rname'] = val['name']
|
||||
try:
|
||||
val['cn_name'] = idna.decode(val['name'])
|
||||
except:
|
||||
val['cn_name'] = val['name']
|
||||
# 是否有代理
|
||||
try:
|
||||
val['proxy'] = False
|
||||
proxy_list = self.site_obj.GetProxyList(public.to_dict_obj({'sitename': val['name']}))
|
||||
for i in proxy_list:
|
||||
if i['type'] == 1:
|
||||
val['proxy'] = True
|
||||
break
|
||||
if 'type' in val["project_config"].keys() and 'PHPMOD' == val["project_config"]["type"]:
|
||||
res = Proxy().get_proxy_list(public.to_dict_obj({'sitename': val['name']}))
|
||||
if res['status']:
|
||||
for i in res['data']:
|
||||
if i['type'] == 1:
|
||||
val['proxy'] = True
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
# 是否有重定向
|
||||
try:
|
||||
val['redirect'] = False
|
||||
redict_list = self.site_obj.GetRedirectList(public.to_dict_obj({'sitename': val['name']}))
|
||||
for i in redict_list:
|
||||
if i['type'] == 1:
|
||||
val['redirect'] = True
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
# 付费插件内容,按需加载
|
||||
# if 'waf' in custom_conf:
|
||||
# 前端必须需要这个参数,后续在调整
|
||||
val['waf'] = custom_conf["waf"].get(val['name'], {})
|
||||
|
||||
if 'quota' in custom_conf:
|
||||
val['quota'] = custom_conf['quota'].get(val['path'], self.default_quota)
|
||||
|
||||
if 'net' in custom_conf:
|
||||
val['net'] = custom_conf['net'].get(val['name'], {})
|
||||
return data_list
|
||||
|
||||
def get_php_mod_status(self,val):
|
||||
try:
|
||||
if int(val["project_config"]['dependence']) == 1:
|
||||
pid_file = '/tmp/php_mod_{}.pl'.format(val['name'])
|
||||
else:
|
||||
return val
|
||||
if not os.path.exists(pid_file):
|
||||
val["project_config"]['dependence'] = 0
|
||||
else:
|
||||
pid = public.readFile(pid_file)
|
||||
if not pid:
|
||||
val["project_config"]['dependence'] = 0
|
||||
else:
|
||||
try:
|
||||
pid = int(pid)
|
||||
import psutil
|
||||
p = psutil.Process(pid)
|
||||
if 'Yak-Panel' == p.name() or 'btpython' == p.name():
|
||||
val["project_config"]['dependence'] = 1
|
||||
else:
|
||||
val["project_config"]['dependence'] = 0
|
||||
except:
|
||||
val["project_config"]['dependence'] = 0
|
||||
except:
|
||||
pass
|
||||
return val
|
||||
"""
|
||||
@name 获取前端需要的表头
|
||||
"""
|
||||
|
||||
def get_header_list(self, get):
|
||||
|
||||
try:
|
||||
from config import config
|
||||
table_header = config().get_table_header(public.to_dict_obj({'table_name': 'phpTableColumn'}))
|
||||
if table_header['phpTableColumn']:
|
||||
table_header["phpTableColumn"] = json.loads(table_header["phpTableColumn"])
|
||||
table_header = [i['subtitle'] if 'subtitle' in i else i['label'] for i in table_header["phpTableColumn"] if (i.get('isCustom', False) == True) and ('subtitle' in i.keys() or 'label' in i.keys())]
|
||||
else:
|
||||
table_header = ['WAF图标', '容量限制', '日流量', '容量']
|
||||
except:
|
||||
table_header = ['WAF图标', '容量限制', '日流量', '容量']
|
||||
return table_header
|
||||
|
||||
def get_waf_status_all(self, names):
|
||||
"""
|
||||
@name 获取waf状态
|
||||
"""
|
||||
data = {}
|
||||
try:
|
||||
path = '/www/server/btwaf/site.json'
|
||||
res = json.loads(public.readFile(path))
|
||||
config_path = '/www/server/btwaf/config.json'
|
||||
open_status = json.loads(public.readFile(config_path))["open"]
|
||||
if not open_status:
|
||||
return data
|
||||
for site in res:
|
||||
data[site] = {}
|
||||
data[site]['status'] = True
|
||||
if 'open' in res[site]:
|
||||
data[site]['status'] = res[site]['open']
|
||||
except:
|
||||
return data
|
||||
data = {i: data[i] if i in data else {} for i in names}
|
||||
return data
|
||||
|
||||
def get_site_net(self, info, siteName):
|
||||
"""
|
||||
@name 获取网站流量
|
||||
@param siteName<string> 网站名称
|
||||
@return dict
|
||||
"""
|
||||
try:
|
||||
if info['status']: info = info['data']
|
||||
|
||||
if siteName in info:
|
||||
return info[siteName]
|
||||
except:
|
||||
pass
|
||||
return {}
|
||||
|
||||
def get_site_netinfo(self):
|
||||
"""
|
||||
@name 获取网站流量
|
||||
"""
|
||||
try:
|
||||
import PluginLoader
|
||||
args = public.dict_obj()
|
||||
args.model_index = 'panel'
|
||||
res = PluginLoader.module_run("total", "get_site_traffic", args)
|
||||
|
||||
return res
|
||||
except:
|
||||
pass
|
||||
return {}
|
||||
|
||||
def new_get_site_netinfo(self, names=None):
|
||||
"""
|
||||
@name 获取重构版监控报表网站流量
|
||||
@param names<list> 获取的网站列表
|
||||
"""
|
||||
if names is None:
|
||||
names = []
|
||||
try:
|
||||
import PluginLoader
|
||||
args = public.dict_obj()
|
||||
args.names = names
|
||||
args.model_index = 'panel'
|
||||
res = PluginLoader.module_run("total", "new_get_site_traffic", args)
|
||||
return res
|
||||
except:
|
||||
pass
|
||||
return {}
|
||||
|
||||
"""
|
||||
@name 获取证书详情
|
||||
"""
|
||||
|
||||
def get_site_ssl_info(self, siteName):
|
||||
try:
|
||||
s_file = 'vhost/nginx/{}.conf'.format(siteName)
|
||||
is_apache = False
|
||||
if not os.path.exists(s_file):
|
||||
s_file = 'vhost/apache/{}.conf'.format(siteName)
|
||||
is_apache = True
|
||||
|
||||
if not os.path.exists(s_file):
|
||||
return -1
|
||||
|
||||
s_conf = public.readFile(s_file)
|
||||
if not s_conf: return -1
|
||||
ssl_file = None
|
||||
if is_apache:
|
||||
if s_conf.find('SSLCertificateFile') == -1:
|
||||
return -1
|
||||
s_tmp = re.findall(r"SSLCertificateFile\s+(.+\.pem)", s_conf)
|
||||
if not s_tmp: return -1
|
||||
ssl_file = s_tmp[0]
|
||||
else:
|
||||
if s_conf.find('ssl_certificate') == -1:
|
||||
return -1
|
||||
s_tmp = re.findall(r"ssl_certificate\s+(.+\.pem);", s_conf)
|
||||
if not s_tmp: return -1
|
||||
ssl_file = s_tmp[0]
|
||||
ssl_info = public.get_cert_data(ssl_file)
|
||||
if not ssl_info: return -1
|
||||
ssl_info['endtime'] = int(
|
||||
int(time.mktime(time.strptime(ssl_info['notAfter'], "%Y-%m-%d")) - time.time()) / 86400)
|
||||
return ssl_info
|
||||
except:
|
||||
return -1
|
||||
|
||||
def get_php_version(self, siteName):
|
||||
try:
|
||||
if not self.web_server:
|
||||
self.web_server = public.get_webserver()
|
||||
|
||||
spath = public.get_panel_path()
|
||||
conf = public.readFile('{}/vhost/{}/{}.conf'.format(spath, self.web_server, siteName))
|
||||
|
||||
if self.web_server == 'openlitespeed':
|
||||
conf = public.readFile(spath + '/vhost/' + self.web_server + '/detail/' + siteName + '.conf')
|
||||
if self.web_server == 'nginx':
|
||||
rep = r"enable-php-(\w{2,5})\.conf"
|
||||
tmp = re.findall(rep, conf)
|
||||
if not tmp:
|
||||
rep = r"enable-php-(\w{2,5})-wpfastcgi\.conf"
|
||||
elif self.web_server == 'apache':
|
||||
rep = r"php-cgi-(\w{2,5})\.sock"
|
||||
else:
|
||||
rep = r"path\s*/usr/local/lsws/lsphp(\d+)/bin/lsphp"
|
||||
tmp = re.search(rep, conf).groups()
|
||||
if tmp[0] == '00':
|
||||
return '静态',True
|
||||
if tmp[0] == 'other':
|
||||
return '其它',True
|
||||
|
||||
return tmp[0][0] + '.' + tmp[0][1],os.path.exists('/www/server/php/{}/bin/php'.format(tmp[0]))
|
||||
except:
|
||||
return '静态',True
|
||||
|
||||
########################## 内部调用函数 #######################
|
||||
|
||||
"""
|
||||
@name 初始化参数
|
||||
"""
|
||||
|
||||
def _get_site_args(self, get):
|
||||
try:
|
||||
if not 'type' in get:
|
||||
get.type = 0
|
||||
get.type = int(get.p)
|
||||
except:
|
||||
get.type = 0
|
||||
|
||||
if not 'project_type' in get:
|
||||
get.project_type = 'PHP'
|
||||
|
||||
get.search_key = get.project_type.lower()
|
||||
|
||||
# 获取自定义排序
|
||||
if not 'order' in get:
|
||||
try:
|
||||
sort = public.readFile(self.siteorder_path)
|
||||
if sort:
|
||||
if sort.split(' ')[0] in self.__SORT_DATA:
|
||||
get.order = sort
|
||||
except:
|
||||
pass
|
||||
|
||||
if not 'order' in get:
|
||||
get.order = 'addtime desc'
|
||||
public.writeFile(self.siteorder_path, get.order)
|
||||
|
||||
# 获取每页显示条数
|
||||
try:
|
||||
if not 'limit' in get:
|
||||
get.type = 0
|
||||
get.limit = int(get.limit)
|
||||
except:
|
||||
get.limit = 0
|
||||
|
||||
if not get.limit:
|
||||
try:
|
||||
limit = int(public.readFile(self.limit_path))
|
||||
if limit:
|
||||
get.limit = int(limit)
|
||||
else:
|
||||
get.limit = 20
|
||||
except:
|
||||
get.limit = 20
|
||||
|
||||
if get.limit:
|
||||
public.writeFile(self.limit_path, str(get.limit))
|
||||
|
||||
if hasattr(get, 'search'):
|
||||
public.set_search_history(get.table,get.search_key,get.search)
|
||||
|
||||
return get
|
||||
|
||||
"""
|
||||
@name 追加 or条件
|
||||
"""
|
||||
|
||||
def get_search_where(self, get):
|
||||
|
||||
# 增加域名搜索
|
||||
where = ''
|
||||
params = get.params
|
||||
|
||||
conditions = ''
|
||||
if '_' in get.search:
|
||||
conditions = " escape '/'"
|
||||
|
||||
pids = []
|
||||
nlist = public.M('domain').where("name LIKE ?{}".format(conditions), ("%{}%".format(get.search),)).field('pid').select()
|
||||
for val in nlist:
|
||||
pids.append(str(val['pid']))
|
||||
|
||||
if pids:
|
||||
where = "{} OR id IN ({})".format(get.where, ','.join(pids))
|
||||
else:
|
||||
where = "{}".format(get.where)
|
||||
|
||||
return where, params
|
||||
|
||||
"""
|
||||
@获取网站查询条件,追加and查询条件
|
||||
"""
|
||||
|
||||
def get_data_where(self, get):
|
||||
|
||||
wheres = []
|
||||
get = self._get_site_args(get)
|
||||
|
||||
wheres.append(("(project_type = ?)", (get.project_type)))
|
||||
if get.project_type == 'PHP':
|
||||
if not get.type in ['-1', -1]:
|
||||
if int(get.type) == -2:
|
||||
wheres.append("(status = '0')")
|
||||
else:
|
||||
wheres.append("(type_id = {})".format(get.type))
|
||||
return wheres
|
||||
Reference in New Issue
Block a user