1. Add user login function.
2. Add the first professional plug-in Nginx WAF.
3. Release a new version of the online editor.
4. Fixed some bugs.
This commit is contained in:
jose
2021-02-23 09:52:47 +08:00
parent 5e2cbf9a5c
commit 7bacfb79e0
147 changed files with 22965 additions and 6148 deletions
+128 -118
View File
@@ -12,13 +12,13 @@ import os
import time
import re
import uuid
import threading
import socket
os.chdir('/www/server/panel')
if not os.name in ['nt']:
os.chdir('/www/server/panel')
if not 'class/' in sys.path:
sys.path.insert(0,'class/')
from flask import Flask,session,render_template,send_file,request,redirect,g,make_response,render_template_string,abort,Response as Resp
from flask import Config, Flask, session, render_template, send_file, request, redirect, g, make_response, \
render_template_string, abort, Response as Resp
from cachelib import SimpleCache
from werkzeug.wrappers import Response
from flask_session import Session
@@ -27,8 +27,9 @@ from flask_sockets import Sockets
cache = SimpleCache()
import public
#初始化Flask应用
app = Flask(__name__,template_folder="templates/" + public.GetConfigValue('template'))
# 初始化Flask应用
app = Flask(__name__, template_folder="templates/{}".format(public.GetConfigValue('template')))
Compress(app)
sockets = Sockets(app)
@@ -57,12 +58,9 @@ app.config['SESSION_PERMANENT'] = True
app.config['SESSION_USE_SIGNER'] = True
app.config['SESSION_KEY_PREFIX'] = 'BT_:'
app.config['SESSION_COOKIE_NAME'] = "SESSIONID"
app.config['PERMANENT_SESSION_LIFETIME'] = 86400
app.config['PERMANENT_SESSION_LIFETIME'] = 86400 * 30
Session(app)
from datetime import datetime
import socket
import common
#初始化路由
@@ -130,6 +128,7 @@ if admin_path in admin_path_checks: admin_path = '/bt'
#Flask请求勾子
@app.before_request
def request_check():
g.request_time = time.time()
#路由和URI长度过滤
if len(request.path) > 128: return abort(403)
if len(request.url) > 1024: return abort(403)
@@ -171,9 +170,14 @@ def request_check():
#Flask 请求结束勾子
@app.teardown_request
def request_end(reques = None):
if request.path in ['/service_status']: return
not_acts = ['GetTaskSpeed','GetNetWork','check_pay_status','get_re_order_status','get_order_stat']
key = request.args.get('action')
if not key in not_acts and request.full_path.find('/static/') == -1: public.write_request_log()
if not key in not_acts and request.full_path.find('/static/') == -1:
public.write_request_log()
if 'api_request' in g:
if g.api_request:
session.clear()
#Flask 404页面勾子
@app.errorhandler(404)
@@ -190,31 +194,11 @@ def notfound(e):
}
return Response(errorStr,status=404,headers=headers)
#@app.errorhandler(500)
# def internalerror(e):
# public.submit_error()
# errorStr = public.ReadFile('./BTPanel/templates/' + public.GetConfigValue('template') + '/error.html')
# try:
# if not app.config['DEBUG']:
# errorStr = errorStr.format(public.getMsg('PAGE_ERR_500_TITLE'),
# public.getMsg('PAGE_ERR_500_H1'),
# public.getMsg('PAGE_ERR_500_P1'),
# public.getMsg('NAME'),
# public.getMsg('PAGE_ERR_HELP'))
# else:
# errorStr = errorStr.format(public.getMsg('PAGE_ERR_500_TITLE'),
# str(e),
# '<pre>'+public.get_error_info() + '</pre>',
# public.getMsg('INIT_DEBUG_INFO'),public.getMsg('INIT_VERSION_LAST') + public.version())
# except IndexError:pass
# return errorStr,500
#===================================Flask HOOK========================#
# ===================================Flask HOOK========================#
#===================================普通路由区========================#
@app.route('/',methods=method_all)
# ===================================普通路由区========================#
@app.route('/', methods=method_all)
def home():
#面板首页
comReturn = comm.local()
@@ -225,6 +209,7 @@ def home():
data['ftpCount'] = public.M('ftps').count()
data['databaseCount'] = public.M('databases').count()
data['lan'] = public.GetLan('index')
data['js_random'] = get_js_random()
public.auto_backup_panel()
return render_template( 'index.html',data = data)
@@ -297,9 +282,11 @@ def site(pdata = None):
comReturn = comm.local()
if comReturn: return comReturn
if request.method == method_get[0] and not pdata:
data = {}
import system
data = system.system().GetConcifInfo()
data['isSetup'] = True
data['lan'] = public.getLan('site')
data['js_random'] = get_js_random()
if os.path.exists(public.GetConfigValue('setup_path')+'/nginx') == False \
and os.path.exists(public.GetConfigValue('setup_path')+'/apache') == False \
and os.path.exists(public.GetConfigValue('openlitespeed_path')+'/lsws') == False:
@@ -308,7 +295,10 @@ def site(pdata = None):
import panelSite
siteObject = panelSite.panelSite()
defs = ('get_site_domains','GetRedirectFile','SaveRedirectFile','DeleteRedirect','GetRedirectList','CreateRedirect','ModifyRedirect',
defs = ('upload_csv','create_website_multiple','del_redirect_multiple','del_proxy_multiple','delete_dir_auth_multiple',
'delete_dir_bind_multiple','delete_domain_multiple','set_site_etime_multiple','set_site_php_version_multiple',
'delete_website_multiple','set_site_status_multiple','get_site_err_log','get_site_domains','GetRedirectFile',
'SaveRedirectFile','DeleteRedirect','GetRedirectList','CreateRedirect','ModifyRedirect',
'set_dir_auth','delete_dir_auth','get_dir_auth','modify_dir_auth_pass',
'GetSiteLogs','GetSiteDomains','GetSecurity','SetSecurity','ProxyCache','CloseToHttps','HttpToHttps','SetEdate',
'SetRewriteTel','GetCheckSafe','CheckSafe','GetDefaultSite','SetDefaultSite','CloseTomcat','SetTomcat','apacheAddPort',
@@ -329,6 +319,7 @@ def ftp(pdata = None):
FtpPort()
data = {}
data['isSetup'] = True
data['js_random'] = get_js_random()
if os.path.exists(public.GetConfigValue('setup_path') + '/pure-ftpd') == False: data['isSetup'] = False
data['lan'] = public.GetLan('ftp')
return render_template('ftp.html',data=data)
@@ -354,10 +345,11 @@ def database(pdata = None):
data['isSetup'] = os.path.exists(public.GetConfigValue('setup_path') + '/mysql/bin')
data['mysql_root'] = public.M('config').where('id=?',(1,)).getField('mysql_root')
data['lan'] = public.GetLan('database')
data['js_random'] = get_js_random()
return render_template('database.html',data=data)
import database
databaseObject = database.database()
defs = ('check_mysql_ssl_status','write_ssl_to_mysql','GetdataInfo','GetInfo','ReTable','OpTable','AlTable','GetSlowLogs','GetRunStatus',
defs = ('get_mysql_user','check_mysql_ssl_status','write_ssl_to_mysql','GetdataInfo','GetInfo','ReTable','OpTable','AlTable','GetSlowLogs','GetRunStatus',
'SetDbConf','GetDbStatus','BinLog','GetErrorLog','GetMySQLInfo','SetDataDir','SetMySQLPort',
'AddDatabase','DeleteDatabase','SetupPassword','ResDatabasePassword','ToBackup','DelBackup',
'InputSql','SyncToDatabases','SyncGetDatabases','GetDatabaseAccess','SetDatabaseAccess')
@@ -375,7 +367,6 @@ def acme(pdata = None):
'get_auths','auth_domain','check_auth_status','download_cert','apply_cert','renew_cert','apply_cert_api','apply_dns_auth')
return publicObject(acme_v2_object,defs,None,pdata)
@app.route('/message/<action>',methods=method_all)
def message(action = None):
#提示消息管理
@@ -404,6 +395,7 @@ def control(pdata = None):
if request.method == method_get[0]:
data = {}
data['lan'] = public.GetLan('control')
data['js_random'] = get_js_random()
return render_template( 'control.html',data=data)
@app.route('/firewall',methods=method_all)
@@ -414,6 +406,7 @@ def firewall(pdata = None):
if request.method == method_get[0] and not pdata:
data = {}
data['lan'] = public.GetLan('firewall')
data['js_random'] = get_js_random()
return render_template( 'firewall.html',data=data)
import firewalls
firewallObject = firewalls.firewalls()
@@ -429,6 +422,7 @@ def ssh_security(pdata = None):
if request.method == method_get[0] and not pdata:
data = {}
data['lan'] = public.GetLan('firewall')
data['js_random'] = get_js_random()
return render_template( 'firewall.html',data=data)
import ssh_security
firewallObject = ssh_security.ssh_security()
@@ -437,23 +431,6 @@ def ssh_security(pdata = None):
return publicObject(firewallObject,defs,None,pdata)
# @app.route('/firewall_new',methods=method_all)
# def firewall_new(pdata = None):
# comReturn = comm.local()
# if comReturn: return comReturn
# if request.method == method_get[0] and not pdata:
# data = {}
# data['lan'] = public.GetLan('firewall')
# return render_template( 'firewall_new.html',data=data)
# import firewall_new
# firewallObject = firewall_new.firewalls()
# defs = ('GetList','AddDropAddress','DelDropAddress','FirewallReload','SetFirewallStatus',
# 'AddAcceptPort','DelAcceptPort','SetSshStatus','SetPing','SetSshPort','GetSshInfo',
# 'AddSpecifiesIp','DelSpecifiesIp'
# )
# return publicObject(firewallObject,defs,None,pdata)
@app.route('/monitor', methods=method_all)
def panel_monitor(pdata=None):
#云控统计信息
@@ -535,13 +512,14 @@ def files(pdata = None):
data = {}
data['recycle_bin'] = os.path.exists('data/recycle_bin.pl')
data['lan'] = public.GetLan('files')
data['js_random'] = get_js_random()
return render_template('files.html',data=data)
import files
filesObject = files.files()
defs = ('get_progress','restore_website','fix_permissions','get_all_back','restore_path_permissions','del_path_premissions','get_path_premissions','back_path_permissions',
'CheckExistsFiles','GetExecLog','GetSearch','ExecShell','GetExecShellMsg','exec_git','exec_composer','create_download_url',
'UploadFile','GetDir','CreateFile','CreateDir','DeleteDir','DeleteFile','get_download_url_list','remove_download_url','modify_download_url',
'CopyFile','CopyDir','MvFile','GetFileBody','SaveFileBody','Zip','UnZip','get_download_url_find',
'CopyFile','CopyDir','MvFile','GetFileBody','SaveFileBody','Zip','UnZip','get_download_url_find','set_file_ps',
'SearchFiles','upload','read_history','re_history','auto_save_temp','get_auto_save_body','get_videos',
'GetFileAccess','SetFileAccess','GetDirSize','SetBatchData','BatchPaste','install_rar','get_path_size',
'DownloadFile','GetTaskSpeed','CloseLogs','InstallSoft','UninstallSoft','SaveTmpFile','get_composer_version','exec_composer','update_composer',
@@ -559,6 +537,7 @@ def crontab(pdata = None):
if request.method == method_get[0] and not pdata:
data = {}
data['lan'] = public.GetLan('crontab')
data['js_random'] = get_js_random()
return render_template( 'crontab.html',data=data)
import crontab
crontabObject = crontab.crontab()
@@ -575,6 +554,7 @@ def soft(pdata = None):
if request.method == method_get[0] and not pdata:
data={}
data['lan'] = public.GetLan('soft')
data['js_random'] = get_js_random()
return render_template( 'soft.html',data=data)
@app.route('/config',methods=method_all)
@@ -595,9 +575,6 @@ def config(pdata = None):
data['ipv6'] = ''
sess_out_path = 'data/session_timeout.pl'
if not os.path.exists(sess_out_path): public.writeFile(sess_out_path,'86400')
workers_p = 'data/workers.pl'
if not os.path.exists(workers_p): public.writeFile(workers_p,'1')
data['workers'] = int(public.readFile(workers_p))
s_time_tmp = public.readFile(sess_out_path)
if not s_time_tmp: s_time_tmp = '0'
data['session_timeout'] = int(s_time_tmp)
@@ -607,25 +584,32 @@ def config(pdata = None):
data['basic_auth']['value'] = public.getMsg('CLOSED')
if data['basic_auth']['open']: data['basic_auth']['value'] = public.getMsg('OPENED')
data['debug'] = ''
data['js_random'] = get_js_random()
if app.config['DEBUG']: data['debug'] = 'checked'
data['is_local'] = ''
if public.is_local(): data['is_local'] = 'checked'
return render_template( 'config.html',data=data)
import config
defs = ('get_ols_private_cache_status','get_ols_value','set_ols_value','get_ols_private_cache','get_ols_static_cache','set_ols_static_cache','switch_ols_private_cache','set_ols_private_cache',
'set_coll_open','get_qrcode_data','check_two_step','set_two_step_auth','create_user','remove_user','modify_user',
'get_key','get_php_session_path','set_php_session_path','get_cert_source','get_users',
'set_local','set_debug','get_panel_error_logs','clean_panel_error_logs',
'get_basic_auth_stat','set_basic_auth','get_cli_php_version','get_tmp_token',
'set_cli_php_version','DelOldSession', 'GetSessionCount', 'SetSessionConf',
'GetSessionConf','get_ipv6_listen','set_ipv6_status','GetApacheValue','SetApacheValue',
'GetNginxValue','SetNginxValue','get_token','set_token','set_admin_path','is_pro',
'get_php_config','get_config','SavePanelSSL','GetPanelSSL','GetPHPConf','SetPHPConf',
'GetPanelList','AddPanelInfo','SetPanelInfo','DelPanelInfo','ClickPanelInfo','SetPanelSSL',
'SetTemplates','Set502','setPassword','setUsername','setPanel','setPathInfo','setPHPMaxSize',
'getFpmConfig','setFpmConfig','setPHPMaxTime','syncDate','setPHPDisable','SetControl',
'ClosePanel','AutoUpdatePanel','SetPanelLock','return_mail_list','del_mail_list','add_mail_address','user_mail_send','get_user_mail','set_dingding','get_dingding','get_settings','user_stmp_mail_send','user_dingding_send'
)
defs = (
'get_panel_ssl_status','set_file_deny', 'del_file_deny', 'get_file_deny',
'get_httpd_access_log_format_parameter','set_httpd_format_log_to_website','get_httpd_access_log_format',
'del_httpd_access_log_format','add_httpd_access_log_format','get_nginx_access_log_format_parameter',
'set_format_log_to_website','get_nginx_access_log_format','del_nginx_access_log_format',
'add_nginx_access_log_format','get_ols_private_cache_status','get_ols_value','set_ols_value',
'get_ols_private_cache','get_ols_static_cache','set_ols_static_cache','switch_ols_private_cache','set_ols_private_cache',
'set_coll_open','get_qrcode_data','check_two_step','set_two_step_auth','create_user','remove_user','modify_user',
'get_key','get_php_session_path','set_php_session_path','get_cert_source','get_users',
'set_local','set_debug','get_panel_error_logs','clean_panel_error_logs','get_menu_list','set_hide_menu_list',
'get_basic_auth_stat','set_basic_auth','get_cli_php_version','get_tmp_token','get_temp_login','set_temp_login','remove_temp_login','clear_temp_login','get_temp_login_logs',
'set_cli_php_version','DelOldSession', 'GetSessionCount', 'SetSessionConf',
'GetSessionConf','get_ipv6_listen','set_ipv6_status','GetApacheValue','SetApacheValue',
'GetNginxValue','SetNginxValue','get_token','set_token','set_admin_path','is_pro',
'get_php_config','get_config','SavePanelSSL','GetPanelSSL','GetPHPConf','SetPHPConf',
'GetPanelList','AddPanelInfo','SetPanelInfo','DelPanelInfo','ClickPanelInfo','SetPanelSSL',
'SetTemplates','Set502','setPassword','setUsername','setPanel','setPathInfo','setPHPMaxSize',
'getFpmConfig','setFpmConfig','setPHPMaxTime','syncDate','setPHPDisable','SetControl',
'ClosePanel','AutoUpdatePanel','SetPanelLock','return_mail_list','del_mail_list','add_mail_address','user_mail_send','get_user_mail','set_dingding','get_dingding','get_settings','user_stmp_mail_send','user_dingding_send'
)
return publicObject(config.config(),defs,None,pdata)
@app.route('/ajax',methods=method_all)
@@ -686,7 +670,7 @@ def ssl(pdata = None):
if comReturn: return comReturn
import panelSSL
toObject = panelSSL.panelSSL()
defs = ('RemoveCert','renew_lets_ssl','SetCertToSite','GetCertList','SaveCert','GetCert','GetCertName',
defs = ('check_url_txt','RemoveCert','renew_lets_ssl','SetCertToSite','GetCertList','SaveCert','GetCert','GetCertName','again_verify',
'DelToken','GetToken','GetUserInfo','GetOrderList','GetDVSSL','Completed','SyncOrder','download_cert','set_cert','cancel_cert_order',
'get_order_list','get_order_find','apply_order_pay','get_pay_status','apply_order','get_verify_info','get_verify_result','get_product_list','set_verify_info',
'GetSSLInfo','downloadCRT','GetSSLProduct','Renew_SSL','Get_Renew_SSL')
@@ -746,7 +730,7 @@ def auth(pdata = None):
if comReturn: return comReturn
import panelAuth
toObject = panelAuth.panelAuth()
defs = ('get_re_order_status_plugin','create_plugin_other_order','get_order_stat',
defs = ('auth_activate','get_product_auth','get_stripe_session_id','get_re_order_status_plugin','create_plugin_other_order','get_order_stat',
'get_voucher_plugin','create_order_voucher_plugin','get_product_discount_by',
'get_re_order_status','create_order_voucher','create_order','get_order_status',
'get_voucher','flush_pay_status','create_serverid','check_serverid',
@@ -766,7 +750,7 @@ def download():
if filename.find('|') != -1:
filename = filename.split('|')[1]
if not filename: return public.ReturnJson(False,"INIT_ARGS_ERR"),json_header
if filename in ['alioss','qiniu','upyun','txcos','ftp']: return panel_cloud()
if filename in ['alioss','qiniu','upyun','txcos','ftp','msonedrive','gcloud_storage', 'gdrive', 'aws_s3']: return panel_cloud()
if not os.path.exists(filename): return public.ReturnJson(False,"FILE_NOT_EXISTS"),json_header
if request.args.get('play') == 'true':
@@ -779,6 +763,8 @@ def download():
if extName in ['png','gif','jpeg','jpg']: mimetype = None
return send_file(filename,mimetype=mimetype,
as_attachment=True,
add_etags=True,
conditional=True,
attachment_filename=os.path.basename(filename),
cache_timeout=0)
@@ -831,15 +817,15 @@ def login():
if admin_path != '/bt' and os.path.exists(admin_path_file) and not 'admin_auth' in session:
is_auth_path = True
num_key = public.md5(public.GetClientIp() + '_auth_path')
if not public.get_error_num(num_key,20): return public.returnMsg(False,'连续20次安全入口验证失败,禁止1小时')
if not public.get_error_num(num_key,20): return public.returnMsg(False,'AUTH_FAILED1')
#登录输入验证
if request.method == method_post[0]:
v_list = ['username','password','code','vcode','cdn_url']
for v in v_list:
pv = request.form.get(v,'').strip()
if v == 'cdn_url':
if len(pv) > 32: return public.returnMsg(False,'错误的参数长度!'),json_header
if not re.match(r"^[\w\.-]+$",pv): public.returnJson(False,'错误的参数格式'),json_header
if len(pv) > 32: return public.returnMsg(False,'PARAMETER_LEN_ERR'),json_header
if not re.match(r"^[\w\.-]+$",pv): public.returnJson(False,'PARAMETER_FORMAT_ERR'),json_header
continue
if not pv: continue
@@ -847,14 +833,14 @@ def login():
if v == 'code': p_len = 4
if v == 'vcode': p_len = 6
if len(pv) != p_len:
if v == 'code': return public.returnJson(False,'验证码长度错误'),json_header
return public.returnJson(False,'错误的参数长度'),json_header
if v == 'code': return public.returnJson(False,'VCODE_LEN_ERR'),json_header
return public.returnJson(False,'PARAMETER_LEN_ERR'),json_header
if not re.match(r"^\w+$",pv):
return public.returnJson(False,'错误的参数格式'),json_header
return public.returnJson(False,'PARAMETER_FORMAT_ERR'),json_header
for n in request.form.keys():
if not n in v_list:
return public.returnJson(False,'登录参数中不能有多余参数'),json_header
return public.returnJson(False,'EXTRA_PARAMETER_ERR'),json_header
get = get_input()
import userlogin
@@ -869,10 +855,12 @@ def login():
if session['login'] != False:
session['login'] = False
cache.set('dologin',True)
public.WriteLog('用户登出','客户端:{},已手动退出面板'.format(public.GetClientIp()+ ":" + str(request.environ.get('REMOTE_PORT'))))
public.WriteLog('TYPE_LOGOUT','MANUALLY_LOGOUT',(public.GetClientIp()+ ":" + str(request.environ.get('REMOTE_PORT')),))
if 'tmp_login_expire' in session:
s_file = 'data/session/{}'.format(session['tmp_login_id'])
if os.path.exists(s_file):
os.remove(s_file)
session.clear()
session_path = r'/dev/shm/session_py' + str(sys.version_info[0])
if os.path.exists(session_path): public.ExecShell("rm -f " + session_path + '/*')
sess_file = 'data/sess_files/' + public.get_sess_key()
if os.path.exists(sess_file):
try:
@@ -883,11 +871,17 @@ def login():
if is_auth_path:
if route_path != request.path and route_path + '/' != request.path:
public.set_error_num(num_key)
#return abort(404)
data = {}
data['lan'] = public.getLan('close')
return render_template('autherr.html',data=data)
referer = request.headers.get('Referer','err')
referer_tmp = referer.split('/')
referer_path = referer_tmp[-1]
if referer_path == '':
referer_path = referer_tmp[-2]
if route_path != '/'+referer_path:
public.set_error_num(num_key)
#return abort(404)
data = {}
data['lan'] = public.getLan('close')
return render_template('autherr.html',data=data)
session['admin_auth'] = True
public.set_error_num(num_key,True)
comReturn = common.panelSetup().init()
@@ -929,16 +923,19 @@ def tips():
return render_template('tips.html')
@app.route('/get_app_bind_status',methods=method_all)
def get_app_bind_status(pdata = None):
#APP绑定状态查询
@app.route('/get_app_bind_status', methods=method_all)
def get_app_bind_status(pdata=None):
# APP绑定状态查询
if not public.check_app('app_bind'):return public.returnMsg(False, 'API_DISABLED')
import panelApi
api_object = panelApi.panelApi()
return json.dumps(api_object.get_app_bind_status(get_input())),json_header
@app.route('/check_bind',methods=method_all)
def check_bind(pdata = None):
#APP绑定查询
@app.route('/check_bind', methods=method_all)
def check_bind(pdata=None):
# APP绑定查询
if not public.check_app('app_bind'):return public.returnMsg(False, 'API_DISABLED')
import panelApi
api_object = panelApi.panelApi()
return json.dumps(api_object.check_bind(get_input())),json_header
@@ -1098,6 +1095,7 @@ def panel_public():
return data,json_header
if get.name != 'app': return abort(404)
if not public.check_app('wxapp'): return public.returnMsg(False, 'UNBOUND_USER')
import panelPlugin
plu = panelPlugin.panelPlugin()
get.s = '_check'
@@ -1126,6 +1124,10 @@ def send_favicon():
@app.route('/service_status',methods = method_get)
def service_status():
#检查面板当前状态
try:
if not 'login' in session: session.clear()
except:
pass
return 'True'
@app.route('/coll',methods=method_all)
@@ -1140,7 +1142,7 @@ def panel_other(name=None,fun = None,stype=None):
args = None
else:
args = get_input()
args_list = ['mail_from','password','mail_to','subject','content','subtype']
args_list = ['mail_from','password','mail_to','subject','content','subtype','data']
for k in args.__dict__:
if not k in args_list: return abort(404)
@@ -1256,6 +1258,7 @@ def panel_hook():
@app.route('/install',methods=method_all)
def install():
#初始化面板接口
if not os.path.exists('install.pl'): return redirect('/login')
if public.M('config').where("id=?",('1',)).getField('status') == 1:
if os.path.exists('install.pl'): os.remove('install.pl')
session.clear()
@@ -1311,7 +1314,8 @@ def get_dir_down(filename,token,find):
import files
args = public.dict_obj()
args.path = filename
to_path = filename.replace(find['filename'],'').strip('/')
args.share = True
to_path = filename.replace(find['filename'], '').strip('/')
if request.args.get('play') == 'true':
pdata = files.files().get_videos(args)
@@ -1322,7 +1326,7 @@ def get_dir_down(filename,token,find):
pdata['token'] = token
pdata['src_path'] = find['filename']
pdata['to_path'] = to_path
if find['expire'] > (time.time() + (86400 * 365 * 10)):
if find['expire'] < (time.time() + (86400 * 365 * 10)):
pdata['expire'] = public.format_date(times=find['expire'])
else:
pdata['expire'] = public.getMsg('NEVER_EXPIRES')
@@ -1380,6 +1384,8 @@ class run_exec:
result = eval(fun)
else:
result = eval(fun)
r_type = type(result)
if r_type == Resp: return result
result = public.GetJson(result),json_header
break
if not result:
@@ -1387,12 +1393,12 @@ class run_exec:
if g.is_aes:
result = public.aes_encrypt(result[0],g.aes_key),json_header
else:
if os.path.exists('pyenv/bin/python') and sys.version_info[0] == 3:
if not os.path.exists('data/debug.pl'):
x_token = request.headers.get('x-http-token')
if x_token:
aes_pwd = x_token[:8] + x_token[40:48]
result = "BT-CRT"+public.aes_encrypt(result[0],aes_pwd),{'Content-Type':'text/plain; charset=utf-8'}
# if os.path.exists('pyenv/bin/python') and sys.version_info[0] == 3:
# if not os.path.exists('data/debug.pl'):
# x_token = request.headers.get('x-http-token')
# if x_token:
# aes_pwd = x_token[:8] + x_token[40:48]
# result = "BT-CRT"+public.aes_encrypt(result[0],aes_pwd),{'Content-Type':'text/plain; charset=utf-8'}
pass
return result
@@ -1430,10 +1436,7 @@ def publicObject(toObject,defs,action=None,get = None):
if hasattr(toObject,'site_path_check'):
if not toObject.site_path_check(get): return public.ReturnJson(False,'INIT_ACCEPT_NOT'),json_header
p = run_exec()
result = p.run(toObject,defs,get)
del p
return result
return run_exec().run(toObject,defs,get)
@@ -1578,6 +1581,14 @@ def is_login(result):
result.set_cookie('request_token',request_token,max_age=86400*30)
return result
# js随机数模板使用,用于不更新版本号时更新前端文件不需要用户强制刷新浏览器
def get_js_random():
js_random = public.readFile('data/js_random.pl')
if not js_random or js_random == '1':
js_random = public.GetRandomString(16)
public.writeFile('data/js_random.pl',js_random)
return js_random
#获取输入数据
def get_input():
data = public.dict_obj()
@@ -1585,17 +1596,17 @@ def get_input():
for key in request.args.keys():
data[key] = str(request.args.get(key,''))
try:
x_token = request.headers.get('x-http-token')
if x_token:
aes_pwd = x_token[:8] + x_token[40:48]
# x_token = request.headers.get('x-http-token')
# if x_token:
# aes_pwd = x_token[:8] + x_token[40:48]
for key in request.form.keys():
if key in exludes: continue
data[key] = str(request.form.get(key,''))
if x_token:
if len(data[key]) > 5:
if data[key][:6] == 'BT-CRT':
data[key] = public.aes_decrypt(data[key][6:],aes_pwd)
# if x_token:
# if len(data[key]) > 5:
# if data[key][:6] == 'BT-CRT':
# data[key] = public.aes_decrypt(data[key][6:],aes_pwd)
except:
try:
post = request.form.to_dict()
@@ -1609,7 +1620,6 @@ def get_input():
for k in g.form_data.keys():
data[k] = str(g.form_data[k])
if not hasattr(data,'data'): data.data = []
return data
Binary file not shown.
+123
View File
@@ -28,6 +28,12 @@
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: iconfont;
src: url("../icons/iconfont.woff");
font-weight: normal;
font-style: normal;
}
.binary-icon:before {
font-family: "Octicons Regular";
font-size: 16px;
@@ -4939,4 +4945,121 @@
color: #6a9fb5;
font-family: octicons;
content: "\f0c9";
}
/* 文件目录图标 */
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-houtui:before {
content: "\e60f";
}
.icon-search1:before {
content: "\e60e";
}
.icon-lishi:before {
content: "\e652";
}
.icon-shoucang:before {
content: "\e648";
}
.icon-wenjian:before {
content: "\e6ab";
}
.icon-vscode:before {
content: "\e609";
}
.icon-fenxiang:before {
content: "\e62a";
}
.icon-tishi:before {
content: "\e63f";
}
.icon-guanbi:before {
content: "\e60c";
}
.icon-favorites:before {
content: "\e66c";
}
.icon-share1:before {
content: "\e607";
}
.icon-authority:before {
content: "\e606";
}
.icon-dir_kill:before {
content: "\e643";
}
.icon-zhixiang-zuo:before {
content: "\e6fd";
}
.icon-next:before {
content: "\e772";
}
.icon-prev:before {
content: "\e7b4";
}
.icon-lajitong-copy:before {
content: "\e605";
}
.icon-xingxing:before {
content: "\e602";
}
.icon-triangle-right:before {
content: "\e601";
}
.icon-search:before {
content: "\e60d";
}
.icon-arrow-down:before {
content: "\e7b2";
}
.icon-arrow-right:before {
content: "\e743";
}
.icon-arrow-lift:before {
content: "\e744";
}
.icon-terminal:before {
content: "\e600";
}
.icon-iconfont53:before {
content: "\e75e";
}
.icon-xiala:before {
content: "\e62e";
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

+345 -14
View File
@@ -376,7 +376,7 @@ function bindBTName(a,type){
closeBtn: 2,
shift: 5,
shadeClose: false,
content: "<div class='bt-form pd20 pb70'><div class='line'><span class='tname'>"+lan.public.user+"</span><div class='info-r'><input class='bt-input-text' type='text' name='username' id='p1' value='' placeholder='"+lan.config.user_bt+"' style='width:100%'/></div></div><div class='line'><span class='tname'>"+lan.public.pass+"</span><div class='info-r'><input class='bt-input-text' type='password' name='password' id='p2' value='' placeholder='"+lan.config.pass_bt+"' style='width:100%'/></div></div><div class='bt-form-submit-btn'><button type='button' class='btn btn-danger btn-sm' onclick=\"layer.closeAll()\">"+lan.public.cancel+"</button> "+btn+"</div></div>"
content: "<div class='bt-form pd20 pb70'><div class='line'><span class='tname' style='width:100px;'>"+lan.public.user+"</span><div class='info-r' style='margin-left:100px;'><input class='bt-input-text' type='text' name='username' id='p1' value='' placeholder='"+lan.config.user_bt+"' style='width:100%'/></div></div><div class='line'><span class='tname' style='width:100px;'>"+lan.public.pass+"</span><div class='info-r' style='margin-left:100px;'><input class='bt-input-text' type='password' name='password' id='p2' value='' placeholder='"+lan.config.pass_bt+"' style='width:100%'/></div></div><div class='bt-form-submit-btn'><button type='button' class='btn btn-danger btn-sm' onclick=\"layer.closeAll()\">"+lan.public.cancel+"</button> "+btn+"</div></div>"
})
}
//解除绑定宝塔账号
@@ -385,7 +385,10 @@ function UnboundBt(){
layer.confirm(lan.config.binding_un_msg,{closeBtn:2,icon:3,title:lan.config.binding_un},function(){
$.get("/ssl?action=DelToken",function(b){
layer.msg(b.msg,{icon:b.status? 1:2})
$("input[name='btusername']").val('');
if(b.status){
window.location.reload();
$("input[name='btusername']").val('');
}
})
})
}
@@ -574,11 +577,11 @@ function SavePanelSSL(){
}
function SetDebug() {
var status_s = {false:'Open',true:'Close'}
var status_s = {false:'open',true:'close'}
var debug_stat = $("#panelDebug").prop('checked');
bt.confirm({
title: status_s[debug_stat] + "Developer mode",
msg: "Do you really want "+ status_s[debug_stat]+" developer mode?",
title: (debug_stat?'Open':'Close') + " developer mode",
msg: "Do you confirm to "+ (debug_stat?'open':'close') +" developer mode?",
cancel: function () {
$("#panelDebug").prop('checked',debug_stat);
}}, function () {
@@ -772,11 +775,11 @@ function open_wxapp(){
$(function () {
$.get("/ssl?action=GetUserInfo", function (b) {
$.get("/ssl?action=GetUserInfo", function (b) {
if (b.status) {
$("input[name='btusername']").val(b.data.username);
$("input[name='btusername']").next().text(lan.public.edit).attr("onclick", "bindBTName(2,'c')").css({ "margin-left": "-82px" });
$("input[name='btusername']").next().after('<span class="btn btn-xs btn-success" onclick="UnboundBt()" style="vertical-align: 0px;">' + lan.config.binding_un + '</span>');
$("input[name='btusername']").next().text(lan.public.edit).attr("onclick", "bindBTName(2,'c')").css({ "right": "57px" });
$("input[name='btusername']").next().after('<span class="modify btn btn-xs btn-success" onclick="UnboundBt()" style="vertical-align: 0px;">' + lan.config.binding_un + '</span>');
}
else {
$("input[name='btusername']").next().text(lan.config.binding).attr("onclick", "bindBTName(2,'b')").removeAttr("style");
@@ -804,7 +807,7 @@ function GetPanelApi() {
isOpen = rdata.open ? 'checked' : '';
layer.open({
type: 1,
area: "500px",
area: "522px",
title: lan.config.set_api,
closeBtn: 2,
shift: 5,
@@ -814,7 +817,7 @@ function GetPanelApi() {
<span class="tname">'+lan.config.api+'</span>\
<div class="info-r" style="height:28px;">\
<input class="btswitch btswitch-ios" id="panelApi_s" type="checkbox" '+ isOpen+'>\
<label style="position: relative;top: 5px;" class="btswitch-btn" for="panelApi_s" onclick="SetPanelApi(2)"></label>\
<label style="position: relative;top: 5px;" class="btswitch-btn" for="panelApi_s" onclick="SetPanelApi(2,1)"></label>\
</div>\
</div>\
<div class="line">\
@@ -872,10 +875,12 @@ function SetPanelApi(t_type,index) {
return false
}
set_token_req(pdata,function(rdata){
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
if (rdata.msg == lan.config.open_successfully) {
if(t_type == 2 && index != '0') GetPanelApi();
}
layer.close(layer.index);
if (rdata.msg == 'Open success!') {
if(t_type == 2 && index != '1') GetPanelApi();
}
if(t_type == 2) $('#panelApi').prop('checked',rdata.msg == 'Open success!'?true:false);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
@@ -1259,3 +1264,329 @@ function show_basic_auth(rdata) {
</div>'
})
}
function get_panel_hide_list(){
var loadT = bt.load('Getting panel menu bar, please wait...'),arry = [];
$.post('/config?action=get_menu_list',function(rdata){
loadT.close();
$.each(rdata,function(index,item){
if(!item.show) arry.push(item.title)
});
$('#panel_menu_hide').val(arry.length > 0?arry.join('/'):'No hidden bar');
});
}
get_panel_hide_list();
// 设置面板菜单显示功能
function set_panel_ground(){
var loadT = bt.load('Getting panel menu bar, please wait...');
$.post('/config?action=get_menu_list',function(rdata){
var html = '',arry = ["dologin","memuAconfig","memuAsoft","memuA"],is_option = '';
loadT.close();
$.each(rdata,function(index,item){
is_option = '<div class="index-item" style="float:right;"><input class="btswitch btswitch-ios" id="'+ item.id +'0000" name="'+ item.id +'" type="checkbox" '+ (item.show?'checked':'') +'><label class="btswitch-btn" for="'+ item.id +'0000"></label></div>'
if(item.id == 'dologin' || item.id == 'memuAconfig' || item.id == 'memuAsoft' || item.id == 'memuA') is_option = 'Inoperable';
html += '<tr><td>'+ item.title +'</td><td><div style="float:right;">'+ is_option +'</div></td></tr>';
});
layer.open({
type:1,
title:'Manage panel menu bar',
area:['350px','536px'],
shadeClose:false,
closeBtn:2,
content:'<div class="divtable softlist" id="panel_menu_tab" style="padding: 20px 15px;"><table class="table table-hover"><thead><tr><th>Menu bar</th><th style="text-align:right;width:120px;">Display</th></tr></thead><tbody>'+ html +'</tbody></table></div>',
success:function(){
$('#panel_menu_tab input').click(function(){
var arry = [];
$(this).parents('tr').siblings().each(function(index,el){
if($(this).find('input').length >0 && !$(this).find('input').prop('checked')){
arry.push($(this).find('input').attr('name'));
}
});
if(!$(this).prop('checked')){
arry.push($(this).attr('name'));
}
var loadT = bt.load('Setting panel menu bar display status, please wait...');
$.post('/config?action=set_hide_menu_list',{hide_list:JSON.stringify(arry)},function(rdata){
loadT.close();
bt.msg(rdata);
});
});
}
});
});
}
/**
* @description 获取临时授权列表
* @param {Function} callback 回调函数列表
* @returns void
*/
function get_temp_login(data,callback){
var loadT = bt.load('Get temporary authorization list, please wait...');
bt.send('get_temp_login','config/get_temp_login',data,function(res){
if(res.status === false){
layer.closeAll();
bt.msg(res);
return false;
}
loadT.close();
if(callback) callback(res)
});
}
/**
* @description 设置临时链接
* @param {Function} callback 回调函数列表
* @returns void
*/
function set_temp_login(callback){
var loadT = bt.load('Setting temporary links, please wait...');
bt.send('set_temp_login','config/set_temp_login',{},function(res){
loadT.close();
if(callback) callback(res)
});
}
/**
* @description 设置临时链接
* @param {Object} data 传入参数,id
* @param {Function} callback 回调函数列表
* @returns void
*/
function remove_temp_login(data,callback){
var loadT = bt.load('Deleting temporary authorization record, please wait...');
bt.send('remove_temp_login','config/remove_temp_login',{id:data.id},function(res){
loadT.close();
if(callback) callback(res)
});
}
/**
* @description 强制用户登出
* @param {Object} data 传入参数,id
* @param {Function} callback 回调函数列表
* @returns void
*/
function clear_temp_login(data,callback){
var loadT = bt.load('Forcing user to log out, please wait...');
bt.send('clear_temp_login','config/clear_temp_login',{id:data.id},function(res){
loadT.close();
if(callback) callback(res)
});
}
/**
* @description 渲染授权管理列表
* @param {Object} data 传入参数,id
* @param {Function} callback 回调函数列表
* @returns void
*/
function reader_temp_list(data,callback){
if(typeof data == 'function') callback = data,data = {p:1};
get_temp_login(data,function(rdata){
var html = '';
$.each(rdata.data,function(index,item){
html += '<tr><td>'+ (item.login_addr || 'Not login') +'</td><td>'+ (function(){
switch(item.state){
case 0:
return 'Not login';
break;
case 1:
return 'Logged in';
break;
case -1:
return 'Expired';
break;
}
}()) +'</td><td >'+ (item.login_time == 0?'Not login':bt.format_data(item.login_time)) +'</td><td>'+ bt.format_data(item.expire) +'</td><td style="text-align:right;">'+ (function(){
if(item.state != 1){
return '<a href="javascript:;" class="btlink remove_temp_login" data-ip="'+ item.login_addr +'" data-id="'+ item.id +'">Del</a>';
}
if(item.online_state){
return '<a href="javascript:;" class="btlink clear_temp_login" style="color:red" data-ip="'+ item.login_addr +'" data-id="'+ item.id +'">Force logout </a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="javascript:;" class="btlink logs_temp_login" data-ip="'+ item.login_addr +'" data-id="'+ item.id +'">Logs</a>';
}
return '<a href="javascript:;" class="btlink logs_temp_login" data-ip="'+ item.login_addr +'" data-id="'+ item.id +'">Logs</a>';
}()) +'</td></tr>';
});
$('#temp_login_view_tbody').html(html);
$('.temp_login_view_page').html(rdata.page);
if(callback) callback()
});
}
/**
* @description 获取操作日志
* @param {Object} data 传入参数,id
* @param {Function} callback 回调函数列表
* @returns void
*/
function get_temp_login_logs(data,callback){
var loadT = bt.load('Getting operation log, please wait...');
bt.send('clear_temp_login','config/get_temp_login_logs',{id:data.id},function(res){
loadT.close();
if(callback) callback(res)
});
}
/**
* @description 渲染操作日志
* @param {Object} data 传入参数,id
* @param {Function} callback 回调函数列表
* @returns void
*/
function reader_temp_login_logs(data,callback){
get_temp_login_logs(data,function(res){
var html = '';
$.each(res,function(index,item){
html += '<tr><td>'+ item.type +'</td><td>'+ item.addtime +'</td><td><span title="'+ item.log +'" style="white-space: pre;">'+ item.log +'</span></td></tr>';
});
if(callback) callback({tbody:html,data:res});
})
}
/**
* @description 设置临时链接
* @param {Function} callback 回调函数列表
* @returns void
*/
function get_temp_login_view(){
layer.open({
type: 1,
area:["700px",'600px'],
title: "Temporary authorization management",
closeBtn: 2,
shift: 5,
shadeClose: false,
content:'<div class="login_view_table pd15">'+
'<button class="btn btn-success btn-sm va0 create_temp_login" >Create authorization</button>'+
'<div class="divtable mt10">'+
'<table class="table table-hover">'+
'<thead><tr><th>Login IP</th><th>Status</th><th>Login time</th><th>Expiration time</th><th style="text-align:right;">Opt</th></tr></thead>'+
'<tbody id="temp_login_view_tbody"></tbody>'+
'</table>'+
'<div class="temp_login_view_page page"></div>'+
'</div>'+
'</div>',
success:function(){
reader_temp_list();
// 创建临时授权
$('.create_temp_login').click(function(){
bt.confirm({title:'Risk tips',msg:'<span style="color:red">Note 1: Abuse of temporary authorization may lead to security risks.</br>Note 2: Not publish temporary authorized connections in public</span></br>Temporary authorization connection is about to be created. Continue?'},function(){
layer.open({
type: 1,
area:'570px',
title: "Create temporary authorization",
closeBtn: 2,
shift: 5,
shadeClose: false,
content:'<div class="bt-form create_temp_view">'+
'<div class="line"><span class="tname" style="width: auto;">Temporary authorized address</span><div class="info-r ml0"><textarea id="temp_link" class="bt-input-text mr20" style="margin: 0px;width: 500px;height: 50px;line-height: 19px;"></textarea></div></div>'+
'<div class="line"><button type="submit" class="btn btn-success btn-sm btn-copy-temp-link" data-clipboard-text="">Copy address</button></div>'+
'<ul class="help-info-text c7"><li>The temporary authorization is valid within 1 hour after it is generated. It is a one-time authorization and will be invalid immediately after use</li><li>Use temporary authorization to log in to the panel within 1 hour. Do not publish temporary authorization connection in public</li><li>The authorized connection information is only displayed here once. If you forget it before use, please regenerate it</li></ul>'+
'</div>',
success:function(){
set_temp_login(function(res){
if(res.status){
var temp_link = location.origin+ '/login?tmp_token=' + res.token;
$('#temp_link').val(temp_link);
$('.btn-copy-temp-link').attr('data-clipboard-text',temp_link);
}
});
var clipboard = new ClipboardJS('.btn');
clipboard.on('success', function(e) {
bt.msg({status:true,msg:'Copy succeeded!'});
e.clearSelection();
});
clipboard.on('error', function(e) {
bt.msg({status:false,msg:'Copy failed, please copy address manually'});
});
},
end:function(){
reader_temp_list();
}
});
});
});
// 操作日志
$('#temp_login_view_tbody').on('click','.logs_temp_login',function(){
var id = $(this).data('id'),ip = $(this).data('ip');
layer.open({
type: 1,
area:['700px','550px'],
title:'Operation logs ['+ ip +']',
closeBtn: 2,
shift: 5,
shadeClose: false,
content:'<div class="pd15">'+
'<button class="btn btn-default btn-sm va0 refresh_login_logs">Refresh logs</button>'+
'<div class="divtable mt10 tablescroll" style="max-height: 420px;overflow-y: auto;border:none">'+
'<table class="table table-hover" id="logs_login_view_table">'+
'<thead><tr><th width="90px">Operation</th><th width="150px">Time</th><th>logs</th></tr></thead>'+
'<tbody ></tbody>'+
'</table>'+
'</div>'+
'</div>',
success:function(){
reader_temp_login_logs({id:id},function(data){
$('#logs_login_view_table tbody').html(data.tbody);
});
$('.refresh_login_logs').click(function(){
reader_temp_login_logs({id:id},function(data){
$('#logs_login_view_table tbody').html(data.tbody);
});
});
bt.fixed_table('logs_login_view_table');
}
});
});
//删除授权记录,仅未使用的授权记录
$('#temp_login_view_tbody').on('click','.remove_temp_login',function(){
var id = $(this).data('id');
bt.confirm({
title:'Remove unused licenses',
msg:'Delete unused authorization record, continue?'
},function(){
remove_temp_login({id:id},function(res){
reader_temp_list(function(){
bt.msg(res);
})
})
})
});
//强制下线,强制登录的用户下线
$('#temp_login_view_tbody').on('click','.clear_temp_login',function(){
var id = $(this).data('id'),ip= $(this).data('ip');
bt.confirm({
title:'Force logout [ '+ ip +' ]',
msg:'Confirm to force logout [ '+ ip +' ]?'
},function(){
clear_temp_login({id:id},function(res){
reader_temp_list(function(){
bt.msg(res);
});
});
})
});
// 分页操作
$('.temp_login_view_page').on('click','a',function(ev){
var href = $(this).attr('href'),reg = /([0-9]*)$/,page = reg.exec(href)[0];
reader_temp_list({p:page});
ev.stopPropagation();
ev.preventDefault();
});
}
});
}
+1 -1
View File
@@ -900,7 +900,7 @@ function toBackup(type){
sBody += '<p class="clearfix plan">\
<div class="textname pull-left mr20" style="margin-left: 29px; font-size: 14px;">'+lan.crontab.exclusion_rule+'</div>\
<div class="dropdown planBackupTo pull-left mr20">\
<span><textarea style=" height: 112px;width:300px;line-height:22px;" class="bt-input-text" type="text" name="sBody" id="exclude" placeholder="'+lan.crontab.exclusion_rule_tips+'\ndata/config.php\nstatic/upload\n *.log\n"></textarea></span>\
<span><textarea style=" height: 113px;width:300px;line-height:22px;" class="bt-input-text" type="text" name="sBody" id="exclude" placeholder="'+lan.crontab.exclusion_rule_tips+'\ndata/config.php\nstatic/upload\n *.log\n"></textarea></span>\
</div>\
</p>';
}
+27 -11
View File
@@ -18,26 +18,27 @@ var database = {
}
},
{
field: 'password', width: '15%', title: lan.database.add_pass, templet: function (item) {
var _html = '<span class="password" data-pw="' + item.password + '">**********</span>';
field: 'password', title: lan.database.add_pass, templet: function (item) {
var _html = '<span class="dataBase"><span class="password" data-pw="' + item.password + '">**********</span>';
_html += '<span onclick="bt.pub.show_hide_pass(this)" class="glyphicon glyphicon-eye-open cursor pw-ico" style="margin-left:10px"></span>';
_html += '<span class="ico-copy cursor btcopy" style="margin-left:10px" title="'+lan.database.copy_pass+'" data-pw="' + item.password + '" onclick="bt.pub.copy_pass(\'' + item.password + '\')"></span>';
_html += '<span class="ico-copy cursor btcopy" style="margin-left:10px" title="'+lan.database.copy_pass+'" data-pw="' + item.password + '" onclick="bt.pub.copy_pass(\'' + item.password + '\')"></span></span>';
return _html;
}
},
{
field: 'backup', title: lan.database.backup, templet: function (item) {
var backup = '';
var backup = '<span class="dataBase">';
var _msg = lan.database.backup_empty;
if (item.backup_count > 0) _msg = lan.database.backup_ok;
backup = "<a href='javascript:;' class='btlink' onclick=\"database.database_detail('" + item.id + "','" + item.name + "')\">" + _msg + "</a> | "
backup += "<a href='javascript:;' class='btlink' onclick=\"database.database_detail('" + item.id + "','" + item.name + "')\">" + _msg + "</a> | "
backup += "<a class='btlink' href=\"javascript:database.input_database('" + item.name + "');\" title='" + lan.database.input_title + "'>" + lan.database.input + "</a>";
backup += '</span>';
return backup;
}
},
{
field: 'ps', title: lan.database.add_ps, templet: function (item) {
var _ps = "<span class='c9 input-edit' onclick=\"bt.pub.set_data_by_key('databases','ps',this)\" >"
var _ps = "<span class='c9 input-edit webNote' onclick=\"bt.pub.set_data_by_key('databases','ps',this)\" >"
if (item.password) {
_ps += item.ps
} else {
@@ -48,18 +49,22 @@ var database = {
}
},
{
field: 'opt', width: 300, title: lan.database.operation, align: 'right', templet: function (item) {
var option = "<a href=\"javascript:;\" class=\"btlink\" onclick=\"bt.database.open_phpmyadmin('" + item.name + "','" + item.username + "','" + item.password + "')\" title=\""+lan.database.admin_title+"\">"+lan.database.admin+"</a> | ";
field: 'opt', title: lan.database.operation, align: 'right', templet: function (item) {
var option = "<span class=\"dataBase\"><a href=\"javascript:;\" class=\"btlink\" onclick=\"bt.database.open_phpmyadmin('" + item.name + "','" + item.username + "','" + item.password + "')\" title=\""+lan.database.admin_title+"\">"+lan.database.admin+"</a> | ";
option += "<a href=\"javascript:;\" class=\"btlink\" onclick=\"database.rep_tools('" + item.name + "')\" title=\""+lan.database.mysql_tools+"\">"+lan.database.tools+"</a> | ";
option += "<a href=\"javascript:;\" class=\"btlink\" onclick=\"bt.database.set_data_access('" + item.username + "')\" title=\""+lan.database.set_db_auth+"\">"+lan.database.auth+"</a> | ";
option += "<a href=\"javascript:;\" class=\"btlink\" onclick=\"database.set_data_pass(" + item.id + ",'" + item.username + "','" + item.password + "')\" title=\""+lan.database.edit_pass_title+"\">"+lan.database.edit_pass+"</a> | ";
option += "<a href=\"javascript:;\" class=\"btlink\" onclick=\"database.del_database(" + item.id + ",'" + item.name + "')\" title=\""+lan.database.del_title+"\">"+lan.database.del+"</a>";
option += "<a href=\"javascript:;\" class=\"btlink\" onclick=\"database.del_database(" + item.id + ",'" + item.name + "')\" title=\""+lan.database.del_title+"\">"+lan.database.del+"</a></span>";
return option;
}
},
],
data: rdata.data
})
});
$(window).resize(function() {
database.forSize();
});
database.forSize();
})
},
rep_tools: function (db_name, res) {
@@ -303,7 +308,11 @@ var database = {
var _tab = bt.render({
table: '#DataBackupList',
columns: [
{ field: 'name', title: lan.database.backup_name },
{ field: 'name', title: lan.database.backup_name, templet: function (item) {
var _opt = '<span class="btlink" style="display: inline-block;max-width: 265px;">'+item.name+'</span>'
return _opt;
}
},
{
field: 'size', title: lan.database.backup_size, templet: function (item) {
return bt.format_size(item.size);
@@ -325,6 +334,7 @@ var database = {
bt.database.backup_data(id, dataname, function (rdata) {
if (rdata.status) database.database_detail(id, dataname);
database.get_list();
if (!rdata.status) layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
})
})
}, 100)
@@ -431,5 +441,11 @@ var database = {
database.input_database(name);
});
});
},
//浏览器窗口大小变化时调整内容宽度
forSize:function(){
var ticket_with = $('#DataBody').parent().width(),
td_width = ticket_with*0.8-30-$('#DataBody th:eq(2)').width()-$('#DataBody th:eq(3)').width()-$('#DataBody th:eq(4)').width()-$('#DataBody th:eq(6)').width();
$('#DataBody .webNote').css('max-width',td_width);
}
}
+4434 -3689
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+27 -4
View File
@@ -1,6 +1,11 @@
bt.pub.check_install(function (rdata) {
if (rdata === false) bt.index.rec_install();
})
$("select[name='network-io']").change(function(){
var net_key = $(this).val();
if(net_key == 'all') net_key = '';
bt.set_cookie('network_io_key',net_key);
});
var interval_stop = false;
var index = {
warning_list:[],
@@ -245,7 +250,25 @@ var index = {
if (_lval > 100) _lval = 100;
index.set_val(_loadbox, { usage: _lval, items: load_arr })
_loadbox.parents('ul').data('data', net);
var net_key = bt.get_cookie('network_io_key');
if(net_key){
console.log(net_key,net.network[net_key])
net.up = net.network[net_key].up;
net.down = net.network[net_key].down;
net.downTotal = net.network[net_key].downTotal;
net.upTotal = net.network[net_key].upTotal;
net.downPackets = net.network[net_key].downPackets;
net.upPackets = net.network[net_key].upPackets;
net.downAll = net.network[net_key].downTotal;
net.upAll = net.network[net_key].upTotal;
}
var net_option = '<option value="all">All</option>';
$.each(net.network,function(k,v){
var act = (k == net_key)?'selected':'';
net_option += '<option value="'+k+'" '+act+'>'+k+'</option>';
});
$('select[name="network-io"]').html(net_option);
//刷新流量
$("#upSpeed").html(net.up + ' KB');
$("#downSpeed").html(net.down + ' KB');
@@ -484,8 +507,8 @@ var index = {
<div class="update_title"><i class="layui-layer-ico layui-layer-ico1"></i><span>'+lan.index.last_version_now+'</span></div>\
<div class="update_version">'+lan.index.this_version+'<a href="https://forum.aapanel.com/d/9-aapanel-linux-panel-6-1-5-installation-tutorial/36" target="_blank" class="btlink" title="'+lan.index.check_this_version_log+'">'+lan.index.bt_linux+ (rdata.msg.is_beta == 1 ? lan.index.test_version+' ' + rdata.msg.beta.version : lan.index.final_version+' ' + rdata.msg.version) + '</a>&nbsp;&nbsp;'+ lan.index.release_time + (rdata.msg.is_beta == 1 ? rdata.msg.beta.uptime : rdata.msg.uptime) + '</div>\
<div class="update_conter">\
<div class="update_tips">'+ (is_beta != 1 ? lan.index.test_version : lan.index.final_version) + lan.index.last_version_is + (result.msg.is_beta != 1 ? result.msg.beta.version : result.msg.version) + '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'+lan.index.update_time+'&nbsp;&nbsp;' + (is_beta != 1 ? result.msg.beta.uptime : result.msg.uptime) + '</div>\
'+ (is_beta !== 1 ? '<span>'+lan.index.update_verison_click+'<a href="javascript:;" onclick="index.beta_msg()" class="btlink btn_update_testPanel">'+lan.index.check_detail+'</a></span>' : '<span>'+lan.index.change_final_click+'<a href="javascript:;" onclick="index.to_not_beta()" class="btlink btn_update_testPanel">'+lan.index.change_final+'</a></span>') + '\
<div class="update_tips">'+ (is_beta != 1 ? lan.index.test_version : lan.index.final_version) + lan.index.last_version_is + (result.msg.is_beta != 1 ? result.msg.beta.version : result.msg.version) + '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'+lan.index.update_time+'&nbsp;&nbsp;' + (is_beta != 1 ? result.msg.beta.uptime : result.msg.uptime) + '</div>\
'+ (is_beta !== 1 ? '<span>'+lan.index.update_verison_click+'<a href="javascript:;" onclick="index.beta_msg()" class="btlink btn_update_testPanel">'+lan.index.check_detail+'</a></span>' : '<span>'+lan.index.change_final_click+'<a href="javascript:;" onclick="index.to_not_beta()" class="btlink btn_update_testPanel">&nbsp;&nbsp;'+lan.index.change_final+'</a></span>') + '\
</div>\
<div class="bt-form-submit-btn">\
<button type="button" class="btn btn-danger btn-sm btn-title" onclick="layer.closeAll()">'+ lan.public.cancel + '</button>\
@@ -547,7 +570,7 @@ var index = {
layer.closeAll();
bt.system.to_update(function (rdata) {
if (rdata.status) {
bt.msg({ msg: lan.index.update_ok, icon: 1 })
bt.msg({ msg: rdata.msg, icon: 1 })
$("#btversion").html(rdata.version);
$("#toUpdate").html('');
bt.system.reload_panel();
@@ -578,7 +601,7 @@ var index = {
bt.send('get_beta_logs', 'ajax/get_beta_logs', {}, function (data) {
var my_list = '';
new_load.close();
if(data.status === false){
if(data.status == false){
layer.msg(data.msg,{icon: 2});
return false;
}
+2 -5
View File
@@ -1,9 +1,6 @@
/*!
* jQuery Contextify v1.0.8 (http://contextify.js.org)
* jQuery Contextify v1.0.7 (http://contextify.js.org)
* Copyright (c) 2016 Adam Bouqdib
* Licensed under GPL-2.0 (http://abemedia.co.uk/license)
*/
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery,window)}(function(a,b){function c(b,c){this.element=b,this.options=a.extend({},e,c),this._defaults=e,this._name=d,this.init()}var d="contextify",e={items:[],action:"contextmenu",menuId:"contextify-menu",menuClass:"dropdown-menu",headerClass:"dropdown-header",dividerClass:"divider",before:!1},f=0,g=a(b);c.prototype.init=function(){var b=a.extend({},this.options,a(this.element).data());b.id=f,a(this.element).attr("data-contextify-id",b.id).on("contextmenu",function(c){c.preventDefault(),"function"==typeof b.before&&b.before(this,b);var d=a('<ul class="'+b.menuClass+'" role="menu" id="'+b.menuId+'" data-contextify-id="'+b.id+'"/>');d.data(b);var e,f=b.items.length;for(e=0;e<f;e++){var h=b.items[e],i=a("<li/>");if(h.divider)i.addClass(b.dividerClass);else if(h.header)i.addClass(b.headerClass),i.html(h.header);else{i.append("<a/>");var j=i.find("a");if(h.href&&j.attr("href",h.href),h.onclick&&(j.on("click",b,h.onclick),j.css("cursor","pointer")),h.data){for(var k in h.data)d.attr("data-"+k,h.data[k]);j.data(h.data)}j.html(h.text)}d.append(i)}var l=a("#"+b.menuId);l.length>0?l!==d&&l.replaceWith(d):a("body").append(d);var m=g.width(),n=g.height(),o=d.outerWidth(),p=d.outerHeight(),q=o+c.clientX<m?c.clientX:m-o,r=p+c.clientY<n?c.clientY:n-p;d.css("top",r).css("left",q).css("position","fixed").show();if($("#rmenu").is(":visible")) d.hide()}).parents().on("mouseup",function(){a("#"+b.menuId).hide()}),g.on("scroll",function(){a("#"+b.menuId).hide()}),f++},c.prototype.destroy=function(){var b=a(this.element),c=a.extend({},this.options,b.data());b.removeAttr("data-contextify-id").off("contextmenu").parents().off("mouseup",function(){a("#"+c.menuId).hide()}),g.off("scroll",function(){a("#"+c.menuId).hide()}),a("#"+c.menuId).remove()},a.fn[d]=function(b){return this.each(function(){a.data(this,"plugin_"+d)&&"[object String]"===Object.prototype.toString.call(b)?a.data(this,"plugin_"+d)[b]():a.data(this,"plugin_"+d)||a.data(this,"plugin_"+d,new c(this,b))})}});
//# sourceMappingURL=jquery.contextify.min.js.map
(function(factory){if(typeof define==="function"&&define.amd){define(["jquery"],factory)}else{factory(jQuery,window)}}(function($,window){var pluginName="contextify",defaults={items:[],action:"contextmenu",menuId:"contextify-menu",menuClass:"dropdown-menu",headerClass:"dropdown-header",dividerClass:"divider",before:false},contextifyId=0;function Plugin(element,options){this.element=element;this.options=$.extend({},defaults,options);this._defaults=defaults;this._name=pluginName;this.init()}Plugin.prototype.init=function(){var options=$.extend({},this.options,$(this.element).data()),that=$(this);options.id=contextifyId;$(this.element).attr("data-contextify-id",options.id).on("contextmenu",function(e){e.preventDefault();if(typeof(options.before)==="function"){options.before(this,options)}var menu=$('<ul class="'+options.menuClass+'" role="menu" id="'+options.menuId+'" data-contextify-id="'+options.id+'"/>');menu.data(options);var l=options.items.length;var i;for(i=0;i<l;i++){var item=options.items[i];var el=$("<li/>");if(item.divider){el.addClass(options.dividerClass)}else{if(item.header){el.addClass(options.headerClass);el.html(item.header)}else{el.append("<a/>");var a=el.find("a");if(item.href){a.attr("href",item.href)}if(item.onclick){a.on("click",options,item.onclick);a.css("cursor","pointer")}if(item.data){for(var data in item.data){menu.attr("data-"+data,item.data[data])}a.data(item.data)}a.html(item.text)}}menu.append(el)}var currentMenu=$("#"+options.menuId);if(currentMenu.length>0){if(currentMenu!==menu){currentMenu.replaceWith(menu)}}else{$("body").append(menu)}var clientTop=$(window).scrollTop()+e.clientY,x=(menu.width()+e.clientX<$(window).width())?e.clientX:e.clientX-menu.width(),y=(menu.height()+e.clientY<$(window).height())?clientTop:clientTop-menu.height();menu.css("top",y).css("left",x).css("position","fixed").show();$(document).one("click",function(e){$("#"+options.menuId).hide();e.preventDefault()})}).one("click",function(e){$("#"+options.menuId).hide();e.preventDefault()});contextifyId++};Plugin.prototype.destroy=function(){var el=$(this.element),options=$.extend({},this.options,el.data()),menu=$("#"+options.menuId);el.removeAttr("data-contextify-id").off("contextmenu").parents().off("mouseup",function(){menu.hide()});menu.remove()};$.fn[pluginName]=function(options){return this.each(function(){if($.data(this,"plugin_"+pluginName)&&Object.prototype.toString.call(options)==="[object String]"){$.data(this,"plugin_"+pluginName)[options]()}else{if(!$.data(this,"plugin_"+pluginName)){$.data(this,"plugin_"+pluginName,new Plugin(this,options))}}})}}));
+311 -70
View File
@@ -1,7 +1,103 @@
$(document).ready(function() {
$(".sub-menu a.sub-menu-a").click(function() {
$(this).next(".sub").slideToggle("slow").siblings(".sub:visible").slideUp("slow");
$(function(){
$.fn.extend({
fixedThead:function(options){
var _that = $(this);
console.log(_that);
var option = {
height:400,
shadow:true,
resize:true
};
options = $.extend(option,options);
if($(this).find('table').length === 0){
return false;
}
var _height = $(this)[0].style.height,_table_config = _height.match(/([0-9]+)([%\w]+)/);
if(_table_config === null){
_table_config = [null,options.height,'px'];
}else{
$(this).css({
'boxSizing': 'content-box',
'paddingBottom':$(this).find('thead').height()
});
}
$(this).css({'position':'relative'});
var _thead = $(this).find('thead')[0].outerHTML,
_tbody = $(this).find('tbody')[0].outerHTML,
_thead_div = $('<div class="thead_div"><table class="table table-hover mb0"></table></div>'),
_shadow_top = $('<div class="tbody_shadow_top"></div>'),
_tbody_div = $('<div class="tbody_div" style="height:'+ _table_config[1] + _table_config[2] +';"><table class="table table-hover mb0" style="margin-top:-'+ $(this).find('thead').height() +'px"></table></div>'),
_shadow_bottom = $('<div class="tbody_shadow_bottom"></div>');
_thead_div.find('table').append(_thead);
_tbody_div.find('table').append(_thead);
_tbody_div.find('table').append(_tbody);
$(this).html('');
$(this).append(_thead_div);
$(this).append(_shadow_top);
$(this).append(_tbody_div);
$(this).append(_shadow_bottom);
var _table_width = _that.find('.thead_div table')[0].offsetWidth,
_body_width = _that.find('.tbody_div table')[0].offsetWidth,
_length = _that.find('tbody tr:eq(0)>td').length;
$(this).find('tbody tr:eq(0)>td').each(function(index,item){
var _item = _that.find('thead tr:eq(0)>th').eq(index);
if(index === (_length-1)){
_item.attr('width',$(item)[0].clientWidth + (_table_width - _body_width));
}else{
_item.attr('width',$(item)[0].offsetWidth);
}
});
if(options.resize){
$(window).resize(function(){
var _table_width = _that.find('.thead_div table')[0].offsetWidth,
_body_width = _that.find('.tbody_div table')[0].offsetWidth,
_length = _that.find('tbody tr:eq(0)>td').length;
_that.find('tbody tr:eq(0)>td').each(function(index,item){
var _item = _that.find('thead tr:eq(0)>th').eq(index);
if(index === (_length-1)){
_item.attr('width',$(item)[0].clientWidth + (_table_width - _body_width));
}else{
_item.attr('width',$(item)[0].offsetWidth);
}
});
});
}
if(options.shadow){
var table_body = $(this).find('.tbody_div')[0];
if(_table_config[1] >= table_body.scrollHeight){
$(this).find('.tbody_shadow_top').hide();
$(this).find('.tbody_shadow_bottom').hide();
}else{
$(this).find('.tbody_shadow_top').hide();
$(this).find('.tbody_shadow_bottom').show();
}
$(this).find('.tbody_div').scroll(function(e){
var _scrollTop = $(this)[0].scrollTop,
_scrollHeight = $(this)[0].scrollHeight,
_clientHeight = $(this)[0].clientHeight,
_shadow_top = _that.find('.tbody_shadow_top'),
_shadow_bottom = _that.find('.tbody_shadow_bottom');
if(_scrollTop == 0){
_shadow_top.hide();
_shadow_bottom.show();
}else if(_scrollTop > 0 && _scrollTop < (_scrollHeight - _clientHeight)){
_shadow_top.show();
_shadow_bottom.show();
}else if(_scrollTop == (_scrollHeight - _clientHeight)){
_shadow_top.show();
_shadow_bottom.hide();
}
})
}
}
});
}(jQuery))
$(document).ready(function() {
$(".sub-menu a.sub-menu-a").click(function() {
$(this).next(".sub").slideToggle("slow").siblings(".sub:visible").slideUp("slow");
});
});
var aceEditor = {
layer_view: '',
@@ -83,57 +179,67 @@ var aceEditor = {
// 事件编辑器-方法,事件绑定
eventEditor: function() {
var _this = this,_icon = '<span class="icon"><i class="glyphicon glyphicon-ok" aria-hidden="true"></i></span>';
$(window).resize(function() {
var _id = $('.ace_conter_menu .active').attr('data-id');
if (_id != undefined) {
aceEditor.editor['ace_editor_' + _id].ace.resize();
//_this.setEditorView()
$(window).resize(function(){
if(_this.ace_active != undefined) _this.setEditorView()
if( $('.aceEditors .layui-layer-maxmin').length >0){
$('.aceEditors').css({
'top':0,
'left':0,
'width':$(this)[0].innerWidth,
'height':$(this)[0].innerHeight
});
}
});
$('.ace_editor_main').on('click',function(){
})
$(document).click(function(e){
$('.ace_toolbar_menu').hide();
$('.ace_conter_editor .ace_editors').css('fontSize', _this.aceConfig.aceEditor.fontSize + 'px');
$('.ace_toolbar_menu .menu-tabs,.ace_toolbar_menu .menu-encoding,.ace_toolbar_menu .menu-files').hide();
});
$('.ace_editor_main').on('click',function(){
$('.ace_toolbar_menu').hide();
});
$(document).click(function(e) {
$('.ace_toolbar_menu').hide();
$('.ace_toolbar_menu .menu-tabs,.ace_toolbar_menu .menu-encoding,.ace_toolbar_menu .menu-files').hide();
})
// 显示工具条
$('.ace_header .pull-down').click(function() {
if ($(this).find('i').hasClass('glyphicon-menu-down')) {
$('.ace_header').css({ 'marginTop': '-35px', 'height': '0' });
$(this).css({ 'top': '35px', 'height': '40px', 'line-height': '40px' });
$(this).find('i').addClass('glyphicon-menu-up').removeClass('glyphicon-menu-down');
} else {
$('.ace_header').removeAttr('style');
$('.ace_toolbar_menu').click(function(e){
e.stopPropagation();
e.preventDefault();
});
// 显示工具条
$('.ace_header .pull-down').click(function(){
if($(this).find('i').hasClass('glyphicon-menu-down')){
$('.ace_header').css({'top':'-35px'});
$('.ace_overall').css({'top':'0'});
$(this).css({'top':'35px','height':'40px','line-height':'40px'});
$(this).find('i').addClass('glyphicon-menu-up').removeClass('glyphicon-menu-down');
}else{
$('.ace_header').css({'top':'0'});
$('.ace_overall').css({'top':'35px'});
$(this).removeAttr('style');
$(this).find('i').addClass('glyphicon-menu-down').removeClass('glyphicon-menu-up');
}
_this.setEditorView();
});
$(this).find('i').addClass('glyphicon-menu-down').removeClass('glyphicon-menu-up');
}
_this.setEditorView();
});
// 切换TAB视图
$('.ace_conter_menu').on('click', '.item', function(e) {
var _id = $(this).attr('data-id'),
_item = _this.editor['ace_editor_' + _id]
$('.item_tab_' + _id).addClass('active').siblings().removeClass('active');
$('#ace_editor_' + _id).addClass('active').siblings().removeClass('active');
_this.ace_active = _id;
_this.currentStatusBar(_id);
_this.is_file_history(_item);
});
// 移上TAB按钮变化,仅文件被修改后
$('.ace_conter_menu').on('mouseover', '.item .icon-tool', function() {
var type = $(this).attr('data-file-state');
if (type != '0') {
$(this).removeClass('glyphicon-exclamation-sign').addClass('glyphicon-remove');
}
});
// 移出tab按钮变化,仅文件被修改后
$('.ace_conter_menu').on('mouseout', '.item .icon-tool', function() {
var type = $(this).attr('data-file-state');
if (type != '0') {
$(this).removeClass('glyphicon-remove').addClass('glyphicon-exclamation-sign');
}
});
$('.ace_conter_menu').on('click', '.item', function (e) {
var _id = $(this).attr('data-id'),_item = _this.editor['ace_editor_' + _id];
$('.item_tab_'+ _id).addClass('active').siblings().removeClass('active');
$('#ace_editor_'+ _id).addClass('active').siblings().removeClass('active');
_this.ace_active = _id;
_this.currentStatusBar(_id);
_this.is_file_history(_item);
});
// 移上TAB按钮变化,仅文件被修改后
$('.ace_conter_menu').on('mouseover', '.item .icon-tool', function () {
var type = $(this).attr('data-file-state');
if (type != '0') {
$(this).removeClass('glyphicon-exclamation-sign').addClass('glyphicon-remove');
}
});
// 移出tab按钮变化,仅文件被修改后
$('.ace_conter_menu').on('mouseout', '.item .icon-tool', function () {
var type = $(this).attr('data-file-state');
if (type != '0') {
$(this).removeClass('glyphicon-remove').addClass('glyphicon-exclamation-sign');
}
});
// 关闭编辑视图
$('.ace_conter_menu').on('click', '.item .icon-tool', function(e) {
var file_type = $(this).attr('data-file-state');
@@ -192,8 +298,16 @@ var aceEditor = {
});
break;
}
e.stopPropagation();
$('.ace_toolbar_menu').hide();
$('.ace_toolbar_menu .menu-tabs,.ace_toolbar_menu .menu-encoding,.ace_toolbar_menu .menu-files').hide();
e.stopPropagation();
e.preventDefault();
});
$(window).keyup(function(e){
if(e.keyCode === 116 && $('#ace_conter').length == 1){
layer.msg('Unable to refresh in editor mode. Please close and try again');
}
});
// 新建编辑器视图
$('.ace_editor_add').click(function() {
_this.addEditorView();
@@ -327,7 +441,7 @@ var aceEditor = {
_this.searchRelevance()
});
// 顶部状态栏
$('.ace_header span').click(function(e) {
$('.ace_header>span').click(function(e) {
var type = $(this).attr('class'),
editor_item = _this.editor['ace_editor_' + _this.ace_active];
var _icon = '<span class="icon"><i class="glyphicon glyphicon-ok" aria-hidden="true"></i></span>';
@@ -2095,7 +2209,8 @@ function format_form_data(form_data){
function ajax_encrypt(request){
if(!this.type || !this.data || !this.contentType) return;
if($("#panel_debug").attr("data") == 'True') return;
if($("#panel_debug").attr("data") == 'True') return;
if($("#panel_debug").attr("data-pyversion") == '2') return;
if(this.type == 'POST' && this.data.length > 1){
this.data = format_form_data(this.data);
}
@@ -2118,8 +2233,8 @@ function ajaxSetup() {
if (my_headers) {
$.ajaxSetup({
headers: my_headers,
dataFilter: ajax_decrypt,
beforeSend: ajax_encrypt
// dataFilter: ajax_decrypt,
// beforeSend: ajax_encrypt
});
}
}
@@ -2269,6 +2384,11 @@ function GetDiskList(b) {
var a = "";
var c = "path=" + b + "&disk=True";
$.post("/files?action=GetDir", c, function(h) {
if(h.status == false) {
layer.close(layer.index);
layer.msg(h.msg,{icon: 2});
return false;
}
if (h.DISK != undefined) {
for (var f = 0; f < h.DISK.length; f++) {
a += "<dd onclick=\"GetDiskList('" + h.DISK[f].path + "')\"><span class='glyphicon glyphicon-hdd'></span>&nbsp;" + h.DISK[f].path + "</dd>"
@@ -2995,7 +3115,7 @@ function setUserName(a) {
var checks = ['admin', 'root', 'admin123', '123456'];
if ($.inArray(p1, checks) >= 0) {
layer.msg(lan.index.usually_username_ban, {
layer.msg(lan.public.usually_username_ban, {
icon: 2
});
return;
@@ -3812,7 +3932,7 @@ var Term = {
route: '/webssh', //被访问的方法
term: null,
term_box: null,
ssh_info: null,
ssh_info: {},
last_body:false,
last_cd:null,
config:{
@@ -3864,8 +3984,8 @@ var Term = {
//连接服务器成功
on_open:function(ws_event){
Term.send(JSON.stringify(Term.ssh_info || {}))
Term.term.FitAddon.fit();
Term.resize();
// Term.term.FitAddon.fit();
// Term.resize();
var f_path = $("#fileInputPath").val();
if(f_path){
Term.last_cd = "cd " + f_path;
@@ -3892,7 +4012,13 @@ var Term = {
// }
// },
on_message: function (ws_event) {
result = ws_event.data;
result = ws_event.data;
if ((result.indexOf("@127.0.0.1:") != -1 || result.indexOf("@localhost:") != -1) && result.indexOf('Authentication failed') != -1) {
Term.term.write(result);
Term.localhost_login_form(result);
Term.close();
return;
}
if(Term.last_cd){
if(result.indexOf(Term.last_cd) != -1 && result.length - Term.last_cd.length < 3) {
Term.last_cd = null;
@@ -3956,7 +4082,7 @@ var Term = {
Term.term.FitAddon.fit()
Term.send(JSON.stringify({resize:1,rows:Term.term.rows,cols:Term.term.cols}));
Term.term.focus();
},200)
},100)
},
// resize: function() {
// var m_width = 100;
@@ -4046,26 +4172,26 @@ var Term = {
],function(){
layer.close(loadT);
Term.term = new Terminal({
rendererType: "canvas",
cols: 100,
rows: 34,
fontSize:15,
screenKeys: true,
useStyle: true ,
});
rendererType: "canvas",
cols: 100,
rows: 31,
fontSize:15,
screenKeys: true,
useStyle: true ,
});
Term.term.setOption('cursorBlink', true);
Term.last_body = false;
Term.term_box = layer.open({
type: 1,
title: lan.public.terminal,
area: ['920px', '630px'],
area: ['925px', '630px'],
closeBtn: 2,
shadeClose: false,
skin:'term_box_all',
content: '<link rel="stylesheet" href="/static/css/xterm.css" />\
<div class="term-box" style="background-color:#000" id="term"></div>',
<div class="term-box" style="background-color:#000;padding-top: 7px;" id="term"></div>',
cancel: function (index,lay) {
bt.confirm({msg:'Closing the SSH session, the command in progress in the current command line session may be aborted. Continute?',title: "Cofirm to close the SSH session?"},function(ix){
bt.confirm({msg:'<div style="word-break: break-word;">Closing the SSH session, the command in progress in the current command line session may be aborted. Continute?</div>',title: "Cofirm to close the SSH session?"},function(ix){
Term.term.dispose();
layer.close(index);
layer.close(ix);
@@ -4080,6 +4206,7 @@ var Term = {
Term.term.loadAddon(Term.term.FitAddon);
Term.term.WebLinksAddon = new WebLinksAddon.WebLinksAddon()
Term.term.loadAddon(Term.term.WebLinksAddon)
Term.term.focus();
}
});
Term.term.onData(function (data) {
@@ -4114,7 +4241,121 @@ var Term = {
Term.term.scrollToBottom();
Term.term.focus();
});
},
localhost_login_form:function(result){
var template = '<div class="localhost-form-shade"><div class="localhost-form-view bt-form-2x"><div class="localhost-form-title"><i class="localhost-form_tip"></i><span style="vertical-align: middle;">Login failed, please fill the local server information!</span></div>\
<div class="line input_group">\
<span class="tname">Server IP</span>\
<div class="info-r">\
<input type="text" name="host" class="bt-input-text mr5" style="width:240px" placeholder="Server IP" value="127.0.0.1" autocomplete="off" />\
<input type="text" name="port" class="bt-input-text mr5" style="width:60px" placeholder="Port" value="22" autocomplete="off"/>\
</div>\
</div>\
<div class="line">\
<span class="tname">SSH account</span>\
<div class="info-r">\
<input type="text" name="username" class="bt-input-text mr5" style="width:305px" placeholder="SSH account" value="root" autocomplete="off"/>\
</div>\
</div>\
<div class="line">\
<span class="tname">Verification</span>\
<div class="info-r ">\
<div class="btn-group">\
<button type="button" tabindex="-1" class="btn btn-sm auth_type_checkbox btn-success" data-ctype="0">Password</button>\
<button type="button" tabindex="-1" class="btn btn-sm auth_type_checkbox btn-default data-ctype="1">Server key</button>\
</div>\
</div>\
</div>\
<div class="line c_password_view show">\
<span class="tname">Password</span>\
<div class="info-r">\
<input type="text" name="password" class="bt-input-text mr5" placeholder="SSH Password" style="width:305px;" value="" autocomplete="off"/>\
</div>\
</div>\
<div class="line c_pkey_view hidden">\
<span class="tname">Private key</span>\
<div class="info-r">\
<textarea rows="4" name="pkey" class="bt-input-text mr5" placeholder="SSH server key" style="width:305px;height: 80px;line-height: 18px;padding-top:10px;"></textarea>\
</div>\
</div><button type="submit" class="btn btn-sm btn-success">Login</button></div></div>';
$('.term-box').after(template);
$('.auth_type_checkbox').click(function(){
var index = $(this).index();
$(this).addClass('btn-success').removeClass('btn-default').siblings().removeClass('btn-success').addClass('btn-default')
switch(index){
case 0:
$('.c_password_view').addClass('show').removeClass('hidden');
$('.c_pkey_view').addClass('hidden').removeClass('show').find('input').val('');
break;
case 1:
$('.c_password_view').addClass('hidden').removeClass('show').find('input').val('');
$('.c_pkey_view').addClass('show').removeClass('hidden');
break;
}
});
$('.localhost-form-view > button').click(function(){
var form = {};
$('.localhost-form-view input,.localhost-form-view textarea').each(function(index,el){
var name = $(this).attr('name'),value = $(this).val();
form[name] = value;
switch(name){
case 'port':
if(!bt.check_port(value)){
bt.msg({status:false,msg:'Server port format error!'});
return false;
}
break;
case 'username':
if(value == ''){
bt.msg({status:false,msg:'Server user name cannot be empty!'});
return false;
}
break;
case 'password':
if(value == '' && $('.c_password_view').hasClass('show')){
bt.msg({status:false,msg:'Server password cannot be empty!'});
return false;
}
break;
case 'pkey':
if(value == '' && $('.c_pkey_view').hasClass('show')){
bt.msg({status:false,msg:'The server key cannot be empty!'});
return false;
}
break;
}
});
form.ps = 'Local server';
if(result){
if(result.indexOf('@127.0.0.1') != -1){
var user = result.split('@')[0].split(',')[1];
var port = result.split('1:')[1]
$("input[name='username']").val(user);
$("input[name='port']").val(port);
}
}
var loadT = bt.load('Adding server information, please wait...');
bt.send('create_host','xterm/create_host',form,function(res){
loadT.close();
bt.msg(res);
if(res.status){
bt.msg({status:true,msg:'Login successful!'});
$('.layui-layer-shade').remove();
$('.term_box_all').remove();
Term.term.dispose();
Term.close();
web_shell();
}
});
});
$('.localhost-form-view [name="password"]').keyup(function(e){
if(e.keyCode == 13){
$('.localhost-form-view > button').click();
}
}).focus()
}
}
function web_shell() {
File diff suppressed because it is too large Load Diff
+1589 -584
View File
File diff suppressed because it is too large Load Diff
+727 -78
View File
@@ -7,45 +7,33 @@ var soft = {
if (search == undefined || search == 'null' || search == 'undefined' || search == '') search = undefined;
var _this = this;
var istype = getCookie('softType');
if (istype == 'undefined' || istype == 'null' || !istype) {
if(istype == 'undefined' || istype == 'null' || !istype){
istype = 0;
}
if (type == 0) type = bt.get_cookie('softType');
if (page == 0) page = bt.get_cookie('p' + type);
if (type == '11') {
soft.get_dep_list(1)
if (type == '11'){
soft.get_dep_list(1);
return;
}
soft.is_install = false;
console.log(type)
bt.soft.get_soft_list(page, type, search, function(rdata) {
if (rdata.pro < 0) {
$("#updata_pro_info").html('');
} else if (rdata.pro === -2) {
$("#updata_pro_info").html('<div class="alert alert-success" style="margin-bottom:15px"><strong>' + lan.soft.pro_expire + '</strong><button class="btn btn-success btn-xs va0 updata_pro" onclick="bt.soft.updata_pro()" title="' + lan.soft.renew_pro + '" style="margin-left:8px">' + lan.soft.renew_now + '</button>');
} else if (rdata.pro === -1) {
$("#updata_pro_info").html('<div class="alert alert-success" style="margin-bottom:15px"><strong > ' + lan.soft.upgrade_pro + '</strong><button class="btn btn-success btn-xs va0 updata_pro" onclick="bt.soft.updata_pro()" title="' + lan.soft.upgrade_pro_now + '" style="margin-left:8px">' + lan.soft.upgrade_now + '</button>\</div>');
}
soft.set_soft_tips('#updata_pro_info',type);
// if (rdata.pro < 0) {
// $("#updata_pro_info").html('');
// } else if (rdata.pro === -2) {
// $("#updata_pro_info").html('<div class="alert alert-success" style="margin-bottom:15px"><strong>' + lan.soft.pro_expire + '</strong><button class="btn btn-success btn-xs va0 updata_pro" onclick="bt.soft.updata_pro()" title="' + lan.soft.renew_pro + '" style="margin-left:8px">' + lan.soft.renew_now + '</button>');
// } else if (rdata.pro === -1) {
// $("#updata_pro_info").html('<div class="alert alert-success" style="margin-bottom:15px"><strong > ' + lan.soft.upgrade_pro + '</strong><button class="btn btn-success btn-xs va0 updata_pro" onclick="bt.soft.updata_pro()" title="' + lan.soft.upgrade_pro_now + '" style="margin-left:8px">' + lan.soft.upgrade_now + '</button>\</div>');
// }
if (type == 10) {
$("#updata_pro_info").html('<div class="alert alert-danger" style="margin-bottom:15px"><strong>' + lan.soft.bt_developer + '</strong><a class="btn btn-success btn-xs va0" href="https://www.aapanel.com" title="' + lan.soft.get_third_party_apps + '" style="margin-left: 8px" target="_blank">' + lan.soft.get_third_party_apps + '</a><input type="file" style="display:none;" accept=".zip,.tar.gz" id="update_zip" multiple="multiple"><button class="btn btn-success btn-xs" onclick="soft.update_zip_open()" style="margin-left:8px">' + lan.soft.import_plug + '</button></div>')
} else if (type == 11) {
$("#updata_pro_info").html('<div class="alert alert-info" style="margin-bottom:15px"><strong>' + lan.soft.comingsoon + '</strong></div>')
}
// if (type == 10) {
// $("#updata_pro_info").html('<div class="alert alert-danger" style="margin-bottom:15px"><strong>' + lan.soft.bt_developer + '</strong><a class="btn btn-success btn-xs va0" href="https://www.aapanel.com" title="' + lan.soft.get_third_party_apps + '" style="margin-left: 8px" target="_blank">' + lan.soft.get_third_party_apps + '</a><input type="file" style="display:none;" accept=".zip,.tar.gz" id="update_zip" multiple="multiple"><button class="btn btn-success btn-xs" onclick="soft.update_zip_open()" style="margin-left:8px">' + lan.soft.import_plug + '</button></div>')
// } else if (type == 11) {
// $("#updata_pro_info").html('<div class="alert alert-info" style="margin-bottom:15px"><strong>' + lan.soft.comingsoon + '</strong></div>')
// }
var tBody = '';
rdata.type.unshift({
icon: 'icon',
id: 0,
ps: lan.soft.all,
sort: 1,
title: lan.soft.all
}, {
icon: 'icon',
id: -1,
ps: 'Installed',
sort: 1,
title: 'Installed'
})
rdata.type.unshift({icon: 'icon',id: 0,ps: lan.soft.all,sort: 1,title: lan.soft.all}, {icon: 'icon',id: -1,ps: 'Installed',sort: 1,title: 'Installed'})
for (var i = 0; i < rdata.type.length; i++) {
var c = '';
if (istype == rdata.type[i].id) {
@@ -53,7 +41,7 @@ var soft = {
}
// 注释软件管理的付费插件,第三方插件,一键部署
// if (rdata.type[i].id != "11" && rdata.type[i].id != "10" && rdata.type[i].id != "8") {
if (rdata.type[i].id != "11" && rdata.type[i].id != "8") {
if (rdata.type[i].id != "11") {
tBody += '<span typeid="' + rdata.type[i].id + '" ' + c + '>' + rdata.type[i].title + '</span>';
}
}
@@ -130,7 +118,7 @@ var soft = {
{
field: 'price',
title: 'Developer',
width: 92,
width: 110,
templet: function(item) {
if (!item.author) return 'official'
return item.author;
@@ -164,17 +152,17 @@ var soft = {
templet: function(item) {
var price = lan.soft.free;
if (item.price > 0) {
price = '<span style="color:#fc6d26">' + item.price + '</span>';
price = '<span style="color:#fc6d26">$' + item.price + '</span>';
}
return price;
}
},
(type == 10 ? {
field: 'sort',
width: 60,
title: 'Score',
width: 80,
title: 'Rated',
templet: function(item) {
return item.sort !== undefined ? ('<a href="javascript:;" onclick="score.open_score_view(' + item.pid + ',\'' + item.title + '\',' + item.count + ')" class="btlink open_sort_view">' + (item.sort <= 0 || item.sort > 5 ? '无评分' : item.sort.toFixed(1)) + '</a>') : '--';
return item.sort !== undefined ? ('<a href="javascript:;" onclick="score.open_score_view(' + item.pid + ',\'' + item.title + '\',' + item.count + ')" class="btlink open_sort_view">' + (item.sort <= 0 || item.sort > 5 ? lan.soft.not_rated : item.sort.toFixed(1)) + '</a>') : '--';
}
} : ''),
{
@@ -186,9 +174,9 @@ var soft = {
if (item.pid > 0) {
if (item.endtime > 0) {
if (item.type != 10) {
endtime = bt.format_data(item.endtime, 'yyyy/MM/dd') + '<a class="btlink" onclick="bt.soft.re_plugin_pay(\'' + item.title + '\',\'' + item.pid + '\',1)"> (' + lan.soft.renew + ')</a>';
endtime = bt.format_data(item.endtime, 'yyyy/MM/dd') ;
} else {
endtime = bt.format_data(item.endtime, 'yyyy/MM/dd') + '<a class="btlink" onclick="bt.soft.re_plugin_pay_other(\'' + item.title + '\',\'' + item.pid + '\',1,' + item.price + ')"> (' + lan.soft.renew + ')</a>';
endtime = bt.format_data(item.endtime, 'yyyy/MM/dd') ;
}
} else if (item.endtime === 0) {
endtime = lan.soft.permanent;
@@ -196,9 +184,9 @@ var soft = {
endtime = lan.soft.not_open;
} else if (item.endtime === -2) {
if (item.type != 10) {
endtime = lan.soft.already_expire + '<a class="btlink" onclick="bt.soft.re_plugin_pay(\'' + item.title + '\',\'' + item.pid + '\',1)"> (' + lan.soft.renew + ')</a>';
endtime = lan.soft.already_expire ;
} else {
endtime = lan.soft.already_expire + '<a class="btlink" onclick="bt.soft.re_plugin_pay_other(\'' + item.title + '\',\'' + item.pid + '\',1,' + item.price + ')"> (' + lan.soft.renew + ')</a>';
endtime = lan.soft.already_expire ;
}
}
}
@@ -270,7 +258,7 @@ var soft = {
break;
}
if (item.type != 10) {
pay_opt = '<a class="btlink" onclick="bt.soft.re_plugin_pay(\'' + item.title + '\',\'' + item.pid + '\',' + re_status + ')">' + re_msg + '</a>';
pay_opt = '<a class="btlink" onclick=\'bt.soft.product_pay_view('+ JSON.stringify({name:item.title,pid:item.pid,type:item.type,plugin:true,renew:item.endtime}) +')\'>' + re_msg + '</a>';
} else {
pay_opt = '<a class="btlink" onclick="bt.soft.re_plugin_pay_other(\'' + item.title + '\',\'' + item.pid + '\',' + re_status + ',' + item.price + ')">' + re_msg + '</a>';
}
@@ -405,6 +393,191 @@ var soft = {
}
})
},
// 渲染列表
render_promote_list:function(data){
if($('#soft_recom_list').length > 0) $('#soft_recom_list').remove();
var html = $('<ul id="soft_recom_list" class="recom_list"></ul>'),that = this;
for(var i=0;i< data.length;i++){
var type = '', item = data[i];
(function(item){
switch (item.type) {
case 'link': // 链接推荐
type = $('<a href="'+ item.data +'" target="_blank" title="'+ (item.title || '') +'"><span>'+ (item.title || '') +'</span></a>');
break;
case 'soft': // 软件推荐
case 'other': // 第三方推荐
case 'onekey': // 一键部署推荐
type = $('<a href="javascript:;" class="btlink" title="'+ (item.title || '') +'"><span>'+ (item.title || '') +'</span></a>').click(function(){
that.render_promote_view(item);
});
break;
}
html.append($('<li></li>').append(type));
}(item))
// html.append($('<li><img src="'+ item.image +'"></li>').append(type));
}
$('#updata_pro_info').before(html);
},
// 渲染软件列表
render_promote_view:function(find){
var that = this,is_single_product = find.data.length > 1,find_data = find.data;
if(is_single_product){
layer.open({
title:find.title,
area:'800px',
btn:false,
closeBtn:2,
shadeClose:false,
content: (function(){
var html = '';
for(var i=0;i<find_data.length;i++){
var item = find_data[i],thtml = '';
if(!item.setup){
thtml = '<button type="button" class="btn btn-success btn-xs" onclick="bt.soft.install(\''+ item.name +'\',this)">Install</button>';
}else{
if(item.pid != 0){
if(item.endtime == 0){ //永久
thtml = '<button type="button" class="btn btn-success btn-xs" onclick="bt.soft.set_lib_config(\''+ item.name +'\',\''+ item.title +'\')">Setting</button>';
}else if(item.endtime > 0){ //已购买
thtml = '<button type="button" class="btn btn-success btn-xs" onclick="bt.soft.set_lib_config(\''+ item.name +'\',\''+ item.title +'\')">Setting</button>';
}else if(item.endtime == -1){ //未购买
thtml = '<button type="button" class="btn btn-success btn-xs" onclick=\'bt.soft.product_pay_view('+ JSON.stringify({name:item.title,pid:item.pid,type:item.type,pulgin:true,renew:item.endtime}) +');\'>Upgrade now</button>';
}else if(item.endtime == -2){ //已过期
thtml = '<button type="button" class="btn btn-success btn-xs" onclick=\'bt.soft.product_pay_view('+ JSON.stringify({name:item.title,pid:item.pid,type:item.type,pulgin:true,renew:item.endtime}) +');\'>立即续费</button>';
}
}else{
thtml = '<button type="button" class="btn btn-success btn-xs" onclick="bt.soft.set_lib_config(\''+ item.name +'\',\''+ item.title +'\')">Setting</button>';
}
}
html += '<div class="recom_item_box">' +
'<div class="recom_item_left">' +
'<div class="recom_item_images"><img src="/static/img/'+(find.type == 'onekey'?'dep_ico':'soft_ico')+'/ico-'+ item.name +'.png" /></div>' +
'<div class="recom_item_pay"><a href="javascript:;" class="btlink" style="color:'+(item.setup?'#20a53a':'#666')+'">'+ (item.setup?'Installed':'Not installed') +'</a></div>'+
'</div>' +
'<div class="recom_item_right">' +
'<div class="recom_item_title">' +
'<div class="recom_item_text">'+ item.title + '&nbsp;v'+ item.version +'</div>' +
'<div class="recom_item_price">$<span>'+ item.price +'</span>/month</div>' +
'</div>' +
'<div class="recom_item_info" title="'+ item.ps +'">'+ item.ps +'</div>'+
'<div class="recom_item_btn">'+ thtml +'</div>'+
'</div>' +
'</div>'
}
return html;
})(),
});
}
},
set_soft_tips:function(el,type){
var tips_info = $('<div class="alert" style="margin-bottom:15px"><div class="soft_tips_text"></div><div class="btn-ground" style="display:inline-block;"></div></div>'), explain = tips_info.find('.soft_tips_text'), btn_ground = tips_info.find('.btn-ground');
$(el).empty();
type = parseInt(type);
if(type != 11) $(el).next('.onekey-menu-sub').remove();
if(type == 10){
explain.text('Security Reminder: aaPanel officially conducted a security audit before the third-party plug-in was put on the shelves, but there may be security risks. Please check it out before using it in the production environment.');
btn_ground = soft.render_tips_btn(btn_ground,[
//{title:'免费入驻',href:'https://www.bt.cn/developer/',rel:'noreferrer noopener',target:'_blank',btn:'免费入驻',class:'btn btn-success btn-xs va0',style:"margin-left:10px;"},
{title:'Get third-party apps',rel:'noreferrer noopener',href:'https://www.bt.cn/bbs/forum-40-1.html',target:'_blank',btn:'Get third-party apps',class:'btn btn-success btn-xs va0 ml15',style:"margin-left:10px;"},
{title:'Import plugins',href:'javascript:;',btn:'Import plugins','class':'btn btn-success btn-xs va0 ml15','style':"margin-left:10px;",click:function(e){
var input = $('<input type="file" style="display:none;" accept=".zip,.tar.gz" id="update_zip" multiple="multiple">').change(function (e) {
var files =$(this)[0].files;
if (files.length == 0) return;
soft.update_zip(files[0]);
}).click();
}}
]);
$(el).append(tips_info.addClass('alert-danger'));
}else if(type == 11){
explain.text('BT one click宝塔一键部署已上线,诚邀全球优秀项目入驻(限项目官方) ');
btn_ground = soft.render_tips_btn(btn_ground,[
{title:'免费入驻',href:'https://www.bt.cn/bbs/thread-33063-1-1.html',rel:'noreferrer noopener',target:'_blank',btn:'免费入驻',class:'btn btn-success btn-xs va0',style:"margin-left:10px;"},
{title:'导入项目',href:'javascript:;',rel:'noreferrer noopener',btn:'导入项目',class:'btn btn-success btn-xs va0',style:"margin-left:10px;",click:soft.input_package}
]);
$(el).append(tips_info.addClass('alert-info'));
}else{
var ltd = parseInt(bt.get_cookie('ltd_end')),pro = parseInt(bt.get_cookie('pro_end')),todayDate = parseInt(new Date().getTime()/1000),_ltd = null;
if((ltd > 0 && (ltd == pro || pro < 0)) || (ltd < 0 && pro >= 0) || (ltd > 0 && pro >= 0)){
_ltd = ((ltd > 0 && (ltd == pro || pro < 0)) || (ltd > 0 && pro >= 0))?1:0;
explain.html('当前为'+ (_ltd?'Pro':'专业版') +''+ (_ltd?'Pro':'专业版') +'可以免费使用'+ (_ltd?'专业版及企业版插件':'专业版插件') + (!(pro == 0 && ltd < 0)?(',过期时间:'+ (bt.format_data((_ltd?ltd:pro),'yyyy/MM/dd') ) +''+((((_ltd?ltd:pro) - todayDate) <= 15*24*60*60)?('<span style="color:red">距离过期仅剩'+ Math.round(((_ltd?ltd:pro) - todayDate) / (24*60*60)) +'天</span>'):'')):',过期时间:<span style="color: #fc6d26;font-weight: bold;">永久授权</span>'));
}else if(ltd == -1 && pro == -1){
explain.html('Upgrade to Pro edition, all plugins, free to use!');
}else if(pro == 0 && ltd < 0){
_ltd = 2;
explain.html('当前为专业版,专业版可以免费使用专业版插件,过期时间:永久授权。'+(type == 12?'&nbsp;&nbsp;<span style="color:#af8e48">升级企业版,企业可以免费试用企业版插件及专业版插件。</span>':''));
if(type == 12){
btn_ground = soft.render_tips_btn(btn_ground,{title:'立即升级',href:'javascript:;',btn:'立即升级','class':'btn btn-success btn-xs va0 ml15','style':"margin-left:10px;",click:bt.soft.updata_ltd});
}
}else if(ltd == -2 || pro == -2){
_ltd = (ltd == -2)?1:0;
explain.html('当前为'+ (_ltd?'企业版':'专业版') +''+ (_ltd?'企业版':'专业版') +'可以免费使用'+ (_ltd?'专业版及企业版插件':'专业版插件') +'<span style="color:red">'+ (_ltd?'企业版':'专业版') +'已过期</span>');
}
var btn_config = {title:null,href:'javascript:;',btn:null,'class':'btn btn-success btn-xs va0 ml15','style':"margin-left:10px;",click:null};
var set_btn_style = function(res){
if(!res.status || !res){
$.extend(btn_config,{title:'立即登录',btn:'立即登录',click:function(){
bt.pub.bind_btname(function(){
window.location.reload();
});
}});
}else{
if(type == 12 && (ltd < 0 && pro >=0)){
explain.html('企业版可以免费使用专业版及企业版插件,了解专业版和企业版的区别,请点击<a href="https://www.bt.cn/download/linux.html" target="_blank" class="btlink ml5">查看详情</a>。<a href="https://www.bt.cn/bbs/forum.php?mod=viewthread&tid=50342&page=1&extra=#pid179211" target="_blank" class="btlink ml5">《专业版升级企业版教程》</a>');
$(el).append(tips_info.addClass('alert-ltd-success'));
return false;
}else{
if(_ltd != 2){
var fun = '';
switch(_ltd){
case null:
fun = bt.soft.updata_commercial_view
break;
case 1:
fun = bt.soft.updata_ltd
break;
case 0:
fun = bt.soft.updata_pro
break;
}
$.extend(btn_config,{title:_ltd == null?'Upgrade now':'立即续费',btn:_ltd == null?'Upgrade now':'立即续费',click:fun})
}
}
}
if(_ltd != 2){
if(!(pro == 0 && ltd < 0)){
btn_ground = soft.render_tips_btn(btn_ground,btn_config);
}
}
$(el).append(tips_info.addClass(_ltd == 1?'alert-ltd-success':'alert-success'));
}
var bt_user_info = bt.get_cookie('bt_user_info');
if(!bt_user_info){
bt.pub.get_user_info(function(res){
if(!res.status){
set_btn_style(false);
return false;
}
bt.set_cookie('bt_user_info',JSON.stringify(res),300000);
set_btn_style(res);
});
}else{
set_btn_style(JSON.parse(bt.get_cookie('bt_user_info')));
}
}
},
render_tips_btn:function(node,arry){
if(!Array.isArray(arry)) arry = [arry]
for(var i=0;i<arry.length;i++){
var item = arry[i], btn = '<a ';
for(var key in item){ if(key != 'click' && key != 'btn') btn += item[key]?(key+'="'+item[key]+'" '):'' }
btn += '>'+item['btn'] +'</a>';
if(item.click){
btn = $(btn).on('click',item.click)
}
node.append(btn);
}
return node
},
get_dep_list: function(p) {
var loadT = layer.msg('Getting list <img src="/static/img/ing.gif">', {
icon: 16,
@@ -783,6 +956,10 @@ var soft = {
type: 'apache_status',
title: lan.soft.nginx_status
},
{
type: 'apache_format_log',
title: 'Logs format'
},
{
type: 'log',
title: lan.soft.run_log
@@ -796,6 +973,10 @@ var soft = {
type: 'nginx_status',
title: lan.soft.nginx_status
},
{
type: 'nginx_format_log',
title: 'Logs format'
},
{
type: 'log',
title: lan.soft.err_log
@@ -865,6 +1046,10 @@ var soft = {
val: ver,
title: lan.soft.php_main4
},
{ type: 'fpm_config',
val: ver,
title: 'FPM profile'
},
{
type: 'set_dis_fun',
val: ver,
@@ -912,14 +1097,14 @@ var soft = {
}
]
var phpSort = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
var phpSort = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
webcache = bt.get_cookie('serverType') == 'openlitespeed' ? true : false;
for (var i = 0; i < phpSort.length; i++) {
var item = opt_list[i];
if (item) {
if (item.os == undefined || item['os'] == bt.os) {
if (name.indexOf("5.2") >= 0 && item.php53) continue;
if (webcache && item.type=='set_fpm_config' || item.type=='get_php_status') continue;
if (webcache && (item.type=='set_fpm_config' || item.type=='get_php_status')) continue;
var apache24 = item.apache24 ? 'class="apache24"' : '';
menu.append($('<p data-id="' + i + '" ' + apache24 + ' onclick="soft.get_tab_contents(\'' + item.type + '\',this)" >' + item.title + '</p>').data('item', item))
}
@@ -1037,6 +1222,23 @@ var soft = {
});
})
break;
case 'fpm_config':
var tabCon = $(".soft-man-con").empty();
tabCon.append('<p style="color: #666; margin-bottom: 7px">' + lan.bt.edit_ps + '</p>');
tabCon.append('<div class="bt-input-text ace_config_editor_scroll" style="line-height:18px;" id="textBody"></div>')
tabCon.append('<button id="OnlineEditFileBtn" class="btn btn-success btn-sm" style="margin-top:10px;">' + lan.public.save + '</button>')
var _arry = ['If you do not understand the php-fpm configuration file, please do not modify it!'];
tabCon.append(bt.render_help(_arry))
$('.return_php_info').click(function(){
$('.bt-soft-menu p:eq(12)').click();
});
var fileName = bt.soft.get_config_path(version).replace('php.ini','php-fpm.conf');
var loadT = bt.load(lan.soft.get);
var config = bt.aceEditor({el:'textBody',path:fileName});
$("#OnlineEditFileBtn").click(function () {
bt.saveEditor(config);
});
break;
case 'change_version':
var _list = [];
var opt_version = '';
@@ -1201,7 +1403,7 @@ var soft = {
var title11 = ((1 - rdata.Key_reads / rdata.Key_read_requests) * 100).toFixed(2);
var title12 = ((1 - rdata.Innodb_buffer_pool_reads / rdata.Innodb_buffer_pool_read_requests) * 100).toFixed(2);
var title14 = ((rdata.Created_tmp_disk_tables / rdata.Created_tmp_tables) * 100).toFixed(2);
var Con = '<div class="divtable"><table class="table table-hover table-bordered" style="margin-bottom:10px;background-color:#fafafa">\
var Con = '<div class="divtable"><table class="table table-hover table-bordered" style="background-color:#fafafa">\
<tbody>\
<tr><th>' + lan.soft.mysql_status_title1 + '</th><td>' + getLocalTime(rdata.Run) + '</td><th>' + lan.soft.mysql_status_title5 + '</th><td>' + parseInt(rdata.Questions / rdata.Uptime) + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title2 + '</th><td>' + rdata.Connections + '</td><th>' + lan.soft.mysql_status_title6 + '</th><td>' + parseInt((parseInt(rdata.Com_commit) + parseInt(rdata.Com_rollback)) / rdata.Uptime) + '</td></tr>\
@@ -1209,20 +1411,20 @@ var soft = {
<tr><th>' + lan.soft.mysql_status_title4 + '</th><td>' + ToSize(rdata.Bytes_received) + '</td><th>' + lan.soft.mysql_status_title8 + '</th><td>' + rdata.Position + '</td></tr>\
</tbody>\
</table>\
<table class="table table-hover table-bordered" style="margin-bottom: 10px;">\
<thead style="display:none;"><th></th><th></th><th></th><th></th></thead>\
<table class="table table-hover table-bordered">\
<thead style="visibility: hidden;"><th width="225"></th><th></th><th></th></thead>\
<tbody>\
<tr><th>' + lan.soft.mysql_status_title9 + '</th><td>' + rdata.Threads_running + '/' + rdata.Max_used_connections + '</td><td colspan="2">' + lan.soft.mysql_status_ps1 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title10 + '</th><td>' + (!isNaN(title10) ? title10 : '0') + '%</td><td colspan="2">' + lan.soft.mysql_status_ps2 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title11 + '</th><td>' + (!isNaN(title11) ? title11 : '0') + '%</td><td colspan="2">' + lan.soft.mysql_status_ps3 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title12 + '</th><td>' + (!isNaN(title12) ? title12 : '0') + '%</td><td colspan="2">' + lan.soft.mysql_status_ps4 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title13 + '</th><td>' + cache_size + '</td><td colspan="2">' + lan.soft.mysql_status_ps5 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title14 + '</th><td>' + (!isNaN(title14) ? title14 : '0') + '%</td><td colspan="2">' + lan.soft.mysql_status_ps6 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title15 + '</th><td>' + rdata.Open_tables + '</td><td colspan="2">' + lan.soft.mysql_status_ps7 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title16 + '</th><td>' + rdata.Select_full_join + '</td><td colspan="2">' + lan.soft.mysql_status_ps8 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title17 + '</th><td>' + rdata.Select_range_check + '</td><td colspan="2">' + lan.soft.mysql_status_ps9 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title18 + '</th><td>' + rdata.Sort_merge_passes + '</td><td colspan="2">' + lan.soft.mysql_status_ps10 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title19 + '</th><td>' + rdata.Table_locks_waited + '</td><td colspan="2">' + lan.soft.mysql_status_ps11 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title9 + '</th><td>' + rdata.Threads_running + '/' + rdata.Max_used_connections + '</td><td>' + lan.soft.mysql_status_ps1 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title10 + '</th><td>' + (!isNaN(title10) ? title10 : '0') + '%</td><td>' + lan.soft.mysql_status_ps2 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title11 + '</th><td>' + (!isNaN(title11) ? title11 : '0') + '%</td><td>' + lan.soft.mysql_status_ps3 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title12 + '</th><td>' + (!isNaN(title12) ? title12 : '0') + '%</td><td>' + lan.soft.mysql_status_ps4 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title13 + '</th><td>' + cache_size + '</td><td>' + lan.soft.mysql_status_ps5 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title14 + '</th><td>' + (!isNaN(title14) ? title14 : '0') + '%</td><td>' + lan.soft.mysql_status_ps6 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title15 + '</th><td>' + rdata.Open_tables + '</td><td>' + lan.soft.mysql_status_ps7 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title16 + '</th><td>' + rdata.Select_full_join + '</td><td>' + lan.soft.mysql_status_ps8 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title17 + '</th><td>' + rdata.Select_range_check + '</td><td>' + lan.soft.mysql_status_ps9 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title18 + '</th><td>' + rdata.Sort_merge_passes + '</td><td>' + lan.soft.mysql_status_ps10 + '</td></tr>\
<tr><th>' + lan.soft.mysql_status_title19 + '</th><td>' + rdata.Table_locks_waited + '</td><td>' + lan.soft.mysql_status_ps11 + '</td></tr>\
<tbody>\
</table></div>'
$(".soft-man-con").html(Con);
@@ -1647,6 +1849,451 @@ var soft = {
bt.render_table("tab-nginx-status", arrs);
})
break;
case 'nginx_format_log':
var loadT = bt.load();
bt.send('get_nginx_access_log_format', 'config/get_nginx_access_log_format', {}, function(rdata) {
$(".soft-man-con").html("<button class='btn btn-success btn-sm mb15 table-add-format'>Add format</button><div class='divtable' style='max-height: 570px;overflow: auto;'><table id='tab-nginx-logs-format' class='table table-hover'><thead><tr><th width='15%'>Name</th><th>Format</th><th width='120' style='text-align:right;'>Opt</th></tr></thead><tbody></tbody></table></div>");
bt.send('get_nginx_access_log_format_parameter', 'config/get_nginx_access_log_format_parameter', {}, function(res) {
loadT.close();
var _format_ul = '<ul class="bt-select-list">';
Object.keys(res).map(function(key){
_format_ul += '<li data-val="'+key+'">'+key+'&nbsp;:&nbsp;'+res[key]+'</li>';
})
_format_ul += '</ul>';
for (const j in rdata) {
if (rdata.hasOwnProperty(j)) {
const result = rdata[j];
var _format = result.map(function(item, index){
return Object.keys(item)[0];
});
var element = '<span class="nginx-one-format">' + _format.join('</span><span class="nginx-one-format">') + '</span>',
_td = '<tr><td>'+j+'</td>\
<td>'+element+'</td>\
<td align="right" data-name="'+j+'"><a class="btlink table-apply-format">Apply</a> | <a class="btlink table-set-format">Set</a> | <a class="btlink table-del-format">Del</a></td></tr>';
$("#tab-nginx-logs-format tbody").append(_td);
//表格头固定
$('#tab-nginx-logs-format').parent().on('scroll', function () {
var scrollTop = $('#tab-nginx-logs-format').parent().scrollTop();
$('#tab-nginx-logs-format thead').css({"transform":"translateY("+scrollTop+"px)","position":"relative","z-index":"1"});
});
}
}
$('.table-add-format, .table-set-format').click(function() {
if($(this).hasClass('table-set-format')) {
var format_title = 'Set format',
first_format = '',
add_type = 'edit',
td_format = $(this).parent().prev().find('.nginx-one-format');
format_name = $(this).parent().attr('data-name');
for (var i = 0; i < td_format.length; i++) {
first_format += '<div class="line">\
<div class="bt-select">\
<div class="bt-select-input plr10">\
<div class="bt-select-val" data-active="'+td_format.eq(i).text()+'">'+td_format.eq(i).text()+'</div>\
<span class="bt-down-icon"></span>\
</div>\
</div>\
<a href="javascript:;" class="del-format">Del</a>\
</div>';
}
}else{
var format_title = 'Add format',
format_name = '',
add_type = 'add',
first_format = '',
format_list = ['$http_x_forwarded_for','$remote_addr','-','[$time_local]','$request','$status','$body_bytes_sent','$http_referer','$http_user_agent'];
for (var i = 0; i < format_list.length; i++) {
first_format += '<div class="line">\
<div class="bt-select">\
<div class="bt-select-input plr10">\
<div class="bt-select-val" data-active="'+format_list[i]+'">'+format_list[i]+'</div>\
<span class="bt-down-icon"></span>\
</div>\
</div>\
<a href="javascript:;" class="del-format">Del</a>\
</div>';
}
}
layer.open({
type: 1,
title: format_title,
closeBtn: 2,
area: '375px',
btn: ['Confirm', 'Cancel'],
content: '<div class="bt-form pd20 nginx-add-format" style="position: relative;">\
<div class="line" style="font-size: 13px;">\
<span style="text-align: right;display: inline-block;margin-right: 7px;width: 50px;">Name: </span>\
<input name="log_format_name" class="bt-input-text" type="text" style="width:274px" placeholder = "Please enter the format name.">\
</div>\
<span style="position: absolute;top: 70px;left: 25px;">Format:</span>\
<div style="position: relative;margin-left: 60px;">\
<div class="format-table">'+first_format+'</div>\
'+_format_ul+'\
</div>\
<button class="btn btn-success btn-sm btn-title btn-add-format" type="button" style="margin-top: 10px;margin-left: 60px;"><span class="glyphicon cursor glyphicon-plus mr5"></span>Add parameter</button>\
<ul class="help-info-text c7"><li>The format are executed in the order of parameters.</li></ul>\
</div>',
success: function(index, layero) {
$('.nginx-add-format [name=log_format_name]').val(format_name);
$('.nginx-add-format').parents('.layui-layer-content').css('overflow','inherit');
$('.nginx-add-format').on('click', '.bt-select-input', function (e) {
if($(this).hasClass('active')){
$('.nginx-add-format .bt-select-list').removeClass('active');
$(this).removeClass('active').find('.bt-down-icon').css('transform','rotate(-45deg)');
}else{
var _choose = $(this).find('.bt-select-val').text();
$('.bt-select-list li').removeClass('active');
$('.active.bt-select-input').removeClass('active').find('.bt-down-icon').css('transform','rotate(-45deg)')
$('.bt-select-list li:contains('+_choose+')').addClass('active');
$('.nginx-add-format .bt-select-list').addClass('active').css('top',$(this).offset().top-$('.format-table').offset().top+33);
$(this).addClass('active').find('.bt-down-icon').css('transform','rotate(135deg)');
}
e.stopPropagation();
$(document).click(function(e){
$('.active.bt-select-list').removeClass('active');
$(this).find('.bt-down-icon').css('transform','rotate(-45deg)');
e.preventDefault();
e.stopPropagation();
});
});
$('.nginx-add-format').on('click', '.bt-select-list li', function (e) {
var _value = $(this).attr('data-val');
$('.active.bt-select-input').find('.bt-select-val').attr('data-active',_value).text(_value);
$('.nginx-add-format .bt-select-list,.active.bt-select-input').removeClass('active');
});
$('.btn-add-format').click(function (e) {
var _new_line = '<div class="line">\
<div class="bt-select">\
<div class="bt-select-input plr10">\
<div class="bt-select-val" data-active="$server_name">$server_name</div>\
<span class="bt-down-icon" ></span>\
</div>\
</div>\
<a href="javascript:;" class="del-format">Del</a>\
</div>';
$('.format-table').append(_new_line);
$('.format-table').scrollTop(10000000)
});
$('.nginx-add-format').on('click', '.del-format', function (e) {
if ($('.del-format').length == 1) {
layer.msg('This is the last parameter.', {icon: 2});
return false;
}
$(this).parent().remove();
});
},
yes: function(index, layero) {
if ($('.nginx-add-format [name=log_format_name]').val()=='') {
layer.msg('The format name cannot be empty!', {icon: 2});
return false;
}
var log_format = [];
$(".nginx-add-format .format-table .bt-select-val").each(function(){
log_format.push($(this).attr("data-active"));
});
var format_data = {
"log_format_name": $('.nginx-add-format [name=log_format_name]').val(),
"log_format": JSON.stringify(log_format),
"act": add_type
}
bt.send('add_nginx_access_log_format', 'config/add_nginx_access_log_format', format_data, function(res) {
layer.close(index);
$('.bt-soft-menu p:contains("Logs format")').click();
layer.msg(res.msg, {icon: res.status ? 1 : 2});
})
}
})
});
$('#tab-nginx-logs-format').on('click', '.table-del-format', function (e) {
var log_format_name = $(this).parent().attr('data-name'),
loadP = layer.confirm('Confirm to delete【'+log_format_name+'】this logs format?', {
title: 'Confirm Delete?',
closeBtn: 2
}, function() {
layer.close(loadP);
bt.send('del_nginx_access_log_format', 'config/del_nginx_access_log_format', {'log_format_name': log_format_name}, function(res) {
if(res.status) $('.bt-soft-menu p:contains("Logs format")').click();
layer.msg(res.msg, {icon: res.status ? 1 : 2});
});
});
});
$('#tab-nginx-logs-format').on('click', '.table-apply-format', function (e) {
var log_format_name = $(this).parent().attr('data-name');
bt.send('get_nginx_access_log_format_parameter', 'config/get_nginx_access_log_format_parameter', {'log_format_name':log_format_name}, function(res) {
if (Object.keys(res.site_list).length == 0) {
layer.msg('There is no site can apply!', {icon: 2});
return false;
}
var _site_ul = '<ul class="format-site-list">';
Object.keys(res.site_list).map(function(key){
_site_ul += '<li style="padding: 10px"><div class="bt_checkbox_groups'+(res.site_list[key]?' active':'')+'" data-val="'+key+'"></div>'+key+'</li>';
});
_site_ul += '</ul>';
layer.open({
type: 1,
title: 'Website apply format',
closeBtn: 2,
btn: ['Confirm', 'Cancel'],
content: '<div class="bt-form pd20 nginx-add-site" style="font-size: 13px;">\
<div class="line">\
<span style="text-align: right;display: inline-block;position: absolute;">Site: </span>\
'+_site_ul+'\
</div>\
<div class="line c7">The checked site would used the format.</div>\
</div>',
success: function(index, layero) {
$('.nginx-add-site').on('click', '.format-site-list li', function (e) {
if ($(this).find('.bt_checkbox_groups').hasClass('active')) {
$(this).find('.bt_checkbox_groups').removeClass('active');
} else {
$(this).find('.bt_checkbox_groups').addClass('active');
}
});
},
yes: function(index, layero) {
var sites = [];
$(".nginx-add-site .format-site-list .bt_checkbox_groups.active").each(function(){
sites.push($(this).attr("data-val"));
});
var format_data = {
"log_format_name": log_format_name,
"sites": JSON.stringify(sites)
}
bt.send('set_format_log_to_website', 'config/set_format_log_to_website', format_data, function(res) {
layer.close(index);
if(res.status) $('.bt-soft-menu p:contains("Logs format")').click();
layer.msg(res.msg, {icon: res.status ? 1 : 2});
})
}
})
});
});
});
});
break;
case 'apache_format_log':
var loadT = bt.load();
bt.send('get_httpd_access_log_format', 'config/get_httpd_access_log_format', {}, function(rdata) {
$(".soft-man-con").html("<button class='btn btn-success btn-sm mb15 table-add-format'>Add format</button><div class='divtable' style='max-height: 570px;overflow: auto;'><table id='tab-nginx-logs-format' class='table table-hover'><thead><tr><th width='15%'>Name</th><th>Format</th><th width='120' style='text-align:right;'>Opt</th></tr></thead><tbody></tbody></table></div>");
bt.send('get_httpd_access_log_format_parameter', 'config/get_httpd_access_log_format_parameter', {}, function(res) {
loadT.close();
var _format_ul = '<ul class="bt-select-list">';
Object.keys(res).map(function(key){
_format_ul += '<li data-val="'+key+'">'+key+'&nbsp;:&nbsp;'+res[key]+'</li>';
})
_format_ul += '</ul>';
for (const j in rdata) {
if (rdata.hasOwnProperty(j)) {
const result = rdata[j];
var _format = result.map(function(item, index){
return Object.keys(item)[0];
});
var element = '<span class="nginx-one-format">' + _format.join('</span><span class="nginx-one-format">') + '</span>',
_td = '<tr><td>'+j+'</td>\
<td>'+element+'</td>\
<td align="right" data-name="'+j+'"><a class="btlink table-apply-format">Apply</a> | <a class="btlink table-set-format">Set</a> | <a class="btlink table-del-format">Del</a></td></tr>';
$("#tab-nginx-logs-format tbody").append(_td);
//表格头固定
$('#tab-nginx-logs-format').parent().on('scroll', function () {
var scrollTop = $('#tab-nginx-logs-format').parent().scrollTop();
$('#tab-nginx-logs-format thead').css({"transform":"translateY("+scrollTop+"px)","position":"relative","z-index":"1"});
});
}
}
$('.table-add-format, .table-set-format').click(function() {
if($(this).hasClass('table-set-format')) {
var format_title = 'Set format',
first_format = '',
add_type = 'edit',
td_format = $(this).parent().prev().find('.nginx-one-format');
format_name = $(this).parent().attr('data-name');
for (var i = 0; i < td_format.length; i++) {
first_format += '<div class="line">\
<div class="bt-select">\
<div class="bt-select-input plr10">\
<div class="bt-select-val" data-active="'+td_format.eq(i).text()+'">'+td_format.eq(i).text()+'</div>\
<span class="bt-down-icon"></span>\
</div>\
</div>\
<a href="javascript:;" class="del-format">Del</a>\
</div>';
}
}else{
var format_title = 'Add format',
format_name = '',
add_type = 'add',
first_format = '',
format_list = ['%{X-Forwarded-For}i','%h','%l','%u','%t','%r','%>s','%b','%{Referer}i','%{User-agent}i'];
for (var i = 0; i < format_list.length; i++) {
first_format += '<div class="line">\
<div class="bt-select">\
<div class="bt-select-input plr10">\
<div class="bt-select-val" data-active="'+format_list[i]+'">'+format_list[i]+'</div>\
<span class="bt-down-icon"></span>\
</div>\
</div>\
<a href="javascript:;" class="del-format">Del</a>\
</div>';
}
}
layer.open({
type: 1,
title: format_title,
closeBtn: 2,
area: '375px',
btn: ['Confirm', 'Cancel'],
content: '<div class="bt-form pd20 nginx-add-format" style="position: relative;">\
<div class="line" style="font-size: 13px;">\
<span style="text-align: right;display: inline-block;margin-right: 7px;width: 50px;">Name: </span>\
<input name="log_format_name" class="bt-input-text" type="text" style="width:274px" placeholder = "Please enter the format name.">\
</div>\
<span style="position: absolute;top: 70px;left: 25px;">Format:</span>\
<div style="position: relative;margin-left: 60px;">\
<div class="format-table">'+first_format+'</div>\
'+_format_ul+'\
</div>\
<button class="btn btn-success btn-sm btn-title btn-add-format" type="button" style="margin-top: 10px;margin-left: 60px;"><span class="glyphicon cursor glyphicon-plus mr5"></span>Add parameter</button>\
<ul class="help-info-text c7"><li>The format are executed in the order of parameters.</li></ul>\
</div>',
success: function(index, layero) {
$('.nginx-add-format [name=log_format_name]').val(format_name);
$('.nginx-add-format').parents('.layui-layer-content').css('overflow','inherit');
$('.nginx-add-format').on('click', '.bt-select-input', function (e) {
if($(this).hasClass('active')){
$('.nginx-add-format .bt-select-list').removeClass('active');
$(this).removeClass('active').find('.bt-down-icon').css('transform','rotate(-45deg)');
}else{
var _choose = $(this).find('.bt-select-val').text();
$('.bt-select-list li').removeClass('active');
$('.active.bt-select-input').removeClass('active').find('.bt-down-icon').css('transform','rotate(-45deg)')
$('.bt-select-list li:contains('+_choose+')').addClass('active');
$('.nginx-add-format .bt-select-list').addClass('active').css('top',$(this).offset().top-$('.format-table').offset().top+33);
$(this).addClass('active').find('.bt-down-icon').css('transform','rotate(135deg)');
}
e.stopPropagation();
$(document).click(function(e){
$('.active.bt-select-list').removeClass('active');
$(this).find('.bt-down-icon').css('transform','rotate(-45deg)');
e.preventDefault();
e.stopPropagation();
});
});
$('.nginx-add-format').on('click', '.bt-select-list li', function (e) {
var _value = $(this).attr('data-val');
$('.active.bt-select-input').find('.bt-select-val').attr('data-active',_value).text(_value);
$('.nginx-add-format .bt-select-list,.active.bt-select-input').removeClass('active');
});
$('.btn-add-format').click(function (e) {
var _new_line = '<div class="line">\
<div class="bt-select">\
<div class="bt-select-input plr10">\
<div class="bt-select-val" data-active="%>s">%>s</div>\
<span class="bt-down-icon" ></span>\
</div>\
</div>\
<a href="javascript:;" class="del-format">Del</a>\
</div>';
$('.format-table').append(_new_line);
$('.format-table').scrollTop(10000000)
});
$('.nginx-add-format').on('click', '.del-format', function (e) {
if ($('.del-format').length == 1) {
layer.msg('This is the last parameter.', {icon: 2});
return false;
}
$(this).parent().remove();
});
},
yes: function(index, layero) {
if ($('.nginx-add-format [name=log_format_name]').val()=='') {
layer.msg('The format name cannot be empty!', {icon: 2});
return false;
}
var log_format = [];
$(".nginx-add-format .format-table .bt-select-val").each(function(){
log_format.push($(this).attr("data-active"));
});
var format_data = {
"log_format_name": $('.nginx-add-format [name=log_format_name]').val(),
"log_format": JSON.stringify(log_format),
'act':add_type
}
bt.send('add_httpd_access_log_format', 'config/add_httpd_access_log_format', format_data, function(res) {
layer.close(index);
if(res.status) $('.bt-soft-menu p:contains("Logs format")').click();
layer.msg(res.msg, {icon: res.status ? 1 : 2});
})
}
})
});
$('#tab-nginx-logs-format').on('click', '.table-del-format', function (e) {
var log_format_name = $(this).parent().attr('data-name'),
loadP = layer.confirm('Confirm to delete【'+log_format_name+'】this logs format?', {
title: 'Confirm Delete?',
closeBtn: 2
}, function() {
layer.close(loadP);
bt.send('del_httpd_access_log_format', 'config/del_httpd_access_log_format', {'log_format_name': log_format_name}, function(res) {
if(res.status) $('.bt-soft-menu p:contains("Logs format")').click();
layer.msg(res.msg, {icon: res.status ? 1 : 2});
});
});
});
$('#tab-nginx-logs-format').on('click', '.table-apply-format', function (e) {
var log_format_name = $(this).parent().attr('data-name');
bt.send('get_httpd_access_log_format_parameter', 'config/get_httpd_access_log_format_parameter', {'log_format_name':log_format_name}, function(res) {
if (Object.keys(res.site_list).length == 0) {
layer.msg('There is no site can apply!', {icon: 2});
return false;
}
var _site_ul = '<ul class="format-site-list">';
Object.keys(res.site_list).map(function(key){
_site_ul += '<li style="padding: 10px"><div class="bt_checkbox_groups'+(res.site_list[key]?' active':'')+'" data-val="'+key+'"></div>'+key+'</li>';
});
_site_ul += '</ul>';
layer.open({
type: 1,
title: 'Website apply format',
closeBtn: 2,
btn: ['Confirm', 'Cancel'],
content: '<div class="bt-form pd20 nginx-add-site" style="font-size: 13px;">\
<div class="line">\
<span style="text-align: right;display: inline-block;position: absolute;">Site: </span>\
'+_site_ul+'\
</div>\
<div class="line c7">The checked site would used the format.</div>\
</div>',
success: function(index, layero) {
$('.nginx-add-site').on('click', '.format-site-list li', function (e) {
if ($(this).find('.bt_checkbox_groups').hasClass('active')) {
$(this).find('.bt_checkbox_groups').removeClass('active');
} else {
$(this).find('.bt_checkbox_groups').addClass('active');
}
});
},
yes: function(index, layero) {
var sites = [];
$(".nginx-add-site .format-site-list .bt_checkbox_groups.active").each(function(){
sites.push($(this).attr("data-val"));
});
var format_data = {
"log_format_name": log_format_name,
"sites": JSON.stringify(sites)
}
bt.send('set_httpd_format_log_to_website', 'config/set_httpd_format_log_to_website', format_data, function(res) {
layer.close(index);
if(res.status) $('.bt-soft-menu p:contains("Logs format")').click();
layer.msg(res.msg, {icon: res.status ? 1 : 2});
})
}
})
});
});
});
});
break;
case 'apache_status':
var loadT = bt.load();
bt.send('GetApacheStatus', 'ajax/GetApacheStatus', {}, function(rdata) {
@@ -2199,10 +2846,10 @@ var soft = {
bt.open({
type: 1,
title: "PHP-" + version + "-PHPINFO",
area: ['70%', '90%'],
area: ['73%', '90%'],
closeBtn: 2,
shadeClose: true,
content: '<div style="white-space: pre-wrap;">'+content+'</div>'
content: '<div style="white-space: pre-wrap;padding:0 10px;">'+content+'</div>'
})
})
})
@@ -2474,6 +3121,17 @@ var soft = {
for (var sk in item) $('.' + sk).val(item[sk]);
}
},
{
title: 'Connection',
name: 'listen',
value: rdata.unix,
type: 'select',
items: [
{ title: 'UNIX socket', value: 'unix' },
{ title: 'TCP socket', value: 'tcp' }
],
ps: '* UNIX socket recommended'
},
{
title: lan.soft.php_fpm_model,
name: 'pm',
@@ -2587,14 +3245,14 @@ var soft = {
clicks = clicks.concat(_form.clicks);
}
_c_form.append('<ul class="help-info-text c7">\
<li>[Max num of child processes] The larger the number, the stronger the concurrency, but max_children should not exceed 5000</li>\
<li>[Ram] Each PHP child process needs about 20MB of Ram, too large max_children will cause server instability</li>\
<li>[Static mode] In the static mode, the set number of child processes is always maintained, which has a large Ram overhead, but has a good concurrency capability.</li>\
<li>[Dynamic mode] will recover the process according to the set max number of idle processes, the Ram overhead is small, it is recommended to use a small Ram machine</li>\
<li>[Max num of child processes] The larger the number, the stronger the concurrency,<br>&nbsp;&nbsp;&nbsp;&nbsp; but max_children should not exceed 5000.</li>\
<li>[Ram] Each PHP child process needs about 20MB of Ram,<br>&nbsp;&nbsp;&nbsp;&nbsp; too large max_children will cause server instability.</li>\
<li>[Static mode] In the static mode, the set number of child processes is always maintained,<br>&nbsp;&nbsp;&nbsp;&nbsp; which has a large Ram overhead, but has a good concurrency capability.</li>\
<li>[Dynamic mode] will recover the process according to the set max number of idle processes,<br>&nbsp;&nbsp;&nbsp;&nbsp; the Ram overhead is small, it is recommended to use a small Ram machine.</li>\
<li>[64GB Ram recommended value] max_children <= 1000, start / min_spare = 50, max_spare <= 200</li>\
<li>[Multi-PHP Version] If you have installed multiple PHP versions and are using them, it is recommended to reduce the concurrent configuration appropriately.</li>\
<li>[No database] If no database such as mysql is installed, it is recommended to set 2 times the recommended concurrency</li>\
<li>[Note] The above are the recommended configuration instructions. The online projects are complex and diverse. Please adjust according to actual conditions.</li>\
<li>[Multi-PHP Version] If you have installed multiple PHP versions and are using them,<br>&nbsp;&nbsp;&nbsp;&nbsp; it is recommended to reduce the concurrent configuration appropriately.</li>\
<li>[No database] If no database such as mysql is installed,<br>&nbsp;&nbsp;&nbsp;&nbsp; it is recommended to set 2 times the recommended concurrency.</li>\
<li>[Note] The above are the recommended configuration instructions.<br>&nbsp;&nbsp;&nbsp;&nbsp; The online projects are complex and diverse. Please adjust according to actual conditions.</li>\
</ul>')
tabCon.append(_c_form);
@@ -2932,26 +3590,17 @@ var soft = {
});
},
input_zip: function(plugin_name, tmp_path) {
bt.soft.show_speed_window('Installing, this may take a few minutes...', function() {
$.post('/plugin?action=input_zip', {
plugin_name: plugin_name,
tmp_path: tmp_path
}, function(rdata) {
input_zip: function (plugin_name,tmp_path,data) {
bt.soft.show_speed_window({title:'Installing, this may take a few minutes...',status:true},function(){
$.post('/plugin?action=input_zip', { plugin_name: plugin_name, tmp_path: tmp_path }, function (rdata) {
layer.closeAll()
if (rdata.status) {
soft.get_list();
}
setTimeout(function() {
layer.msg(rdata.msg, {
icon: rdata.status ? 1 : 2
})
}, 1000);
setTimeout(function () { layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 }) }, 1000);
});
});
}
};
function soft_td_width_auto() {
+192 -10
View File
@@ -35,7 +35,14 @@ Terms.prototype = {
//服务器消息事件
on_message: function (ws_event){
result = ws_event.data;
if (result === "\rServer connection failed!\r" || result == "\rWrong user name or password!\r") {
if(!result) return;
// if (result === "\rServer connection failed!\r" || result == "\rWrong user name or password!\r") {
// this.close();
// return;
// }
if ((result.indexOf("@127.0.0.1:") != -1 || result.indexOf("@localhost:") != -1) && result.indexOf('Authentication failed') != -1) {
this.term.write(result);
host_trem.localhost_login_form(result);
this.close();
return;
}
@@ -102,7 +109,6 @@ Terms.prototype = {
if (!this.bws || this.bws.readyState == 3 || this.bws.readyState == 2) {
this.connect();
}
//判断当前连接状态,如果!=1,则100ms后尝试重新发送
if (this.bws.readyState === 1) {
this.bws.send(data);
@@ -158,6 +164,7 @@ var host_trem = {
host_list:[],
command_list:[],
sort_time:null,
is_full:false,
command_form:{
title:'',
shell:'',
@@ -172,22 +179,69 @@ var host_trem = {
},
init:function(){
var that = this,isMousemove = true;
$(window).resize(function(){
var win = $(window)[0],win_width = win.innerHeight,win_height = win.innerHeight;
$('.main-content .safe').height(win_height - 105);
$('#term_box_view,.term_tootls').height(win_height - 105);
$('.tootls_commonly_list').height(win_height - 563);
Object.defineProperty(host_trem,'is_full',{
get:function(val){
return val;
},
set:function(newValue) {
if(newValue){
$('body').addClass('full_term_view');
var win = $(window)[0],win_width = win.innerHeight,win_height = win.innerHeight;
$('.main-content .safe').height(win_height);
$('#term_box_view,.term_tootls').height(win_height);
$('.tootls_host_list').height((win_height - 80) * .75);
$('.tootls_commonly_list').height((win_height - 80) * .25);
$('.tab_tootls .glyphicon').removeClass('glyphicon-resize-full').addClass('glyphicon-resize-small').attr('title','Exit full screen');
}else{
$('body').removeClass('full_term_view');
$('.tab_tootls .glyphicon').removeClass('glyphicon-resize-small').addClass('glyphicon-resize-full').attr('title','Full Screen');
}
}
});
document.onkeydown = function(e){
e = e || window.event;
if ((e.metaKey && e.keyCode == 82) || e.keyCode == 116){
return false;
}
if(that.is_full && e.keyCode == 27){
return false;
}
}
$(window).resize(function(ev){
var win = $(window)[0],win_width = win.innerHeight,win_height = win.innerHeight,host_commonly = win_height - 185;
if(that.isFullScreen()){
$('.main-content .safe').height(win_height);
$('#term_box_view,.term_tootls').height(win_height);
$('.tootls_host_list').height((win_height - 80) * .75);
$('.tootls_commonly_list').height((win_height - 80) * .25);
}else{
$('.main-content .safe').height(win_height - 105);
$('#term_box_view,.term_tootls').height(win_height - 105);
$('.tootls_host_list').height(host_commonly * .75);
$('.tootls_commonly_list').height(host_commonly * .25);
}
var id = $('.term_item_tab .active').data('id');
var item_term = that.host_term[id].term;
item_term.FitAddon.fit();
that.host_term[id].resize({cols:item_term.cols, rows:item_term.rows});
});
$('.tab_tootls').on('click','.glyphicon-resize-full',function(){
$(this).removeClass('glyphicon-resize-full').addClass('glyphicon-resize-small').attr('title','Exit full Screen');
$('body').addClass('full_term_view');
that.requestFullScreen();
});
$('.tab_tootls').on('click','.glyphicon-resize-small',function(){
$(this).removeClass('glyphicon-resize-small').addClass('glyphicon-resize-full').attr('title','Full Screen');
$('body').removeClass('full_term_view');
that.exitFullscreen();
});
$(document).ready(function (e) {
var win = $(window)[0],win_width = win.innerHeight,win_height = win.innerHeight;
var win = $(window)[0],win_width = win.innerHeight,win_height = win.innerHeight,host_commonly = win_height - 185;
$('.main-content .safe').height(win_height - 105);
$('#term_box_view,.term_tootls').height(win_height - 105);
$('.tootls_commonly_list').height(win_height - 563);
$('.tootls_host_list').height(host_commonly * .75);
$('.tootls_commonly_list').height(host_commonly * .25);
that.open_term_view();
});
@@ -361,6 +415,134 @@ var host_trem = {
this.reader_host_list();
this.reader_command_list();
},
// 判断全屏状态
isFullScreen:function() {
var is_full = document.isFullScreen || document.mozIsFullScreen || document.webkitIsFullScreen;
this.is_full = is_full
return is_full;
},
// 进入全屏
requestFullScreen:function(element){
if(element == undefined) element = document.documentElement;
// 判断各种浏览器,找到正确的方法
var requestMethod = element.requestFullScreen || //W3C
element.webkitRequestFullScreen || //FireFox
element.mozRequestFullScreen || //Chrome等
element.msRequestFullScreen; //IE11
if (requestMethod) {
requestMethod.call(element);
} else if (typeof window.ActiveXObject !== "undefined") { //for Internet Explorer
var wscript = new ActiveXObject("WScript.Shell");
if (wscript !== null) {
wscript.SendKeys("{F11}");
}
}
this.is_full = true;
},
// 退出全屏
exitFullscreen:function(element) {
if(element == undefined) element = document.documentElement;
// 判断各种浏览器,找到正确的方法
var exitMethod = document.exitFullscreen || //W3C
document.mozCancelFullScreen || //FireFox
document.webkitExitFullscreen || //Chrome等
document.webkitExitFullscreen; //IE11
if (exitMethod) {
exitMethod.call(document);
} else if (typeof window.ActiveXObject !== "undefined") { //for Internet Explorer
var wscript = new ActiveXObject("WScript.Shell");
if (wscript !== null) {
wscript.SendKeys("{F11}");
}
}
this.is_full = false;
},
/**
* @name 本地服务器登录表单
* @author chudong<2020-08-10>
* @return void
*/
localhost_login_form:function(result){
var that = this,form = $(this.render_template({html:host_form_view.innerHTML,data:{form:$.extend(that.host_form,{host:'127.0.0.1'})}})),id = $('.localhost_item').data('id')
form.find('.ssh_ps_tips').remove();
form.prepend('<div class="localhost-form-title"><i class="localhost-form_tip"></i><span style="vertical-align: middle;">Login failed, please fill the local server information!</span></div>');
form.append('<button type="submit" class="btn btn-sm btn-success">Login</button>');
$('#'+id).append('<div class="localhost-form-shade"><div class="localhost-form-view bt-form-2x">'+ form[0].innerHTML +'</div></div>');
if(result){
if(result.indexOf('@127.0.0.1') != -1){
var user = result.split('@')[0].split(',')[1];
var port = result.split('1:')[1]
$("input[name='username']").val(user);
$("input[name='port']").val(port);
}
}
$('.auth_type_checkbox').click(function(){
var index = $(this).index();
$(this).addClass('btn-success').removeClass('btn-default').siblings().removeClass('btn-success').addClass('btn-default')
switch(index){
case 0:
$('.c_password_view').addClass('show').removeClass('hidden');
$('.c_pkey_view').addClass('hidden').removeClass('show').find('input').val('');
break;
case 1:
$('.c_password_view').addClass('hidden').removeClass('show').find('input').val('');
$('.c_pkey_view').addClass('show').removeClass('hidden');
break;
}
});
$('.localhost-form-view > button').click(function(){
var form = {};
$('.localhost-form-view input,.localhost-form-view textarea').each(function(index,el){
var name = $(this).attr('name'),value = $(this).val();
form[name] = value;
switch(name){
case 'port':
if(!bt.check_port(value)){
bt.msg({status:false,msg:'Server port format error!'});
return false;
}
break;
case 'username':
if(value == ''){
bt.msg({status:false,msg:'Server user name cannot be empty!'});
return false;
}
break;
case 'password':
if(value == '' && $('.c_password_view').hasClass('show')){
bt.msg({status:false,msg:'Server password cannot be empty!'});
return false;
}
break;
case 'pkey':
if(value == '' && $('.c_pkey_view').hasClass('show')){
bt.msg({status:false,msg:'The server key cannot be empty!'});
return false;
}
break;
}
});
delete form.sort
form.ps = 'Local server';
that.create_host(form,function(res){
bt.msg(res);
if(res.status){
bt.msg({status:true,msg:'Login successful!'});
$('.localhost_item .icon-trem-close').click();
that.open_term_view();
}
});
});
$('.localhost-form-view [name="password"]').keyup(function(e){
if(e.keyCode == 13){
$('.localhost-form-view > button').click();
}
}).focus();
},
reader_right_menu:function(config,callback){
var menu = $('<ul class="menu_right_list" id="term_title_menu"></ul>').css({'top':config.position[1],'left':config.position[0]}),html = '';
@@ -612,7 +794,7 @@ var host_trem = {
tab_content.find('.term_item').removeClass('active').siblings().removeClass('active');
tab_content.append('<div class="term_item active" id="'+ random +'" data-host="'+ info.host +'"></div>');
item_list.find('.item').removeClass('active');
item_list.append('<span class="active item" data-host="'+ info.host +'" data-id="'+ random +'"><i class="icon icon-sucess"></i><div class="content"><span>'+ info.ps +'</span></div><span class="icon-trem-close"></span></span>');
item_list.append('<span class="active item '+ (info.host =='127.0.0.1'?'localhost_item':'') +'" data-host="'+ info.host +'" data-id="'+ random +'"><i class="icon icon-sucess"></i><div class="content"><span>'+ info.ps +'</span></div><span class="icon-trem-close"></span></span>');
this.host_term[random] = new Terms('#'+random,{ssh_info:{host:info.host,ps:info.ps,id:random}});
},
/**
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+17 -2
View File
@@ -13,6 +13,7 @@
"TYPE_PANEL":"Panel configuration",
"TYPE_PHP":"PHP configuration",
"TYPE_CRON":"Cron job",
"USER_MANAGE": "User Management",
"TYPE_FIREWALL":"Firewall manager",
"DOMAIN_ADD_SUCCESS":"Site [{1}] added domain [{2}] successfully!",
"DOMAIN_DEL_SUCCESS":"Site [{1}] deleted domain [{2}] successfully!",
@@ -150,10 +151,24 @@
"MODIFY_SSH_INFO": "Modify the SSH information of HOST: {1}",
"ADD_SSH_INFO": "Add the SSH information of HOST: {1}",
"DEL_SSH_INFO": "Delete the SSH information of HOST: {1}",
"TYPE_TERMINAL": "aaPanel terminal",
"ADD_COMMAND_COMMAND": "Add common commands [{1}]",
"EDIT_COMMAND_COMMAND": "Modify common commands [{1}]",
"DEL_COMMAND_COMMAND": "Delete common commands [{1}]",
"OPEN_FILE": "Open File",
"TASK_QUEUE": "Task queue"
"TASK_QUEUE": "Task queue",
"SSH_LOGIN": "Successfully logged in to the SSH server [{1}:{2}]",
"EDIT_MENU_SUCCESS": "Successfully modify the panel menu display list",
"TMP_LOGIN": "Generate temporary connection, expiration time: {1}",
"TMP_LOGIN1": "Temporary login URL has been generated",
"TMP_LOGIN2": "Failed to generate temporary login URL",
"TMP_LOGIN3": "Delete temporary login URL",
"LOGOUT_TMP_UESR": "Force logout of temporary users:{1}",
"CREATE_USER": "Create new user {1}",
"DEL_USER": "Delete users[{1}]",
"EDIT_USER": "Edit user{1}",
"ADD_COMPILATION_PARA": "Add custom compilation parameters: {1}:{2}",
"REMOVE_PARA": "Remove custom compilation parameters: {1}:{2}",
"SET_SOFTWARE_COMPILATION": "Setup software: Custom compilation parameters for {1} are configured as: {2}",
"SET_FILE_NOTES": "Set the file name [{1}], notes: {2}",
"CLEAR_FILE_NOTES": "Clear file notes [{1}]"
}
+238 -3
View File
@@ -185,6 +185,7 @@
"DATABASE_NAME_ERR":"Database name is illegal!",
"DATABASE_NAME_ERR_T":"Database name cannot contain special characters!",
"DATABASE_NAME_EXISTS":"Database exists!",
"DATABASE_USERNAME_EXISTS": "The user name already exists. For security reasons, we do not allow one database user to manage multiple databases",
"DATABASE_NAME_LEN":"Database name cannot be more than 16 characters!",
"DATABASE_ERR_CONNECT":"ERROR to connect database, pls check database status!",
"DATABASE_ERR_PASS":"Mysql root or user password is incorrect, please try to reset!",
@@ -474,7 +475,6 @@
"AUTO_INSTALL_ACME_FAIL": "Trying to automatically install ACME failed, please try to install manually by the following command<p>Installation command",
"SET_API_FIRST": "Please set this API first",
"INSTALL_CLOUDDNS_FIRST": "Please install the [CloudDNS] plugin first.",
"CHOOSE_DOMAIN": "Please choose domain",
"CHECK_SSL_ERR": "Wildcard domain cannot use the method of [file verification] to apply for a certificate!",
"RESOLVE_DOMAIN_BYF": "Successfully got, please manually resolve the domain name",
"GET_FAIL": "Failed to get!",
@@ -970,7 +970,6 @@
"SSH_LOGIN_ERR4": "The protocol header response timed out, and the network quality with the target server was too bad: {1}",
"SSH_LOGIN_ERR5": "The SSH protocol handshake timed out, and the network quality with the target server is too bad",
"SSH_LOGIN_ERR6": "unknown error: {1}",
"SSH_LOGIN": "Successfully logged in to the SSH server [{1}:{2}]",
"LOGIN_SUCCESS2": "Login success\n",
"CONNECTION_SUCCEEDED": "connection succeeded",
"RECONNECT_SSH": "The connection is disconnected, press enter to try to reconnect!",
@@ -984,5 +983,241 @@
"UNBOUND_DEVICE": "Unbound device",
"KEY_ERR": "Key verification failed",
"FORM_DATA_ERR": "No form_data data found",
"WRONG_RESPONSE": "Wrong response: {1}"
"WRONG_RESPONSE": "Wrong response: {1}",
"TYPE_TERMINAL": "aaPanel terminal",
"WRONG_CONN_ADDR": "Wrong connection address",
"RECONN_TIMES": "Reconnection attempts:{1}",
"RECONN_FAILED": "Retry connection failed, {1}",
"CONN_FAIL": "Connection failure: {1}",
"CONN_FAIL1": "Connection failure: {1}:{2}",
"AUTH_PRI_KEY": "Authenticating private key",
"AUTH_PASSWD": "Authenticating password",
"AUTH_FAIL": "Authentication failed {1}",
"SSH_LOGIN_ERR10": "The protocol header response timed out",
"SSH_LOGIN_ERR11": "The SSH protocol handshake timed out",
"SSH_LOGIN_INFO3": "The authentication is successful and the session channel is being constructed",
"SSH_LOGIN_INFO2": "Channel is built",
"SSH_LOGIN_ERR14": "Channel disconnected",
"SSH_LOGIN_INFO": "Session interrupted",
"SSH_LOGIN_ERR15": "Error reading tty buffer data, {1}",
"SSH_LOGIN_INFO1": "The client has actively disconnected",
"SSH_LOGIN_ERR16": "An error occurred while reading data from websocket. Retrying",
"SSH_LOGIN_ERR17": "An error occurred while writing data to the buffer: {1}",
"DB_EXIST1": "The specified database already exists in MySQL, please change the name!",
"LOGOUT_TMP_USER": "Temporary user has been forcibly logged out:{1}",
"TMP_USER_NOT_LOGIN": "The specified user is not currently logged in!",
"PERMISSION_DENIED": "Permission denied!",
"PARAMETER_LEN_ERR": "Wrong parameter length!",
"PARAMETER_FORMAT_ERR": "Wrong parameter format",
"VCODE_LEN_ERR": "Verification code length error!",
"EXTRA_PARAMETER_ERR": "There can be no extra parameters in the login parameters",
"USER_OR_PASSWD_ERR": "Username or Password incorrect: {1}",
"NGINX_CONF_NOT_EXISTS": "Nginx configuration file does not exist!",
"PARAMETER_WEBNAME_ERR": "The format of the webname parameter is incorrect, it should be a parseable JSON string",
"WEBSITE_TRAFFIC_LIMIT_ERR": "Concurrency restrictions, IP restrictions, traffic restrictions must be greater than 0",
"INDEX_FILE_ERR": "Failed to get, there is no default document in the configuration file",
"STATIC": "Static",
"PHP_SETUP_FAILED": "Setup failed, no enable-php-xx related configuration items were found in the website configuration file!",
"GET_RUN_PATH_FAILED": "Get Site run path false",
"ANTI_THEFT_EMPTY_ERR": "Anti-theft chain domain name cannot be empty!",
"ANTI_THEFT_ERR": "Please turn on anti-theft first!",
"SSL_ORDER_GET_FAILED": "Failed to get, please try again later!",
"SSL_ORDER_HTTPS_ERR": "[Force HTTPS] is enabled on the current website, please turn off this function before applying for an SSL certificate!",
"SSL_ERR_MSG": "Cannot access verification file correctly",
"SSL_ERR_MSG1": "Possible reason:",
"SSL_ERR_MSG2": "1. The resolution is not correct, or the resolution is not effective [Please resolve the domain name correctly, or wait for the resolution to take effect and try again]",
"SSL_ERR_MSG3": "2. Check if there is 301/302 redirection set up [please temporarily turn off the redirection related configuration]",
"SSL_ERR_MSG4": "3. Check whether the website is set to force HTTPS [please turn off the force HTTPS function temporarily]",
"SSL_RENEW_ERR": "There are currently no certificates to renew!",
"WEBSITE_SSL_RENEW_ERR": "There is no certificate that can be renewed on the current website..",
"MYSQL_SSL_ERR": "SSL is not enabled in the database, please open it in the Mysql manager first",
"MYSQL_SSL_OPEN_SUCCESS": "Open successfully, take effect after manually restarting the database",
"MYSQL_CONF_ERR": "Database configuration file failed to get checked, please check if MySQL configuration file exists [/etc/my.cnf]",
"MYSQL_DATA_DIR_ERR": "The database directory does not exist!",
"MYSQL_BINLOG_ERR": "Please uninstall the Mysql master-slave replication plugin before closing the binary log! !",
"MYSQL_PARAMETER_ERR": "innodb_log_buffer_size cannot be less than 8MB",
"NONSUPPORT51": "Nonsupport mysql5.1!",
"START_BACKUP": "Start backup",
"BACKUP_COMPLETED": "Backup completed",
"BACKUP_DIR_NOT_EXIST": "The specified directory {1} does not exist!",
"BACKUP_UPLOADING": "Uploading to {1}, please wait ...",
"BACKUP_UPLOAD_SUCCESS": "Successfully uploaded to {1}",
"BACKUP_UPLOAD_FAILED": "Error: File upload failed, skip this backup!",
"BACKUP_DEL": "User settings do not retain local backups, deleted {1}",
"BACKUP_CLEAN_ERR": "Failed to clean expired backup, error: {1}",
"BACKUP_KEEP": "Keep the latest number of backups: {1} copies",
"BACKUP_CLEAN": "Expired backup files have been cleaned from disk: {1}",
"BACKUP_CLEAN_REMOVE": "Expired backup files have been cleaned from {1}: {2}",
"BACKUP_SITE": "Backup site: {1}",
"WEBSITE_DIR": "Website root directory: {1}",
"BACKUP_DIR": "Backup directory: {1}",
"DIR_SIZE": "Directory size: {1}",
"BACKUP_EXCLUSION": "Exclusion setting: {1}",
"PARTITION_INFO": "Partition {1} available disk space is: {2}, available Inode is: {3}",
"PARTITION_LESS_THEN": "The available disk space of the target partition is less than {1}, and the backup cannot be completed. Please increase the disk capacity or change the default backup directory on the settings page!",
"INODE_LESS_THEN": "The available Inode of the target partition is less than {1}, and the backup cannot be completed. Please increase the disk capacity or change the default backup directory on the settings page!",
"START_COMPRESS": "Start compressing files: {1}",
"COMPRESS_TIME": "Compression completed, took {1} seconds, compressed package size: {2}",
"WEBSITE_BACKUP_TO": "Site backed up to: {1}",
"DIR_BACKUP_TO": "Directory has been backed up to: {1}",
"DB_BACKUP_ERR": "The specified database [ {1} ] has no data!",
"DB_BACKUP": "Backup database:{1}",
"DB_SIZE": "Database size: {1}",
"DB_CHARACTER": "Database character set: {1}",
"EXPORT_DB": "Start exporting database: {1}",
"EXPORT_DB_ERR": "Database export failed!",
"DB_BACKUP_TO": "Database has been backed up to: {1}",
"EMAIL_NOT_EXISTS": "Email does not exist",
"INPUT_EMAIL": "Please input your email",
"EMAIL_ERR": "Please enter your vaild email",
"EMAIL_EXISTS": "Email already exists",
"COMPLETE_INFO": "Please complete the information",
"TEST_MAIL_TITLE": "aaPanel Alert Test Email",
"TEST_MAIL_CONTENT": "aaPanel Alert Test Email",
"TEST_MAIL_SEND_ERR": "Email sending failed, please check if the STMP password is correct or the hosts are correct",
"NO_DATA": "No Data",
"MAILBOX_NOT_EXIST": "The mailbox does not exist, please add it to the mailbox list",
"EMAIL_TITLE_ERR": "Please fill in the email title",
"EMAIL_CONTENT_ERR": "Please enter the email content",
"SMTP_INFO_ERR": "STMP information was not found, please re-add custom mail STMP information in the settings",
"SEND_SUCCESS": "Sent successfully",
"SEND_FAILED": "Failed to send",
"USERNAME_ERR": "User name must be at least 2 characters",
"PASSWORD_ERR": "Password must be at least 8 characters",
"USERNAME_EXIST": "The specified username already exists!",
"USERNAME_NOT_EXIST": "The specified username not exists!",
"CREATE_USER_SUCCESS": "Create new user {1} success!",
"DEL_USER_ERR": "Cannot delete initial default user!",
"DEL_USER_SUCCESS": "Delete user {1} success!",
"DEL_USER_FAILED": "User deletion failed!",
"CREATE_USER_FAILED": "Create new user failed!",
"NO_CHANGE_SUBMITTED": "No changes submitted",
"WRONG_MODE": "Wrong operating mode",
"EMAIL_FORMAT_ERR": "The E-Mail format is illegal",
"GET_PHP_VER_ERR": "Failed to get php version!",
"DEVELOPER_MODE": "{1} Developer mode(DeBug)",
"OFFLINE_MODE": "{1} Offline mode",
"KEY_NOT_EXIST": "The key does not exist. Please turn on and try again.",
"USERNAME_NOT_EXIST1": "The username does not exist. Please turn on and try again.",
"SELECT_MODE": "Please enter the operation mode",
"GENERATE_KEY_ERR": "Failed to generate key or username. Please check if the hard disk space is insufficient or the directory cannot be written.[ {1} ]",
"CLOSE_SUCCESS": "Closed successfully",
"GOOGLE_AUTH_ERR": "Did not open Google authentication",
"TURN_ON_GOOGLE_AUTH": "Google authentication has been turned on",
"QR_CODE_ERR": "No QR code data, please re-open",
"MYSQL_ROOT_PASSWD_EMTPY_ERR": "Root password cannot be empty",
"DB_PASSWD_EMPTY_ERR": "Database [{1}] password cannot be empty",
"NGINX_NOT_INSTALL": "Nginx is not install",
"CREATE_SITE_DIR_ERR": "Failed to create site root directory, {1}",
"CHOOSE_DOMAIN": "Please choose a domain name",
"CHOOSE_PORT": "Please choose a port",
"CERT_ERR": "Certificate error, please paste the correct PEM format certificate!",
"SSL_FILE_V_ERR": "A generic domain name cannot be used to apply for a certificate using [File Validation]!",
"SSL_FILE_V_ERR_PROXY": "Sites that have reverse proxy turned on cannot request SSL!",
"API_ERR": "Please set the API interface parameters of [{1}] first.",
"CLOUD_DNS_ERR": "Please go to the software store to install [Cloud Resolution] and complete the domain name NS binding.",
"REQUEST_MODULE_ERR": "Missing requests component, please try to repair the panel!",
"WEBSITE_CONF_NOT_EXIST": "The specified website profile does not exist",
"RESPONSE_ERR": "Response resources should use URI path or HTTP status code, such as: /test.png or 404",
"PHP_NOT_FOUND": "No compatible PHP version found, please install first",
"COMPLIANT_NAME_ERR": "Non-compliant names can only be numbers, letters, underscores",
"PARA_NOT_EXIST": "The specified custom compilation parameters do not exist!",
"WRONG_PARAMETER": "Wrong parameter",
"UPLOAD_DIR_ERR": "Cannot upload files to the system root directory!",
"RECYCLE_BIN_ERR": "This is the recycle bin directory, please press the [Recycle Bin] button in the upper right corner to open",
"DIR_ERR": "This is not a directory",
"FILE_EXIST_ERR": "The target file name already exists!",
"MEANINGLESS_OPERA": "Meaningless operation",
"FILE_ONLINE_EDIT_ERR": "The file format does not support online editing!",
"FILE_ERR": "This is not a file!",
"FILE_ERR1": "File encoding is not compatible and cannot be read correctly!",
"FILE_ERR2": "Failed to open file, file may be occupied by other processes!",
"PATH_PARA_ERR": "[path] parameter cannot be empty!",
"HISTORY_DIR_ERR": "Cannot modify history copy directly!",
"FILE_ERR3": "Wrong file content, please save again!",
"HISTORY_ERR": "The specified historical copy does not exist!",
"NOT_EDIT": "Not Edit",
"AUTO_SAVE": "Automatically saved successfully!",
"COPY_PRESS_ERR": "The operation failed, please re-copy the copy or cut process",
"OPERA_FAILED": "The operation failed, please re-operate",
"PHP_EXTENSION_UNINSTALL_ERR": "This extension is the default extension of OLS and cannot be uninstalled",
"QUERY_ERR": "Query error, {1}",
"FILE_DIR_NOT_EXIST": "File or directory does not exist!",
"ADD_REPEATEDLY": "Do not add it repeatedly!",
"FAVORITE_NOT_FOUND": "This favorite object could not be found!",
"ADDRESS_NOT_EXIST": "The specified address does not exist!",
"PASSWD_ERR": "The extract password length cannot be less than 4 bits",
"ALREADY_SHARED": "Already shared!",
"COMMAND_SENT": "Command has been sent!",
"NO_COMPOSER_AVAILABLE": "No composer available!",
"PHP_VER_NOT_FOUND": "No available PHP version was found, or the specified PHP version was not installed!",
"COMPOSER_CONF_NOT_FOUND": "The composer.json configuration file was not found in the specified directory!",
"COMPOSER_UPDATE_ERR": "Currently the latest version, no upgrade required!",
"COMPOSER_UPDATE": "Upgrade composer from {1} to {2}",
"SITE_SSL_ERR_3011": "The website has been redirected, please close it before applying!",
"DEL_ERROR1": "There was an error deleting, please try again.",
"DEL_WEBSITE_MULTIPLE": "Delete website [{1}] successfully",
"DEL_DOMAIN_MULTIPLE": "Delete domain [{1}] successfully",
"ENABLE_WEBSITE_MULTIPLE": "Enable website [{1}] successfully",
"DISABLE_WEBSITE_MULTIPLE": "Disable website [{1}] successfully",
"DEL_SUBDIRBIND": "Delete [{}] subdirectory binding successfully",
"SET_ERROR1": "There was an error setting, please try again.",
"SET_PHPV_MULTIPLE": "Set up website [{1}] PHP version successfully",
"SET_EDATE_MULTIPLE": "Set the website [{1}] expiration time successfully",
"CREATE_WEBSITE_ERR": "There was an error creating, please try again.",
"CREATE_WEBSITE_MULTIPLE": "Create the website [ {1} ] successfully",
"DEL_PROXY_MULTIPLE": "Delete [ {1} ] proxy successfully",
"DEL_DIR_AUTH_MULTIPLE": "Delete [ {} ] dir auth successfully",
"DEL_REDIRECT_MULTIPLE": "Delete redirects [{1}] successfully",
"ALARM_TEST": "aaPanel alarm test",
"MAIL_ADD_FAILED": "Add failed, please check if the URL is correct",
"RENEW_FAILED": "The renewal failed and the certificate directory does not exist.",
"RENEW_FAILED1": "Renewal failed, missing account_key.",
"RENEW_SUCCESS1": "[ {1} ] The certificate renewal was successful.",
"APPLY_SSL": "Ready to apply for SSL, domain name {1}",
"APPLY_SSL_DOMAIN_ERR": "The list of applied domain names cannot be empty.",
"MANUALLY_RESOLVE_DOMAIN": "Get successful, please manually resolve the domain name",
"SAVEING_SSL": "|-Saving certificate..",
"SET_AUTORENEW": "|-Setting up auto-renewal configuration..",
"DEPLOY_SSL_TO_SITE": "|-The application is successful and it is being automatically deployed to the website!",
"APPLY_SSL_SUCCESS": "Application successful.",
"INIT_ACME": "|-Initializing ACME protocol...",
"REGISTER_ACCOUNT": "|-Registering account...",
"GET_VERIFICATION_INFO": "|-Getting verification information...",
"RETURN_VERIFICATION_INFO": "|-Return the verification information to the front end, wait for the user to manually resolve the domain name and complete the verification...",
"SUBMIT_V_REQUEST": "|-User submits verification request...",
"CA_V_DOMAIN": "|-Requesting CA to verify domain name [{1}]...",
"GET_CA_V_RES": "|-Get CA verification results [{1}]...",
"ALL_DOMAIN_V_PASS": "|-All domain names are verified and CSR is being sent...",
"GET_CERT_CONTENT": "|-Getting certificate content...",
"CERT_APPLY_ERR": "Certificate acquisition failed, please try again later.",
"CERT_APPLY_ERR1": "|-Error: {1}, exited the application process.",
"DNS_CONNECT_ERR": "|-The DNS verification failed. Please check if the key is correct.",
"EXIT_APPLY_PROCESS": "|-Exited the application process!",
"DNS_CONNECT_ERR1": "The DNS verification failed. Please check if the key is correct.",
"ADD_TXT_RECORD": "|-Adding resolution record, domain name [{1}], record value [{2}]...",
"CHECK_TXT_RECORD": "|-Attempt to verify the resolution result, domain name [{}], record value [{}]...",
"CA_CHECK_RECORD": "|-Request CA to verify domain name [{1}]...",
"CHECK_CA_RES": "|-Check CA verification results [{1}]...",
"APPLY_WITH_DNS_ERR": "|-An error occurred, try again [{1}]",
"FETCH_CERT_CONTENT": "|-Fetching certificate content...",
"CLEAR_RESOLVE_HISTORY": "|-Clearing resolve history [{1}]",
"DNS_APPLY_ERR": "|-Error: {1}, exit the application process.",
"CREATE_V_FILE": "|-Writing verification file [{1}]...",
"CHECK_FILE_CONTENT": "|-Attempt to verify file contents via HTTP [{1}]...",
"CHECK_FILE_CONTENT1": "|-Verified, content [{1}]...",
"APPLY_SSL_ERROR_MSG": "The signing failed, we were unable to verify your domain name:<p>1. Check if the domain name is bound to the corresponding site.</p><p>2. Check if the domain name is correctly resolved to the server, or the resolution is not fully effective.</p><p>3. If your site has a reverse proxy set up, or if you are using a CDN, please turn it off first.</p><p>4. If your site has a 301 redirect, please turn it off first</p><p>5. If the above checks confirm that there is no problem, please try to change the DNS service provider.</p>'",
"SUCCESS_V": "|-Successful verification, domain name [{1}], record type [{2}], record value [{3}]!",
"NO_ORDER_RENEW": "|-There are currently no certificates to renew.",
"TOTAL_RENEW": "|-{1} Total [{2}] renewal of visa tasks",
"SSL_NOT_EXPIRED_OR_NOT_USE": "|-[{1}] Not expired or the site does not use the Let\\'s Encrypt certificate.",
"WAIT_RENEW1": "|-{1} Waiting for renewal [{2}].",
"RENEW_COMPLETED": "|-After the task is completed, a total of renewals are required.[{1}], renewal success [%s], renewal failed [{2}]. ",
"RENEW_SUCCESS2": "|-Renewal success{1}",
"RENEW_FAILED2": "|-Renewal failed",
"DIR_END_WITH": "The end of the website directory cannot be \".\"",
"File_END_WITH": "It is not recommended to use \".\" at the end of the file because there may be security risks",
"DIR_END_WITH1": "It is not recommended to use \".\" at the end of the directory, because there may be safety risks",
"API_DISABLED": "API has been disabled",
"UNBOUND_USER": "Unbound user"
}
@@ -31,7 +31,7 @@
"NET3":"Download speed",
"NET4":"Total sent",
"NET5":"Total received",
"BT_ACCOUNT":"BT account",
"ACCOUNT":"Account",
"FREE":"Free",
"INVITATION_REWARD":"Invitation reward",
"WECHAT":"WeChat",
@@ -139,7 +139,7 @@
"CT8":"Server time",
"CT9":"Panel user",
"CT10":"Panel password",
"CT11":"Bind BT account",
"CT11":"Bind account",
"CT12":"Panel template",
"CY1":"Take alias for aaPanel",
"CY2":"Suggested port: 8888-65535",
@@ -1144,7 +1144,7 @@ var lan = {
"site_menu_1": "Subdirectory binding",
"site_menu_2": "Website directory",
"site_menu_3": "Traffic control",
"site_menu_4": "URL rewirte",
"site_menu_4": "URL rewrite",
"site_menu_5": "Default indexes",
"site_menu_6": "Configuration file",
"site_menu_7": "SSL",
@@ -1191,7 +1191,7 @@ var lan = {
"limit_net_14": "Traffic control",
"limit_net_15": "Limit the max traffic limit per request (unit: KB)",
"subdirectories": "Subdirectories",
"url_rewrite_alter": "Are you sure to create a independent URL rewirte rule for this subdirectory?",
"url_rewrite_alter": "Are you sure to create a independent URL rewrite rule for this subdirectory?",
"rule_cov_tool": "Rewrite rule converter",
"a_c_n": "Apache to Nginx",
"save_as_template": "Save as template",
+2 -2
View File
@@ -299,7 +299,7 @@
show: false,
showBottom: true,
btns: ["clear", "now", "confirm"],
lang: "cn",
lang: "en",
theme: "default",
position: null,
calendar: false,
@@ -1424,7 +1424,7 @@
}
} else {
if(lay(btn).hasClass(DISABLED)) {
return that.hint("不在有效日期或时间范围内")
return that.hint("Not in the valid date or time range!")
}
}
that.done();
+46 -7
View File
@@ -103,15 +103,19 @@
<span class="set-info c7">{{data['lan']['CY15']}}</span>
</div>
<div class="mtb15">
<span class="set-tit text-right" title="{{data['lan']['BASICAUTH_TIPS1']}}">{{data['lan']['BASICAUTH']}}</span>
<input id="basic_auth" name="basic_auth" class="inputtxt bt-input-text disable" type="text" value="{{data['basic_auth']['value']}}" disabled>
<span class="modify btn btn-xs btn-success basic_auth" onclick="modify_basic_auth()" style=" margin-left: -38px;">{{data['lan']['CONFIG']}}</span>
<span class="set-tit text-right" title="{{data['lan']['BASICAUTH_TIPS1']}}">{{data['lan']['BASICAUTH']}}</span>
<div class="btn_tips">
<input id="basic_auth" name="basic_auth" class="inputtxt bt-input-text disable" type="text" value="{{data['basic_auth']['value']}}" disabled>
<span class="modify btn btn-xs btn-success basic_auth" onclick="modify_basic_auth()" style="margin-left: -38px;">{{data['lan']['CONFIG']}}</span>
</div>
<span class="set-info c7" style="margin-left: 25px;">{{data['lan']['BASICAUTH_TIPS1']}}</span>
</div>
<div class="mtb15">
<span class="set-tit text-right" title="Message channel">Message channel</span>
<input id="channel_auth" name="channel_auth" class="inputtxt bt-input-text disable" type="text" value="" disabled>
<span class="modify btn btn-xs btn-success channel_auth" style="margin-left: -38px;" onclick="open_three_channel_auth()">Set</span>
<span class="set-tit text-right" title="Message channel">Message channel</span>
<div class="btn_tips">
<input id="channel_auth" name="channel_auth" class="inputtxt bt-input-text disable" type="text" value="" disabled>
<span class="modify btn btn-xs btn-success channel_auth" style="margin-left: -38px;" onclick="open_three_channel_auth()">Set</span>
</div>
</div>
<div class="mtb15">
<span class="set-tit text-right" title="{{data['lan']['CT3']}}">{{data['lan']['CT3']}}</span>
@@ -160,7 +164,28 @@
<input name="password_" class="inputtxt bt-input-text disable" type="text" value="******" disabled>
<span class="modify btn btn-xs btn-success" onclick="setPassword()">{{data['lan']['CY10']}}</span>
</div>
</div>
</div>
<div class="mtb15">
<span class="set-tit text-right" title="{{data['lan']['CT10']}}">{{data['lan']['CT11']}}</span>
<div class="btn_tips">
<input name="btusername" class="inputtxt bt-input-text disable" type="text" value="" disabled>
<span class="modify btn btn-xs btn-success mr5" onclick="bindBTName(2,'b')">{{data['lan']['CY11']}}</span>
</div>
</div>
<div class="mtb15">
<span class="set-tit text-right">Menu bar hidden</span>
<div class="btn_tips">
<input class="inputtxt bt-input-text disable" id="panel_menu_hide" type="text" disabled>
<span class="modify btn btn-xs btn-success" onclick="set_panel_ground()" style="margin-left: -35px;">Set</span>
</div>
</div>
<div class="mtb15">
<span class="set-tit text-right">Temporary login</span>
<div class="btn_tips">
<input class="inputtxt bt-input-text disable" type="text" value="Temporary authorization for vistor" disabled>
<span class="modify btn btn-xs btn-success" onclick="get_temp_login_view()">Modify</span>
</div>
</div>
<!--<p class="mtb15"><span class="set-tit text-right" title="{{data['lan']['CT11']}}">{{data['lan']['CT11']}}</span><input name="btusername" class="inputtxt bt-input-text disable" type="text" value="" disabled><span class="modify btn btn-xs btn-success mr5" onclick="bindBTName(2,'b')">{{data['lan']['CY11']}}</span></p>-->
<!--<p class="mtb15 wxapp_p"><span class="set-tit text-right">{{data['lan']['WECHAT']}}</span><input class="inputtxt bt-input-text disable" type="text" value="{{data['wx']}}" disabled><span class="modify btn btn-xs btn-success mr5" onclick="open_wxapp()">{{data['lan']['CY11']}}</span></p>-->
@@ -367,6 +392,20 @@
margin: 0 0 10px 35px;
font-size: 22px;
}
#panel_menu_tab .table>tbody>tr>td{
height: auto;
padding: 8px;
}
.create_temp_view{
padding:15px 20px;
}
.create_temp_view .line .tname{
text-align: left;
float: inherit;
}
.create_temp_view .info-r {
margin: 0;
}
</style>
{% endblock %}
+1 -1
View File
@@ -168,7 +168,7 @@
<th>{{data['lan']['TH3']}}</th>
<th>{{data['lan']['TH7']}}</th>
<th>{{data['lan']['TH8']}}</th>
<th>{{data['lan']['TH4']}}</th>
<th>Last execution time</th>
<th width="190">{{data['lan']['TH5']}}</th>
</tr>
</thead>
+10 -1
View File
@@ -1,6 +1,15 @@
{% extends "layout.html" %}
{% block content %}
<style>
#DataBody .dataBase,#DataBody .webNote{
white-space: nowrap;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
min-width: auto;
}
</style>
<div class="main-content pb55">
<div class="container-fluid">
<div class="pos-box bgw mtb15">
@@ -22,7 +31,7 @@
<button onclick="database.add_database()" title="{{data['lan']['BTNT1']}}" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">{{data['lan']['BTN1']}}</button>
<button onclick="bt.database.set_root()" title="{{data['lan']['BTNT2']}}" class="btn btn-default btn-sm" type="button" style="margin-right: 5px;">{{data['lan']['BTN2']}}</button>
<button onclick="bt.database.open_phpmyadmin('','root','{{data['mysql_root']}}')" title="{{data['lan']['BTNT3']}}" class="btn btn-default btn-sm" type="button" style="margin-right: 5px;">{{data['lan']['BTN3']}}</button>
<!-- <a href="/adminer/index.php" target="_blank" title="Lightweight database management tool that supports remote database management" class="btn btn-default btn-sm" type="button" style="margin-right: 5px;">Adminer</a> -->
<!--<a href="/adminer/index.php" target="_blank" title="Lightweight database management tool that supports remote database management" class="btn btn-default btn-sm" type="button" style="margin-right: 5px;">Adminer</a>-->
<span style="float:right">
<button batch="true" style="float: right;display: none;margin-left:10px;" onclick="database.batch_database('del');" title="{{data['lan']['BTNT4']}}" class="btn btn-default btn-sm">{{data['lan']['BTN4']}}</button>
<button onclick="bt.recycle_bin.open_recycle_bin(6)" id="dataRecycle" title="{{data['lan']['BTNT4']}}" class="btn btn-default btn-sm" style="margin-left: 5px;"><span class="glyphicon glyphicon-trash" style="margin-right: 5px;"></span>{{data['lan']['RECYCLE_BIN']}}</button>
+284 -113
View File
@@ -1,104 +1,308 @@
{% extends "layout.html" %}
{% block content %}
<link rel="stylesheet" href="{{g.cdn_url}}/ace/styles/icons.css">
<link rel="stylesheet" type="text/css" href="{{g.cdn_url}}/css/files_style.min.css">
<style id="file_list_info">.file_checkbox{width:40px !important;}.file_name{width:300px !important;}.file_ps{width:200px !important;}.file_size{width:100px !important;}.file_mtime{width:180px !important;}.file_user{width:80px !important;}.file_accept{width:80px !important;}.file_operation{width:220px !important;}.file_table_view.list_view .file_list_content .file_tr{width:auto;}.file_table_view.list_view .file_list_content{width:auto;}</style>
<div class="main-content">
<div class="container-fluid" style="padding-bottom:50px">
<div class="file-box bgw mtb15" style="position:relative; padding-top:110px">
<div id="tipTools" class="plr15">
<div class="ptb15">
<div class="clearfix">
<div class="pull-left">
<button id="backBtn" class="backBtn btn btn-default btn-sm glyphicon glyphicon-arrow-left pull-left" title="{{data['lan']['BTN1']}}" onClick="BackDir()"></button>
<button class="backBtn refreshBtn btn btn-default btn-sm glyphicon glyphicon-refresh pull-right" title="{{data['lan']['BTN2']}}" style="margin-left:-1px;"></button>
<span id='DirPathPlace' class="pull-left"><input id="fileInputPath" type="text"></span>
<span id='PathPlaceBtn' class="pull-left"></span>
</div>
<div class="pull-left mlr15" style="line-height:26px"><span id='DirInfo'></span></div>
<div class="search pull-right" style="position: absolute; top: 6px; right: 5px;">
<div class="search_box">
<input id="search_all" type="checkbox">
<label for="search_all">{{data['lan']['CONTAIN_SUBDIR']}}</label>
<a style="display: none;" id="recycle_bin" data="{{data['recycle_bin']}}"></a>
<div class="bt_file_updated">
<div class="updated_icon">
<div class="btn download">
<div class="cloud">
<div class="file"></div>
</div>
</div>
</div>
<div class="updated_title">Release the mouse to upload files or folders</div>
</div>
<!-- aceEditors -->
<div class="file_bodys">
<div class="file_path_views">
<div class="file_path_upper" title="Back">
<span class="glyphicon glyphicon-arrow-left"></span>
<!-- <span>Back</span> -->
</div>
<div class="file_path_input">
<div class="file_path_shadow"></div>
<div class="file_dir_view"></div>
<input type="text" data-path="/www/wwwroot" data-backspace class="path_input" id="fileInputPath"/>
</div>
<div class="file_path_refresh" title="Refresh"><i class="icon-file icon-file-refresh"></i></div>
<div class="search_path_views">
<input type="text" placeholder="Search file content" class="file_search_input">
<span class="iconfont icon-shezhi1 is_search_children"></span>
<button type="submit" class="path_btn"><i class="iconfont icon-search"></i></button>
<div class="file_search_config">
<div id="search_all" class="file_search_checked"></div>
<label for="search_all">Include SubDir</label>
</div>
</div>
</div>
<div class="file_nav_view">
<div class="nav_group">
<div class="nav_btn upload_file">
<span class="nav_btn_title">Upload</span>
</div>
</div>
<div class="nav_group">
<div class="nav_btn upload_download">
<span class="nav_btn_title">Remote download</span>
</div>
</div>
<div class="nav_group">
<div class="nav_btn create_file_or_dir">
<span class="nav_btn_title">New</span><i class="iconfont icon-xiala"></i>
<ul class="nav_down_list" data-menu="newFileType">
<li data-type="newBlankDir"><i class="file_menu_icon create_file_icon"></i><span>New directory</span></li>
<li data-type="newBlankFile"><i class="file_new_icon"></i><span>New blank file</span></li>
</ul>
</div>
</div>
<div class="nav_group">
<div class="nav_btn favorites_file_path">
<span class="nav_btn_title" data-menu="favorites">Favorites</span><i class="iconfont icon-xiala"></i>
<ul class="nav_down_list"></ul>
</div>
</div>
<div class="nav_group">
<div class="nav_btn share_file_list">
<span class="nav_btn_title">Share List</span>
</div>
</div>
<div class="nav_group ">
<div class="nav_btn terminal_view">
<i class="iconfont icon-terminal"></i>
<span class="nav_btn_title">Terminal</span>
</div>
</div>
<!-- 挂载磁盘列表 -->
<div class="nav_group mount_disk_list"></div>
<div class="float_r menu-header-foot">
<div class="nav_group multi hide">
<div class="batch_multi_title">
<span>Please choose</span>
<i class="iconfont icon-xiala"></i>
<div class="batch_group_list">
<div class="nav_btn_group" data-type="copy"><i class="file_menu_icon copy_file_icon"></i><span
class="nav_btn_title">Copy</span></div>
<div class="nav_btn_group" data-type="shear"><i class="file_menu_icon shear_file_icon"></i><span
class="nav_btn_title">Cut</span></div>
<div class="nav_btn_group" data-type="compress"><i class="file_menu_icon compress_file_icon"></i><span
class="nav_btn_title">Compress</span></div>
<div class="nav_btn_group" data-type="authority"><i class="file_menu_icon power_file_icon"></i><span
class="nav_btn_title">Permission</span></div>
<div class="nav_btn_group" data-type="del"><i class="file_menu_icon del_file_icon"></i><span
class="nav_btn_title">Del</span></div>
<div class="nav_btn_group hide" style="padding-left:10px;border-left: 1px solid #cfcfcf;margin-left: -1px;">
<span class="nav_btn_title">More</span><i class="iconfont icon-xiala"></i>
<ul class="nav_down_list">
<li data-type="copy"><i class="file_menu_icon copy_file_icon"></i><span>Copy</span></li>
<li data-type="shear"><i class="file_menu_icon shear_file_icon"></i><span>Cut</span></li>
<li data-type="compress"><i class="file_menu_icon compress_file_icon"></i><span>Compress</span></li>
<li data-type="authority"><i class="file_menu_icon power_file_icon"></i><span>Permission</span></li>
<li data-type="del"><i class="file_menu_icon del_file_icon"></i><span>Del</span></li>
</ul>
</div>
<form target="hid" onsubmit='GetFiles(1)'>
<input type="text" id="SearchValue" class="ser-text pull-left" placeholder="" style="padding-right: 159px;" />
<button type="button" class="ser-sub pull-left" onclick='GetFiles(1)'></button>
</form>
<iframe name='hid' id="hid" style="display:none"></iframe>
</div>
</div>
</div>
<div class="clearfix ptb10">
<button class="btn btn-default btn-sm pull-left" onclick="UploadFiles()">{{data['lan']['BTN3']}}</button>
<button class="btn btn-default btn-sm pull-left" onclick="DownloadFile()" title="{{data['lan']['TI1']}}" style="margin:0 5px">{{data['lan']['BTN4']}}</button>
<span id='BarTools'></span>
<span id='Batch' style="background-color:#fff;position:absolute;right:217px;z-index:10"></span>
<span id='comlist' class="comlist"></span>
<div class="btn-group btn-group-sm pull-right" style="margin-right:5px;">
<button id="set_icon" title="{{data['lan']['TI2']}}" type="button" class="btn btn-default">
<i class="glyphicon glyphicon-th"></i>
</button>
<button id="set_list" title="{{data['lan']['TI3']}}" type="button" class="btn btn-default active">
<i class="glyphicon glyphicon-th-list"></i>
</button>
<div class="nav_group file_all_paste hide">
<div class="nav_btn_group">
<i class="file_menu_icon paste_file_icon"></i><span class="nav_btn_title">Paste</span>
</div>
</div>
<div class="nav_group manage_backup">
<div class="nav_btn"><span class="glyphicon glyphicon-trash"></span><span class="nav_btn_title">Backup PMSN</span></div>
</div>
<div class="nav_group recycle_bin">
<div class="nav_btn"><span class="glyphicon glyphicon-trash"></span><span class="nav_btn_title">Recycle bin</span></div>
</div>
<div class="nav_group btn-group btn-group-sm">
<div class="btn btn-default cut_view_model" data-type="icon"><i class="glyphicon glyphicon-th"></i></div>
<div class="btn btn-default cut_view_model" data-type="list"><i class="glyphicon glyphicon-th-list"></i></div>
</div>
</div>
</div>
<div class="file_table_view">
<div class="file_list_header">
<div class="file_main_title">
<div class="file_checkbox file_th">
<div class="file_check" data-type="all" data-checkbox="0"></div>
</div>
<div class="file_name file_th" data-tid="name">
<span>File name</span>
<div class="icon_sort"></div>
</div>
<!-- <div class="file_width_resize"></div>
<div class="file_type file_th" data-tid="type">
<span>类型</span>
<div class="icon_sort"></div>
</div> -->
<div class="file_width_resize"></div>
<div class="file_accept file_th" data-tid="accept">
<span>PMSN/Owner</span>
<div class="icon_sort"></div>
</div>
<div class="file_width_resize"></div>
<div class="file_size file_th" data-tid="size">
<span>Size</span>
<div class="icon_sort"></div>
</div>
<div class="file_width_resize"></div>
<div class="file_mtime file_th" data-tid="mtime">
<span>Modification time</span>
<div class="icon_sort"></div>
</div>
<div class="file_width_resize"></div>
<div class="file_ps file_th" data-tid="ps">
<span>Ps</span>
<div class="icon_sort"></div>
</div>
<div class="file_width_resize"></div>
<div class="file_operation file_th align-right" data-tid="operation">
<span>Opt</span>
</div>
</div>
</div>
<div class="divtable pd15" id="fileCon"></div>
<div class="dataTables_paginate paging_bootstrap pagination plr15" style="position: relative; top: -15px;">
<ul id="filePage" class="page"></ul>
</div>
<div class="file_list_shadow file_shadow_top" style="opacity: 0;"></div>
<div class="file_list_content"></div>
<div class="file_list_shadow file_shadow_bottom" style="opacity: 0;"></div>
<div class="onselectstart"></div>
</div>
<div class="file_right_menu file_menu_list">
<ul class="set_group">
<!-- <li data-id="open_file"><i class="file_menu_icon open_file_icon"></i><span>打开文件夹</span></li> -->
<li data-id="edit_file"><i class="file_menu_icon edit_file_icon"></i><span>Open</span></li>
<li data-id="download_file"><i class="file_menu_icon download_file_icon"></i><span>Download</span></li>
<li class="separate"></li>
<li data-id="copy_file"><i class="file_menu_icon copy_file_icon"></i><span>Copy</span></li>
<li data-id="paste_file"><i class="file_menu_icon paste_file_icon"></i><span>Paste</span></li>
<!-- 判断类型是文件夹时,提示是否复制文件至该文件夹 -->
<li data-id="shear_file"><i class="file_menu_icon shear_file_icon"></i><span>Cut</span></li>
<li class="separate"></li>
<li data-id="rename_file"><i class="file_menu_icon rename_file_icon"></i><span>Rename</span></li>
<li data-id="power_file"><i class="file_menu_icon power_file_icon"></i><span>Permission</span></li>
<li data-id="decompression_file"><i
class="file_menu_icon decompression_file_icon"></i><span>Decompress</span></li>
<li data-id="compress_file">
<i class="file_menu_icon compress_file_icon"></i><span>Compress</span>
<div class="file_menu_down">
<span class="glyphicon glyphicon-triangle-right" aria-hidden="true"></span>
<ul class="set_group">
<li><i class="file_menu_icon compress_file_icon"></i><span>tar.gz (Default)</span></li>
<li><i class="file_menu_icon compress_file_icon"></i><span>zip (General format)</span></li>
<li><i class="file_menu_icon compress_file_icon"></i><span>rar (WinRAR is compatible with Chinese)</span>
</li>
</ul>
</div>
</li>
<li data-id="del_file"><i class="file_menu_icon del_file_icon"></i><span>Del</span></li>
<li class="separate"></li>
<li data-id="add_favorites"><i class="file_menu_icon add_favorites_icon"></i><span>Favorites</span>
</li>
</ul>
</div>
<div class="selection_right_menu file_menu_list">
<ul class="set_group">
<li data-id="copy_file"><i class="file_menu_icon copy_file_icon"></i><span>Copy</span></li>
<li data-id="paste_file"><i class="file_menu_icon shear_file_icon"></i><span>Cut</span></li>
<li data-id="download_file"><i class="file_menu_icon download_file_icon"></i><span>Download</span></li>
<li class="separate"></li>
<li data-id="del_file"><i class="file_menu_icon del_file_icon"></i><span>Del</span></li>
<li class="separate"></li>
<li data-id="paste_file"><i class="file_menu_icon copy_file_icon"></i><span>Copy to</span></li>
<li data-id="paste_file"><i class="file_menu_icon shear_file_icon"></i><span>Move to</span></li>
<li class="separate"></li>
<li data-id="compress_file">
<i class="file_menu_icon compress_file_icon"></i><span>Compress</span>
<div class="file_menu_down"><span class="glyphicon glyphicon-triangle-right"
aria-hidden="true"></span></div>
</li>
</ul>
</div>
<div class="content_right_menu file_menu_list">
<ul class="set_group">
<li data-id="refresh_file"><i class="file_menu_icon refresh_file_icon"></i><span>Refresh</span></li>
<li class="separate"></li>
<li data-id="upload_file"><i class="file_menu_icon upload_file_icon"></i><span>Upload</span></li>
<li data-id="newly_file"><i class="file_menu_icon newly_file_icon"></i><span>New file/directory</span></li>
<li class="separate"></li>
<li data-id="paste_file"><i class="file_menu_icon paste_file_icon"></i><span>Paste</span></li>
</ul>
</div>
<div class="filePage pagination page"></div>
</div>
</div>
<ul id="rmenu" class="dropdown-menu" style="display:none">
<li onclick="javascript:Batch(1);"><a style="cursor: pointer;">{{data['lan']['L1']}}</a></li>
<li onclick="javascript:Batch(2);"><a style="cursor: pointer;">{{data['lan']['L2']}}</a></li>
<li onclick="javascript:Batch(5);"><a style="cursor: pointer;">{{data['lan']['L3']}}</a></li>
<li onclick="javascript:Batch(3);"><a style="cursor: pointer;">{{data['lan']['L4']}}</a></li>
<li onclick="javascript:Batch(4);"><a style="cursor: pointer;">{{data['lan']['L5']}}</a></li>
</ul>
<link rel="stylesheet" href="./static/ace/styles/icons.css">
<script type="text/tmplate" id="aceTmplate">
<script type="text/template" id="upload_file_template">
<div class="upload_or_download_view">
<div class="upload_or_download_content active" data-type="upload">
<div class="upload_btn_groud">
<div class="btn-group">
<button type="button" class="btn btn-primary btn-sm upload_file_btn">Upload file</button>
<button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li><a href="#" data-type="file">Upload file</a></li>
<li><a href="#" data-type="dir">Upload directory</a></li>
</ul>
</div>
<div class="file_upload_info" style="display:none;">
<span>Total press&nbsp;<i class="uploadProgress"></i>, uploading&nbsp;<i class="uploadNumber"></i>,</span>
<span style="display:none">Fail&nbsp;<i class="uploadError"></i></span>
<span>Speed&nbsp;<i class="uploadSpeed">getting</i>,</span>
<span>Expect time&nbsp;<i class="uploadEstimate">getting</i></span><i></i>
</div>
</div>
<div class="upload_file_body active"><span>Please drag the file here</span></div>
<div class="upload_btn_group"><button type="button" class="btn btn-danger btn-sm upload_file_clear">Cancel upload</button><button type="button" class="btn btn-success btn-sm upload_file_submit">Start upload</button></div>
</div>
</div>
</script>
<script type="text/template" id="aceTmplate">
<div id="ace_conter">
<div class="ace_header">
<span class="saveFile"><i class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></i>Save</span>
<span class="saveFileAll"><i class="glyphicon glyphicon-duplicate" aria-hidden="true"></i>Save All</span>
<span class="refreshs"><i class="glyphicon glyphicon-refresh" aria-hidden="true"></i>Refresh</span>
<span class="searchs"><i class="glyphicon glyphicon-search" aria-hidden="true"></i>Search</span>
<span class="replaces"><i class="glyphicon glyphicon-retweet" aria-hidden="true"></i>Replace</span>
<span class="jumpLine"><i class="glyphicon glyphicon-pushpin" aria-hidden="true"></i>JumpLine</span>
<span class="fontSize"><i class="glyphicon glyphicon-text-width" aria-hidden="true"></i>Font</span>
<span class="themes"><i class="glyphicon glyphicon-magnet" aria-hidden="true"></i>Theme</span>
<span class="setUp"><i class="glyphicon glyphicon-cog" aria-hidden="true"></i>Set</span>
<span class="helps"><i class="glyphicon glyphicon-question-sign" aria-hidden="true"></i>Help</span>
<div class="pull-down" title="Hide toolbar"><i class="glyphicon glyphicon-menu-down" aria-hidden="true"></i></div>
<div class="ace_header" style="top: 0">
<span class="saveFile"><i class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></i><span>Save</span></span>
<span class="saveFileAll"><i class="glyphicon glyphicon-duplicate" aria-hidden="true"></i><span>Save All</span></span>
<span class="refreshs"><i class="glyphicon glyphicon-refresh" aria-hidden="true"></i><span>Refresh</span></span>
<span class="searchs"><i class="glyphicon glyphicon-search" aria-hidden="true"></i><span>Search</span></span>
<span class="replaces"><i class="glyphicon glyphicon-retweet" aria-hidden="true"></i><span>Replace</span></span>
<span class="jumpLine"><i class="glyphicon glyphicon-pushpin" aria-hidden="true"></i><span>JumpLine</span></span>
<span class="fontSize"><i class="glyphicon glyphicon-text-width" aria-hidden="true"></i><span>Font</span></span>
<span class="themes"><i class="glyphicon glyphicon-magnet" aria-hidden="true"></i><span>Theme</span></span>
<span class="setUp"><i class="glyphicon glyphicon-cog" aria-hidden="true"></i><span>Set</span></span>
<span class="helps"><i class="glyphicon glyphicon-question-sign" aria-hidden="true"></i><span>Help</span></span>
<div class="pull-down" title="Hide toolbar" style="top: 0"><i class="glyphicon glyphicon-menu-down" aria-hidden="true"></i></div>
</div>
<div class="ace_overall" style="top: 35px;">
<!-- 编辑器目录 -->
<div class="ace_catalogue">
<div class="ace_catalogue" style="left:0px">
<div class="ace_catalogue_title">Directory<div class="dir-menu-right"><span class="glyphicon glyphicon-minus" aria-hidden="true"></span></div></div>
<div class="ace_dir_tools">
<div class="upper_level" title="Back">
<div class="ace_dir_tools">
<div class="upper_level" title="Return to parent directory">
<i class="glyphicon glyphicon-share-alt" aria-hidden="true"></i>
<span>Back</span>
</div>
<div class="search_file" title="Search">
<div class="search_file" title="搜索内容">
<i class="glyphicon glyphicon-search" aria-hidden="true"></i>
<span>Search</span>
</div>
<div class="new_folder" title="New Folder/File">
<div class="new_folder" title="新建文件/目录">
<i class="glyphicon glyphicon-plus" aria-hidden="true"></i>
<span>New</span>
<ul class="folder_down_up">
<li data-type="2"><i class="folder-icon"></i>New Folder</li>
<li data-type="3"><i class="text-icon"></i>New File</li>
<li data-type="2"><i class="folder-icon"></i>新建文件夹</li>
<li data-type="3"><i class="text-icon"></i>新建文件</li>
</ul>
</div>
<div class="refresh_dir" title="ReFresh">
<div class="refresh_dir" title="刷新当前目录">
<span class="glyphicon glyphicon-refresh" aria-hidden="true"></span>
<span>ReFresh</span>
<span>Refresh</span>
</div>
<span class="ace_editor_main_storey"></span>
</div>
<div class="ace_catalogue_list">
<ul class="cd-accordion-menu"></ul>
<ul class="ace_catalogue_menu">
@@ -113,15 +317,13 @@
</div>
<div class="ace_catalogue_drag_icon">
<div class="drag_icon_conter"></div>
<span class="fold_icon_conter" title="Hide Directory"></span>
<span class="fold_icon_conter" title="Hide file directory"></span>
</div>
</div>
<!-- 编辑内容 -->
<div class="ace_editor_main">
<div class="ace_conter_menu">
<div class="ace_editor_add" style="display:none;"><i class="fa fa-plus-square" aria-hidden="true"></i></div>
</div>
<ul class="ace_conter_menu"></ul>
<div class="ace_conter_tips"><div class="tips"></div></div>
<div class="ace_editor_main_storey"></div>
<div class="ace_conter_editor"></div>
@@ -211,44 +413,13 @@
</script>
{% endblock %}
{% block scripts %}
<!--<link rel="stylesheet" type="text/css" href="https://at.alicdn.com/t/font_1628000_cso2y4bz1wk.css">-->
<script type="text/javascript" src="/static/js/jquery-ui.min.js"></script>
<script type="text/javascript" src="/static/js/jquery.contextify.min.js"></script>
<script type="text/javascript" src="/static/js/files.js?date20191219={{g.version}}"></script>
<!-- <script type="text/javascript" src="/static/js/bt_upload.js?version={{g['version']}}"></script> -->
<script type="text/javascript" src="/static/ace/ace.js?date={{g.version}}"></script>
<script type="text/javascript" src="/static/ace/ext-language_tools.js?date={{g.version}}"></script>
<script type="text/javascript" src="/static/js/clipboard.min.js"></script>
<script type="text/javascript" src="/static/js/jquery.dragsort-0.5.2.min.js"></script>
<script type="text/javascript" src="/static/js/polyfill.js"></script>
<script type="text/javascript">
setTimeout(function(){
GetDisk();
},500);
var xPath = getCookie('Path');
setTimeout(function(){
GetFiles((xPath!=undefined?xPath:'/www/wwwroot'));
},800);
PathPlaceBtn((xPath!=undefined?xPath:'/www/wwwroot'));
setCookie('uploadSize',1024 * 1024 * 1024);
if(getCookie('rank') == undefined || getCookie('rank') == null){
setCookie('rank','a');
}
$("#set_icon").click(function(){
setCookie('rank','b');
$(this).addClass("active");
$("#set_list").removeClass("active");
GetFiles(getCookie('Path'));
});
$("#set_list").click(function(){
setCookie('rank','a');
$(this).addClass("active");
$("#set_icon").removeClass("active");
GetFiles(getCookie('Path'));
});
$(".refreshBtn").click(function(){
GetFiles(getCookie('Path'));
});
</script>
{% endblock %}
<script type="text/javascript" src="{{g.cdn_url}}/js/jquery.dragsort-0.5.2.min.js" defer></script>
<script type="text/javascript" src="{{g.cdn_url}}/js/jquery.qrcode.min.js" defer></script>
<script type="text/javascript" src="{{g.cdn_url}}/js/public.js?version={{g['version']}}&repair={{data['js_random']}}"></script>
<script type="text/javascript" src="{{g.cdn_url}}/js/public_backup.js?version={{g['version']}}&repair={{data['js_random']}}"></script>
<script type="text/javascript" src="{{g.cdn_url}}/js/clipboard.min.js" defer></script>
<script type="text/javascript" src="{{g.cdn_url}}/js/polyfill.js"></script>
<script type="text/javascript" src="{{g.cdn_url}}/ace/ace.js" defer></script>
<script type="text/javascript" src="{{g.cdn_url}}/ace/ext-language_tools.js" defer></script>
<script type="text/javascript" src="{{g.cdn_url}}/js/files.min.js?version={{g['version']}}&repair={{data['js_random']}}"></script>
{% endblock %}
+16 -3
View File
@@ -128,10 +128,11 @@
</div>
<div class="divtable pd15">
<div class="firewall-port-box">
<select id="firewalldType" class="bt-input-text c5 mr5" name="type" style="width:80px;">
<select id="firewalldType" class="bt-input-text c5 mr5" name="type">
<option value="port">{{data['lan']['F1']}}</option>
<option value="address">{{data['lan']['F2']}}</option>
</select><input type="text" class="bt-input-text mr5" style="width: 117px;" id="AcceptPort" placeholder="{{data['lan']['F3']}}"><input type="text" class="bt-input-text mr5" id="Ps" placeholder="{{data['lan']['F4']}}"><button id="toAccept" onclick="firewall.add_accept_port()" class="btn btn-default btn-sm va0" type="button">{{data['lan']['F5']}}</button>
</select><input type="text" class="bt-input-text mr5" style="width: 117px;" id="AcceptPort" placeholder="{{data['lan']['F3']}}"><input type="text" class="bt-input-text mr5" id="Ps" placeholder="{{data['lan']['F4']}}"><button id="toAccept" onclick="firewall.add_accept_port()" class="btn btn-default btn-sm va0" type="button">{{data['lan']['F5']}}</button>
<button class="btn btn-default btn-sm sys_firewall" type="button">SYS Firewall</button>
<span id="f-ps" class="c9" style="margin-left: 10px;">{{data['lan']['F6']}}</span>
</div>
<div class="tablescroll">
@@ -208,7 +209,19 @@
firewall.flush_init();
}
})
})
});
$('.sys_firewall').on('click', function () {
$.post('/plugin?action=getConfigHtml', {name: 'firewall'}, function (rdata) {
if(rdata.status == false) {
layer.confirm('The SYS Firewall plugin is not installed, <br>please leave to &quot;<a href="/soft" class="btlink">APP Store > Tools</a>&quot;<br> install SYS Firewall plugin first.',
{title: 'No SYS Firewall', icon: 7, closeBtn: 2,}, function () {
window.location.href = '/soft';
});
} else {
bt.soft.set_lib_config('firewall','SYS Firewall');
}
});
});
$("#firewalldType").change(function(){
var type = $(this).val();
var w = '120px';
+30 -9
View File
@@ -1,6 +1,15 @@
{% extends "layout.html" %}
{% block content %}
<style>
#ftpData .webPath,#ftpData .webNote,#ftpData .ftpStatus{
white-space: nowrap;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
min-width: auto;
}
</style>
<div class="main-content pb55">
<div class="container-fluid">
<div class="pos-box bgw mtb15">
@@ -26,7 +35,7 @@
</span>
<div class="divtable mtb10">
<div class="tablescroll">
<table id="ftpData" class="table table-hover" style="min-width: 900px;border: 0 none;">
<table id="ftpData" class="table table-hover" style="min-width: 700px;border: 0 none;">
</table>
</div>
<div class="dataTables_paginate paging_bootstrap page">
@@ -58,7 +67,7 @@
return _html;
}},
{ field: 'status', title: lan.ftp.status,templet:function(item){
var _status = '<a href="javascript:;" title="'+lan.ftp.ftp_user+'"';
var _status = '<a class="ftpStatus" href="javascript:;" title="'+lan.ftp.ftp_user+'"';
if(item.status=='1'){
_status+=' onclick="ftp.stop_user('+item.id+',\''+item.name+'\') " >';
_status+='<span style="color:#5CB85C">'+lan.ftp.start+' </span><span style="color:#5CB85C" class="glyphicon glyphicon-play"></span>';
@@ -73,10 +82,10 @@
}},
{ field: 'path', title: lan.ftp.add_path,templet:function(item){
var _path = bt.format_path(item.path);
return '<a class="btlink" title="'+lan.ftp.open_path+'" href="javascript:openPath(\''+_path+'\');">'+_path+'</a>';
return '<a class="btlink webPath" title="'+lan.ftp.open_path+'" href="javascript:openPath(\''+_path+'\');">'+_path+'</a>';
}},
{ field: 'ps', title: lan.ftp.add_ps,templet : function(item){
return "<span class='c9 input-edit' onclick=\"bt.pub.set_data_by_key('ftps','ps',this)\">"+item.ps+ "</span>";
return "<span class='c9 input-edit webNote' onclick=\"bt.pub.set_data_by_key('ftps','ps',this)\">"+item.ps+ "</span>";
}},
{ field: 'opt',width:130, title: lan.ftp.operate,align:'right',templet:function(item){
var option = "<a href=\"javascript:;\" class=\"btlink\" onclick=\"ftp.set_password("+item.id+",'"+item.name+"','"+item.password+"')\" title="+lan.ftp.change_pass+">"+lan.ftp.edit_pass+"</a> | ";
@@ -85,8 +94,9 @@
}},
],
data:rdata.data
})
})
});
ftp.forSize();
});
},
batch_ftp:function(type,arr,result){
if(arr == undefined){
@@ -160,15 +170,26 @@
bt.ftp.set_status(id,username,1,function(rdata){
if(rdata.status) ftp.get_list();
})
},
//浏览器窗口大小变化时调整内容宽度
forSize:function(){
var ticket_with = $('#ftpData').parent().width(),
td_width = ticket_with*0.6-160-$('#ftpData th:eq(3)').width(),
path_width = td_width/2 > $('#ftpData th:eq(4)').width() ? $('#ftpData th:eq(4)').width() : td_width/2;
$('#ftpData .webPath').css('max-width',path_width);
$('#ftpData .webNote').css('max-width',td_width-$('#ftpData .webPath').width());
}
}
bt.set_cookie('sites_path',"{{session['config']['sites_path']}}");
$(window).resize(function() {
ftp.forSize();
});
{% if not data['isSetup'] %}
layer.msg('{{data["lan"]["JS1"]}}<a href="/soft" style="color:#20a53a; float: right;">{{data["lan"]["JS2"]}}</a>',{icon:7,time:0,shade: [0.3, '#000']});
$(".layui-layer-shade").css("margin-left", "180px");
$(".layui-layer-shade").css("margin-left", "180px");
{% else %}
ftp.get_list();
ftp.get_list();
{% endif %}
</script>
{% endblock %}
+5 -5
View File
@@ -4,10 +4,10 @@
<div class="main-content">
<div class="index-pos-box bgw">
<div class="position f12 c6 pull-left" style="background:none;padding-left:15px">
<!--<span class="bind-user c4">-->
<!--<a href="javascript:bt.pub.bind_btname();" class="btlink">{{data['lan']['BT_ACCOUNT']}}</a>-->
<!--</span>-->
{% if data['pd'].find("{{data['lan']['BT_ACCOUNT']}}") != -1 %}
<span class="bind-user c4">
<a href="javascript:bt.pub.bind_btname();" class="btlink">{{data['lan']['ACCOUNT']}}</a>
</span>
{% if data['pd'].find("{{data['lan']['ACCOUNT']}}") != -1 %}
<span class="bt-dashi">
<a class="btlink" href="https://www.bt.cn/invite" target="_blank" style="margin-left:5px">{{data['lan']['INVITATION_REWARD']}}</a>
</span>
@@ -117,7 +117,7 @@
<div class="col-xs-12 col-sm-12 col-md-6 pull-left pd0">
<div class="pl7">
<div class="bgw" style="height:491px">
<div class="title c6 f16 plr15">{{data['lan']['FLOW']}}</div>
<div class="title c6 f16 plr15">{{data['lan']['FLOW']}}<span class="pull-right"><select class="bt-input-text" name="network-io" style="font-size: 12px;"></select></span></div>
<div class="bw-info">
<div class="col-sm-6 col-md-3"><p class="c9"><span class="ico-up"></span>{{data['lan']['UPLOAD']}}</p><a id="upSpeed">{{data['lan']['S2']}}</a></div>
<div class="col-sm-6 col-md-3"><p class="c9"><span class="ico-down"></span>{{data['lan']['DOWNLOAD']}}</p><a id="downSpeed">{{data['lan']['S2']}}</a></div>
+21 -14
View File
@@ -9,7 +9,7 @@
<title>{{g.title}}</title>
<link rel="shortcut icon" href="/static/favicon.ico" type="image/x-icon" />
<link href="{{g.cdn_url}}/bootstrap-3.3.5/css/bootstrap.min.css" rel="stylesheet" />
<link href="{{g.cdn_url}}/css/site.css?20191127={{g['version']}}" rel="stylesheet" />
<link href="{{g.cdn_url}}/css/site.css?version={{g['version']}}&repair={{data['js_random']}}" rel="stylesheet" />
<link href="{{g.cdn_url}}/codemirror/lib/codemirror.css?20191127={{g['version']}}" rel="stylesheet" />
<!--[if lte IE 9]>
<script src="/static/js/requestAnimationFrame.js"></script>
@@ -68,7 +68,7 @@
<body>
<div class="bt-warp bge6">
<div class="top-tips">The current version of IE browser is too low, some functions cannot be displayed, please change to other browsers!</div>
<a style="display:none;" id="panel_debug" data="{{g['debug']}}"></a>
<a style="display:none;" id="panel_debug" data="{{g['debug']}}" data-pyversion="{{g['pyversion']}}"></a>
<a style="display:none;" id="request_token_head" token="{{session['request_token_head']}}"></a>
<div id="container" class="container-fluid">
<div class="sidebar-scroll">
@@ -76,11 +76,13 @@
<div id="task" class="task cw" onclick="messagebox()">0</div>
<h3 class="mypcip"><span class="f14 cw">{{session['address']}}</span></h3>
<ul class="menu">
{% for menu in session['menus'] %} {% if menu['href'] == g.uri %}
<li id="{{menu['id']}}" class="current"> <a class="{{menu['class']}}" href="{{menu['href']}}">{{menu['title']}}</a></li>
{% else %}
<li id="{{menu['id']}}"> <a class="{{menu['class']}}" href="{{menu['href']}}">{{menu['title']}}</a></li>
{% endif %} {% endfor %}
{% for menu in g['menus'] %}
{% if menu['href'] == g.uri %}
<li id="{{menu['id']}}" class="current"> <a class="{{menu['class']}}" href="{{menu['href']}}">{{menu['title']}}</a></li>
{% else %}
<li id="{{menu['id']}}"> <a class="{{menu['class']}}" href="{{menu['href']}}">{{menu['title']}}</a></li>
{% endif %}
{% endfor %}
</ul>
<div id="newbtpc"></div>
<div class="btpc-plus" onclick="bindBTPanel(0,'b')">+</div>
@@ -94,14 +96,19 @@
<a style="margin-left:20px;color:#20a53a;" href="https://doc.aapanel.com/web/#/3?page_id=117" target="_blank">User manual</a>
</div>
</div>
<script src="{{g.cdn_url}}/js/aes.js?version={{g['version']}}"></script>
<script src="{{g.cdn_url}}/js/jquery-1.10.2.min.js"></script>
<script src="{{g.cdn_url}}/js/bootstrap.min.js"></script>
<script src="{{g.cdn_url}}/language/{{session['lan']}}/lan.js?date={{g['version']}}"></script>
<script src="{{g.cdn_url}}/layer/layer.js?date={{g['version']}}"></script>
<script src="{{g.cdn_url}}/js/public.js?version={{g['version']}}"></script>
<script src="{{g.cdn_url}}/js/public_backup.js?version={{g['version']}}"></script>
<script src="{{g.cdn_url}}/codemirror/lib/codemirror.js?version={{g['version']}}"></script>
<script src="{{g.cdn_url}}/layer/layer.js?version={{g['version']}}"></script>
<script src="{{g.cdn_url}}/language/{{session['lan']}}/lan.js?version={{g['version']}}&repair={{data['js_random']}}"></script>
<script src="{{g.cdn_url}}/js/clipboard.min.js" defer></script>
<script src="{{g.cdn_url}}/laydate/laydate.js" defer></script>
<script src="{{g.cdn_url}}/js/jquery.qrcode.min.js" defer></script>
<!-- 以下文件未来将被剔除 -->
<script src="{{g.cdn_url}}/js/bootstrap.min.js"></script>
<script src="{{g.cdn_url}}/js/public.js?version={{g['version']}}&repair={{data['js_random']}}"></script>
<script src="{{g.cdn_url}}/js/public_backup.js?version={{g['version']}}&repair={{data['js_random']}}"></script>
<script src="{{g.cdn_url}}/codemirror/lib/codemirror.js" defer></script>
<!-- End -->
<script type="text/javascript" src="{{g.cdn_url}}/js/tools.min.js?version={{g['version']}}&repair={{data['js_random']}}"></script>
{% block scripts %}{% endblock %}
<script type="text/javascript">
if (navigator.appName == "Microsoft Internet Explorer" && parseInt(navigator.appVersion.split(";")[1].replace(/[ ]/g, "").replace("MSIE", "")) < 9) {
+24 -32
View File
@@ -1,13 +1,23 @@
{% extends "layout.html" %}
{% block content %}
<link rel="stylesheet" type="text/css" href="https://at.alicdn.com/t/font_1508259_3g6fa6pdt7k.css" />
<style>
#webBody .webPath,#webBody .ssl_tips{
white-space: nowrap;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
min-width: auto;
}
</style>
<div class="main-content pb55">
<div class="container-fluid">
<div class="pos-box bgw mtb15">
<div class="position f14 c9 pull-left">
<a class="plr10 c4" href="/">{{data['lan']['H1']}}</a>/<span class="plr10 c4">{{data['lan']['H2']}}</span>
</div>
<div class="search pull-right">
<div class="search pull-right" style="display: none;">
<form target="hid" onsubmit='site.get_list(1,$("#SearchValue").val())'>
<input type="text" id="SearchValue" class="ser-text pull-left" placeholder="{{data['lan']['SEARCH']}}" />
<button type="button" class="ser-sub pull-left" onclick='site.get_list(1,$("#SearchValue").val())'></button>
@@ -15,30 +25,11 @@
<iframe name='hid' id="hid" style="display:none"></iframe>
</div>
</div>
<div class="bgw mtb15 pd15">
<div class="site_table_view bgw mtb15 pd15">
<div class="info-title-tips">
<p><span class="glyphicon glyphicon-alert" style="color: #f39c12; margin-right: 10px;"></span> {{data['lan']['PS']}}<a class="btlink" href="/crontab">[Cron]</a></p>
</div>
<button onclick="site.add_site()" class="btn btn-success btn-sm btn-title" type="button">{{data['lan']['BTN1']}}</button>&nbsp;
<button onclick="site.set_default_page()" class="btn btn-default btn-sm btn-title" type="button">{{data['lan']['BTN2']}}</button>
<button onclick="site.set_default_site()" class="btn btn-default btn-sm btn-title" type="button">{{data['lan']['BTN3']}}</button>
<button onclick="site.set_class_type()" class="btn btn-default btn-sm btn-title" type="button">{{data['lan']['BTN5']}}</button>
<button onclick="site.get_cli_version()" class="btn btn-default btn-sm btn-title" type="button">{{data['lan']['PHP_CLI_VER']}}</button>
<span id="allDelete">
<button batch="true" style="float: right;display: none;margin-left:10px;" class="btn btn-default btn-sm" onclick="site.batch_site('del');">{{data['lan']['BTN4']}}</button>
</span>
<div class="move_class">
<button batch="false" style="float: right;margin-left:10px;display: none;" class="btn btn-default btn-sm" onclick="site.batch_site('site_type')">{{data['lan']['MOVE_TO']}}</button>
<!-- <select class="bt-input-text mr5" name="defaultSite" style="width:100px"><option value="off">默认分类</option></select> -->
</div>
<div class="divtable mtb10">
<div class="tablescroll">
<table id="webBody" class="table table-hover" style="min-width: 900px;border: 0 none;"></table>
</div>
<div class="dataTables_paginate paging_bootstrap page">
</div>
<p><span class="glyphicon glyphicon-alert" style="color: #f39c12; margin-right: 10px;"></span> {{data['lan']['PS']}}After the site is successfully established, please<a class="btlink" href="/crontab">[Cron]</a>Add scheduled backup tasks to the page!</p>
</div>
<div id="bt_site_table"></div>
</div>
</div>
</div>
@@ -47,20 +38,21 @@
{% block scripts %}
<script type="text/javascript" src="/static/laydate/laydate.js?date=20180301"></script>
<script type="text/javascript" src="/static/js/bootstrap-select.min.js"></script>
<script type="text/javascript" src="/static/js/site.js?version_20200206={{g['version']}}"></script>
<script type="text/javascript" src="/static/ace/ace.js?date={{g.version}}"></script>
<script type="text/javascript" src="{{g.cdn_url}}/js/site.js?version={{g['version']}}&repair={{data['js_random']}}"></script>
<script type="text/javascript" src="{{g.cdn_url}}/ace/ace.js?version={{g['version']}}" defer></script>
<!-- 以下文件未来将被剔除 -->
<script type="text/javascript" src="{{g.cdn_url}}/js/bootstrap-select.min.js" defer></script>
<script type="text/javascript">
bt.set_cookie('sites_path', "{{session['config']['sites_path']}}");
bt.set_cookie('serverType', "{{session['webserver']}}");
{% if not data['isSetup'] %}
layer.msg('test', { time: 0, icon: 2 });
layer.msg(lan.site.install_web_server_first+'<a href="/soft" style="color:#20a53a; float: right;">'+lan.site.to_install+'</a>', { icon: 7, shade: [0.3, '#000'], time: 0 });
$(".layui-layer-shade").css("margin-left", "180px");
layer.msg(lan.site.install_web_server_first+'<a href="/soft" style="color:#20a53a; float: right;">'+lan.site.to_install+'</a>', { icon: 7, shade: [0.3, '#000'], time: 0 });
$(".layui-layer-shade").css("margin-left", "180px");
{% else %}
site.get_list();
site.plugin_firewall();
//site.get_list();
site.plugin_firewall();
{% endif %}
function reverse(array){
var reverse_array = [];
+3 -2
View File
@@ -30,10 +30,10 @@
</div>
<div class="divtable pd15 relative">
<button class="btn btn-default btn-sm" onclick="soft.flush_cache()" title="{{data['lan']['UPDATE_FROM_CLOUD']}}" style="position:absolute;top:-49px;right:15px">{{data['lan']['UPDATE_APP_LIST']}}</button>
<div id="updata_pro_info">
<div id="updata_pro_info" style="display:none">
<div class="alert alert-success" style="margin-bottom:15px"><strong>{{data['lan']['PS']}}</strong><button class="btn btn-success btn-xs va0 updata_pro" onclick="bt.soft.updata_pro()" title="{{data['lan']['UPDATE_PRO_NOW']}}" style="margin-left:8px">"{{data['lan']['UPDATE_NOW']}}"</button></div>
</div>
<table id="softList" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0"></table>
<table id="softList" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-top:10px"></table>
<div id='softPage' class="dataTables_paginate paging_bootstrap page">
</div>
@@ -51,6 +51,7 @@
<script type="text/javascript" src="/static/laydate/laydate.js?date=20180301"></script>
<script type="text/javascript" src="/static/ace/ace.js?date={{g.version}}"></script>
<script type="text/javascript" src="/static/js/soft.js?version_20200109={{g['version']}}"></script>
<script src="https://js.stripe.com/v3/"></script>
<script type="text/javascript">
bt.set_cookie('sites_path', "{{session['config']['sites_path']}}");
+4 -3
View File
@@ -17,8 +17,9 @@
<span class="glyphicon glyphicon-plus" aria-hidden="true" ></span>
</span>
<span class="tab_tootls">
<span class="glyphicon glyphicon-triangle-top" aria-hidden="true"></span>
<span class="glyphicon glyphicon-triangle-bottom" aria-hidden="true"></span>
<span class="glyphicon glyphicon-resize-full" aria-hidden="true" title="Full Screen"></span><span>Full Screen</span>
<!-- <span class="glyphicon glyphicon-triangle-top" aria-hidden="true"></span>
<span class="glyphicon glyphicon-triangle-bottom" aria-hidden="true"></span> -->
</span>
</div>
<div class="term_content_tab"></div>
@@ -39,7 +40,7 @@
<span class="tname">Server IP</span>
<div class="info-r">
<input type="text" name="host" class="bt-input-text mr5" style="width:240px" value="<% this.form.host %>" placeholder="Enter server IP" val="" autocomplete="off" />
<input type="text" name="port" class="bt-input-text mr5" style="width:60px" placeholder="端口" value="<% this.form.port %>" autocomplete="off"/>
<input type="text" name="port" class="bt-input-text mr5" style="width:60px" placeholder="Port" value="<% this.form.port %>" autocomplete="off"/>
</div>
</div>
<div class="line">
+98 -28
View File
@@ -23,7 +23,8 @@ import time
import os
import sys
os.chdir('/www/server/panel')
sys.path.append('class/')
if not 'class/' in sys.path:
sys.path.insert(0,'class/')
import http_requests as requests
requests.DEFAULT_TYPE = 'curl'
import public
@@ -87,6 +88,10 @@ class acme_v2:
if "type" in result:
if result['type'] == 'urn:acme:error:serverInternal':
raise Exception(public.getMsg('ACME_MSG_ERR'))
if not os.path.exists('/www/server/panel/data/http_type.pl'):
public.writeFile('/www/server/panel/data/http_type.pl','python')
self.get_apis()
return self._apis
raise Exception(res.content)
s_body = res.json()
self._apis = {}
@@ -215,10 +220,37 @@ class acme_v2:
# 取根域名和记录值
def extract_zone(self, domain_name):
top_domain_list = ['.ac.cn', '.ah.cn', '.bj.cn', '.com.cn', '.cq.cn', '.fj.cn', '.gd.cn',
'.gov.cn', '.gs.cn', '.gx.cn', '.gz.cn', '.ha.cn', '.hb.cn', '.he.cn',
'.hi.cn', '.hk.cn', '.hl.cn', '.hn.cn', '.jl.cn', '.js.cn', '.jx.cn',
'.ln.cn', '.mo.cn', '.net.cn', '.nm.cn', '.nx.cn', '.org.cn','my.id']
top_domain_list = ['.ac.cn', '.ah.cn', '.bj.cn', '.com.cn', '.cq.cn', '.fj.cn', '.gd.cn','.gov.cn', '.gs.cn',
'.gx.cn', '.gz.cn', '.ha.cn', '.hb.cn', '.he.cn','.hi.cn', '.hk.cn', '.hl.cn', '.hn.cn',
'.jl.cn', '.js.cn', '.jx.cn','.ln.cn', '.mo.cn', '.net.cn', '.nm.cn', '.nx.cn', '.org.cn',
'.my.id','.com.ac','.com.ad','.com.ae','.com.af','.com.ag','.com.ai','.com.al','.com.am',
'.com.an','.com.ao','.com.aq','.com.ar','.com.as','.com.as','.com.at','.com.au','.com.aw',
'.com.az','.com.ba','.com.bb','.com.bd','.com.be','.com.bf','.com.bg','.com.bh','.com.bi',
'.com.bj','.com.bm','.com.bn','.com.bo','.com.br','.com.bs','.com.bt','.com.bv','.com.bw',
'.com.by','.com.bz','.com.ca','.com.ca','.com.cc','.com.cd','.com.cf','.com.cg','.com.ch',
'.com.ci','.com.ck','.com.cl','.com.cm','.com.cn','.com.co','.com.cq','.com.cr','.com.cu',
'.com.cv','.com.cx','.com.cy','.com.cz','.com.de','.com.dj','.com.dk','.com.dm','.com.do',
'.com.dz','.com.ec','.com.ee','.com.eg','.com.eh','.com.es','.com.et','.com.eu','.com.ev',
'.com.fi','.com.fj','.com.fk','.com.fm','.com.fo','.com.fr','.com.ga','.com.gb','.com.gd',
'.com.ge','.com.gf','.com.gh','.com.gi','.com.gl','.com.gm','.com.gn','.com.gp','.com.gr',
'.com.gt','.com.gu','.com.gw','.com.gy','.com.hm','.com.hn','.com.hr','.com.ht','.com.hu',
'.com.id','.com.id','.com.ie','.com.il','.com.il','.com.in','.com.io','.com.iq','.com.ir',
'.com.is','.com.it','.com.jm','.com.jo','.com.jp','.com.ke','.com.kg','.com.kh','.com.ki',
'.com.km','.com.kn','.com.kp','.com.kr','.com.kw','.com.ky','.com.kz','.com.la','.com.lb',
'.com.lc','.com.li','.com.lk','.com.lr','.com.ls','.com.lt','.com.lu','.com.lv','.com.ly',
'.com.ma','.com.mc','.com.md','.com.me','.com.mg','.com.mh','.com.ml','.com.mm','.com.mn',
'.com.mo','.com.mp','.com.mq','.com.mr','.com.ms','.com.mt','.com.mv','.com.mw','.com.mx',
'.com.my','.com.mz','.com.na','.com.nc','.com.ne','.com.nf','.com.ng','.com.ni','.com.nl',
'.com.no','.com.np','.com.nr','.com.nr','.com.nt','.com.nu','.com.nz','.com.om','.com.pa',
'.com.pe','.com.pf','.com.pg','.com.ph','.com.pk','.com.pl','.com.pm','.com.pn','.com.pr',
'.com.pt','.com.pw','.com.py','.com.qa','.com.re','.com.ro','.com.rs','.com.ru','.com.rw',
'.com.sa','.com.sb','.com.sc','.com.sd','.com.se','.com.sg','.com.sh','.com.si','.com.sj',
'.com.sk','.com.sl','.com.sm','.com.sn','.com.so','.com.sr','.com.st','.com.su','.com.sy',
'.com.sz','.com.tc','.com.td','.com.tf','.com.tg','.com.th','.com.tj','.com.tk','.com.tl',
'.com.tm','.com.tn','.com.to','.com.tp','.com.tr','.com.tt','.com.tv','.com.tw','.com.tz',
'.com.ua','.com.ug','.com.uk','.com.uk','.com.us','.com.uy','.com.uz','.com.va','.com.vc',
'.com.ve','.com.vg','.com.vn','.com.vu','.com.wf','.com.ws','.com.ye','.com.za','.com.zm',
'.com.zw']
old_domain_name = domain_name
top_domain = "."+".".join(domain_name.rsplit('.')[-2:])
new_top_domain = "." + top_domain.replace(".", "")
@@ -506,7 +538,7 @@ class acme_v2:
number_of_checks = 0
while True:
if desired_status == ['valid', 'invalid']:
write_log(public.getMsg('ACME_QUERY_V_RESULT',(number_of_checks + 1,)))
write_log(public.getMsg('ACME_QUERY_V_RESULT',(str(number_of_checks + 1),)))
time.sleep(self._wait_time)
check_authorization_status_response = self.acme_request(url, "")
a_auth = check_authorization_status_response.json()
@@ -514,7 +546,7 @@ class acme_v2:
number_of_checks += 1
if authorization_status in desired_status:
if authorization_status == "invalid":
write_log("|-verification failed!")
write_log("|-"+public.getMsg('VERIFICATION_FAILED'))
try:
if 'error' in a_auth['challenges'][0]:
ret_title = a_auth['challenges'][0]['error']['detail']
@@ -538,12 +570,12 @@ class acme_v2:
if number_of_checks == self._max_check_num:
raise StopIteration(
public.getMsg('ACME_V_TIMES',(
number_of_checks,
self._max_check_num,
self._wait_time
str(number_of_checks),
str(self._max_check_num),
str(self._wait_time)
)))
if desired_status == ['valid', 'invalid']:
write_log('ACME_V_SUCCESS')
write_log(public.getMsg('ACME_V_SUCCESS'))
return check_authorization_status_response
# 格式化错误输出
@@ -559,7 +591,7 @@ class acme_v2:
elif error.find('Error getting validation data') != -1:
return public.getMsg('ACME_ERR_MSG5')
elif "too many certificates already issued for exact set of domains" in error:
return public.getMsg('ACME_ERR_MSG6',(re.findall("exact set of domains: (.+):", error),))
return public.getMsg('ACME_ERR_MSG6',(str(re.findall("exact set of domains: (.+):", error)),))
elif "Error creating new account :: too many registrations for this IP" in error:
return public.getMsg('ACME_ERR_MSG7')
elif "DNS problem: NXDOMAIN looking up A for" in error:
@@ -569,25 +601,25 @@ class acme_v2:
elif error.find('TLS Web Server Authentication') != -1:
return public.getMsg('ACME_ERR_MSG10')
elif error.find('Name does not end in a public suffix') != -1:
return public.getMsg('ACME_ERR_MSG11',(re.findall("Cannot issue for \"(.+)\":", error),))
return public.getMsg('ACME_ERR_MSG11',(str(re.findall("Cannot issue for \"(.+)\":", error)),))
elif error.find('No valid IP addresses found for') != -1:
return public.getMsg('ACME_ERR_MSG12',(re.findall("No valid IP addresses found for (.+)", error),))
return public.getMsg('ACME_ERR_MSG12',(str(re.findall("No valid IP addresses found for (.+)", error)),))
elif error.find('No TXT record found at') != -1:
return public.getMsg('ACME_ERR_MSG13',(re.findall("No TXT record found at (.+)", error),))
return public.getMsg('ACME_ERR_MSG13',(str(re.findall("No TXT record found at (.+)", error)),))
elif error.find('Incorrect TXT record') != -1:
return public.getMsg('ACME_ERR_MSG14',(re.findall("found at (.+)", error), re.findall("Incorrect TXT record \"(.+)\"", error)))
return public.getMsg('ACME_ERR_MSG14',(str(re.findall("found at (.+)", error)), str(re.findall("Incorrect TXT record \"(.+)\"", error))))
elif error.find('Domain not under you or your user') != -1:
return public.getMsg('ACME_ERR_MSG15')
elif error.find('SERVFAIL looking up TXT for') != -1:
return public.getMsg('ACME_ERR_MSG16',re.findall("looking up TXT for (.+)", error))
return public.getMsg('ACME_ERR_MSG16',(str(re.findall("looking up TXT for (.+)", error)),))
elif error.find('Timeout during connect') != -1:
return public.getMsg('ACME_ERR_MSG17')
elif error.find("DNS problem: SERVFAIL looking up CAA for") != -1:
return public.getMsg('ACME_ERR_MSG18',(re.findall("looking up CAA for (.+)", error),))
return public.getMsg('ACME_ERR_MSG18',(str(re.findall("looking up CAA for (.+)", error)),))
elif error.find("Read timed out.") != -1:
return public.getMsg('ACME_ERR_MSG19')
elif error.find('Cannot issue for') != -1:
return public.getMsg('ACME_ERR_MSG20',(re.findall(r'for\s+"(.+)"',error),))
return public.getMsg('ACME_ERR_MSG20',(str(re.findall(r'for\s+"(.+)"',error)),))
elif error.find('too many failed authorizations recently'):
return public.getMsg('ACME_ERR_MSG21')
elif error.find("Error creating new order") != -1:
@@ -642,7 +674,7 @@ class acme_v2:
res = self.acme_request(
self._config['orders'][index]['certificate_url'], "")
if res.status_code not in [200, 201]:
raise Exception(public.getMsg('ACME_CERT_DOWNLOAD_ERR',(res.json(),)))
raise Exception(public.getMsg('ACME_CERT_DOWNLOAD_ERR',(str(res.json()),)))
pem_certificate = res.content
if type(pem_certificate) == bytes:
@@ -874,7 +906,7 @@ fullchain.pem Paste into certificate input box
for j in ns.response.answer:
for i in j.items:
txt_value = i.to_text().replace('"', '').strip()
write_log(public.getMsg('ACME_CHECK_DNS1',(n,txt_value)))
write_log(public.getMsg('ACME_CHECK_DNS1',(str(n),txt_value)))
if txt_value == value:
write_log(public.getMsg('ACME_CHECK_DNS2'))
return True
@@ -1036,7 +1068,7 @@ fullchain.pem Paste into certificate input box
res = self.acme_request(url=self._apis['newAccount'], payload=payload)
if res.status_code not in [201, 200, 409]:
raise Exception(public.getMsg('ACME_REGISTERED_ERR',(res.json(),)))
raise Exception(public.getMsg('ACME_REGISTERED_ERR',(str(res.json()),)))
kid = res.headers["Location"]
return kid
@@ -1212,7 +1244,7 @@ fullchain.pem Paste into certificate input box
if not index: # 判断是否只想验证域名
write_log(public.getMsg('ACME_CREAT_ORDER'))
index = self.create_order(domains, auth_type, auth_to)
write_log('ACME_GET_V')
write_log(public.getMsg('ACME_GET_V'))
self.get_auths(index)
if auth_to == 'dns' and len(self._config['orders'][index]['auths']) > 0:
return self._config['orders'][index]
@@ -1273,14 +1305,19 @@ fullchain.pem Paste into certificate input box
args.siteName = public.M('sites').where('id=?',(args.id,)).getField('name')
args.sitename = args.siteName
data = s.GetRedirectList(args)
# 检查重定向是否开启
if type(data) == list:
for x in data:
if x['type']: return public.returnMsg(False, 'SITE_SSL_ERR_301')
data = s.GetProxyList(args)
# 检查反向代理是否开启
if type(data) == list:
for x in data:
if x['open']: return public.returnMsg(False,'ACME_PROXY_ERR')
if x['type']: return public.returnMsg(False,'ACME_PROXY_ERR')
# 检查旧重定向是否开启
data = s.Get301Status(args)
if data['status']:
return public.returnMsg(False,'SITE_SSL_ERR_3011')
#判断是否强制HTTPS
if s.IsToHttps(args.siteName):
return public.returnMsg(False, 'ACME_FORCE_SSL_ERR')
@@ -1307,7 +1344,7 @@ fullchain.pem Paste into certificate input box
args_obj = public.dict_obj()
if not cron_id:
cronPath = public.GetConfigValue('setup_path') + '/cron/' + echo
shell = '{} /www/server/panel/class/acme_v2.py --renew=1'.format(sys.executable)
shell = '{} -u /www/server/panel/class/acme_v2.py --renew=1'.format(sys.executable)
public.writeFile(cronPath,shell)
args_obj.id = public.M('crontab').add('name,type,where1,where_hour,where_minute,echo,addtime,status,save,backupTo,sType,sName,sBody,urladdress',("Renew Let's Encrypt Certificate",'day','','0','10',echo,time.strftime('%Y-%m-%d %X',time.localtime()),0,'','localhost','toShell','',shell,''))
crontab.crontab().set_cron_status(args_obj)
@@ -1321,6 +1358,32 @@ fullchain.pem Paste into certificate input box
crontab.crontab().set_cron_status(args_obj)
except:pass
# 获取当前正在使用此证书的网站目录
def get_ssl_used_site(self,save_path):
pkey_file = '{}/privkey.pem'.format(save_path)
pkey = public.readFile(pkey_file)
if not pkey: return False
cert_paths = 'vhost/cert'
import panelSite
args = public.dict_obj()
args.siteName = ''
for c_name in os.listdir(cert_paths):
skey_file = '{}/{}/privkey.pem'.format(cert_paths,c_name)
skey = public.readFile(skey_file)
if not skey: continue
if skey == pkey:
args.siteName = c_name
run_path = panelSite.panelSite().GetRunPath(args)
if not run_path: continue
sitePath = public.M('sites').where('name=?',c_name).getField('path')
if not sitePath: continue
to_path = "{}/{}".format(sitePath,run_path)
return to_path
return False
# 续签证书
def renew_cert(self, index):
write_log("", "wb+")
@@ -1343,6 +1406,13 @@ fullchain.pem Paste into certificate input box
self._config['orders'][i]['cert_timeout'] = int(time.time())
if self._config['orders'][i]['cert_timeout'] > s_time or self._config['orders'][i]['auth_to'] == 'dns':
continue
#已删除的网站直接跳过续签
if self._config['orders'][i]['auth_to'].find('|') == -1 and self._config['orders'][i]['auth_to'].find('/') != -1:
if not os.path.exists(self._config['orders'][i]['auth_to']):
auth_to = self.get_ssl_used_site(self._config['orders'][i]['save_path'])
if not auth_to: continue
self._config['orders'][i]['auth_to'] = auth_to
order_index.append(i)
if not order_index:
@@ -1354,7 +1424,7 @@ fullchain.pem Paste into certificate input box
cert = None
for index in order_index:
n += 1
write_log(public.getMsg("ACME_RENEWING",(n,self._config['orders'][index]['domains'])))
write_log(public.getMsg("ACME_RENEWING",(str(n),self._config['orders'][index]['domains'])))
write_log(public.getMsg('ACME_CREAT_ORDER'))
try:
index = self.create_order(
@@ -1477,7 +1547,7 @@ if __name__ == "__main__":
write_log(public.getMsg('ACME_USE_TIPS20',(len(cert['auths']),)))
for i in range(len(cert['auths'])):
write_log('-' * 70)
write_log(public.getMsg('ACME_USE_TIPS21',(i+1, cert['auths'][i]['domain'])))
write_log(public.getMsg('ACME_USE_TIPS21',(str(i+1), cert['auths'][i]['domain'])))
write_log(public.getMsg('ACME_USE_TIPS22',(acme_txt + cert['auths'][i]['domain'].replace('*.', ''), cert['auths'][i]['auth_value'])))
write_log(public.getMsg('ACME_USE_TIPS23',(cert['auths'][i]['domain'].replace('*.', ''), acme_caa)))
write_log('-' * 70)
+41 -25
View File
@@ -9,6 +9,7 @@
from BTPanel import session,request
import public,os,json,time,apache,psutil
class ajax:
__official_url = 'https://brandnew.aapanel.com'
def GetApacheStatus(self,get):
a = apache.apache()
@@ -18,13 +19,13 @@ class ajax:
try:
pp = psutil.Process(i)
if pp.name() not in process_cpu.keys():
process_cpu[pp.name()] = float(pp.cpu_percent(interval=0.1))
process_cpu[pp.name()] += float(pp.cpu_percent(interval=0.1))
process_cpu[pp.name()] = float(pp.cpu_percent(interval=0.01))
process_cpu[pp.name()] += float(pp.cpu_percent(interval=0.01))
except:
pass
def GetNginxStatus(self,get):
try:
if not os.path.exists('/www/server/nginx/sbin/nginx'): return public.returnMsg(False,'nginx is not install')
if not os.path.exists('/www/server/nginx/sbin/nginx'): return public.returnMsg(False,'NGINX_NOT_INSTALL')
process_cpu = {}
worker = int(public.ExecShell("ps aux|grep nginx|grep 'worker process'|wc -l")[0])-1
workermen = int(public.ExecShell("ps aux|grep nginx|grep 'worker process'|awk '{memsum+=$6};END {print memsum}'")[0]) / 1024
@@ -36,6 +37,9 @@ class ajax:
self.CheckStatusConf()
result = public.httpGet('http://127.0.0.1/nginx_status')
tmp = result.split()
if len(tmp) < 15:
result = public.ExecShell('curl http://127.0.0.1/nginx_status')[0]
tmp = result.split()
data = {}
if "request_time" in tmp:
data['accepts'] = tmp[8]
@@ -310,7 +314,7 @@ class ajax:
def GetNetWorkIo(self,get):
#取指定时间段的网络Io
data = public.M('network').dbfile('system').where("addtime>=? AND addtime<=?",(get.start,get.end)).field('id,up,down,total_up,total_down,down_packets,up_packets,addtime').order('id asc').select()
return self.ToAddtime(data)
return self.ToAddtime(data,None)
def GetDiskIo(self,get):
#取指定时间段的磁盘Io
@@ -342,7 +346,10 @@ class ajax:
for i in range(length):
data[i]['addtime'] = time.strftime('%m/%d %H:%M',time.localtime(float(data[i]['addtime'])))
if tomem and data[i]['mem'] > 100: data[i]['mem'] = data[i]['mem'] / mPre
if tomem in [None]:
if type(data[i]['down_packets']) == str:
data[i]['down_packets'] = json.loads(data[i]['down_packets'])
data[i]['up_packets'] = json.loads(data[i]['up_packets'])
return data
else:
count = 0
@@ -353,6 +360,10 @@ class ajax:
continue
value['addtime'] = time.strftime('%m/%d %H:%M',time.localtime(float(value['addtime'])))
if tomem and value['mem'] > 100: value['mem'] = value['mem'] / mPre
if tomem in [None]:
if type(value['down_packets']) == str:
value['down_packets'] = json.loads(value['down_packets'])
value['up_packets'] = json.loads(value['up_packets'])
tmp.append(value)
count = 0
return tmp
@@ -430,8 +441,8 @@ class ajax:
#获取最新的5条测试版更新日志
def get_beta_logs(self,get):
try:
# data = json.loads(public.HttpGet(public.GetConfigValue('home') + '/api/panel/get_beta_logs_en'))
data = json.loads(public.HttpGet('https://console.aapanel.com/api/panel/get_beta_logs_en'))
# data = json.loads(public.HttpGet('https://console.aapanel.com/api/panel/get_beta_logs_en'))
data = json.loads(public.HttpGet('{}/api/panel/getBetaVersionLogs'.format(self.__official_url)))
return data
except:
return public.returnMsg(False,'AJAX_CONN_ERR')
@@ -453,7 +464,7 @@ class ajax:
import json
conf_status = public.M('config').where("id=?",('1',)).field('status').find()
if int(session['config']['status']) == 0 and int(conf_status['status']) == 0:
public.HttpGet(public.GetConfigValue('home')+'/Api/SetupCount?type=Linux')
public.HttpGet('{}/api/setupCount/setupPanel?type=Linux'.format(self.__official_url))
public.M('config').where("id=?",('1',)).setField('status',1)
#取回远程版本信息
@@ -484,8 +495,8 @@ class ajax:
data['o'] = ''
filename = '/www/server/panel/data/o.pl'
if os.path.exists(filename): data['o'] = str(public.readFile(filename))
# sUrl = public.GetConfigValue('home') + '/api/panel/updateLinuxEn'
sUrl = 'https://console.aapanel.com/api/panel/updateLinuxEn'
# sUrl = 'https://console.aapanel.com/api/panel/updateLinuxEn'
sUrl = '{}/api/panel/updateLinuxEn'.format(self.__official_url)
updateInfo = json.loads(public.httpPost(sUrl,data))
if not updateInfo: return public.returnMsg(False,"CONNECT_ERR")
#updateInfo['msg'] = msg;
@@ -665,7 +676,10 @@ class ajax:
#清理日志
def delClose(self,get):
if not 'uid' in session: session['uid'] = 1
if session['uid'] != 1: return public.returnMsg(False,'Permission denied!')
if session['uid'] != 1: return public.returnMsg(False,'PERMISSION_DENIED')
if 'tmp_login_id' in session:
return public.returnMsg(False,'PERMISSION_DENIED')
public.M('logs').where('id>?',(0,)).delete()
public.WriteLog('TYPE_CONFIG','LOG_CLOSE')
return public.returnMsg(True,'LOG_CLOSE')
@@ -865,7 +879,7 @@ class ajax:
#PHP
<FilesMatch \.php$>
SetHandler "proxy:unix:/tmp/php-cgi-{}.sock|fcgi://localhost"
SetHandler "proxy:{}"
</FilesMatch>
#DENY FILES
@@ -883,7 +897,7 @@ class ajax:
Require all granted
DirectoryIndex index.php index.html index.htm default.php default.html default.htm
</Directory>
</VirtualHost>'''.format(v["ext"]["phpversion"],auth)
</VirtualHost>'''.format(public.get_php_proxy(v["ext"]["phpversion"],'apache'),auth)
public.writeFile("/www/server/panel/vhost/apache/phpmyadmin.conf", ssl_conf)
else:
if os.path.exists("/www/server/panel/vhost/nginx/phpmyadmin.conf"):
@@ -947,11 +961,11 @@ class ajax:
if public.get_webserver() == 'nginx':
filename = public.GetConfigValue('setup_path') + '/nginx/conf/enable-php.conf'
conf = public.readFile(filename)
rep = r"php-cgi.*\.sock"
conf = re.sub(rep,'php-cgi-' + get.phpversion + '.sock',conf,1)
rep = r"(unix:/tmp/php-cgi.*\.sock|127.0.0.1:\d+)"
conf = re.sub(rep,public.get_php_proxy(get.phpversion,'nginx'),conf,1)
elif public.get_webserver() == 'apache':
rep = r"php-cgi.*\.sock"
conf = re.sub(rep,'php-cgi-' + get.phpversion + '.sock',conf,1)
rep = r"(unix:/tmp/php-cgi.*\.sock\|fcgi://localhost|fcgi://127.0.0.1:\d+)"
conf = re.sub(rep,public.get_php_proxy(get.phpversion,'apache'),conf,1)
else:
reg = r'/usr/local/lsws/lsphp\d+/bin/lsphp'
conf = re.sub(reg,'/usr/local/lsws/lsphp{}/bin/lsphp'.format(get.phpversion),conf)
@@ -983,7 +997,7 @@ class ajax:
#return public.returnMsg(False,'ERROR');
def ToPunycode(self,get):
import re;
import re
get.domain = get.domain.encode('utf8')
tmp = get.domain.split('.')
newdomain = ''
@@ -1148,6 +1162,7 @@ class ajax:
#检查用户绑定是否正确
def check_user_auth(self,get):
import requests
m_key = 'check_user_auth'
if m_key in session: return session[m_key]
u_path = 'data/userInfo.json'
@@ -1156,16 +1171,15 @@ class ajax:
except:
if os.path.exists(u_path): os.remove(u_path)
return public.returnMsg(False,'AJAX_USER_BE_OVERDUE')
pdata = {'access_key':userInfo['access_key'],'secret_key':userInfo['secret_key']}
result = public.HttpPost(public.GetConfigValue('home') + '/api/panel/check_auth_key',pdata,3)
if result == '0':
url_headers = {"authorization":"bt {}".format(userInfo['token'])}
resp = requests.post('{}/api/user/verifyToken'.format(self.__official_url),headers=url_headers)
resp = resp.json()
if not resp['success']:
if os.path.exists(u_path): os.remove(u_path)
return public.returnMsg(False,'AJAX_USER_BE_OVERDUE')
if result == '1':
session[m_key] = public.returnMsg(True,'AJAX_USER_IS_VALID!')
else:
session[m_key] = public.returnMsg(True,'AJAX_USER_IS_VALID')
return session[m_key]
return public.returnMsg(True,result)
#PHP探针
def php_info(self,args):
@@ -1178,6 +1192,8 @@ class ajax:
if not os.path.exists('/etc/redhat-release'):
php_ini = php_path + php_version + '/etc/php/'+args.php_version+'/litespeed/php.ini'
tmp = public.ExecShell(php_bin + ' /www/server/panel/class/php_info.php')[0]
if tmp.find('Warning: JIT is incompatible') != -1:
tmp = tmp.strip().split('\n')[-1]
result = json.loads(tmp)
result['phpinfo'] = {}
result['phpinfo']['php_version'] = result['php_version']
+143
View File
@@ -11,12 +11,15 @@
# Apache管理模块
#------------------------------
import public,os,re,shutil,math,psutil,time
from json import loads
os.chdir("/www/server/panel")
class apache:
setupPath = '/www/server'
apachedefaultfile = "%s/apache/conf/extra/httpd-default.conf" % (setupPath)
apachempmfile = "%s/apache/conf/extra/httpd-mpm.conf" % (setupPath)
httpdconf = "%s/apache/conf/httpd.conf" % (setupPath)
def GetProcessCpuPercent(self,i,process_cpu):
try:
@@ -201,3 +204,143 @@ class apache:
'<br>') + '</a>')
public.serviceReload()
return public.returnMsg(True, 'SET_SUCCESS')
def add_httpd_access_log_format(self,args):
'''
@name 添加httpd日志格式
@author zhwen<zhw@bt.cn>
@param log_format 需要设置的日志格式["$server_name","$remote_addr","-"....]
@param log_format_name
@param act 操作方式 add/edit
'''
try:
log_format = loads(args.log_format)
data = """
#LOG_FORMAT_BEGIN_{n}
LogFormat '{c}' {n}
#LOG_FORMAT_END_{n}
""".format(n=args.log_format_name,c=' '.join(log_format))
data = data.replace('%{User-agent}i','"%{User-agent}i"')
data = data.replace('%{Referer}i', '"%{Referer}i"')
if args.act == 'edit':
self.del_httpd_access_log_format(args)
conf = public.readFile(self.httpdconf)
if not conf:
return public.returnMsg(False,'CONF_FILE_NOT_EXISTS')
reg = '<IfModule log_config_module>'
conf = re.sub(reg,'<IfModule log_config_module>'+data,conf)
public.writeFile(self.httpdconf,conf)
public.serviceReload()
return public.returnMsg(True, 'SET_SUCCESS')
except:
return public.returnMsg(False, str(public.get_error_info()))
def del_httpd_access_log_format(self,args):
'''
@name 删除日志格式
@author zhwen<zhw@bt.cn>
@param log_format_name
'''
conf = public.readFile(self.httpdconf)
if not conf:
return public.returnMsg(False, 'CONF_FILE_NOT_EXISTS')
reg = '\s*#LOG_FORMAT_BEGIN_{n}(\n|.)+#LOG_FORMAT_END_{n}\n?'.format(n=args.log_format_name)
conf = re.sub(reg,'',conf)
public.writeFile(self.httpdconf,conf)
public.serviceReload()
return public.returnMsg(True, 'SET_SUCCESS')
def get_httpd_access_log_format_parameter(self,args=None):
data = {
"%h":"Client's IP address",
"%r":"Request agreement",
"%t":"Request time",
"%>s":"http status code",
"%b":"Send data size",
"%{Referer}i":"http referer",
"%{User-agent}i":"http user agent",
"%{X-Forwarded-For}i":"The real ip of the client",
"%l":"Remote login name",
"%u":"Remote user",
"-":"-"
}
if hasattr(args,'log_format_name'):
site_list = self._get_format_log_to_website(args.log_format_name)
return {'site_list':site_list,'format_log':data}
else:
return data
def _process_log_format(self,tmp):
log_tips = self.get_httpd_access_log_format_parameter()
data = []
for t in tmp:
t = t.replace('\"','')
t = t.replace("'", "")
if t not in log_tips:
continue
data.append({t:log_tips[t]})
return data
def get_httpd_access_log_format(self,args=None):
try:
reg = "#LOG_FORMAT_BEGIN.*"
conf = public.readFile(self.httpdconf)
if not conf:
return public.returnMsg(False, 'CONF_FILE_NOT_EXISTS')
data = re.findall(reg,conf)
format_name = [i.split('_')[-1] for i in data]
format_log = {}
for i in format_name:
format_reg = "#LOG_FORMAT_BEGIN_{n}(\n|.)+LogFormat\s+\'(.*)\'\s+{n}".format(n=i)
tmp = re.search(format_reg,conf).groups()[1].split()
format_log[i] = self._process_log_format(tmp)
return format_log
except:
return public.get_error_info()
def set_httpd_format_log_to_website(self,args):
'''
@name 设置网站日志格式
@author zhwen<zhw@bt.cn>
@param sites aaa.com,bbb.com
@param log_format_name
'''
# sites = args.sites.split(',')
sites = loads(args.sites)
try:
all_site = public.M('sites').field('name').select()
reg = 'CustomLog\s+"/www.*{}\s*'.format(args.log_format_name)
for site in all_site:
website_conf_file = '/www/server/panel/vhost/apache/{}.conf'.format(site['name'])
conf = public.readFile(website_conf_file)
if not conf:
return public.returnMsg(False, 'CONF_FILE_NOT_EXISTS')
format_exist_reg = '(CustomLog\s+"/www.*\_log).*'
access_log = re.search(format_exist_reg, conf).groups()[0] + '" ' + args.log_format_name
if site['name'] not in sites and re.search(format_exist_reg,conf):
access_log = ' '.join(access_log.split()[:-1])
conf = re.sub(reg, access_log, conf)
public.writeFile(website_conf_file,conf)
continue
conf = re.sub(format_exist_reg,access_log,conf)
public.writeFile(website_conf_file,conf)
public.serviceReload()
return public.returnMsg(True, 'SET_SUCCESS')
except:
return public.returnMsg(False, str(public.get_error_info()))
def _get_format_log_to_website(self,log_format_name):
tmp = public.M('sites').field('name').select()
reg = 'CustomLog.*{}'.format(log_format_name)
data = {}
for i in tmp:
website_conf_file = '/www/server/panel/vhost/apache/{}.conf'.format(i['name'])
conf = public.readFile(website_conf_file)
if not conf:
data[i['name']] = False
continue
if re.search(reg,conf):
data[i['name']] = True
else:
data[i['name']] = False
return data
+2 -1
View File
@@ -12,7 +12,8 @@ if sys.version_info[0] == 2:
reload(sys)
sys.setdefaultencoding('utf-8')
os.chdir('/www/server/panel')
sys.path.append("class/")
if not 'class/' in sys.path:
sys.path.insert(0,'class/')
import time,hashlib,sys,os,json,requests,re,public,random,string,panelMysql,downloadFile
python_bin=public.get_python_bin()
class backup_bak:
+65 -48
View File
@@ -33,36 +33,36 @@ class panelSetup:
ua = ua.lower()
if ua.find('spider') != -1 or ua.find('bot') != -1:
return redirect('https://www.google.com')
g.version = '6.8.4'
g.version = '6.8.8'
g.title = public.GetConfigValue('title')
g.uri = request.path
g.debug = os.path.exists('data/debug.pl')
g.pyversion = sys.version_info[0]
if not g.debug:
g.cdn_url = public.get_cdn_url()
if not g.cdn_url:
g.cdn_url = '/static'
else:
g.cdn_url = '//' + g.cdn_url + '/' + g.version
else:
g.cdn_url = '/static'
session['version'] = g.version
session['title'] = g.title
if request.method == 'GET':
if not g.debug:
g.cdn_url = public.get_cdn_url()
if not g.cdn_url:
g.cdn_url = '/static'
else:
g.cdn_url = '//' + g.cdn_url + '/' + g.version
else:
g.cdn_url = '/static'
session['title'] = g.title
dirPath = '/www/server/phpmyadmin/pma'
if os.path.exists(dirPath):
public.ExecShell("rm -rf {}".format(dirPath))
dirPath = '/www/server/adminer'
if os.path.exists(dirPath):
public.ExecShell("rm -rf {}".format(dirPath))
dirPath = '/www/server/panel/adminer'
if os.path.exists(dirPath):
public.ExecShell("rm -rf {}".format(dirPath))
g.is_aes = False
dirPath = '/www/server/phpmyadmin/pma'
if os.path.exists(dirPath):
public.ExecShell("rm -rf {}".format(dirPath))
dirPath = '/www/server/adminer'
if os.path.exists(dirPath):
public.ExecShell("rm -rf {}".format(dirPath))
dirPath = '/www/server/panel/adminer'
if os.path.exists(dirPath):
public.ExecShell("rm -rf {}".format(dirPath))
return None
@@ -91,13 +91,11 @@ class panelAdmin(panelSetup):
# 设置基础Session
def setSession(self):
session['menus'] = sorted(json.loads(public.ReadFile(
'config/menu.json')), key=lambda x: x['sort'])
session['yaer'] = datetime.now().year
session['download_url'] = 'http://download.bt.cn'
if request.method == 'GET':
g.menus = public.get_menus()
g.yaer = datetime.now().year
session["top_tips"] = public.GetMsg("TOP_TIPS")
session["bt_help"] = public.GetMsg("BT_HELP")
# session["manual"] = public.GetMsg("MANUAL")
session["download"] = public.GetMsg("DOWNLOAD")
if not 'brand' in session:
session['brand'] = public.GetConfigValue('brand')
@@ -113,22 +111,27 @@ class panelAdmin(panelSetup):
session['lan'] = public.GetLanguage()
if not 'home' in session:
session['home'] = 'https://console.aapanel.com'
return None
return False
# 检查Web服务器类型
def checkWebType(self):
if os.path.exists('/usr/local/lsws/bin/lswsctrl'):
session['webserver'] = 'openlitespeed'
elif os.path.exists(self.setupPath + '/apache'):
session['webserver'] = 'apache'
else:
session['webserver'] = 'nginx'
if os.path.exists(self.setupPath+'/'+session['webserver']+'/version.pl'):
session['webversion'] = public.ReadFile(self.setupPath+'/'+session['webserver']+'/version.pl').strip()
filename = self.setupPath+'/data/phpmyadminDirName.pl'
if os.path.exists(filename):
session['phpmyadminDir'] = public.ReadFile(filename).strip()
#if request.method == 'GET':
if not 'webserver' in session:
if os.path.exists('/usr/local/lsws/bin/lswsctrl'):
session['webserver'] = 'openlitespeed'
elif os.path.exists(self.setupPath + '/apache/bin/apachectl'):
session['webserver'] = 'apache'
else:
session['webserver'] = 'nginx'
if not 'webversion' in session:
if os.path.exists(self.setupPath+'/'+session['webserver']+'/version.pl'):
session['webversion'] = public.ReadFile(self.setupPath+'/'+session['webserver']+'/version.pl').strip()
if not 'phpmyadminDir' in session:
filename = self.setupPath+'/data/phpmyadminDirName.pl'
if os.path.exists(filename):
session['phpmyadminDir'] = public.ReadFile(filename).strip()
return False
# 检查面板是否关闭
def checkClose(self):
@@ -139,15 +142,28 @@ class panelAdmin(panelSetup):
def check_login(self):
try:
api_check = True
g.api_request = False
if not 'login' in session:
api_check = self.get_sk()
if api_check:
session.clear()
return api_check
g.api_request = True
else:
if session['login'] == False:
session.clear()
return redirect('/login')
if 'tmp_login_expire' in session:
s_file = 'data/session/{}'.format(session['tmp_login_id'])
if session['tmp_login_expire'] < time.time():
session.clear()
if os.path.exists(s_file): os.remove(s_file)
return redirect('/login')
if not os.path.exists(s_file):
session.clear()
return redirect('/login')
if api_check:
try:
sess_out_path = 'data/session_timeout.pl'
@@ -172,14 +188,13 @@ class panelAdmin(panelSetup):
if 'login_token' in session:
if session['login_token'] != token:
session.clear()
return redirect('/login?dologin=True')
return redirect('/login?dologin=True&go=1')
if api_check:
filename = 'data/sess_files/' + public.get_sess_key()
if not os.path.exists(filename):
session.clear()
return redirect('/login?dologin=True')
return redirect('/login?dologin=True&go=2')
except:
return public.returnMsg(False,public.get_error_info())
session.clear()
return redirect('/login')
@@ -205,7 +220,7 @@ class panelAdmin(panelSetup):
num_key = client_ip + '_api'
if not public.get_error_num(num_key,20):
return public.returnMsg(False,'AUTH_FAILED1')
return public.returnJson(False,'AUTH_FAILED1')
if not client_ip in api_config['limit_addr']:
@@ -214,13 +229,13 @@ class panelAdmin(panelSetup):
else:
num_key = client_ip + '_app'
if not public.get_error_num(num_key,20):
return public.returnMsg(False,'AUTH_FAILED1')
return public.returnJson(False,'AUTH_FAILED1')
a_file = '/dev/shm/' + get.client_bind_token
if not os.path.exists(a_file):
import panelApi
if not panelApi.panelApi().get_app_find(get.client_bind_token):
public.set_error_num(num_key)
return public.returnMsg(False,'UNBOUND_DEVICE')
return public.returnJson(False,'UNBOUND_DEVICE')
public.writeFile(a_file,'')
if not 'key' in api_config:
@@ -255,6 +270,7 @@ class panelAdmin(panelSetup):
'users').where("id=?", ('1',)).getField('email')
if not 'address' in session:
session['address'] = public.GetLocalIp()
return False
# 获取操作系统类型
def GetOS(self):
@@ -271,3 +287,4 @@ class panelAdmin(panelSetup):
tmp['x'] = 'Debian'
tmp['osname'] = public.ReadFile('/etc/issue').split()[0]
session['server_os'] = tmp
return False
+317 -71
View File
@@ -51,65 +51,65 @@ class config:
if emial in self.__mail_list:
self.__mail_list.remove(emial)
public.writeFile(self.__mail_list_data, json.dumps(self.__mail_list))
return public.returnMsg(True, 'Successfully deleted')
return public.returnMsg(True, 'DEL_SUCCESS')
else:
return public.returnMsg(True, 'Email does not exist')
return public.returnMsg(True, 'EMAIL_NOT_EXISTS')
#添加接受邮件地址
def add_mail_address(self, get):
if not hasattr(get, 'email'): return public.returnMsg(False, 'Please input your email')
if not hasattr(get, 'email'): return public.returnMsg(False, 'INPUT_EMAIL')
emailformat = re.compile(r'[a-zA-Z0-9.-_+%]+@[a-zA-Z0-9]+\.[a-zA-Z0-9]+')
if not emailformat.search(get.email): return public.returnMsg(False, 'Please enter your vaild email')
if not emailformat.search(get.email): return public.returnMsg(False, 'EMAIL_ERR')
# 测试发送邮件
if get.email.strip() in self.__mail_list: return public.returnMsg(True, 'Email already exists')
if get.email.strip() in self.__mail_list: return public.returnMsg(True, 'EMAIL_EXISTS')
self.__mail_list.append(get.email.strip())
public.writeFile(self.__mail_list_data, json.dumps(self.__mail_list))
return public.returnMsg(True, 'Added successfully')
return public.returnMsg(True, 'SET_SUCCESS')
# 添加自定义邮箱地址
def user_mail_send(self, get):
if not (hasattr(get, 'email') or hasattr(get, 'stmp_pwd') or hasattr(get, 'hosts') or hasattr(get, 'port')):
return public.returnMsg(False, 'Please complete the information')
return public.returnMsg(False, 'COMPLETE_INFO')
# 自定义邮件
self.mail.qq_stmp_insert(get.email.strip(), get.stmp_pwd.strip(), get.hosts.strip(),get.port.strip())
# 测试发送
if self.mail.qq_smtp_send(get.email.strip(), 'aaPanel Alert Test Email', 'aaPanel Alert Test Email'):
if self.mail.qq_smtp_send(get.email.strip(), public.getMsg('TEST_MAIL_TITLE'), public.getMsg('TEST_MAIL_CONTENT')):
if not get.email.strip() in self.__mail_list:
self.__mail_list.append(get.email.strip())
public.writeFile(self.__mail_list_data, json.dumps(self.__mail_list))
return public.returnMsg(True, 'Added successfully')
return public.returnMsg(True, 'SET_SUCCESS')
else:
ret = []
public.writeFile(self.__mail_config, json.dumps(ret))
return public.returnMsg(False, 'Email sending failed, please check if the STMP password is correct or the hosts are correct')
return public.returnMsg(False, 'TEST_MAIL_SEND_ERR')
# 查看自定义邮箱配置
def get_user_mail(self, get):
qq_mail_info = json.loads(public.ReadFile(self.__mail_config))
if len(qq_mail_info) == 0:
return public.returnMsg(False, 'No Data')
return public.returnMsg(False, 'NO_DATA')
if not 'port' in qq_mail_info:qq_mail_info['port']=465
return public.returnMsg(True, qq_mail_info)
# 用户自定义邮件发送
def user_stmp_mail_send(self, get):
if not (hasattr(get, 'email')): return public.returnMsg(False, 'Please fill in the email address')
if not (hasattr(get, 'email')): return public.returnMsg(False, 'INPUT_EMAIL')
emailformat = re.compile(r'[a-zA-Z0-9.-_+%]+@[a-zA-Z0-9]+\.[a-zA-Z0-9]+')
if not emailformat.search(get.email): return public.returnMsg(False, 'Please enter your vaild email')
if not emailformat.search(get.email): return public.returnMsg(False, 'EMAIL_ERR')
# 测试发送邮件
if not get.email.strip() in self.__mail_list: return public.returnMsg(True, 'The mailbox does not exist, please add it to the mailbox list')
if not (hasattr(get, 'title')): return public.returnMsg(False, 'Please fill in the message header')
if not (hasattr(get, 'body')): return public.returnMsg(False, 'Please enter the message content')
if not get.email.strip() in self.__mail_list: return public.returnMsg(True, 'MAILBOX_NOT_EXIST')
if not (hasattr(get, 'title')): return public.returnMsg(False, 'EMAIL_TITLE')
if not (hasattr(get, 'body')): return public.returnMsg(False, 'EMAIL_CONTENT_ERR')
# 先判断是否存在stmp信息
qq_mail_info = json.loads(public.ReadFile(self.__mail_config))
if len(qq_mail_info) == 0:
return public.returnMsg(False, 'STMP information was not found, please re-add custom mail STMP information in the settings')
return public.returnMsg(False, 'SMTP_INFO_ERR')
if self.mail.qq_smtp_send(get.email.strip(), get.title.strip(), get.body):
# 发送成功
return public.returnMsg(True, 'Sent successfully')
return public.returnMsg(True, 'SEND_SUCCESS')
else:
return public.returnMsg(False, 'Failed to send')
return public.returnMsg(False, 'SEND_FAILED')
# 查看能使用的告警通道
def get_settings(self, get):
@@ -130,22 +130,22 @@ class config:
# 设置钉钉报警
def set_dingding(self, get):
if not (hasattr(get, 'url') or hasattr(get, 'atall')):
return public.returnMsg(False, 'Please complete the information')
return public.returnMsg(False, 'COMPLETE_INFO')
if get.atall:
get.atall = 'True'
else: get.atall = 'False'
self.mail.dingding_insert(get.url.strip(), get.atall)
if self.mail.dingding_send('aaPanel alarm test'):
return public.returnMsg(True, 'Added successfully')
if self.mail.dingding_send(public.getMsg('ALARM_TEST')):
return public.returnMsg(True, 'SET_SUCCESS')
else:
ret = []
public.writeFile(self.__dingding_config, json.dumps(ret))
return public.returnMsg(False, 'Add failed, please check if the URL is correct')
return public.returnMsg(False, 'MAIL_ADD_FAILED')
# 查看钉钉
def get_dingding(self, get):
qq_mail_info = json.loads(public.ReadFile(self.__dingding_config))
if len(qq_mail_info) == 0:
return public.returnMsg(False, 'No Data')
return public.returnMsg(False, 'NO_DATA')
return public.returnMsg(True, qq_mail_info)
# 使用钉钉发送消息
@@ -155,9 +155,9 @@ class config:
return public.returnMsg(False, 'The configuration information of the nails you configured was not found, please add in the settings')
if not (hasattr(get, 'content')): return public.returnMsg(False, 'Please enter the data you need to send')
if self.mail.dingding_send(get.content):
return public.returnMsg(True, 'Sent successfully')
return public.returnMsg(True, 'SEND_SUCCESS')
else:
return public.returnMsg(False, 'Failed to send')
return public.returnMsg(False, 'SEND_FAILED')
def getPanelState(self,get):
@@ -226,51 +226,51 @@ class config:
# 创建新用户
def create_user(self,args):
if session['uid'] != 1: return public.returnMsg(False,'Permission denied!')
if len(args.username) < 2: return public.returnMsg(False,'User name must be at least 2 characters')
if len(args.password) < 8: return public.returnMsg(False,'Password must be at least 8 characters')
if session['uid'] != 1: return public.returnMsg(False,'PERMISSION_DENIED')
if len(args.username) < 2: return public.returnMsg(False,'USERNAME_ERR')
if len(args.password) < 8: return public.returnMsg(False,'PASSWORD_ERR')
pdata = {
"username": args.username.strip(),
"password": public.password_salt(public.md5(args.password.strip()),username=args.username.strip())
}
if(public.M('users').where('username=?',(pdata['username'],)).count()):
return public.returnMsg(False,'The specified username already exists!')
return public.returnMsg(False,'USERNAME_EXIST')
if(public.M('users').insert(pdata)):
public.WriteLog('User Management','Create new user {}'.format(pdata['username']))
return public.returnMsg(True,'Create new user {} success!'.format(pdata['username']))
return public.returnMsg(False,'Create new user failed!')
public.WriteLog('USER_MANAGE','CREATE_USER',(pdata['username'],))
return public.returnMsg(True,'CREATE_USER_SUCCESS',(pdata['username'],))
return public.returnMsg(False,'CREATE_USER_FAILED')
# 删除用户
def remove_user(self,args):
if session['uid'] != 1: return public.returnMsg(False,'Permission denied!')
if int(args.id) == 1: return public.returnMsg(False,'Cannot delete initial default user!')
if session['uid'] != 1: return public.returnMsg(False,'PERMISSION_DENIED')
if int(args.id) == 1: return public.returnMsg(False,'DEL_USER_ERR')
username = public.M('users').where('id=?',(args.id,)).getField('username')
if not username: return public.returnMsg(False,'The specified user does not exist!')
if not username: return public.returnMsg(False,'USERNAME_NOT_EXIST')
if(public.M('users').where('id=?',(args.id,)).delete()):
public.WriteLog('User Management','delete users[{}]'.format(username))
return public.returnMsg(True,'Delete user {} success!'.format(username))
return public.returnMsg(False,'User deletion failed!')
public.WriteLog('USER_MANAGE','DEL_USER',(username))
return public.returnMsg(True,'DEL_USER_SUCCESS',(username,))
return public.returnMsg(False,'DEL_USER_FAILED')
# 修改用户
def modify_user(self,args):
if session['uid'] != 1: return public.returnMsg(False,'Permission denied!')
if session['uid'] != 1: return public.returnMsg(False,'PERMISSION_DENIED')
username = public.M('users').where('id=?',(args.id,)).getField('username')
pdata = {}
if 'username' in args:
if len(args.username) < 2: return public.returnMsg(False,'User name must be at least 2 characters')
if len(args.username) < 2: return public.returnMsg(False,'USERNAME_ERR')
pdata['username'] = args.username.strip()
if 'password' in args:
if args.password:
if len(args.password) < 8: return public.returnMsg(False,'Password must be at least 8 characters')
if len(args.password) < 8: return public.returnMsg(False,'PASSWORD_ERR')
pdata['password'] = public.password_salt(public.md5(args.password.strip()),username=username)
if(public.M('users').where('id=?',(args.id,)).update(pdata)):
public.WriteLog('User Management',"Edit user{}".format(username))
return public.returnMsg(True,'Successfully modified!')
return public.returnMsg(False,'No changes submitted!')
public.WriteLog('USER_MANAGE',"EDIT_USER",(username,))
return public.returnMsg(True,'EDIT_SUCCESS')
return public.returnMsg(False,'NO_CHANGE_SUBMITTED')
def setPanel(self,get):
if not public.IsRestart(): return public.returnMsg(False,'EXEC_ERR_TASK')
@@ -522,6 +522,9 @@ class config:
rep = r"\s*pm\s*=\s*(\w+)\s*"
tmp = re.search(rep, conf).groups()
data['pm'] = tmp[0]
data['unix'] = 'unix'
if not isinstance(public.get_fpm_address(version),str):
data['unix'] = 'tcp'
return data
@@ -535,7 +538,7 @@ class config:
max_spare_servers = get.max_spare_servers
pm = get.pm
if not pm in ['static','dynamic','ondemand']:
return public.returnMsg(False,'Wrong operating mode!')
return public.returnMsg(False,'WRONG_MODE')
file = public.GetConfigValue('setup_path')+"/php/"+version+"/etc/php-fpm.conf"
conf = public.readFile(file)
@@ -558,8 +561,18 @@ class config:
rep = r"\s*listen\.backlog\s*=\s*([0-9-]+)\s*"
conf = re.sub(rep, "\nlisten.backlog = 8192\n", conf)
if get.listen == 'unix':
listen = '/tmp/php-cgi-{}.sock'.format(version)
else:
listen = '127.0.0.1:10{}1'.format(version)
rep = r'\s*listen\s*=\s*.+\s*'
conf = re.sub(rep, "\nlisten = "+listen+"\n", conf)
public.writeFile(file,conf)
public.phpReload(version)
public.sync_php_address(version)
public.WriteLog("TYPE_PHP",'PHP_CHILDREN', (version,max_children,start_servers,min_spare_servers,max_spare_servers))
return public.returnMsg(True, 'SET_SUCCESS')
@@ -686,7 +699,7 @@ class config:
#rep_mail = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$"
rep_mail = r"[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?"
if not re.search(rep_mail,get.email):
return public.returnMsg(False,'The E-Mail format is illegal')
return public.returnMsg(False,'EMAIL_FORMAT_ERR')
import setPanelLets
sp = setPanelLets.setPanelLets()
sps = sp.set_lets(get)
@@ -875,7 +888,7 @@ class config:
continue
if not os.path.exists(p):
continue
phpini = public.readFile(filename)
phpini = public.readFile(p)
for g in gets:
try:
rep = g + r'\s*=\s*(.+)\r?\n'
@@ -946,7 +959,7 @@ class config:
return public.returnMsg(False, 'SPECIAL_CHARACTRES', ('" ~ ` / = "'))
filename = '/www/server/php/' + get.version + '/etc/php.ini'
filename_ols = None
if os.path.exists("/usr/local/lsws"):
if os.path.exists("/usr/local/lsws/bin/lswsctrl"):
filename_ols = '/usr/local/lsws/lsphp{}/etc/php/{}.{}/litespeed/php.ini'.format(get.version, get.version[0],
get.version[1])
if os.path.exists('/etc/redhat-release'):
@@ -958,6 +971,8 @@ class config:
if os.path.exists("/etc/redhat-release"):
ols_php_os_path = '/usr/local/lsws/lsphp{}/lib64/php/modules/'.format(get.version)
ols_so_list = os.listdir(ols_php_os_path)
else:
ols_so_list = []
for f in [filename,filename_ols]:
if not f:
continue
@@ -1075,8 +1090,11 @@ class config:
def get_config(self,get):
if 'config' in session:
session['config']['distribution'] = public.get_linux_distribution()
session['webserver'] = public.get_webserver()
session['config']['webserver'] = session['webserver']
return session['config']
data = public.M('config').where("id=?",('1',)).field('webserver,sites_path,backup_path,status,mysql_root').find()
data['webserver'] = public.get_webserver()
data['distribution'] = public.get_linux_distribution()
return data
@@ -1186,7 +1204,7 @@ class config:
import panelSite
php_versions = panelSite.panelSite().GetPHPVersion(get)
if len(php_versions)==0:
return public.returnMsg(False,'Failed to get php version!')
return public.returnMsg(False,'GET_PHP_VER_ERR')
del(php_versions[0])
for v in php_versions:
if link_re.find(v['version']) != -1: return {"select":v,"versions":php_versions}
@@ -1287,9 +1305,9 @@ class config:
else:
t_str = 'Open'
public.writeFile(debug_path,'True')
public.WriteLog('TYPE_PANEL','%s Developer mode(debug)' % t_str)
public.WriteLog('TYPE_PANEL','DEVELOPER_MODE',(t_str,))
public.restart_panel()
return public.returnMsg(True,'Successful setup!')
return public.returnMsg(True,'SET_SUCCESS')
#设置离线模式
@@ -1301,8 +1319,8 @@ class config:
else:
t_str = 'Open'
public.writeFile(d_path,'True')
public.WriteLog('TYPE_PANEL','%s Offline mode' % t_str)
return public.returnMsg(True,'Successful setup!')
public.WriteLog('TYPE_PANEL','OFFLINE_MODE',(t_str,))
return public.returnMsg(True,'SET_SUCCESS')
# 修改.user.ini文件
def _edit_user_ini(self,file,s_conf,act,session_path):
@@ -1330,12 +1348,13 @@ class config:
:return:
'''
if public.get_webserver() == 'openlitespeed':
return public.returnMsg(False, "This feature does not currently support openlitespeed")
return public.returnMsg(False, "NOT_SUPPORT_OLS")
import panelSite
site_info = public.M('sites').where('id=?', (get.id,)).field('name,path').find()
session_path = "/www/php_session/{}".format(site_info["name"])
if os.path.exists(session_path):
if not os.path.exists(session_path):
os.makedirs(session_path)
public.ExecShell('chown www.www {}'.format(session_path))
run_path = panelSite.panelSite().GetSiteRunPath(get)["runPath"]
user_ini_file = "{site_path}{run_path}/.user.ini".format(site_path=site_info["path"], run_path=run_path)
conf = "session.save_path={}/\nsession.save_handler = files".format(session_path)
@@ -1343,12 +1362,12 @@ class config:
if not os.path.exists(user_ini_file):
public.writeFile(user_ini_file,conf)
public.ExecShell("chattr +i {}".format(user_ini_file))
return public.returnMsg(True,"Successful setup")
return public.returnMsg(True,"SET_SUCCESS")
self._edit_user_ini(user_ini_file,conf,get.act,session_path)
return public.returnMsg(True, "Successful setup")
return public.returnMsg(True, "SET_SUCCESS")
else:
self._edit_user_ini(user_ini_file,conf,get.act,session_path)
return public.returnMsg(True, "Successful setup")
return public.returnMsg(True, "SET_SUCCESS")
# 获取php_session是否存放到独立文件夹
def get_php_session_path(self,get):
@@ -1371,9 +1390,9 @@ class config:
key = public.readFile(self._key_file)
username = public.readFile(self._username_file)
if not key:
return public.returnMsg(False, "The key does not exist. Please turn on and try again.")
return public.returnMsg(False, "KEY_NOT_EXIST")
if not username:
return public.returnMsg(False, "The username does not exist. Please turn on and try again.")
return public.returnMsg(False, "USERNAME_NOT_EXIST1")
return {"key":key,"username":username}
def get_random(self):
@@ -1387,7 +1406,7 @@ class config:
def set_two_step_auth(self,get):
if not hasattr(get,"act") or not get.act:
return public.returnMsg(False, "Please enter the operation mode")
return public.returnMsg(False, "SELECT_MODE")
if get.act == "1":
if not os.path.exists(self._core_fle_path):
os.makedirs(self._core_fle_path)
@@ -1402,37 +1421,264 @@ class config:
username = public.readFile(self._username_file)
local_ip = public.GetLocalIp()
if not secret_key:
return public.returnMsg(False,"Failed to generate key or username. Please check if the hard disk space is insufficient or the directory cannot be written.[ {} ]".format(self._setup_path+"/data/"))
return public.returnMsg(False,"GENERATE_KEY_ERR",(self._setup_path+"/data/",))
try:
data = pyotp.totp.TOTP(secret_key).provisioning_uri(username, issuer_name=local_ip)
try:
panel_name = json.loads(public.readFile(self._setup_path+'/config/config.json'))['title']
except:
panel_name = 'aaPanel'
data = pyotp.totp.TOTP(secret_key).provisioning_uri(username, issuer_name='{}--{}'.format(panel_name,local_ip))
public.writeFile(self._core_fle_path+'/qrcode.txt',str(data))
return public.returnMsg(True, "Open successfully")
return public.returnMsg(True, "OPEN_SUCCESSFUL")
except Exception as e:
return public.returnMsg(False, e)
else:
if os.path.exists(self._key_file):
os.rename(self._key_file,self._bk_key_file)
return public.returnMsg(True, "Closed successfully")
return public.returnMsg(True, "CLOSE_SUCCESS")
# 检测是否开启双因素验证
def check_two_step(self,get):
secret_key = public.readFile(self._key_file)
if not secret_key:
return public.returnMsg(False, "Did not open Google authentication")
return public.returnMsg(True, "Google authentication has been turned on")
return public.returnMsg(False, "GOOGLE_AUTH_ERR")
return public.returnMsg(True, "TURN_ON_GOOGLE_AUTH")
# 读取二维码data
def get_qrcode_data(self,get):
data = public.readFile(self._core_fle_path + '/qrcode.txt')
if data:
return data
return public.returnMsg(True, "No QR code data, please re-open")
return public.returnMsg(True, "QR_CODE_ERR")
# 设置是否云控打开
def set_coll_open(self,get):
if not 'coll_show' in get: return public.returnMsg(False,'Parameter error!')
if not 'coll_show' in get: return public.returnMsg(False,'INIT_ARGS_ERR')
if get.coll_show == 'True':
session['tmp_login'] = True
else:
session['tmp_login'] = False
return public.returnMsg(True,'Successful setup!')
return public.returnMsg(True,'SET_SUCCESS')
# 获取菜单列表
def get_menu_list(self, get):
'''
@name 获取菜单列表
@author hwliang<2020-08-31>
@param get<dict_obj>
@return list
'''
menu_file = 'config/menu.json'
hide_menu_file = 'config/hide_menu.json'
data = json.loads(public.ReadFile(menu_file))
if not os.path.exists(hide_menu_file):
public.writeFile(hide_menu_file, '[]')
hide_menu = public.ReadFile(hide_menu_file)
if not hide_menu:
hide_menu = []
else:
hide_menu = json.loads(hide_menu)
result = []
for d in data:
tmp = {}
tmp['id'] = d['id']
tmp['title'] = d['title']
tmp['show'] = not d['id'] in hide_menu
tmp['sort'] = d['sort']
result.append(tmp)
menus = sorted(result, key=lambda x: x['sort'])
return menus
# 设置隐藏菜单列表
def set_hide_menu_list(self, get):
'''
@name 设置隐藏菜单列表
@author hwliang<2020-08-31>
@param get<dict_obj> {
hide_list: json<list> 所有不显示的菜单ID
}
@return dict
'''
hide_menu_file = 'config/hide_menu.json'
not_hide_id = ["dologin", "memuAconfig", "memuAsoft", "memuA"] # 禁止隐藏的菜单
hide_list = json.loads(get.hide_list)
hide_menu = []
for h in hide_list:
if h in not_hide_id: continue
hide_menu.append(h)
public.writeFile(hide_menu_file, json.dumps(hide_menu))
public.WriteLog('TYPE_CONFIG', 'EDIT_MENU_SUCCESS')
return public.returnMsg(True, 'SET_SUCCESS')
# 获取临时登录列表
def get_temp_login(self, args):
'''
@name 获取临时登录列表
@author hwliang<2020-09-2>
@return dict
'''
if 'tmp_login_expire' in session: return public.returnMsg(False, 'PERMISSION_DENIED')
public.M('temp_login').where('state=? and expire<?', (0, int(time.time()))).setField('state', -1)
callback = ''
if 'tojs' in args:
callback = args.tojs
p = 1
if 'p' in args:
p = int(args.p)
rows = 12
if 'rows' in args:
rows = int(args.rows)
count = public.M('temp_login').count()
data = {}
page_data = public.get_page(count, p, rows, callback)
data['page'] = page_data['page']
data['data'] = public.M('temp_login').limit(page_data['shift'] + ',' + page_data['row']).order('id desc').field(
'id,addtime,expire,login_time,login_addr,state').select()
for i in range(len(data['data'])):
data['data'][i]['online_state'] = os.path.exists('data/session/{}'.format(data['data'][i]['id']))
return data
# 设置临时登录
def set_temp_login(self, args):
'''
@name 设置临时登录
@author hwliang<2020-09-2>
@return dict
'''
if 'tmp_login_expire' in session: return public.returnMsg(False, 'PERMISSION_DENIED')
s_time = int(time.time())
public.M('temp_login').where('state=? and expire>?', (0, s_time)).delete()
token = public.GetRandomString(48)
salt = public.GetRandomString(12)
pdata = {
'token': public.md5(token + salt),
'salt': salt,
'state': 0,
'login_time': 0,
'login_addr': '',
'expire': s_time + 3600,
'addtime': s_time
}
if not public.M('temp_login').count():
pdata['id'] = 101
if public.M('temp_login').insert(pdata):
public.WriteLog('TYPE_CONFIG', 'TMP_LOGIN',(public.format_date(times=pdata['expire']),))
return {'status': True, 'msg': public.getMsg('TMP_LOGIN1'), 'token': token, 'expire': pdata['expire']}
return public.returnMsg(False, 'TMP_LOGIN2')
# 删除临时登录
def remove_temp_login(self, args):
'''
@name 删除临时登录
@author hwliang<2020-09-2>
@param args<dict_obj>{
id: int<临时登录ID>
}
@return dict
'''
if 'tmp_login_expire' in session: return public.returnMsg(False, 'PERMISSION_DENIED')
id = int(args.id)
if public.M('temp_login').where('id=?', (id,)).delete():
public.WriteLog('TYPE_CONFIG', 'TMP_LOGIN3')
return public.returnMsg(True, 'DEL_SUCCESS')
return public.returnMsg(False, 'DEL_ERROR')
# 强制弹出指定临时登录
def clear_temp_login(self, args):
'''
@name 强制登出
@author hwliang<2020-09-2>
@param args<dict_obj>{
id: int<临时登录ID>
}
@return dict
'''
if 'tmp_login_expire' in session: return public.returnMsg(False, 'PERMISSION_DENIED')
id = int(args.id)
s_file = 'data/session/{}'.format(id)
if os.path.exists(s_file):
os.remove(s_file)
public.WriteLog('TYPE_CONFIG', 'LOGOUT_TMP_UESR',(str(id),))
return public.returnMsg(True, 'LOGOUT_TMP_USER',(str(id),))
public.returnMsg(False, 'TMP_USER_NOT_LOGIN')
# 查看临时授权操作日志
def get_temp_login_logs(self, args):
'''
@name 查看临时授权操作日志
@author hwliang<2020-09-2>
@param args<dict_obj>{
id: int<临时登录ID>
}
@return dict
'''
if 'tmp_login_expire' in session: return public.returnMsg(False, 'PERMISSION_DENIED')
id = int(args.id)
data = public.M('logs').where('uid=?', (id,)).order('id desc').select()
return data
def add_nginx_access_log_format(self,args):
n = nginx.nginx()
return n.add_nginx_access_log_format(args)
def del_nginx_access_log_format(self,args):
n = nginx.nginx()
return n.del_nginx_access_log_format(args)
def get_nginx_access_log_format(self,args):
n = nginx.nginx()
return n.get_nginx_access_log_format(args)
def set_format_log_to_website(self,args):
n = nginx.nginx()
return n.set_format_log_to_website(args)
def get_nginx_access_log_format_parameter(self,args):
n = nginx.nginx()
return n.get_nginx_access_log_format_parameter(args)
def add_httpd_access_log_format(self,args):
a = apache.apache()
return a.add_httpd_access_log_format(args)
def del_httpd_access_log_format(self,args):
a = apache.apache()
return a.del_httpd_access_log_format(args)
def get_httpd_access_log_format(self,args):
a = apache.apache()
return a.get_httpd_access_log_format(args)
def set_httpd_format_log_to_website(self,args):
a = apache.apache()
return a.set_httpd_format_log_to_website(args)
def get_httpd_access_log_format_parameter(self,args):
a = apache.apache()
return a.get_httpd_access_log_format_parameter(args)
def get_file_deny(self,args):
import file_execute_deny
p = file_execute_deny.FileExecuteDeny()
return p.get_file_deny(args)
def set_file_deny(self,args):
import file_execute_deny
p = file_execute_deny.FileExecuteDeny()
return p.set_file_deny(args)
def del_file_deny(self,args):
import file_execute_deny
p = file_execute_deny.FileExecuteDeny()
return p.del_file_deny(args)
def get_panel_ssl_status(self,get):
import os
if os.path.exists('/www/server/panel/data/ssl.pl'):
return public.returnMsg(True,'success')
return public.returnMsg(False,'false')
+18 -8
View File
@@ -27,6 +27,7 @@ class crontab:
data=[]
for i in range(len(cront)):
tmp = {}
tmp=cront[i]
if cront[i]['type']=="day":
tmp['type']=public.getMsg('CRONTAB_TODAY')
@@ -50,6 +51,10 @@ class crontab:
elif cront[i]['type']=="month":
tmp['type']=public.getMsg('CRONTAB_MONTH')
tmp['cycle']=public.getMsg('CRONTAB_MONTH_CYCLE',(str(cront[i]['where1']),str(cront[i]['where_hour']),str(cront[i]['where_minute'])))
log_file = '/www/server/cron/{}.log'.format(tmp['echo'])
if os.path.exists(log_file):
tmp['addtime'] = public.format_date(times=int(os.path.getmtime(log_file)))
data.append(tmp)
return data
@@ -196,7 +201,9 @@ class crontab:
(get['name'],get['type'],get['where1'],get['hour'],get['minute'],cronName,time.strftime('%Y-%m-%d %X',time.localtime()),1,get['save'],get['backupTo'],get['sType'],get['sName'],get['sBody'],get['urladdress'])
)
if addData>0:
return public.returnMsg(True,'ADD_SUCCESS')
result = public.returnMsg(True,'ADD_SUCCESS')
result['id'] = addData
return result
return public.returnMsg(False,'ADD_ERROR')
#构造周期
@@ -316,12 +323,15 @@ class crontab:
#从crond删除
def remove_for_crond(self,echo):
u_file = '/var/spool/cron/crontabs/root'
file = self.get_cron_file()
conf=public.readFile(file)
if conf.find(str(echo)) == -1: return True
rep = ".+" + str(echo) + ".+\n"
conf = re.sub(rep, "", conf)
if not public.writeFile(file,conf): return False
try:
if not public.writeFile(file,conf): return False
except:
return False
self.CrondReload()
return True
@@ -333,8 +343,7 @@ class crontab:
shell=param.sFile
else :
head="#!/bin/bash\nPATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin\nexport PATH\n"
python_bin = public.get_python_bin()
python_bin = "{} -u".format(public.get_python_bin())
if public.get_webserver()=='nginx':
log='.log'
elif public.get_webserver()=='apache':
@@ -439,10 +448,11 @@ echo "--------------------------------------------------------------------------
cron_path = c_file
if not os.path.exists(u_path):
cron_path=c_file
if os.path.exists('/usr/bin/yum'):
cron_path = c_file
elif os.path.exists("/usr/bin/apt-get"):
if os.path.exists("/usr/bin/apt-get"):
cron_path = u_file
elif os.path.exists('/usr/bin/yum'):
cron_path = c_file
if cron_path == u_file:
if not os.path.exists(u_path):
+2 -1
View File
@@ -13,7 +13,8 @@
import os, json, sys, time
os.chdir("/www/server/panel")
sys.path.append("class/")
if not 'class/' in sys.path:
sys.path.insert(0,'class/')
import public
sys.path.append(".")
+94 -3
View File
@@ -7,12 +7,16 @@
# | Author: hwliang <hwl@bt.cn>
# +-------------------------------------------------------------------
import sys,os,re,time
sys.path.append("class/")
import db,public
if not 'class/' in sys.path:
sys.path.insert(0,'class/')
import db,public,panelMysql
import json
class data:
__ERROR_COUNT = 0
DB_MySQL = None
web_server = None
setupPath = '/www/server'
'''
* 设置备注信息
* @param String _GET['tab'] 数据库表名
@@ -44,6 +48,55 @@ class data:
if temp['local']: result +=2
return result
# 转换时间
def strf_date(self, sdate):
return time.strftime('%Y-%m-%d', time.strptime(sdate, '%Y%m%d%H%M%S'))
def get_cert_end(self,pem_file):
try:
import OpenSSL
result = {}
x509 = OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_PEM, public.readFile(pem_file))
# 取产品名称
issuer = x509.get_issuer()
result['issuer'] = ''
if hasattr(issuer, 'CN'):
result['issuer'] = issuer.CN
if not result['issuer']:
is_key = [b'0', '0']
issue_comp = issuer.get_components()
if len(issue_comp) == 1:
is_key = [b'CN', 'CN']
for iss in issue_comp:
if iss[0] in is_key:
result['issuer'] = iss[1].decode()
break
# 取到期时间
result['notAfter'] = self.strf_date(
bytes.decode(x509.get_notAfter())[:-1])
# 取申请时间
result['notBefore'] = self.strf_date(
bytes.decode(x509.get_notBefore())[:-1])
# 取可选名称
result['dns'] = []
for i in range(x509.get_extension_count()):
s_name = x509.get_extension(i)
if s_name.get_short_name() in [b'subjectAltName', 'subjectAltName']:
s_dns = str(s_name).split(',')
for d in s_dns:
result['dns'].append(d.split(':')[1])
subject = x509.get_subject().get_components()
# 取主要认证名称
if len(subject) == 1:
result['subject'] = subject[0][1].decode()
else:
result['subject'] = result['dns'][0]
return result
except:
return public.get_cert_data(pem_file)
def get_site_ssl_info(self,siteName):
try:
s_file = 'vhost/nginx/{}.conf'.format(siteName)
@@ -70,14 +123,51 @@ class data:
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)
ssl_info = self.get_cert_end(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
#return "{}:{}".format(ssl_info['issuer'],ssl_info['notAfter'])
def get_php_version(self,siteName):
try:
if not self.web_server:
self.web_server = public.get_webserver()
conf = public.readFile(self.setupPath + '/panel/vhost/'+self.web_server+'/'+siteName+'.conf')
if self.web_server == 'openlitespeed':
conf = public.readFile(
self.setupPath + '/panel/vhost/' + self.web_server + '/detail/' + siteName + '.conf')
if self.web_server == 'nginx':
rep = r"enable-php-([0-9]{2,3})\.conf"
elif self.web_server == 'apache':
rep = r"php-cgi-([0-9]{2,3})\.sock"
else:
rep = r"path\s*/usr/local/lsws/lsphp(\d+)/bin/lsphp"
tmp = re.search(rep,conf).groups()
if tmp[0] == '00':
return 'Static'
return tmp[0][0] + '.' + tmp[0][1]
except:
return 'Static'
def map_to_list(self,map_obj):
try:
if type(map_obj) != list and type(map_obj) != str: map_obj = list(map_obj)
return map_obj
except: return []
def get_database_size(self,databaseName):
try:
if not self.DB_MySQL:self.DB_MySQL = panelMysql.panelMysql()
db_size = self.map_to_list(self.DB_MySQL.query("select sum(DATA_LENGTH)+sum(INDEX_LENGTH) from information_schema.tables where table_schema='{}'".format(databaseName)))[0][0]
if not db_size: return 0
return int(db_size)
except:
return 0
'''
@@ -108,6 +198,7 @@ class data:
for i in range(len(data['data'])):
data['data'][i]['domain'] = SQL.table('domain').where("pid=?",(data['data'][i]['id'],)).count()
data['data'][i]['ssl'] = self.get_site_ssl_info(data['data'][i]['name'])
data['data'][i]['php_version'] = self.get_php_version(data['data'][i]['name'])
elif table == 'firewall':
for i in range(len(data['data'])):
if data['data'][i]['port'].find(':') != -1 or data['data'][i]['port'].find('.') != -1 or data['data'][i]['port'].find('-') != -1:

Some files were not shown because too many files have changed in this diff Show More