update to 6.8.27
@@ -9,14 +9,44 @@
|
||||
# +-------------------------------------------------------------------
|
||||
from gevent import monkey
|
||||
monkey.patch_all()
|
||||
import os,sys,ssl
|
||||
import os,sys,ssl,time,logging
|
||||
|
||||
_PATH = '/www/server/panel'
|
||||
os.chdir(_PATH)
|
||||
os.system("nohup ./pyenv/bin/python3 class/jobs.py &>/dev/null &")
|
||||
upgrade_file = 'script/upgrade_flask.sh'
|
||||
if os.path.exists(upgrade_file):
|
||||
os.system("nohup bash {} &>/dev/null &".format(upgrade_file))
|
||||
|
||||
if os.path.exists('class/flask'):
|
||||
os.system('rm -rf class/flask')
|
||||
|
||||
|
||||
if not 'class/' in sys.path:
|
||||
sys.path.insert(0,'class/')
|
||||
from BTPanel import app,sys,public
|
||||
is_debug = os.path.exists('data/debug.pl')
|
||||
|
||||
|
||||
# # 检查加载器
|
||||
# def check_plugin_loader():
|
||||
# plugin_loader_file = 'class/PluginLoader.so'
|
||||
# machine = 'x86_64'
|
||||
# try:
|
||||
# machine = os.uname().machine
|
||||
# except:
|
||||
# pass
|
||||
# plugin_loader_src_file = "class/PluginLoader.{}.Python3.7.so".format(machine)
|
||||
# if machine == 'x86_64':
|
||||
# glibc_version = public.get_glibc_version()
|
||||
# if glibc_version in ['2.14','2.13','2.12','2.11','2.10']:
|
||||
# plugin_loader_src_file = "class/PluginLoader.{}.glibc214.Python3.7.so".format(machine)
|
||||
# if os.path.exists(plugin_loader_src_file):
|
||||
# os.system("\cp -f {} {}".format(plugin_loader_src_file, plugin_loader_file))
|
||||
|
||||
# check_plugin_loader()
|
||||
|
||||
|
||||
if is_debug:
|
||||
import pyinotify,time,logging,re
|
||||
logging.basicConfig(level=logging.DEBUG,format="[%(asctime)s][%(levelname)s] - %(message)s")
|
||||
@@ -26,7 +56,10 @@ if is_debug:
|
||||
_exts = ['py','html','BT-Panel','so']
|
||||
_explude_patts = [
|
||||
re.compile('{}/plugin/.+'.format(_PATH)),
|
||||
re.compile('{}/(tmp|temp)/.+'.format(_PATH))
|
||||
re.compile('{}/(tmp|temp)/.+'.format(_PATH)),
|
||||
re.compile('{}/pyenv/.+'.format(_PATH)),
|
||||
re.compile('{}/class/projectModel/.+'.format(_PATH)),
|
||||
re.compile('{}/class/databaseModel/.+'.format(_PATH))
|
||||
]
|
||||
_lsat_time = 0
|
||||
|
||||
@@ -68,17 +101,53 @@ if is_debug:
|
||||
if not self.is_ext(event.pathname): return
|
||||
self.panel_reload(event.pathname,'[Modify]')
|
||||
|
||||
def process_IN_MOVED_TO(self,event):
|
||||
if not self.is_ext(event.pathname): return
|
||||
self.panel_reload(event.pathname,'[覆盖]')
|
||||
|
||||
def debug_event():
|
||||
logger.debug('Launch the panel in debug mode')
|
||||
logger.debug('Listening port:0.0.0.0:{}'.format(public.readFile('data/port.pl')))
|
||||
|
||||
event = PanelEventHandler()
|
||||
watchManager = pyinotify.WatchManager()
|
||||
mode = pyinotify.IN_CREATE | pyinotify.IN_DELETE | pyinotify.IN_MODIFY
|
||||
mode = pyinotify.IN_CREATE | pyinotify.IN_DELETE | pyinotify.IN_MODIFY | pyinotify.IN_MOVED_TO
|
||||
watchManager.add_watch(_PATH, mode, auto_add=True, rec=True)
|
||||
notifier = pyinotify.Notifier(watchManager, event)
|
||||
notifier.loop()
|
||||
|
||||
def run_task():
|
||||
public.ExecShell("chmod 700 {}/BT-Task".format(_PATH))
|
||||
public.ExecShell("{}/BT-Task".format(_PATH))
|
||||
|
||||
def daemon_task():
|
||||
cycle = 60
|
||||
task_pid_file = "{}/logs/task.pid".format(_PATH)
|
||||
while 1:
|
||||
time.sleep(cycle)
|
||||
|
||||
# 检查pid文件是否存在
|
||||
if not os.path.exists(task_pid_file):
|
||||
continue
|
||||
|
||||
# 读取pid文件
|
||||
task_pid = public.readFile(task_pid_file)
|
||||
if not task_pid:
|
||||
run_task()
|
||||
continue
|
||||
|
||||
# 检查进程是否存在
|
||||
comm_file = "/proc/{}/comm".format(task_pid)
|
||||
if not os.path.exists(comm_file):
|
||||
run_task()
|
||||
continue
|
||||
|
||||
# 是否为面板进程
|
||||
comm = public.readFile(comm_file)
|
||||
if comm.find('BT-Task') == -1:
|
||||
run_task()
|
||||
continue
|
||||
|
||||
if __name__ == '__main__':
|
||||
pid_file = "{}/logs/panel.pid".format(_PATH)
|
||||
if os.path.exists(pid_file):
|
||||
@@ -96,13 +165,17 @@ if __name__ == '__main__':
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
|
||||
f = open('data/port.pl')
|
||||
PORT = int(f.read())
|
||||
|
||||
try:
|
||||
f = open('data/port.pl')
|
||||
PORT = int(f.read())
|
||||
f.close()
|
||||
if not PORT: PORT = 7800
|
||||
except:
|
||||
PORT = 7800
|
||||
HOST = '0.0.0.0'
|
||||
if os.path.exists('data/ipv6.pl'):
|
||||
HOST = "0:0:0:0:0:0:0:0"
|
||||
f.close()
|
||||
|
||||
|
||||
keyfile = 'ssl/privateKey.pem'
|
||||
certfile = 'ssl/certificate.pem'
|
||||
@@ -111,41 +184,83 @@ if __name__ == '__main__':
|
||||
is_ssl = True
|
||||
|
||||
if not is_ssl or is_debug:
|
||||
err_f = open('logs/error.log','a+')
|
||||
os.dup2(err_f.fileno(),sys.stderr.fileno())
|
||||
err_f.close()
|
||||
try:
|
||||
err_f = open('logs/error.log','a+')
|
||||
os.dup2(err_f.fileno(),sys.stderr.fileno())
|
||||
err_f.close()
|
||||
except Exception as ex:
|
||||
print(ex)
|
||||
|
||||
import threading
|
||||
import jobs
|
||||
|
||||
job = threading.Thread(target=jobs.control_init)
|
||||
job.setDaemon(True)
|
||||
job.start()
|
||||
|
||||
task_thread = threading.Thread(target=daemon_task)
|
||||
task_thread.setDaemon(True)
|
||||
task_thread.start()
|
||||
|
||||
if is_ssl:
|
||||
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
||||
ssl_context.load_cert_chain(certfile=certfile,keyfile=keyfile)
|
||||
ssl_context.options = (ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1)
|
||||
ssl_context.set_ciphers("ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE")
|
||||
if hasattr(ssl_context, "minimum_version"):
|
||||
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
|
||||
else:
|
||||
ssl_context.options = (ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1)
|
||||
|
||||
ssl_context.set_ciphers("ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE")
|
||||
is_ssl_verify = os.path.exists('/www/server/panel/data/ssl_verify_data.pl')
|
||||
if is_ssl_verify:
|
||||
crlfile = '/www/server/panel/ssl/crl.pem'
|
||||
rootcafile = '/www/server/panel/ssl/ca.pem'
|
||||
#注销列表
|
||||
# ssl_context.load_verify_locations(crlfile)
|
||||
# ssl_context.verify_flags |= ssl.VERIFY_CRL_CHECK_CHAIN
|
||||
#加载证书
|
||||
ssl_context.load_verify_locations(rootcafile)
|
||||
ssl_context.verify_mode = ssl.CERT_REQUIRED
|
||||
ssl_context.set_default_verify_paths()
|
||||
|
||||
# 设置日志格式
|
||||
_level = logging.WARNING
|
||||
if is_debug: _level = logging.NOTSET
|
||||
logging.basicConfig(level=_level,format="[%(asctime)s][%(levelname)s] - %(message)s")
|
||||
logger = logging.getLogger()
|
||||
app.logger = logger
|
||||
|
||||
from gevent.pywsgi import WSGIServer
|
||||
from geventwebsocket.handler import WebSocketHandler
|
||||
try:
|
||||
import flask_sock
|
||||
if is_ssl:
|
||||
http_server = WSGIServer((HOST, PORT), app,ssl_context = ssl_context,log=app.logger)
|
||||
else:
|
||||
http_server = WSGIServer((HOST, PORT), app,log=app.logger)
|
||||
except:
|
||||
from geventwebsocket.handler import WebSocketHandler
|
||||
if is_ssl:
|
||||
http_server = WSGIServer((HOST, PORT), app,ssl_context = ssl_context,handler_class=WebSocketHandler,log=app.logger)
|
||||
else:
|
||||
http_server = WSGIServer((HOST, PORT), app,handler_class=WebSocketHandler,log=app.logger)
|
||||
|
||||
if is_ssl:
|
||||
http_server = WSGIServer((HOST, PORT), app,handler_class=WebSocketHandler,ssl_context = ssl_context)
|
||||
else:
|
||||
http_server = WSGIServer((HOST, PORT), app,handler_class=WebSocketHandler)
|
||||
|
||||
if is_debug:
|
||||
try:
|
||||
dev = threading.Thread(target=debug_event)
|
||||
dev.setDaemon(True)
|
||||
dev.start()
|
||||
except:
|
||||
pass
|
||||
|
||||
http_server.serve_forever()
|
||||
is_process = os.path.exists('data/is_process.pl')
|
||||
if not is_process:
|
||||
http_server.serve_forever()
|
||||
else:
|
||||
http_server.start()
|
||||
from multiprocessing import Process
|
||||
def serve_forever():
|
||||
http_server.start_accepting()
|
||||
http_server._stop_event.wait()
|
||||
|
||||
process_count = 2
|
||||
for i in range(process_count):
|
||||
p = Process(target=serve_forever)
|
||||
p.daemon = True
|
||||
p.start()
|
||||
|
||||
while 1:
|
||||
time.sleep(1000)
|
||||
@@ -132,7 +132,10 @@
|
||||
}
|
||||
|
||||
.file_table_view.icon_view .file_ico_type {
|
||||
height: 60px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.file_table_view.icon_view .file_list_content .file_icon {
|
||||
@@ -555,7 +558,13 @@
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.file_table_view.list_view .file_list_content .file_ico_type img.file_images{
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -11px;
|
||||
}
|
||||
.file_table_view.list_view .file_title {
|
||||
vertical-align: top;
|
||||
padding-left: 38px;
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
* Default styles for xterm.js
|
||||
*/
|
||||
|
||||
.xterm {
|
||||
.xterm {
|
||||
font-feature-settings: "liga" 0;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<div>
|
||||
<p style="margin-bottom:8px"><span style="display: inline-block; width: 104px;">目标URL</span><input class="bt-input-text" type="text" name="toUrl" value="http://" style="margin-left: 5px;width: 380px;height: 30px;margin-right:10px;" placeholder="请填写完整URL,例:http://www.test.com"></p>
|
||||
<p style="margin-bottom:8px"><span style="display: inline-block; width: 104px;">发送域名</span><input class="bt-input-text" type="text" name="toDomain" value="$host" style="margin-left: 5px;width: 380px;height: 30px;margin-right:10px;" placeholder="发送到目标服务器的域名,例:www.test.com"></p>
|
||||
<p style="margin-bottom:8px"><span style="display: inline-block; width: 104px;">内容替换</span><input class="bt-input-text" type="text" name="sub1" value="" style="margin-left: 5px;width: 182px;height: 30px;margin-right:10px;" placeholder="被替换的文本,可留空"><input class="bt-input-text" type="text" name="sub2" value="" style="margin-left: 5px;width: 183px;height: 30px;margin-right:10px;" placeholder="替换为,可留空"></p>
|
||||
<div class="label-input-group ptb10"><label style="font-weight:normal"><input type="checkbox" name="status" onclick="Proxy('w6.hao.com',1)">启用反向代理</label><label style="margin-left: 18px;"><input type="checkbox" name="status" onclick="OpenCache('w6.hao.com',1)">开启缓存</label></div>
|
||||
<ul class="help-info-text c7 ptb10">
|
||||
<li>目标Url必需是可以访问的,否则将直接502</li>
|
||||
<li>默认本站点所有域名访问将被传递到目标服务器,请确保目标服务器已绑定域名</li>
|
||||
<li>若您是被动代理,请在发送域名处填写上目标站点的域名</li>
|
||||
<li>若您不需要内容替换功能,请直接留空</li>
|
||||
<li>可通过purge清理指定URL的缓存,示例:http://test.com/purge/test.png</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
Before Width: | Height: | Size: 516 B |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 553 B |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 532 B |
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 630 B |
|
Before Width: | Height: | Size: 715 B |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 21 KiB |
@@ -1,13 +0,0 @@
|
||||
<div>
|
||||
<p style="margin-bottom:8px"><span style="display: inline-block; width: 104px;">目标URL</span><input class="bt-input-text" type="text" name="toUrl" value="http://" style="margin-left: 5px;width: 380px;height: 30px;margin-right:10px;" placeholder="请填写完整URL,例:http://www.test.com"></p>
|
||||
<p style="margin-bottom:8px"><span style="display: inline-block; width: 104px;">发送域名</span><input class="bt-input-text" type="text" name="toDomain" value="$host" style="margin-left: 5px;width: 380px;height: 30px;margin-right:10px;" placeholder="发送到目标服务器的域名,例:www.test.com"></p>
|
||||
<p style="margin-bottom:8px"><span style="display: inline-block; width: 104px;">内容替换</span><input class="bt-input-text" type="text" name="sub1" value="" style="margin-left: 5px;width: 182px;height: 30px;margin-right:10px;" placeholder="被替换的文本,可留空"><input class="bt-input-text" type="text" name="sub2" value="" style="margin-left: 5px;width: 183px;height: 30px;margin-right:10px;" placeholder="替换为,可留空"></p>
|
||||
<div class="label-input-group ptb10"><label style="font-weight:normal"><input type="checkbox" name="status" onclick="Proxy('w6.hao.com',1)">启用反向代理</label><label style="margin-left: 18px;"><input type="checkbox" name="status" onclick="OpenCache('w6.hao.com',1)">开启缓存</label></div>
|
||||
<ul class="help-info-text c7 ptb10">
|
||||
<li>目标Url必需是可以访问的,否则将直接502</li>
|
||||
<li>默认本站点所有域名访问将被传递到目标服务器,请确保目标服务器已绑定域名</li>
|
||||
<li>若您是被动代理,请在发送域名处填写上目标站点的域名</li>
|
||||
<li>若您不需要内容替换功能,请直接留空</li>
|
||||
<li>可通过purge清理指定URL的缓存,示例:http://test.com/purge/test.png</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -377,15 +377,15 @@ function bindBTName(a,type){
|
||||
if(a == 1) {
|
||||
p1 = $("#p1").val();
|
||||
p2 = $("#p2").val();
|
||||
var loadT = layer.msg(lan.config.token_get,{icon:16,time:0,shade: [0.3, '#000']});
|
||||
var loadT = layer.msg(lan.config.token_get, {icon: 16, time: 0, shade: [0.3, '#000']});
|
||||
$.post(" /ssl?action=GetToken", {
|
||||
username: p1,
|
||||
password: p2
|
||||
}, function(b){
|
||||
bt.clear_cookie('bt_user_info')
|
||||
}, function (b) {
|
||||
bt.clear_cookie('bt_user_info');
|
||||
layer.close(loadT);
|
||||
layer.msg(b.msg, {icon: b.status?1:2});
|
||||
if(b.status) {
|
||||
layer.msg(b.msg, {icon: b.status ? 1 : 2});
|
||||
if (b.status) {
|
||||
window.location.reload();
|
||||
$("input[name='btusername']").val(p1);
|
||||
}
|
||||
@@ -448,224 +448,232 @@ function setPanelSSL(){
|
||||
var status = $("#panelSSL").prop("checked");
|
||||
var loadT = layer.msg(lan.config.ssl_msg,{icon:16,time:0,shade: [0.3, '#000']});
|
||||
if(status){
|
||||
var confirm = layer.confirm('Whether to close the panel SSL certificate', {title:'Tips',btn: ['Confirm','Cancel'],icon:0,closeBtn:2}, function() {
|
||||
var confirm = layer.confirm('Whether to close the panel SSL certificate', {
|
||||
title: 'Tips',
|
||||
btn: ['Confirm', 'Cancel'],
|
||||
icon: 0,
|
||||
closeBtn: 2,
|
||||
cancel: function () {
|
||||
$("#panelSSL").prop("checked", true);
|
||||
}
|
||||
}, function () {
|
||||
bt.send('SetPanelSSL', 'config/SetPanelSSL', {}, function (rdata) {
|
||||
layer.close(loadT);
|
||||
if (rdata.status) {
|
||||
layer.msg(rdata.msg,{icon:1});
|
||||
layer.msg(rdata.msg, {icon: 1});
|
||||
$.get('/system?action=ReWeb', function () {
|
||||
});
|
||||
setTimeout(function () {
|
||||
window.location.href = ((window.location.protocol.indexOf('https') != -1) ? 'http://' : 'https://') + window.location.host + window.location.pathname;
|
||||
}, 1500);
|
||||
}
|
||||
else {
|
||||
layer.msg(res.rdata,{icon:2});
|
||||
} else {
|
||||
layer.msg(res.rdata, {icon: 2});
|
||||
}
|
||||
});
|
||||
return;
|
||||
})
|
||||
}
|
||||
}, function () {
|
||||
this.cancel();
|
||||
});
|
||||
}
|
||||
else {
|
||||
bt.send('get_cert_source', 'config/get_cert_source', {}, function (rdata) {
|
||||
layer.close(loadT);
|
||||
var sdata = rdata;
|
||||
var _data = {
|
||||
title: 'Panel SSL',
|
||||
area: '630px',
|
||||
class: 'ssl_cert_from ssl_cert_panel_from',
|
||||
list: [
|
||||
{
|
||||
html: '\
|
||||
<div style="position: relative; width: 90%; margin: 0 auto;">\
|
||||
<i class="layui-layer-ico layui-layer-ico3" style="left: 0;"></i>\
|
||||
<h3 style="margin-left: 45px;">' + lan.config.ssl_open_ps + '</h3>\
|
||||
<ul style="width: 100%;">\
|
||||
<li style="color:red;">' + lan.config.ssl_open_ps_1 + '</li>\
|
||||
<li>' + lan.config.ssl_open_ps_2 + '</li>\
|
||||
<li>If panel is not accessible, you can click the <a class="btlink" href="https://forum.aapanel.com/d/167-common-problems-after-opening-the-panel-certificate" target="_blank">link</a> below to find solutions</li>\
|
||||
</ul>\
|
||||
</div>\
|
||||
'
|
||||
},
|
||||
{
|
||||
title: 'Cert Type',
|
||||
name: 'cert_type',
|
||||
type: 'select',
|
||||
width: '260px',
|
||||
// value: sdata.cert_type,
|
||||
value: '3',
|
||||
items: [
|
||||
{value: '1', title: 'Self-signed certificate'},
|
||||
{value: '2', title: 'Let\'s Encrypt'},
|
||||
{value: '3', title: 'I have certficate'}
|
||||
],
|
||||
callback: function (obj) {
|
||||
var set_height = function () {
|
||||
var layer_box = $('.ssl_cert_from').parents('.layui-layer');
|
||||
var window_height = $(window).height();
|
||||
var height = layer_box.height();
|
||||
var top = (window_height - height) / 2;
|
||||
layer_box.css({
|
||||
'top': top + 'px'
|
||||
});
|
||||
}
|
||||
var subid = obj.attr('name') + '_subid';
|
||||
var keyid = obj.attr('name') + '_keyid';
|
||||
$('#' + subid).remove();
|
||||
$('#' + keyid).remove();
|
||||
if (obj.val() == '1') {
|
||||
set_height();
|
||||
}
|
||||
if (obj.val() == '2') {
|
||||
var _tr = bt.render_form_line({
|
||||
title: 'E-Mail',
|
||||
name: 'email',
|
||||
width: '260px',
|
||||
placeholder: 'Admin E-Mail',
|
||||
value: sdata.email
|
||||
});
|
||||
obj.parents('div.line').append('<div class="line" id=' + subid + '>' + _tr.html + '</div>');
|
||||
set_height();
|
||||
}
|
||||
if (obj.val() == '3') {
|
||||
var loadT = layer.msg(lan.config.get_cert, {icon: 16, time: 0, shade: [0.3, '#000']});
|
||||
$.post('/config?action=GetPanelSSL', {}, function (cert) {
|
||||
layer.close(loadT);
|
||||
if (cert.privateKey === 'false') {
|
||||
cert.privateKey = 'paste your Private key (KEY) here';
|
||||
}
|
||||
if (cert.certPem === 'false') {
|
||||
cert.certPem = 'paste your Certificate (CRT/PEM) here';
|
||||
}
|
||||
obj.parents('div.line').append('\
|
||||
<div class="myKeyCon" id="' + keyid + '" style="margin: 0 auto; padding: 16px 0 0;">\
|
||||
<div class="ssl-con-key pull-left">Key<br>\
|
||||
<textarea id="key" class="bt-input-text">' + cert.privateKey + '</textarea>\
|
||||
</div>\
|
||||
<div class="ssl-con-key pull-right">Certificate (in pem format)<br>\
|
||||
<textarea id="csr" class="bt-input-text">' + cert.certPem + '</textarea>\
|
||||
</div>\
|
||||
<div style="clear: both;"></div>\
|
||||
</div>\
|
||||
');
|
||||
set_height();
|
||||
});
|
||||
}
|
||||
$('.ssl_cert_from .line .tname').css('width', '75px');
|
||||
}
|
||||
},
|
||||
{
|
||||
html: '\
|
||||
<div class="details" style="width: 80%;">\
|
||||
<input type="checkbox" id="checkSSL" />\
|
||||
<label style="font-weight: 400;" for="checkSSL">' + lan.config.ssl_open_ps_4 + '</label>\
|
||||
<a class="btlink" style="top: 0;" href="https://forum.aapanel.com/d/167-common-problems-after-opening-the-panel-certificate" target="_blank">' + lan.config.ssl_open_ps_5 + '</a>\
|
||||
</div>\
|
||||
'
|
||||
}
|
||||
bt.send('get_cert_source', 'config/get_cert_source', {}, function (rdata) {
|
||||
layer.close(loadT);
|
||||
var sdata = rdata;
|
||||
var _data = {
|
||||
title: 'Panel SSL',
|
||||
area: '630px',
|
||||
class: 'ssl_cert_from ssl_cert_panel_from',
|
||||
list: [
|
||||
{
|
||||
html: '\
|
||||
<div style="position: relative; width: 90%; margin: 0 auto;">\
|
||||
<i class="layui-layer-ico layui-layer-ico3" style="left: 0;"></i>\
|
||||
<h3 style="margin-left: 45px;">' + lan.config.ssl_open_ps + '</h3>\
|
||||
<ul style="width: 100%;">\
|
||||
<li style="color:red;">' + lan.config.ssl_open_ps_1 + '</li>\
|
||||
<li>' + lan.config.ssl_open_ps_2 + '</li>\
|
||||
<li>If panel is not accessible, you can click the <a class="btlink" href="https://forum.aapanel.com/d/167-common-problems-after-opening-the-panel-certificate" target="_blank">link</a> below to find solutions</li>\
|
||||
</ul>\
|
||||
</div>\
|
||||
'
|
||||
},
|
||||
{
|
||||
title: 'Cert Type',
|
||||
name: 'cert_type',
|
||||
type: 'select',
|
||||
width: '260px',
|
||||
value: sdata.cert_type,
|
||||
items: [
|
||||
{value: '1', title: 'Self-signed certificate'},
|
||||
{value: '2', title: 'Let\'s Encrypt'},
|
||||
{value: '3', title: 'I have certficate'}
|
||||
],
|
||||
callback: function (obj) {
|
||||
var set_height = function () {
|
||||
var layer_box = $('.ssl_cert_from').parents('.layui-layer');
|
||||
var window_height = $(window).height();
|
||||
var height = layer_box.height();
|
||||
var top = (window_height - height) / 2;
|
||||
layer_box.css({
|
||||
'top': top + 'px'
|
||||
});
|
||||
}
|
||||
var subid = obj.attr('name') + '_subid';
|
||||
var keyid = obj.attr('name') + '_keyid';
|
||||
$('#' + subid).remove();
|
||||
$('#' + keyid).remove();
|
||||
if (obj.val() == '1') {
|
||||
set_height();
|
||||
}
|
||||
if (obj.val() == '2') {
|
||||
var _tr = bt.render_form_line({
|
||||
title: 'E-Mail',
|
||||
name: 'email',
|
||||
width: '260px',
|
||||
placeholder: 'Admin E-Mail',
|
||||
value: sdata.email
|
||||
});
|
||||
obj.parents('div.line').append('<div class="line" id=' + subid + '>' + _tr.html + '</div>');
|
||||
set_height();
|
||||
}
|
||||
if (obj.val() == '3') {
|
||||
var loadT = layer.msg(lan.config.get_cert, {icon: 16, time: 0, shade: [0.3, '#000']});
|
||||
$.post('/config?action=GetPanelSSL', {}, function (cert) {
|
||||
layer.close(loadT);
|
||||
if (cert.privateKey === 'false') {
|
||||
cert.privateKey = 'paste your Private key (KEY) here';
|
||||
}
|
||||
if (cert.certPem === 'false') {
|
||||
cert.certPem = 'paste your Certificate (CRT/PEM) here';
|
||||
}
|
||||
obj.parents('div.line').append('\
|
||||
<div class="myKeyCon" id="' + keyid + '" style="margin: 0 auto; padding: 16px 0 0;">\
|
||||
<div class="ssl-con-key pull-left">Key<br>\
|
||||
<textarea id="key" class="bt-input-text">' + cert.privateKey + '</textarea>\
|
||||
</div>\
|
||||
<div class="ssl-con-key pull-right">Certificate (in pem format)<br>\
|
||||
<textarea id="csr" class="bt-input-text">' + cert.certPem + '</textarea>\
|
||||
</div>\
|
||||
<div style="clear: both;"></div>\
|
||||
</div>\
|
||||
');
|
||||
set_height();
|
||||
});
|
||||
}
|
||||
|
||||
],
|
||||
btns: [
|
||||
{
|
||||
title: 'Close', name: 'close', callback: function (rdata, load, callback) {
|
||||
load.close();
|
||||
$("#panelSSL").prop("checked", false);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Submit',
|
||||
name: 'submit',
|
||||
css: 'btn-success',
|
||||
callback: function (rdata, load, callback) {
|
||||
if (!$('#checkSSL').is(':checked')) return bt.msg({
|
||||
status: false,
|
||||
msg: 'Please confirm the risk first!'
|
||||
});
|
||||
layer.confirm('Whether to open the panel SSL certificate', {
|
||||
title: 'Tips',
|
||||
btn: ['Confirm', 'Cancel'],
|
||||
icon: 0,
|
||||
closeBtn: 2
|
||||
}, function () {
|
||||
var loading = bt.load();
|
||||
var type = $('select[name="cert_type"]').val();
|
||||
if (type == '3') {
|
||||
SavePanelSSL({
|
||||
loading: false,
|
||||
callback: function (res) {
|
||||
SetPanelSSL(rdata, function (res) {
|
||||
loading.close();
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
SetPanelSSL(rdata, function (rdata) {
|
||||
loading.close();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
html: '\
|
||||
<div class="details" style="width: 90%; padding-top: 15px;">\
|
||||
<input type="checkbox" id="checkSSL" />\
|
||||
<label style="font-weight: 400; margin: -1px 5px 0px;" for="checkSSL">' + lan.config.ssl_open_ps_4 + '</label>\
|
||||
<a class="btlink" style="top: 0;" href="https://forum.aapanel.com/d/167-common-problems-after-opening-the-panel-certificate" target="_blank">' + lan.config.ssl_open_ps_5 + '</a>\
|
||||
</div>\
|
||||
'
|
||||
}
|
||||
|
||||
}
|
||||
],
|
||||
end: function () {
|
||||
$("#panelSSL").prop("checked", false);
|
||||
}
|
||||
};
|
||||
var _bs = bt.render_form(_data);
|
||||
setTimeout(function () {
|
||||
$('.cert_type' + _bs).trigger('change')
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
],
|
||||
btns: [
|
||||
{
|
||||
title: 'Close', name: 'close', callback: function (rdata, load, callback) {
|
||||
load.close();
|
||||
$("#panelSSL").prop("checked", false);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Submit',
|
||||
name: 'submit',
|
||||
css: 'btn-success',
|
||||
callback: function (rdata, load, callback) {
|
||||
if (!$('#checkSSL').is(':checked')) return bt.msg({
|
||||
status: false,
|
||||
msg: 'Please confirm the risk first!'
|
||||
});
|
||||
layer.confirm('Whether to open the panel SSL certificate', {
|
||||
title: 'Tips',
|
||||
btn: ['Confirm', 'Cancel'],
|
||||
icon: 0,
|
||||
closeBtn: 2
|
||||
}, function () {
|
||||
var loading = bt.load();
|
||||
var type = $('select[name="cert_type"]').val();
|
||||
if (type == '3') {
|
||||
SavePanelSSL({
|
||||
loading: false,
|
||||
callback: function (res) {
|
||||
SetPanelSSL(rdata, function (res) {
|
||||
loading.close();
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
SetPanelSSL(rdata, function (rdata) {
|
||||
loading.close();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
],
|
||||
end: function () {
|
||||
$("#panelSSL").prop("checked", false);
|
||||
}
|
||||
};
|
||||
var _bs = bt.render_form(_data);
|
||||
setTimeout(function () {
|
||||
$('.cert_type' + _bs).trigger('change')
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function SetPanelSSL(rdata, callback) {
|
||||
bt.send('SetPanelSSL', 'config/SetPanelSSL', rdata, function (rdata) {
|
||||
if (callback) callback(rdata);
|
||||
if (rdata.status) {
|
||||
$.get('/system?action=ReWeb');
|
||||
layer.msg(rdata.msg, {icon: 1, time: 1500}, function () {
|
||||
window.location.href = ((window.location.protocol.indexOf('https') != -1) ? 'http://' : 'https://') + window.location.host + window.location.pathname;
|
||||
});
|
||||
} else {
|
||||
layer.msg(rdata.msg, {icon: 2});
|
||||
}
|
||||
});
|
||||
bt.send('SetPanelSSL', 'config/SetPanelSSL', rdata, function (rdata) {
|
||||
if (callback) callback(rdata);
|
||||
if (rdata.status) {
|
||||
$.get('/system?action=ReWeb');
|
||||
layer.msg(rdata.msg, {icon: 1, time: 1500}, function () {
|
||||
window.location.href = ((window.location.protocol.indexOf('https') != -1) ? 'http://' : 'https://') + window.location.host + window.location.pathname;
|
||||
});
|
||||
} else {
|
||||
layer.msg(rdata.msg, {icon: 2});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function GetPanelSSL(){
|
||||
var loadT = layer.msg(lan.config.get_cert,{icon:16,time:0,shade: [0.3, '#000']});
|
||||
$.post('/config?action=GetPanelSSL',{},function(cert){
|
||||
layer.close(loadT);
|
||||
var certBody = '<div class="tab-con">\
|
||||
function GetPanelSSL() {
|
||||
var loadT = layer.msg(lan.config.get_cert, {icon: 16, time: 0, shade: [0.3, '#000']});
|
||||
$.post('/config?action=GetPanelSSL', {}, function (cert) {
|
||||
layer.close(loadT);
|
||||
var certBody = '<div class="tab-con">\
|
||||
<div class="myKeyCon ptb15">\
|
||||
<div class="ssl-con-key pull-left mr20">'+lan.config.key+'<br>\
|
||||
<textarea id="key" class="bt-input-text">'+cert.privateKey+'</textarea>\
|
||||
<div class="ssl-con-key pull-left mr20">' + lan.config.key + '<br>\
|
||||
<textarea id="key" class="bt-input-text">' + cert.privateKey + '</textarea>\
|
||||
</div>\
|
||||
<div class="ssl-con-key pull-left">'+lan.config.pem_cert+'<br>\
|
||||
<textarea id="csr" class="bt-input-text">'+cert.certPem+'</textarea>\
|
||||
<div class="ssl-con-key pull-left">' + lan.config.pem_cert + '<br>\
|
||||
<textarea id="csr" class="bt-input-text">' + cert.certPem + '</textarea>\
|
||||
</div>\
|
||||
<div class="ssl-btn pull-left mtb15" style="width:100%">\
|
||||
<button class="btn btn-success btn-sm" onclick="SavePanelSSL()">'+lan.config.save+'</button>\
|
||||
<button class="btn btn-success btn-sm" onclick="SavePanelSSL()">' + lan.config.save + '</button>\
|
||||
</div>\
|
||||
</div>\
|
||||
<ul class="help-info-text c7 pull-left">\
|
||||
<li>'+lan.config.ps+'<a href="http://www.bt.cn/bbs/thread-704-1-1.html" class="btlink" target="_blank">['+lan.config.help+']</a>。</li>\
|
||||
<li>'+lan.config.ps1+'</li><li>'+lan.config.ps2+'</li>\
|
||||
<li>' + lan.config.ps + '<a href="http://www.bt.cn/bbs/thread-704-1-1.html" class="btlink" target="_blank">[' + lan.config.help + ']</a>。</li>\
|
||||
<li>' + lan.config.ps1 + '</li><li>' + lan.config.ps2 + '</li>\
|
||||
</ul>\
|
||||
</div>'
|
||||
layer.open({
|
||||
type: 1,
|
||||
area: "600px",
|
||||
title: lan.config.custom_panel_cert,
|
||||
closeBtn: 2,
|
||||
shift: 5,
|
||||
shadeClose: false,
|
||||
content:certBody
|
||||
});
|
||||
});
|
||||
area: "600px",
|
||||
title: lan.config.custom_panel_cert,
|
||||
closeBtn: 2,
|
||||
shift: 5,
|
||||
shadeClose: false,
|
||||
content: certBody
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// function SavePanelSSL(){
|
||||
@@ -684,54 +692,55 @@ function GetPanelSSL(){
|
||||
// }
|
||||
|
||||
function SavePanelSSL(option) {
|
||||
option = option || {
|
||||
loading: true
|
||||
};
|
||||
var privateKey = $("#key").val().trim();
|
||||
var certPem = $("#csr").val().trim();
|
||||
if (privateKey === 'false') return layer.msg('Please paste your Private key (KEY) here', {icon: 2});
|
||||
if (certPem === 'false') return layer.msg('Please paste your Certificate (CRT/PEM) here', {icon: 2});
|
||||
var data = {
|
||||
privateKey: privateKey,
|
||||
certPem: certPem
|
||||
}
|
||||
var loadT;
|
||||
if (option.loading) {
|
||||
loadT = layer.msg(lan.config.ssl_msg, {icon: 16, time: 0, shade: [0.3, '#000']});
|
||||
}
|
||||
$.post('/config?action=SavePanelSSL', data, function (rdata) {
|
||||
if (option.loading) layer.close(loadT);
|
||||
if (rdata.status) {
|
||||
if (option.callback) {
|
||||
option.callback(rdata);
|
||||
} else {
|
||||
layer.closeAll();
|
||||
layer.msg(rdata.msg, {icon: 1});
|
||||
}
|
||||
} else {
|
||||
layer.msg(rdata.msg, {icon: 2});
|
||||
}
|
||||
});
|
||||
option = option || {
|
||||
loading: true
|
||||
};
|
||||
var privateKey = $("#key").val().trim();
|
||||
var certPem = $("#csr").val().trim();
|
||||
if (privateKey === 'false') return layer.msg('Please paste your Private key (KEY) here', {icon: 2});
|
||||
if (certPem === 'false') return layer.msg('Please paste your Certificate (CRT/PEM) here', {icon: 2});
|
||||
var data = {
|
||||
privateKey: privateKey,
|
||||
certPem: certPem
|
||||
}
|
||||
var loadT;
|
||||
if (option.loading) {
|
||||
loadT = layer.msg(lan.config.ssl_msg, {icon: 16, time: 0, shade: [0.3, '#000']});
|
||||
}
|
||||
$.post('/config?action=SavePanelSSL', data, function (rdata) {
|
||||
if (option.loading) layer.close(loadT);
|
||||
if (rdata.status) {
|
||||
if (option.callback) {
|
||||
option.callback(rdata);
|
||||
} else {
|
||||
layer.closeAll();
|
||||
layer.msg(rdata.msg, {icon: 1});
|
||||
}
|
||||
} else {
|
||||
layer.msg(rdata.msg, {icon: 2});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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: (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 () {
|
||||
var loadT = layer.msg(lan.public.the, { icon: 16, time: 0, shade: [0.3, '#000'] });
|
||||
$.post('/config?action=set_debug', {}, function (rdata) {
|
||||
layer.close(loadT);
|
||||
if (rdata.status) layer.closeAll()
|
||||
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
|
||||
});
|
||||
},function () {
|
||||
$("#panelDebug").prop('checked',debug_stat);
|
||||
});
|
||||
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 () {
|
||||
var loadT = layer.msg(lan.public.the, {icon: 16, time: 0, shade: [0.3, '#000']});
|
||||
$.post('/config?action=set_debug', {}, function (rdata) {
|
||||
layer.close(loadT);
|
||||
if (rdata.status) layer.closeAll()
|
||||
layer.msg(rdata.msg, {icon: rdata.status ? 1 : 2});
|
||||
});
|
||||
}, function () {
|
||||
$("#panelDebug").prop('checked', debug_stat);
|
||||
});
|
||||
}
|
||||
|
||||
function set_local() {
|
||||
@@ -1237,11 +1246,11 @@ function modify_basic_auth() {
|
||||
m_html = '<div class="risk_form"><i class="layui-layer-ico layui-layer-ico3"></i>'
|
||||
+ '<h3 class="risk_tilte">Warning! Do not understand this feature, do not open!</h3>'
|
||||
+ '<ul style="border: 1px solid #ececec;border-radius: 10px; margin: 0px auto;margin-top: 20px;margin-bottom: 20px;background: #f7f7f7; width: 100 %;padding: 33px;list-style-type: inherit;">'
|
||||
+ '<li style="color:red;">You must use and understand this feature to decide if you want to open it!</li>'
|
||||
+ '<li>After opening, access the panel in any way, you will be asked to enter the BasicAuth username and password first.</li>'
|
||||
+ '<li>After being turned on, it can effectively prevent the panel from being scanned and found, but it cannot replace the account password of the panel itself.</li>'
|
||||
+ '<li>Please remember the BasicAuth password, but forget that you will not be able to access the panel.</li>'
|
||||
+ '<li>If you forget your password, you can disable BasicAuth authentication by using the bt command in SSH.</li>'
|
||||
+ '<li style="color:red;">'+lan.config.know_risk+'</li>'
|
||||
+ '<li>'+lan.config.basic_auth_desc1+'</li>'
|
||||
+ '<li>'+lan.config.basic_auth_desc2+'</li>'
|
||||
+ '<li>'+lan.config.basic_auth_desc3+'</li>'
|
||||
+ '<li>'+lan.config.basic_auth_desc4+'</li>'
|
||||
+ '</ul></div>'
|
||||
+ '<div class="details">'
|
||||
+ '<input type="checkbox" id="check_basic"><label style="font-weight: 400;margin: 3px 10px 0px;font-size:12px;" for="check_basic">I already know the details and are willing to take risks</label>'
|
||||
|
||||
@@ -132,6 +132,9 @@ function SetControl(act){
|
||||
}
|
||||
|
||||
loadT = layer.msg(lan.public.the,{icon:16,time:0})
|
||||
if(!/^-?\d+$/.test(day)){
|
||||
return layer.msg('The number of days to keep must be an integer',{icon:2,time:2000});
|
||||
}
|
||||
$.post('/config?action=SetControl','type='+type+'&day='+day,function(rdata){
|
||||
layer.close(loadT);
|
||||
layer.msg(rdata.msg,{icon:rdata.status?1:2});
|
||||
@@ -218,7 +221,6 @@ $.get('/ajax?action=GetCpuIo&start='+b+'&end='+e,function(rdata){
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: lan.public.pre,
|
||||
boundaryGap: [0, '100%'],
|
||||
min:0,
|
||||
max: 100,
|
||||
splitLine:{
|
||||
@@ -266,7 +268,8 @@ $.get('/ajax?action=GetCpuIo&start='+b+'&end='+e,function(rdata){
|
||||
}
|
||||
]
|
||||
};
|
||||
myChartCpu.setOption(option);
|
||||
myChartCpu.clear()
|
||||
myChartCpu.setOption(option, true);
|
||||
window.addEventListener("resize",function(){
|
||||
myChartCpu.resize();
|
||||
});
|
||||
@@ -307,7 +310,6 @@ $.get('/ajax?action=GetCpuIo&start='+b+'&end='+e,function(rdata){
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: lan.public.pre,
|
||||
boundaryGap: [0, '100%'],
|
||||
min:0,
|
||||
max: 100,
|
||||
splitLine:{
|
||||
@@ -355,7 +357,8 @@ $.get('/ajax?action=GetCpuIo&start='+b+'&end='+e,function(rdata){
|
||||
}
|
||||
]
|
||||
};
|
||||
myChartMen.setOption(option);
|
||||
myChartMen.clear()
|
||||
myChartMen.setOption(option, true);
|
||||
window.addEventListener("resize",function(){
|
||||
myChartMen.resize();
|
||||
});
|
||||
@@ -364,109 +367,156 @@ $.get('/ajax?action=GetCpuIo&start='+b+'&end='+e,function(rdata){
|
||||
|
||||
//磁盘io
|
||||
function disk(b, e) {
|
||||
$.get('/ajax?action=GetDiskIo&start=' + b + '&end=' + e, function (rdata) {
|
||||
var myChartDisk = echarts.init(document.getElementById('diskview'));
|
||||
var rData = [];
|
||||
var wData = [];
|
||||
var xData = [];
|
||||
//var yData = [];
|
||||
//var zData = [];
|
||||
$.get('/ajax?action=GetDiskIo&start=' + b + '&end=' + e, function (rdata) {
|
||||
var myChartDisk = echarts.init(document.getElementById('diskview'));
|
||||
var rData = [];
|
||||
var wData = [];
|
||||
var xData = [];
|
||||
var yData = [];
|
||||
var zData = [];
|
||||
|
||||
for (var i = 0; i < rdata.length; i++) {
|
||||
rData.push((rdata[i].read_bytes / 1024 / 60).toFixed(2));
|
||||
wData.push((rdata[i].write_bytes / 1024 / 60).toFixed(2));
|
||||
xData.push(rdata[i].addtime);
|
||||
//yData.push(rdata[i].read_count);
|
||||
//zData.push(rdata[i].write_count);
|
||||
}
|
||||
option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross'
|
||||
},
|
||||
//formatter: lan.control.time+":{b0}<br />{a0}: {c0} Kb/s<br />{a1}: {c1} Kb/s",
|
||||
},
|
||||
legend: {
|
||||
data: [lan.control.disk_read_bytes, lan.control.disk_write_bytes]
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: xData,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#666"
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: lan.index.unit + ':KB/s',
|
||||
boundaryGap: [0, '100%'],
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: "#ddd"
|
||||
}
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#666"
|
||||
}
|
||||
}
|
||||
},
|
||||
dataZoom: [{
|
||||
type: 'inside',
|
||||
start: 0,
|
||||
end: 100,
|
||||
zoomLock: true
|
||||
}, {
|
||||
start: 0,
|
||||
end: 100,
|
||||
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
|
||||
handleSize: '80%',
|
||||
handleStyle: {
|
||||
color: '#fff',
|
||||
shadowBlur: 3,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.6)',
|
||||
shadowOffsetX: 2,
|
||||
shadowOffsetY: 2
|
||||
}
|
||||
}],
|
||||
series: [
|
||||
{
|
||||
name: lan.control.disk_read_bytes,
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'none',
|
||||
sampling: 'average',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: 'rgb(255, 70, 131)'
|
||||
}
|
||||
},
|
||||
data: rData
|
||||
},
|
||||
{
|
||||
name: lan.control.disk_write_bytes,
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
symbol: 'none',
|
||||
sampling: 'average',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: 'rgba(46, 165, 186, .7)'
|
||||
}
|
||||
},
|
||||
data: wData
|
||||
}
|
||||
]
|
||||
};
|
||||
myChartDisk.setOption(option);
|
||||
window.addEventListener("resize", function () {
|
||||
myChartDisk.resize();
|
||||
});
|
||||
})
|
||||
for (var i = 0; i < rdata.length; i++) {
|
||||
rData.push((rdata[i].read_bytes / 1024 / 60).toFixed(2));
|
||||
wData.push((rdata[i].write_bytes / 1024 / 60).toFixed(2));
|
||||
xData.push(rdata[i].addtime);
|
||||
yData.push(rdata[i].read_count);
|
||||
zData.push(rdata[i].read_time);
|
||||
}
|
||||
option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross'
|
||||
},
|
||||
formatter: function (config) {
|
||||
var _tips = '';
|
||||
var unit = 'KB/s';
|
||||
var time = config[0].axisValue;
|
||||
var _style = '<span style="display: inline-block; width: 10px; height: 10px; margin-rigth:10px; border-radius: 50%; background: ';
|
||||
for (var i = 0; i < config.length; i++) {
|
||||
var item = config[i];
|
||||
_tips += _style + item.color + ';"></span> ' + item.seriesName + ': ';
|
||||
if (item.seriesName == lan.control.disk_read_bytes || item.seriesName == lan.control.disk_write_bytes) {
|
||||
_tips += item.data + unit + (config.length - 1 !== i ? '<br />' : '');
|
||||
} else {
|
||||
if (item.seriesName == lan.control.disk_rw_count) {
|
||||
_tips += item.data + '/s' + (config.length - 1 !== i ? '<br />' : '');
|
||||
}else{
|
||||
_tips += item.data + 'ms' + (config.length - 1 !== i ? '<br />' : '');
|
||||
}
|
||||
}
|
||||
}
|
||||
return lan.control.time + ": " + time + "<br />" + _tips;
|
||||
}
|
||||
//formatter: lan.control.time+":{b0}<br />{a0}: {c0} Kb/s<br />{a1}: {c1} Kb/s",
|
||||
},
|
||||
legend: {
|
||||
data: [
|
||||
lan.control.disk_read_bytes,
|
||||
lan.control.disk_write_bytes,
|
||||
lan.control.disk_rw_count,
|
||||
lan.control.disk_rw_time
|
||||
]
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: xData,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#666"
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: lan.index.unit + ':KB/s',
|
||||
boundaryGap: [0, '20%'],
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: "#ddd"
|
||||
}
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#666"
|
||||
}
|
||||
}
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside',
|
||||
start: 0,
|
||||
end: 100,
|
||||
zoomLock: true
|
||||
},
|
||||
{
|
||||
start: 0,
|
||||
end: 100,
|
||||
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
|
||||
handleSize: '80%',
|
||||
handleStyle: {
|
||||
color: '#fff',
|
||||
shadowBlur: 3,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.6)',
|
||||
shadowOffsetX: 2,
|
||||
shadowOffsetY: 2
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: lan.control.disk_read_bytes,
|
||||
type: 'line',
|
||||
symbol: 'none',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: 'rgb(255, 70, 131)'
|
||||
}
|
||||
},
|
||||
data: rData
|
||||
},
|
||||
{
|
||||
name: lan.control.disk_write_bytes,
|
||||
type: 'line',
|
||||
symbol: 'none',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: 'rgba(46, 165, 186, .7)'
|
||||
}
|
||||
},
|
||||
data: wData
|
||||
},
|
||||
{
|
||||
name: lan.control.disk_rw_count,
|
||||
type: 'line',
|
||||
symbol: 'none',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: 'rgba(30, 144, 255)'
|
||||
}
|
||||
},
|
||||
data: yData
|
||||
},
|
||||
{
|
||||
name: lan.control.disk_rw_time,
|
||||
type: 'line',
|
||||
symbol: 'none',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: 'rgba(255, 140, 0)'
|
||||
}
|
||||
},
|
||||
data: zData
|
||||
}
|
||||
]
|
||||
};
|
||||
myChartDisk.clear()
|
||||
myChartDisk.setOption(option, true);
|
||||
window.addEventListener("resize", function () {
|
||||
myChartDisk.resize();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//网络Io
|
||||
@@ -513,7 +563,7 @@ $.get('/ajax?action=GetNetWorkIo&start='+b+'&end='+e,function(rdata){
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: lan.index.unit+':KB/s',
|
||||
boundaryGap: [0, '100%'],
|
||||
boundaryGap: [0, '20%'],
|
||||
splitLine:{
|
||||
lineStyle:{
|
||||
color:"#ddd"
|
||||
@@ -572,7 +622,8 @@ $.get('/ajax?action=GetNetWorkIo&start='+b+'&end='+e,function(rdata){
|
||||
}
|
||||
]
|
||||
};
|
||||
myChartNetwork.setOption(option);
|
||||
myChartNetwork.clear()
|
||||
myChartNetwork.setOption(option, true);
|
||||
window.addEventListener("resize",function(){
|
||||
myChartNetwork.resize();
|
||||
});
|
||||
@@ -702,7 +753,8 @@ $.get('/ajax?action=get_load_average&start='+b+'&end='+e,function(rdata){
|
||||
}
|
||||
]
|
||||
};
|
||||
myChartgetload.setOption(option);
|
||||
myChartgetload.clear()
|
||||
myChartgetload.setOption(option, true);
|
||||
window.addEventListener("resize",function(){
|
||||
myChartgetload.resize();
|
||||
});
|
||||
@@ -783,6 +835,8 @@ function getload(b,e){
|
||||
],
|
||||
yAxis: [{
|
||||
scale: true,
|
||||
min: 0,
|
||||
max: 100,
|
||||
name: lan.control.resource_usage,
|
||||
splitLine: { // y轴网格显示
|
||||
show: true,
|
||||
@@ -923,7 +977,8 @@ function getload(b,e){
|
||||
fontSize: 12
|
||||
}
|
||||
}
|
||||
myChartgetload.setOption(option);
|
||||
myChartgetload.clear()
|
||||
myChartgetload.setOption(option, true);
|
||||
window.addEventListener("resize",function(){
|
||||
myChartgetload.resize();
|
||||
})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
var database_table = {}
|
||||
var database = {
|
||||
dbCloudServerTable: null, //远程服务器视图
|
||||
cloudDatabaseList: [], //远程服务器列表
|
||||
init: function () {
|
||||
this.database_table_view();
|
||||
var _this = this;
|
||||
@@ -10,247 +12,427 @@ var database = {
|
||||
}
|
||||
});
|
||||
},
|
||||
database_table_view:function(search){
|
||||
$('#bt_database_table').empty();
|
||||
database_table = bt_tools.table({
|
||||
el: '#bt_database_table',
|
||||
url: '/data?action=getData',
|
||||
param: {
|
||||
table: 'databases',
|
||||
search:search|| ''
|
||||
}, //参数
|
||||
minWidth: '1000px',
|
||||
default: "Database list is empty", // 数据为空时的默认提示
|
||||
column:[
|
||||
{ fid: 'id', type: 'checkbox', width: 30 },
|
||||
{
|
||||
fid: 'name',
|
||||
width: 120,
|
||||
title: lan.database.add_name,
|
||||
template: function (item) {
|
||||
return '<span class="limit-text-length" style="width: 120px;" title="' + item.name + '">' + item.name + '</span>';
|
||||
database_table_view: function (search) {
|
||||
var that = this;
|
||||
this.get_cloud_server_list(function () {
|
||||
$('#bt_database_table').empty();
|
||||
var param = { table: 'databases', search: search || '' };
|
||||
database_table = bt_tools.table({
|
||||
el: '#bt_database_table',
|
||||
url: '/data?action=getData',
|
||||
param: param, //参数
|
||||
minWidth: '1000px',
|
||||
autoHeight: true,
|
||||
default: "Database list is empty", // 数据为空时的默认提示
|
||||
beforeRequest: function () {
|
||||
var db_type_val = $('.database_type_select_filter').val();
|
||||
switch (db_type_val) {
|
||||
case 'all':
|
||||
delete param['db_type'];
|
||||
delete param['sid'];
|
||||
break;
|
||||
case 0:
|
||||
param['db_type'] = 0;
|
||||
break;
|
||||
default:
|
||||
delete param['db_type'];
|
||||
param['sid'] = db_type_val;
|
||||
}
|
||||
return param;
|
||||
},
|
||||
{
|
||||
fid: 'username',
|
||||
width: 120,
|
||||
title: lan.database.user,
|
||||
sort: function () {
|
||||
database_table.$refresh_table_list(true);
|
||||
},
|
||||
template: function (item) {
|
||||
return '<span class="limit-text-length" style="width: 120px;" title="' + item.username + '">' + item.username + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
fid:'password',
|
||||
width: 200,
|
||||
title:lan.database.add_pass,
|
||||
type:'password',
|
||||
copy:true,
|
||||
eye_open:true
|
||||
},
|
||||
{
|
||||
fid:'backup',
|
||||
title: lan.database.backup,
|
||||
width: 130,
|
||||
template: function (item) {
|
||||
var backup = lan.database.backup_empty,
|
||||
_class = "bt_warning";
|
||||
if (item.backup_count > 0) backup = lan.database.backup_ok, _class = "bt_success";
|
||||
return '<span><a href="javascript:;" class="btlink ' + _class + '" onclick="database.database_detail('+ item.id+',\''+item.name+'\')">' + backup + (item.backup_count > 0 ? ('(' + item.backup_count + ')') : '') + '</a> | ' +
|
||||
'<a href="javascript:database.input_database(\''+item.name+'\')" class="btlink">'+lan.database.input+'</a></span>';
|
||||
}
|
||||
},
|
||||
// {
|
||||
// fid: 'ps', title: lan.database.add_ps, templet: function (item) {
|
||||
// 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 {
|
||||
// _ps += lan.database.cant_get_pass+'<span style="color:red">'+lan.database.edit_pass+'</span>'+lan.database.button_set_pass+'!';
|
||||
// }
|
||||
// _ps += "</span>";
|
||||
// return _ps;
|
||||
// }
|
||||
// },
|
||||
{
|
||||
fid: 'ps',
|
||||
title: lan.database.add_ps,
|
||||
type: 'input',
|
||||
blur: function (row, index, ev) {
|
||||
bt.pub.set_data_ps({
|
||||
id: row.id,
|
||||
table: 'databases',
|
||||
ps: ev.target.value
|
||||
}, function (res) {
|
||||
layer.msg(res.msg, (res.status ? {} : {
|
||||
icon: 2
|
||||
}));
|
||||
});
|
||||
},
|
||||
keyup: function (row, index, ev) {
|
||||
if (ev.keyCode === 13) {
|
||||
$(this).blur();
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
title: lan.database.operation,
|
||||
width: 280,
|
||||
align: 'right',
|
||||
group: [{
|
||||
title: lan.database.admin,
|
||||
tips: lan.database.admin_title,
|
||||
event: function(row) {
|
||||
bt.database.open_phpmyadmin(row.name,row.username,row.password);
|
||||
}
|
||||
},{
|
||||
title: lan.database.auth,
|
||||
tips:lan.database.set_db_auth,
|
||||
event: function(row) {
|
||||
bt.database.set_data_access(row.username);
|
||||
}
|
||||
},{
|
||||
title:lan.database.tools,
|
||||
tips:lan.database.mysql_tools,
|
||||
event: function(row){
|
||||
database.rep_tools(row.name);
|
||||
}
|
||||
},{
|
||||
title:lan.database.edit_pass,
|
||||
tips:lan.database.edit_pass_title,
|
||||
event: function(row){
|
||||
database.set_data_pass(row.id,row.username,row.password);
|
||||
}
|
||||
},{
|
||||
title:lan.database.del,
|
||||
tips:lan.database.del_title,
|
||||
event: function(row){
|
||||
database.del_database(row.id,row.name);
|
||||
}
|
||||
}]
|
||||
}
|
||||
],
|
||||
sortParam: function (data) {
|
||||
return {
|
||||
'order': data.name + ' ' + data.sort
|
||||
};
|
||||
},
|
||||
tootls: [{ // 按钮组
|
||||
type: 'group',
|
||||
positon: ['left', 'top'],
|
||||
list: [{
|
||||
title: lan.database.add_title,
|
||||
active: true,
|
||||
event: function () {
|
||||
bt.database.add_database(function (res){
|
||||
if(res.status) database_table.$refresh_table_list(true);
|
||||
})
|
||||
}
|
||||
},{
|
||||
title: lan.database.edit_root,
|
||||
event: function () {
|
||||
bt.database.set_root('root')
|
||||
}
|
||||
},{
|
||||
title: 'phpMyAdmin',
|
||||
event: function () {
|
||||
bt.database.open_phpmyadmin('','root', bt.config.mysql_root)
|
||||
}
|
||||
},{
|
||||
title: 'Sync all',
|
||||
style: {'margin-left':'30px'},
|
||||
event: function () {
|
||||
database.sync_to_database(0)
|
||||
}
|
||||
},{
|
||||
title: 'Get DB from server',
|
||||
event: function () {
|
||||
// database.sync_to_database(1)
|
||||
bt.database.sync_database(function (rdata) {
|
||||
if (rdata.status) that.database_table.$refresh_table_list(true);
|
||||
});
|
||||
}
|
||||
}]
|
||||
},{
|
||||
type: 'batch', //batch_btn
|
||||
positon: ['left', 'bottom'],
|
||||
placeholder: 'Select batch operation',
|
||||
buttonValue: 'Execute',
|
||||
disabledSelectValue: 'Select the DB to execute!!',
|
||||
selectList: [{
|
||||
title:'Sync to Server',
|
||||
url:'/database?action=SyncToDatabases&type=1',
|
||||
paramName: 'ids', //列表参数名,可以为空
|
||||
paramId: 'id', // 需要传入批量的id
|
||||
th:'Database Name',
|
||||
beforeRequest: function(list) {
|
||||
var arry = [];
|
||||
$.each(list, function (index, item) {
|
||||
arry.push(item.id);
|
||||
});
|
||||
return JSON.stringify(arry)
|
||||
},
|
||||
success: function (res, list, that) {
|
||||
layer.closeAll();
|
||||
var html = '';
|
||||
$.each(list, function (index, item) {
|
||||
html += '<tr><td>' + item.name + '</td><td><div style="float:right;"><span style="color:' + (res.status ? '#20a53a' : 'red') + '">' + res.msg + '</span></div></td></tr>';
|
||||
});
|
||||
that.$batch_success_table({
|
||||
title: 'Batch sync selected',
|
||||
th: 'Database Name',
|
||||
html: html
|
||||
});
|
||||
}
|
||||
},{
|
||||
title: "Delete database",
|
||||
url: '/database?action=DeleteDatabase',
|
||||
load: true,
|
||||
param: function (row) {
|
||||
return {
|
||||
id: row.id,
|
||||
name: row.name
|
||||
column:[
|
||||
{ fid: 'id', type: 'checkbox', width: 20 },
|
||||
{
|
||||
fid: 'name',
|
||||
width: 120,
|
||||
title: lan.database.add_name,
|
||||
template: function (item) {
|
||||
return '<span class="limit-text-length" style="width: 100px;" title="' + item.name + '">' + item.name + '</span>';
|
||||
}
|
||||
},
|
||||
callback: function (that) { // 手动执行,data参数包含所有选中的站点
|
||||
var ids = [];
|
||||
for (var i = 0; i < that.check_list.length; i++) {
|
||||
ids.push(that.check_list[i].id);
|
||||
}
|
||||
database.del_database(ids,function(param){
|
||||
that.start_batch(param, function (list) {
|
||||
layer.closeAll()
|
||||
var html = '';
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var item = list[i];
|
||||
html += '<tr><td>' + item.name + '</td><td><div style="float:right;"><span style="color:' + (item.request.status ? '#20a53a' : 'red') + '">' + item.request.msg + '</span></div></td></tr>';
|
||||
}
|
||||
database_table.$batch_success_table({
|
||||
title: 'Batch deletion',
|
||||
th: 'Database Name',
|
||||
html: html
|
||||
});
|
||||
});
|
||||
{
|
||||
fid: 'username',
|
||||
width: 120,
|
||||
title: lan.database.user,
|
||||
sort: function () {
|
||||
database_table.$refresh_table_list(true);
|
||||
})
|
||||
},
|
||||
template: function (item) {
|
||||
return '<span class="limit-text-length" style="width: 100px;" title="' + item.username + '">' + item.username + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
fid:'password',
|
||||
width: 220,
|
||||
title: lan.database.add_pass,
|
||||
type: 'password',
|
||||
copy: true,
|
||||
eye_open: true,
|
||||
template: function (row) {
|
||||
var id = row.id;
|
||||
var username = row.username;
|
||||
var password = row.password;
|
||||
if (row.password === '') return '<span class="c9 cursor" onclick="database.set_data_pass(\'' + id + '\',\'' + username + '\',\'' + password + '\')">' + lan.database.not_found_pwd_1 + '<span style="color:red">' + lan.database.not_found_pwd_2 + '</span>' + lan.database.not_found_pwd_3 + '!</span>';
|
||||
return true;
|
||||
}
|
||||
},
|
||||
bt.public.get_quota_config('database'),
|
||||
{
|
||||
fid: 'backup',
|
||||
title: lan.database.backup,
|
||||
width: 130,
|
||||
template: function (item) {
|
||||
var backup = lan.database.backup_empty,
|
||||
_class = "bt_warning";
|
||||
if (item.backup_count > 0) backup = lan.database.backup_ok, _class = "bt_success";
|
||||
return '<span><a href="javascript:;" class="btlink ' + _class + '" onclick="database.database_detail('+ item.id+',\''+item.name+'\')">' + backup + (item.backup_count > 0 ? ('(' + item.backup_count + ')') : '') + '</a> | ' +
|
||||
'<a href="javascript:database.input_database(\''+item.name+'\')" class="btlink">'+lan.database.input+'</a></span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
fid: 'position',
|
||||
title: lan.database.position,
|
||||
type: 'text',
|
||||
template: function (row) {
|
||||
var type_column = '-';
|
||||
var host = row.conn_config.db_host;
|
||||
var port = row.conn_config.db_port;
|
||||
switch(row.db_type){
|
||||
case 0:
|
||||
type_column = lan.database.add_auth_local;
|
||||
break;
|
||||
case 1:
|
||||
type_column = (lan.database.cloud_database + '(' + host + ':' + port + ')').toString();
|
||||
break;
|
||||
case 2:
|
||||
var list = that.cloudDatabaseList;
|
||||
$.each(list, function(index, item) {
|
||||
var db_host = item.db_host;
|
||||
var db_port = item.db_port;
|
||||
if (row.sid == item.id) {
|
||||
// 默认显示备注
|
||||
if (item.ps !== '') {
|
||||
type_column = item.ps
|
||||
} else {
|
||||
type_column = (lan.database.cloud_database + '(' + db_host + ':' + db_port + ')').toString();
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
return '<span class="size_ellipsis" style="width: 100px" title="' + type_column + '">' + type_column + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
fid: 'ps',
|
||||
title: lan.database.add_ps,
|
||||
type: 'input',
|
||||
blur: function (row, index, ev) {
|
||||
bt.pub.set_data_ps({
|
||||
id: row.id,
|
||||
table: 'databases',
|
||||
ps: ev.target.value
|
||||
}, function (res) {
|
||||
layer.msg(res.msg, (res.status ? {} : {
|
||||
icon: 2
|
||||
}));
|
||||
});
|
||||
},
|
||||
keyup: function (row, index, ev) {
|
||||
if (ev.keyCode === 13) {
|
||||
$(this).blur();
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
title: lan.database.operation,
|
||||
width: 280,
|
||||
align: 'right',
|
||||
group: [
|
||||
{
|
||||
title: lan.database.admin,
|
||||
tips: lan.database.admin_title,
|
||||
hide: function (row) {
|
||||
return row.db_type != 0
|
||||
},
|
||||
event: function(row) {
|
||||
bt.database.open_phpmyadmin(row.name,row.username,row.password);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lan.database.auth,
|
||||
tips:lan.database.set_db_auth,
|
||||
hide: function (row) {
|
||||
return row.db_type == 1
|
||||
},
|
||||
event: function(row) {
|
||||
bt.database.set_data_access(row.username);
|
||||
}
|
||||
},
|
||||
{
|
||||
title:lan.database.tools,
|
||||
tips:lan.database.mysql_tools,
|
||||
event: function(row){
|
||||
database.rep_tools(row.name);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lan.database.edit_pass,
|
||||
tips: lan.database.edit_pass_title,
|
||||
hide: function (row) {
|
||||
return row.db_type == 1
|
||||
},
|
||||
event: function(row){
|
||||
database.set_data_pass(row.id,row.username,row.password);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lan.database.del,
|
||||
tips: lan.database.del_title,
|
||||
event: function(row){
|
||||
database.del_database(row.id, row.name, row);
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}]
|
||||
}, { //分页显示
|
||||
type: 'page',
|
||||
positon: ['right', 'bottom'], // 默认在右下角
|
||||
pageParam: 'p', //分页请求字段,默认为 : p
|
||||
page: 1, //当前分页 默认:1
|
||||
numberParam: 'limit', //分页数量请求字段默认为 : limit
|
||||
number: 20, //分页数量默认 : 20条
|
||||
numberList: [10, 20, 50, 100, 200], // 分页显示数量列表
|
||||
numberStatus: true, // 是否支持分页数量选择,默认禁用
|
||||
jump: true, //是否支持跳转分页,默认禁用
|
||||
}]
|
||||
],
|
||||
sortParam: function (data) {
|
||||
return {
|
||||
'order': data.name + ' ' + data.sort
|
||||
};
|
||||
},
|
||||
tootls: [
|
||||
{ // 按钮组
|
||||
type: 'group',
|
||||
positon: ['left', 'top'],
|
||||
list: [
|
||||
{
|
||||
title: lan.database.add_title,
|
||||
active: true,
|
||||
event: function () {
|
||||
that.generate_cloud_server_list(function (list) {
|
||||
bt.database.add_database(list, function (res){
|
||||
if (res.status) database_table.$refresh_table_list(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lan.database.edit_root,
|
||||
event: function () {
|
||||
bt.database.set_root('root')
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'phpMyAdmin',
|
||||
event: function () {
|
||||
bt.database.open_phpmyadmin('','root', bt.config.mysql_root)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lan.database.cloud_server,
|
||||
event: function() {
|
||||
database.open_cloud_server();
|
||||
}
|
||||
},{
|
||||
title: 'Sync all',
|
||||
style: { 'margin-left': '30px' },
|
||||
event: function () {
|
||||
database.sync_to_database(0)
|
||||
}
|
||||
}, {
|
||||
title: 'Get DB from server',
|
||||
event: function () {
|
||||
that.generate_cloud_server_list(function (list) {
|
||||
bt_tools.open({
|
||||
title: lan.database.select_position,
|
||||
area: '450px',
|
||||
skin: 'databaseCloudServer',
|
||||
btn: [lan.public.confirm, lan.public.cancel],
|
||||
content: {
|
||||
'class':'pd20',
|
||||
form:[
|
||||
{
|
||||
label: lan.database.position,
|
||||
group:{
|
||||
type: 'select',
|
||||
name: 'sid',
|
||||
width: '260px',
|
||||
list: list
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
success: function ($layer) {
|
||||
$layer.find('.layui-layer-content').css('overflow','inherit');
|
||||
},
|
||||
yes: function (form, index) {
|
||||
bt.database.sync_database(form.sid, function (rdata) {
|
||||
if (rdata.status) {
|
||||
database_table.$refresh_table_list(true);
|
||||
layer.close(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
// {
|
||||
// title: 'Recycle bin',
|
||||
// style: {
|
||||
// 'position': 'absolute',
|
||||
// 'right': '-5px'
|
||||
// },
|
||||
// icon: 'trash',
|
||||
// event: function () {
|
||||
// bt.recycle_bin.open_recycle_bin(6)
|
||||
// }
|
||||
// }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'batch', // batch_btn
|
||||
positon: ['left', 'bottom'],
|
||||
placeholder: 'Select batch operation',
|
||||
buttonValue: 'Execute',
|
||||
disabledSelectValue: 'Select the DB to execute!!',
|
||||
selectList: [
|
||||
{
|
||||
title: 'Sync to Server',
|
||||
url: '/database?action=SyncToDatabases&type=1',
|
||||
paramName: 'ids', //列表参数名,可以为空
|
||||
paramId: 'id', // 需要传入批量的id
|
||||
th: 'Database Name',
|
||||
refresh: true,
|
||||
beforeRequest: function (list) {
|
||||
var arry = [];
|
||||
$.each(list, function (index, item) {
|
||||
arry.push(item.id);
|
||||
});
|
||||
return JSON.stringify(arry)
|
||||
},
|
||||
success: function (res, list, that) {
|
||||
layer.closeAll();
|
||||
var html = '';
|
||||
$.each(list, function (index, item) {
|
||||
html += '<tr><td>' + item.name + '</td><td><div style="float:right;"><span style="color:' + (res.status ? '#20a53a' : 'red') + '">' + res.msg + '</span></div></td></tr>';
|
||||
});
|
||||
that.$batch_success_table({
|
||||
title: 'Batch sync selected',
|
||||
th: 'Database Name',
|
||||
html: html
|
||||
});
|
||||
}
|
||||
}, {
|
||||
title: "Delete database",
|
||||
url: '/database?action=DeleteDatabase',
|
||||
load: true,
|
||||
refresh: true,
|
||||
param: function (row) {
|
||||
return {
|
||||
id: row.id,
|
||||
name: row.name
|
||||
}
|
||||
},
|
||||
callback: function (that) {
|
||||
// 手动执行, data参数包含所有选中的站点
|
||||
var ids = [];
|
||||
for (var i = 0; i < that.check_list.length; i++) {
|
||||
ids.push(that.check_list[i].id);
|
||||
}
|
||||
database.del_database(ids, function(param){
|
||||
that.start_batch(param, function (list) {
|
||||
layer.closeAll()
|
||||
var html = '';
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var item = list[i];
|
||||
html += '<tr><td>' + item.name + '</td><td><div style="float:right;"><span style="color:' + (item.request.status ? '#20a53a' : 'red') + '">' + item.request.msg + '</span></div></td></tr>';
|
||||
}
|
||||
database_table.$batch_success_table({
|
||||
title: 'Batch deletion',
|
||||
th: 'Database Name',
|
||||
html: html
|
||||
});
|
||||
database_table.$refresh_table_list(true);
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'search',
|
||||
positon: ['right', 'top'],
|
||||
placeholder: lan.database.database_search,
|
||||
searchParam: 'search', //搜索请求字段,默认为 search
|
||||
value: '',// 当前内容,默认为空
|
||||
},
|
||||
{ //分页显示
|
||||
type: 'page',
|
||||
positon: ['right', 'bottom'], // 默认在右下角
|
||||
pageParam: 'p', //分页请求字段,默认为 : p
|
||||
page: 1, //当前分页 默认:1
|
||||
numberParam: 'limit', //分页数量请求字段默认为 : limit
|
||||
number: 20, //分页数量默认 : 20条
|
||||
numberList: [10, 20, 50, 100, 200], // 分页显示数量列表
|
||||
numberStatus: true, // 是否支持分页数量选择,默认禁用
|
||||
jump: true, //是否支持跳转分页,默认禁用
|
||||
}
|
||||
]
|
||||
});
|
||||
// 未安装数据库
|
||||
if (!isSetup) {
|
||||
$("button[title='phpMyAdmin']").hide();
|
||||
$("button[title='Root password']").hide();
|
||||
}
|
||||
that.render_cloud_server_list();
|
||||
});
|
||||
},
|
||||
// 渲染远程数据库选择框
|
||||
render_cloud_server_list: function () {
|
||||
if ($('.database_type_select_filter').length == 0) {
|
||||
$('#bt_database_table .bt_search').before('<select class="bt-input-text mr5 database_type_select_filter" style="width:120px" name="db_type_filter"></select>');
|
||||
$('.database_type_select_filter').change(function () {
|
||||
database_table.$refresh_table_list(true);
|
||||
});
|
||||
}
|
||||
var option = '<option value="all">' + lan.public.all + '</option>';
|
||||
$.each(this.cloudDatabaseList, function (index, item) {
|
||||
var tips = item.ps != '' ? item.ps : item.db_host;
|
||||
option += '<option value="' + item.id + '">' + tips + '</option>';
|
||||
});
|
||||
$('.database_type_select_filter').html(option);
|
||||
},
|
||||
// 获取远程服务器列表
|
||||
get_cloud_server_list: function (callback) {
|
||||
var that = this;
|
||||
var loadT = bt.load(lan.database.get_cloud_list_tips);
|
||||
bt.send('GetCloudServer', 'database/GetCloudServer', {}, function (cloudData) {
|
||||
loadT.close();
|
||||
that.cloudDatabaseList = cloudData;
|
||||
callback && callback();
|
||||
});
|
||||
},
|
||||
// 生成远程服务器列表
|
||||
generate_cloud_server_list: function (callback) {
|
||||
var list = this.cloudDatabaseList;
|
||||
if (list.length == 0) {
|
||||
return layer.msg(lan.database.add_server_tips, {
|
||||
time: 0, icon: 2, closeBtn: 2, shade: .3
|
||||
});
|
||||
}
|
||||
var cloudList = [];
|
||||
$.each(list, function (index, item) {
|
||||
var ps = item.ps;
|
||||
var host = item.db_host;
|
||||
if (!ps || !host) return;
|
||||
var tips = ps != '' ? (ps + ' (' + host + ')') : host;
|
||||
cloudList.push({ title: tips, value: item.id });
|
||||
});
|
||||
callback && callback(cloudList);
|
||||
},
|
||||
rep_tools: function (db_name, res) {
|
||||
var loadT = layer.msg(lan.database.get_data, { icon: 16, time: 0 });
|
||||
bt.send('GetInfo', 'database/GetInfo', { db_name: db_name }, function (rdata) {
|
||||
@@ -263,6 +445,7 @@ var database = {
|
||||
var tbody = '';
|
||||
for (var i = 0; i < rdata.tables.length; i++) {
|
||||
if (!types[rdata.tables[i].type]) continue;
|
||||
var setType = rdata.tables[i].type == 'InnoDB' ? types.MyISAM : types.InnoDB
|
||||
tbody += '<tr>\
|
||||
<td><input value="dbtools_' + rdata.tables[i].table_name + '" class="check" onclick="database.selected_tools(null,\'' + db_name + '\');" type="checkbox"></td>\
|
||||
<td><span style="width:150px;"> ' + rdata.tables[i].table_name + '</span></td>\
|
||||
@@ -273,7 +456,7 @@ var database = {
|
||||
<td style="text-align: right;">\
|
||||
<a class="btlink" onclick="database.rep_database(\''+ db_name + '\',\'' + rdata.tables[i].table_name + '\')">'+lan.database.backup_re+'</a> |\
|
||||
<a class="btlink" onclick="database.op_database(\''+ db_name + '\',\'' + rdata.tables[i].table_name + '\')">'+lan.database.optimization+'</a> |\
|
||||
<a class="btlink" onclick="database.to_database_type(\''+ db_name + '\',\'' + rdata.tables[i].table_name + '\',\'' + types[rdata.tables[i].type] + '\')">'+ lan.database.change + types[rdata.tables[i].type] + '</a>\
|
||||
<a class="btlink" onclick="database.to_database_type(\''+ db_name + '\',\'' + rdata.tables[i].table_name + '\',\'' + setType + '\')">'+ lan.database.change + setType + '</a>\
|
||||
</td>\
|
||||
</tr> '
|
||||
}
|
||||
@@ -288,7 +471,7 @@ var database = {
|
||||
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: lan.database.mysql_tools_box+"【" + db_name + "】",
|
||||
title: lan.database.mysql_tools_box+" [ " + db_name + " ]",
|
||||
area: ['850px', '580px'],
|
||||
closeBtn: 2,
|
||||
shadeClose: false,
|
||||
@@ -405,11 +588,6 @@ var database = {
|
||||
if (rdata.status) database_table.$refresh_table_list(true);
|
||||
});
|
||||
},
|
||||
sync_database: function () {
|
||||
bt.database.sync_database(function (rdata) {
|
||||
if (rdata.status) database_table.$refresh_table_list(true);
|
||||
})
|
||||
},
|
||||
add_database: function () {
|
||||
bt.database.add_database(function (rdata) {
|
||||
if (rdata.status) database_table.$refresh_table_list(true);
|
||||
@@ -449,9 +627,16 @@ var database = {
|
||||
break;
|
||||
}
|
||||
},
|
||||
del_database: function (wid, dbname, callback) {
|
||||
var rendom = bt.get_random_code(),num1 = rendom['num1'],num2 = rendom['num2'],title = '';
|
||||
del_database: function (wid, dbname, obj, callback) {
|
||||
var rendom = bt.get_random_code();
|
||||
var num1 = rendom['num1'];
|
||||
var num2 = rendom['num2'];
|
||||
var title = '';
|
||||
var tips = 'The deletion may affect the business!';
|
||||
title = typeof dbname === "function" ?'Batch delete databases':'Delete database [ '+ dbname +' ]';
|
||||
if (obj && obj.db_type > 0) {
|
||||
tips = lan.database.del_cloud_database_tips;
|
||||
}
|
||||
layer.open({
|
||||
type:1,
|
||||
title:title,
|
||||
@@ -462,7 +647,7 @@ var database = {
|
||||
shadeClose: true,
|
||||
content:"<div class=\'bt-form webDelete pd30\' id=\'site_delete_form\'>" +
|
||||
"<i class=\'layui-layer-ico layui-layer-ico0\'></i>" +
|
||||
"<div class=\'f13 check_title\' style=\'margin-bottom: 20px;\'>The deletion may affect the business!</div>" +
|
||||
"<div class=\'f13 check_title\' style=\'margin-bottom: 20px;\'>" + tips + "</div>" +
|
||||
"<div style=\'color:red;margin:18px 0 18px 18px;font-size:14px;font-weight: bold;\'>Note: The data is priceless, please operate with caution! ! !"+(!recycle_bin_db_open?'<br><br>Risk: The DB recycle bin is not enabled, deleting will disappear forever!':'')+"</div>" +
|
||||
"<div class=\'vcode\'>" + lan.bt.cal_msg + "<span class=\'text\'>"+ num1 +" + "+ num2 +"</span>=<input type=\'number\' id=\'vcodeResult\' value=\'\'></div>" +
|
||||
"</div>",
|
||||
@@ -592,7 +777,7 @@ var database = {
|
||||
bt.open({
|
||||
type: 1,
|
||||
skin: 'demo-class',
|
||||
area: '700px',
|
||||
area: ['700px', '400px'],
|
||||
title: lan.database.backup_title,
|
||||
closeBtn: 2,
|
||||
shift: 5,
|
||||
@@ -643,6 +828,242 @@ var database = {
|
||||
database.input_database(name);
|
||||
});
|
||||
},
|
||||
// 打开远程服务器列表弹框
|
||||
open_cloud_server: function () {
|
||||
var that = this;
|
||||
bt_tools.open({
|
||||
title: lan.database.cloud_server_list,
|
||||
area: ['860px', '400px'],
|
||||
btn: false,
|
||||
skin: 'databaseCloudServer',
|
||||
content: '<div id="db_cloud_server_table" class="pd20"></div>',
|
||||
success: function () {
|
||||
that.dbCloudServerTable = bt_tools.table({
|
||||
el: '#db_cloud_server_table',
|
||||
url: '/database?action=GetCloudServer',
|
||||
default: lan.database.cloud_server_empty,
|
||||
height: 300,
|
||||
column: [
|
||||
{
|
||||
fid: 'db_host',
|
||||
title: lan.database.server_address,
|
||||
width: 150,
|
||||
template: function (item) {
|
||||
return '<span style="width:200px;word-wrap:break-word;" title="' + item.db_host+'">' + item.db_host + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
fid: 'db_port',
|
||||
width: 100,
|
||||
title: lan.database.port
|
||||
},
|
||||
{
|
||||
fid: 'db_user',
|
||||
width: 120,
|
||||
title: lan.database.user
|
||||
},
|
||||
{
|
||||
fid: 'db_password',
|
||||
width: 190,
|
||||
type: 'password',
|
||||
title: lan.database.add_pass,
|
||||
copy: true,
|
||||
eye_open: true
|
||||
},
|
||||
{
|
||||
fid: 'ps',
|
||||
title: lan.database.add_ps,
|
||||
template: function (item) {
|
||||
var ps = item.ps;
|
||||
return '<span style="display: flex;"><span class="size_ellipsis" style="flex: 1; width: 0;" title="' + ps + '">' + ps + '</span></span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
width: 130,
|
||||
title: lan.database.operation,
|
||||
align: 'right',
|
||||
group: [
|
||||
{
|
||||
title: 'Get DB',
|
||||
event: function (row) {
|
||||
bt.database.sync_database(row.id, function (rdata) {
|
||||
if (rdata.status) {
|
||||
database_table.$refresh_table_list(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lan.public.edit,
|
||||
event: function (row) {
|
||||
that.render_db_cloud_server_view(row, true);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lan.public.del,
|
||||
event: function (row) {
|
||||
that.del_db_cloud_server(row);
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
tootls:[
|
||||
{
|
||||
type: 'group',
|
||||
positon: ['left', 'top'],
|
||||
list:[{
|
||||
title: lan.public.add + ' ' + lan.database.cloud_server,
|
||||
active: true,
|
||||
event: function() {
|
||||
that.render_db_cloud_server_view();
|
||||
}
|
||||
}]
|
||||
}
|
||||
],
|
||||
success: function (config) {
|
||||
that.cloudDatabaseList = config.data;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
// 添加/编辑远程服务器视图
|
||||
render_db_cloud_server_view: function(config, is_edit) {
|
||||
var that = this;
|
||||
if (!config) {
|
||||
config = {
|
||||
db_host: '',
|
||||
db_port: '3306',
|
||||
db_user: '',
|
||||
db_password: '',
|
||||
db_user: 'root',
|
||||
ps: ''
|
||||
};
|
||||
}
|
||||
var title = is_edit ? lan.public.edit : lan.public.add;
|
||||
bt_tools.open({
|
||||
title: title + ' ' + lan.database.cloud_server,
|
||||
area: '450px',
|
||||
btn: [lan.public.save, lan.public.cancel],
|
||||
skin: 'addCloudServerProject',
|
||||
content:{
|
||||
'class':'pd20',
|
||||
form:[
|
||||
{
|
||||
label: lan.database.server_address,
|
||||
group:{
|
||||
type: 'text',
|
||||
name: 'db_host',
|
||||
width: '260px',
|
||||
value: config.db_host,
|
||||
placeholder: lan.database.input_server_address,
|
||||
event: function () {
|
||||
$('[name=db_host]').on('input', function () {
|
||||
$('[name=db_ps]').val($(this).val());
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: lan.database.port,
|
||||
group: {
|
||||
type: 'number',
|
||||
name: 'db_port',
|
||||
width: '260px',
|
||||
value: config.db_port,
|
||||
placeholder: lan.database.input_port
|
||||
}
|
||||
},
|
||||
{
|
||||
label: lan.database.user,
|
||||
group: {
|
||||
type: 'text',
|
||||
name: 'db_user',
|
||||
width: '260px',
|
||||
value: config.db_user,
|
||||
placeholder: lan.database.input_username
|
||||
}
|
||||
},
|
||||
{
|
||||
label: lan.database.add_pass,
|
||||
group:{
|
||||
type: 'text',
|
||||
name: 'db_password',
|
||||
width: '260px',
|
||||
value: config.db_password,
|
||||
placeholder: lan.database.input_password
|
||||
}
|
||||
},
|
||||
{
|
||||
label: lan.database.add_ps,
|
||||
group:{
|
||||
type: 'text',
|
||||
name: 'db_ps',
|
||||
width: '260px',
|
||||
value: config.ps,
|
||||
placeholder: lan.database.server_note
|
||||
}
|
||||
},
|
||||
{
|
||||
group: {
|
||||
type: 'help',
|
||||
style: {'margin-top':'0'},
|
||||
list: [
|
||||
lan.database.remote_help_1,
|
||||
lan.database.remote_help_2,
|
||||
lan.database.remote_help_3,
|
||||
lan.database.remote_help_4
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
yes: function (form, indexs) {
|
||||
var interface = is_edit ? 'ModifyCloudServer' : 'AddCloudServer';
|
||||
if (form.db_host == '') return layer.msg(lan.database.input_server_address, { icon: 2 });
|
||||
if (form.db_port == '') return layer.msg(lan.database.input_port, { icon: 2 });
|
||||
if (form.db_user == '') return layer.msg(lan.database.input_username, { icon: 2 });
|
||||
if (form.db_password == '') return layer.msg(lan.database.input_password, { icon: 2 });
|
||||
|
||||
if (is_edit) form['id'] = config['id'];
|
||||
|
||||
var tips = is_edit ? lan.database.edit_cloud_server_tips : lan.database.add_cloud_server_tips;
|
||||
var layerT = bt.load(tips);
|
||||
bt.send(interface, 'database/' + interface, form, function (rdata) {
|
||||
layerT.close();
|
||||
if (rdata.status) {
|
||||
that.dbCloudServerTable.$refresh_table_list();
|
||||
layer.close(indexs);
|
||||
layer.msg(rdata.msg, { icon: 1 });
|
||||
} else {
|
||||
layer.msg(rdata.msg, {
|
||||
time:0,icon:2,closeBtn: 2, shade: .3, area: '650px'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
// 删除远程服务器管理关系
|
||||
del_db_cloud_server: function (row) {
|
||||
var that = this;
|
||||
bt.confirm({
|
||||
title: lan.public.del + ' [' + row.db_host + '] ' + lan.database.cloud_server,
|
||||
msg: lan.database.del_cloud_server_tips + '!'
|
||||
}, function () {
|
||||
bt.send('RemoveCloudServer', 'database/RemoveCloudServer', {
|
||||
id: row.id
|
||||
}, function (rdata) {
|
||||
if (rdata.status) {
|
||||
database_table.$refresh_table_list(true);
|
||||
that.dbCloudServerTable.$refresh_table_list(true);
|
||||
}
|
||||
bt.msg(rdata);
|
||||
});
|
||||
})
|
||||
},
|
||||
input_database: function (name) {
|
||||
var path = bt.get_cookie('backup_path') + "/database";
|
||||
bt.send('get_files', 'files/GetDir', 'reverse=True&sort=mtime&tojs=GetFiles&p=1&showRow=100&path=' + path, function (rdata) {
|
||||
@@ -658,7 +1079,7 @@ var database = {
|
||||
bt.open({
|
||||
type: 1,
|
||||
skin: 'demo-class',
|
||||
area: '600px',
|
||||
area: ["600px", "530px"],
|
||||
title: lan.database.input_title_file+'['+name+']',
|
||||
closeBtn: 2,
|
||||
shift: 5,
|
||||
|
||||
@@ -68,516 +68,6 @@ var bt_file = {
|
||||
fix_permissions: lan.files.fix_permission,
|
||||
del_path_premissions: lan.files.deleting_permission,
|
||||
},
|
||||
file_drop:{
|
||||
f_path:null,
|
||||
startTime: 0,
|
||||
endTime:0,
|
||||
uploadLength:0, //上传数量
|
||||
splitSize: 1024 * 1024 * 2, //文件上传分片大小
|
||||
splitEndTime: 0,
|
||||
splitStartTime:0,
|
||||
fileSize:0,
|
||||
speedLastTime:0,
|
||||
filesList:[], // 文件列表数组
|
||||
errorLength:0, //上传失败文件数量
|
||||
isUpload:true, //上传状态,是否可以上传
|
||||
uploadSuspend:[], //上传暂停参数
|
||||
isUploadNumber:800,//限制单次上传数量
|
||||
uploadAllSize:0, // 上传文件总大小
|
||||
uploadedSize:0, // 已上传文件大小
|
||||
updateedSizeLast:0,
|
||||
topUploadedSize:0, // 上一次文件上传大小
|
||||
uploadExpectTime:0, // 预计上传时间
|
||||
initTimer:0, // 初始化计时
|
||||
speedInterval:null, //平局速度定时器
|
||||
timerSpeed:0, //速度
|
||||
isLayuiDrop:false, //是否是小窗口拖拽
|
||||
uploading:false,
|
||||
is_webkit:(function(){
|
||||
if(navigator.userAgent.indexOf('WebKit') > -1) return true;
|
||||
return false;
|
||||
})(),
|
||||
init:function(){
|
||||
if($('#mask_layer').length == 0) {
|
||||
window.UploadFiles = function(){ bt_file.file_drop.dialog_view()};
|
||||
$("body").append($('<div class="mask_layer" id="mask_layer" style="position:fixed;top:0;left:0;right:0;bottom:0; background:rgba(255,255,255,0.6);border:3px #ccc dashed;z-index:99999999;display:none;color:#999;font-size:40px;text-align:center;overflow:hidden;"><span style="position: absolute;top: 50%;left: 50%;margin-left: -300px;margin-top: -40px;">Upload files to the current directory'+ (!this.is_webkit?'<i style="font-size:20px;font-style:normal;display:block;margin-top:15px;color:red;">The current browser does not support drag upload. Commend to use Chrome browser or WebKit kernel for browsing</i>':'') +'</span></div>'));
|
||||
this.event_relation(document.querySelector('#container'),document,document.querySelector('#mask_layer'));
|
||||
}
|
||||
},
|
||||
// 事件关联 (进入,离开,放下)
|
||||
event_relation:function(enter,leave,drop){
|
||||
var that = this,obj = Object.keys(arguments);
|
||||
for(var item in arguments){
|
||||
if(typeof arguments[item] == "object" && typeof arguments[item].nodeType != 'undefined'){
|
||||
arguments[item] = {
|
||||
el:arguments[item],
|
||||
callback:null
|
||||
}
|
||||
}
|
||||
}
|
||||
leave.el.addEventListener("dragleave",(leave.callback != null)?leave.callback:function(e){
|
||||
if(e.x == 0 && e.y == 0) $('#mask_layer').hide();
|
||||
e.preventDefault();
|
||||
},false);
|
||||
enter.el.addEventListener("dragenter", (enter.callback != null)?enter.callback:function(e){
|
||||
if(e.dataTransfer.items[0].kind == 'string') return false
|
||||
$('#mask_layer').show();
|
||||
that.isLayuiDrop = false;
|
||||
e.preventDefault();
|
||||
},false);
|
||||
drop.el.addEventListener("dragover",function(e){ e.preventDefault() }, false);
|
||||
drop.el.addEventListener("drop",(enter.callback != null)?drop.callback:that.ev_drop, false);
|
||||
},
|
||||
|
||||
|
||||
// 事件触发
|
||||
ev_drop:function(e){
|
||||
if(e.dataTransfer.items[0].kind == 'string') return false;
|
||||
if(!bt_file.file_drop.is_webkit){
|
||||
$('#mask_layer').hide();
|
||||
return false;
|
||||
}
|
||||
e.preventDefault();
|
||||
if(bt_file.file_drop.uploading){
|
||||
layer.msg('Uploading files, please wait...');
|
||||
return false;
|
||||
}
|
||||
var items = e.dataTransfer.items,time,num = 0;
|
||||
loadT = layer.msg('Getting upload files details, please wait...',{icon:16,time:0,shade:.3});
|
||||
bt_file.file_drop.isUpload = true;
|
||||
if(items && items.length && items[0].webkitGetAsEntry != null) {
|
||||
if(items[0].kind != 'file') return false;
|
||||
}
|
||||
if(bt_file.file_drop.filesList == null) bt_file.file_drop.filesList = []
|
||||
for(var i = bt_file.file_drop.filesList.length -1; i >= 0 ; i--){
|
||||
if(bt_file.file_drop.filesList[i].is_upload) bt_file.file_drop.filesList.splice(-i,1)
|
||||
}
|
||||
$('#mask_layer').hide();
|
||||
function update_sync(s){
|
||||
s.getFilesAndDirectories().then(function(subFilesAndDirs) {
|
||||
return iterateFilesAndDirs(subFilesAndDirs, s.path);
|
||||
});
|
||||
}
|
||||
|
||||
var iterateFilesAndDirs = function(filesAndDirs, path) {
|
||||
if(!bt_file.file_drop.isUpload) return false
|
||||
for (var i = 0; i < filesAndDirs.length; i++) {
|
||||
if (typeof(filesAndDirs[i].getFilesAndDirectories) == 'function') {
|
||||
update_sync(filesAndDirs[i])
|
||||
} else {
|
||||
if(num > bt_file.file_drop.isUploadNumber){
|
||||
bt_file.file_drop.isUpload = false;
|
||||
layer.msg(' '+ bt_file.file_drop.isUploadNumber +' items cannot upload, please compress first!。',{icon:2,area:'405px'});
|
||||
bt_file.file_drop.filesList = [];
|
||||
clearTimeout(time);
|
||||
return false;
|
||||
}
|
||||
bt_file.file_drop.filesList.push({
|
||||
file:filesAndDirs[i],
|
||||
path:bt.get_file_path(path +'/'+ filesAndDirs[i].name).replace('//','/'),
|
||||
name:filesAndDirs[i].name.replace('//','/'),
|
||||
icon:bt_file.get_ext_name(filesAndDirs[i].name),
|
||||
size:bt_file.file_drop.to_size(filesAndDirs[i].size),
|
||||
upload:0, //上传状态,未上传:0、上传中:1,已上传:2,上传失败:-1
|
||||
is_upload:false
|
||||
});
|
||||
bt_file.file_drop.uploadAllSize += filesAndDirs[i].size
|
||||
clearTimeout(time);
|
||||
time = setTimeout(function(){
|
||||
layer.close(loadT);
|
||||
bt_file.file_drop.dialog_view();
|
||||
},100);
|
||||
num ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if('getFilesAndDirectories' in e.dataTransfer){
|
||||
e.dataTransfer.getFilesAndDirectories().then(function(filesAndDirs) {
|
||||
return iterateFilesAndDirs(filesAndDirs, '/');
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
// 上传视图
|
||||
dialog_view:function(config){
|
||||
var that = this,html = '';
|
||||
this.f_path = bt_file.file_path;
|
||||
if(!$('.file_dir_uploads').length > 0){
|
||||
if(that.filesList == null) that.filesList = []
|
||||
for(var i =0; i<that.filesList.length; i++){
|
||||
var item = that.filesList[i];
|
||||
html +='<li><div class="fileItem"><span class="filename" title="File path:'+ (item.path + '/' + item.name).replace('//','/') +' File type:'+ item.file.type +' File size:'+ item.size +'"><i class="ico ico-'+ item.icon + '"></i>'+ (item.path + '/' + item.name).replace('//','/') +'</span><span class="filesize">'+ item.size +'</span><span class="fileStatus">'+ that.is_upload_status(item.upload) +'</span></div><div class="fileLoading"></div></li>';
|
||||
}
|
||||
var is_show = that.filesList.length > 11;
|
||||
layer.open({
|
||||
type: 1,
|
||||
closeBtn: 1,
|
||||
maxmin:true,
|
||||
area: ['550px','505px'],
|
||||
btn:['Upload','Cancel','Clear'],
|
||||
title: 'Upload files to【'+ bt.get_cookie('Path') +'】--- Support breakpoint renewal',
|
||||
skin:'file_dir_uploads',
|
||||
content:'\
|
||||
<div style="padding:15px 15px 10px 15px;">\
|
||||
<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 path</a>\
|
||||
</li>\
|
||||
</ul>\
|
||||
</div>\
|
||||
<div class="file_upload_info" style="display:none;">\
|
||||
<span>Total process <i class="uploadProgress"></i>, uploading <i class="uploadNumber"></i>,</span>\
|
||||
<span style="display:none">Upload fail <i class="uploadError"></i></span>\
|
||||
<span>Speed <i class="uploadSpeed">Getting</i>,</span>\
|
||||
<span>Expect time <i class="uploadEstimate">Getting</i></span>\
|
||||
<i></i>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="upload_file_body '+ (html==''?'active':'') +'">'+ (html!=''?('<ul class="dropUpLoadFileHead" style="padding-right:'+ (is_show?'15':'0') +'px"><li class="fileTitle"><span class="filename">File name</span><span class="filesize">File size</span><span class="fileStatus">File status</span></li></ul><ul class="dropUpLoadFile list-list">'+ html +'</ul>') :'<span>Please drag the file here'+ (!that.is_webkit?'<i style="display: block;font-style: normal;margin-top: 10px;color: red;font-size: 17px;">The current browser does not support drag upload. Commend to use Chrome browser or WebKit kernel for browsing</i>':'') +'</span>') +'\
|
||||
</div>\
|
||||
</div>\
|
||||
',
|
||||
success:function(layers){
|
||||
$('#mask_layer').hide();
|
||||
layers.find('.layui-layer-btn2').css('float', 'left');
|
||||
$('.file_dir_uploads .layui-layer-max').hide();
|
||||
$('.upload_btn_groud .upload_file_btn').click(function(){$('.upload_btn_groud .dropdown-menu [data-type=file]').click()});
|
||||
$('.upload_btn_groud .dropdown-menu a').click(function(){
|
||||
var type = $(this).attr('data-type');
|
||||
$('<input type="file" multiple="true" autocomplete="off" '+ (type == 'dir'?'webkitdirectory=""':'') +' />').change(function(e){
|
||||
var files = e.target.files,arry = [];
|
||||
for(var i=0;i<files.length;i++){
|
||||
var config = {
|
||||
file:files[i],
|
||||
path: bt.get_file_path('/' + files[i].webkitRelativePath).replace('//','/') ,
|
||||
icon:bt_file.get_ext_name(files[i].name),
|
||||
name:files[i].name.replace('//','/'),
|
||||
size:that.to_size(files[i].size),
|
||||
upload:0, //上传状态,未上传:0、上传中:1,已上传:2,上传失败:-1
|
||||
is_upload:true
|
||||
}
|
||||
that.filesList.push(config);
|
||||
bt_file.file_drop.uploadAllSize += files[i].size
|
||||
}
|
||||
that.dialog_view(that.filesList);
|
||||
}).click();
|
||||
});
|
||||
var el = '';
|
||||
that.event_relation({
|
||||
el:$('.upload_file_body')[0],
|
||||
callback:function(e){
|
||||
if($(this).hasClass('active')){
|
||||
$(this).css('borderColor','#4592f0').find('span').css('color','#4592f0');
|
||||
}
|
||||
}
|
||||
},{
|
||||
el:$('.upload_file_body')[0],
|
||||
callback:function(e){
|
||||
if($(this).hasClass('active')){
|
||||
$(this).removeAttr('style').find('span').removeAttr('style');
|
||||
}
|
||||
}
|
||||
},{
|
||||
el:$('.upload_file_body')[0],
|
||||
callback:function (e) {
|
||||
var active = $('.upload_file_body');
|
||||
if(active.hasClass('active')){
|
||||
active.removeAttr('style').find('span').removeAttr('style');
|
||||
}
|
||||
that.ev_drop(e);
|
||||
that.isLayuiDrop = true;
|
||||
}
|
||||
});
|
||||
},
|
||||
yes:function(index, layero){
|
||||
if(!that.uploading){
|
||||
if(that.filesList.length == 0){
|
||||
layer.msg('Please select file',{icon:0});
|
||||
return false;
|
||||
}
|
||||
$('.layui-layer-btn0').css({'cursor':'no-drop','background':'#5c9e69'}).attr('data-upload','true').text('Uploading');
|
||||
that.upload_file();
|
||||
that.initTimer = new Date();
|
||||
that.uploading = true;
|
||||
//that.get_timer_speed();
|
||||
}
|
||||
},
|
||||
btn2:function (index, layero){
|
||||
if(that.uploading){
|
||||
layer.confirm('Do you want to cancel the upload of files? It need to delete the uploaded files manually. Continue?',{title:'Cancel file upload',icon:0},function(indexs){
|
||||
layer.close(index);
|
||||
layer.close(indexs);
|
||||
});
|
||||
return false;
|
||||
}else{
|
||||
layer.close(index);
|
||||
}
|
||||
},
|
||||
btn3: function (index, layero) {
|
||||
if (that.uploading) {
|
||||
layer.confirm('Do you want to cancel the upload of files? It need to delete the uploaded files manually. Continue?',{title:'Cancel file upload',icon:0},function(indexs){
|
||||
$('.upload_file_body').addClass('active').html('<span>Please drag the file here</span>')
|
||||
$('.file_upload_info').css('display','none').siblings().css('display','inline-block');
|
||||
that.filesList.length = 0
|
||||
});
|
||||
return false;
|
||||
} else {
|
||||
$('.upload_file_body').addClass('active').html('<span>Please drag the file here</span>');
|
||||
that.filesList.length = 0;
|
||||
$('.file_upload_info').css('display','none').siblings().css('display','inline-block')
|
||||
return false;
|
||||
}
|
||||
},
|
||||
end:function (){
|
||||
// GetFiles(bt.get_cookie('Path'));
|
||||
that.clear_drop_stauts(true);
|
||||
},
|
||||
min:function(){
|
||||
$('.file_dir_uploads .layui-layer-max').show();
|
||||
$('#layui-layer-shade'+$('.file_dir_uploads').attr('times')).fadeOut();
|
||||
},
|
||||
restore:function(){
|
||||
$('.file_dir_uploads .layui-layer-max').hide();
|
||||
$('#layui-layer-shade'+$('.file_dir_uploads').attr('times')).fadeIn();
|
||||
}
|
||||
});
|
||||
}else{
|
||||
if(config == undefined && !that.isLayuiDrop) return false;
|
||||
if(that.isLayuiDrop) config = that.filesList;
|
||||
$('.upload_file_body').html('<ul class="dropUpLoadFileHead" style="padding-right:'+ (config.length>11?'15':'0') +'px"><li class="fileTitle"><span class="filename">File name</span><span class="filesize">File size</span><span class="fileStatus">File status</span></li></ul><ul class="dropUpLoadFile list-list"></ul>').removeClass('active');
|
||||
if(Array.isArray(config)){
|
||||
for(var i =0; i<config.length; i++){
|
||||
var item = config[i];
|
||||
html +='<li><div class="fileItem"><span class="filename" title="File path:'+ item.path + '/' + item.name +' File type:'+ item.file.type +' Size:'+ item.size +'"><i class="ico ico-'+ item.icon + '"></i>'+ (item.path + '/' + item.name).replace('//','/') +'</span><span class="filesize">'+ item.size +'</span><span class="fileStatus">'+ that.is_upload_status(item.upload) +'</span></div><div class="fileLoading"></div></li>';
|
||||
}
|
||||
$('.dropUpLoadFile').append(html);
|
||||
}else{
|
||||
$('.dropUpLoadFile').append('<li><div class="fileItem"><span class="filename" title="File path:'+ (config.path + '/' + config.name).replace('//','/') +' File type:'+ config.type +' Size:'+ config.size +'"><i class="ico ico-'+ config.icon + '"></i>'+ (config.path + '/' + config.name).replace('//','/') +'</span><span class="filesize">'+ config.size +'</span><span class="fileStatus">'+ that.is_upload_status(config.upload) +'</span></div><div class="fileLoading"></div></li>');
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
// 上传单文件状态
|
||||
is_upload_status:function(status,val){
|
||||
if(val === undefined) val = ''
|
||||
switch(status){
|
||||
case -1:
|
||||
return '<span class="upload_info upload_error" title="Fail'+ (val != ''?','+val:'') +'">Fail'+ (val != ''?','+val:'') +'</span>';
|
||||
break;
|
||||
case 0:
|
||||
return '<span class="upload_info upload_primary">Waiting to upload</span>';
|
||||
break;
|
||||
case 1:
|
||||
return '<span class="upload_info upload_success">Uploaded</span>';
|
||||
break;
|
||||
case 2:
|
||||
return '<span class="upload_info upload_warning">Uploading '+ val+'</span>';
|
||||
break;
|
||||
case 3:
|
||||
return '<span class="upload_info upload_success">Stoped</span>';
|
||||
break;
|
||||
}
|
||||
},
|
||||
// 设置上传实时反馈视图
|
||||
set_upload_view:function(index,config){
|
||||
var item = $('.dropUpLoadFile li:eq('+ index +')'),that = this;
|
||||
var file_info = $('.file_upload_info');
|
||||
if($('.file_upload_info .uploadProgress').length == 0){
|
||||
$('.file_upload_info').html('<span>Total process <i class="uploadProgress"></i>,Uploading <i class="uploadNumber"></i>,</span><span style="display:none">Fail <i class="uploadError"></i></span><span>Speed <i class="uploadSpeed">Getting</i>,</span><span>Expect time <i class="uploadEstimate">Getting</i></span><i></i>');
|
||||
}
|
||||
file_info.show().prev().hide().parent().css('paddingRight',0);
|
||||
if(that.errorLength > 0) file_info.find('.uploadError').text('('+ that.errorLength +'份)').parent().show();
|
||||
file_info.find('.uploadNumber').html('('+ that.uploadLength +'/'+ that.filesList.length +')');
|
||||
file_info.find('.uploadProgress').html( ((that.uploadedSize / that.uploadAllSize) * 100).toFixed(2) +'%');
|
||||
if(config.upload === 1 || config.upload === -1){
|
||||
that.filesList[index].is_upload = true;
|
||||
that.uploadLength += 1;
|
||||
item.find('.fileLoading').css({'width':'100%','opacity':'.5','background': config.upload == -1?'#ffadad':'#20a53a21'});
|
||||
item.find('.filesize').text(config.size);
|
||||
item.find('.fileStatus').html(that.is_upload_status(config.upload,(config.upload === 1?('(Time:'+ that.diff_time(that.startTime,that.endTime) +')'):config.errorMsg)));
|
||||
item.find('.fileLoading').fadeOut(500,function(){
|
||||
$(this).remove();
|
||||
var uploadHeight = $('.dropUpLoadFile');
|
||||
if(uploadHeight.length == 0) return false;
|
||||
if(uploadHeight[0].scrollHeight > uploadHeight.height()){
|
||||
uploadHeight.scrollTop(uploadHeight.scrollTop()+40);
|
||||
}
|
||||
});
|
||||
}else{
|
||||
item.find('.fileLoading').css('width',config.percent);
|
||||
item.find('.filesize').text(config.upload_size +'/'+ config.size);
|
||||
item.find('.fileStatus').html(that.is_upload_status(config.upload,'('+ config.percent +')'));
|
||||
}
|
||||
},
|
||||
// 清除上传状态
|
||||
clear_drop_stauts:function(status){
|
||||
var time = new Date(),that = this;
|
||||
if(!status){
|
||||
try {
|
||||
var s_peed = bt_file.file_drop.to_size(bt_file.file_drop.uploadedSize / ((time.getTime() - bt_file.file_drop.initTimer.getTime()) / 1000))
|
||||
$('.file_upload_info').html('<span>'+ this.uploadLength +' uploaded,'+ (this.errorLength>0?(this.errorLength +'failures, '):'') +'time'+ this.diff_time(this.initTimer,time) + ',speed '+ s_peed +'/s</span>').append($('<i class="ico-tips-close"></i>').click(function(){
|
||||
$('.file_upload_info').hide().prev().show();
|
||||
}));
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
}
|
||||
$('.layui-layer-btn0').removeAttr('style data-upload').text(lan.upload.upload);
|
||||
$.extend(bt_file.file_drop,{
|
||||
startTime: 0,
|
||||
endTime:0,
|
||||
uploadLength:0, //上传数量
|
||||
splitSize: 1024 * 1024 * 2, //文件上传分片大小
|
||||
filesList:[], // 文件列表数组
|
||||
errorLength:0, //上传失败文件数量
|
||||
isUpload:false, //上传状态,是否可以上传
|
||||
isUploadNumber:800,//限制单次上传数量
|
||||
uploadAllSize:0, // 上传文件总大小
|
||||
uploadedSize:0, // 已上传文件大小
|
||||
topUploadedSize:0, // 上一次文件上传大小
|
||||
uploadExpectTime:0, // 预计上传时间
|
||||
initTimer:0, // 初始化计时
|
||||
speedInterval:null, //平局速度定时器
|
||||
timerSpeed:0, //速度
|
||||
uploading:false
|
||||
});
|
||||
clearInterval(that.speedInterval);
|
||||
},
|
||||
// 上传文件,文件开始字段,文件编号
|
||||
upload_file:function(fileStart,index){
|
||||
if(fileStart == undefined && this.uploadSuspend.length == 0) fileStart = 0,index = 0;
|
||||
if(this.filesList.length === index){
|
||||
clearInterval(this.speedInterval);
|
||||
this.clear_drop_stauts();
|
||||
bt_file.reader_file_list({path:bt_file.file_path,is_operating:false});
|
||||
return false;
|
||||
}
|
||||
var that = this;
|
||||
that.splitEndTime = new Date().getTime()
|
||||
that.get_timer_speed()
|
||||
|
||||
that.splitStartTime = new Date().getTime()
|
||||
var item = this.filesList[index],fileEnd = '';
|
||||
if(item == undefined) return false;
|
||||
fileEnd = Math.min(item.file.size, fileStart + this.splitSize),
|
||||
that.fileSize = fileEnd - fileStart
|
||||
form = new FormData();
|
||||
if(fileStart == 0){
|
||||
that.startTime = new Date();
|
||||
item = $.extend(item,{percent:'0%',upload:2,upload_size:'0B'});
|
||||
}
|
||||
form.append("f_path", this.f_path + item.path);
|
||||
form.append("f_name", item.name);
|
||||
form.append("f_size", item.file.size);
|
||||
form.append("f_start", fileStart);
|
||||
form.append("blob", item.file.slice(fileStart, fileEnd));
|
||||
that.set_upload_view(index,item);
|
||||
$.ajax({
|
||||
url:'/files?action=upload',
|
||||
type: "POST",
|
||||
data: form,
|
||||
async: true,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success:function(data){
|
||||
if(typeof(data) === "number"){
|
||||
that.set_upload_view(index,$.extend(item,{percent:(((data / item.file.size)* 100).toFixed(2) +'%'),upload:2,upload_size:that.to_size(data)}));
|
||||
if(fileEnd != data){
|
||||
that.uploadedSize += data;
|
||||
}else{
|
||||
that.uploadedSize += parseInt(fileEnd - fileStart);
|
||||
}
|
||||
|
||||
that.upload_file(data,index);
|
||||
}else{
|
||||
if(data.status){
|
||||
that.endTime = new Date();
|
||||
that.uploadedSize += parseInt(fileEnd - fileStart);
|
||||
that.set_upload_view(index,$.extend(item,{upload:1,upload_size:item.size}));
|
||||
that.upload_file(0,index += 1);
|
||||
}else{
|
||||
that.set_upload_view(index,$.extend(item,{upload:-1,errorMsg:data.msg}));
|
||||
that.errorLength ++;
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
error:function(e){
|
||||
if(that.filesList[index].req_error === undefined) that.filesList[index].req_error = 1
|
||||
if(that.filesList[index].req_error > 2){
|
||||
that.set_upload_view(index,$.extend(that.filesList[index],{upload:-1,errorMsg:e.statusText == 'error'?lan.public.network_err:e.statusText }));
|
||||
that.errorLength ++;
|
||||
that.upload_file(fileStart,index += 1)
|
||||
return false;
|
||||
}
|
||||
that.filesList[index].req_error += 1;
|
||||
that.upload_file(fileStart,index)
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
},
|
||||
// 获取上传速度
|
||||
get_timer_speed:function(speed){
|
||||
var done_time = new Date().getTime()
|
||||
if(done_time - this.speedLastTime > 1000){
|
||||
var that = this,num = 0;
|
||||
if(speed == undefined) speed = 200
|
||||
var s_time = (that.splitEndTime - that.splitStartTime) / 1000;
|
||||
that.timerSpeed = (that.fileSize / s_time).toFixed(2)
|
||||
that.updateedSizeLast = that.uploadedSize
|
||||
if(that.timerSpeed < 2) return;
|
||||
|
||||
$('.file_upload_info .uploadSpeed').text(that.to_size(isNaN(that.timerSpeed)?0:that.timerSpeed)+'/s');
|
||||
var estimateTime = that.time(parseInt(((that.uploadAllSize - that.uploadedSize) / that.timerSpeed) * 1000))
|
||||
if(!isNaN(that.timerSpeed)) $('.file_upload_info .uploadEstimate').text(estimateTime.indexOf('NaN') == -1?estimateTime:'0 '+lan.bt.s);
|
||||
this.speedLastTime = done_time;
|
||||
}
|
||||
},
|
||||
time:function(date){
|
||||
var hours = Math.floor(date / (60 * 60 * 1000));
|
||||
var minutes = Math.floor(date / (60 * 1000));
|
||||
var seconds = parseInt((date % (60 * 1000)) / 1000);
|
||||
var result = seconds + 'sec';
|
||||
if(minutes > 0) {
|
||||
result = minutes + "min" + seconds + 'sec';
|
||||
}
|
||||
if(hours > 0){
|
||||
result = hours + 'hour' + Math.floor((date - (hours * (60 * 60 * 1000))) / (60 * 1000)) + "min";
|
||||
}
|
||||
return result
|
||||
},
|
||||
diff_time: function (start_date, end_date) {
|
||||
var diff = end_date.getTime() - start_date.getTime();
|
||||
var minutes = Math.floor(diff / (60 * 1000));
|
||||
var leave3 = diff % (60 * 1000);
|
||||
var seconds = leave3 / 1000
|
||||
var result = seconds.toFixed(minutes > 0?0:2) + lan.bt.s;
|
||||
if (minutes > 0) {
|
||||
result = minutes + "min" + seconds.toFixed(0) + lan.bt.s
|
||||
}
|
||||
return result
|
||||
},
|
||||
|
||||
to_size: function (a) {
|
||||
var d = [" B", " KB", " MB", " GB", " TB", " PB"];
|
||||
var e = 1024;
|
||||
for (var b = 0; b < d.length; b += 1) {
|
||||
if (a < e) {
|
||||
var num = (b === 0 ? a : a.toFixed(2)) + d[b];
|
||||
return (!isNaN((b === 0 ? a : a.toFixed(2))) && typeof num != 'undefined')?num:'0B';
|
||||
}
|
||||
a /= e
|
||||
}
|
||||
}
|
||||
},
|
||||
init:function(){
|
||||
if (bt.get_cookie('rank') == undefined || bt.get_cookie('rank') == null || bt.get_cookie('rank') == 'a' || bt.get_cookie('rank') == 'b') {
|
||||
bt.set_cookie('rank', 'list');
|
||||
@@ -587,7 +77,7 @@ var bt_file = {
|
||||
this.event_bind(); // 事件绑定
|
||||
this.reader_file_list({is_operating:true}); // 渲染文件列表
|
||||
this.render_file_disk_list(); // 渲染文件磁盘列表
|
||||
this.file_drop.init(); // 初始化文件上传
|
||||
// this.file_drop.init(); // 初始化文件上传
|
||||
this.set_file_table_width(); // 设置表格宽度
|
||||
},
|
||||
// 事件绑定
|
||||
@@ -752,8 +242,10 @@ var bt_file = {
|
||||
});
|
||||
});
|
||||
// 上传
|
||||
$('.upload_file').on('click',function(e){
|
||||
that.file_drop.dialog_view();
|
||||
$('.upload_file').on('click',function(e) {
|
||||
var path = $('#fileInputPath').attr('data-path');
|
||||
uploadFiles.init_upload_path(path);
|
||||
uploadFiles.upload_layer();
|
||||
});
|
||||
// 下载
|
||||
$('.upload_download').on('click',function(e){
|
||||
@@ -1084,14 +576,24 @@ var bt_file = {
|
||||
//设置单页显示的数量,默认为100,设置local本地缓存
|
||||
$('.filePage').on('change','.showRow',function(){
|
||||
var val = $(this).val();
|
||||
bt.set_cookie('showRow',val)
|
||||
that.reader_file_list({showRow:val,p:1,is_operating:false});
|
||||
bt.set_storage('local', 'showRow', val);
|
||||
var search = $('.file_search_input').val();
|
||||
var data = { showRow: val, p: 1, is_operating: false, search: search, file_btn: !!search }
|
||||
if ($('#search_all').hasClass('active')) {
|
||||
data.all = 'True';
|
||||
}
|
||||
that.reader_file_list(data);
|
||||
});
|
||||
|
||||
// 页码跳转
|
||||
$('.filePage').on('click','div:nth-child(2) a',function(e){
|
||||
var num = $(this).attr('href').match(/p=([0-9]+)$/)[1];
|
||||
that.reader_file_list({path:that.path,p:num})
|
||||
var search = $('.file_search_input').val();
|
||||
var data = { path: that.path, p: num, search: search, file_btn: !!search }
|
||||
if ($('#search_all').hasClass('active')) {
|
||||
data.all = 'True';
|
||||
}
|
||||
that.reader_file_list(data);
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
})
|
||||
@@ -1154,10 +656,11 @@ var bt_file = {
|
||||
top: endPos.top > startPos.top ? startPos.top : endPos.top,
|
||||
left: endPos.left > startPos.left ? startPos.left : endPos.left
|
||||
};
|
||||
var enter_files_box = that.enter_files_box()
|
||||
if(bt.get_cookie('rank') == 'list'){ //在列表模式下减去表头高度
|
||||
fixedPoint.top = fixedPoint.top + 40
|
||||
}
|
||||
var enter_files_box = that.enter_files_box()
|
||||
|
||||
// 拖拽范围的宽高
|
||||
var w = Math.min(Math.abs(endPos.left - startPos.left), con_l + container.width() - fixedPoint.left);
|
||||
var h = Math.min(Math.abs(endPos.top - startPos.top), con_t + container.height() - fixedPoint.top);
|
||||
@@ -1216,29 +719,31 @@ var bt_file = {
|
||||
}
|
||||
|
||||
// 鼠标抬起
|
||||
bt_file.window_mouseup = function() {
|
||||
bt_file.window_mouseup = function(ev) {
|
||||
var _move_array = [],enter_files_box = that.enter_files_box();
|
||||
var box_offset_top = enter_files_box.offset().top;
|
||||
var box_offset_left = enter_files_box.offset().left;
|
||||
var box_offset_w = enter_files_box.offset().left + enter_files_box.width();
|
||||
var box_offset_h = enter_files_box.offset().top + enter_files_box.height();
|
||||
$(container).find('.file_tr').each(function(i,item){
|
||||
var offset_top = $(item).offset().top;
|
||||
var offset_left = $(item).offset().left;
|
||||
var offset_h = $(item).offset().top + $(item).height();
|
||||
var offset_w = $(item).offset().left + $(item).width();
|
||||
if(box_offset_top && box_offset_left && box_offset_w && box_offset_h){
|
||||
$(container).find('.file_tr').each(function(i,item){
|
||||
var offset_top = $(item).offset().top;
|
||||
var offset_left = $(item).offset().left;
|
||||
var offset_h = $(item).offset().top + $(item).height();
|
||||
var offset_w = $(item).offset().left + $(item).width();
|
||||
|
||||
if(bt.get_cookie('rank') == 'icon'){ // 为Icon模式时
|
||||
if(offset_w >= box_offset_left && offset_left <= box_offset_w && offset_h >= box_offset_top && offset_top <= box_offset_h){
|
||||
_move_array.push($(item).data('index'))
|
||||
}
|
||||
}else{// 为List模式时
|
||||
if (offset_w >= box_offset_left && offset_h >= box_offset_top && offset_top <= box_offset_h ) {
|
||||
_move_array.push($(item).data('index'))
|
||||
}
|
||||
}
|
||||
});
|
||||
that.render_file_selected(_move_array); //渲染数据
|
||||
if(bt.get_cookie('rank') == 'icon'){ // 为Icon模式时
|
||||
if(offset_w >= box_offset_left && offset_left <= box_offset_w && offset_h >= box_offset_top && offset_top <= box_offset_h){
|
||||
_move_array.push($(item).data('index'))
|
||||
}
|
||||
}else{// 为List模式时
|
||||
if (offset_w >= box_offset_left && offset_h >= box_offset_top && offset_top <= box_offset_h ) {
|
||||
_move_array.push($(item).data('index'))
|
||||
}
|
||||
}
|
||||
});
|
||||
that.render_file_selected(_move_array); //渲染数据
|
||||
}
|
||||
enter_files_box.remove(); //删除盒子
|
||||
$('.file_list_content').unbind('mousewheel'); //解绑滚轮事件
|
||||
$(document).unbind('mousemove',bt_file.window_mousemove);
|
||||
@@ -1292,24 +797,31 @@ var bt_file = {
|
||||
if(type == 'more') return true;
|
||||
item.open = type;
|
||||
item.index = data.index;
|
||||
item.type_tips = item.type == 'file'?'File':'Directory';
|
||||
item.type_tips = item.type == 'file' ? 'File' : 'Directory';
|
||||
that.file_groud_event(item);
|
||||
});
|
||||
// 文件搜索
|
||||
$('.replace_content').on('click', function() {
|
||||
$('.replace_content').on('click', function () {
|
||||
that.replace_content_view()
|
||||
})
|
||||
},
|
||||
// 上传文件
|
||||
file_drop: function () {
|
||||
var path = $('#fileInputPath').attr('data-path');
|
||||
uploadFiles.init_upload_path(path);
|
||||
uploadFiles.upload_layer();
|
||||
},
|
||||
/**
|
||||
* @descripttion: 文件拖拽范围
|
||||
* @author: Lifu
|
||||
* @return: 拖拽元素
|
||||
*/
|
||||
enter_files_box:function(){
|
||||
if($('#web_mouseDrag').length == 0){
|
||||
$('<div></div>',{id:'web_mouseDrag', style: [
|
||||
'position:absolute; top:0; left:0;',
|
||||
'border:1px solid #072246; background-color: #cce8ff;',
|
||||
enter_files_box: function () {
|
||||
if ($('#web_mouseDrag').length == 0) {
|
||||
$('<div></div>', {
|
||||
id: 'web_mouseDrag', style: [
|
||||
'position:absolute; top:0; left:0;',
|
||||
'border:1px solid #072246; background-color: #cce8ff;',
|
||||
'filter:Alpha(Opacity=15); opacity:0.15;',
|
||||
'overflow:hidden;display:none;z-index:9;'
|
||||
].join('')}).appendTo('.file_table_view');
|
||||
@@ -1443,12 +955,12 @@ var bt_file = {
|
||||
});
|
||||
_width += $('.menu-header-foot').innerWidth();
|
||||
if(menu_width - _width < (disk_list_width+5)){
|
||||
$('.nav_group.mount_disk_list').addClass('thezoom').find('.disk_title_group_btn').removeClass('hide');
|
||||
$('.nav_group.mount_disk_list').addClass('thezoom').find('.disk_title_group_btn').removeClass('hide');
|
||||
}else{
|
||||
$('.nav_group.mount_disk_list,.nav_group.multi').removeClass('thezoom');
|
||||
}
|
||||
if(this.area[0] < 1700){
|
||||
indexs = Math.ceil(((1700 - this.area[0]) / 68));
|
||||
if(this.area[0] < 1760){
|
||||
indexs = Math.ceil(((1760 - this.area[0]) / 68));
|
||||
$('.batch_group_list>.nav_btn_group').each(function(index){
|
||||
if(index >= $('.batch_group_list>.nav_btn_group').length - (indexs+2)){
|
||||
$(this).hide();
|
||||
@@ -2017,13 +1529,13 @@ var bt_file = {
|
||||
'<div class="file_td file_ps"><span class="file_ps_title" title="'+ item.ps +'">' + (item.is_os_ps?item.ps:'<input type="text" class="set_file_ps" data-value="'+ item.ps +'" value="'+ item.ps +'" />') + '</span></div>'+
|
||||
'<div class="file_td file_operation"><div class="set_operation_group '+ (that.is_mobile?'is_mobile':'') +'">'+
|
||||
'<a href="javascript:;" class="btlink" data-type="open">'+ is_editor_tips +'</a> | '+
|
||||
'<a href="javscript:;" class="btlink" data-type="copy">Copy</a> | '+
|
||||
'<a href="javscript:;" class="btlink" data-type="shear">Cut</a> | '+
|
||||
'<a href="javscript:;" class="btlink" data-type="rename">Rename</a> | '+
|
||||
'<a href="javscript:;" class="btlink" data-type="authority">PMSN</a> | '+
|
||||
'<a href="javascript:;" class="btlink" data-type="copy">Copy</a> | '+
|
||||
'<a href="javascript:;" class="btlink" data-type="shear">Cut</a> | '+
|
||||
'<a href="javascript:;" class="btlink" data-type="rename">Rename</a> | '+
|
||||
'<a href="javascript:;" class="btlink" data-type="authority">PMSN</a> | '+
|
||||
'<a href="javascript:;" class="btlink" data-type="'+ (is_compress?'unzip':'compress') +'">'+ (is_compress?'Unzip':'Zip') +'</a> | '+
|
||||
'<a href="javscript:;" class="btlink" data-type="del">Del</a> | '+
|
||||
'<a href="javscript:;" class="btlink foo_menu_title" data-type="more">More<i></i></a>'+
|
||||
'<a href="javascript:;" class="btlink" data-type="del">Del</a> | '+
|
||||
'<a href="javascript:;" class="btlink foo_menu_title" data-type="more">More<i></i></a>'+
|
||||
'</div></div>'+
|
||||
'</div>';
|
||||
if(item.type == 'dir') is_dir_num ++;
|
||||
@@ -2123,7 +1635,8 @@ var bt_file = {
|
||||
delete config['cancel_favorites']; // 未分享
|
||||
config['favorites'] = (data.type == 'dir' ? 'Favorites dir' : 'Favorites file');
|
||||
}
|
||||
if (data.ext == 'php') config['dir_kill'] = '文件查杀';
|
||||
// if (data.ext == 'php') config['dir_kill'] = '文件查杀';
|
||||
if (data.ext == 'php') delete config['dir_kill'];
|
||||
if (data.ext != 'php' && data.type != 'dir') delete config['dir_kill'];
|
||||
var num = 0;
|
||||
$.each(compression, function(index, item) { // 判断压缩文件
|
||||
@@ -2411,15 +1924,17 @@ var bt_file = {
|
||||
case 'folad': //解压到...
|
||||
this.unpack_file_to_path(data)
|
||||
break;
|
||||
case 'refresh': // 刷新文件列表
|
||||
$('.file_path_refresh').click();
|
||||
break;
|
||||
case 'upload': //上传文件
|
||||
this.file_drop.dialog_view();
|
||||
break;
|
||||
case 'soft_link': //软链接创建
|
||||
this.set_soft_link();
|
||||
break;
|
||||
case 'refresh': // 刷新文件列表
|
||||
$('.file_path_refresh').click();
|
||||
break;
|
||||
case 'upload': //上传文件
|
||||
var path = $('#fileInputPath').attr('data-path');
|
||||
uploadFiles.init_upload_path(path);
|
||||
uploadFiles.upload_layer();
|
||||
break;
|
||||
case 'soft_link': //软链接创建
|
||||
this.set_soft_link();
|
||||
break;
|
||||
case 'create_dir': // 新建文件目录
|
||||
$('.file_nav_view .create_file_or_dir li').eq(0).click();
|
||||
break;
|
||||
@@ -2449,9 +1964,17 @@ var bt_file = {
|
||||
* @return: 无返回值
|
||||
*/
|
||||
batch_file_manage:function(stype){
|
||||
var that = this,_api = '',_fname = [],_obj = {},_path = $('');
|
||||
var that = this,
|
||||
_api = '',
|
||||
_fname = [],
|
||||
_obj = {},
|
||||
_path = $('')
|
||||
types = [];
|
||||
$.each(this.file_table_arry,function(index,item){
|
||||
_fname.push(item.filename)
|
||||
if (item.type && types.indexOf(item.type) == -1) {
|
||||
types.push(item.type);
|
||||
}
|
||||
_fname.push(item.filename);
|
||||
})
|
||||
switch(stype){
|
||||
case 'copy': //复制
|
||||
@@ -2479,8 +2002,16 @@ var bt_file = {
|
||||
_obj['filename'] = _fname.join(',');
|
||||
_obj['open'] = 'tar_gz'
|
||||
_obj['path'] = that.file_path+'/'+file_title;
|
||||
if (types.length > 1) {
|
||||
_obj['type_tips'] = 'folder and file';
|
||||
} else if (types[0] == 'dir') {
|
||||
_obj['type_tips'] = 'folder';
|
||||
} else if (types[0] == 'file') {
|
||||
_obj['type_tips'] = 'file';
|
||||
} else {
|
||||
_obj['type_tips'] = '';
|
||||
}
|
||||
return that.compress_file_or_dir(_obj,true)
|
||||
break;
|
||||
}
|
||||
// 批量标记
|
||||
that.$http(_api,_obj,function(res){
|
||||
@@ -4210,8 +3741,7 @@ var bt_file = {
|
||||
$('.layer_close').click(function () {
|
||||
layer.close(layers);
|
||||
});
|
||||
|
||||
that.$http('get_path_premissions',{path: data.filename},function(edata){
|
||||
that.$http('get_path_premissions',{path: data.path},function(edata){
|
||||
if(edata.length == 0) $('.backuptip').text('No backup');
|
||||
});
|
||||
$('button.restore').click(function () {
|
||||
@@ -4579,14 +4109,19 @@ var bt_file = {
|
||||
*/
|
||||
remove_present_task:function(id){
|
||||
var that = this;
|
||||
layer.confirm('Do you want to cancel the upload of files? It need to delete the uploaded files manually. Continue?',{title:'Cancel file upload',icon:0},function(indexs){
|
||||
bt.send('remove_task','task/remove_task',{id:id},function(rdata){
|
||||
layer.msg(rdata.msg,{icon:1})
|
||||
layer.close(that.file_present_task)
|
||||
that.file_present_task = null;
|
||||
})
|
||||
layer.close(indexs);
|
||||
});
|
||||
layer.confirm('Do you want to cancel the current task queue?', {
|
||||
title: 'Cancel task queue',
|
||||
icon: 0
|
||||
}, function (indexs) {
|
||||
layer.close(indexs);
|
||||
var loadT = bt.load('Canceling task...');
|
||||
$.post('/task?action=remove_task', {
|
||||
id: id
|
||||
}, function(rdata) {
|
||||
loadT.close()
|
||||
bt.msg(rdata);
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @descripttion 设置访问权限
|
||||
|
||||
@@ -724,6 +724,8 @@ var index = {
|
||||
var rlen = rdata.length;
|
||||
var clickName = '';
|
||||
var setup_length = 0;
|
||||
var softboxsum = 12;
|
||||
var softboxcon = '';
|
||||
for (var i = 0; i < rlen; i++) {
|
||||
if (rdata[i].setup) {
|
||||
setup_length++;
|
||||
@@ -754,9 +756,34 @@ var index = {
|
||||
}
|
||||
}
|
||||
$("#indexsoft").html(con);
|
||||
// 推荐安装软件
|
||||
try {
|
||||
var recomConfig = product_recommend.get_recommend_type(1)
|
||||
if(recomConfig){
|
||||
var pay_status = product_recommend.get_pay_status();
|
||||
for (var i = 0; i < recomConfig['list'].length; i++) {
|
||||
const item = recomConfig['list'][i];
|
||||
if(setup_length > softboxsum) break;
|
||||
if(pay_status.is_pay && item['install']) continue;
|
||||
softboxcon += '<div class="col-sm-3 col-md-3 col-lg-3">\
|
||||
<div class="recommend-soft recom-iconfont">\
|
||||
<div class="product-close hide">关闭推荐</div>\
|
||||
<div class="images"><img src="/static/img/soft_ico/ico-'+ item['name'] +'.png"></div>\
|
||||
<div class="product-name">'+ item['title'] +'</div>\
|
||||
<div class="product-pay-btn">\
|
||||
'+ ((item['isBuy'] && !item['install'])?
|
||||
'<button class="btn btn-sm btn-success home_recommend_btn" style="margin-left:0;" onclick="bt.soft.install(\''+ item['name'] +'\')">Install</button>':
|
||||
'<a class="btn btn-sm btn-default mr5 '+ (!item.preview?'hide':'') +'" href="'+ item.preview +'" target="_blank">Preview</a><button type="submit" class="btn btn-sm btn-success home_recommend_btn" onclick=\"product_recommend.pay_product_sign(\'pro\','+ item.pay +')\">Buy now</button>') +'\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>'
|
||||
setup_length ++;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
//软件位置移动
|
||||
var softboxsum = 12;
|
||||
var softboxcon = '';
|
||||
if (setup_length <= softboxsum) {
|
||||
for (var i = 0; i < softboxsum - setup_length; i++) {
|
||||
softboxcon += '<div class="col-sm-3 col-md-3 col-lg-3 no-bg"></div>'
|
||||
@@ -794,7 +821,7 @@ 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> '+ 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) + ' '+lan.index.update_time+' ' + (is_beta != 1 ? result.msg.beta.uptime : result.msg.uptime) + '</div>\
|
||||
<div class="update_tips">'+ lan.index.last_version_is+(is_beta != 1 ? lan.index.test_version : lan.index.final_version) + (result.msg.is_beta != 1 ? result.msg.beta.version : result.msg.version) + ' '+lan.index.update_time+' ' + (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>\
|
||||
<div class="bt-form-submit-btn">\
|
||||
@@ -834,11 +861,11 @@ var index = {
|
||||
content: '<div class="setchmod bt-form" style="padding-bottom:50px;">\
|
||||
<div class="update_title"><i class="layui-layer-ico layui-layer-ico0"></i><span>'+lan.index.have_new_version+'</span></div>\
|
||||
<div class="update_conter">\
|
||||
<div class="update_version">'+lan.index.last_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_version_log+'">'+lan.index.bt_linux+ (is_beta === 1 ? lan.index.test_version : lan.index.final_version) + rdata.version + '</a></br>'+lan.index.update_date + (result.msg.is_beta == 1 ? result.msg.beta.uptime : result.msg.uptime) + '</div>\
|
||||
<div class="update_version">'+lan.index.last_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_version_log+'">'+lan.index.bt_linux+ (is_beta === 1 ? lan.index.test_version : lan.index.final_version) +' '+ rdata.version + '</a></br>'+lan.index.update_date + (result.msg.is_beta == 1 ? result.msg.beta.uptime : result.msg.uptime) + '</div>\
|
||||
<div class="update_logs">'+ rdata.updateMsg + '</div>\
|
||||
</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) + ' '+lan.index.update_time+' ' + (is_beta != 1 ? result.msg.beta.uptime : result.msg.uptime) + '</div>\
|
||||
<div class="update_tips">'+ lan.index.last_version_is +(is_beta !== 1 ? lan.index.test_version : lan.index.final_version) + (result.msg.is_beta != 1 ? result.msg.beta.version : result.msg.version) + ' '+lan.index.update_time+' ' + (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>\
|
||||
<div class="bt-form-submit-btn">\
|
||||
@@ -1068,6 +1095,7 @@ var index = {
|
||||
}, 100)
|
||||
},
|
||||
open_log: function () {
|
||||
return
|
||||
bt.open({
|
||||
type: 1,
|
||||
area: '640px',
|
||||
@@ -1077,7 +1105,7 @@ var index = {
|
||||
shadeClose: false,
|
||||
content: '<div class="DrawRecordCon"></div>'
|
||||
});
|
||||
$.get('https://www.bt.cn/Api/getUpdateLogs?type=' + bt.os, function (rdata) {
|
||||
$.get('https://www.bt.cn/api/panel/updateLinuxEn', function (rdata) {
|
||||
var body = '';
|
||||
for (var i = 0; i < rdata.length; i++) {
|
||||
body += '<div class="DrawRecord DrawRecordlist">\
|
||||
@@ -1244,7 +1272,7 @@ var index = {
|
||||
break;
|
||||
case 1:
|
||||
if(data.type != 'ignore'){
|
||||
bt.confirm({title:'Ignore risk',msg:'Confirm to ignore【'+ data.title +'】risk?'},function(){
|
||||
bt.confirm({title:'Ignore risk',msg:'Confirm to ignore [ '+ data.title +' ] risk?'},function(){
|
||||
that.warning_set_ignore(data.model,function(res){
|
||||
that.get_warning_list(false,function(){
|
||||
bt.msg(res)
|
||||
@@ -1309,7 +1337,74 @@ var index = {
|
||||
if(callback) callback(res);
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @description 获取当前的产品状态
|
||||
*/
|
||||
get_product_status: function (callback) {
|
||||
// var loadT = layer.msg('正在获取产品状态,请稍候...', { icon: 16, time: 0 })
|
||||
bt.send('get_pd', 'ajax/get_pd', {}, function (res) {
|
||||
$('.btpro-gray').replaceWith($(res[0]));
|
||||
bt.set_cookie('pro_end', res[1]);
|
||||
bt.set_cookie('ltd_end', res[2]);
|
||||
if(res[1] === 0){
|
||||
$(".btpro span").click(function(e){
|
||||
layer.confirm('切换回免费版可通过解绑账号实现', { icon: 3, btn: ['解绑账号'], closeBtn: 2, title: '是否取消授权' }, function () {
|
||||
$.post('/ssl?action=DelToken', {}, function (rdata) {
|
||||
layer.msg(rdata.msg);
|
||||
setTimeout(function () {
|
||||
window.location.reload();
|
||||
},2000);
|
||||
});
|
||||
});
|
||||
e.stopPropagation();
|
||||
});
|
||||
}
|
||||
if(callback) callback();
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @description 推荐进阶版产品
|
||||
*/
|
||||
recommend_paid_version: function () {
|
||||
try {
|
||||
var recomConfig = product_recommend.get_recommend_type(0)
|
||||
var pay_status = product_recommend.get_pay_status()
|
||||
var is_pay = pay_status.is_pay;
|
||||
var advanced = pay_status.advanced;
|
||||
var end_time = pay_status.end_time;
|
||||
var html = '',list_html = '';
|
||||
if(!is_pay) advanced = ''; //未购买的时候,使用推荐内容
|
||||
if(recomConfig){
|
||||
var item = recomConfig;
|
||||
for (let j = 0; j < item['ps'].length; j++) {
|
||||
const element = item['ps'][j];
|
||||
list_html += '<div class="item">'+ element +'</div>';
|
||||
}
|
||||
var pay_html = '';
|
||||
if(is_pay){
|
||||
pay_html = '<div class="product-buy '+ (advanced || item.name) +'-type">Expired: <span>'+ (end_time === 0?'Lifetime':(end_time === -2?'Expired':bt.format_data(end_time,'yyyy-MM-dd')) + ' <a class="btlink" href="javascript:;" onclick="product_recommend.pay_product_sign(\''+ advanced +'\','+ item.pay +')">Renew</a>') +'</span></div>'
|
||||
}else{
|
||||
pay_html = '<div class="product-buy"><button type="button" class="btn btn-xs btn-success" onclick="product_recommend.pay_product_sign(\''+ (advanced || item.name) +'\','+ item.pay +')">Buy now</button></div>'
|
||||
}
|
||||
html = '<div class="conter-box bgw">\
|
||||
<div class="recommend-top pd15 '+ (is_pay?( advanced +'-bg'):'') +'">'+ (!is_pay?pay_html:'') +'<div class="product-ico '+ (advanced || item.name) +''+ (!is_pay?'-pay':'') +'-ico"></div>' + (is_pay?pay_html:'') +'\
|
||||
<div class="product-label">'+ list_html +'</div>\
|
||||
</div>\
|
||||
</div>'
|
||||
$('#home-recommend').html(html)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
index.get_init();
|
||||
//setTimeout(function () { index.get_cloud_list() }, 800);
|
||||
//setTimeout(function () { index.get_cloud_list() }, 800);
|
||||
|
||||
product_recommend.init(function(){
|
||||
index.get_product_status(function(){
|
||||
index.recommend_paid_version()
|
||||
});
|
||||
index.get_index_list();
|
||||
})
|
||||
@@ -334,13 +334,13 @@ var aceEditor = {
|
||||
title: lan.public.history_version + '[ ' + _item.fileName + ' ]',
|
||||
skin: 'historys_layer',
|
||||
content: '<div class="pd20">\
|
||||
<div class="divtable">\
|
||||
<table class="historys table table-hover">\
|
||||
<thead><tr><th>' + lan.public.file_name + '</th><th>' + lan.public.v_time + '</th><th style="text-align:right;">' + lan.public.operate + '</th></tr></thead>\
|
||||
<tbody></tbody>\
|
||||
</table>\
|
||||
</div>\
|
||||
</div>',
|
||||
<div class="divtable" style="overflow:auto;height:450px; border: 1px solid #ddd;">\
|
||||
<table class="historys table table-hover" id="historys-table" style="border: none;">\
|
||||
<thead><tr><th>' + lan.public.file_name + '</th><th>' + lan.public.v_time + '</th><th style="text-align:right;">' + lan.public.operate + '</th></tr></thead>\
|
||||
<tbody></tbody>\
|
||||
</table>\
|
||||
</div>\
|
||||
</div>',
|
||||
success: function(layeo, index) {
|
||||
var _html = '';
|
||||
for (var i = 0; i < _item.historys.length; i++) {
|
||||
@@ -360,6 +360,7 @@ var aceEditor = {
|
||||
$('.recovery_file_historys').click(function() {
|
||||
_this.event_ecovery_file(this);
|
||||
});
|
||||
bt.fixed_table('historys-table');
|
||||
}
|
||||
});
|
||||
break;
|
||||
@@ -2963,7 +2964,9 @@ function loadScript(arry, param, callback) {
|
||||
var ready = 0;
|
||||
if (typeof param === 'function') callback = param
|
||||
for (var i = 0; i < arry.length; i++) {
|
||||
if (!Array.isArray(bt['loadScript'])) bt['loadScript'] = []
|
||||
if (!Array.isArray(bt['loadScript'])) {
|
||||
bt['loadScript'] = []
|
||||
}
|
||||
if (!is_file_existence(arry[i], true)) {
|
||||
if ((arry.length - 1) === i && callback) callback();
|
||||
continue;
|
||||
@@ -2986,6 +2989,7 @@ function loadScript(arry, param, callback) {
|
||||
} else {
|
||||
(function(i) {
|
||||
script.onload = function() {
|
||||
if (!bt['loadScript']) bt['loadScript'] = [];
|
||||
bt['loadScript'].push(arry[i]);
|
||||
ready++;
|
||||
};
|
||||
@@ -3667,7 +3671,7 @@ function bindBTPanel(a, type, ip, btid, url, user, pw) {
|
||||
var gurl = "/config?action=AddPanelInfo";
|
||||
var btaddress = $("#btaddress").val();
|
||||
if (!btaddress.match(/^(http|https)+:\/\/([\w-]+\.)+[\w-]+:\d+/)) {
|
||||
layer.msg(lan.bt.panel_err_format + '<p>http://192.168.0.1:7800</p>', { icon: 5, time: 5000 });
|
||||
layer.msg(lan.bt.panel_err_format + '<p>http://192.168.0.1:8888</p>', { icon: 5, time: 5000 });
|
||||
return;
|
||||
}
|
||||
var btuser = encodeURIComponent($("#btuser").val());
|
||||
@@ -3774,7 +3778,10 @@ function messagebox(){
|
||||
'<p>'+lan.public.exec_log+'</p>' +
|
||||
'</div>' +
|
||||
'<div class="bt-w-con pd15">' +
|
||||
'<div class="bt-w-item active" id="command_install_list"><ul class="cmdlist"></ul></div>'+
|
||||
'<div class="bt-w-item active" id="command_install_list">\
|
||||
<ul class="cmdlist"></ul>\
|
||||
<div style="position: fixed;bottom: 15px;">' + lan.public.task_long_time_not_exec + '</div>\
|
||||
</div>'+
|
||||
'<div class="bt-w-item" id="messageContent"></div>'+
|
||||
'<div class="bt-w-item"><pre id="execLog" class="command_output_pre" style="height: 530px;"></pre></div>'+
|
||||
'</div>' +
|
||||
@@ -3797,7 +3804,7 @@ function messagebox(){
|
||||
bt.send('GetExecLog','files/GetExecLog',{},function(res){
|
||||
loadT.close();
|
||||
var exec_log = $('#execLog');
|
||||
console.log(exec_log)
|
||||
// console.log(exec_log)
|
||||
exec_log.html(res)
|
||||
exec_log[0].scrollTop = exec_log[0].scrollHeight
|
||||
})
|
||||
@@ -3873,43 +3880,48 @@ function reader_realtime_tasks(refresh){
|
||||
html = '',
|
||||
message = res.msg,
|
||||
task = res.task;
|
||||
$('#taskNum').html(typeof res.task === "undefined"?0:res.task.length);
|
||||
$('#taskNum').html(typeof res.task === "undefined" ? 0 : res.task.length);
|
||||
if(typeof res.task === "undefined"){
|
||||
html = '<div style="padding:5px;">'+lan.bt.task_not_list+'</div><div style="position: fixed;bottom: 15px;">' + lan.public.task_long_time_not_exec + '</div>'
|
||||
|
||||
command_install_list.html(html)
|
||||
}else{
|
||||
var shell = '', message_split = message.split("\n");
|
||||
var del_task = '<a style="color:green" onclick="RemoveTask($id)" href="javascript:;">'+ lan.public.del +'</a>',loading_img = "<img src='"+ loading +"'/>";
|
||||
for(var j = 0; j < message_split.length; j++) {
|
||||
shell += message_split[j] + "</br>";
|
||||
}
|
||||
if(command_install_list.find('li').length){
|
||||
if(command_install_list.find('li').length > res.task.length) command_install_list.find('li:eq(0)').remove();
|
||||
if(task[0].status !== '0' && !command_install_list.find('pre').length) command_install_list.find('li:eq(0)').append('<pre class=\'cmd command_output_pre\'>' + shell +'</pre>')
|
||||
messageBoxWssock.el = command_install_list.find('pre');
|
||||
}else{
|
||||
for (var i = 0; i < task.length; i++) {
|
||||
var item = task[i], task_html = '', del_task = '<a style="color:green" onclick="RemoveTask(' + item.id + ')" href="javascript:;">'+ lan.public.del +'</a>',loading_img = "<img src='"+ loading +"'/>";
|
||||
if(item.status === '-1' && item.type === 'download'){
|
||||
task_html = "<div class='line-progress' style='width:" + message.pre + "%'></div><span class='titlename'>" + item.name + "<a style='margin-left:130px;'>" + (ToSize(message.used) + "/" + ToSize(message.total)) + "</a></span><span class='com-progress'>" + message.pre + "%</span><span class='state'>"+ lan.bt.task_downloading +" "+ loading_img +" | "+ del_task +"</span>";
|
||||
}else{
|
||||
task_html += '<span class="titlename">' + item.name + '</span>';
|
||||
task_html += '<span class="state">';
|
||||
if(item.status !== "-1"){
|
||||
task_html += lan.bt.task_sleep + ' | ' + del_task;
|
||||
}else{
|
||||
var is_scan = item.name.indexOf("扫描") !== -1;
|
||||
task_html += (is_scan?lan.bt.task_scan:lan.bt.task_install) + ' ' + loading_img + ' | ' + del_task;
|
||||
}
|
||||
task_html += "</span>";
|
||||
if(item.type !== "download" && item.status === "-1"){
|
||||
task_html += '<pre class=\'cmd command_output_pre\'>' + shell +'</pre>'
|
||||
}
|
||||
// if(command_install_list.find('li').length){
|
||||
// if(command_install_list.find('li').length > res.task.length) command_install_list.find('li:eq(0)').remove();
|
||||
// if(task[0].status !== '0' && !command_install_list.find('pre').length) command_install_list.find('li:eq(0)').append('<pre class=\'cmd command_output_pre\'>' + shell +'</pre>')
|
||||
// messageBoxWssock.el = command_install_list.find('pre');
|
||||
// }else{
|
||||
for (var i = 0; i < task.length; i++) {
|
||||
var item = task[i], task_html = '';
|
||||
if(item.status === '-1' && item.type === 'download'){
|
||||
task_html = "<div class='line-progress' style='width:" + message.pre + "%'></div><span class='titlename'>" + item.name + "<a style='margin-left:130px;'>" + (ToSize(message.used) + "/" + ToSize(message.total)) + "</a></span><span class='com-progress'>" + message.pre + "%</span><span class='state'>"+ lan.bt.task_downloading +" "+ loading_img +" | "+ del_task.replace('$id', item.id) +"</span>";
|
||||
}else{
|
||||
task_html += '<span class="titlename">' + item.name + '</span>';
|
||||
task_html += '<span class="state">';
|
||||
switch(item.status){
|
||||
case '0':
|
||||
task_html += lan.bt.task_sleep + ' | ' + del_task.replace('$id', item.id);
|
||||
break
|
||||
case '-1':
|
||||
var is_scan = item.name.indexOf("扫描") !== -1;
|
||||
task_html += (is_scan ? lan.bt.task_scan : lan.bt.task_install) + ' ' + loading_img + ' | ' + del_task.replace('$id', item.id);
|
||||
break
|
||||
}
|
||||
task_html += "</span>";
|
||||
if(item.type !== "download" && item.status === "-1"){
|
||||
task_html += '<pre class=\'cmd command_output_pre\'>' + shell +'</pre>'
|
||||
}
|
||||
html += "<li>"+ task_html +"</li>";
|
||||
}
|
||||
command_install_list.find('ul').append(html);
|
||||
html += "<li>"+ task_html +"</li>";
|
||||
}
|
||||
if(task[0].status === '0'){
|
||||
command_install_list.find('ul').html(html);
|
||||
// }
|
||||
if(task.length > 0 && task[0].status === '0'){
|
||||
setTimeout(function(){
|
||||
reader_realtime_tasks(true)
|
||||
},100)
|
||||
@@ -5188,4 +5200,148 @@ var MessageChannel = {
|
||||
})
|
||||
}
|
||||
}
|
||||
/** 消息通道 end**/
|
||||
/** 消息通道 end**/
|
||||
var product_recommend = {
|
||||
data:null,
|
||||
/**
|
||||
* @description 初始化
|
||||
*/
|
||||
init:function(callback){
|
||||
var _this = this;
|
||||
if(location.pathname.indexOf('bind') > -1) return;
|
||||
this.get_product_type(function (rdata) {
|
||||
_this.data = rdata
|
||||
if(callback) callback(rdata)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @description 获取推荐类型
|
||||
* @param {object} type 参数{type:类型}
|
||||
*/
|
||||
get_recommend_type:function(type){
|
||||
var config = null,pathname = location.pathname.replace('/','') || 'home';
|
||||
for (var i = 0; i < this.data.length; i++) {
|
||||
var item = this.data[i];
|
||||
if(item.type == type && item.show) config = item
|
||||
}
|
||||
return config
|
||||
},
|
||||
|
||||
/**
|
||||
* @description 或指定版本事件
|
||||
* @param {} name
|
||||
*/
|
||||
get_version_event:function (item,param) {
|
||||
var pay_status = this.get_pay_status();
|
||||
bt.soft.get_soft_find(item.name,function(res){
|
||||
if((res.type === 12 && pay_status.is_pay && pay_status.advanced !== 'ltd') || !pay_status.is_pay){
|
||||
product_recommend.recommend_product_view(item)
|
||||
}else if(!res.setup){
|
||||
bt.soft.install(item.name)
|
||||
}else{
|
||||
bt.plugin.get_plugin_byhtml(item.name,function(html){
|
||||
if(typeof html === "string"){
|
||||
layer.open({
|
||||
type:1,
|
||||
shade:0,
|
||||
skin:'hide',
|
||||
content:html,
|
||||
success:function(){
|
||||
var is_event = false;
|
||||
for (var i = 0; i < item.eventList.length; i++) {
|
||||
var data = item.eventList[i];
|
||||
var oldVersion = data.version.replace('.',''),newVersion = res.version.replace('.','');
|
||||
if(newVersion <= oldVersion){
|
||||
is_event = true
|
||||
setTimeout(function () {
|
||||
new Function(data.event.replace('$siteName',param))()
|
||||
},100)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!is_event) new Function(item.eventList[item.eventList.length - 1].event.replace('$siteName',param))()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @description 获取支付状态
|
||||
*/
|
||||
get_pay_status:function(){
|
||||
var pro_end = parseInt(bt.get_cookie('pro_end') || -1);
|
||||
var ltd_end = parseInt(bt.get_cookie('ltd_end') || -1);
|
||||
var is_pay = pro_end > -1 || ltd_end > -1; // 是否购买付费版本
|
||||
var advanced = 'pro'; // 已购买,专业版优先显示
|
||||
if(pro_end === -2 || pro_end > -1) advanced = 'pro';
|
||||
if(ltd_end === -2 || ltd_end > -1) advanced = 'ltd';
|
||||
var end_time = advanced === 'ltd'? ltd_end:pro_end; // 到期时间
|
||||
return { advanced: advanced, is_pay:is_pay, end_time:end_time };
|
||||
},
|
||||
|
||||
pay_product_sign:function (type,source) {
|
||||
switch (type) {
|
||||
case 'pro':
|
||||
bt.soft['updata_' + type](source);
|
||||
break;
|
||||
case 'ltd':
|
||||
bt.soft['updata_' + type](false, source);
|
||||
break;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @description 获取项目类型
|
||||
* @param {Function} callback 回调函数
|
||||
*/
|
||||
get_product_type:function(callback){
|
||||
bt.send('get_pay_type','ajax/get_pay_type',{},function(rdata){
|
||||
bt.set_storage('session','get_pay_type',JSON.stringify(rdata))
|
||||
if(callback) callback(rdata)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @description 推荐购买产品
|
||||
* @param {Object} pay_id 购买的入口id
|
||||
*/
|
||||
recommend_product_view: function (config) {
|
||||
var name = config.name.split('_')[0];
|
||||
var status = this.get_pay_status();
|
||||
console.log(status);
|
||||
bt.open({
|
||||
title:false,
|
||||
area:'650px',
|
||||
btn:false,
|
||||
content:'<div class="ptb15" style="display: flex;">\
|
||||
<div class="product_view"><img src="/static/images/recommend/'+ name +'.png"/></div>\
|
||||
<div class="product_describe ml10">\
|
||||
<div class="describe_title">'+ config.pluginName +'</div>\
|
||||
<div class="describe_ps">'+ config.ps +'</div>\
|
||||
<div class="product_describe_btn">\
|
||||
<a class="btn btn-default mr10 btn-sm productPreview '+ (!config.preview?'hide':'') +'" href="'+ config.preview +'" target="_blank">产品预览</a><button class="btn btn-success btn-sm buyNow">立即购买</button>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>',
|
||||
success:function () {
|
||||
// 产品预览
|
||||
$('.product_view img').click(function () {
|
||||
layer.open({
|
||||
type:1,
|
||||
title:'查看图片',
|
||||
area:['650px','450px'],
|
||||
closeBtn:2,
|
||||
btn:false,
|
||||
content:'<img src="/static/images/recommend/'+ name +'.png" style="width:100%" />'
|
||||
})
|
||||
})
|
||||
// 立即购买
|
||||
$('.buyNow').click(function(){
|
||||
bt.set_cookie('pay_source',config.pay)
|
||||
bt.soft['updata_' + status.advanced]()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ var soft = {
|
||||
// } 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);
|
||||
soft.set_soft_tips(rdata,type);
|
||||
|
||||
// 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>')
|
||||
@@ -317,17 +317,27 @@ var soft = {
|
||||
if (item.endtime < 0 && item.pid > 0) {
|
||||
var re_msg = '';
|
||||
var re_status = 0;
|
||||
var buy_type = 0;
|
||||
switch (item.endtime) {
|
||||
case -1:
|
||||
re_msg = lan.soft.buy_now;
|
||||
buy_type = 31;
|
||||
break;
|
||||
case -2:
|
||||
re_msg = lan.soft.renew_now;
|
||||
re_status = 1;
|
||||
buy_type = 32;
|
||||
break;
|
||||
}
|
||||
if (item.type != 10) {
|
||||
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>';
|
||||
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,
|
||||
totalNum:buy_type
|
||||
}) +')\'>' + 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>';
|
||||
}
|
||||
@@ -530,8 +540,12 @@ var soft = {
|
||||
});
|
||||
}
|
||||
},
|
||||
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'),_this = this;
|
||||
set_soft_tips:function(rdata,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'),
|
||||
_this = this,
|
||||
el = '#updata_pro_info';
|
||||
$(el).empty()
|
||||
type = parseInt(type);
|
||||
if(type != 11) $(el).next('.onekey-menu-sub').remove();
|
||||
@@ -558,6 +572,16 @@ var soft = {
|
||||
]);
|
||||
$(el).append(tips_info.addClass('alert-info'));
|
||||
}else{
|
||||
var genre = true,
|
||||
is_buy = false
|
||||
if (rdata.ltd > 0 || type === 12) {
|
||||
genre = false
|
||||
} else if (rdata.pro >= 0 || type === 8) {
|
||||
genre = true
|
||||
}
|
||||
if (rdata.ltd > 0 || rdata.pro >= 0) is_buy = true
|
||||
if (type === 12 && rdata.ltd < 0) is_buy = false
|
||||
var buy_type = is_buy?30:29
|
||||
var ltd = parseInt(bt.get_cookie('ltd_end') || -1),pro = parseInt(bt.get_cookie('pro_end') || -1),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;
|
||||
@@ -589,29 +613,28 @@ var soft = {
|
||||
$(el).append(tips_info.addClass('alert-ltd-success'));
|
||||
return false;
|
||||
}else{
|
||||
if(pro < 0){
|
||||
fun = bt.soft.updata_pro
|
||||
}else{
|
||||
fun = bt.soft.renew_pro
|
||||
}
|
||||
$.extend(btn_config,{title:_ltd == null?'Upgrade now':'Renew Now',btn:_ltd == null?'Upgrade now':'Renew Now',click:fun})
|
||||
}
|
||||
}
|
||||
if(_ltd != 2){
|
||||
if(!(pro == 0 && ltd < 0)){
|
||||
btn_ground = soft.render_tips_btn(btn_ground,btn_config);
|
||||
var btn = $('<a title="' + (is_buy ? 'Renew Now' : 'Upgrade now') + '" href="javascript:;" class="btn btn-success btn-xs va0 ml15" style="margin-left:10px;">' + (is_buy ? 'Renew Now' : 'Upgrade now') + '</a>')
|
||||
btn.on('click', function () {
|
||||
genre ? bt.soft.updata_pro(buy_type) : bt.soft.updata_ltd(undefined,buy_type)
|
||||
})
|
||||
tips_info.addClass('showprofun').find('.btn-ground').append(btn)
|
||||
}
|
||||
}
|
||||
// if(_ltd != 2){
|
||||
// if(!(pro == 0 && ltd < 0)){
|
||||
// btn_ground = soft.render_tips_btn(btn_ground);
|
||||
// }
|
||||
// }
|
||||
$(el).append(tips_info.addClass(_ltd == 1?'alert-ltd-success':'alert-success'));
|
||||
if(_this.trail){
|
||||
setTimeout(function (){
|
||||
$('.btn-ground').after('<span class="pro_trail" style="font-weight: 700;margin-left:25px;">Try the Pro edition for free for 15 days</span>')
|
||||
$('.btn-ground').after('<span class="pro_trail" style="font-weight: 700;margin-left:25px;">Try the Pro edition for free</span>')
|
||||
var trail = $('<a href="javascript:;" class="btn btn-success btn-xs va0 ml15" style="margin-left:10px;">Click to try</a>');
|
||||
trail.click((!res.status || !res)?fun:function(){
|
||||
var loadT = bt.load()
|
||||
bt.confirm({
|
||||
title:"Pro Edition",
|
||||
msg:"Get 15-day Pro edition free, get it now?"
|
||||
msg:"Get 7-day Pro edition free, get it now?"
|
||||
},function (){
|
||||
bt.send('free_trial','auth/free_trial',{},function(res){
|
||||
loadT.close()
|
||||
@@ -693,6 +716,7 @@ var soft = {
|
||||
$.post('/deployment?action=GetList', pdata, function(rdata) {
|
||||
layer.close(loadT)
|
||||
var tBody = '';
|
||||
soft.set_soft_tips(rdata, 11);
|
||||
rdata.type.unshift({
|
||||
icon: 'icon',
|
||||
id: 0,
|
||||
@@ -2799,6 +2823,9 @@ var soft = {
|
||||
}, function(rdata) {
|
||||
loading.close();
|
||||
bt.msg(rdata);
|
||||
setTimeout(function () {
|
||||
location.reload();
|
||||
}, 1000);
|
||||
})
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -339,11 +339,11 @@ var host_trem = {
|
||||
}
|
||||
that.editor_host_view({
|
||||
form:rdata,
|
||||
config: {btn: 'Save', title: 'Edit server information 【'+ host +'】'}
|
||||
config: {btn: 'Save', title: 'Edit server information [ '+ host +' ]'}
|
||||
});
|
||||
});
|
||||
}else{
|
||||
bt.confirm({title:'Delete information',msg:'Delete service information 【'+ host +'】, continue?',icon:0},function(index){
|
||||
bt.confirm({title:'Delete information',msg:'Delete service information [ '+ host +' ], continue?',icon:0},function(index){
|
||||
that.remove_host(host,function(rdata){
|
||||
layer.close(index);
|
||||
that.reader_host_list(function(){
|
||||
@@ -560,10 +560,12 @@ var host_trem = {
|
||||
case 0:
|
||||
$('.c_password_view').addClass('show').removeClass('hidden');
|
||||
$('.c_pkey_view').addClass('hidden').removeClass('show').find('input').val('');
|
||||
$('.key_pwd_line').addClass('hidden').removeClass('show');
|
||||
break;
|
||||
case 1:
|
||||
$('.c_password_view').addClass('hidden').removeClass('show').find('input').val('');
|
||||
$('.c_pkey_view').addClass('show').removeClass('hidden');
|
||||
$('.key_pwd_line').addClass('show').removeClass('hidden');
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -652,30 +654,39 @@ var host_trem = {
|
||||
*/
|
||||
editor_host_view:function(obj){
|
||||
var that = this;
|
||||
if (!obj) obj = {form: this.host_form, config: {btn: 'Submit', title: 'Add host information'}}
|
||||
if (!obj) {
|
||||
obj = {
|
||||
form: this.host_form,
|
||||
config: {
|
||||
btn: 'Submit', title: 'Add host information'
|
||||
}
|
||||
}
|
||||
}
|
||||
this.render_template({
|
||||
html: host_form_view.innerHTML,
|
||||
data: obj
|
||||
}, function (html) {
|
||||
layer.open({
|
||||
type: 1 //Page层类型
|
||||
,area: '510px'
|
||||
,closeBtn: 2
|
||||
,title: obj.config.title
|
||||
,btn: [obj.config.btn, 'Cancel']
|
||||
,content: html
|
||||
,success: function (layers, index){
|
||||
$('.auth_type_checkbox').click(function(){
|
||||
, area: '510px'
|
||||
, closeBtn: 2
|
||||
, title: obj.config.title
|
||||
, btn: [obj.config.btn, 'Cancel']
|
||||
, content: html
|
||||
, success: function (layers, index) {
|
||||
$('.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){
|
||||
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');
|
||||
$('.key_pwd_line').addClass('hidden').removeClass('show');
|
||||
break;
|
||||
case 1:
|
||||
$('.c_password_view').addClass('hidden').removeClass('show').find('input').val('');
|
||||
$('.c_pkey_view').addClass('show').removeClass('hidden');
|
||||
$('.key_pwd_line').addClass('show').removeClass('hidden');
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -791,30 +802,37 @@ var host_trem = {
|
||||
* @name 常用信息添加或编辑
|
||||
* @author chudong<2020-08-10>
|
||||
* @param {Objeact} obj 需要编辑的form数据,可以为空,为空则添加
|
||||
* @return void
|
||||
*/
|
||||
editor_command_view:function(obj){
|
||||
* @return void
|
||||
*/
|
||||
editor_command_view: function (obj) {
|
||||
var that = this;
|
||||
if (!obj) obj = {form: this.command_form, config: {btn: 'Submit', title: 'Add command information'}};
|
||||
if (!obj) {
|
||||
obj = {
|
||||
form: this.command_form,
|
||||
config: {
|
||||
btn: 'Submit', title: 'Add command information'
|
||||
}
|
||||
};
|
||||
}
|
||||
this.render_template({
|
||||
html: shell_form_view.innerHTML,
|
||||
data: obj
|
||||
}, function (html) {
|
||||
layer.open({
|
||||
type: 1 //Page层类型
|
||||
,area: '510px'
|
||||
,closeBtn: 2
|
||||
,title: obj.config.title
|
||||
,btn: [obj.config.btn, 'Cancel']
|
||||
,content: html
|
||||
,yes: function (indexs,layero){
|
||||
var shell = $('[name="shell"]').val(),title = $('[name="title"]').val();
|
||||
if(title == ''){
|
||||
bt.msg({status:false,msg:'Command description cannot be empty!'});
|
||||
, area: '510px'
|
||||
, closeBtn: 2
|
||||
, title: obj.config.title
|
||||
, btn: [obj.config.btn, 'Cancel']
|
||||
, content: html
|
||||
, yes: function (indexs, layero) {
|
||||
var shell = $('[name="shell"]').val(), title = $('[name="title"]').val();
|
||||
if (title == '') {
|
||||
bt.msg({status: false, msg: 'Command description cannot be empty!'});
|
||||
return false;
|
||||
}
|
||||
if(shell == ''){
|
||||
bt.msg({status:false,msg:'Command cannot be empty!'});
|
||||
if (shell == '') {
|
||||
bt.msg({status: false, msg: 'Command cannot be empty!'});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ var lan = {
|
||||
if(!msgs[key]) return '';
|
||||
msg = msgs[key];
|
||||
for(var i=0;i<args.length;i++){
|
||||
console.log('test',args[i])
|
||||
// console.log('test',args[i])
|
||||
msg = msg.replace('{'+(i+1)+'}',args[i]+'');
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ var lan = {
|
||||
"process_user":"User",
|
||||
"process_act":"Action",
|
||||
"kill_msg":"Killing this process...",
|
||||
"rep_panel_msg":"Will try to verify and repair the panel program, continue?",
|
||||
"rep_panel_msg":"Verify and repair the panel, continue?",
|
||||
"rep_panel_title":"Repair panel",
|
||||
"rep_panel_the":"Verifying module...",
|
||||
"rep_panel_ok":"Repair completed, please press Ctrl+F5 to refresh the cache!",
|
||||
@@ -128,7 +128,7 @@ var lan = {
|
||||
"available":"Available",
|
||||
"inode_percent":"Inode usage",
|
||||
"test_version":"Beta",
|
||||
"final_version":"Stable",
|
||||
"final_version":"Stable ",
|
||||
"update_version":"Version update",
|
||||
"last_version_now":"Congratulations, it is currently the latest version",
|
||||
"this_version":"Current version: ",
|
||||
@@ -136,10 +136,10 @@ var lan = {
|
||||
"bt_linux":"aaPanel Linux",
|
||||
"release_time":"Release time: ",
|
||||
"last_version_is":"The latest version is ",
|
||||
"update_time":"Update time",
|
||||
"update_time":"Release: ",
|
||||
"update_verison_click":"If you need update to beta version, please click ",
|
||||
"check_detail":"details",
|
||||
"change_final_click":"If you need to switch back to the stable version, please click",
|
||||
"change_final_click":"",
|
||||
"change_final":"Switch to the stable version",
|
||||
"have_new_version":"New panel version available",
|
||||
"last_version":"Latest version: ",
|
||||
@@ -173,7 +173,7 @@ var lan = {
|
||||
"config":{
|
||||
"modify_time":"Modified time",
|
||||
"select_fileordir":"Select File/Dir",
|
||||
"close_panel_msg":"Disabling Panel will make the panel not accessible, are you sure to disable panel service? ",
|
||||
"close_panel_msg":"Close Panel will make the panel not accessible! Are you sure?",
|
||||
"close_panel_title":"Disable Panel",
|
||||
"config_save":"Saving configuration...",
|
||||
"config_sync":"Syncing time...",
|
||||
@@ -247,9 +247,28 @@ var lan = {
|
||||
"not_modified":"Please leave blank if not modified",
|
||||
"set_username":"Please set the username",
|
||||
"set_passwd":"Please set the password",
|
||||
"basic_auth_tips1":"Note: Please do not use your usual password here, which may lead to password leakage!",
|
||||
"basic_auth_tips2":"After opening, access the panel in any way, you will be asked to enter the BasicAuth username and password first.",
|
||||
"basic_auth_tips3":"After being turned on, it can effectively prevent the panel from being scanned and found, but it cannot replace the account password of the panel itself."
|
||||
"basic_auth_tips1":"Note: Please do not use your usual password here!",
|
||||
"basic_auth_tips2":"Access the panel in any way, you need to enter the BasicAuth info!",
|
||||
"basic_auth_tips3":"It can effectively prevent the panel from being scanned and found,but cannot replace the panel login info",
|
||||
"know_risk":"You must use and understand this feature to decide if you want to open it!",
|
||||
"basic_auth_desc1": "After open, access the panel in any way, you need enter the BasicAuth username and password.",
|
||||
"basic_auth_desc2": "It can effectively prevent the panel from being scanned and found.",
|
||||
"basic_auth_desc3": "You must record the account password you set.",
|
||||
"basic_auth_desc4": "If you forget your password, you can disable BasicAuth using the [bt] command in SSH.",
|
||||
"panel_entrance_err": "Set the response status when unauthenticated",
|
||||
"response": "Response",
|
||||
"response_msg1":"security entry error",
|
||||
"response_desc":"Response when not logged in and not properly entered for security entry, used to hide panel features",
|
||||
"open_strong_password": "Open strong password",
|
||||
"close_strong_password": "Close strong password",
|
||||
"strong_password_desc1":"After the strong password is enabled, the complexity of the password will be judged. rule: ",
|
||||
"strong_password_desc2":"Length 8, upper and lower case letters, numbers and characters exist",
|
||||
"strong_password_desc3":"When Strong Password is turned off, password login will no longer verify password complexity",
|
||||
"not_set":"Not set",
|
||||
"set_password_expiration_time":"Set password expiration time",
|
||||
"expire_password_desc1":"Need to reset password after expiration",
|
||||
"expire_password_desc2":"When set to 0, it means to disable this function",
|
||||
"expire_time":"Expire time"
|
||||
},
|
||||
"control":{
|
||||
"save_day_err":"Number of saving day is illegal!",
|
||||
@@ -265,7 +284,9 @@ var lan = {
|
||||
"m5":"5 min",
|
||||
"m15":"15 min",
|
||||
"resource_usage":"Resource usage %",
|
||||
"load_detail":"Load details"
|
||||
"load_detail":"Load details",
|
||||
"disk_rw_count": "r/w times",
|
||||
"disk_rw_time": "r/w wait"
|
||||
},
|
||||
"crontab":{
|
||||
"task_log_title": "Cron Job Running Log",
|
||||
@@ -699,7 +720,7 @@ var lan = {
|
||||
"empty":"Currently no FTP data",
|
||||
"stop_title":"Deactivate this user",
|
||||
"start_title":"Activate this user",
|
||||
"stop":"Deactivated",
|
||||
"stop":"Stopped",
|
||||
"start":"Activated",
|
||||
"copy":"Copy password",
|
||||
"open_path":"Open directory",
|
||||
@@ -720,7 +741,7 @@ var lan = {
|
||||
"add_ps_title":"Note info (Less than 255 characters)",
|
||||
"del_all":"Batch delete selected FTP users?",
|
||||
"del_all_err":"The following FTP users deletion failed:",
|
||||
"stop_confirm":"Do you want to deactivate FTP of {1}?",
|
||||
"stop_confirm":"Do you want to close FTP of {1}?",
|
||||
"pass_title":"Change FTP User Password",
|
||||
"pass_user":"Username",
|
||||
"pass_new":"New password",
|
||||
@@ -734,20 +755,26 @@ var lan = {
|
||||
"ftp_user":"FTP User",
|
||||
"operate":"Operation",
|
||||
"change_pass":"Change FTP password",
|
||||
"del":"Del"
|
||||
"del":"Del",
|
||||
"set_path_tips1":"Migrating data is by copying",
|
||||
"set_path_tips3":"Need to manually clean up old data after migration is complete",
|
||||
"set_path_tips2":"If the amount of data is large, manual migration is recommended",
|
||||
"migrate":"Migrate",
|
||||
"change_ftp_user_home":"Change ftp user home"
|
||||
},
|
||||
"database":{
|
||||
"empty":"Currently no databases",
|
||||
"backup_empty":"Not exist",
|
||||
"backup_ok":"Exists",
|
||||
"copy_pass":"Copy password",
|
||||
"input":"Import",
|
||||
"input_title":"Import Database",
|
||||
"admin":"Manager",
|
||||
"admin_title":"Database Manager",
|
||||
"auth":"Permission",
|
||||
"auth_title":"Set access permission",
|
||||
"edit_pass":"CHG PW",
|
||||
"empty": "Currently no databases",
|
||||
"database_search": "Database search",
|
||||
"backup_empty": "Not exist",
|
||||
"backup_ok": "Exists",
|
||||
"copy_pass": "Copy password",
|
||||
"input": "Import",
|
||||
"input_title": "Import Database",
|
||||
"admin": "Manager",
|
||||
"admin_title": "Database Manager",
|
||||
"auth": "Permission",
|
||||
"auth_title": "Set access permission",
|
||||
"edit_pass": "CHG PW",
|
||||
"edit_pass_title":"Change database password",
|
||||
"del_title":"Delete database",
|
||||
"ps":"Note info",
|
||||
@@ -763,27 +790,28 @@ var lan = {
|
||||
"add_auth_ip":"Specific IP",
|
||||
"add_auth_ip_title":"Please input IP authorized to access this database",
|
||||
"add_ps":"Notes",
|
||||
"edit_root":"Root password",
|
||||
"user":"Username",
|
||||
"edit_pass_new":"New password",
|
||||
"edit_pass_new_title":"New database password",
|
||||
"edit_pass_confirm":"Are you sure to change password?",
|
||||
"backup_re":"Restore",
|
||||
"backup_name":"File name",
|
||||
"backup_size":"File size",
|
||||
"backup_time":"Backup time",
|
||||
"backup_title":"Database Backup Details",
|
||||
"backup":"Backup",
|
||||
"input_confirm":"Database will be overwritten, continue?",
|
||||
"input_the":"Importing, please wait...",
|
||||
"backup_the":"Backing up, please wait...",
|
||||
"backup_del_title":"Delete backup file",
|
||||
"backup_del_confirm":"Are you sure to delete backup file?",
|
||||
"del_all_title":"Batch delete databases",
|
||||
"del_all_err":"The following database(s) deletion failed:",
|
||||
"input_title_file":"Import to database from file",
|
||||
"input_local_up":"Upload from local",
|
||||
"input_ps1":"Only support sql, zip, (tar.gz|gz|tgz)",
|
||||
"edit_root": "Root password",
|
||||
"user": "Username",
|
||||
"edit_pass_new": "New password",
|
||||
"edit_pass_new_title": "New database password",
|
||||
"edit_pass_confirm": "Are you sure to change password?",
|
||||
"backup_re": "Repair",
|
||||
"backup_name": "File name",
|
||||
"backup_size": "File size",
|
||||
"backup_time": "Backup time",
|
||||
"backup_title": "Database Backup Details",
|
||||
"backup": "Backup",
|
||||
"position": "Position",
|
||||
"input_confirm": "Database will be overwritten, continue?",
|
||||
"input_the": "Importing, please wait...",
|
||||
"backup_the": "Backing up, please wait...",
|
||||
"backup_del_title": "Delete backup file",
|
||||
"backup_del_confirm": "Are you sure to delete backup file?",
|
||||
"del_all_title": "Batch delete databases",
|
||||
"del_all_err": "The following database(s) deletion failed:",
|
||||
"input_title_file": "Import to database from file",
|
||||
"input_local_up": "Upload from local",
|
||||
"input_ps1": "Only support sql, zip, (tar.gz|gz|tgz)",
|
||||
"input_ps2":"Structure of zip, tar.gz archive: test.sql must be contained in test.zip or test.tar.gz",
|
||||
"input_ps3":"If the file is oversized, you can also upload database archives to /www/backup/database with SFTP tools",
|
||||
"input_up_type":"Please upload sql or zip or tar.gz archives",
|
||||
@@ -807,18 +835,43 @@ var lan = {
|
||||
"db_name":"Database name",
|
||||
"tb_name":"Table name",
|
||||
"engine":"Engine",
|
||||
"character":"Character",
|
||||
"row_num":"Row number",
|
||||
"tb_repair":"[Repair] Try to repair the damaged table with the REPAIR command. You can only do a simple repair. <br> If the repair is not successful, consider using the myisamchk tool.",
|
||||
"tb_optimization":"[Optimize] Execute OPTIMIZE command to recover unreleased disk space. Recommended executing it once a month.",
|
||||
"tb_change_engine":"[Convert to InnoDB/MyISAM] Convert database table engine. Recommended converting all tables to InnoDB",
|
||||
"repair":"Repair",
|
||||
"send_repair_command":"Repair command sent, please wait...",
|
||||
"send_opt_command":"Optimization command sent, please wait...",
|
||||
"send_change_command":"Engine conversion command sent, please wait...",
|
||||
"choose_at_least_one_tb":"Please select at least one table!",
|
||||
"download":"Download"
|
||||
},
|
||||
"character": "Character",
|
||||
"row_num": "Row number",
|
||||
"tb_repair": "[Repair] Try to repair the damaged table with the REPAIR command. You can only do a simple repair. <br> If the repair is not successful, consider using the myisamchk tool.",
|
||||
"tb_optimization": "[Optimize] Execute OPTIMIZE command to recover unreleased disk space. Recommended executing it once a month.",
|
||||
"tb_change_engine": "[Convert to InnoDB/MyISAM] Convert database table engine. Recommended converting all tables to InnoDB",
|
||||
"repair": "Repair",
|
||||
"send_repair_command": "Repair command sent, please wait...",
|
||||
"send_opt_command": "Optimization command sent, please wait...",
|
||||
"send_change_command": "Engine conversion command sent, please wait...",
|
||||
"choose_at_least_one_tb": "Please select at least one table!",
|
||||
"download": "Download",
|
||||
"not_found_pwd_1": "Get passwd failed, click ",
|
||||
"not_found_pwd_2": "reset",
|
||||
"not_found_pwd_3": "",
|
||||
"cloud_server": "Remote DB",
|
||||
"cloud_server_list": "Remote DB list",
|
||||
"cloud_server_empty": "Remove DB list is empty",
|
||||
"server_address": "DB address",
|
||||
"port": "Port",
|
||||
"input_server_address": "Please fill you server address",
|
||||
"input_port": "Database port",
|
||||
"input_username": "Database administrator name",
|
||||
"input_password": "Database administrator password",
|
||||
"server_note": "Server Notes",
|
||||
"remote_help_1": "Compatible with MySQL5.5, MariaDB10.1 and above",
|
||||
"remote_help_2": "Support cloud database",
|
||||
"remote_help_3": "Note 1: Make sure this server has permission to access the database",
|
||||
"remote_help_4": "Note 2: Please make sure that the administrator account you fill in has sufficient permissions",
|
||||
"add_cloud_server_tips": "Connecting to remote server, please wait...",
|
||||
"edit_cloud_server_tips": "Modifying remote server connection information, please wait...",
|
||||
"add_server_tips": "Add at least one remote server or install a local database",
|
||||
"select_position": "Select database location",
|
||||
"cloud_database": "Remote database",
|
||||
"get_cloud_list_tips": "Fetching remote server list, please wait...",
|
||||
"del_cloud_server_tips": "Only delete management information and database records in the panel, not delete remote databases",
|
||||
"del_cloud_database_tips": "The remote database does not support the database recycle bin. After deletion, it cannot be recovered. Please operate with caution!"
|
||||
},
|
||||
"soft":{
|
||||
"php_main1":"PHP service",
|
||||
"php_main2":"Limit of upload",
|
||||
@@ -1129,6 +1182,7 @@ var lan = {
|
||||
"not_rated":"Not rated"
|
||||
},
|
||||
"site":{
|
||||
"website": "Website",
|
||||
"executing":"is being executed, please wait...",
|
||||
"click_edit":"Click to edit content",
|
||||
"have_been_selected":"Selected ",
|
||||
@@ -1197,7 +1251,7 @@ var lan = {
|
||||
"parsed_info":"For reference only, users using CDN pls ignore",
|
||||
"domain_empty":"Domain cannot be empty!",
|
||||
"domain_last_cannot":"The last domain is unable to be deleted",
|
||||
"domain_del_confirm":"Are you sure to delete domain from this site?",
|
||||
"domain_del_confirm":"Are you sure to delete this domain name?",
|
||||
"webback_del_confirm":"Are you sure to delete backup file?",
|
||||
"del_bak_file":"Delete backup file",
|
||||
"filename":"File name",
|
||||
@@ -1320,8 +1374,8 @@ var lan = {
|
||||
"bt_ssl_help_5":"Please check domain resolution before applying, unresolved domain leads to audit failure.",
|
||||
"bt_ssl_help_6":"aaPanel SSL certificate is the free version of TrustAsia DV SSL CA - G5 certificate, which only supports a single domain.",
|
||||
"bt_ssl_help_7":"Valid for 1 year, renewal is not supported, reapplication is required after expiration.",
|
||||
"bt_ssl_help_8":"Let's Encrypt free certificate, valid for 3 months, supports wildcard domain. Auto-renew by default.",
|
||||
"bt_ssl_help_9":"If your site uses CDN or 301 redirect, you will not be able to apply for and renew certificate through file verification.",
|
||||
"bt_ssl_help_8":"The certificate is valid for 3 months, supports wildcard domain. Auto-renew by default.",
|
||||
"bt_ssl_help_9":"If you uses CDN or redirect, you may not be able to apply and renew through file verification.",
|
||||
"bt_ssl_help_10":"Paste you KEY and CRT content, and then save it<a href='http://www.bt.cn/bbs/thread-704-1-1.html' class='btlink' target='_blank'>[HELP]</a>。",
|
||||
"phone_input":"Enter mobile phone number",
|
||||
"ssl_apply_1":"Submitting order,please wait..",
|
||||
@@ -1431,7 +1485,7 @@ var lan = {
|
||||
"dns_check_tips3": "Before using the [aaPanel DNS Cloud Resolution] API, you need to confirm that the domain DNS for which you want to apply for SSL certificate is [Cloud Resolution]",
|
||||
"dns_check_tips4": "Before using the [DNSPod/ Ali Cloud DNS] API, you need to set the API key of the corresponding interface in the pop-up window",
|
||||
"dns_check_tips5": "Check in advance (identify problems in advance)",
|
||||
"check_dns": "DNS verification",
|
||||
"check_dns": "DNS verification (Wildcard support)",
|
||||
"choose_dns": "Select DNS API",
|
||||
"interface": "API",
|
||||
"wait": "Wait",
|
||||
@@ -1586,7 +1640,7 @@ var lan = {
|
||||
"created":"Successfully created",
|
||||
"batch_add_site":"Batch add site",
|
||||
"site_name":"Site name",
|
||||
"opt_result":"Opt result",
|
||||
"opt_result":"Opt result"
|
||||
}
|
||||
},
|
||||
"public":{
|
||||
@@ -1778,18 +1832,35 @@ var lan = {
|
||||
"save_file_content":"Saving file content, please wait...",
|
||||
"save_ace_config":"Setting ace config, please wait...",
|
||||
"get_ace_config":"Getting ace config, please wait...",
|
||||
"save_all":"All saved successfully",
|
||||
"online_text_editor":"Online text editor",
|
||||
"save_tips":"Save Tips",
|
||||
"save_tips1":"Detected that the file was not saved, did you save the file change?",
|
||||
"save_tips2":"If you don\'t save, the changes will be lost!",
|
||||
"dont_save":"Dont save",
|
||||
"terminal":"Terminal",
|
||||
"set":"Set",
|
||||
"result":"Result",
|
||||
"selected":"Selected ",
|
||||
"please_choose":"Please choose"
|
||||
},
|
||||
"save_all": "All saved successfully",
|
||||
"online_text_editor": "Online text editor",
|
||||
"save_tips": "Save Tips",
|
||||
"save_tips1": "Detected that the file was not saved, did you save the file change?",
|
||||
"save_tips2": "If you don\'t save, the changes will be lost!",
|
||||
"dont_save": "Dont save",
|
||||
"terminal": "Terminal",
|
||||
"set": "Set",
|
||||
"result": "Result",
|
||||
"selected": "Selected ",
|
||||
"please_choose": "Please choose",
|
||||
"manage_cloud_server": "Remote servers",
|
||||
"capacity": "Quota",
|
||||
"notConfigured": "Not set",
|
||||
"currentUsedCapacity": "Quota already set",
|
||||
"quotaCapacity": "Set new quota",
|
||||
"capacityFinished": "Capacity is used up",
|
||||
"finished": "Has been finished",
|
||||
"modifyQuotaCapacity": "Click Modify Capacity Quota",
|
||||
"capacityTips1": "Reminder: This feature is exclusive to the pro edition",
|
||||
"capacityTips2": "Requires an XFS filesystem and includes the [prjquota] parameter to use",
|
||||
"capacityTips3": "Example of fstab: /dev/vdc1 /data xfs defaults,prjquota 0 0",
|
||||
"capacityTips4": "Import using the panel or root user, not affected by quotas",
|
||||
"capacityTips5": "Quota: To cancel quota, set to \"0\"",
|
||||
"modify_path_quota": "Setting directory quota, please wait...",
|
||||
"modify_mysql_quota": "Setting MySql quota, please wait...",
|
||||
"setup_success": "Setup successfully!",
|
||||
"setup_fail": "Setup Failed!"
|
||||
},
|
||||
"public_backup":{
|
||||
"login_expire":"Your login status has expired, please log in again!",
|
||||
"session_expire":"Session expired",
|
||||
@@ -1856,26 +1927,27 @@ var lan = {
|
||||
"month1":"1 month",
|
||||
"month3":"3 months",
|
||||
"month6":"6 months",
|
||||
"year1":"1 year",
|
||||
"year2":"2 years",
|
||||
"year3":"3 years",
|
||||
"permanent":"Permanent",
|
||||
"buy_multiplev_bt_pro":"Note: If you need to purchase multiple permanent licenses, please visit the aaPanel official site to purchase",
|
||||
"goto_bt":"Go to aaPanel official site",
|
||||
"up_pro_use_allplug_free":"Upgrade to Pro, all plugins are free to use",
|
||||
"buy":"Buy",
|
||||
"renew":"Renew",
|
||||
"type":"Type",
|
||||
"apiece_of_plug":"1 plugin",
|
||||
"up_pro":"Upgrade to Professional Edition",
|
||||
"use_allplug_free":"All plugins are free to use",
|
||||
"pro_expire_must_renew_or_change_free_version":"(When The Pro version expires, you will need to renew it before you can log in, or you can use SSH to execute the free version downgrade command to switch to the free version)",
|
||||
"duration":"Duration",
|
||||
"total":"Total",
|
||||
"rmb":"Yuan",
|
||||
"pay_by_wechatqrcore":"WeChat QR Code payment",
|
||||
"get_payment_info":"Getting payment info...",
|
||||
"loading":"Loading, please wait",
|
||||
"year1": "1 year",
|
||||
"year2": "2 years",
|
||||
"year3": "3 years",
|
||||
"permanent": "Permanent",
|
||||
"buy_multiplev_bt_pro": "Note: If you need to purchase multiple permanent licenses, please visit the aaPanel official site to purchase",
|
||||
"goto_bt": "Go to aaPanel official site",
|
||||
"up_pro_use_allplug_free": "Upgrade to Pro, all plugins are free to use",
|
||||
"buy": "Buy",
|
||||
"renew": "Renew",
|
||||
"type": "Type",
|
||||
"add_to": "Add to ",
|
||||
"apiece_of_plug": "1 plugin",
|
||||
"up_pro": "Upgrade to Professional Edition",
|
||||
"use_allplug_free": "All plugins are free to use",
|
||||
"pro_expire_must_renew_or_change_free_version": "(When The Pro version expires, you will need to renew it before you can log in, or you can use SSH to execute the free version downgrade command to switch to the free version)",
|
||||
"duration": "Duration",
|
||||
"total": "Total",
|
||||
"rmb": "Yuan",
|
||||
"pay_by_wechatqrcore": "WeChat QR Code payment",
|
||||
"get_payment_info": "Getting payment info...",
|
||||
"loading": "Loading, please wait",
|
||||
"choose_cash_coupon":"Please choose a coupon",
|
||||
"no_cash_coupon":"No coupon available",
|
||||
"pay_plug_success":"Successfully paid for the plugin!",
|
||||
@@ -2662,5 +2734,273 @@ var lan = {
|
||||
"switch_account":"Switch account",
|
||||
"email_account_empty_err":"Email account cannot be empty",
|
||||
"email_passwd_empty_err":"Email password cannot be empty"
|
||||
},
|
||||
'docker': {
|
||||
'public': {
|
||||
'activated': 'Running',
|
||||
'paused': 'Paused',
|
||||
'stopped': 'Stopped',
|
||||
'please_enter': 'Please enter ',
|
||||
'no_data': ' list is empty',
|
||||
'container': 'Name',
|
||||
'compose': 'Compose',
|
||||
'compose_template': 'Compose template',
|
||||
'mirror_image': 'Image',
|
||||
'network': 'Network',
|
||||
'volume': 'Volume name',
|
||||
'repository': 'Repository',
|
||||
'tag': 'Tag',
|
||||
'creation_time': 'Creation time',
|
||||
'execution': 'In execution, please wait ...',
|
||||
'no_data': function (val) {
|
||||
return val + ' list is empty'
|
||||
},
|
||||
'del_tips': function (val) {
|
||||
return 'Do you really want to delete this ' + val.toLowerCase() + ' from the list?'
|
||||
},
|
||||
'batch_select_tips': function (val) {
|
||||
return 'Select the ' + val.toLowerCase() + ' to execute!'
|
||||
},
|
||||
'batch_del': function (val) {
|
||||
return 'Batch delete ' + val.toLowerCase();
|
||||
},
|
||||
'batch_del_tips': function (val) {
|
||||
return 'Delete the selected ' + val.toLowerCase() + ' at the same time, do you continue?'
|
||||
},
|
||||
},
|
||||
'container': {
|
||||
'add_container': 'Add Container',
|
||||
'name': 'Container name',
|
||||
'status': 'Status',
|
||||
'mirror_image': 'Image',
|
||||
'cpu_usage': 'Cpu usage',
|
||||
'port': 'Port (Host-->Container)',
|
||||
'time': 'Start time',
|
||||
'start': 'Start',
|
||||
'stop': 'Stop',
|
||||
'pause': 'Pause',
|
||||
'unpause': 'Unpause',
|
||||
'restart': 'Restart',
|
||||
'reload': 'Reload',
|
||||
'monitoring': 'Stats',
|
||||
'online_monitoring': 'Online stats',
|
||||
'basic_information': 'Basic information',
|
||||
'flow_situation': 'Flow situation',
|
||||
'path': 'Path',
|
||||
'batch_select_tips': 'Select the container to execute!',
|
||||
'path_not': 'Directory does not exist',
|
||||
'get_logs_tips': 'Getting container Logs',
|
||||
'log': 'Container log',
|
||||
'log_none': 'The current log is empty',
|
||||
'del_container': 'Delete Container',
|
||||
'batch_del_container_tips': 'At the same time delete the selected container, do you continue?',
|
||||
'del_container_msg': 'Do you really want to delete this container from the list?',
|
||||
'del_container_tips': 'Deleting containers',
|
||||
'network': 'Network IO',
|
||||
'disk': 'Disk IO',
|
||||
'start_container': 'Start container',
|
||||
'stop_container': 'Stop container',
|
||||
'pause_container': 'Pause container',
|
||||
'unpause_container': 'Unpause container',
|
||||
'restart_container': 'Restart container',
|
||||
'reload_container': 'Reload container',
|
||||
'create_container': 'Container',
|
||||
'container_arr': 'Compose',
|
||||
'container_input_tips': 'Container name, e.g: docker_1',
|
||||
'port_select1': 'Expose ports',
|
||||
'port_select2': 'Expose all ports',
|
||||
'container_port': 'Container port',
|
||||
'server_port': 'Host port',
|
||||
'boot_command': 'Command',
|
||||
'boot_command_input_tips': 'Please enter the boot command',
|
||||
'shop_container_del': 'Automatically delete the container after the container stops',
|
||||
'limit_cpu': 'Limit CPU',
|
||||
'mount_volume': 'Volume',
|
||||
'server_directory': 'Server directory',
|
||||
'container_directory': 'Container directory',
|
||||
'read_only': 'Read only',
|
||||
'tag': 'Tag',
|
||||
'tag_textarea_tips': 'Container Tag, one per line, e.g: key=value',
|
||||
'env_variable': 'Env variable',
|
||||
'one_line': '(one per line)',
|
||||
'env_variable_textarea_tips': 'Add an environment variable format as follows. If you have multiple, please add it: ',
|
||||
'restart_rule': 'Restart rule',
|
||||
'restart_rule_select1': 'Rest up immediately after closing',
|
||||
'restart_rule_select2': 'Restart at the time of error (restart 5 times by default)',
|
||||
'restart_rule_select3': 'Not restart',
|
||||
'restart_rule_select_tips': 'Manual shutdown will not start automatically',
|
||||
'add_container_tips1': "The container name cannot be empty",
|
||||
'add_container_tips2': 'Please select the image',
|
||||
'add_container_tips3': 'CPU cannot be less than equal to 0',
|
||||
'add_container_tips4': 'Memory cannot be less than equal to 0',
|
||||
'add_container_api_tips': 'Adding container',
|
||||
'execute_container_command': 'Execute the container command',
|
||||
},
|
||||
'compose': {
|
||||
'no_data': 'Compose list is empty',
|
||||
'project_name': 'Project name',
|
||||
'container_number': 'Num of containers',
|
||||
'startup_time': 'Startup time',
|
||||
'batch_select_tips': 'Select the compose to execute!',
|
||||
'add_btn': 'Add Compose project',
|
||||
'name_input_tips': 'Please enter the compose name',
|
||||
'description_input_tips': 'Please enter the description',
|
||||
'compose_template_select_tips': 'Please select Compose template',
|
||||
'add_compose_tips1': 'Please create the Compose template first',
|
||||
'add_compose_tips2': 'Please enter the name',
|
||||
'getting_compose': 'Getting Compose',
|
||||
'container_list': 'Container list',
|
||||
'no_container': 'No container',
|
||||
'del_compose': 'Delete Compose',
|
||||
'del_compose_tips': 'Do you really want to delete this compose from the list?',
|
||||
'deleting_compose': 'Deleting Compose',
|
||||
'batch_del_compose': 'Batch delete compose',
|
||||
'batch_del_tips': 'Delete the selected compose at the same time, do you continue?',
|
||||
},
|
||||
'compose_template': {
|
||||
'template_name': 'Template name',
|
||||
'compose_template_name': 'Compose template name',
|
||||
'pull_mirror_image': 'Pull image',
|
||||
'getting_template': 'Getting template',
|
||||
'del_template': 'Delete template',
|
||||
'del_template_tips': 'Do you really want to delete this template from the list?',
|
||||
'add_title': 'Add Compose template',
|
||||
'create_template': 'Template name',
|
||||
'create_template_input': 'Please enter the template name',
|
||||
'content': 'Content',
|
||||
'search_local_template': 'Search local template',
|
||||
'search_input_tips': 'Please enter or select the file folder where the compose is located',
|
||||
'search': 'Search',
|
||||
'add_yaml_template': 'Add yaml template',
|
||||
'add_search_tips1': 'Choose the compose you need to add',
|
||||
'selected': 'Selected',
|
||||
'add_template': 'Add template',
|
||||
'adding_template': 'Adding template',
|
||||
'search_folder_tips1': 'Please enter or select your folder path',
|
||||
'search_folder_tips2': 'No compose file is found, please check the path',
|
||||
'add_template_tips1': 'The template name cannot be empty',
|
||||
'add_template_tips2': 'The content of the template cannot be empty',
|
||||
'add_path_tips1': 'Please select the Compose file',
|
||||
'add_path_tips2': 'Do you continue to add the selected ',
|
||||
'add_path_tips3': ' composes to the template?',
|
||||
'batch_select_tips': 'Select the template to execute!',
|
||||
'batch_del_template': 'Batch delete template',
|
||||
'batch_del_tips': 'Delete the selected template at the same time, do you continue?',
|
||||
'saving': 'Saving template',
|
||||
},
|
||||
'image': {
|
||||
'name': 'Image name',
|
||||
'creation_time': 'Creation time',
|
||||
'push': 'Push',
|
||||
'export': 'Export',
|
||||
'export': 'Export',
|
||||
'btn1': 'Pull image',
|
||||
'btn2': 'Import image',
|
||||
'btn3': 'Build image',
|
||||
'batch_tips': 'Select the image to execute!',
|
||||
'batch_del': 'Batch delete image',
|
||||
'batch_del_tips': 'Delete the selected image at the same time, do you continue?',
|
||||
'push_tips1': 'Please select the repository',
|
||||
'push_tips2': 'Please create a repository first',
|
||||
'push_tips3': 'The tag cannot be empty',
|
||||
'push_title1': 'Push ',
|
||||
'push_title2': ' to the repository',
|
||||
'warehouse_name': 'Repository name',
|
||||
'tag_input': 'Please enter the label, e.g: image: v1',
|
||||
'export_title': function (val) {
|
||||
return 'Export image [' + val + ']'
|
||||
},
|
||||
'path_input': 'Please enter the mirror path',
|
||||
'file_input': 'Please enter the exposed file name',
|
||||
'export_tips1': 'The path cannot be empty',
|
||||
'export_tips2': 'Export file name cannot be empty',
|
||||
'exporting': 'Exporting image',
|
||||
'del': function (val) {
|
||||
if (val) return 'Delete image [' + val + ']'
|
||||
return 'Delete image'
|
||||
},
|
||||
'del_tips': 'Do you really want to delete this mirror from the list?',
|
||||
'deleting': 'Deleting image',
|
||||
'pull_title': 'Pull image',
|
||||
'warehouse_select': 'Please select the repository',
|
||||
'mirror_name': 'Image',
|
||||
'mirror_input': 'Please enter the image name, e.g: [ image:v1 ]',
|
||||
'pull_tips1': 'Please create a repository first',
|
||||
'pull_tips2': 'The image name cannot be empty',
|
||||
'import': 'Import',
|
||||
'importing': 'Importing image',
|
||||
'build_title': 'Build image',
|
||||
'dockerfile_input': 'Please enter or select the dockerfile file',
|
||||
},
|
||||
'network': {
|
||||
'name': 'Network name',
|
||||
'show': 'Show',
|
||||
'num': 'Network number',
|
||||
'gateway': 'Gateway',
|
||||
'add': 'Add network',
|
||||
'del': function (val) {
|
||||
if (val) return 'Delete network [' + val + ']'
|
||||
return 'Delete network'
|
||||
},
|
||||
'del_tips': 'Do you really want to delete this network from the list?',
|
||||
'deleting': 'Deleting network',
|
||||
'name_input': 'Please enter the network name',
|
||||
'device': 'Device',
|
||||
'parameter': 'Parameter',
|
||||
'parameter_textarea': 'Parameter, one per line, e.g: key=value',
|
||||
'sub_network': 'Sub-net',
|
||||
'sub_network_input': 'Please enter the subnet',
|
||||
'gateway_input': 'Please enter the gateway',
|
||||
'ip_range': 'IP range',
|
||||
'ip_range_input': 'Please enter the IP address range',
|
||||
'tag_textarea': 'Network tag, one per line, e.g: key=value',
|
||||
'add_tips1': 'The network name cannot be empty',
|
||||
'add_tips2': 'Parameters cannot be empty',
|
||||
'add_tips3': 'The subnet cannot be empty',
|
||||
'add_tips4': 'The gateway cannot be empty',
|
||||
'add_tips5': 'IP address range cannot be empty',
|
||||
'adding': 'Adding network',
|
||||
},
|
||||
'volume': {
|
||||
'mount': 'Mount point',
|
||||
'driver': 'Driver',
|
||||
'del': function (val) {
|
||||
if (val) return 'Delete volume [' + val + ']'
|
||||
return 'Delete volume'
|
||||
},
|
||||
'deleting': 'Deleting volume',
|
||||
'add': 'Add volume',
|
||||
'name_input': 'Please enter the volume name',
|
||||
'option': 'Option',
|
||||
'tag_textarea': 'Volume tag, one per line, e.g: key=value',
|
||||
'add_tips1': 'Volume name cannot be empty',
|
||||
'adding': 'Adding volume',
|
||||
},
|
||||
'repository': {
|
||||
'username': 'Username',
|
||||
'name': 'Repository name',
|
||||
'del': function (val) {
|
||||
if (val) return 'Delete volume [' + val + ']'
|
||||
return 'Delete volume'
|
||||
},
|
||||
'deleting': 'Deleting repository',
|
||||
'add': 'Add repository',
|
||||
'address': 'Repository address',
|
||||
'address_input': 'Please enter the Repository address',
|
||||
'name_input': 'Please enter the Repository name',
|
||||
'user_input': 'Please enter the Repository username',
|
||||
'pwd': 'Password',
|
||||
'pwd_input': 'Please enter the Repository password',
|
||||
'namespaces': 'Namespaces',
|
||||
'namespaces_input': 'Please enter the naming space',
|
||||
'form_tips1': 'The repository address cannot be empty',
|
||||
'form_tips2': 'The repository name cannot be empty',
|
||||
'form_tips3': 'The repository username cannot be empty',
|
||||
'form_tips4': 'The repository password cannot be empty',
|
||||
'form_tips5': 'Naming space cannot be empty',
|
||||
},
|
||||
'setup': {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@
|
||||
"SITE_ADD_BINDING":"Domain and name of subdirectory cannot be empty!",
|
||||
"SITE_INDEX_ERR_FORMAT":"Default Document Format is invalid, e.g., index.html",
|
||||
"SITE_INDEX_ERR_EMPTY":"Default Document cannot be empty!",
|
||||
"SITE_PATH_ERR_RE":"Same as original directory, no need to change!",
|
||||
"SITE_PATH_ERR_RE":"Same as original path, no need to change!",
|
||||
"SITE_PHPVERSION_ERR_A22":"Apache2.2 does NOT support MultiPHP!",
|
||||
"SITE_PHPVERSION_SUCCESS":"Successfully changed PHP Version of site [{1}] to PHP-{2}",
|
||||
"SITE_BASEDIR_OPEN_SUCCESS":"Base directory turned on!",
|
||||
@@ -1012,7 +1012,7 @@
|
||||
"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!",
|
||||
"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}",
|
||||
|
||||
@@ -106,23 +106,24 @@
|
||||
"TH2":"User",
|
||||
"TH3":"Password",
|
||||
"TH4":"Backup",
|
||||
"TH5":"Notes",
|
||||
"TH6":"Action",
|
||||
"SP1":"Sync",
|
||||
"SP2":"Sync all",
|
||||
"SP3":"Obtaining information from server",
|
||||
"TP1":"Sync selected database information to server",
|
||||
"TP2":"Sync all database information to server",
|
||||
"TP3":"Obtaining database list from server",
|
||||
"JS1":"Pls install MySQL first!",
|
||||
"JS2":"Install",
|
||||
"RECYCLE_BIN":"Recycle bin"
|
||||
},
|
||||
"TH5": "Notes",
|
||||
"TH6": "Action",
|
||||
"SP1": "Sync",
|
||||
"SP2": "Sync all",
|
||||
"SP3": "Obtaining information from server",
|
||||
"TP1": "Sync selected database information to server",
|
||||
"TP2": "Sync all database information to server",
|
||||
"TP3": "Obtaining database list from server",
|
||||
"JS1": "Pls install MySQL first!",
|
||||
"JS2": "Install",
|
||||
"RECYCLE_BIN": "Recycle bin",
|
||||
"NOT_INSTALL_DATABASE_DESC": "未安装本地数据库,已隐藏无法使用的功能!"
|
||||
},
|
||||
|
||||
"config":{
|
||||
"H1":"Dashboard",
|
||||
"H2":"Panel Setting",
|
||||
"I1":"Turn off panel",
|
||||
"I1":"Close panel",
|
||||
"I2":"Auto update",
|
||||
"I3":"Panel SSL",
|
||||
"C1":"Setting",
|
||||
@@ -143,16 +144,25 @@
|
||||
"CT12":"Panel template",
|
||||
"CY1":"Take alias for aaPanel",
|
||||
"CY2":"Suggested port: 8888-65535",
|
||||
"CY3":"Binding a access domain to the Panel Warning:If a domain is bound to Panel, you'll have to access panel with Domain ONLY!",
|
||||
"CY4":"Split multiple IP with (,) Warning:If authorized IP is set, ONLY the PC with authorized IP can access the panel!",
|
||||
"CY3":"Set a domain name for the panel",
|
||||
"CY31":"Note: You can only use this domain name to access the panel after setting",
|
||||
"CY4": "Split multiple IP with (,) Warning:",
|
||||
"CY41": "If IP is set, ONLY the authorized IP can access the panel!",
|
||||
"CY5":"New created site will be saved to subdirectory by default!",
|
||||
"CY6":"Directory of site and database backup!",
|
||||
"CY7":"Defualt IP is Internet IP. If you need use local virtual machine to test, please input Intranet IP of virtual machine!",
|
||||
"CY7":"Default IP is Internet IP. If you need use local virtual machine to test, please input Intranet IP!",
|
||||
"CY8":"Sync",
|
||||
"CY9":"Modify",
|
||||
"CY10":"Modify",
|
||||
"CY11":"Bind",
|
||||
"CY12":"Save",
|
||||
"PASSWORD_EXPIRE": "Password expire",
|
||||
"TEMP_ACCESS": "Temporary login",
|
||||
"TEMP_ACCESS_DESC": "Temporarily provide panel access to non-admins",
|
||||
"PASSWORD_EXPIRE_DESC": "Set the panel password expiration time",
|
||||
"STRONG_PASSWORD":"Strong password",
|
||||
"NOT_LOGGED_IN_RESPONSE": "Not logged in response",
|
||||
"NOT_LOGGED_IN_RESPONSE_DESC": "Response when not logged in and not properly entered for security entry, can be used to hide panel features",
|
||||
"SET_IPV6":"Allow ipv6 access panel after turning on",
|
||||
"LISTEN_IPV6":"Listen IPv6",
|
||||
"SET_PANEL_SSL":"Click to customize the panel certificate",
|
||||
@@ -160,8 +170,8 @@
|
||||
"API":"API",
|
||||
"LOGINTIMEOUT":"Login session timeout",
|
||||
"TIMEOUT":"Timeout",
|
||||
"CY13":"seconds, If the user does not have any operation within ",
|
||||
"CY14":" seconds, the panel will automatically exit",
|
||||
"CY13":"sec, If the user does not have any operation within ",
|
||||
"CY14":" sec, the panel will auto logout",
|
||||
"S_ENTRY":"Security Entrance",
|
||||
"CY15":"Panel Admin entrance. After setting, you can ONLY log in to the panel through the specified Security Entrance, e.g. /www_bt_cn",
|
||||
"WECHAT":"WeChat Mini Program",
|
||||
@@ -172,8 +182,32 @@
|
||||
"BASICAUTH_TIPS1":"Used for BasicAuth authentication configuration",
|
||||
"CONFIG":"Set",
|
||||
"BASICAUTH_TIPS2":"Add a BasicAuth-based authentication service to the panel to prevent the panel from being swept",
|
||||
"S_PORT_TIPS":"Note: For servers with security groups, please release the new port in the security group in advance."
|
||||
|
||||
"S_PORT_TIPS":"Note: For servers with security groups, please release the new port in the security group in advance.",
|
||||
"CLOSE_PANEL": "Only close the panel, does not affect the operation of web, database, etc.",
|
||||
"ALLOW_IPV6": "Allow panel access via IPv6 address",
|
||||
"OFFLINE": "All services that require internet access will be unavailable",
|
||||
"OFFLINE_MODE": "Offline mode",
|
||||
"DEV_MODE": "Developer mode",
|
||||
"DEV_MODE_DESC": "Only used by third-party developers in the development stage",
|
||||
"API_DESC": "Enable panel interface access (APP needs to enable this function)",
|
||||
"HELP": "Help",
|
||||
"HIDE_MENU_BAR": "Menu bar hidden",
|
||||
"HIDE_MENU_BAR_DESC": "Hide left menu bar",
|
||||
"UNBIND":"Unbind",
|
||||
"BIND_ACCOUNT": "Bind account",
|
||||
"GLOBAL": "Global",
|
||||
"SECURITY": "Security",
|
||||
"NOTIFY": "Notification",
|
||||
"SET_SSL": "After opening, it can only be accessed through the https",
|
||||
"BASEAUTH_DESC": "Add an extra layer of auth to effectively prevent the panel from being scanned",
|
||||
"GOOGLE_AUTH_DESC": "A dynamic verification code is required to log in to the panel",
|
||||
"STRONG_PASS_DESC": "Enable strong password for the panel, rules: ",
|
||||
"STRONG_PASS_DESC1": "Length 8, upper and lower case letters, numbers and characters exist",
|
||||
"EMAIL_NOT_SET": "Email is not set",
|
||||
"TG_NOT_SET": "Telegram is not set",
|
||||
"NOTIFY_DESC": "After setting, abnormal message can be pushed",
|
||||
"LOGIN_ALARM": "Login panel notification",
|
||||
"LOGIN_ALARM_DESC": "Every time you log in the panel will push a message to your receiver"
|
||||
},
|
||||
|
||||
"close":{
|
||||
|
||||
@@ -139,7 +139,7 @@ var lan = {
|
||||
"update_time": "Update time",
|
||||
"update_verison_click": "If you need to update the beta version, please click",
|
||||
"check_detail": "see details",
|
||||
"change_final_click": "If you need to switch back to the official version, please click",
|
||||
"change_final_click": "If you need to switch back to the stable version, click ",
|
||||
"change_final": "Switch to the official version",
|
||||
"have_new_version": "Is there a new panel version update, is it updated?",
|
||||
"last_version": "The latest version of: ",
|
||||
@@ -1247,7 +1247,7 @@ var lan = {
|
||||
"bt_ssl_help_6": "BT-Panel SSL certificate is the free version of TrustAsia DV SSL CA - G5 certificate, which only supports a single domain.",
|
||||
"bt_ssl_help_7": "Valid for 1 year, does not support renewal, need to apply again when expired.",
|
||||
"bt_ssl_help_8": "Let's Encrypt free certificate, valid for 3 months, supports multiple domain names. Auto-renew by default.",
|
||||
"bt_ssl_help_9": "If your site uses CDN or 301 redirect, you will not be able to apply for and renew certificate through file verification.",
|
||||
"bt_ssl_help_9": "If your site uses CDN or has redirect, you may not be able to apply for and renew through file verification.",
|
||||
"bt_ssl_help_10": "Paste you KEY and CRT content, and then save it<a href='http://www.bt.cn/bbs/thread-704-1-1.html' class='btlink' target='_blank'>[HELP]</a>。",
|
||||
"phone_input": "Input phone number",
|
||||
"ssl_apply_1": "Submitting order,please wait..",
|
||||
|
||||
@@ -2,16 +2,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{data['lan']['AUTHTITLE']}}</title>
|
||||
<title>Ingress verification failed</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{{data['lan']['AUTHENTRY']}}</h1>
|
||||
<p><b>{{data['lan']['AUTHERR_REASON']}}</b>{{data['lan']['AUTHERR_REASON_CONTENT']}}</p>
|
||||
<p><b>{{data['lan']['AUTHERR_RESOLVENT']}}</b>{{data['lan']['AUTHERR_RESOLVENT_CONTENT']}}</p>
|
||||
<p>1.{{data['lan']['AUTHERR_RESOLVENT1']}}: /etc/init.d/bt default</p>
|
||||
<p>2.{{data['lan']['AUTHERR_RESOLVENT2']}}: rm -f /www/server/panel/data/admin_path.pl</p>
|
||||
<p style="color:red;">{{data['lan']['AUTHERR_TACK_CARE']}}</p>
|
||||
<hr>
|
||||
<address>{{data['lan']['NAME']}}, <a href="https://forum.aapanel.com/d/1090-login-panel-using-security-portal" target="_blank">{{data['lan']['HELP']}}</a></address>
|
||||
<h1>Please use the correct Ingress</h1>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,331 +1,550 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<link href="{{g.cdn_url}}/layer/skin/default/layer.css" rel="stylesheet"/>
|
||||
<div class="main-content">
|
||||
<div class="container-fluid" style="padding-bottom:54px">
|
||||
<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 class="pos-box bgw mtb15 radius4">
|
||||
<div class="tab-list" id="configTab">
|
||||
<div class="tabs-item" data-type="allConfig">{{data['lan']['GLOBAL']}}</div>
|
||||
<div class="tabs-item" data-type="panelConfig">{{data['lan']['H2']}}</div>
|
||||
<div class="tabs-item" data-type="securityConfig">{{data['lan']['SECURITY']}}</div>
|
||||
<div class="tabs-item" data-type="pushConfig">{{data['lan']['NOTIFY']}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix bgw mtb15 pd15">
|
||||
<div class="safe-port pull-left">
|
||||
<div class="ss-text pull-left mr50">
|
||||
<em>{{data['lan']['I1']}}</em>
|
||||
<div class='ssh-item'>
|
||||
<input class='btswitch btswitch-ios' id='closePl' type='checkbox'>
|
||||
<label class='btswitch-btn' for='closePl' onclick='ClosePanel()'></label>
|
||||
<div class="setbox bgw mtb15 tab-view-box configure-box">
|
||||
<!-- 面板设置 -->
|
||||
<div class="panel-config hide" data-type="panelConfig">
|
||||
<div class="configure-title">{{data['lan']['H2']}}</div>
|
||||
<div class="configure-block">
|
||||
<!-- 关闭面板 -->
|
||||
<div class="line" title="{{data['lan']['I1']}}">
|
||||
<div class="line-title">{{data['lan']['I1']}}</div>
|
||||
<div class="line-form">
|
||||
<div class="line-row">
|
||||
<div class="ssh-item" style="margin-left: 0;padding: 0;">
|
||||
<input class="btswitch btswitch-ios" id="closePanel" type="checkbox"
|
||||
name="close_panel"/>
|
||||
<label class="btswitch-btn" for="closePanel" style="margin-bottom: 0;"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line-row-tips">{{data['lan']['CLOSE_PANEL']}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 监听IPv6 -->
|
||||
<div class="line" title="IPv6">
|
||||
<div class="line-title">IPv6</div>
|
||||
<div class="line-form">
|
||||
<div class="line-row">
|
||||
<div class="ssh-item" style="margin-left: 0;padding: 0;">
|
||||
<input class="btswitch btswitch-ios" id="monitorIPv6" type="checkbox" name="ipv6"/>
|
||||
<label class="btswitch-btn" for="monitorIPv6" style="margin-bottom: 0;"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line-row-tips">{{data['lan']['ALLOW_IPV6']}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 离线模式 -->
|
||||
<div class="line" title="Offline mode">
|
||||
<div class="line-title">{{data['lan']['OFFLINE_MODE']}}</div>
|
||||
<div class="line-form">
|
||||
<div class="line-row">
|
||||
<div class="ssh-item" style="margin-left: 0;padding: 0;">
|
||||
<input class="btswitch btswitch-ios" id="offlineMode" type="checkbox"
|
||||
name="is_local"/>
|
||||
<label class="btswitch-btn" for="offlineMode" style="margin-bottom: 0;"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line-row-tips">{{data['lan']['OFFLINE']}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- 开发者模式 -->
|
||||
<div class="line" title="Developer mode">
|
||||
<div class="line-title">{{data['lan']['DEV_MODE']}}</div>
|
||||
<div class="line-form">
|
||||
<div class="line-row">
|
||||
<div class="ssh-item" style="margin-left: 0;padding: 0;">
|
||||
<input class="btswitch btswitch-ios" id="developerMode" type="checkbox"
|
||||
name="debug"/>
|
||||
<label class="btswitch-btn" for="developerMode" style="margin-bottom: 0;"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line-row-tips">{{data['lan']['DEV_MODE_DESC']}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- API -->
|
||||
<div class="line" title="API">
|
||||
<div class="line-title">API</div>
|
||||
<div class="line-form">
|
||||
<div class="line-row">
|
||||
<div class="ssh-item" style="margin-left: 0; margin-top: -3px; padding: 0;">
|
||||
<input class="btswitch btswitch-ios" id="apiInterface" type="checkbox" name="api"/>
|
||||
<label class="btswitch-btn" for="apiInterface" style="margin-bottom: 0;"></label>
|
||||
</div>
|
||||
<button type="button" class="btn btn-default btn-xs apiInterfaceBtn"
|
||||
style="margin-left: 10px;">{{data['lan']['CONFIG']}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="line-row-tips">{{data['lan']['API_DESC']}},<a
|
||||
href="https://forum.aapanel.com/d/482-api-interface-tutorial" class="btlink"
|
||||
target="_blank">{{data['lan']['HELP']}}</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 面板别名 -->
|
||||
<div class="line" title="{{data['lan']['CT1']}}">
|
||||
<div class="line-title">{{data['lan']['CT1']}}</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" name="webname"/>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-sm ml5 savePanelConfig" disabled>{{data['lan']['CY12']}}</button>
|
||||
<div class="line-row-tips">{{data['lan']['CY1']}}</div>
|
||||
</div>
|
||||
<!-- 超时时间 -->
|
||||
<div class="line" title="Timeout">
|
||||
<div class="line-title">Timeout</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" name="session_timeout"/>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-sm ml5 savePanelConfig" disabled>{{data['lan']['CY12']}}</button>
|
||||
<div class="line-row-tips">{{data['lan']['CY13']}} <span
|
||||
class="color-red seconds">0</span> {{data['lan']['CY14']}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- 默认建站目录 -->
|
||||
<div class="line" title="{{data['lan']['CT5']}}">
|
||||
<div class="line-title">{{data['lan']['CT5']}}</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" name="sites_path"/>
|
||||
<div class="selected-file sitesPath"><span
|
||||
class="glyphicon glyphicon-folder-open cursor"></span></div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-sm ml5 savePanelConfig" disabled>{{data['lan']['CY12']}}</button>
|
||||
<div class="line-row-tips">{{data['lan']['CY5']}}</div>
|
||||
</div>
|
||||
<!-- 默认备份目录 -->
|
||||
<div class="line" title="{{data['lan']['CT6']}}">
|
||||
<div class="line-title">{{data['lan']['CT6']}}</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" name="backup_path"/>
|
||||
<div class="selected-file backupPath"><span
|
||||
class="glyphicon glyphicon-folder-open cursor"></span></div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-sm ml5 savePanelConfig" disabled>{{data['lan']['CY12']}}</button>
|
||||
<div class="line-row-tips">{{data['lan']['CY6']}}</div>
|
||||
</div>
|
||||
<!-- 服务器IP -->
|
||||
<div class="line" title="{{data['lan']['CT7']}}">
|
||||
<div class="line-title">{{data['lan']['CT7']}}</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" name="address"/>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-sm ml5 savePanelConfig" disabled>{{data['lan']['CY12']}}</button>
|
||||
<div class="line-row-tips">{{data['lan']['CY7']}}</div>
|
||||
</div>
|
||||
<!-- 服务器时间 -->
|
||||
<div class="line" title="{{data['lan']['CT8']}}">
|
||||
<div class="line-title">{{data['lan']['CT8']}}</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" name="systemdate" disabled/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 面板账号 -->
|
||||
<div class="line" title="{{data['lan']['CT9']}}">
|
||||
<div class="line-title">{{data['lan']['CT9']}}</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" name="username" disabled/>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-sm ml5 editPanelAccount">{{data['lan']['CONFIG']}}</button>
|
||||
<div class="line-row-tips"> </div>
|
||||
</div>
|
||||
<!-- 面板密码 -->
|
||||
<div class="line" title="{{data['lan']['CT10']}}">
|
||||
<div class="line-title">{{data['lan']['CT10']}}</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" name="password" disabled/>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-sm ml5 editPanelPassword">{{data['lan']['CONFIG']}}</button>
|
||||
<div class="line-row-tips"> </div>
|
||||
</div>
|
||||
<!-- 绑定宝塔账号 -->
|
||||
<div class="line" title="Bind account">
|
||||
<div class="line-title">{{data['lan']['BIND_ACCOUNT']}}</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" name="bind_user_info" disabled/>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-sm ml5 bindBtUser">{{data['lan']['CONFIG']}}</button>
|
||||
<button type="button" class="btn btn-default btn-sm ml5 unbindBtUser">{{data['lan']['UNBIND']}}</button>
|
||||
<div class="line-row-tips"> </div>
|
||||
</div>
|
||||
<!-- 面板菜单栏隐藏 -->
|
||||
<div class="line" title="Menu bar hidden">
|
||||
<div class="line-title">{{data['lan']['HIDE_MENU_BAR']}}</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" name="menu_hide_list" disabled/>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-sm ml5 menuBarManage">{{data['lan']['CONFIG']}}</button>
|
||||
<div class="line-row-tips">{{data['lan']['HIDE_MENU_BAR_DESC']}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ss-text pull-left mr50">
|
||||
<em title={{data['lan']['SET_IPV6']}}>{{data['lan']['LISTEN_IPV6']}}</em>
|
||||
<div class='ssh-item'>
|
||||
<input class='btswitch btswitch-ios' id='panelIPv6' type='checkbox' {{data['ipv6']}}>
|
||||
<label class='btswitch-btn' for='panelIPv6' onclick="SetIPv6()"></label>
|
||||
</div>
|
||||
<!-- 安全设置 -->
|
||||
<div class="panel-config hide" data-type="securityConfig">
|
||||
<div class="configure-title">{{data['lan']['SECURITY']}}</div>
|
||||
<div class="configure-block">
|
||||
<!-- 面板SSL -->
|
||||
<div class="line" title="{{data['lan']['I3']}}">
|
||||
<div class="line-title">{{data['lan']['I3']}}</div>
|
||||
<div class="line-form">
|
||||
<div class="line-row">
|
||||
<div class="ssh-item" style="margin-left: 0;padding: 0;">
|
||||
<input class="btswitch btswitch-ios" id="panelSsl" type="checkbox" name="ssl">
|
||||
<label class="btswitch-btn" for="panelSsl" style="margin-bottom: 0;"></label>
|
||||
</div>
|
||||
<button ype="button" class="btn btn-default btn-xs panelSslConfig" style="vertical-align: middle;
|
||||
margin-left: 10px;">{{data['lan']['CONFIG']}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="line-row-tips">{{data['lan']['SET_SSL']}},<a
|
||||
href="http://www.bt.cn/bbs/thread-704-1-1.html" class="btlink"
|
||||
target="_blank">{{data['lan']['HELP']}}</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- BasicAuth认证 -->
|
||||
<div class="line" title="BasicAuth">
|
||||
<div class="line-title">BasicAuth</div>
|
||||
<div class="line-form">
|
||||
<div class="line">
|
||||
<div class="ssh-item" style="margin-left: 0;padding: 0;">
|
||||
<input class="btswitch btswitch-ios" id="basicAuth" type="checkbox"
|
||||
name="basic_auth"/>
|
||||
<label class="btswitch-btn" for="basicAuth" style="margin-bottom: 0;"></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line-row-tips">{{data['lan']['BASEAUTH_DESC']}},<a
|
||||
href="https://www.bt.cn/bbs/thread-34374-1-1.html" class="btlink"
|
||||
target="_blank">{{data['lan']['HELP']}}</a></div>
|
||||
</div>
|
||||
<!-- 动态口令认证 -->
|
||||
<div class="line" title="Google authentication">
|
||||
<div class="line-title">Google authentication</div>
|
||||
<div class="line-form">
|
||||
<div class="line-row">
|
||||
<div class="ssh-item" style="margin-left: 0;padding: 0;">
|
||||
<input class="btswitch btswitch-ios" id="checkTwoStep" type="checkbox"
|
||||
name="check_two_step"/>
|
||||
<label class="btswitch-btn" for="checkTwoStep" style="margin-bottom: 0;"></label>
|
||||
</div>
|
||||
<button ype="button" class="btn btn-default btn-xs checkTwoStepConfig" style="vertical-align: middle;
|
||||
margin-left: 10px;">{{data['lan']['CONFIG']}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="line-row-tips">{{data['lan']['GOOGLE_AUTH_DESC']}},<a
|
||||
href="https://forum.aapanel.com/d/357-how-to-use-google-authenticator-in-the-aapanel"
|
||||
class="btlink" target="_blank">{{data['lan']['HELP']}}</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 访问设备验证 -->
|
||||
<!-- <div class="line" title="访问设备验证">
|
||||
<div class="line-title">访问设备验证</div>
|
||||
<div class="line-form">
|
||||
<div class="line-row">
|
||||
<div class="ssh-item" style="margin-left: 0;padding: 0;">
|
||||
<input class="btswitch btswitch-ios" id="sslVerify" type="checkbox" name="ssl_verify"/>
|
||||
<label class="btswitch-btn" for="sslVerify" style="margin-bottom: 0;"></label>
|
||||
</div>
|
||||
<button ype="button" class="btn btn-default btn-xs sslVerifyConfig" style="vertical-align: middle;
|
||||
margin-left: 10px;">访问设备验证配置</button>
|
||||
</div>
|
||||
<div class="line-row-tips">基于SSL证书双向验证,开启后电脑需要安装此证书,否则将无法访问,属于极高安全级别的访问限制方式,类似银行账号U盘密钥登录。<a href="https://www.bt.cn/bbs/thread-77863-1-1.html" class="btlink" target="_blank">了解详情</a></div>
|
||||
</div>
|
||||
</div> -->
|
||||
<!-- 密码复杂度验证 -->
|
||||
<div class="line" title="{{data['lan']['STRONG_PASSWORD']}}">
|
||||
<div class="line-title">{{data['lan']['STRONG_PASSWORD']}}</div>
|
||||
<div class="line-form">
|
||||
<div class="line-row">
|
||||
<div class="ssh-item" style="margin-left: 0;padding: 0;">
|
||||
<input class="btswitch btswitch-ios" id="passwordSafe" type="checkbox"
|
||||
name="paw_complexity"/>
|
||||
<label class="btswitch-btn" for="passwordSafe" style="margin-bottom: 0;"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line-row-tips">{{data['lan']['STRONG_PASS_DESC']}}<span class="color-red">{{data['lan']['STRONG_PASS_DESC1']}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 绑定域名 -->
|
||||
<div class="line" title="{{data['lan']['CT3']}}">
|
||||
<div class="line-title">{{data['lan']['CT3']}}</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" name="domain"/>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-sm ml5 savePanelConfig" disabled>Save</button>
|
||||
<div class="line-row-tips">{{data['lan']['CY3']}},<span class="color-red">{{data['lan']['CY31']}}</span></div>
|
||||
</div>
|
||||
<!-- 授权IP -->
|
||||
<div class="line" title="{{data['lan']['CT4']}}">
|
||||
<div class="line-title">{{data['lan']['CT4']}}</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" placeholder="1.1.1.1,2.2.2.1-2.2.2.2"
|
||||
name="limitip"/>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-sm ml5 savePanelConfig" disabled>Save</button>
|
||||
<div class="line-row-tips">{{data['lan']['CY4']}}<span class="color-red">{{data['lan']['CY41']}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 面板端口 -->
|
||||
<div class="line" title="{{data['lan']['CT2']}}">
|
||||
<div class="line-title">{{data['lan']['CT2']}}</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" name="port" disabled/>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-sm ml5 setPanelPort">Set</button>
|
||||
<div class="line-row-tips">{{data['lan']['CY2']}}, <span class="color-red">{{data['lan']['S_PORT_TIPS']}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 安全入口 -->
|
||||
<div class="line" title="Security Entrance">
|
||||
<div class="line-title">Security Entrance</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" name="admin_path" disabled/>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-sm ml5 setSafetyEntrance">Set</button>
|
||||
<div class="line-row-tips">Panel Admin entrance. After setting, you can ONLY log in to the panel
|
||||
through the specified Security Entrance, e.g. /www_bt_cn
|
||||
</div>
|
||||
</div>
|
||||
<!-- 未认证的响应状态 -->
|
||||
<div class="line" title="{{data['lan']['NOT_LOGGED_IN_RESPONSE']}}">
|
||||
<div class="line-title">{{data['lan']['NOT_LOGGED_IN_RESPONSE']}}</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" name="status_code" disabled/>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-sm ml5 setStatusCodeView">Set</button>
|
||||
<div class="line-row-tips">{{data['lan']['NOT_LOGGED_IN_RESPONSE_DESC']}}</div>
|
||||
</div>
|
||||
<!-- 密码过期时间 -->
|
||||
<div class="line" title="{{data['lan']['PASSWORD_EXPIRE']}}">
|
||||
<div class="line-title">{{data['lan']['PASSWORD_EXPIRE']}}</div>
|
||||
<div class="line-input">
|
||||
<input type="text" class="bt-input-text" name="paw_expire_time" disabled/>
|
||||
<button type="button" class="btn btn-success btn-sm ml5 setPawExpiration">Set</button>
|
||||
</div>
|
||||
<div class="line-row-tips">{{data['lan']['PASSWORD_EXPIRE_DESC']}}</div>
|
||||
</div>
|
||||
<!-- 临时访问授权 -->
|
||||
<div class="line" title="{{data['lan']['TEMP_ACCESS']}}">
|
||||
<div class="line-title">{{data['lan']['TEMP_ACCESS']}}</div>
|
||||
<div class="line-input">
|
||||
<button type="button" class="btn btn-success btn-sm setTempAuthView">{{data['lan']['CONFIG']}}</button>
|
||||
</div>
|
||||
<div class="line-row-tips">{{data['lan']['TEMP_ACCESS_DESC']}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ss-text pull-left mr50">
|
||||
<em class="btlink" style="color: #20a53a;" onclick="GetPanelSSL()" title={{data['lan']['SET_PANEL_SSL']}}>{{data['lan']['I3']}}</em>
|
||||
<div class='ssh-item'>
|
||||
<input class='btswitch btswitch-ios' id='panelSSL' type='checkbox'>
|
||||
<label class='btswitch-btn' for='panelSSL' onclick="setPanelSSL()"></label>
|
||||
</div>
|
||||
<!-- 通知设置 -->
|
||||
<div class="panel-config hide" data-type="pushConfig">
|
||||
<div class="configure-title">{{data['lan']['NOTIFY']}}</div>
|
||||
<div class="configure-block">
|
||||
<!-- 消息通道 -->
|
||||
<div class="line" title="{{data['lan']['NOTIFY']}}">
|
||||
<div class="line-title">{{data['lan']['NOTIFY']}}</div>
|
||||
<div class="line-input">
|
||||
<div class="line-row">
|
||||
<a href="javascript:;" class="bt_warning setMessageChannelMail">{{data['lan']['EMAIL_NOT_SET']}}</a> |
|
||||
<a href="javascript:;" class="bt_warning setMessageChannelTelegram">{{data['lan']['TG_NOT_SET']}}
|
||||
set</a>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-xs setMessageChannelMailBtn">{{data['lan']['CONFIG']}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="line-row-tips">{{data['lan']['NOTIFY_DESC']}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ss-text pull-left mr50">
|
||||
<em class="btlink" style="color: #20a53a;" onclick="GetPanelApi()" title={{data['lan']['SET_API']}}>{{data['lan']['API']}}</em>
|
||||
<div class='ssh-item'>
|
||||
<input class='btswitch btswitch-ios' id='panelApi' type='checkbox' {{data['api']}}>
|
||||
<label class='btswitch-btn' for='panelApi' onclick="SetPanelApi(2)"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ss-text pull-left mr50">
|
||||
<em title="Developer mode">Developer mode</em>
|
||||
<div class='ssh-item'>
|
||||
<input class='btswitch btswitch-ios' id='panelDebug' type='checkbox' {{data['debug']}}>
|
||||
<label class='btswitch-btn' for='panelDebug' onclick="SetDebug()"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ss-text pull-left mr50">
|
||||
<em title="after Open, The panel will stop connecting to the cloud, and the software installation, uninstallation, panel update and other functions will not be available.">Offline mode</em>
|
||||
<div class='ssh-item'>
|
||||
<input class='btswitch btswitch-ios' id='panelLocal' type='checkbox' {{data['is_local']}}>
|
||||
<label class='btswitch-btn' for='panelLocal' onclick="set_local()"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ss-text pull-left mr50">
|
||||
<em title="User login authentication based on Google Authenticator"><a href="javascript:;" class="btlink open_two_verify_view">Google authentication</a></em>
|
||||
<div class='ssh-item'>
|
||||
<input class='btswitch btswitch-ios' id='panel_verification' type='checkbox'/>
|
||||
<label class='btswitch-btn' for='panel_verification'></label>
|
||||
<!-- 登录告警 -->
|
||||
<div class="line" title="{{data['lan']['LOGIN_ALARM']}}">
|
||||
<div class="line-title">{{data['lan']['LOGIN_ALARM']}}</div>
|
||||
<div class="line-input">
|
||||
<div class="line-row">
|
||||
<a href="javascript:;" class="bt_warning setAlarmMail">{{data['lan']['EMAIL_NOT_SET']}}</a>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success btn-xs setAlarmMailBtn">{{data['lan']['CONFIG']}}</button>
|
||||
</div>
|
||||
<div class="line-row-tips">{{data['lan']['LOGIN_ALARM_DESC']}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setbox bgw mtb15">
|
||||
<div class="title c6 plr15">
|
||||
<h3 class="f16">{{data['lan']['C1']}}</h3>
|
||||
<button class="btn btn-default btn-sm" style="float: right;margin-top: 10px;display: none;" onclick="apiSetup()">{{data['lan']['C2']}}</button>
|
||||
</div>
|
||||
<div class="info-title-tips" style="margin: 20px 30px 0px;">
|
||||
<p><span class="glyphicon glyphicon-alert" style="color: #f39c12; margin-right: 10px;"></span>{{data['lan']['C3']}}</p>
|
||||
</div>
|
||||
<div class="setting-con pd15">
|
||||
<form id="set-Config">
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="{{data['lan']['CT1']}}">{{data['lan']['CT1']}}</span>
|
||||
<input id="webname" name="webname" class="inputtxt bt-input-text" type="text" value="{{session['title']}}">
|
||||
<span class="set-info c7">{{data['lan']['CY1']}}</span>
|
||||
</div>
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="{{data['lan']['CT2']}}">{{data['lan']['CT2']}}</span>
|
||||
<div class="btn_tips">
|
||||
<input id="banport" name="port" class="inputtxt bt-input-text disable" type="number" value="{{data['panel']['port']}}" maxlength="5" disabled>
|
||||
<span class="modify btn btn-xs btn-success" onclick="modify_port_val({{data['panel']['port']}})">{{data['lan']['CY10']}}</span>
|
||||
</div>
|
||||
<span class="set-info c7">{{data['lan']['CY2']}}, <a style="color:red;">{{data['lan']['S_PORT_TIPS']}}</a></span>
|
||||
</div>
|
||||
<!-- <div class="mtb15">-->
|
||||
<!-- <span class="set-tit text-right" title="{{data['lan']['panel_performance']}}">{{data['lan']['concurrent_thread']}}</span>-->
|
||||
<!-- <input name="workers" class="inputtxt bt-input-text" type="number" min="1" max="1024" value="{{data['workers']}}">-->
|
||||
<!-- <span class="set-info c7">{{data['lan']['thread_ps']}}</span>-->
|
||||
<!-- </div>-->
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="{{data['lan']['LOGINTIMEOUT']}}">{{data['lan']['TIMEOUT']}}</span>
|
||||
<input name="session_timeout" class="inputtxt bt-input-text" type="number" value="{{data['session_timeout']}}">
|
||||
<span class="set-info c7">{{data['lan']['CY13']}}<a style="color:red;">{{data['session_timeout']}}</a>{{data['lan']['CY14']}}</span>
|
||||
</div>
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="{{data['lan']['CT2']}}">{{data['lan']['S_ENTRY']}}</span>
|
||||
<div class="btn_tips">
|
||||
<input id="admin_path" name="admin_path" class="inputtxt bt-input-text disable" type="text" value="{{data['panel']['admin_path']}}" disabled />
|
||||
<span class="modify btn btn-xs btn-success" onclick="modify_auth_path()">{{data['lan']['CY10']}}</span>
|
||||
</div>
|
||||
<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>
|
||||
<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="Notification">Notification</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="MessageChannelSettings()">Set</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="Login panel alarm">Login panel alarm</span>
|
||||
<div class="btn_tips">
|
||||
<input id="panel_report" name="panel_report" class="inputtxt bt-input-text disable" type="text" value="" disabled>
|
||||
<span class="modify btn btn-xs btn-success panel_report" onclick="set_panel_report()">Set</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="{{data['lan']['CT3']}}">{{data['lan']['CT3']}}</span>
|
||||
<input name="domain" class="inputtxt bt-input-text" type="text" value="{{data['panel']['domain']}}">
|
||||
<span class="set-info c7">{{data['lan']['CY3']}}</span>
|
||||
</div>
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="{{data['lan']['CT4']}}">{{data['lan']['CT4']}}</span>
|
||||
<input name="limitip" class="inputtxt bt-input-text" type="text" value="{{data['panel']['limitip']}}">
|
||||
<span class="set-info c7">{{data['lan']['CY4']}}</span>
|
||||
</div>
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="{{data['lan']['CT5']}}">{{data['lan']['CT5']}}</span>
|
||||
<input name="sites_path" class="inputtxt bt-input-text" type="text" value="{{data['sites_path']}}">
|
||||
<span class="set-info c7">{{data['lan']['CY5']}}</span>
|
||||
</div>
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="{{data['lan']['CT6']}}">{{data['lan']['CT6']}}</span>
|
||||
<input name="backup_path" class="inputtxt bt-input-text" type="text" value="{{data['backup_path']}}">
|
||||
<span class="set-info c7">{{data['lan']['CY6']}}</span>
|
||||
</div>
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="{{data['lan']['CT7']}}">{{data['lan']['CT7']}}</span>
|
||||
<input name="address" class="inputtxt bt-input-text" type="text" value="{{data['panel']['address']}}">
|
||||
<span class="set-info c7">{{data['lan']['CY7']}}</span>
|
||||
</div>
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="{{data['lan']['CT8']}}">{{data['lan']['CT8']}}</span>
|
||||
<div class="btn_tips">
|
||||
<input id="systemdate" name="systemdate" class="inputtxt bt-input-text disable" type="text" value="{{data['systemdate']}}">
|
||||
<!--span class="modify btn btn-xs btn-success" onclick="syncDate()">{{data['lan']['CY8']}}</span-->
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="{{data['lan']['CT9']}}">{{data['lan']['CT9']}}</span>
|
||||
<div class="btn_tips">
|
||||
<input name="username_" class="inputtxt bt-input-text disable" type="text" value="{{session['username']}}" disabled>
|
||||
<span class="modify btn btn-xs btn-success" onclick="setUserName()">{{data['lan']['CY9']}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mtb15">
|
||||
<span class="set-tit text-right" title="{{data['lan']['CT10']}}">{{data['lan']['CT10']}}</span>
|
||||
<div class="btn_tips">
|
||||
<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 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>-->
|
||||
</form>
|
||||
<div class="bt-submit set-submit">{{data['lan']['C4']}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.boxConter {
|
||||
height: 458px;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.iconCode {
|
||||
padding: 50px 60px;
|
||||
}
|
||||
|
||||
.box-conter {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#QRcode {
|
||||
margin-bottom: 25px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.iconCode #QRcode,
|
||||
.iconCode .codeTip {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.iconCode .weChatSamll img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.iconCode .weChatSamll {
|
||||
display: none;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
position: absolute;
|
||||
border: 1px solid #ececec;
|
||||
border-radius: 5px;
|
||||
bottom: 150px;
|
||||
right: 50px;
|
||||
.configure-box {
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.iconCode .weChatSamll:after {
|
||||
content: '';
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #ececec;
|
||||
border-right: 1px solid #ececec;
|
||||
transform: rotate(45deg);
|
||||
position: absolute;
|
||||
border-radius: 4px;
|
||||
left: 90px;
|
||||
bottom: -8px;
|
||||
}
|
||||
|
||||
.iconCode .weChat {
|
||||
margin-left: 15px;
|
||||
.configure-block > .line {
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
.iconCode .weChat:hover .weChatSamll {
|
||||
display: block;
|
||||
}
|
||||
.configure-block > .line:hover {
|
||||
background: #a5a5a514;
|
||||
transition: background .2s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.iconCode .QRcode {
|
||||
margin-bottom: 15px;
|
||||
.configure-title {
|
||||
line-height: 30px;
|
||||
font-size: 14px;
|
||||
border-bottom: 1px solid #e7e7e7;
|
||||
padding: 5px 5px 8px 10px;
|
||||
font-weight: bold;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.configure-box .configure-block {
|
||||
padding: 25px 0;
|
||||
}
|
||||
|
||||
.configure-box .line .line-title {
|
||||
font-size: 12px;
|
||||
color: #333;
|
||||
display: inline-block;
|
||||
width: 160px;
|
||||
text-align: right;
|
||||
padding-right: 15px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.configure-box .line input[type="text"] {
|
||||
width: 260px;
|
||||
}
|
||||
|
||||
.configure-box .line .line-tips {
|
||||
margin-top: 5px;
|
||||
color: #999;
|
||||
margin-left: 135px;
|
||||
}
|
||||
|
||||
.configure-box .line > button {
|
||||
height: 30px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.configure-box .line .line-input input,
|
||||
.configure-box .line .line-form input {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.configure-box .line .line-input {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.configure-box .line .line-form {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.configure-box .line .line-form .ssh-item {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
float: none;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.line-row, .line-row-tips {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.line-row-tips {
|
||||
margin-left: 10px !important;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.bt_warning {
|
||||
color: #fc6d26;
|
||||
}
|
||||
|
||||
.line-split {
|
||||
border-bottom: 1px #ececec dashed;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.selected-file {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
width: 40px;
|
||||
text-align: center;
|
||||
background: #fafafa;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
border: 1px solid #cccccc;
|
||||
border-top-right-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.codeTip ul li {
|
||||
margin-bottom: 10px;
|
||||
.btn-success[disabled] {
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.personalDetails .head_img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
float: left;
|
||||
margin-right: 30px;
|
||||
.info-title-tips {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 25px;
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
.personalDetails .head_img img {
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.personalDetails .nick_name {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
width: 148px;
|
||||
float: left;
|
||||
font-size: 15px;
|
||||
color: #808080;
|
||||
.download_Qcode {
|
||||
overflow: hidden;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.personalDetails .userList {
|
||||
.download_Qcode .item_down {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
border-right: 1px solid #ececee;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.download_Qcode .item_down:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.download_Qcode .qcode_title {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.download_Qcode .item_down img {
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.create_temp_view {
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.create_temp_view .line .tname {
|
||||
text-align: left;
|
||||
float: inherit;
|
||||
}
|
||||
|
||||
.create_temp_view .info-r {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.info-block {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.personalDetails .userList .addweChat {
|
||||
height: 50px;
|
||||
text-align: center;
|
||||
padding-top: 20px;
|
||||
color: #20a53a;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.personalDetails .userList .item {
|
||||
height: 70px;
|
||||
padding: 10px 15px;
|
||||
border: 1px solid #ececec;
|
||||
margin: 15px 65px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.personalDetails .userList .cancelBind {
|
||||
height: 50px;
|
||||
width: 60px;
|
||||
float: right;
|
||||
line-height: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
.verify_title{
|
||||
.verify_title {
|
||||
color: #555;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
@@ -333,15 +552,37 @@
|
||||
line-height: 40px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.verify_item{
|
||||
|
||||
.verify_item {
|
||||
padding: 0 35px;
|
||||
}
|
||||
.verify_item .verify_vice_title{
|
||||
|
||||
.verify_item .verify_vice_title {
|
||||
font-size: 15.5px;
|
||||
color: #666;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.verify_tips{
|
||||
|
||||
.verify_box {
|
||||
background: #f8f8f8;
|
||||
padding: 15px 25px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.verify_box .verify_box_line {
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
font-size: 14px;
|
||||
color: #444;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.verify_box .verify_box_line span {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.verify_tips {
|
||||
margin: 0 15px;
|
||||
margin-top: 25px;
|
||||
padding: 20px 25px;
|
||||
@@ -349,76 +590,27 @@
|
||||
color: #666;
|
||||
border-top: 1px solid #ececec;
|
||||
}
|
||||
.verify_tips p{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.verify_box{
|
||||
background: #f8f8f8;
|
||||
padding: 15px 25px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 4px;
|
||||
/* width: 200px; */
|
||||
}
|
||||
.verify_box .verify_box_line{
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
font-size: 14px;
|
||||
color: #444;
|
||||
font-weight: 500;
|
||||
}
|
||||
.verify_box .verify_box_line span{
|
||||
color: #666;
|
||||
}
|
||||
.google_verify ul li{
|
||||
height: auto;
|
||||
line-height: 18px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.risk_form{
|
||||
|
||||
|
||||
.bt-w-menu {
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
.risk_form ul{
|
||||
border: 1px solid #ececec;
|
||||
border-radius: 10px;
|
||||
font-size:12px;
|
||||
margin: 0px auto;
|
||||
margin:15px 0;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
background: #f7f7f7;
|
||||
width: 100%;
|
||||
padding: 25px 40px;
|
||||
list-style-type: inherit;
|
||||
.bt-w-con {
|
||||
margin-left: 110px;
|
||||
}
|
||||
.risk_form ul li{
|
||||
line-height: 18px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.risk_tilte{
|
||||
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 %}
|
||||
{% block scripts %}
|
||||
<script src="/static/js/config.js?date12222={{g['version']}}"></script>
|
||||
<script type="text/javascript">
|
||||
setCookie('serverType',"{{session['webserver']}}");
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script src="{{g.cdn_url}}/js/jquery-1.10.2.min.js"></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/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}}/amd/require.min.js" data-main="{{g.cdn_url}}/amd/main"></script>
|
||||
<script>
|
||||
var sessionInfo = {
|
||||
title: "{{session['title']}}",
|
||||
username: "{{session['username']}}",
|
||||
statusCode: "{{data['status_code']}}"
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -141,6 +141,7 @@
|
||||
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script src="/static/js/echarts.min.js"></script>
|
||||
<script src="/static/js/control.js?date={{g['version']}}"></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -180,20 +180,53 @@
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.layer-create-content .layui-layer-content{
|
||||
overflow: inherit;
|
||||
}
|
||||
.layer-create-content .layui-layer-content {
|
||||
overflow: inherit;
|
||||
}
|
||||
.textname i.form-checkbox {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.textname i.form-checkbox.active {
|
||||
background-color: #20a53a;
|
||||
border-color: #20a53a;
|
||||
}
|
||||
.textname i.form-checkbox.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
display: block;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-left: -2.5px;
|
||||
margin-top: -6px;
|
||||
width: 5px;
|
||||
height: 10px;
|
||||
border: solid #fff;
|
||||
border-width: 0 2px 2px 0;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.textname .form-checkbox-label {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="/static/js/crontab.js?date20200106={{g['version']}}"></script>
|
||||
<script type="text/javascript">
|
||||
setCookie('serverType',"{{session['webserver']}}");
|
||||
toWeek();
|
||||
toHour();
|
||||
toMinute();
|
||||
toShell();
|
||||
getCronData();
|
||||
</script>
|
||||
{{ super() }}
|
||||
<script src="/static/js/crontab.js?date20200106={{g['version']}}"></script>
|
||||
<script type="text/javascript">
|
||||
setCookie('serverType', "{{session['webserver']}}");
|
||||
toWeek();
|
||||
toHour();
|
||||
toMinute();
|
||||
toShell();
|
||||
getCronData();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -4,16 +4,9 @@
|
||||
|
||||
<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">
|
||||
<form target="hid" onsubmit='return false;'>
|
||||
<input type="text" id="SearchValue" class="ser-text pull-left" placeholder="{{data['lan']['SEARCH']}}" />
|
||||
<button type="button" class="ser-sub pull-left" onclick='database.database_table_view($("#SearchValue").val())'></button>
|
||||
</form>
|
||||
<iframe name='hid' id="hid" style="display:none"></iframe>
|
||||
<div class="pos-box bgw mtb15 ">
|
||||
<div class="tab-list">
|
||||
<div class="tabs-item active">{{data['lan']['H2']}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="safe bgw mtb15 pd15">
|
||||
@@ -26,28 +19,35 @@
|
||||
</div>
|
||||
<form id="toPHPMyAdmin" public-data="{{session['phpmyadminDir']}}/index.php" action="{{session['phpmyadminDir']}}/index.php" method="post" style="display: none;" target="_blank">
|
||||
<input type="text" name="pma_username" id="pma_username" value="" />
|
||||
<input type="password" name="pma_password" id="pma_password" value="" />
|
||||
<input type="text" name="server" value="1" />
|
||||
<input type="text" name="target" value="index.php" />
|
||||
<input type="text" name="db" id="db" value="" />
|
||||
<input type="password" name="pma_password" id="pma_password" value=""/>
|
||||
<input type="text" name="server" value="1"/>
|
||||
<input type="text" name="target" value="index.php"/>
|
||||
<input type="text" name="db" id="db" value=""/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="text/javascript" src="/static/js/bt_upload.js?version={{g['version']}}"></script>
|
||||
<script src="/static/js/database.js?date={{g['version']}}"></script>
|
||||
<script type="text/javascript">
|
||||
bt.set_cookie('backup_path', "{{session['config']['backup_path']}}");
|
||||
|
||||
{% if not data['isSetup'] %}
|
||||
layer.msg('{{data["lan"]["JS1"]}}<a href="/soft#i" style="color:#20a53a;float: right;">{{data["lan"]["JS2"]}}</a>',{icon:7,shade: [0.3, '#000'],time:0});
|
||||
$(".layui-layer-shade").css("margin-left", "180px");
|
||||
{% else %}
|
||||
|
||||
var isSetup = true;
|
||||
{% if not data['isSetup'] %}
|
||||
// layer.msg('{{data["lan"]["JS1"]}}<a href="/soft#i" style="color:#20a53a;float: right;">{{data["lan"]["JS2"]}}</a>', {
|
||||
// icon: 7,
|
||||
// shade: [0.3, '#000'],
|
||||
// time: 0
|
||||
// });
|
||||
// $(".layui-layer-shade").css("margin-left", "180px");
|
||||
// layer.msg('{{data["lan"]["NOT_INSTALL_DATABASE_DESC"]}}', { time: 2000 });
|
||||
isSetup = false;
|
||||
// {% else %}
|
||||
// database.get_list();
|
||||
{% endif %}
|
||||
|
||||
</script>
|
||||
<script src="/static/js/upload.js?date={{g['version']}}"></script>
|
||||
{% endblock %}
|
||||
@@ -1017,7 +1017,7 @@ td {
|
||||
<!--<ul class="bg-bubbles"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul>-->
|
||||
<div class="div-center">
|
||||
<div class="file-down-header">
|
||||
<div class="file-name">Share file【 <span style="font-size:14px;">{{data.filename}} </span> 】</div>
|
||||
<div class="file-name">Share file [ <span style="font-size:14px;">{{data.filename}} </span> ]</div>
|
||||
<div class="file-validity-time">Term of validity:{{data.expire}}</div>
|
||||
</div>
|
||||
{% if not data['PATH'] %}
|
||||
@@ -1282,7 +1282,7 @@ td {
|
||||
layer.open({
|
||||
type: 1,
|
||||
closeBtn: 1,
|
||||
title: 'Preview pictures【'+fileName+'】',
|
||||
title: 'Preview pictures [ '+fileName+' ]',
|
||||
area: area,
|
||||
shadeClose: true,
|
||||
content: '<div class="showpicdiv"><img width="100%" src="' + imgUrl + '"></div>'
|
||||
|
||||
@@ -7,7 +7,5 @@
|
||||
<body>
|
||||
<h1>{1}</h1>
|
||||
<p>{2}</p>
|
||||
<hr>
|
||||
<address>{3} <a href="https://forum.aapanel.com/" target="_blank">{4}</a></address>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,15 +1,283 @@
|
||||
{% extends "layout.html" %}
|
||||
{% block content %}
|
||||
<style>
|
||||
.pos-box {
|
||||
height: auto;
|
||||
}
|
||||
.control-item {
|
||||
display: inline-block;
|
||||
height: 45px;
|
||||
min-width: 100px;
|
||||
padding: 0 20px;
|
||||
line-height: 45px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
.control-item.active {
|
||||
color: #20a53a;
|
||||
background: #20a53a10;
|
||||
}
|
||||
.daily-thumbnail{
|
||||
width: 1200px;
|
||||
margin: 80px auto;
|
||||
}
|
||||
.thumbnail-box{
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.thumbnail-introduce{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.thumbnail-introduce span{
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.thumbnail-introduce ul {
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
line-height: 30px;
|
||||
margin: 20px 0;
|
||||
list-style-type: square;
|
||||
}
|
||||
.thumbnail-introduce ul li + li {
|
||||
margin-left: 40px;
|
||||
}
|
||||
.pluginTipsGg {
|
||||
position: relative;
|
||||
width: 950px;
|
||||
height: 678px;
|
||||
background-color: #f1f1f1;
|
||||
background-size: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: top;
|
||||
border: 1px solid #f2f2f2;
|
||||
border-radius: 4px;
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
}
|
||||
/*.pluginTipsGg:hover::before{*/
|
||||
/* display: inline-block;*/
|
||||
/*}*/
|
||||
.pluginTipsGg::before {
|
||||
content: '点击预览';
|
||||
display: none;
|
||||
background: #000;
|
||||
opacity: 0.2;
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
line-height: 621px;
|
||||
font-size: 18px;
|
||||
vertical-align: bottom;
|
||||
text-align: center;
|
||||
border-radius: 4px;
|
||||
transition: all 1s;
|
||||
}
|
||||
.tab-list .tabs-item.active:after {
|
||||
content: '';
|
||||
width: 20px;
|
||||
height: 2px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 0px;
|
||||
background: red;
|
||||
margin-left: -10px;
|
||||
background: #20a53a;
|
||||
}
|
||||
.thumbnail-box .thumbnail-tab {
|
||||
margin-right: 20px;
|
||||
width: 120px;
|
||||
border-left: 1px solid #def2e2;
|
||||
}
|
||||
.thumbnail-tab li {
|
||||
padding: 0 20px;
|
||||
line-height: 36px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
}
|
||||
.thumbnail-tab li.on {
|
||||
border-left: 2px solid #20a53a;
|
||||
color: #20a53a;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.thumbnail-item {
|
||||
display: none;
|
||||
}
|
||||
.thumbnail-item.show {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<div class="main-content pb55" style="min-height: 525px;">
|
||||
<div class="container-fluid">
|
||||
<div class="site_table_view bgw mtb15 pd15">
|
||||
<div style="padding: 40px;background: #f8f8f8;text-align: center;vertical-align: middle;">
|
||||
<h1 style="font-size: 37px;">Sorry, you need to meet the following conditions to use:</h1>
|
||||
<p style="font-size: 20px;margin-top: 38px;color: red;">Please upgrade Nginx firewall version to 7.8.0 or above</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
{% if 'error_msg' in data %}
|
||||
<div class="pos-box bgw mtb15">
|
||||
<div class="control-nav">
|
||||
<div class="control-item active" name="control">aaPanel WAF</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mtb15 pd15 bgw daily-view">
|
||||
<div class="info-title-tips">
|
||||
<p><span class="glyphicon glyphicon-alert" style="color: #f39c12; margin-right: 10px;"></span>Tip: This page can be turned off in the panel settings</p>
|
||||
</div>
|
||||
<div class="daily-thumbnail">
|
||||
<div class="thumbnail-introduce">
|
||||
<span>Nginx WAF function introduction</span>
|
||||
<ul>
|
||||
<li>Only supports Nginx</li>
|
||||
<li>Defend against CC attacks</li>
|
||||
<li>Keyword blocking</li>
|
||||
<li>Block malicious scans</li>
|
||||
<li>Stop hackers</li>
|
||||
</ul>
|
||||
<div class="daily-product-buy">
|
||||
<a title="Buy professional" href="javascript:;" class="btn btn-success va0 ml15 payPlugin">Buy now</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="thumbnail-box">
|
||||
<ul class="thumbnail-tab">
|
||||
<li class="on">Overview</li>
|
||||
<li>Report</li>
|
||||
<li>Global</li>
|
||||
<li>WebSite</li>
|
||||
<li>Blockade</li>
|
||||
</ul>
|
||||
<div class="thumbnail-item show">
|
||||
<div class="pluginTipsGg" style="background-image: url(/static/img/nginx_firewall/1.png);"></div>
|
||||
</div>
|
||||
<div class="thumbnail-item">
|
||||
<div class="pluginTipsGg" style="background-image: url(/static/img/nginx_firewall/2.png);"></div>
|
||||
</div>
|
||||
<div class="thumbnail-item">
|
||||
<div class="pluginTipsGg" style="background-image: url(/static/img/nginx_firewall/3.png);"></div>
|
||||
</div>
|
||||
<div class="thumbnail-item">
|
||||
<div class="pluginTipsGg" style="background-image: url(/static/img/nginx_firewall/4.png);"></div>
|
||||
</div>
|
||||
<div class="thumbnail-item">
|
||||
<div class="pluginTipsGg" style="background-image: url(/static/img/nginx_firewall/5.png);"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="pos-box bgw mtb15">
|
||||
<div class="control-nav">
|
||||
<div class="control-item active" name="control">aaPanel WAF</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mtb15 pd15 bgw daily-view">
|
||||
<div class="info-title-tips">
|
||||
<p><span class="glyphicon glyphicon-alert" style="color: #f39c12; margin-right: 10px;"></span>Tip: This page can be turned off in the panel settings</p>
|
||||
</div>
|
||||
<div class="daily-thumbnail">
|
||||
<div class="thumbnail-introduce">
|
||||
<span>Nginx WAF function introduction</span>
|
||||
<ul>
|
||||
<li>Only supports Nginx</li>
|
||||
<li>Defend against CC attacks</li>
|
||||
<li>Keyword blocking</li>
|
||||
<li>Block malicious scans</li>
|
||||
<li>Stop hackers</li>
|
||||
</ul>
|
||||
<div class="daily-product-buy">
|
||||
<a title="Buy professional" href="javascript:;" class="btn btn-success va0 ml15 payPlugin">Buy now</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="thumbnail-box">
|
||||
<ul class="thumbnail-tab">
|
||||
<li class="on">Overview</li>
|
||||
<li>Report</li>
|
||||
<li>Global</li>
|
||||
<li>WebSite</li>
|
||||
<li>Blockade</li>
|
||||
</ul>
|
||||
<div class="thumbnail-item show">
|
||||
<div class="pluginTipsGg" style="background-image: url(/static/img/nginx_firewall/1.png);"></div>
|
||||
</div>
|
||||
<div class="thumbnail-item">
|
||||
<div class="pluginTipsGg" style="background-image: url(/static/img/nginx_firewall/2.png);"></div>
|
||||
</div>
|
||||
<div class="thumbnail-item">
|
||||
<div class="pluginTipsGg" style="background-image: url(/static/img/nginx_firewall/3.png);"></div>
|
||||
</div>
|
||||
<div class="thumbnail-item">
|
||||
<div class="pluginTipsGg" style="background-image: url(/static/img/nginx_firewall/4.png);"></div>
|
||||
</div>
|
||||
<div class="thumbnail-item">
|
||||
<div class="pluginTipsGg" style="background-image: url(/static/img/nginx_firewall/5.png);"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="text/javascript">
|
||||
bt.send('get_soft_find', 'plugin/get_soft_find', {
|
||||
sName: 'btwaf'
|
||||
}, function (res) {
|
||||
if (res.endtime >= 0) {
|
||||
$('.payPlugin').after('<a href="javascript:;" class="btn btn-success va0 ml15 installWaf">Install now</a>');
|
||||
$('.payPlugin').remove();
|
||||
}
|
||||
});
|
||||
|
||||
$('.daily-product-buy').on('click', '.installWaf', function(){
|
||||
bt.soft.install('btwaf');
|
||||
// change_install_success();
|
||||
});
|
||||
|
||||
$('.payPlugin').on('click',function(){
|
||||
bt.soft.get_soft_find('btwaf',function(rdata){
|
||||
bt.soft.product_pay_view({"name":rdata.title,"pid":rdata.pid,"type":rdata.type,"plugin":true,"ps":rdata.ps, 'totalNum': 25});
|
||||
setTimeout(function(){
|
||||
$('.lib_ltd').click();
|
||||
},500);
|
||||
});
|
||||
});
|
||||
|
||||
$('.thumbnail-tab li').click(function () {
|
||||
var index = $(this).index();
|
||||
$(this).addClass('on').siblings('.on').removeClass('on');
|
||||
$('.thumbnail-item').eq(index).addClass('show').siblings('.show').removeClass('show');
|
||||
});
|
||||
|
||||
function change_install_success() {
|
||||
var timer = setInterval(function () {
|
||||
bt.send('get_soft_find', 'plugin/get_soft_find', {
|
||||
sName: 'btwaf'
|
||||
}, function (res) {
|
||||
if (res.setup) {
|
||||
clearInterval(timer);
|
||||
setTimeout(function () {
|
||||
location.reload();
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
// $('.thumbnail-box').on('click',function(){
|
||||
// layer.open({
|
||||
// title:false,
|
||||
// btn:false,
|
||||
// shadeClose:true,
|
||||
// closeBtn: 2,
|
||||
// area:['950px','725px'],
|
||||
// content:'<div class="pd10"><img src="/static/img/btwaf-nginx.png" style="width:100%"/></div>'
|
||||
// })
|
||||
// })
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -38,7 +38,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="file_nav_view">
|
||||
<div class="file_nav_view clearfix">
|
||||
<div class="nav_group">
|
||||
<div class="nav_btn upload_file">
|
||||
<span class="nav_btn_title">Upload</span>
|
||||
@@ -403,15 +403,15 @@
|
||||
<ul></ul>
|
||||
</div>
|
||||
<div class="menu-item menu-setUp" style="display: none;">
|
||||
<div class="menu-title">Editor setting【Some settings need to be restart editor】</div>
|
||||
<div class="menu-title">Editor setting [ Some settings need to be restart editor ]</div>
|
||||
<ul class="editor_menu">
|
||||
<li data-type="wrap">Auto wrap</li>
|
||||
<li data-type="enableLiveAutocompletion">Code autocomplete</li>
|
||||
<li data-type="enableSnippets">Enable snippets</li>
|
||||
<li data-type="showInvisibles">Show hidden characters</li>
|
||||
<li data-type="showLineNumbers">Show line numbers</li>
|
||||
|
||||
</ul>
|
||||
<li data-type="showLineNumbers">Show line numbers</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -419,13 +419,19 @@
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<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.js?version={{g['version']}}&repair={{data['js_random']}}"></script>
|
||||
{{ super() }}
|
||||
<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.js?version={{g['version']}}&repair={{data['js_random']}}"></script>
|
||||
<script type="text/javascript"
|
||||
src="{{g.cdn_url}}/js/upload-drog.js?version={{g['version']}}&repair={{data['js_random']}}"></script>
|
||||
{% endblock %}
|
||||
@@ -61,16 +61,22 @@
|
||||
font-family: Courier New;
|
||||
font-size: 12px;
|
||||
}
|
||||
.security_detail pre {
|
||||
white-space: pre-wrap;
|
||||
white-space: -moz-pre-wrap;
|
||||
white-space: -pre-wrap;
|
||||
white-space: -o-pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.detail_tips {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.security_detail pre {
|
||||
white-space: pre-wrap;
|
||||
white-space: -moz-pre-wrap;
|
||||
white-space: -pre-wrap;
|
||||
white-space: -o-pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.detail_tips {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.setchmod {
|
||||
padding-top: 0;
|
||||
}
|
||||
</style>
|
||||
<div class="main-content">
|
||||
<div class="container-fluid" style="padding-bottom: 50px;">
|
||||
@@ -80,7 +86,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="safe container-fluid bgw mtb15 pd15">
|
||||
<div class="mr50 pull-left">
|
||||
<div class="mr20 pull-left">
|
||||
<form>
|
||||
<div class="ss-text pull-left">
|
||||
<em>{{data['lan']['BTN1']}}</em>
|
||||
@@ -90,7 +96,7 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="mr50 pull-left">
|
||||
<div class="mr20 pull-left">
|
||||
<div class="ss-text pull-left mr5">
|
||||
<em>{{data['lan']['BTN2']}}</em>
|
||||
<input type="text" class="bt-input-text" id="mstscPort" value="" />
|
||||
@@ -160,8 +166,8 @@
|
||||
|
||||
</table>
|
||||
</div>
|
||||
<div class="dataTables_paginate paging_bootstrap page logsBody" style="margin-bottom:0">
|
||||
</div>
|
||||
<div class="dataTables_paginate paging_bootstrap page logsBody" style="margin-bottom:0">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -171,16 +177,17 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="text/javascript">
|
||||
|
||||
var firewall = {
|
||||
ssl_scanning_list: [], //扫描列表
|
||||
on_search:function(){
|
||||
firewall.get_log_list(1,$('.search_input').val());
|
||||
|
||||
var firewall = {
|
||||
ssl_scanning_list: [], //扫描列表
|
||||
on_search: function () {
|
||||
firewall.get_log_list(1, $('.search_input').val());
|
||||
},
|
||||
get_init:function(){
|
||||
firewall.flush_init();
|
||||
firewall.get_list();
|
||||
get_init: function () {
|
||||
firewall.flush_init();
|
||||
firewall.get_list();
|
||||
firewall.get_log_list();
|
||||
firewall.get_logs_size();
|
||||
$('.sshswitch').click(function(){
|
||||
@@ -314,14 +321,14 @@
|
||||
<button class="btn btn-success btn-sm add_white_ip" type="button">Add IP white list</button>\
|
||||
<div class="pull-right ssl_login_config_view"><span>Monitor root login</span><input class="btswitch btswitch-ios" id="ssh_root_login" type="checkbox"><label class="btswitch-btn" for="ssh_root_login" title="Monitor root login"></label></div>\
|
||||
<div class="divtable mtb15" style="max-height: 441px;overflow: auto;">\
|
||||
<table id="ssh_ip_white_table" class="table table-hover" style="min-width: 500px;border: 0 none;"></table>\
|
||||
<table id="ssh_ip_white_table" class="table table-hover" style="min-width: 500px;"></table>\
|
||||
</div>\
|
||||
<ul class="help-info-text c7">\
|
||||
<li>This list is an IP whitelist, and no alarm will be issued when these IPs log in</li>\
|
||||
</ul>\
|
||||
</div>\
|
||||
<div class="bt-box" style="display: none;">\
|
||||
<table id="ssh_logs_table" class="table table-hover" style="min-width: 500px;border: 0 none;"></table>\
|
||||
<table id="ssh_logs_table" class="table table-hover" style="min-width: 500px;"></table>\
|
||||
<div class="page">\
|
||||
<div id="ssh_logs"></div>\
|
||||
</div>\
|
||||
@@ -465,7 +472,7 @@
|
||||
var item = this.ssl_scanning_list[index];
|
||||
layer.open({
|
||||
type: 1,
|
||||
title:'View details【 '+ item.name +' 】',
|
||||
title:'View details [ '+ item.name +' ]',
|
||||
area: '500px',
|
||||
closeBtn:2,
|
||||
btn: ['Confirm'],
|
||||
@@ -700,7 +707,7 @@
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: '{{data["lan"]["PANEL_LOG"]}}',
|
||||
area: ['700px', '490px'],
|
||||
area: ['700px', '496px'],
|
||||
shadeClose: false,
|
||||
closeBtn: 2,
|
||||
content: '<div class="setchmod bt-form pb70">'
|
||||
|
||||
@@ -1,195 +1,387 @@
|
||||
{% 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;
|
||||
}
|
||||
#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">
|
||||
<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">
|
||||
<form target="hid" onsubmit='ftp.get_list(1,$("#SearchValue").prop("value"))'>
|
||||
<input type="text" id="SearchValue" class="ser-text pull-left" placeholder="{{data['lan']['SEARCH']}}" />
|
||||
<button type="button" class="ser-sub pull-left" onclick='ftp.get_list(1,$("#SearchValue").prop("value"))'></button>
|
||||
</form>
|
||||
<iframe name='hid' id="hid" style="display:none"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
<div class="safe bgw mtb15 pd15">
|
||||
<div class="info-title-tips">
|
||||
<p><span class="glyphicon glyphicon-alert" style="color: #f39c12; margin-right: 10px;"></span>{{data['lan']['PS']}} ftp://{{session['address']}}:{{session['port']}}</p>
|
||||
</div>
|
||||
<button onclick="ftp.add_user()" class="btn btn-success btn-sm" type="button">{{data['lan']['BTN1']}}</button>
|
||||
<button onclick="ftp.set_port()" class="btn btn-default btn-sm" type="button" style="margin-left:5px">{{data['lan']['BTN2']}}</button>
|
||||
<span style="float:right">
|
||||
<button batch="true" style="float: right;display: none;margin-left:10px;" onclick="ftp.batch_ftp('del');" class="btn btn-default btn-sm">{{data['lan']['BTN3']}}</button>
|
||||
</span>
|
||||
<div class="divtable mtb10">
|
||||
<div class="tablescroll">
|
||||
<table id="ftpData" class="table table-hover" style="min-width: 700px;border: 0 none;">
|
||||
</table>
|
||||
</div>
|
||||
<div class="dataTables_paginate paging_bootstrap page">
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
<form target="hid" onsubmit='ftp.get_list(1,$("#SearchValue").prop("value"))'>
|
||||
<input type="text" id="SearchValue" class="ser-text pull-left" placeholder="{{data['lan']['SEARCH']}}" />
|
||||
<button type="button" class="ser-sub pull-left" onclick='ftp.get_list(1,$("#SearchValue").prop("value"))'></button>
|
||||
</form>
|
||||
<iframe name='hid' id="hid" style="display:none"></iframe>
|
||||
</div> -->
|
||||
<div class="pos-box bgw mtb15">
|
||||
<div class="tab-list" id="cutMode">
|
||||
<div class="tabs-item active">{{data['lan']['H2']}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="safe bgw mtb15 pd15">
|
||||
<div class="info-title-tips">
|
||||
<p><span class="glyphicon glyphicon-alert" style="color: #f39c12; margin-right: 10px;"></span>{{data['lan']['PS']}} ftp://{{session['address']}}:{{session['port']}}</p>
|
||||
</div>
|
||||
<div id="bt_ftp_table"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script type="text/javascript">
|
||||
|
||||
var ftp = {
|
||||
get_list:function(page,search){
|
||||
if (page == undefined) page = 1;
|
||||
if (!search) search = $("#SearchValue").val();
|
||||
bt.ftp.get_list(page,search,function(rdata){
|
||||
$('.dataTables_paginate').html(rdata.page);
|
||||
var _tab = bt.render({
|
||||
table:'#ftpData',
|
||||
columns:[
|
||||
{ field:'id',type:'checkbox',width:30},
|
||||
{ field: 'name', title: lan.ftp.add_user,width:'20%'},
|
||||
{ field: 'password',width:'15%', title: lan.ftp.add_pass,templet : function(item){
|
||||
var _html = '<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.ftp.copy+'" data-pw="'+item.password+'" onclick="bt.pub.copy_pass(\''+item.password+'\')"></span>';
|
||||
return _html;
|
||||
}},
|
||||
{ field: 'status', title: lan.ftp.status,templet:function(item){
|
||||
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>';
|
||||
}
|
||||
else{
|
||||
_status+=' onclick="ftp.start_user('+item.id+',\''+item.name+'\')"';
|
||||
_status+='<span style="color:red">'+lan.ftp.stop+' </span><span style="color:red" class="glyphicon glyphicon-pause"></span>';
|
||||
}
|
||||
return _status;
|
||||
},sort:function(){
|
||||
ftp.get_list();
|
||||
}},
|
||||
{ field: 'path', title: lan.ftp.add_path,templet:function(item){
|
||||
var _path = bt.format_path(item.path);
|
||||
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 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> | ";
|
||||
option += "<a href=\"javascript:;\" class=\"btlink\" onclick=\"ftp.del("+item.id+",'"+item.name+"')\" title="+lan.ftp.del_ftp_title+">"+lan.ftp.del+"</a>";
|
||||
return option;
|
||||
}},
|
||||
],
|
||||
data:rdata.data
|
||||
});
|
||||
ftp.forSize();
|
||||
});
|
||||
},
|
||||
batch_ftp:function(type,arr,result){
|
||||
if(arr == undefined){
|
||||
arr = [];
|
||||
result = {count:0,error_list:[]};
|
||||
$('input[type="checkbox"].check:checked').each(function(){
|
||||
var _val = $(this).val();
|
||||
if(!isNaN(_val)) arr.push($(this).parents('tr').data('item'));
|
||||
})
|
||||
bt.show_confirm(lan.ftp.del_all,"<a style='color:red;'>"+lan.get('del_all_ftp',[arr.length])+"</a>",function(){
|
||||
bt.closeAll();
|
||||
ftp.batch_ftp(type,arr,result);
|
||||
});
|
||||
return;
|
||||
}
|
||||
var item = arr[0];
|
||||
switch(type){
|
||||
case 'del':
|
||||
if(arr.length<1){
|
||||
ftp.get_list();
|
||||
bt.msg({msg:lan.get('del_all_ftp_ok',[result.count]),icon:1,time:5000});
|
||||
return;
|
||||
}
|
||||
bt.ftp.del(item.id,item.name,function(rdata){
|
||||
if(rdata.status){
|
||||
result.count+=1;
|
||||
}else{
|
||||
result.error_list.push({name:item.item,err_msg:rdata.msg});
|
||||
}
|
||||
arr.splice(0,1)
|
||||
ftp.batch_ftp(type,arr,result);
|
||||
})
|
||||
break;
|
||||
}
|
||||
},
|
||||
del:function(id,ftp_username){
|
||||
bt.show_confirm(lan.public.del+"["+ftp_username+"]",lan.get('confirm_del',[ftp_username]),function(){
|
||||
bt.ftp.del(id,ftp_username,function(rdata){
|
||||
if(rdata.status) ftp.get_list();
|
||||
bt.msg(rdata);
|
||||
})
|
||||
})
|
||||
},
|
||||
add_user:function(){
|
||||
bt.ftp.add(function(rdata){
|
||||
if(rdata.status) ftp.get_list();
|
||||
})
|
||||
},
|
||||
set_password:function(id,name,password){
|
||||
var bs = bt.ftp.set_password(function(rdata){
|
||||
if(rdata.status) ftp.get_list();
|
||||
})
|
||||
$('.id'+bs).val(id);
|
||||
$('.ftp_username'+bs).val(name);
|
||||
$('.new_password'+bs).val(password);
|
||||
},
|
||||
set_port:function(){
|
||||
var bs = bt.ftp.set_port(function(rdata){
|
||||
if(rdata.status) ftp.get_list();
|
||||
})
|
||||
$('.port'+bs).val('{{session["port"]}}');
|
||||
},
|
||||
stop_user:function(id,username){
|
||||
bt.confirm({msg:lan.ftp.stop_confirm.replace('{1}',username),title:lan.ftp.stop_title},function(index){
|
||||
bt.ftp.set_status(id,username,0,function(rdata){
|
||||
if(rdata.status) ftp.get_list();
|
||||
})
|
||||
})
|
||||
},
|
||||
start_user:function(id,username){
|
||||
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());
|
||||
}
|
||||
}
|
||||
{{ super() }}
|
||||
<script>
|
||||
bt.set_cookie('sites_path',"{{session['config']['sites_path']}}");
|
||||
$(window).resize(function() {
|
||||
ftp.forSize();
|
||||
});
|
||||
{% if not data['isSetup'] %}
|
||||
|
||||
{% 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");
|
||||
{% else %}
|
||||
ftp.get_list();
|
||||
|
||||
{% endif %}
|
||||
{% else %}
|
||||
var ftp_table = bt_tools.table({
|
||||
el: '#bt_ftp_table',
|
||||
url: '/data?action=getData',
|
||||
param: { table: 'ftps' },
|
||||
minWidth: '1000px',
|
||||
autoHeight: true,
|
||||
pageName: 'ftp',
|
||||
default: lan.pythonmamager.no_data,
|
||||
sortParam: function (data) {
|
||||
return { 'order': data.name + ' ' + data.sort }
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* @description 设置FTP端口
|
||||
* @param {function} callback 回调函数
|
||||
* @return void
|
||||
*/
|
||||
add_ftp_user: function (callback) {
|
||||
var that = this;
|
||||
bt.ftp.add(function(rdata){
|
||||
if (callback) callback(rdata);
|
||||
if (rdata.status) that.$refresh_table_list(true);
|
||||
})
|
||||
},
|
||||
/**
|
||||
* @description 设置FTP端口
|
||||
* @param {object} obj 配置对象包含port
|
||||
* @param {function} callback 回调函数
|
||||
* @return void
|
||||
*/
|
||||
del_ftp_user: function (obj, callback) {
|
||||
var that = this;
|
||||
var msg = lan.public.del+"["+ obj.name +"]";
|
||||
var title = lan.get('confirm_del',[obj.name]);
|
||||
bt.show_confirm(msg, title, function () {
|
||||
bt.ftp.del(obj.id,obj.name, function (rdata) {
|
||||
if (callback) callback(rdata);
|
||||
bt.msg(rdata);
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @description 设置FTP密码
|
||||
* @param {object} obj 配置对象包含id、name、password
|
||||
* @param {function} callback 回调函数
|
||||
* @return void
|
||||
*/
|
||||
set_ftp_password: function (obj, callback) {
|
||||
var that = this,bs = bt.ftp.set_password(function(rdata){
|
||||
if(callback) callback(rdata);
|
||||
});
|
||||
$('.id'+bs).val(obj.id);
|
||||
$('.ftp_username'+bs).val(obj.name);
|
||||
$('.new_password'+bs).val(obj.password);
|
||||
},
|
||||
/**
|
||||
* @description 设置FTP端口
|
||||
* @param {object} obj 配置对象包含port
|
||||
* @param {function} callback 回调函数
|
||||
* @return void
|
||||
*/
|
||||
set_ftp_port: function (callback) {
|
||||
var bs = bt.ftp.set_port(function(rdata){
|
||||
if(callback) callback(rdata);
|
||||
if (rdata.status) {
|
||||
setTimeout(function () {
|
||||
window.location.reload()
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
$('.port' + bs).val('{{session["port"]}}');
|
||||
},
|
||||
/**
|
||||
* @description 设置ftp状态
|
||||
* @param {object} obj 配置对象包含id、username、status
|
||||
* @param {function} callback 回调函数
|
||||
* @return void
|
||||
*/
|
||||
set_ftp_status: function (obj, callback) {
|
||||
if (!parseInt(obj.status)) {
|
||||
bt.ftp.set_status(obj.id,obj.name,"1",function(rdata){
|
||||
if(callback) callback(rdata);
|
||||
});
|
||||
} else {
|
||||
bt.confirm({msg:lan.ftp.stop_confirm.replace('{1}',obj.name),title:lan.ftp.stop_title},function(index){
|
||||
bt.ftp.set_status(obj.id,obj.name,"0",function(rdata){
|
||||
if(callback) callback(rdata);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @description 设置路径
|
||||
* @param {object} row 配置对象包含id、username、status
|
||||
* @return void
|
||||
*/
|
||||
set_path: function (row, callback) {
|
||||
if (row == null) return;
|
||||
bt_tools.open({
|
||||
title: lan.ftp.change_ftp_user_home,
|
||||
area: '450px',
|
||||
btn: [lan.public.save, lan.public.cancel],
|
||||
content: {
|
||||
'class': 'pd20',
|
||||
form: [
|
||||
{
|
||||
label: lan.ftp.add_user,
|
||||
group: {
|
||||
type: 'text',
|
||||
name: 'ftp_username',
|
||||
width: '260px',
|
||||
value: row.name,
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
{
|
||||
label: lan.ftp.add_path,
|
||||
class: 'path_line',
|
||||
value: row.path,
|
||||
group: {
|
||||
type: 'text',
|
||||
name: 'path',
|
||||
width: '230px',
|
||||
icon: {
|
||||
type: 'glyphicon-folder-open',
|
||||
select: 'all',
|
||||
event: function (ev) {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
group: {
|
||||
type: 'help',
|
||||
style: {'margin-top': '0'},
|
||||
list: [
|
||||
lan.ftp.set_path_tips1,
|
||||
lan.ftp.set_path_tips2,
|
||||
lan.ftp.set_path_tips3
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
success: function () {
|
||||
$('.path_line').after('\
|
||||
<div class="line">\
|
||||
<span class="tname checkType">' + lan.ftp.migrate + '</span>\
|
||||
<div class="info-r" style="height:32px;margin-left:125px;padding-top:6px;">\
|
||||
<input type="checkbox" name="migrate" id="migrate" class="btswitch btswitch-ios">\
|
||||
<label for="migrate" class="btswitch-btn"></label>\
|
||||
</div>\
|
||||
</div>');
|
||||
$('input[name="path"]').val(row.path)
|
||||
},
|
||||
yes: function (form, index) {
|
||||
if (form.path === '') {
|
||||
return layer.msg('Please select a path', {icon: 2});
|
||||
}
|
||||
var loading = bt.load('Setting up, please wait...');
|
||||
var migrate = $('#migrate').is(':checked');
|
||||
var data = Object.assign({id: row.id, migrate: migrate ? 1 : 0}, form);
|
||||
bt.send('set_user_home', 'ftp/set_user_home', data, function (rdata) {
|
||||
loading.close();
|
||||
bt.msg(rdata);
|
||||
setTimeout(function () {
|
||||
if (!rdata.status) return;
|
||||
layer.close(index);
|
||||
callback && callback();
|
||||
}, 2000)
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
column: [
|
||||
{ type:'checkbox', width: 20 },
|
||||
{ fid: 'name', title: lan.ftp.add_user, type: 'text' },
|
||||
{
|
||||
fid: 'password',
|
||||
title: lan.ftp.add_pass,
|
||||
type: 'password',
|
||||
copy: true,
|
||||
eye_open: true
|
||||
},
|
||||
{
|
||||
fid: 'status',
|
||||
title: lan.ftp.status,
|
||||
sort: true,
|
||||
width: 100,
|
||||
type: 'status',
|
||||
config: {
|
||||
icon: true,
|
||||
list: [
|
||||
[ '1', lan.ftp.start, 'bt_success', 'glyphicon-play' ],
|
||||
[ '0', lan.ftp.stop, 'bt_danger', 'glyphicon-pause']
|
||||
]
|
||||
},
|
||||
event: function (row, index, ev, key, that) {
|
||||
that.set_ftp_status({
|
||||
id: row.id, status: row.status, name: row.name
|
||||
}, function (res) {
|
||||
if (res.status)
|
||||
that.$modify_row_data({ status: parseInt(row.status) ? '0' : '1' });
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
fid: 'path',
|
||||
title: lan.ftp.add_path,
|
||||
type: 'link',
|
||||
event: function (row, index, ev) {
|
||||
openPath(row.path);
|
||||
}
|
||||
},
|
||||
bt.public.get_quota_config('ftp'),
|
||||
{
|
||||
fid: 'ps',
|
||||
title: lan.ftp.add_ps,
|
||||
type: 'input',
|
||||
blur: function (row, index, ev) {
|
||||
bt.pub.set_data_ps({
|
||||
id: row.id, table: 'ftps', ps: ev.target.value
|
||||
}, function (res) {
|
||||
bt_tools.msg(res);
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: lan.ftp.operate,
|
||||
type: 'group',
|
||||
width: 170,
|
||||
align: 'right',
|
||||
group:[
|
||||
{
|
||||
title: 'Set Path',
|
||||
event: function (row, index, ev, key, that) {
|
||||
that.set_path(row, function () {
|
||||
that.$refresh_table_list(true);
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lan.ftp.edit_pass,
|
||||
event: function (row, index, ev, key, that) {
|
||||
that.set_ftp_password({
|
||||
id: row.id, name: row.name, password: row.password
|
||||
}, function (rdata) {
|
||||
if (rdata.status) that.$refresh_table_list(true);
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
title: lan.ftp.del,
|
||||
event: function (row, index, ev, key, that) {
|
||||
that.del_ftp_user({
|
||||
id: row.id, name: row.name
|
||||
}, function (res) {
|
||||
if (res.status) that.$refresh_table_list(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
tootls:[
|
||||
{
|
||||
type: 'group',
|
||||
positon: ['left', 'top'],
|
||||
list:[
|
||||
{
|
||||
title: 'Add FTP',
|
||||
active: true,
|
||||
event: function (ev, that) {
|
||||
that.add_ftp_user();
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Change FTP Port',
|
||||
event: function (ev, that) {
|
||||
that.set_ftp_port();
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'search',
|
||||
positon: ['right', 'top'],
|
||||
placeholder: 'FTP search',
|
||||
searchParam: 'search', // 搜索请求字段,默认为 search
|
||||
value: '', // 当前内容,默认为空
|
||||
},
|
||||
{ // 批量操作
|
||||
type: 'batch',
|
||||
positon: ['left', 'bottom'],
|
||||
config: {
|
||||
title: lan.ftp.del,
|
||||
url: '/ftp?action=DeleteUser',
|
||||
load: true,
|
||||
param: function (row) {
|
||||
return { id: row.id, username: row.name }
|
||||
},
|
||||
callback: function (that) {
|
||||
var msg = '<div style="color: red;">' + lan.get('del_all_ftp', [that.check_list.length]) + '</div>';
|
||||
bt.show_confirm(lan.ftp.del_all, msg, function () {
|
||||
that.start_batch({}, function (list) {
|
||||
var html = '';
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var item = list[i];
|
||||
html += '<tr><td>'+ item.name +'</td><td><div style="float:right;"><span style="color:'+ (item.request.status?'#20a53a':'red') +'">'+ item.request.msg +'</span></div></td></tr>';
|
||||
}
|
||||
ftp_table.$batch_success_table({
|
||||
title: 'Batch Delete FTP',
|
||||
th: 'FTP',
|
||||
html: html
|
||||
});
|
||||
ftp_table.$refresh_table_list(true);
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
{ // 分页显示
|
||||
type: 'page',
|
||||
positon: ['right','bottom'], // 默认在右下角
|
||||
pageParam: 'p', // 分页请求字段,默认为 : p
|
||||
page: 1, // 当前分页 默认:1
|
||||
numberParam: 'limit', //分页数量请求字段默认为 : limit
|
||||
number: 20, //分页数量默认 : 20条
|
||||
numberList: [10, 20, 50, 100, 200], // 分页显示数量列表
|
||||
numberStatus: true, // 是否支持分页数量选择,默认禁用
|
||||
jump: true, // 是否支持跳转分页,默认禁用
|
||||
}
|
||||
]
|
||||
});
|
||||
{% endif %}
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -69,28 +69,31 @@
|
||||
}
|
||||
</style>
|
||||
<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']['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>
|
||||
{% endif %}
|
||||
<!--<span class="bind-weixin c4"><a href="javascript:bt.weixin.open_wxapp();" class="btlink">{{data['lan']['WECHAT']}}</a></span>-->
|
||||
<span class="ico-system">{{data['lan']['S1']}}</span><span id="info" style="margin-left:10px;"> {{data['lan']['S2']}}</span>  {{data['lan']['S3']}} <span id="running">{{data['lan']['S4']}}</span>
|
||||
</div>
|
||||
<span class="pull-right f12 c6" style="line-height:52px; margin-right:15px">
|
||||
{{data['pd']|safe}}
|
||||
<span id="btversion" style="margin-right:10px">{{session['version']}}</span>
|
||||
<span id="toUpdate"><a class="btlink" href="javascript:index.check_update();">{{data['lan']['UPDATE']}}</a></span>
|
||||
<span style="margin:0 10px"><a class="btlink" href="javascript:index.re_panel();">{{data['lan']['FIX']}}</a></span>
|
||||
<span style="margin-right:10px"><a class="btlink" href="javascript:index.re_server();">{{data['lan']['RESTART']}}</a></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="container-fluid" style="padding-bottom: 66px;padding-left: 15px;">
|
||||
<div class="index-pos-box bgw mtb15">
|
||||
<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']['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>
|
||||
{% endif %}
|
||||
<!--<span class="bind-weixin c4"><a href="javascript:bt.weixin.open_wxapp();" class="btlink">{{data['lan']['WECHAT']}}</a></span>-->
|
||||
<span class="ico-system">{{data['lan']['S1']}}</span><span id="info" style="margin-left:10px;"> {{data['lan']['S2']}}</span>  {{data['lan']['S3']}} <span id="running">{{data['lan']['S4']}}</span>
|
||||
</div>
|
||||
<span class="pull-right f12 c6" style="line-height:52px; margin-right:15px">
|
||||
{{data['pd']|safe}}
|
||||
<span id="btversion" style="margin-right:10px">
|
||||
<a onclick="index.open_log()" style="cursor: pointer;">{{session['version']}}</a>
|
||||
</span>
|
||||
<span id="toUpdate"><a class="btlink" href="javascript:index.check_update();">{{data['lan']['UPDATE']}}</a></span>
|
||||
<span style="margin:0 10px"><a class="btlink" href="javascript:index.re_panel();">{{data['lan']['FIX']}}</a></span>
|
||||
<span style="margin-right:10px"><a class="btlink" href="javascript:index.re_server();">{{data['lan']['RESTART']}}</a></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-xs-24 col-sm-24 col-md-24" id="home-recommend"></div>
|
||||
<div class="danger-tips">
|
||||
<div class="important-title" id="messageError" style="display: none; margin-top:15px"></div>
|
||||
</div>
|
||||
@@ -249,7 +252,7 @@
|
||||
|
||||
|
||||
{% block scripts %}
|
||||
|
||||
{{ super() }}
|
||||
<script type="text/javascript" src="/static/js/jquery.dragsort-0.5.2.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/echarts.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/index.js?f2={{g['version']}}"></script>
|
||||
|
||||
@@ -1,141 +1,152 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="referer" content="never" />
|
||||
<meta name="renderer" content="webkit">
|
||||
<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?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>
|
||||
<![endif]-->
|
||||
<style>
|
||||
.top-tips {
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
color: red;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
z-index: 999;
|
||||
background-color: white;
|
||||
text-align: center;
|
||||
line-height: 50px;
|
||||
font-size: 20px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
font-weight: bold;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.contextmenu {
|
||||
position: absolute;
|
||||
width: 120px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
z-index: 99999999;
|
||||
}
|
||||
|
||||
.contextmenu li {
|
||||
border-left: 3px solid transparent;
|
||||
transition: ease 0.3s;
|
||||
}
|
||||
|
||||
.contextmenu li:hover {
|
||||
background: #707070;
|
||||
border-left: 3px solid #333;
|
||||
}
|
||||
|
||||
.contextmenu li a {
|
||||
display: block;
|
||||
padding: 5px 10px;
|
||||
color: #000000;
|
||||
text-decoration: none;
|
||||
transition: ease 0.3s;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.contextmenu li:hover a {
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="referer" content="never" />
|
||||
<meta name="renderer" content="webkit">
|
||||
<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}}/codemirror/lib/codemirror.css?20191127={{g['version']}}" rel="stylesheet" />
|
||||
<link href="{{g.cdn_url}}/css/site.css?version={{g['version']}}&repair={{data['js_random']}}" rel="stylesheet" />
|
||||
{% for css_f in g['other_css'] %}
|
||||
<link href="{{css_f}}" rel="stylesheet" />
|
||||
{% endfor %}
|
||||
<!--[if lte IE 9]>
|
||||
<script src="/static/js/requestAnimationFrame.js"></script>
|
||||
<![endif]-->
|
||||
<style>
|
||||
.contextmenu {
|
||||
position: absolute;
|
||||
width: 120px;
|
||||
background: #FFFFFF;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
z-index: 99999999;
|
||||
}
|
||||
|
||||
.contextmenu li {
|
||||
border-left: 3px solid transparent;
|
||||
transition: ease 0.3s;
|
||||
}
|
||||
|
||||
.contextmenu li:hover {
|
||||
background: #707070;
|
||||
border-left: 3px solid #333;
|
||||
}
|
||||
|
||||
.contextmenu li a {
|
||||
display: block;
|
||||
padding: 5px 10px;
|
||||
color: #000000;
|
||||
text-decoration: none;
|
||||
transition: ease 0.3s;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.contextmenu li:hover a {
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
var recycle_bin_db_open = !!{{g['recycle_bin_db_open']}},recycle_bin_open = !!{{g['recycle_bin_open']}}
|
||||
var ie_version = (function() {
|
||||
var userAgent = navigator.userAgent,
|
||||
isLessIE11 = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1,
|
||||
isEdge = userAgent.indexOf('Edge') > -1 && !isLessIE11,
|
||||
isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1;
|
||||
if (isLessIE11) {
|
||||
var IEReg = new RegExp('MSIE (\\d+\\.\\d+);');
|
||||
IEReg.test(userAgent);
|
||||
var IEVersionNum = parseFloat(RegExp['$1']);
|
||||
if (IEVersionNum === 7) {// IE7
|
||||
return 7
|
||||
} else if (IEVersionNum === 8) {// IE8
|
||||
return 8
|
||||
} else if (IEVersionNum === 9) {// IE9
|
||||
return 9
|
||||
} else if (IEVersionNum === 10) { // IE10
|
||||
return 10
|
||||
} else {
|
||||
return 6
|
||||
}
|
||||
} else if (isEdge) { // edge
|
||||
return 'edge'
|
||||
} else if (isIE11) {// IE11
|
||||
return 11
|
||||
} else {// 不是ie浏览器
|
||||
return -1
|
||||
}
|
||||
}());
|
||||
if(ie_version != -1 && ie_version < 10 && ie_version != 'edge'){
|
||||
window.location.href = '/tips';
|
||||
var recycle_bin_db_open = !!{{g['recycle_bin_db_open']}};
|
||||
var recycle_bin_open = !!{{g['recycle_bin_open']}};
|
||||
var ie_version = (function() {
|
||||
var userAgent = navigator.userAgent;
|
||||
var isLessIE11 = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1;
|
||||
var isEdge = userAgent.indexOf('Edge') > -1 && !isLessIE11;
|
||||
var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1;
|
||||
if (isLessIE11) {
|
||||
var IEReg = new RegExp('MSIE (\\d+\\.\\d+);');
|
||||
IEReg.test(userAgent);
|
||||
var IEVersionNum = parseFloat(RegExp['$1']);
|
||||
if (IEVersionNum === 7) {// IE7
|
||||
return 7
|
||||
} else if (IEVersionNum === 8) {// IE8
|
||||
return 8
|
||||
} else if (IEVersionNum === 9) {// IE9
|
||||
return 9
|
||||
} else if (IEVersionNum === 10) { // IE10
|
||||
return 10
|
||||
} else {
|
||||
return 6
|
||||
}
|
||||
} else if (isEdge) { // edge
|
||||
return 'edge'
|
||||
} else if (isIE11) {// IE11
|
||||
return 11
|
||||
} else {// 不是ie浏览器
|
||||
return -1
|
||||
}
|
||||
}());
|
||||
if (ie_version != -1 && ie_version < 10 && ie_version != 'edge') {
|
||||
window.location.href = '/tips';
|
||||
}
|
||||
if(ie_version != -1 && ( ie_version >= 10 || ie_version === 'edge')){
|
||||
var title = document.createElement('div');
|
||||
title.setAttribute('class', 'content');
|
||||
title.setAttribute('style', 'height: 50px;position: absolute;top: 0;left: 0;right: 0;line-height: 50px;z-index: 9999999;background: rgba(0,0,0,.5);text-align: center;color: #ff922e;font-size: 19px;font-weight: 600;')
|
||||
title.innerHTML = '<span>The current version of IE browser is too low, some functions cannot be displayed, please change to other browsers!</span><span class="compatibility_tips" style="position: absolute;right: 15px;top: 10px;font-size: 14px;display: inline-block; height: 30px;line-height: 28px;padding: 0 12px;font-weight: 500;color: #ffffff; border-radius: 4px;cursor: pointer;border: 2px solid #ffffff;font-weight: 500;">Close Tips</span>';
|
||||
title.querySelector('.compatibility_tips').addEventListener('click',function(res){
|
||||
var parentNode = this.parentElement;
|
||||
parentNode.parentElement.removeChild(parentNode);
|
||||
});
|
||||
document.querySelector('html').appendChild(title);
|
||||
}
|
||||
if (!window.location.origin) {
|
||||
window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<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']}}" 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">
|
||||
<div class="sidebar-auto">
|
||||
<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 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>
|
||||
</div>
|
||||
</div>
|
||||
<button style="display: none;" id="bt_copys" class="bt_copy" data-clipboard-text=""></button>
|
||||
<a style="display: none;" id="defaultPath">{{session['config']['sites_path']}}</a> {% block content %}{% endblock %}
|
||||
<div class="footer bgw">{{session['brand']}}{{session['product']}} ©2014-{{session['yaer']}} {{session['brand']}} (bt.cn)
|
||||
<!--<a style="margin-left:20px;color:#20a53a;" href="http://www.bt.cn/bbs" target="_blank">求助|建议请上宝塔论坛</a>-->
|
||||
<a style="margin-left:20px;color:#20a53a;" href="http://forum.aapanel.com" target="_blank">{{session['bt_help']}}</a>
|
||||
<a style="margin-left:20px;color:#20a53a;" href="https://doc.aapanel.com/web/#/3?page_id=117" target="_blank">Documentation</a>
|
||||
</div>
|
||||
<div class="bt-warp bge6">
|
||||
<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">
|
||||
<div class="sidebar-auto">
|
||||
<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 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>
|
||||
</div>
|
||||
<script src="{{g.cdn_url}}/js/jquery-1.10.2.min.js"></script>
|
||||
</div>
|
||||
<button style="display: none;" id="bt_copys" class="bt_copy" data-clipboard-text=""></button>
|
||||
<a style="display: none;" id="defaultPath">{{session['config']['sites_path']}}</a> {% block content %}{% endblock %}
|
||||
<div class="footer bgw">{{session['brand']}}{{session['product']}} ©2014-{{session['yaer']}} {{session['brand']}} (bt.cn)
|
||||
<!--<a style="margin-left:20px;color:#20a53a;" href="http://www.bt.cn/bbs" target="_blank">求助|建议请上宝塔论坛</a>-->
|
||||
<a style="margin-left:20px;color:#20a53a;" href="http://forum.aapanel.com" target="_blank">{{session['bt_help']}}</a>
|
||||
<a style="margin-left:20px;color:#20a53a;" href="https://doc.aapanel.com/web/#/3?page_id=117" target="_blank">Documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var recycle_bin_db_open = "{{g['recycle_bin_db_open']}}" === "1";
|
||||
var recycle_bin_open = "{{g['recycle_bin_open']}}" === "1";
|
||||
var update_code = "{{data['js_random']}}";
|
||||
var panel_version = "{{g['version']}}";
|
||||
var cdn_url = "{{g.cdn_url}}";
|
||||
</script>
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{g.cdn_url}}/js/jquery-1.10.2.min.js"></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/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>
|
||||
@@ -146,134 +157,126 @@
|
||||
{% for js_f in g['other_js'] %}
|
||||
<script type="text/javascript" src="{{js_f}}"></script>
|
||||
{% endfor %}
|
||||
{% block scripts %}{% endblock %}
|
||||
<script type="text/javascript">
|
||||
$("#setBox").click(function() {
|
||||
if ($(this).prop("checked")) {
|
||||
$("input[name=id]").prop("checked", true);
|
||||
<script type="text/javascript">
|
||||
$("#setBox").click(function() {
|
||||
if ($(this).prop("checked")) {
|
||||
$("input[name=id]").prop("checked", true);
|
||||
} else {
|
||||
$("input[name=id]").prop("checked", false);
|
||||
}
|
||||
});
|
||||
setCookie('order', 'id desc');
|
||||
var is_files_html = false;
|
||||
var task_open = 0;
|
||||
var task_close = false;
|
||||
if ($(".current").attr("id") == 'memuAfiles') {
|
||||
is_files_html = true;
|
||||
}
|
||||
function task_stat(my_init) {
|
||||
if (!my_init) {
|
||||
my_init = 0;
|
||||
if (task_open) return;
|
||||
}
|
||||
if (task_close) return;
|
||||
$.post('/task?action=get_task_lists', {
|
||||
status: -3
|
||||
}, function(task_list) {
|
||||
if (task_list.length == 0) {
|
||||
if (my_init && is_files_html) GetFiles(getCookie('Path'));
|
||||
if (task_open) {
|
||||
layer.close(task_open);
|
||||
task_open = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
console.log(task_list.length)
|
||||
var msg_body = '';
|
||||
var is_add = false;
|
||||
for (var i = 0; i < task_list.length; i++) {
|
||||
if (task_list[i]['status'] == -1) {
|
||||
if (!task_open || !$(".message-list").attr("class")) {
|
||||
show_task();
|
||||
}
|
||||
if (task_list[i]['type'] == '1') {
|
||||
msg_body += '<div class="mw-con">\
|
||||
<ul class="waiting-down-list">\
|
||||
<li>\
|
||||
<div class="down-filse-name"><span class="fname" style="width:80%;" title="Downloading: ' + task_list[i].shell + '">Downloading: ' + task_list[i].shell + '</span><span style="position: absolute;left: 84%;top: 25px;color: #999;">' + task_list[i].log.pre + '%</span><span class="btlink" onclick="remove_task(' + task_list[i].id + ')" style="position: absolute;top: 25px;right: 20px;">Cancel</span></div>\
|
||||
<div class="down-progress"><div class="done-progress" style="width:' + task_list[i].log.pre + '%"></div></div>\
|
||||
<div class="down-info"><span class="total-size"> ' + task_list[i].log.used + '/' + ToSize(task_list[i].log.total) + '</span><span class="speed-size">' + (task_list[i].log.speed == 0 ? 'On connection..' : task_list[i].log.speed) + '/s</span><span style="margin-left: 20px;">Estimate: ' + task_list[i].log.time + '</span></div>\
|
||||
</li>\
|
||||
</ul>\
|
||||
</div>';
|
||||
} else {
|
||||
$("input[name=id]").prop("checked", false);
|
||||
msg_body += '\<div class="mw-title">\
|
||||
<span style="max-width: 88%;display: block;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;">' + task_list[i].name + ': ' + task_list[i].shell + '</span><span class="btlink" onclick="remove_task(' + task_list[i].id + ')" style="position: absolute;top: 10px;right: 15px;">Cancel</span></div>\
|
||||
<div class="mw-con codebg">\
|
||||
<code>' + task_list[i].log + '</code>\
|
||||
</div>';
|
||||
}
|
||||
});
|
||||
setCookie('order', 'id desc');
|
||||
var is_files_html = false;
|
||||
var task_open = 0;
|
||||
var task_close = false;
|
||||
if ($(".current").attr("id") == 'memuAfiles') {
|
||||
is_files_html = true;
|
||||
}
|
||||
|
||||
function task_stat(my_init) {
|
||||
if (!my_init) {
|
||||
my_init = 0;
|
||||
if (task_open) return;
|
||||
} else {
|
||||
if (!is_add) {
|
||||
msg_body += '<div class="mw-title">Waiting to execute task</div><div class="mw-con"><ul class="waiting-list">';
|
||||
is_add = true;
|
||||
}
|
||||
if (task_close) return;
|
||||
$.post('/task?action=get_task_lists', {
|
||||
status: -3
|
||||
}, function(task_list) {
|
||||
if (task_list.length == 0) {
|
||||
if (my_init && is_files_html) GetFiles(getCookie('Path'));
|
||||
if (task_open) {
|
||||
layer.close(task_open);
|
||||
task_open = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(task_list.length)
|
||||
var msg_body = '';
|
||||
var is_add = false;
|
||||
for (var i = 0; i < task_list.length; i++) {
|
||||
if (task_list[i]['status'] == -1) {
|
||||
if (!task_open || !$(".message-list").attr("class")) {
|
||||
show_task();
|
||||
}
|
||||
|
||||
if (task_list[i]['type'] == '1') {
|
||||
msg_body += '<div class="mw-con">\
|
||||
<ul class="waiting-down-list">\
|
||||
<li>\
|
||||
<div class="down-filse-name"><span class="fname" style="width:80%;" title="Downloading: ' + task_list[i].shell + '">Downloading: ' + task_list[i].shell + '</span><span style="position: absolute;left: 84%;top: 25px;color: #999;">' + task_list[i].log.pre + '%</span><span class="btlink" onclick="remove_task(' + task_list[i].id + ')" style="position: absolute;top: 25px;right: 20px;">Cancel</span></div>\
|
||||
<div class="down-progress"><div class="done-progress" style="width:' + task_list[i].log.pre + '%"></div></div>\
|
||||
<div class="down-info"><span class="total-size"> ' + task_list[i].log.used + '/' + ToSize(task_list[i].log.total) + '</span><span class="speed-size">' + (task_list[i].log.speed == 0 ? 'On connection..' : task_list[i].log.speed) + '/s</span><span style="margin-left: 20px;">Estimate: ' + task_list[i].log.time + '</span></div>\
|
||||
</li>\
|
||||
</ul>\
|
||||
</div>'
|
||||
} else {
|
||||
msg_body += '<div class="mw-title"><span style="max-width: 88%;display: block;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;">' + task_list[i].name + ': ' + task_list[i].shell + '</span><span class="btlink" onclick="remove_task(' + task_list[i].id + ')" style="position: absolute;top: 10px;right: 15px;">Cancel</span></div>\
|
||||
<div class="mw-con codebg">\
|
||||
<code>' + task_list[i].log + '</code>\
|
||||
</div>'
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!is_add) {
|
||||
msg_body += '<div class="mw-title">Waiting to execute task</div><div class="mw-con"><ul class="waiting-list">';
|
||||
is_add = true;
|
||||
}
|
||||
msg_body += '<li><span class="wt-list-name" style="width: 90%;">' + task_list[i].name + ': ' + task_list[i].shell + '</span><span class="mw-cancel" onclick="remove_task(' + task_list[i].id + ')">X</span></li>';
|
||||
}
|
||||
}
|
||||
if (task_open) {
|
||||
if (is_add) {
|
||||
msg_body += '</ul></div>';
|
||||
}
|
||||
$(".message-list").html(msg_body);
|
||||
}
|
||||
|
||||
|
||||
if (my_init > 3) {
|
||||
if (is_files_html) GetFiles(getCookie('Path'));
|
||||
my_init = 1;
|
||||
}
|
||||
my_init += 1
|
||||
setTimeout(function() {
|
||||
task_stat(my_init);
|
||||
}, 1000);
|
||||
});
|
||||
msg_body += '<li><span class="wt-list-name" style="width: 90%;">' + task_list[i].name + ': ' + task_list[i].shell + '</span><span class="mw-cancel" onclick="remove_task(' + task_list[i].id + ')">X</span></li>';
|
||||
}
|
||||
}
|
||||
|
||||
function show_task() {
|
||||
task_open = layer.open({
|
||||
type: 1,
|
||||
title: "Real time task queue",
|
||||
area: '500px',
|
||||
closeBtn: 2,
|
||||
shadeClose: false,
|
||||
shade: false,
|
||||
offset: 'auto',
|
||||
content: '<div style="margin: 10px;" class="message-list"></div>',
|
||||
cancel: function() {
|
||||
task_close = true;
|
||||
}
|
||||
});
|
||||
if (task_open) {
|
||||
if (is_add) {
|
||||
msg_body += '</ul></div>';
|
||||
}
|
||||
$(".message-list").html(msg_body);
|
||||
}
|
||||
|
||||
function remove_task(id) {
|
||||
loadT = layer.msg('Canceling task...', {
|
||||
time: 0,
|
||||
icon: 16,
|
||||
shade: [0.3, '#000']
|
||||
});
|
||||
$.post('/task?action=remove_task', {
|
||||
id: id
|
||||
}, function(rdata) {
|
||||
layer.close(loadT)
|
||||
layer.msg(rdata.msg);
|
||||
});
|
||||
if (my_init > 3) {
|
||||
if (is_files_html) GetFiles(getCookie('Path'));
|
||||
my_init = 1;
|
||||
}
|
||||
loadScript([
|
||||
'{{g.cdn_url}}/laydate/laydate.js',
|
||||
'{{g.cdn_url}}/js/jquery.qrcode.min.js',
|
||||
'{{g.cdn_url}}/js/clipboard.min.js'
|
||||
], function(e) {
|
||||
|
||||
});
|
||||
task_stat();
|
||||
</script>
|
||||
</div>
|
||||
my_init += 1
|
||||
setTimeout(function() {
|
||||
task_stat(my_init);
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
function show_task() {
|
||||
task_open = layer.open({
|
||||
type: 1,
|
||||
title: "Real time task queue",
|
||||
area: '500px',
|
||||
closeBtn: 2,
|
||||
shadeClose: false,
|
||||
shade: false,
|
||||
offset: 'auto',
|
||||
content: '<div style="margin: 10px;" class="message-list"></div>',
|
||||
cancel: function() {
|
||||
task_close = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
function remove_task(id) {
|
||||
layer.confirm('Do you want to cancel the current task queue?', {
|
||||
title: 'Cancel task queue',
|
||||
icon: 0
|
||||
}, function (indexs) {
|
||||
layer.close(indexs);
|
||||
var loadT = bt.load('Canceling task...');
|
||||
$.post('/task?action=remove_task', {
|
||||
id: id
|
||||
}, function(rdata) {
|
||||
loadT.close()
|
||||
bt.msg(rdata);
|
||||
});
|
||||
});
|
||||
}
|
||||
loadScript([
|
||||
'{{g.cdn_url}}/laydate/laydate.js',
|
||||
'{{g.cdn_url}}/js/jquery.qrcode.min.js',
|
||||
'{{g.cdn_url}}/js/clipboard.min.js'
|
||||
], function(e) {});
|
||||
task_stat();
|
||||
</script>
|
||||
{% endblock %}
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -13,7 +13,7 @@
|
||||
</style>
|
||||
<div class="main-content pb55">
|
||||
<div class="container-fluid">
|
||||
<div class="pos-box bgw mtb15">
|
||||
<!-- <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>
|
||||
@@ -24,23 +24,33 @@
|
||||
</form>
|
||||
<iframe name='hid' id="hid" style="display:none"></iframe>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="pos-box bgw mtb15">
|
||||
<div class="tab-list" id="cutMode">
|
||||
<div class="tabs-item active" data-type="php">PHP Project</div>
|
||||
<div class="tabs-item" data-type="nodejs">Node Project</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="site_table_view bgw mtb15 pd15">
|
||||
<div class="info-title-tips">
|
||||
<div id="site_table_view" 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']}}after the site is successfully established, please<a class="btlink" href="/crontab">[Cron]</a>add scheduled backup tasks to the page!</p>
|
||||
</div>
|
||||
<div class="tab-nav" id="cutMode">
|
||||
<span class="on">PHP Project</span>
|
||||
<span >Node Project</span>
|
||||
</div>
|
||||
<div class="tab-con" style="padding:10px 0;overflow: inherit;">
|
||||
</div> -->
|
||||
<div class="tab-con" style="padding: 0;overflow: inherit;">
|
||||
<div class="tab-con-block">
|
||||
<div id="bt_site_table"></div>
|
||||
<div class="mask_layer hide"><div class="prompt_description"></div></div>
|
||||
<div class="mask_layer hide">
|
||||
<div class="prompt_description"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-con-block">
|
||||
<div id="bt_node_table"></div>
|
||||
<div class="mask_layer hide"><div class="prompt_description"></div></div>
|
||||
<div class="mask_layer hide">
|
||||
<div class="prompt_description node-model"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -50,6 +60,7 @@
|
||||
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="text/javascript">
|
||||
bt.set_cookie('sites_path', "{{session['config']['sites_path']}}");
|
||||
bt.set_cookie('serverType', "{{session['webserver']}}");
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="text/javascript" src="/static/js/jquery.dragsort-0.5.2.min.js"></script>
|
||||
<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>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
|
||||
@@ -63,19 +63,29 @@
|
||||
<div class="line c_password_view <% (this.form.password != '' || this.form.pkey == '' && this.form.password == '')?'show':'hidden'%>">
|
||||
<span class="tname">Password</span>
|
||||
<div class="info-r">
|
||||
<input type="text" name="password" class="bt-input-text mr5" placeholder="Please enter SSH password" style="width:305px;" value="<% this.form.password %>" autocomplete="off"/>
|
||||
<input type="text" name="password" class="bt-input-text mr5" placeholder="Please enter SSH password"
|
||||
style="width:305px;" value="<% this.form.password %>" autocomplete="off"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line c_pkey_view <% this.form.pkey != ''?'show':'hidden'%>">
|
||||
<span class="tname">Private key</span>
|
||||
<div class="info-r">
|
||||
<textarea rows="4" name="pkey" class="bt-input-text mr5" placeholder="Please enter SSH Private key" style="width:305px;height: 80px;line-height: 18px;padding-top:10px;"><% this.form.pkey %></textarea>
|
||||
<textarea rows="4" name="pkey" class="bt-input-text mr5" placeholder="Please enter SSH Private key"
|
||||
style="width:305px;height: 80px;line-height: 18px;padding-top:10px;"><% this.form.pkey %></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line key_pwd_line <% this.form.pkey != '' ? 'show' : 'hidden' %>">
|
||||
<span class="tname">Key password</span>
|
||||
<div class="info-r">
|
||||
<input type="text" name="pkey_passwd" class="bt-input-text mr5" placeholder="Please enter Key password, can be blank" style="width:305px;"
|
||||
value="<% this.form.pkey_passwd %>" autocomplete="off"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<span class="tname">Remarks</span>
|
||||
<div class="info-r">
|
||||
<input type="text" name="ps" class="bt-input-text mr5" placeholder="Please enter remarks, can be blank" style="width:305px;" value="<% this.form.ps %>" autocomplete="off"/>
|
||||
<input type="text" name="ps" class="bt-input-text mr5" placeholder="Please enter remarks, can be blank"
|
||||
style="width:305px;" value="<% this.form.ps %>" autocomplete="off"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -91,13 +101,16 @@
|
||||
<div class="line">
|
||||
<span class="tname">Content</span>
|
||||
<div class="info-r">
|
||||
<textarea rows="4" name="shell" class="bt-input-text mr5" placeholder="Please enter command content, required" style="width:305px;height: 150px;line-height: 18px;padding-top:10px;"><% this.form.shell %></textarea>
|
||||
<textarea rows="4" name="shell" class="bt-input-text mr5"
|
||||
placeholder="Please enter command content, required"
|
||||
style="width:305px;height: 150px;line-height: 18px;padding-top:10px;"><% this.form.shell %></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="text/javascript" src="/static/js/jquery.dragsort-0.5.2.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/clipboard.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/xterm.js"></script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python
|
||||
#coding: utf-8
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# 宝塔Linux面板
|
||||
# -------------------------------------------------------------------
|
||||
@@ -18,21 +18,22 @@ import binascii
|
||||
import hashlib
|
||||
import base64
|
||||
import json
|
||||
import copy
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
|
||||
os.chdir('/www/server/panel')
|
||||
if not 'class/' in sys.path:
|
||||
sys.path.insert(0,'class/')
|
||||
sys.path.insert(0, 'class/')
|
||||
import http_requests as requests
|
||||
|
||||
requests.DEFAULT_TYPE = 'curl'
|
||||
import public
|
||||
|
||||
try:
|
||||
import OpenSSL
|
||||
except:
|
||||
public.ExecShell("pip install -I pyopenssl")
|
||||
public.ExecShell("btpip install -I pyOpenSSL")
|
||||
import OpenSSL
|
||||
try:
|
||||
import dns.resolver
|
||||
@@ -40,6 +41,7 @@ except:
|
||||
public.ExecShell("pip install dnspython")
|
||||
import dns.resolver
|
||||
|
||||
|
||||
class acme_v2:
|
||||
_url = None
|
||||
_apis = None
|
||||
@@ -89,7 +91,7 @@ class acme_v2:
|
||||
result = res.json()
|
||||
if "type" in result:
|
||||
if result['type'] == 'urn:acme:error:serverInternal':
|
||||
raise Exception(public.getMsg('ACME_MSG_ERR'))
|
||||
raise Exception(public.get_msg_gettext('Service shutdown or internal error due to maintenance, check [ https://letsencrypt.status.io ] see for more details.'))
|
||||
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()
|
||||
@@ -125,19 +127,19 @@ class acme_v2:
|
||||
self.set_crond()
|
||||
return account
|
||||
except Exception as ex:
|
||||
return public.returnMsg(False,str(ex))
|
||||
return public.return_msg_gettext(False,str(ex))
|
||||
|
||||
# 设置帐户信息
|
||||
def set_account_info(self, args):
|
||||
if not 'account' in self._config:
|
||||
return public.returnMsg(False, 'ACME_ACCOUNT_ERR')
|
||||
return public.return_msg_gettext(False, 'The specified account does not exist')
|
||||
account = json.loads(args.account)
|
||||
if 'email' in account:
|
||||
self._config['email'] = account['email']
|
||||
del(account['email'])
|
||||
self._config['account'][self._mod_index[self._debug]] = account
|
||||
self.save_config()
|
||||
return public.returnMsg(True, 'ACME_SUCCESS_ACCOUNT_SETUP')
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
|
||||
# 获取订单列表
|
||||
def get_orders(self, args):
|
||||
@@ -153,19 +155,19 @@ class acme_v2:
|
||||
# 删除订单
|
||||
def remove_order(self, args):
|
||||
if not 'orders' in self._config:
|
||||
return public.returnMsg(False, 'ACME_ORDER_NOT_EXIST')
|
||||
return public.return_msg_gettext(False, 'The specified order does not exist!')
|
||||
if not args.index in self._config['orders']:
|
||||
return public.returnMsg(False, 'ACME_ORDER_NOT_EXIST')
|
||||
return public.return_msg_gettext(False, 'The specified order does not exist!')
|
||||
del(self._config['orders'][args.index])
|
||||
self.save_config()
|
||||
return public.returnMsg(True, 'ACME_DEL_ODER_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Order deleted successfully!')
|
||||
|
||||
# 取指定订单数据
|
||||
def get_order_find(self, args):
|
||||
if not 'orders' in self._config:
|
||||
return public.returnMsg(False, 'ACME_ORDER_NOT_EXIST')
|
||||
return public.return_msg_gettext(False, 'The specified order does not exist!')
|
||||
if not args.index in self._config['orders']:
|
||||
return public.returnMsg(False, 'ACME_ORDER_NOT_EXIST')
|
||||
return public.return_msg_gettext(False, 'The specified order does not exist!')
|
||||
result = self._config['orders'][args.index]
|
||||
result['cert'] = self.get_cert_info(args.index)
|
||||
return result
|
||||
@@ -186,27 +188,27 @@ class acme_v2:
|
||||
if not os.path.exists(path): # 尝试重新下载证书
|
||||
self.download_cert(args.index)
|
||||
if not os.path.exists(path):
|
||||
return public.returnMsg(False, 'ACME_GET_CERT_ERR')
|
||||
return public.return_msg_gettext(False, 'Certificate read failed, directory does not exist!')
|
||||
import panelTask
|
||||
bt_task = panelTask.bt_task()
|
||||
zip_file = path+'/cert.zip'
|
||||
result = bt_task._zip(path, '.', path+'/cert.zip', '/dev/null', 'zip')
|
||||
if not os.path.exists(zip_file):
|
||||
return result
|
||||
return public.returnMsg(True, zip_file)
|
||||
return public.return_msg_gettext(True, zip_file)
|
||||
|
||||
# 吊销证书
|
||||
def revoke_order(self, index):
|
||||
if type(index) != str:
|
||||
index = index.index
|
||||
if not index in self._config['orders']:
|
||||
raise Exception(public.getMsg('ACME_ORDER_NOT_EXIST'))
|
||||
raise Exception(public.get_msg_gettext('The specified order does not exist!'))
|
||||
cert_path = self._config['orders'][index]['save_path']
|
||||
if not os.path.exists(cert_path):
|
||||
raise Exception(public.getMsg('ACME_CERT_ERR'))
|
||||
raise Exception(public.get_msg_gettext('No certificate found for the specified order!'))
|
||||
cert = self.dump_der(cert_path)
|
||||
if not cert:
|
||||
raise Exception(public.getMsg('ACME_CERT_READ_ERR'))
|
||||
raise Exception(public.get_msg_gettext('Certificate read failed!'))
|
||||
payload = {
|
||||
"certificate": self.calculate_safe_base64(cert),
|
||||
"reason": 4
|
||||
@@ -217,7 +219,7 @@ class acme_v2:
|
||||
public.ExecShell("rm -rf {}".format(cert_path))
|
||||
del(self._config['orders'][index])
|
||||
self.save_config()
|
||||
return public.returnMsg(True, "Certificate revoked!")
|
||||
return public.return_msg_gettext(True, "Certificate revoked!")
|
||||
return res.json()
|
||||
|
||||
# 取根域名和记录值
|
||||
@@ -320,7 +322,7 @@ class acme_v2:
|
||||
def create_order(self, domains, auth_type, auth_to, index=None):
|
||||
domains = self.format_domains(domains)
|
||||
if not domains:
|
||||
raise Exception(public.getMsg('ACME_DOMAIN_ERR'))
|
||||
raise Exception(public.get_msg_gettext('Need at least a domain name!'))
|
||||
# 构造标识
|
||||
identifiers = []
|
||||
for domain_name in domains:
|
||||
@@ -348,7 +350,7 @@ class acme_v2:
|
||||
a_auth = res.json()
|
||||
ret_title = self.get_error(str(a_auth))
|
||||
raise StopIteration(
|
||||
"{0} >>>> {1}".format(
|
||||
"{} >>>> {}".format(
|
||||
ret_title,
|
||||
json.dumps(a_auth)
|
||||
)
|
||||
@@ -365,7 +367,7 @@ class acme_v2:
|
||||
# 获取验证信息
|
||||
def get_auths(self, index):
|
||||
if not index in self._config['orders']:
|
||||
raise Exception(public.getMsg('ACME_ORDER_NOT_EXIST'))
|
||||
raise Exception(public.get_msg_gettext('The specified order does not exist!'))
|
||||
|
||||
# 检查是否已经获取过授权信息
|
||||
if 'auths' in self._config['orders'][index]:
|
||||
@@ -447,7 +449,7 @@ class acme_v2:
|
||||
if not self._config['orders'][index]['auth_type'] in ['http','tls']:
|
||||
return True
|
||||
acme_path = '{}/.well-known/acme-challenge'.format(self._config['orders'][index]['auth_to'])
|
||||
write_log(public.getMsg('ACME_V_DIR',(acme_path,)))
|
||||
write_log(public.get_msg_gettext('|-Verify the dir:{}',(acme_path,)))
|
||||
if os.path.exists(acme_path):
|
||||
public.ExecShell("rm -f {}/*".format(acme_path))
|
||||
acme_path = '/www/server/stop/.well-known/acme-challenge'
|
||||
@@ -476,7 +478,7 @@ class acme_v2:
|
||||
except:
|
||||
err = public.get_error_info()
|
||||
print(err)
|
||||
raise Exception(public.getMsg('ACME_WRITE_V_FILE_ERR',(err,)))
|
||||
raise Exception(public.get_msg_gettext('Writing verification file failed: {}',(err,)))
|
||||
|
||||
# 解析域名
|
||||
def create_dns_record(self, auth_to, domain, dns_value):
|
||||
@@ -507,7 +509,7 @@ class acme_v2:
|
||||
key = dc['data'][0]['value']
|
||||
secret = dc['data'][1]['value']
|
||||
except:
|
||||
raise Exception(public.getMsg('ACME_DNS_API_ERR'))
|
||||
raise Exception(public.get_msg_gettext('No valid DNSAPI key information found'))
|
||||
else:
|
||||
key = tmp[1]
|
||||
secret = tmp[2]
|
||||
@@ -526,7 +528,7 @@ class acme_v2:
|
||||
# 验证域名
|
||||
def auth_domain(self, index):
|
||||
if not index in self._config['orders']:
|
||||
raise Exception(public.getMsg('ACME_ORDER_NOT_EXIST'))
|
||||
raise Exception(public.get_msg_gettext('The specified order does not exist!'))
|
||||
|
||||
# 开始验证
|
||||
for auth in self._config['orders'][index]['auths']:
|
||||
@@ -553,7 +555,7 @@ class acme_v2:
|
||||
number_of_checks = 0
|
||||
while True:
|
||||
if desired_status == ['valid', 'invalid']:
|
||||
write_log(public.getMsg('ACME_QUERY_V_RESULT',(str(number_of_checks + 1),)))
|
||||
write_log(public.get_msg_gettext('|-{} Query verification results..',(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()
|
||||
@@ -561,7 +563,7 @@ class acme_v2:
|
||||
number_of_checks += 1
|
||||
if authorization_status in desired_status:
|
||||
if authorization_status == "invalid":
|
||||
write_log("|-"+public.getMsg('VERIFICATION_FAILED'))
|
||||
write_log("|-"+public.get_msg_gettext('Verification failed'))
|
||||
try:
|
||||
if 'error' in a_auth['challenges'][0]:
|
||||
ret_title = a_auth['challenges'][0]['error']['detail']
|
||||
@@ -575,7 +577,7 @@ class acme_v2:
|
||||
except:
|
||||
ret_title = str(a_auth)
|
||||
raise StopIteration(
|
||||
"{0} >>>> {1}".format(
|
||||
"{} >>>> {}".format(
|
||||
ret_title,
|
||||
json.dumps(a_auth)
|
||||
)
|
||||
@@ -584,75 +586,75 @@ class acme_v2:
|
||||
|
||||
if number_of_checks == self._max_check_num:
|
||||
raise StopIteration(
|
||||
public.getMsg('ACME_V_TIMES',(
|
||||
public.get_msg_gettext('Error: Attempted verification {} times. The maximum number of verifications is {}. The verification interval is {} seconds.',(
|
||||
str(number_of_checks),
|
||||
str(self._max_check_num),
|
||||
str(self._wait_time)
|
||||
)))
|
||||
if desired_status == ['valid', 'invalid']:
|
||||
write_log(public.getMsg('ACME_V_SUCCESS'))
|
||||
write_log(public.get_msg_gettext('|-Verification succeeded!'))
|
||||
return check_authorization_status_response
|
||||
|
||||
# 格式化错误输出
|
||||
def get_error(self, error):
|
||||
if error.find("Max checks allowed") >= 0:
|
||||
return public.getMsg('ACME_ERR_MSG1')
|
||||
return public.get_msg_gettext('CA cannot verify your domain name, please check if the domain name resolution is correct, or wait 5-10 minutes and try again.')
|
||||
elif error.find("Max retries exceeded with") >= 0 or error.find('status_code=0 ') != -1:
|
||||
return public.getMsg('ACME_ERR_MSG2')
|
||||
return public.get_msg_gettext('CA server connection timed out, please try again later.')
|
||||
elif error.find("The domain name belongs") >= 0:
|
||||
return public.getMsg('ACME_ERR_MSG3')
|
||||
return public.get_msg_gettext('The domain name does not belong to this DNS service provider, please make sure the domain name is filled in correctly.')
|
||||
elif error.find('login token ID is invalid') >= 0:
|
||||
return public.getMsg('ACME_ERR_MSG4')
|
||||
return public.get_msg_gettext('DNS server connection failed, please check if the key is correct.')
|
||||
elif error.find('Error getting validation data') != -1:
|
||||
return public.getMsg('ACME_ERR_MSG5')
|
||||
return public.get_msg_gettext('Data validation failed and the CA was unable to get the correct captcha from the authenticated connection.')
|
||||
elif "too many certificates already issued for exact set of domains" in error:
|
||||
return public.getMsg('ACME_ERR_MSG6',(str(re.findall("exact set of domains: (.+):", error)),))
|
||||
return public.get_msg_gettext('Issuing failed, the domain {} has exceeded the limit of weekly reissues!',(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')
|
||||
return public.get_msg_gettext('Issuing failed, the current server IP has reached the limit of creating up to 10 accounts every 3 hours.')
|
||||
elif "DNS problem: NXDOMAIN looking up A for" in error:
|
||||
return public.getMsg('ACME_ERR_MSG8')
|
||||
return public.get_msg_gettext('Validation failed, domain name was not resolved, or resolution did not take effect!')
|
||||
elif "Invalid response from" in error:
|
||||
return public.getMsg('ACME_ERR_MSG9')
|
||||
return public.get_msg_gettext('Verification failed, domain name resolution error or verification URL cannot be accessed!')
|
||||
elif error.find('TLS Web Server Authentication') != -1:
|
||||
return public.getMsg('ACME_ERR_MSG10')
|
||||
return public.get_msg_gettext('Connection to CA server failed, please try again later.')
|
||||
elif error.find('Name does not end in a public suffix') != -1:
|
||||
return public.getMsg('ACME_ERR_MSG11',(str(re.findall("Cannot issue for \"(.+)\":", error)),))
|
||||
return public.get_msg_gettext('Unsupported domain name {}, please check the domain name is correct!',(str(re.findall("Cannot issue for \"(.+)\":", error)),))
|
||||
elif error.find('No valid IP addresses found for') != -1:
|
||||
return public.getMsg('ACME_ERR_MSG12',(str(re.findall("No valid IP addresses found for (.+)", error)),))
|
||||
return public.get_msg_gettext('No resolution record was found for domain name {}, please check if the domain name resolution takes effect!',(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',(str(re.findall("No TXT record found at (.+)", error)),))
|
||||
return public.get_msg_gettext('No valid TXT resolution record was found in the domain name {}, please check whether the TXT record is parsed correctly. If it is applied by DNSAPI, please try again in 10 minutes!',(str(re.findall("No TXT record found at (.+)", error)),))
|
||||
elif error.find('Incorrect TXT record') != -1:
|
||||
return public.getMsg('ACME_ERR_MSG14',(str(re.findall("found at (.+)", error)), str(re.findall("Incorrect TXT record \"(.+)\"", error))))
|
||||
return public.get_msg_gettext('A wrong TXT record was found on {}: {}, please check whether the TXT resolution is correct, if it is applied by DNSAPI, please try again in 10 minutes!',(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')
|
||||
return public.get_msg_gettext('This domain name does not exist under this dnspod account, adding resolution failed!')
|
||||
elif error.find('SERVFAIL looking up TXT for') != -1:
|
||||
return public.getMsg('ACME_ERR_MSG16',(str(re.findall("looking up TXT for (.+)", error)),))
|
||||
return public.get_msg_gettext('No valid TXT resolution record was found in the domain name {}, please check whether the TXT record is parsed correctly. If it is applied by DNSAPI, please try again in 10 minutes!',(str(re.findall("looking up TXT for (.+)", error)),))
|
||||
elif error.find('Timeout during connect') != -1:
|
||||
return public.getMsg('ACME_ERR_MSG17')
|
||||
return public.get_msg_gettext('The connection timed out and the CA server was unable to access your website!')
|
||||
elif error.find("DNS problem: SERVFAIL looking up CAA for") != -1:
|
||||
return public.getMsg('ACME_ERR_MSG18',(str(re.findall("looking up CAA for (.+)", error)),))
|
||||
return public.get_msg_gettext('Domain name {} is currently required to verify the CAA record, please parse the CAA record manually, or retry the application after 1 hour!',(str(re.findall("looking up CAA for (.+)", error)),))
|
||||
elif error.find("Read timed out.") != -1:
|
||||
return public.getMsg('ACME_ERR_MSG19')
|
||||
return public.get_msg_gettext('The verification timed out. Please check if the domain name is resolved correctly. If it is resolved correctly, the connection between the server and LetsEncrypt may be abnormal. Please try again later!')
|
||||
elif error.find('Cannot issue for') != -1:
|
||||
return public.getMsg('ACME_ERR_MSG20',(str(re.findall(r'for\s+"(.+)"',error)),))
|
||||
return public.get_msg_gettext('Cannot issue a certificate for {}, cannot apply for a wildcard certificate with a domain name suffix directly!',(str(re.findall(r'for\s+"(.+)"',error)),))
|
||||
elif error.find('too many failed authorizations recently'):
|
||||
return public.getMsg('ACME_ERR_MSG21')
|
||||
return public.get_msg_gettext('The account has more than 5 failed orders within 1 hour, please wait 1 hour and try again!')
|
||||
elif error.find("Error creating new order") != -1:
|
||||
return public.getMsg('ACME_ERR_MSG22')
|
||||
return public.get_msg_gettext('Order creation failed, please try again later!')
|
||||
elif error.find("Too Many Requests") != -1:
|
||||
return public.getMsg('ACME_ERR_MSG23')
|
||||
return public.get_msg_gettext('More than 5 verification failures in 1 hour, the application is temporarily banned, please try again later!')
|
||||
elif error.find('HTTP Error 400: Bad Request') != -1:
|
||||
return public.getMsg('ACME_ERR_MSG24')
|
||||
return public.get_msg_gettext('CA server denied access, please try again later!')
|
||||
elif error.find('Temporary failure in name resolution') != -1:
|
||||
return public.getMsg('ACME_ERR_MSG25')
|
||||
return public.get_msg_gettext('The DNS of the server is faulty and the domain name cannot be resolved. Please use the Linux toolbox to check the DNS configuration')
|
||||
elif error.find('Too Many Requests') != -1:
|
||||
return public.getMsg('ACME_ERR_MSG26')
|
||||
return public.get_msg_gettext('Too many requests for this domain name. Please try again 3 hours later')
|
||||
else:
|
||||
return error
|
||||
|
||||
# 发送验证请求
|
||||
def respond_to_challenge(self, auth):
|
||||
payload = {"keyAuthorization": "{0}".format(
|
||||
payload = {"keyAuthorization": "{}".format(
|
||||
auth['acme_keyauthorization'])}
|
||||
respond_to_challenge_response = self.acme_request(
|
||||
auth['dns_challenge_url'], payload)
|
||||
@@ -666,7 +668,7 @@ class acme_v2:
|
||||
url=self._config['orders'][index]['finalize'], payload=payload)
|
||||
if send_csr_response.status_code not in [200, 201]:
|
||||
raise ValueError(
|
||||
public.getMsg('ACME_SEND_CSR_ERR',(send_csr_response.status_code,send_csr_response.json()))
|
||||
public.get_msg_gettext('Error: Sending CSR: Response status {} Response value: {}',(send_csr_response.status_code,send_csr_response.json()))
|
||||
)
|
||||
send_csr_response_json = send_csr_response.json()
|
||||
certificate_url = send_csr_response_json["certificate"]
|
||||
@@ -689,7 +691,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',(str(res.json()),)))
|
||||
raise Exception(public.get_msg_gettext('Failed to download certificate: {}',(str(res.json()),)))
|
||||
|
||||
pem_certificate = res.content
|
||||
if type(pem_certificate) == bytes:
|
||||
@@ -781,8 +783,10 @@ fullchain.pem Paste into certificate input box
|
||||
# 获取目标证书的基本信息
|
||||
to_cert_init = self.get_cert_init(to_pem_file)
|
||||
# 判断证书品牌是否一致
|
||||
if to_cert_init['issuer'] != cert_init['issuer'] and to_cert_init['issuer'].find("Let's Encrypt") == -1:
|
||||
continue
|
||||
try:
|
||||
if to_cert_init['issuer'] != cert_init['issuer'] and to_cert_init['issuer'].find("Let's Encrypt") == -1 and to_cert_init['issuer'] != 'R3':
|
||||
continue
|
||||
except: continue
|
||||
# 判断目标证书的到期时间是否较早
|
||||
if to_cert_init['notAfter'] > cert_init['notAfter']:
|
||||
continue
|
||||
@@ -802,7 +806,7 @@ fullchain.pem Paste into certificate input box
|
||||
public.writeFile(
|
||||
to_key_file, public.readFile(key_file, 'rb'), 'wb')
|
||||
public.writeFile(to_info, json.dumps(cert_init))
|
||||
write_log(public.getMsg('ACME_CERT_REPLACE',(to_path,)))
|
||||
write_log(public.get_msg_gettext('|-Detected that the certificate under {} overlaps with the certificate of this application and has an earlier expiration time, and has been replaced with a new certificate!',(to_path,)))
|
||||
# 重载web服务
|
||||
public.serviceReload()
|
||||
if is_panel: public.restart_panel()
|
||||
@@ -818,7 +822,7 @@ fullchain.pem Paste into certificate input box
|
||||
for domain in self._config['orders'][index]['domains']:
|
||||
if domain in cert_init['dns']:
|
||||
return index
|
||||
if cert_init['issuer'].find("Let's Encrypt") != -1:
|
||||
if cert_init['issuer'].find("Let's Encrypt") != -1 or cert_init['issuer'] == 'R3':
|
||||
return pem_file
|
||||
return None
|
||||
except: return None
|
||||
@@ -828,10 +832,10 @@ fullchain.pem Paste into certificate input box
|
||||
if not os.path.exists(args.pem_file):
|
||||
args.pem_file = 'vhost/cert/{}/fullchain.pem'.format(args.siteName)
|
||||
if not os.path.exists(args.pem_file):
|
||||
return public.returnMsg(False, 'ACME_CERT_FILE_ERR')
|
||||
return public.return_msg_gettext(False, 'The specified certificate file does not exist!')
|
||||
cert_init = self.get_cert_init(args.pem_file)
|
||||
if not cert_init:
|
||||
return public.returnMsg(False, 'ACME_CERT_GET_CERTINFO_ERR')
|
||||
return public.return_msg_gettext(False, 'Certificate information acquisition failed!')
|
||||
cert_init['dnsapi'] = json.loads(public.readFile(self._dnsapi_file))
|
||||
return cert_init
|
||||
|
||||
@@ -922,7 +926,7 @@ fullchain.pem Paste into certificate input box
|
||||
|
||||
# 检查DNS记录
|
||||
def check_dns(self, domain, value, s_type='TXT'):
|
||||
write_log(public.getMsg('ACME_CHECK_DNS',(domain, s_type, value)))
|
||||
write_log(public.get_msg_gettext('|-Attempt to verify DNS records locally, domain name: {}, type: {} record value: {}',(domain, s_type, value)))
|
||||
time.sleep(10)
|
||||
n = 0
|
||||
while n < 20:
|
||||
@@ -933,9 +937,9 @@ 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',(str(n),txt_value)))
|
||||
write_log(public.get_msg_gettext('|-Number of verifications: {}, value: {}',(str(n),txt_value)))
|
||||
if txt_value == value:
|
||||
write_log(public.getMsg('ACME_CHECK_DNS2'))
|
||||
write_log(public.get_msg_gettext('|-Local authentication succeeded!'))
|
||||
return True
|
||||
except:
|
||||
try:
|
||||
@@ -943,7 +947,7 @@ fullchain.pem Paste into certificate input box
|
||||
except:
|
||||
return False
|
||||
time.sleep(3)
|
||||
write_log(public.getMsg('ACME_CHECK_DNS3'))
|
||||
write_log(public.get_msg_gettext('|-Local authentication failed!'))
|
||||
return True
|
||||
|
||||
# 创建CSR
|
||||
@@ -954,11 +958,11 @@ fullchain.pem Paste into certificate input box
|
||||
X509Req = OpenSSL.crypto.X509Req()
|
||||
X509Req.get_subject().CN = domain_name
|
||||
if domain_alt_names:
|
||||
SAN = "DNS:{0}, ".format(domain_name).encode("utf8") + ", ".join(
|
||||
SAN = "DNS:{}, ".format(domain_name).encode("utf8") + ", ".join(
|
||||
"DNS:" + i for i in domain_alt_names
|
||||
).encode("utf8")
|
||||
else:
|
||||
SAN = "DNS:{0}".format(domain_name).encode("utf8")
|
||||
SAN = "DNS:{}".format(domain_name).encode("utf8")
|
||||
|
||||
X509Req.add_extensions(
|
||||
[
|
||||
@@ -984,7 +988,7 @@ fullchain.pem Paste into certificate input box
|
||||
acme_thumbprint = self.calculate_safe_base64(
|
||||
hashlib.sha256(acme_header_jwk_json.encode("utf8")).digest()
|
||||
)
|
||||
acme_keyauthorization = "{0}.{1}".format(token, acme_thumbprint)
|
||||
acme_keyauthorization = "{}.{}".format(token, acme_thumbprint)
|
||||
base64_of_acme_keyauthorization = self.calculate_safe_base64(
|
||||
hashlib.sha256(acme_keyauthorization.encode("utf8")).digest()
|
||||
)
|
||||
@@ -994,7 +998,7 @@ fullchain.pem Paste into certificate input box
|
||||
# 构造验证信息
|
||||
def get_identifier_auth(self, index, url, auth_info):
|
||||
s_type = self.get_auth_type(index)
|
||||
write_log(public.getMsg('ACME_BUILD_AUTH',(s_type,)))
|
||||
write_log(public.get_msg_gettext('|-Verification type: {}',(s_type,)))
|
||||
domain = auth_info['identifier']['value']
|
||||
wildcard = False
|
||||
# 处理通配符
|
||||
@@ -1019,7 +1023,7 @@ fullchain.pem Paste into certificate input box
|
||||
# 获取域名验证方式
|
||||
def get_auth_type(self, index):
|
||||
if not index in self._config['orders']:
|
||||
raise Exception(public.getMsg('ACME_ORDER_NOT_EXIST'))
|
||||
raise Exception(public.get_msg_gettext('The specified order does not exist!'))
|
||||
s_type = 'http-01'
|
||||
if 'auth_type' in self._config['orders'][index]:
|
||||
if self._config['orders'][index]['auth_type'] == 'dns':
|
||||
@@ -1087,7 +1091,7 @@ fullchain.pem Paste into certificate input box
|
||||
elif self._config['email']:
|
||||
payload = {
|
||||
"termsOfServiceAgreed": True,
|
||||
"contact": ["mailto:{0}".format(self._config['email'])],
|
||||
"contact": ["mailto:{}".format(self._config['email'])],
|
||||
}
|
||||
else:
|
||||
payload = {"termsOfServiceAgreed": True}
|
||||
@@ -1095,7 +1099,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',(str(res.json()),)))
|
||||
raise Exception(public.get_msg_gettext('Registration for ACME account failed: {}',(str(res.json()),)))
|
||||
kid = res.headers["Location"]
|
||||
return kid
|
||||
|
||||
@@ -1111,7 +1115,7 @@ fullchain.pem Paste into certificate input box
|
||||
protected = self.get_acme_header(url)
|
||||
protected64 = self.calculate_safe_base64(json.dumps(protected))
|
||||
signature = self.sign_message(
|
||||
message="{0}.{1}".format(protected64, payload64)) # bytes
|
||||
message="{}.{}".format(protected64, payload64)) # bytes
|
||||
signature64 = self.calculate_safe_base64(signature) # str
|
||||
data = json.dumps(
|
||||
{"protected": protected64, "payload": payload64,
|
||||
@@ -1172,7 +1176,7 @@ fullchain.pem Paste into certificate input box
|
||||
public_key_public_numbers = private_key.public_key().public_numbers()
|
||||
|
||||
exponent = "{0:x}".format(public_key_public_numbers.e)
|
||||
exponent = "0{0}".format(exponent) if len(
|
||||
exponent = "0{}".format(exponent) if len(
|
||||
exponent) % 2 else exponent
|
||||
modulus = "{0:x}".format(public_key_public_numbers.n)
|
||||
jwk = {
|
||||
@@ -1268,23 +1272,25 @@ fullchain.pem Paste into certificate input box
|
||||
index = None
|
||||
if 'index' in args:
|
||||
index = args['index']
|
||||
if 'auto_wildcard' in args:
|
||||
self._auto_wildcard = 1
|
||||
if not index: # 判断是否只想验证域名
|
||||
write_log(public.getMsg('ACME_CREAT_ORDER'))
|
||||
write_log(public.get_msg_gettext('|-Creating order..'))
|
||||
index = self.create_order(domains, auth_type, auth_to)
|
||||
write_log(public.getMsg('ACME_GET_V'))
|
||||
write_log(public.get_msg_gettext('|-Getting verification information..'))
|
||||
self.get_auths(index)
|
||||
if auth_to == 'dns' and len(self._config['orders'][index]['auths']) > 0:
|
||||
return self._config['orders'][index]
|
||||
write_log(public.getMsg('ACME_V_DOMAIN'))
|
||||
write_log(public.get_msg_gettext('|-Verifying domain name..'))
|
||||
self.auth_domain(index)
|
||||
self.remove_dns_record()
|
||||
write_log(public.getMsg('ACME_SEND_CSR'))
|
||||
write_log(public.get_msg_gettext('|-Sending CSR..'))
|
||||
self.send_csr(index)
|
||||
write_log(public.getMsg('ACME_DOWNLOAD_CERT'))
|
||||
write_log(public.get_msg_gettext('|-Downloading certificate..'))
|
||||
cert = self.download_cert(index)
|
||||
cert['status'] = True
|
||||
cert['msg'] = public.getMsg('ACME_APPLY_SUCCESS')
|
||||
write_log(public.getMsg('ACME_APPLY_SUCCESS1'))
|
||||
cert['msg'] = public.get_msg_gettext('Application successful!')
|
||||
write_log(public.get_msg_gettext('|-Successful application, deploying to site..'))
|
||||
return cert
|
||||
except Exception as ex:
|
||||
self.remove_dns_record()
|
||||
@@ -1295,7 +1301,7 @@ fullchain.pem Paste into certificate input box
|
||||
else:
|
||||
msg = ex
|
||||
write_log(public.get_error_info())
|
||||
return public.returnMsg(False, msg)
|
||||
return public.return_msg_gettext(False, msg)
|
||||
|
||||
# 申请证书 - api
|
||||
def apply_cert_api(self, args):
|
||||
@@ -1307,7 +1313,7 @@ fullchain.pem Paste into certificate input box
|
||||
try:
|
||||
project_info = json.loads(project_info)
|
||||
if not 'ssl_path' in project_info:
|
||||
return public.returnMsg(False, 'There is a problem with the current Java project configuration file, please rebuild')
|
||||
return public.return_msg_gettext(False, 'There is a problem with the current Java project configuration file, please rebuild')
|
||||
if not os.path.exists(project_info['ssl_path']):
|
||||
os.makedirs(project_info['ssl_path'])
|
||||
path = project_info['ssl_path']
|
||||
@@ -1319,7 +1325,7 @@ fullchain.pem Paste into certificate input box
|
||||
self._auto_wildcard = True
|
||||
return self.apply_cert(json.loads(args.domains), args.auth_type, args.auth_to)
|
||||
except:
|
||||
return public.returnMsg(False, 'There is a problem with the current Java project configuration file, please rebuild')
|
||||
return public.return_msg_gettext(False, 'There is a problem with the current Java project configuration file, please rebuild')
|
||||
else:
|
||||
if re.match(r"^\d+$", args.auth_to):
|
||||
import panelSite
|
||||
@@ -1330,7 +1336,7 @@ fullchain.pem Paste into certificate input box
|
||||
args.auth_to = args.auth_to[:-1]
|
||||
|
||||
if not os.path.exists(args.auth_to):
|
||||
return public.returnMsg(False, 'ACME_DIR_ERR')
|
||||
return public.return_msg_gettext(False, 'Invalid site directory, please check if the specified site exists!')
|
||||
|
||||
check_result = self.check_auth_env(args, check=True)
|
||||
if check_result: return check_result
|
||||
@@ -1423,8 +1429,8 @@ fullchain.pem Paste into certificate input box
|
||||
return
|
||||
for domain in json.loads(args.domains):
|
||||
if public.checkIp(domain): continue
|
||||
if domain.find('*.') >=0 and args.auth_type in ['http','tls']:
|
||||
raise public.returnMsg(False, 'ACME_PAN_DOMAIN_ERR')
|
||||
if domain.find('*.') != -1 and args.auth_type in ['http','tls']:
|
||||
raise public.return_msg_gettext(False, 'Pan domain names cannot apply for a certificate using [File Verification]!')
|
||||
import panelSite
|
||||
s = panelSite.panelSite()
|
||||
if args.auth_type in ['http','tls']:
|
||||
@@ -1460,7 +1466,7 @@ fullchain.pem Paste into certificate input box
|
||||
s.ModifyRedirect(args)
|
||||
redirect_tmp[args.sitename].append(x['redirectname'])
|
||||
else:
|
||||
if x['type']: return public.returnMsg(False, 'SITE_SSL_ERR_301')
|
||||
if x['type']: return public.return_msg_gettext(False, 'Your site has 301 Redirect on,Please turn it off first!')
|
||||
if redirect_tmp[args.sitename]:
|
||||
public.writeFile('{}/data/stop_r_tmp.pl'.format(public.get_panel_path()),json.dumps(redirect_tmp))
|
||||
data = s.GetProxyList(args)
|
||||
@@ -1486,13 +1492,13 @@ fullchain.pem Paste into certificate input box
|
||||
write_log("|- Turning off proxy {}".format(args.proxyname))
|
||||
proxy_tmp[args.sitename].append(x['proxyname'])
|
||||
else:
|
||||
if x['type']: return public.returnMsg(False,'ACME_PROXY_ERR')
|
||||
if x['type']: return public.return_msg_gettext(False,'Sites with reverse proxy turned on cannot apply for SSL!')
|
||||
if proxy_tmp[args.sitename]:
|
||||
public.writeFile('{}/data/stop_p_tmp.pl'.format(public.get_panel_path()),json.dumps(proxy_tmp))
|
||||
# 检查旧重定向是否开启
|
||||
data = s.Get301Status(args)
|
||||
if data['status']:
|
||||
return public.returnMsg(False,'SITE_SSL_ERR_3011')
|
||||
return public.return_msg_gettext(False,'The website has been redirected, please close it before applying!')
|
||||
#判断是否强制HTTPS
|
||||
if s.IsToHttps(args.siteName):
|
||||
if os.path.exists(self._stop_rp_file):
|
||||
@@ -1501,14 +1507,14 @@ fullchain.pem Paste into certificate input box
|
||||
s.CloseToHttps(args)
|
||||
public.writeFile('{}/data/stop_httptohttps.pl'.format(public.get_panel_path()), '')
|
||||
else:
|
||||
return public.returnMsg(False, 'ACME_FORCE_SSL_ERR')
|
||||
return public.return_msg_gettext(False, 'After configuring Force HTTPS, you cannot use [File Verification] to apply for a certificate!')
|
||||
public.serviceReload()
|
||||
except:
|
||||
return False
|
||||
else:
|
||||
if args.auth_to.find('Dns_com') != -1:
|
||||
if not os.path.exists('plugin/dns/dns_main.py'):
|
||||
return public.returnMsg(False, 'ACME_DNS_ERR')
|
||||
return public.return_msg_gettext(False, 'Please go to the software store to install [cloud analysis], and complete the domain name NS binding.')
|
||||
return False
|
||||
|
||||
# DNS手动验证
|
||||
@@ -1601,6 +1607,138 @@ fullchain.pem Paste into certificate input box
|
||||
site_status = public.M('sites').where('id=?', (site_id,)).field('status').select()[0]['status']
|
||||
return site_status
|
||||
|
||||
def get_index(self, domains):
|
||||
'''
|
||||
@name 获取标识
|
||||
@author hwliang<2022-02-10>
|
||||
@param domains<list> 域名列表
|
||||
@return string
|
||||
'''
|
||||
identifiers = []
|
||||
for domain_name in domains:
|
||||
identifiers.append({"type": 'dns', "value": domain_name})
|
||||
return public.md5(json.dumps(identifiers))
|
||||
|
||||
# 续签同品牌其它证书
|
||||
def renew_cert_other(self):
|
||||
'''
|
||||
@name 续签同品牌其它证书
|
||||
@author hwliang<2022-02-10>
|
||||
@return void
|
||||
'''
|
||||
cert_path = "{}/vhost/cert".format(public.get_panel_path())
|
||||
if not os.path.exists(cert_path): return
|
||||
new_time = time.time() + (86400 * 30)
|
||||
n = 0
|
||||
if not 'orders' in self._config: self._config['orders'] = {}
|
||||
import panelSite
|
||||
siteObj = panelSite.panelSite()
|
||||
args = public.dict_obj()
|
||||
for siteName in os.listdir(cert_path):
|
||||
try:
|
||||
cert_file = '{}/{}/fullchain.pem'.format(cert_path, siteName)
|
||||
if not os.path.exists(cert_file): continue # 无证书文件
|
||||
siteInfo = public.M('sites').where('name=?', siteName).find()
|
||||
if not siteInfo: continue # 无网站信息
|
||||
cert_init = self.get_cert_init(cert_file)
|
||||
if not cert_init: continue # 无法获取证书
|
||||
end_time = time.mktime(time.strptime(cert_init['notAfter'], '%Y-%m-%d'))
|
||||
if end_time > new_time: continue # 未到期
|
||||
try:
|
||||
if not cert_init['issuer'] in ['R3', "Let's Encrypt"] and cert_init['issuer'].find(
|
||||
"Let's Encrypt") == -1:
|
||||
continue # 非同品牌证书
|
||||
except:
|
||||
continue
|
||||
|
||||
if isinstance(cert_init['dns'], str): cert_init['dns'] = [cert_init['dns']]
|
||||
index = self.get_index(cert_init['dns'])
|
||||
if index in self._config['orders'].keys(): continue # 已在订单列表
|
||||
|
||||
n += 1
|
||||
write_log("|-Renewing additional certificate {}, domain name:{}..".format(n, cert_init['subject']))
|
||||
write_log("|-Creating order..")
|
||||
args.id = siteInfo['id']
|
||||
runPath = siteObj.GetRunPath(args)
|
||||
if runPath and not runPath in ['/']:
|
||||
path = siteInfo['path'] + '/' + runPath
|
||||
else:
|
||||
path = siteInfo['path']
|
||||
|
||||
self.renew_cert_to(cert_init['dns'],'http',path.replace('//','/'))
|
||||
except:
|
||||
write_log("|-Renewal failed:")
|
||||
|
||||
def renew_cert_to(self, domains, auth_type, auth_to, index=None):
|
||||
siteName = None
|
||||
cert = {}
|
||||
args = public.dict_obj()
|
||||
if auth_to[-1] == "/":
|
||||
auth_to = auth_to[:-1]
|
||||
site_id = public.M('sites').where('path=?', auth_to).getField('id')
|
||||
args.id = site_id
|
||||
if os.path.exists(auth_to):
|
||||
if public.M('sites').where('path=?', auth_to).count() == 1:
|
||||
# site_id = public.M('sites').where('path=?',auth_to).getField('id')
|
||||
siteName = public.M('sites').where('path=?', auth_to).getField('name')
|
||||
import panelSite
|
||||
siteObj = panelSite.panelSite()
|
||||
# args = public.dict_obj()
|
||||
# args.id = site_id
|
||||
runPath = siteObj.GetRunPath(args)
|
||||
if runPath and not runPath in ['/']:
|
||||
path = auth_to + '/' + runPath
|
||||
if os.path.exists(path): auth_to = path.replace('//', '/')
|
||||
|
||||
else:
|
||||
siteName = self.get_site_name_by_domains(domains)
|
||||
try:
|
||||
index = self.create_order(
|
||||
domains,
|
||||
auth_type,
|
||||
auth_to.replace('//', '/'),
|
||||
index
|
||||
)
|
||||
|
||||
write_log("|-Getting verification information..")
|
||||
self.get_auths(index)
|
||||
write_log("|-Verifying domain name..")
|
||||
self.auth_domain(index)
|
||||
write_log("|-Sending CSR..")
|
||||
self.remove_dns_record()
|
||||
self.send_csr(index)
|
||||
write_log("|-Downloading certificate..")
|
||||
cert = self.download_cert(index)
|
||||
self._config['orders'][index]['renew_time'] = int(time.time())
|
||||
|
||||
# 清理失败重试记录
|
||||
self._config['orders'][index]['retry_count'] = 0
|
||||
self._config['orders'][index]['next_retry_time'] = 0
|
||||
|
||||
# 保存证书配置
|
||||
self.save_config()
|
||||
cert['status'] = True
|
||||
cert['msg'] = 'Renewed successfully!'
|
||||
write_log("|-Renewed successfully!!")
|
||||
except Exception as e:
|
||||
if str(e).find('please try again later') == -1: # 受其它证书影响和连接CA失败的的不记录重试次数
|
||||
if index:
|
||||
# 设置下次重试时间
|
||||
self._config['orders'][index]['next_retry_time'] = int(time.time() + (86400 * 2))
|
||||
# 记录重试次数
|
||||
if not 'retry_count' in self._config['orders'][index].keys():
|
||||
self._config['orders'][index]['retry_count'] = 1
|
||||
self._config['orders'][index]['retry_count'] += 1
|
||||
# 保存证书配置
|
||||
self.save_config()
|
||||
msg = str(e).split('>>>>')[0]
|
||||
write_log("|-" + msg)
|
||||
return public.returnMsg(False, msg)
|
||||
finally:
|
||||
self.turnon_redirect_proxy_httptohttps(args)
|
||||
write_log("-" * 70)
|
||||
return cert
|
||||
|
||||
# 续签证书
|
||||
def renew_cert(self, index):
|
||||
write_log("", "wb+")
|
||||
@@ -1612,10 +1750,11 @@ fullchain.pem Paste into certificate input box
|
||||
# 在面板点击申请证书时不要重启面板以防后续请求出错
|
||||
self._by_panel = True
|
||||
if index not in self._config['orders']:
|
||||
raise Exception(public.getMsg('ACME_RENEW_ERR'))
|
||||
raise Exception(public.get_msg_gettext('The specified order number does not exist and cannot be renewed!'))
|
||||
order_index.append(index)
|
||||
else:
|
||||
s_time = time.time() + (30 * 86400)
|
||||
if not 'orders' in self._config: self._config['orders'] = {}
|
||||
for i in self._config['orders'].keys():
|
||||
if not 'save_path' in self._config['orders'][i]:
|
||||
continue
|
||||
@@ -1645,17 +1784,21 @@ fullchain.pem Paste into certificate input box
|
||||
|
||||
# 是否到了最大重试次数
|
||||
if 'retry_count' in self._config['orders'][i]:
|
||||
if self._config['orders'][i]['retry_count'] >= 3:
|
||||
write_log('|-Skip the domain name this time: {}, this certificate will not be renewed due to failure to renew 3 times in a row, (The number of errors will be reset after manual renewal and success)'.format(self._config['orders'][i]['domains']))
|
||||
if self._config['orders'][i]['retry_count'] >= 5:
|
||||
write_log('|-Skip the domain name this time: {}, this certificate will not be renewed due to failure to renew 5 times in a row, (The number of errors will be reset after manual renewal and success)'.format(self._config['orders'][i]['domains']))
|
||||
continue
|
||||
|
||||
# 加入到续签订单
|
||||
order_index.append(i)
|
||||
|
||||
if not order_index:
|
||||
write_log(public.getMsg('ACME_NO_NEED_RENEW'))
|
||||
return public.returnMsg(False,public.getMsg('ACME_NO_NEED_RENEW'))
|
||||
write_log(public.getMsg("ACME_NEED_RENEW",(str(len(order_index)),)))
|
||||
write_log(public.get_msg_gettext('|-No SSL certificate found within 30 days!'))
|
||||
self.get_apis()
|
||||
self.renew_cert_other()
|
||||
# return public.return_msg_gettext(False,public.get_msg_gettext('|-No SSL certificate found within 30 days!'))
|
||||
write_log("|-All tasks have been processed!")
|
||||
return
|
||||
write_log(public.get_msg_gettext('|-A total of {} certificates need to be renewed',(str(len(order_index)),)))
|
||||
n = 0
|
||||
self.get_apis()
|
||||
cert = None
|
||||
@@ -1671,53 +1814,54 @@ fullchain.pem Paste into certificate input box
|
||||
write_log('|-Renew the visa certificate and start checking the environment')
|
||||
self.check_auth_env(args,check=True)
|
||||
n += 1
|
||||
write_log(public.getMsg("ACME_RENEWING",(str(n),str(self._config['orders'][index]['domains']))))
|
||||
write_log(public.getMsg('ACME_CREAT_ORDER'))
|
||||
try:
|
||||
run_path = self.get_site_runpath(self._config['orders'][index]['domains'])
|
||||
if run_path:
|
||||
if self._config['orders'][index]['auth_to'] != run_path:
|
||||
self._config['orders'][index]['auth_to'] = run_path
|
||||
index = self.create_order(
|
||||
self._config['orders'][index]['domains'],
|
||||
self._config['orders'][index]['auth_type'],
|
||||
self._config['orders'][index]['auth_to'],
|
||||
index
|
||||
)
|
||||
write_log(public.getMsg('ACME_GET_V'))
|
||||
self.get_auths(index)
|
||||
write_log(public.getMsg('ACME_V_DOMAIN'))
|
||||
self.auth_domain(index)
|
||||
write_log(public.getMsg('ACME_SEND_CSR'))
|
||||
self.remove_dns_record()
|
||||
self.send_csr(index)
|
||||
write_log(public.getMsg('ACME_DOWNLOAD_CERT'))
|
||||
cert = self.download_cert(index)
|
||||
self._config['orders'][index]['renew_time'] = int(time.time())
|
||||
|
||||
# 清理失败重试记录
|
||||
self._config['orders'][index]['retry_count'] = 0
|
||||
self._config['orders'][index]['next_retry_time'] = 0
|
||||
|
||||
# 保存证书配置
|
||||
self.save_config()
|
||||
cert['status'] = True
|
||||
cert['msg'] = public.getMsg('ACME_RENEW_SUCCESS')
|
||||
if os.path.exists(self._stop_rp_file):
|
||||
self.turnon_redirect_proxy_httptohttps(args)
|
||||
write_log(public.getMsg('ACME_RENEW_SUCCESS1'))
|
||||
except Exception as e:
|
||||
if str(e).find('请稍候重试') == -1: # 受其它证书影响和连接CA失败的的不记录重试次数
|
||||
# 设置下次重试时间
|
||||
self._config['orders'][index]['next_retry_time'] = int(time.time() + (86400 * 2))
|
||||
# 记录重试次数
|
||||
if not 'retry_count' in self._config['orders'][index].keys():
|
||||
self._config['orders'][index]['retry_count'] = 1
|
||||
self._config['orders'][index]['retry_count'] += 1
|
||||
# 保存证书配置
|
||||
self.save_config()
|
||||
write_log("|-" + str(e).split('>>>>')[0])
|
||||
write_log("-" * 70)
|
||||
write_log(public.get_msg_gettext('|-Renewing certificate number of {},domain: {}..',(str(n),str(self._config['orders'][index]['domains']))))
|
||||
write_log(public.get_msg_gettext('|-Creating order..'))
|
||||
cert = self.renew_cert_to(self._config['orders'][index]['domains'],self._config['orders'][index]['auth_type'],self._config['orders'][index]['auth_to'],index)
|
||||
# try:
|
||||
# run_path = self.get_site_runpath(self._config['orders'][index]['domains'])
|
||||
# if run_path:
|
||||
# if self._config['orders'][index]['auth_to'] != run_path:
|
||||
# self._config['orders'][index]['auth_to'] = run_path
|
||||
# index = self.create_order(
|
||||
# self._config['orders'][index]['domains'],
|
||||
# self._config['orders'][index]['auth_type'],
|
||||
# self._config['orders'][index]['auth_to'],
|
||||
# index
|
||||
# )
|
||||
# write_log(public.get_msg_gettext('|-Getting verification information..'))
|
||||
# self.get_auths(index)
|
||||
# write_log(public.get_msg_gettext('|-Verifying domain name..'))
|
||||
# self.auth_domain(index)
|
||||
# write_log(public.get_msg_gettext('|-Sending CSR..'))
|
||||
# self.remove_dns_record()
|
||||
# self.send_csr(index)
|
||||
# write_log(public.get_msg_gettext('|-Downloading certificate..'))
|
||||
# cert = self.download_cert(index)
|
||||
# self._config['orders'][index]['renew_time'] = int(time.time())
|
||||
#
|
||||
# # 清理失败重试记录
|
||||
# self._config['orders'][index]['retry_count'] = 0
|
||||
# self._config['orders'][index]['next_retry_time'] = 0
|
||||
#
|
||||
# # 保存证书配置
|
||||
# self.save_config()
|
||||
# cert['status'] = True
|
||||
# cert['msg'] = public.get_msg_gettext('Renewed successfully!')
|
||||
# if os.path.exists(self._stop_rp_file):
|
||||
# self.turnon_redirect_proxy_httptohttps(args)
|
||||
# write_log(public.get_msg_gettext('|-Renewed successfully!'))
|
||||
# except Exception as e:
|
||||
# if str(e).find('请稍候重试') == -1: # 受其它证书影响和连接CA失败的的不记录重试次数
|
||||
# # 设置下次重试时间
|
||||
# self._config['orders'][index]['next_retry_time'] = int(time.time() + (86400 * 2))
|
||||
# # 记录重试次数
|
||||
# if not 'retry_count' in self._config['orders'][index].keys():
|
||||
# self._config['orders'][index]['retry_count'] = 1
|
||||
# self._config['orders'][index]['retry_count'] += 1
|
||||
# # 保存证书配置
|
||||
# self.save_config()
|
||||
# write_log("|-" + str(e).split('>>>>')[0])
|
||||
# write_log("-" * 70)
|
||||
return cert
|
||||
except Exception as ex:
|
||||
self.remove_dns_record()
|
||||
@@ -1728,7 +1872,7 @@ fullchain.pem Paste into certificate input box
|
||||
else:
|
||||
msg = ex
|
||||
write_log(public.get_error_info())
|
||||
return public.returnMsg(False, msg)
|
||||
return public.return_msg_gettext(False, msg)
|
||||
|
||||
|
||||
def echo_err(msg):
|
||||
@@ -1751,22 +1895,22 @@ def write_log(log_str, mode="ab+"):
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
p = argparse.ArgumentParser(usage=public.getMsg('ACME_USE_TIPS'))
|
||||
p = argparse.ArgumentParser(usage=public.get_msg_gettext('Required parameters: --domain list of domain names, multiple separated by commas!'))
|
||||
p.add_argument('--domain', default=None,
|
||||
help=public.getMsg('ACME_USE_TIPS1'), dest="domains")
|
||||
p.add_argument('--type', default=None, help=public.getMsg('ACME_USE_TIPS2'), dest="auth_type")
|
||||
p.add_argument('--path', default=None, help=public.getMsg('ACME_USE_TIPS3'), dest="path")
|
||||
p.add_argument('--dnsapi', default=None, help=public.getMsg('ACME_USE_TIPS4'), dest="dnsapi")
|
||||
p.add_argument('--dns_key', default=None, help=public.getMsg('ACME_USE_TIPS5'), dest="key")
|
||||
p.add_argument('--dns_secret', default=None,help=public.getMsg('ACME_USE_TIPS6'), dest="secret")
|
||||
p.add_argument('--index', default=None, help=public.getMsg('ACME_USE_TIPS7'), dest="index")
|
||||
p.add_argument('--renew', default=None, help=public.getMsg('ACME_USE_TIPS8'), dest="renew")
|
||||
p.add_argument('--revoke', default=None, help=public.getMsg('ACME_USE_TIPS9'), dest="revoke")
|
||||
help=public.get_msg_gettext('Please specify the domain name to apply for a certificate'), dest="domains")
|
||||
p.add_argument('--type', default=None, help=public.get_msg_gettext('Please specify verification type'), dest="auth_type")
|
||||
p.add_argument('--path', default=None, help=public.get_msg_gettext('Please specify the website document root'), dest="path")
|
||||
p.add_argument('--dnsapi', default=None, help=public.get_msg_gettext('Please specify DNSAPI'), dest="dnsapi")
|
||||
p.add_argument('--dns_key', default=None, help=public.get_msg_gettext('Please specify DNSAPI key'), dest="key")
|
||||
p.add_argument('--dns_secret', default=None,help=public.get_msg_gettext('Please specify DNSAPI secret'), dest="secret")
|
||||
p.add_argument('--index', default=None, help=public.get_msg_gettext('Specify the order index'), dest="index")
|
||||
p.add_argument('--renew', default=None, help=public.get_msg_gettext('renew certificate'), dest="renew")
|
||||
p.add_argument('--revoke', default=None, help=public.get_msg_gettext('Revoke certificate'), dest="revoke")
|
||||
args = p.parse_args()
|
||||
cert = None
|
||||
if args.revoke:
|
||||
if not args.index:
|
||||
echo_err(public.getMsg('ACME_USE_TIPS10'))
|
||||
echo_err(public.get_msg_gettext('Please enter the index of the order to be revoked in the --index parameter'))
|
||||
p = acme_v2()
|
||||
result = p.revoke_order(args.index)
|
||||
write_log(result)
|
||||
@@ -1779,24 +1923,24 @@ if __name__ == "__main__":
|
||||
try:
|
||||
if not args.index:
|
||||
if not args.domains:
|
||||
echo_err(public.getMsg('ACME_USE_TIPS11'))
|
||||
echo_err(public.get_msg_gettext('Please specify the domain name for which you want to apply for a certificate in the --domain parameter, multiple separated by commas (,)'))
|
||||
if not args.auth_type in ['http', 'tls', 'dns']:
|
||||
echo_err(public.getMsg('ACME_USE_TIPS12'))
|
||||
echo_err(public.get_msg_gettext('Please specify the correct authentication type in the --type parameter, supporting dns and http'))
|
||||
auth_to = ''
|
||||
if args.auth_type in ['http', 'tls']:
|
||||
if not args.path:
|
||||
echo_err(public.getMsg('ACME_USE_TIPS13'))
|
||||
echo_err(public.get_msg_gettext('Please specify the website document root in the --path parameter!'))
|
||||
if not os.path.exists(args.path):
|
||||
echo_err(public.getMsg('ACME_USE_TIPS14',(args.path,)))
|
||||
echo_err(public.get_msg_gettext('The specified site root does not exist, please check: {}',(args.path,)))
|
||||
auth_to = args.path
|
||||
else:
|
||||
if args.dnsapi == '0':
|
||||
auth_to = 'dns'
|
||||
else:
|
||||
if not args.key:
|
||||
echo_err(public.getMsg('ACME_USE_TIPS15'))
|
||||
echo_err(public.get_msg_gettext('When applying using dnsapi, specify the dnsapi key in the --dns_key parameter!'))
|
||||
if not args.secret:
|
||||
echo_err(public.getMsg('ACME_USE_TIPS16'))
|
||||
echo_err(public.get_msg_gettext('When applying using dnsapi, specify the secret of dnsapi in the --dns_secret parameter!'))
|
||||
auth_to = "{}|{}|{}".format(
|
||||
args.dnsapi, args.key, args.secret)
|
||||
|
||||
@@ -1808,27 +1952,27 @@ if __name__ == "__main__":
|
||||
acme_txt = '_acme-challenge.'
|
||||
acme_caa = '1 issue letsencrypt.org'
|
||||
write_log("=" * 65)
|
||||
write_log("\033[32m"+public.getMsg('ACME_USE_TIPS17')+"\033[0m")
|
||||
write_log("\033[32m"+public.get_msg_gettext('|-Manual order submission is successful, please resolve DNS records according to the following tips: ')+"\033[0m")
|
||||
write_log("=" * 65)
|
||||
write_log(public.getMsg('ACME_USE_TIPS18',(cert['index'],)))
|
||||
write_log(public.getMsg('ACME_USE_TIPS19')+": ./acme_v2.py --index=\"{}\"".format(cert['index']))
|
||||
write_log(public.getMsg('ACME_USE_TIPS20',(len(cert['auths']),)))
|
||||
write_log(public.get_msg_gettext('|-Order index: {}',(cert['index'],)))
|
||||
write_log(public.get_msg_gettext('|-Retry the command')+": ./acme_v2.py --index=\"{}\"".format(cert['index']))
|
||||
write_log(public.get_msg_gettext('|-A total of \033[36m{}\033[0m domain name records need to be resolved.',(len(cert['auths']),)))
|
||||
for i in range(len(cert['auths'])):
|
||||
write_log('-' * 70)
|
||||
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(public.get_msg_gettext('|-The \033[36m{}\033[0m domain names are: {}, please resolve the following information: ',(str(i+1), cert['auths'][i]['domain'])))
|
||||
write_log(public.get_msg_gettext('|-Record Type: TXT Record Name: \033[41m{}\033[0m Record Value: \033[41m{}\033 [0m [Required]',(acme_txt + cert['auths'][i]['domain'].replace('*.', ''), cert['auths'][i]['auth_value'])))
|
||||
write_log(public.get_msg_gettext('|-Record type: CAA Record name: \033[41m{}\033[0m Record value: \033[41m{}\033[0m [Optional]',(cert['auths'][i]['domain'].replace('*.', ''), acme_caa)))
|
||||
write_log('-' * 70)
|
||||
input_data = ""
|
||||
while input_data not in ['y', 'Y', 'n', 'N']:
|
||||
input_msg = public.getMsg('ACME_USE_TIPS24')
|
||||
input_msg = public.get_msg_gettext('Please wait 2-3 minutes after completing the resolution and enter Y and press Enter to continue verifying the domain name: ')
|
||||
if sys.version_info[0] == 2:
|
||||
input_data = raw_input(input_msg)
|
||||
else:
|
||||
input_data = input(input_msg)
|
||||
if input_data in ['n', 'N']:
|
||||
write_log("=" * 65)
|
||||
write_log(public.getMsg('ACME_USE_TIPS25'))
|
||||
write_log(public.get_msg_gettext('|-The user abandons the application and exits the program!'))
|
||||
exit()
|
||||
cert = p.apply_cert(
|
||||
[], auth_type=args.auth_type, auth_to='dns', index=cert['index'])
|
||||
@@ -1843,8 +1987,8 @@ if __name__ == "__main__":
|
||||
if not cert:
|
||||
exit()
|
||||
write_log("=" * 65)
|
||||
write_log(public.getMsg('ACME_USE_TIPS26'))
|
||||
write_log(public.get_msg_gettext('|-Certificate obtained successfully!'))
|
||||
write_log("=" * 65)
|
||||
write_log(public.getMsg('ACME_USE_TIPS27',(','.join(cert['domains']),)))
|
||||
write_log(public.getMsg('ACME_USE_TIPS28',(public.format_date(times=cert['cert_timeout']),)))
|
||||
write_log(public.getMsg('ACME_USE_TIPS29',(cert['save_path'],)))
|
||||
write_log(public.get_msg_gettext('Certified Domain Name: {}',(','.join(cert['domains']),)))
|
||||
write_log(public.get_msg_gettext('Certificate expiration time: {}',(public.format_date(times=cert['cert_timeout']),)))
|
||||
write_log(public.get_msg_gettext('Certificate saved at: {}/',(cert['save_path'],)))
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# +-------------------------------------------------------------------
|
||||
# | Author: hwliang <hwl@bt.cn>
|
||||
# +-------------------------------------------------------------------
|
||||
from BTPanel import session,request
|
||||
from BTPanel import session,request,cache
|
||||
import public,os,json,time,apache,psutil
|
||||
class ajax:
|
||||
__official_url = 'https://brandnew.aapanel.com'
|
||||
@@ -25,7 +25,7 @@ class ajax:
|
||||
pass
|
||||
def GetNginxStatus(self,get):
|
||||
try:
|
||||
if not os.path.exists('/www/server/nginx/sbin/nginx'): return public.returnMsg(False,'NGINX_NOT_INSTALL')
|
||||
if not os.path.exists('/www/server/nginx/sbin/nginx'): return public.return_msg_gettext(False,'Nginx is 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
|
||||
@@ -66,8 +66,8 @@ class ajax:
|
||||
data['workermen'] = "%s%s" % (int(workermen), "MB")
|
||||
return data
|
||||
except Exception as ex:
|
||||
public.WriteLog('GET_INFO','NGINX_LOAD_ERR',(ex,))
|
||||
return public.returnMsg(False,'GET_DATA_ERR')
|
||||
public.write_log_gettext('Get Info','Nginx load status acquisition failed:{}',(ex,))
|
||||
return public.return_msg_gettext(False,'Data acquisition failed!')
|
||||
|
||||
def GetPHPStatus(self,get):
|
||||
#取指定PHP版本的负载状态
|
||||
@@ -80,8 +80,8 @@ class ajax:
|
||||
tmp['start time'] = time.strftime('%Y-%m-%d %H:%M:%S',fTime)
|
||||
return tmp
|
||||
except Exception as ex:
|
||||
public.WriteLog('GET_INFO',"PHP_LOAD_ERR",(public.get_error_info(),))
|
||||
return public.returnMsg(False,'PHP_LOAD_ERR1')
|
||||
public.write_log_gettext('Get Info',"PHP load status acquisition failed: {}",(public.get_error_info(),))
|
||||
return public.return_msg_gettext(False,'PHP load status acquisition failed!')
|
||||
|
||||
def CheckStatusConf(self):
|
||||
if public.get_webserver() != 'nginx': return
|
||||
@@ -152,19 +152,19 @@ class ajax:
|
||||
|
||||
def CheckLibInstall(self,checks):
|
||||
for cFile in checks:
|
||||
if os.path.exists(cFile): return public.GetMsg("ALREADY_INSTALLED")
|
||||
return public.GetMsg("NOT_INSTALL")
|
||||
if os.path.exists(cFile): return public.GetMsg('Already installed')
|
||||
return public.GetMsg('Not installed')
|
||||
|
||||
#取插件操作选项
|
||||
def GetLibOpt(self,status,libName):
|
||||
optStr = ''
|
||||
if status == public.GetMsg("NOT_INSTALL"):
|
||||
optStr = '<a class="link" href="javascript:InstallLib(\''+libName+'\');">'+public.GetMsg("INSTALL")+'</a>'
|
||||
if status == public.GetMsg('Not installed'):
|
||||
optStr = '<a class="link" href="javascript:InstallLib(\''+libName+'\');">'+public.GetMsg('Uninstallaton succeeded')+'</a>'
|
||||
else:
|
||||
libConfig = public.GetMsg("CONF")
|
||||
if(libName == 'beta'): libConfig = public.GetMsg("CLOSE_BETA")
|
||||
libConfig = public.GetMsg('Old configuration')
|
||||
if(libName == 'beta'): libConfig = public.GetMsg('Beta tester profile')
|
||||
|
||||
optStr = '<a class="link" href="javascript:SetLibConfig(\''+libName+'\');">'+libConfig+'</a> | <a class="link" href="javascript:UninstallLib(\''+libName+'\');">'+public.GetMsg("UNINSTALL")+'</a>';
|
||||
optStr = '<a class="link" href="javascript:SetLibConfig(\''+libName+'\');">'+libConfig+'</a> | <a class="link" href="javascript:UninstallLib(\''+libName+'\');">'+public.get_msg_gettext("Uninstallaton succeeded")+'</a>';
|
||||
return optStr
|
||||
|
||||
#取插件AS
|
||||
@@ -189,9 +189,9 @@ class ajax:
|
||||
result = public.ExecShell(public.get_python_bin() + " " + public.GetConfigValue('setup_path') + "/panel/script/backup_"+get.name+".py list")
|
||||
|
||||
if result[0].find("ERROR:") == -1:
|
||||
public.WriteLog("PLUG_MAM","SET_PLUG[" +info['name']+ "]AS!")
|
||||
return public.returnMsg(True, 'SET_SUCCESS')
|
||||
return public.returnMsg(False,'AK_SK_CONNECT_ERROR',(info['name'],))
|
||||
public.write_log_gettext("Plugin manager","Set plugin [" +info['name']+ "]AS!")
|
||||
return public.return_msg_gettext(True, 'Successfully set')
|
||||
return public.return_msg_gettext(False,'ERROR: Unable to connect to the {} server, please check if the [AK/SK/Storage] setting is correct!',(info['name'],))
|
||||
|
||||
#设置内测
|
||||
def SetBeta(self,get):
|
||||
@@ -229,7 +229,7 @@ class ajax:
|
||||
result = public.ExecShell(public.get_python_bin() + " " + public.GetConfigValue('setup_path') + "/panel/script/backup_"+get.name+".py list")
|
||||
return json.loads(result[0])
|
||||
except:
|
||||
return public.returnMsg(False, 'GET_QINIU_FILE_LIST')
|
||||
return public.return_msg_gettext(False, 'Failed to get the list, please check if the [AK/SK/Storage] setting is correct!')
|
||||
|
||||
|
||||
|
||||
@@ -301,11 +301,11 @@ class ajax:
|
||||
import psutil
|
||||
p = psutil.Process(int(get.pid))
|
||||
name = p.name()
|
||||
if name == 'python': return public.returnMsg(False,'KILL_PROCESS_ERR')
|
||||
if name == 'python': return public.return_msg_gettext(False,'Error, cannot end task processes!')
|
||||
|
||||
p.kill()
|
||||
public.WriteLog('TYPE_PROCESS','KILL_PROCESS',(get.pid,name))
|
||||
return public.returnMsg(True,'KILL_PROCESS',(get.pid,name))
|
||||
public.write_log_gettext('Task manager','Ended processes[{}][{}] Successfully!',(get.pid,name))
|
||||
return public.return_msg_gettext(True,'Ended processes[{}][{}] Successfully!',(get.pid,name))
|
||||
|
||||
def GoToProcess(self,name):
|
||||
ps = ['sftp-server','login','nm-dispatcher','irqbalance','qmgr','wpa_supplicant','lvmetad','auditd','master','dbus-daemon','tapdisk','sshd','init','ksoftirqd','kworker','kmpathd','kmpath_handlerd','python','kdmflush','bioset','crond','kthreadd','migration','rcu_sched','kjournald','iptables','systemd','network','dhclient','systemd-journald','NetworkManager','systemd-logind','systemd-udevd','polkitd','tuned','rsyslogd']
|
||||
@@ -445,8 +445,8 @@ class ajax:
|
||||
public.writeFile('/www/server/panel/data/is_beta.pl','true')
|
||||
try:
|
||||
return {'status': True, 'msg': "Successful application!"}
|
||||
except: return public.returnMsg(False,'AJAX_CONN_ERR')
|
||||
except: return public.returnMsg(False,'AJAX_USER_BINDING_ERR')
|
||||
except: return public.return_msg_gettext(False,'Fail to connect to the server!')
|
||||
except: return public.return_msg_gettext(False,'Please bind your account first!')
|
||||
|
||||
def to_not_beta(self,get):
|
||||
try:
|
||||
@@ -461,8 +461,8 @@ class ajax:
|
||||
if os.path.exists(beta_file):
|
||||
os.remove(beta_file)
|
||||
return {"status": True, "msg": "Successful application!"}
|
||||
except: return public.returnMsg(False,'AJAX_CONN_ERR')
|
||||
except: return public.returnMsg(False,'AJAX_USER_BINDING_ERR')
|
||||
except: return public.return_msg_gettext(False,'Fail to connect to the server!')
|
||||
except: return public.return_msg_gettext(False,'Please bind your account first!')
|
||||
|
||||
def to_beta(self):
|
||||
try:
|
||||
@@ -483,11 +483,10 @@ class ajax:
|
||||
#获取最新的5条测试版更新日志
|
||||
def get_beta_logs(self,get):
|
||||
try:
|
||||
# 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')
|
||||
return public.return_msg_gettext(False,'Fail to connect to the server!')
|
||||
|
||||
def get_other_info(self):
|
||||
other = {}
|
||||
@@ -502,13 +501,11 @@ class ajax:
|
||||
|
||||
def UpdatePanel(self,get):
|
||||
try:
|
||||
if not public.IsRestart(): return public.returnMsg(False,'EXEC_ERR_TASK')
|
||||
if not public.IsRestart(): return public.return_msg_gettext(False,'Please run the program when all install tasks finished!')
|
||||
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('{}/api/setupCount/setupPanel?type=Linux'.format(self.__official_url))
|
||||
public.arequests('get', '{}/api/setupCount/setupPanel?type=Linux'.format(self.__official_url))
|
||||
|
||||
public.M('config').where("id=?",('1',)).setField('status',1)
|
||||
|
||||
#取回远程版本信息
|
||||
@@ -535,21 +532,22 @@ class ajax:
|
||||
data['oem'] = ''
|
||||
data['intrusion'] = 0
|
||||
data['uid'] = self.get_uid()
|
||||
#msg = public.getMsg('PANEL_UPDATE_MSG');
|
||||
#msg = public.getMsg('Current version is stable version and already latest. Update cycle of stable version is generally 2 months,while developer version will update every Wednesday!');
|
||||
data['o'] = public.get_oem_name()
|
||||
sUrl = '{}/api/panel/updateLinuxEn'.format(self.__official_url)
|
||||
updateInfo = json.loads(public.httpPost(sUrl,data))
|
||||
if not updateInfo: return public.returnMsg(False,"CONNECT_ERR")
|
||||
if not updateInfo: return public.return_msg_gettext(False,'Failed to connect server!')
|
||||
#updateInfo['msg'] = msg;
|
||||
if os.path.exists('/www/server/panel/data/is_beta.pl'):
|
||||
updateInfo['is_beta'] = 1
|
||||
session['updateInfo'] = updateInfo
|
||||
|
||||
#检查是否需要升级
|
||||
if updateInfo['is_beta'] == 1:
|
||||
if updateInfo['beta']['version'] ==session['version']: return public.returnMsg(False,updateInfo)
|
||||
else:
|
||||
if updateInfo['version'] ==session['version']: return public.returnMsg(False,updateInfo)
|
||||
if not hasattr(get,'toUpdate'):
|
||||
if updateInfo['is_beta'] == 1:
|
||||
if updateInfo['beta']['version'] == session['version']: return public.returnMsg(False,updateInfo)
|
||||
else:
|
||||
if updateInfo['version'] == session['version']: return public.returnMsg(False,updateInfo)
|
||||
|
||||
|
||||
#是否执行升级程序
|
||||
@@ -560,9 +558,9 @@ class ajax:
|
||||
httpUrl = public.get_url()
|
||||
if httpUrl: updateInfo['downUrl'] = httpUrl + '/install/' + uptype + '/LinuxPanel_EN-' + updateInfo['version'] + '.zip'
|
||||
public.downloadFile(updateInfo['downUrl'],'panel.zip')
|
||||
if os.path.getsize('panel.zip') < 1048576: return public.returnMsg(False,"PANEL_UPDATE_ERR_DOWN")
|
||||
if os.path.getsize('panel.zip') < 1048576: return public.return_msg_gettext(False,'File download failed, please try again or update manually!')
|
||||
public.ExecShell('unzip -o panel.zip -d ' + setupPath + '/')
|
||||
import compileall
|
||||
# import compileall
|
||||
if os.path.exists('/www/server/panel/runserver.py'): public.ExecShell('rm -f /www/server/panel/*.pyc')
|
||||
if os.path.exists('/www/server/panel/class/common.py'): public.ExecShell('rm -f /www/server/panel/class/*.pyc')
|
||||
|
||||
@@ -572,7 +570,7 @@ class ajax:
|
||||
if updateInfo['is_beta'] == 1: self.to_beta()
|
||||
public.ExecShell("/etc/init.d/bt start")
|
||||
public.writeFile('data/restart.pl','True')
|
||||
return public.returnMsg(True,'PANEL_UPDATE',(updateInfo['version'],))
|
||||
return public.return_msg_gettext(True,'Successful to update to {}',(updateInfo['version'],))
|
||||
|
||||
#输出新版本信息
|
||||
data = {
|
||||
@@ -580,13 +578,20 @@ class ajax:
|
||||
'version': updateInfo['version'],
|
||||
'updateMsg' : updateInfo['updateMsg']
|
||||
}
|
||||
|
||||
# 输出忽略的版本
|
||||
updateInfo['ignore'] = []
|
||||
no_path = '{}/data/no_update.pl'.format(public.get_panel_path())
|
||||
if os.path.exists(no_path):
|
||||
try:
|
||||
updateInfo['ignore'] = json.loads(public.readFile(no_path))
|
||||
except:
|
||||
pass
|
||||
public.ExecShell('rm -rf /www/server/phpinfo/*')
|
||||
return public.returnMsg(True,updateInfo)
|
||||
except Exception as ex:
|
||||
return public.get_error_info()
|
||||
return public.returnMsg(False,"CONNECT_ERR")
|
||||
|
||||
return public.return_msg_gettext(False,'Failed to connect server!')
|
||||
|
||||
#检查是否安装任何
|
||||
def CheckInstalled(self,get):
|
||||
checks = ['nginx','apache','php','pure-ftpd','mysql']
|
||||
@@ -611,7 +616,7 @@ class ajax:
|
||||
filename = '/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'):
|
||||
filename = '/usr/local/lsws/lsphp' + get.version + '/etc/php.ini'
|
||||
if not os.path.exists(filename): return public.returnMsg(False,'PHP_NOT_EXISTS')
|
||||
if not os.path.exists(filename): return public.return_msg_gettext(False,'Requested PHP version does NOT exist!')
|
||||
phpini = public.readFile(filename)
|
||||
data = {}
|
||||
rep = "disable_functions\s*=\s{0,1}(.*)\n"
|
||||
@@ -698,7 +703,7 @@ class ajax:
|
||||
|
||||
# 下载云端php扩展配置
|
||||
def _get_cloud_phplib(self):
|
||||
if not session.get('download_url'): session['download_url'] = 'http://node.aapanel.com'
|
||||
if not session.get('download_url'): session['download_url'] = 'https://node.aapanel.com'
|
||||
download_url = session['download_url'] + '/install/lib/phplib_en.json'
|
||||
tstr = public.httpGet(download_url)
|
||||
data = json.loads(tstr)
|
||||
@@ -723,13 +728,13 @@ 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.return_msg_gettext(False,'Permission denied!')
|
||||
if 'tmp_login_id' in session:
|
||||
return public.returnMsg(False,'PERMISSION_DENIED')
|
||||
return public.return_msg_gettext(False,'Permission denied!')
|
||||
|
||||
public.M('logs').where('id>?',(0,)).delete()
|
||||
public.WriteLog('TYPE_CONFIG','LOG_CLOSE')
|
||||
return public.returnMsg(True,'LOG_CLOSE')
|
||||
public.write_log_gettext('Panel setting','Panel Logs emptied!')
|
||||
return public.return_msg_gettext(True,'Panel Logs emptied!')
|
||||
|
||||
def __get_webserver_conffile(self):
|
||||
webserver = public.get_webserver()
|
||||
@@ -778,54 +783,54 @@ class ajax:
|
||||
# 修改php ssl端口
|
||||
def change_phpmyadmin_ssl_port(self,get):
|
||||
if public.get_webserver() == "openlitespeed":
|
||||
return public.returnMsg(False, 'NOT_SUPPORT_OLS')
|
||||
return public.return_msg_gettext(False, 'The current web server is openlitespeed. This function is not supported yet.')
|
||||
import re
|
||||
try:
|
||||
port = int(get.port)
|
||||
if 1 > port > 65535:
|
||||
return public.returnMsg(False, 'PORT_CHECK_RANGE')
|
||||
return public.return_msg_gettext(False, 'Port range is incorrect!')
|
||||
except:
|
||||
return public.returnMsg(False, 'PORT_FORMAT_ERR')
|
||||
return public.return_msg_gettext(False, 'Please enter the correct port number')
|
||||
for i in ["nginx","apache"]:
|
||||
file = "/www/server/panel/vhost/{}/phpmyadmin.conf".format(i)
|
||||
conf = public.readFile(file)
|
||||
if not conf:
|
||||
return public.returnMsg(False,"PHPMYADMIN_SSL_ERR",(i,))
|
||||
return public.return_msg_gettext(False,'Did not find the {} configuration file, please try to close the ssl port settings before opening',(i,))
|
||||
rulePort = ['80', '443', '21', '20', '8080', '8081', '8089', '11211', '6379']
|
||||
if get.port in rulePort:
|
||||
return public.returnMsg(False, 'AJAX_PHPMYADMIN_PORT_ERR')
|
||||
return public.return_msg_gettext(False, 'Please do NOT use the usual port as the phpMyAdmin port!')
|
||||
if i == "nginx":
|
||||
if not os.path.exists("/www/server/panel/vhost/apache/phpmyadmin.conf"):
|
||||
return public.returnMsg(False, "PHPMYADMIN_SSL_ERR1")
|
||||
return public.return_msg_gettext(False, 'Did not find the apache phpmyadmin ssl configuration file, please try to close the ssl port settings before opening')
|
||||
rep = "listen\s*([0-9]+)\s*.*;"
|
||||
oldPort = re.search(rep, conf)
|
||||
if not oldPort:
|
||||
return public.returnMsg(False, 'PHPMYADMIN_SSL_ERR2')
|
||||
return public.return_msg_gettext(False, 'Did not detect the port that nginx phpmyadmin listens, please confirm whether the file has been manually modified.')
|
||||
oldPort = oldPort.groups()[0]
|
||||
conf = re.sub(rep, 'listen ' + get.port + ' ssl;', conf)
|
||||
else:
|
||||
rep = "Listen\s*([0-9]+)\s*\n"
|
||||
oldPort = re.search(rep, conf)
|
||||
if not oldPort:
|
||||
return public.returnMsg(False, 'PHPMYADMIN_SSL_ERR3')
|
||||
return public.return_msg_gettext(False, 'Did not detect the port that apache phpmyadmin listens, please confirm whether the file has been manually modified.')
|
||||
oldPort = oldPort.groups()[0]
|
||||
conf = re.sub(rep, "Listen " + get.port + "\n", conf, 1)
|
||||
rep = "VirtualHost\s*\*:[0-9]+"
|
||||
conf = re.sub(rep, "VirtualHost *:" + get.port, conf, 1)
|
||||
if oldPort == get.port: return public.returnMsg(False, 'SOFT_PHPVERSION_ERR_PORT')
|
||||
if oldPort == get.port: return public.return_msg_gettext(False, 'Port [{}] is in use!',(get.port,))
|
||||
public.writeFile(file, conf)
|
||||
public.serviceReload()
|
||||
if i=="apache":
|
||||
import firewalls
|
||||
get.ps = public.getMsg('SOFT_PHPVERSION_PS')
|
||||
get.ps = public.getMsg('New phpMyAdmin Port')
|
||||
fw = firewalls.firewalls()
|
||||
fw.AddAcceptPort(get)
|
||||
public.serviceReload()
|
||||
public.WriteLog('TYPE_SOFT', 'SOFT_PHPMYADMIN_PORT', (get.port,))
|
||||
public.write_log_gettext('Software manager', 'Modified access port to {} for phpMyAdmin!', (get.port,))
|
||||
get.id = public.M('firewall').where('port=?', (oldPort,)).getField('id')
|
||||
get.port = oldPort
|
||||
fw.DelAcceptPort(get)
|
||||
return public.returnMsg(True, 'SET_PORT_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
|
||||
def _get_phpmyadmin_auth(self):
|
||||
import re
|
||||
@@ -846,9 +851,9 @@ class ajax:
|
||||
# 设置phpmyadmin ssl
|
||||
def set_phpmyadmin_ssl(self,get):
|
||||
if public.get_webserver() == "openlitespeed":
|
||||
return public.returnMsg(False, 'NOT_SUPPORT_OLS')
|
||||
return public.return_msg_gettext(False, 'The current web server is openlitespeed. This function is not supported yet.')
|
||||
if not os.path.exists("/www/server/panel/ssl/certificate.pem"):
|
||||
return public.returnMsg(False,'PHPMYADMIN_SSL_ERR4')
|
||||
return public.return_msg_gettext(False,'The panel certificate does not exist. Please apply for the panel certificate and try again.')
|
||||
if get.v == "1":
|
||||
# 获取auth信息
|
||||
auth = ""
|
||||
@@ -952,9 +957,9 @@ class ajax:
|
||||
if os.path.exists("/www/server/panel/vhost/apache/phpmyadmin.conf"):
|
||||
os.remove("/www/server/panel/vhost/apache/phpmyadmin.conf")
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True, 'SET_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True,'PHPMYADMIN_SSL_ERR5')
|
||||
return public.return_msg_gettext(True,'Open successfully, please manually release phpmyadmin ssl port')
|
||||
|
||||
|
||||
#设置PHPMyAdmin
|
||||
@@ -965,13 +970,13 @@ class ajax:
|
||||
if public.get_webserver() == 'openlitespeed':
|
||||
filename = "/www/server/panel/vhost/openlitespeed/detail/phpmyadmin.conf"
|
||||
conf = public.readFile(filename)
|
||||
if not conf: return public.returnMsg(False,'ERROR')
|
||||
if not conf: return public.return_msg_gettext(False,'Operation failed')
|
||||
if hasattr(get,'port'):
|
||||
mainPort = public.readFile('data/port.pl').strip()
|
||||
rulePort = ['80','443','21','20','8080','8081','8089','11211','6379']
|
||||
oldPort = "888"
|
||||
if get.port in rulePort:
|
||||
return public.returnMsg(False,'AJAX_PHPMYADMIN_PORT_ERR')
|
||||
return public.return_msg_gettext(False,'Please do NOT use the usual port as the phpMyAdmin port!')
|
||||
if public.get_webserver() == 'nginx':
|
||||
rep = r"listen\s+([0-9]+)\s*;"
|
||||
oldPort = re.search(rep,conf).groups()[0]
|
||||
@@ -990,19 +995,19 @@ class ajax:
|
||||
if tmp:
|
||||
oldPort = tmp.groups(1)
|
||||
conf = re.sub(reg,"address *:{}".format(get.port),conf)
|
||||
if oldPort == get.port: return public.returnMsg(False,'SOFT_PHPVERSION_ERR_PORT')
|
||||
if oldPort == get.port: return public.returnMsg(False,'Port [{}] is in use!',(get.port,))
|
||||
|
||||
public.writeFile(filename,conf)
|
||||
import firewalls
|
||||
get.ps = public.getMsg('SOFT_PHPVERSION_PS')
|
||||
get.ps = public.getMsg('New phpMyAdmin Port')
|
||||
fw = firewalls.firewalls()
|
||||
fw.AddAcceptPort(get)
|
||||
public.serviceReload()
|
||||
public.WriteLog('TYPE_SOFT','SOFT_PHPMYADMIN_PORT',(get.port,))
|
||||
public.write_log_gettext('Software manager','Modified access port to {} for phpMyAdmin!',(get.port,))
|
||||
get.id = public.M('firewall').where('port=?',(oldPort,)).getField('id')
|
||||
get.port = oldPort
|
||||
fw.DelAcceptPort(get)
|
||||
return public.returnMsg(True,'SET_PORT_SUCCESS')
|
||||
return public.returnMsg(True,'Setup successfully!')
|
||||
|
||||
if hasattr(get,'phpversion'):
|
||||
if public.get_webserver() == 'nginx':
|
||||
@@ -1018,8 +1023,8 @@ class ajax:
|
||||
conf = re.sub(reg,'/usr/local/lsws/lsphp{}/bin/lsphp'.format(get.phpversion),conf)
|
||||
public.writeFile(filename,conf)
|
||||
public.serviceReload()
|
||||
public.WriteLog('TYPE_SOFT','SOFT_PHPMYADMIN_PHP',(get.phpversion,))
|
||||
return public.returnMsg(True,'SOFT_PHPVERSION_SET')
|
||||
public.write_log_gettext('Software manager','Modified PHP runtime version to PHP-{} for phpMyAdmin!',(get.phpversion,))
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
if hasattr(get,'password'):
|
||||
import panelSite
|
||||
@@ -1029,17 +1034,49 @@ class ajax:
|
||||
return panelSite.panelSite().SetHasPwd(get)
|
||||
|
||||
if hasattr(get,'status'):
|
||||
if conf.find(public.GetConfigValue('setup_path') + '/stop') != -1:
|
||||
conf = conf.replace(public.GetConfigValue('setup_path') + '/stop',public.GetConfigValue('setup_path') + '/phpmyadmin')
|
||||
pma_path = public.GetConfigValue('setup_path') + '/phpmyadmin'
|
||||
stop_path = public.GetConfigValue('setup_path') + '/stop'
|
||||
|
||||
|
||||
webserver = public.get_webserver()
|
||||
if conf.find(stop_path) != -1:
|
||||
conf = conf.replace(stop_path,pma_path)
|
||||
msg = public.getMsg('START')
|
||||
|
||||
if webserver == 'nginx':
|
||||
sub_string = '''{};
|
||||
allow 127.0.0.1;
|
||||
allow ::1;
|
||||
deny all'''.format(pma_path)
|
||||
if conf.find(sub_string) != -1:
|
||||
conf = conf.replace(sub_string,pma_path)
|
||||
msg = public.getMsg('START')
|
||||
else:
|
||||
conf = conf.replace(pma_path,sub_string)
|
||||
msg = public.getMsg('STOP')
|
||||
elif webserver == 'apache':
|
||||
src_string = 'AllowOverride All'
|
||||
sub_string = '''{}
|
||||
Deny from all
|
||||
Allow from 127.0.0.1 ::1 localhost'''.format(src_string,pma_path)
|
||||
if conf.find(sub_string) != -1:
|
||||
conf = conf.replace(sub_string,src_string)
|
||||
msg = public.getMsg('START')
|
||||
else:
|
||||
conf = conf.replace(src_string,sub_string)
|
||||
msg = public.getMsg('STOP')
|
||||
else:
|
||||
conf = conf.replace(public.GetConfigValue('setup_path') + '/phpmyadmin',public.GetConfigValue('setup_path') + '/stop')
|
||||
msg = public.getMsg('STOP')
|
||||
if conf.find(stop_path) != -1:
|
||||
conf = conf.replace(stop_path,pma_path)
|
||||
msg = public.getMsg('START')
|
||||
else:
|
||||
conf = conf.replace(pma_path,stop_path)
|
||||
msg = public.getMsg('STOP')
|
||||
|
||||
public.writeFile(filename,conf)
|
||||
public.serviceReload()
|
||||
public.WriteLog('TYPE_SOFT','SOFT_PHPMYADMIN_STATUS',(msg,))
|
||||
return public.returnMsg(True,'SOFT_PHPMYADMIN_STATUS',(msg,))
|
||||
public.write_log_gettext('Software manager','phpMyAdmin already {}!',(msg,))
|
||||
return public.return_msg_gettext(True,'phpMyAdmin already {}!',(msg,))
|
||||
#except:
|
||||
#return public.returnMsg(False,'ERROR');
|
||||
|
||||
@@ -1060,8 +1097,8 @@ class ajax:
|
||||
|
||||
#保存PHP排序
|
||||
def phpSort(self,get):
|
||||
if public.writeFile('/www/server/php/sort.pl',get.ssort): return public.returnMsg(True,'SUCCESS')
|
||||
return public.returnMsg(False,'ERROR')
|
||||
if public.writeFile('/www/server/php/sort.pl',get.ssort): return public.return_msg_gettext(True,'Setup successfully!')
|
||||
return public.return_msg_gettext(False,'Operation failed')
|
||||
|
||||
#获取广告代码
|
||||
def GetAd(self,get):
|
||||
@@ -1081,7 +1118,7 @@ class ajax:
|
||||
#获取警告标识
|
||||
def GetWarning(self,get):
|
||||
warningFile = 'data/warning.json'
|
||||
if not os.path.exists(warningFile): return public.returnMsg(False,'AJAX_WARNING_ERR')
|
||||
if not os.path.exists(warningFile): return public.return_msg_gettext(False,'Warning list does NOT exist!')
|
||||
import json,time;
|
||||
wlist = json.loads(public.readFile(warningFile))
|
||||
wlist['time'] = int(time.time())
|
||||
@@ -1099,7 +1136,7 @@ class ajax:
|
||||
|
||||
warningFile = 'data/warning.json'
|
||||
public.writeFile(warningFile,json.dumps(wlist))
|
||||
return public.returnMsg(True,'SET_SUCCESS')
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
#获取memcached状态
|
||||
def GetMemcachedStatus(self,get):
|
||||
@@ -1139,7 +1176,7 @@ class ajax:
|
||||
conf = re.sub('CACHESIZE=\d+','CACHESIZE='+get.cachesize,conf)
|
||||
public.writeFile(confFile,conf)
|
||||
public.ExecShell(confFile + ' reload')
|
||||
return public.returnMsg(True,'SET_SUCCESS')
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
#取redis状态
|
||||
def GetRedisStatus(self,get):
|
||||
@@ -1180,10 +1217,10 @@ class ajax:
|
||||
def GetFpmLogs(self,get):
|
||||
import re
|
||||
fpm_path = '/www/server/php/' + get.version + '/etc/php-fpm.conf'
|
||||
if not os.path.exists(fpm_path): return public.returnMsg(False,'AJAX_LOG_FILR_NOT_EXISTS')
|
||||
if not os.path.exists(fpm_path): return public.return_msg_gettext(False,'Log file does NOT exist!')
|
||||
fpm_conf = public.readFile(fpm_path)
|
||||
log_tmp = re.findall(r"error_log\s*=\s*(.+)",fpm_conf)
|
||||
if not log_tmp: return public.returnMsg(False,'AJAX_LOG_FILR_NOT_EXISTS')
|
||||
if not log_tmp: return public.return_msg_gettext(False,'Log file does NOT exist!')
|
||||
log_file = log_tmp[0].strip()
|
||||
if log_file.find('var/log') == 0:
|
||||
log_file = '/www/server/php/' +get.version + '/'+ log_file
|
||||
@@ -1193,10 +1230,10 @@ class ajax:
|
||||
def GetFpmSlowLogs(self,get):
|
||||
import re
|
||||
fpm_path = '/www/server/php/' + get.version + '/etc/php-fpm.conf'
|
||||
if not os.path.exists(fpm_path): return public.returnMsg(False,'AJAX_LOG_FILR_NOT_EXISTS')
|
||||
if not os.path.exists(fpm_path): return public.return_msg_gettext(False,'Log file does NOT exist!')
|
||||
fpm_conf = public.readFile(fpm_path)
|
||||
log_tmp = re.findall(r"slowlog\s*=\s*(.+)",fpm_conf)
|
||||
if not log_tmp: return public.returnMsg(False,'AJAX_LOG_FILR_NOT_EXISTS')
|
||||
if not log_tmp: return public.return_msg_gettext(False,'Log file does NOT exist!')
|
||||
log_file = log_tmp[0].strip()
|
||||
if log_file.find('var/log') == 0:
|
||||
log_file = '/www/server/php/' +get.version + '/'+ log_file
|
||||
@@ -1204,12 +1241,120 @@ class ajax:
|
||||
|
||||
#取指定日志
|
||||
def GetOpeLogs(self,get):
|
||||
if not os.path.exists(get.path): return public.returnMsg(False,'AJAX_LOG_FILR_NOT_EXISTS')
|
||||
if not os.path.exists(get.path): return public.return_msg_gettext(False,'Log file does NOT exist!')
|
||||
return public.returnMsg(True,public.GetNumLines(get.path,1000))
|
||||
|
||||
|
||||
def get_pd(self,get):
|
||||
from BTPanel import cache
|
||||
tmp = -1
|
||||
try:
|
||||
import panelPlugin
|
||||
# get = public.dict_obj()
|
||||
# get.init = 1
|
||||
tmp1 = panelPlugin.panelPlugin().get_cloud_list(get)
|
||||
except:
|
||||
tmp1 = None
|
||||
if tmp1:
|
||||
tmp = tmp1[public.to_string([112, 114, 111])]
|
||||
ltd = tmp1.get('ltd', -1)
|
||||
else:
|
||||
ltd = -1
|
||||
tmp4 = cache.get(public.to_string([112, 95, 116, 111, 107, 101, 110]))
|
||||
if tmp4:
|
||||
tmp_f = public.to_string([47, 116, 109, 112, 47]) + tmp4
|
||||
if not os.path.exists(tmp_f): public.writeFile(tmp_f, '-1')
|
||||
tmp = public.readFile(tmp_f)
|
||||
if tmp: tmp = int(tmp)
|
||||
if not ltd: ltd = -1
|
||||
if tmp == None: tmp = -1
|
||||
if ltd < 1:
|
||||
if ltd == -2:
|
||||
tmp3 = public.to_string(
|
||||
[60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116, 108, 116, 100,
|
||||
45, 103, 114, 97, 121, 34, 62, 60, 115, 112, 97, 110, 32, 115, 116, 121, 108, 101,
|
||||
61, 34, 99, 111, 108, 111, 114, 58, 32, 35, 102, 99, 54, 100, 50, 54, 59, 102, 111,
|
||||
110, 116, 45, 119, 101, 105, 103, 104, 116, 58, 32, 98, 111, 108, 100, 59, 109, 97,
|
||||
114, 103, 105, 110, 45, 114, 105, 103, 104, 116, 58, 53, 112, 120, 34, 62, 24050, 36807,
|
||||
26399, 60, 47, 115, 112, 97, 110, 62, 60, 97, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116,
|
||||
108, 105, 110, 107, 34, 32, 111, 110, 99, 108, 105, 99, 107, 61, 34, 98, 116, 46, 115, 111,
|
||||
102, 116, 46, 117, 112, 100, 97, 116, 97, 95, 108, 116, 100, 40, 41, 34, 62, 82, 69, 78, 69, 87,
|
||||
60, 47, 97,
|
||||
62, 60, 47, 115, 112, 97, 110, 62])
|
||||
elif tmp == -1:
|
||||
tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98,
|
||||
116, 112, 114, 111, 45, 102, 114, 101, 101, 34, 32, 111, 110, 99, 108, 105, 99,
|
||||
107,
|
||||
61, 34, 98, 116, 46, 115, 111, 102, 116, 46, 114, 101, 110, 101, 119, 95, 112,
|
||||
114,
|
||||
111, 40, 41, 34, 32, 116, 105, 116, 108, 101, 61, 34, 67, 108, 105, 99, 107,
|
||||
32, 116, 111, 32,
|
||||
103, 101, 116, 32, 80, 82, 79, 34, 62, 20813, 36153, 29256, 60, 47, 115, 112,
|
||||
97, 110, 62])
|
||||
elif tmp == -2:
|
||||
tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116,
|
||||
112, 114, 111, 45, 103, 114, 97, 121, 34, 62, 60, 115, 112, 97, 110, 32,
|
||||
115, 116, 121, 108, 101, 61, 34, 99, 111, 108, 111, 114, 58, 32, 35,
|
||||
102, 99, 54, 100, 50, 54, 59, 102, 111, 110, 116, 45, 119, 101, 105, 103,
|
||||
104, 116, 58, 32, 98, 111, 108, 100, 59, 109, 97, 114, 103, 105, 110, 45,
|
||||
114, 105, 103, 104, 116, 58, 53, 112, 120, 34, 62, 24050, 36807, 26399,
|
||||
60, 47, 115, 112, 97, 110, 62, 60, 97, 32, 99, 108, 97, 115, 115, 61, 34,
|
||||
98, 116, 108, 105, 110, 107, 34, 32, 111, 110, 99, 108, 105, 99, 107, 61,
|
||||
34, 98, 116, 46, 115, 111, 102, 116, 46, 114, 101, 110, 101, 119, 95, 112, 114,
|
||||
111, 40, 41, 34, 62, 82, 69, 78, 69, 87, 60, 47, 97, 62, 60, 47, 115, 112, 97,
|
||||
110, 62])
|
||||
if tmp >= 0 and ltd in [-1, -2]:
|
||||
if tmp == 0:
|
||||
tmp2 = public.to_string([27704, 20037, 25480, 26435])
|
||||
tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116,
|
||||
112, 114, 111, 34, 62, 123, 48, 125, 60, 115, 112, 97, 110, 32, 115, 116,
|
||||
121, 108, 101, 61, 34, 99, 111, 108, 111, 114, 58, 32, 35, 102, 99, 54,
|
||||
100,
|
||||
50, 54, 59, 102, 111, 110, 116, 45, 119, 101, 105, 103, 104, 116,
|
||||
58, 32, 98, 111, 108, 100, 59, 34, 62, 123, 49, 125, 60, 47, 115,
|
||||
112, 97, 110, 62, 60, 47, 115, 112, 97, 110, 62]).format(
|
||||
public.to_string([21040, 26399, 26102, 38388, 65306]), tmp2)
|
||||
else:
|
||||
tmp2 = time.strftime(public.to_string([37, 89, 45, 37, 109, 45, 37, 100]), time.localtime(tmp))
|
||||
tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116,
|
||||
112, 114, 111, 34, 62, 69, 120, 112, 105, 114, 101, 58, 32, 60, 115, 112,
|
||||
97, 110, 32, 115, 116, 121, 108, 101, 61, 34, 99, 111, 108, 111, 114,
|
||||
58, 32, 35, 102, 99, 54, 100, 50, 54, 59, 102, 111, 110, 116, 45, 119,
|
||||
101, 105, 103, 104, 116, 58, 32, 98, 111, 108, 100, 59, 109, 97, 114,
|
||||
103, 105, 110, 45, 114, 105, 103, 104, 116, 58, 53, 112, 120, 34, 62, 123,
|
||||
48, 125, 60, 47, 115, 112, 97, 110, 62, 60, 97, 32, 99, 108, 97, 115,
|
||||
115, 61, 34, 98, 116, 108, 105, 110, 107, 34, 32, 111, 110, 99, 108, 105,
|
||||
99,
|
||||
107, 61, 34, 98, 116, 46, 115, 111, 102, 116, 46, 114, 101, 110, 101, 119,
|
||||
95,
|
||||
112, 114, 111, 40, 41, 34, 62, 82, 69, 78, 69, 87, 60, 47, 97, 62, 60,
|
||||
47, 115, 112, 97, 110, 62]).format(tmp2)
|
||||
else:
|
||||
tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116, 112,
|
||||
114, 111, 45, 103, 114, 97, 121, 34, 32, 111, 110, 99, 108, 105, 99, 107,
|
||||
61, 34, 98, 116, 46, 115, 111, 102, 116, 46, 117, 112, 100, 97, 116, 97, 95, 112,
|
||||
114, 111, 40, 41, 34, 32, 116, 105, 116, 108, 101, 61, 34, 67, 108, 105, 99,
|
||||
107, 32, 116,
|
||||
111, 32, 103, 101, 116, 32, 80, 82, 79, 34, 62, 70, 82,
|
||||
69, 69, 60, 47, 115, 112, 97, 110, 62])
|
||||
else:
|
||||
tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116, 108, 116,
|
||||
100, 34, 62, 69, 120, 112, 105, 114, 101, 58, 32, 60, 115, 112, 97, 110, 32, 115,
|
||||
116,
|
||||
121, 108, 101, 61, 34, 99, 111, 108, 111, 114, 58, 32, 35, 102, 99, 54, 100, 50,
|
||||
54, 59, 102, 111, 110, 116, 45, 119, 101, 105, 103, 104, 116, 58, 32, 98, 111,
|
||||
108, 100, 59, 109, 97, 114, 103, 105, 110, 45, 114, 105, 103, 104, 116, 58, 53,
|
||||
112, 120, 34, 62, 123, 125, 60, 47, 115, 112, 97, 110, 62, 60, 97, 32, 99, 108,
|
||||
97, 115, 115, 61, 34, 98, 116, 108, 105, 110, 107, 34, 32, 111, 110, 99, 108, 105,
|
||||
99, 107, 61, 34, 98, 116, 46, 115, 111, 102, 116, 46, 114, 101, 110, 101, 119, 95,
|
||||
112, 114, 111, 40, 41, 34, 62, 82, 69, 78, 69, 87, 60, 47, 97, 62, 60, 47, 115,
|
||||
112, 97, 110, 62]).format(
|
||||
time.strftime(public.to_string([37, 89, 45, 37, 109, 45, 37, 100]), time.localtime(ltd)))
|
||||
|
||||
return tmp3, tmp, ltd
|
||||
|
||||
#检查用户绑定是否正确
|
||||
def check_user_auth(self,get):
|
||||
import requests
|
||||
# import requests
|
||||
m_key = 'check_user_auth'
|
||||
if m_key in session: return session[m_key]
|
||||
u_path = 'data/userInfo.json'
|
||||
@@ -1217,15 +1362,16 @@ class ajax:
|
||||
userInfo = json.loads(public.ReadFile(u_path))
|
||||
except:
|
||||
if os.path.exists(u_path): os.remove(u_path)
|
||||
return public.returnMsg(False,'AJAX_USER_BE_OVERDUE')
|
||||
return public.return_msg_gettext(False,'Account binding has expired, please re-bind on the [Settings] page!')
|
||||
url_headers = {"authorization":"bt {}".format(userInfo['token'])}
|
||||
resp = requests.post('{}/api/user/verifyToken'.format(self.__official_url),headers=url_headers,verify=False)
|
||||
# resp = requests.post('{}/api/user/verifyToken'.format(self.__official_url),headers=url_headers,verify=False)
|
||||
resp = public.HttpPost.post('{}/api/user/verifyToken'.format(self.__official_url), headers=url_headers, verify=False)
|
||||
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')
|
||||
return public.return_msg_gettext(False,'Account binding has expired, please re-bind on the [Settings] page!')
|
||||
else:
|
||||
session[m_key] = public.returnMsg(True,'AJAX_USER_IS_VALID')
|
||||
session[m_key] = public.return_msg_gettext(True,'Binding is valid!')
|
||||
return session[m_key]
|
||||
|
||||
|
||||
@@ -1239,7 +1385,7 @@ class ajax:
|
||||
php_ini = php_path + php_version + '/etc/php.ini'
|
||||
if not os.path.exists('/etc/redhat-release') and public.get_webserver() == 'openlitespeed':
|
||||
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]
|
||||
tmp = public.ExecShell(php_bin + ' -c {} /www/server/panel/class/php_info.php'.format(php_ini))[0]
|
||||
if tmp.find('Warning: JIT is incompatible') != -1:
|
||||
tmp = tmp.strip().split('\n')[-1]
|
||||
result = json.loads(tmp)
|
||||
@@ -1258,8 +1404,113 @@ class ajax:
|
||||
|
||||
#取指定行
|
||||
def get_lines(self,args):
|
||||
if not os.path.exists(args.filename): return public.returnMsg(False,'LOG_EMPTY')
|
||||
if not os.path.exists(args.filename): return public.returnMsg(False,'Logs emptied')
|
||||
s_body = public.ExecShell("tail -n {} {}".format(args.num,args.filename))[0]
|
||||
return public.returnMsg(True,s_body)
|
||||
|
||||
|
||||
def log_analysis(self,get):
|
||||
import log_analysis
|
||||
log_analysis=log_analysis.log_analysis()
|
||||
return log_analysis.log_analysis(get)
|
||||
|
||||
|
||||
def speed_log(self,get):
|
||||
import log_analysis
|
||||
log_analysis=log_analysis.log_analysis()
|
||||
return log_analysis.speed_log(get)
|
||||
|
||||
|
||||
|
||||
def get_result(self,get):
|
||||
import log_analysis
|
||||
log_analysis=log_analysis.log_analysis()
|
||||
return log_analysis.get_result(get)
|
||||
|
||||
def get_detailed(self,get):
|
||||
import log_analysis
|
||||
log_analysis=log_analysis.log_analysis()
|
||||
return log_analysis.get_detailed(get)
|
||||
|
||||
def download_pay_type(self, path):
|
||||
public.downloadFile(public.get_url() + '/install/lib/pay_type_en.json', path)
|
||||
return True
|
||||
|
||||
def get_pay_type(self, get):
|
||||
"""
|
||||
@name 获取推荐列表
|
||||
"""
|
||||
spath = '{}/data/pay_type.json'.format(public.get_panel_path())
|
||||
down = cache.get('pay_type')
|
||||
if not down:
|
||||
public.run_thread(self.download_pay_type, (spath,))
|
||||
cache.set('pay_type', 1, 86400)
|
||||
try:
|
||||
data = json.loads(public.readFile("data/pay_type.json"))
|
||||
except:
|
||||
public.run_thread(self.download_pay_type, (spath,))
|
||||
data = {}
|
||||
|
||||
import panelPlugin
|
||||
plu_panel = panelPlugin.panelPlugin()
|
||||
plugin_list = plu_panel.get_cloud_list()
|
||||
if not 'pro' in plugin_list: plugin_list['pro'] = -1
|
||||
|
||||
for item in data:
|
||||
if 'list' in item:
|
||||
item['list'] = self.__get_home_list(item['list'], item['type'], plugin_list, plu_panel)
|
||||
if item['type'] == 1:
|
||||
if len(item['list']) > 4: item['list'] = item['list'][:4]
|
||||
# if item['type'] == 0 and plugin_list['pro'] >= 0:
|
||||
# item['show'] = False
|
||||
return data
|
||||
|
||||
def __get_home_list(self, sList, stype, plugin_list, plu_panel):
|
||||
"""
|
||||
@name 获取首页软件列表推荐
|
||||
"""
|
||||
nList = []
|
||||
webserver = public.get_webserver()
|
||||
for x in sList:
|
||||
for plugin_info in plugin_list['list']:
|
||||
if x['name'] == plugin_info['name']:
|
||||
if not 'endtime' in plugin_info or plugin_info['endtime'] >= 0:
|
||||
x['isBuy'] = True
|
||||
is_check = False
|
||||
if 'dependent' in x:
|
||||
if x['dependent'] == webserver: is_check = True
|
||||
else:
|
||||
is_check = True
|
||||
if is_check:
|
||||
info = plu_panel.get_soft_find(x['name'])
|
||||
if info:
|
||||
if stype == 1:
|
||||
# if plugin_list['pro'] >= 0: continue
|
||||
if not info['setup']:
|
||||
x['install'] = info['setup']
|
||||
nList.append(x)
|
||||
else:
|
||||
x['install'] = info['setup']
|
||||
nList.append(x)
|
||||
return nList
|
||||
|
||||
def ignore_version(self, get):
|
||||
"""
|
||||
@忽略版本更新
|
||||
:param version 忽略的版本号
|
||||
"""
|
||||
version = get.version
|
||||
path = '{}/data/no_update.pl'.format(public.get_panel_path())
|
||||
try:
|
||||
data = json.loads(public.readFile(path))
|
||||
except:
|
||||
data = []
|
||||
|
||||
if not version in data: data.append(version)
|
||||
|
||||
public.writeFile(path, json.dumps(data))
|
||||
try:
|
||||
del (session['updateInfo'])
|
||||
except:
|
||||
pass
|
||||
|
||||
return public.return_msg_gettext(True, "Ignore success, this version will no longer be reminded to update.")
|
||||
@@ -43,7 +43,7 @@ class apache:
|
||||
try:
|
||||
workermen = int(public.ExecShell("ps aux|grep httpd|grep 'start'|awk '{memsum+=$6};END {print memsum}'")[0]) / 1024
|
||||
except:
|
||||
return public.returnMsg(False,"Get worker RAM False")
|
||||
return public.return_msg_gettext(False,"Get worker RAM False")
|
||||
for proc in psutil.process_iter():
|
||||
if proc.name() == "httpd":
|
||||
self.GetProcessCpuPercent(proc.pid,process_cpu)
|
||||
@@ -54,7 +54,7 @@ class apache:
|
||||
# 计算启动时间
|
||||
Uptime = re.search("ServerUptimeSeconds:\s+(.*)",result)
|
||||
if not Uptime:
|
||||
return public.returnMsg(False, "Get worker Uptime False")
|
||||
return public.return_msg_gettext(False, "Get worker Uptime False")
|
||||
Uptime = int(Uptime.group(1))
|
||||
min = Uptime / 60
|
||||
hours = min / 60
|
||||
@@ -65,16 +65,16 @@ class apache:
|
||||
#格式化重启时间
|
||||
restarttime = re.search("RestartTime:\s+(.*)",result)
|
||||
if not restarttime:
|
||||
return public.returnMsg(False, "Get worker Restart Time False")
|
||||
return public.return_msg_gettext(False, "Get worker Restart Time False")
|
||||
restarttime = restarttime.group(1)
|
||||
rep = "\w+,\s([\w-]+)\s([\d\:]+)\s\w+"
|
||||
date = re.search(rep,restarttime)
|
||||
if not date:
|
||||
return public.returnMsg(False, "Get worker date False")
|
||||
return public.return_msg_gettext(False, "Get worker date False")
|
||||
date = date.group(1)
|
||||
timedetail = re.search(rep,restarttime)
|
||||
if not timedetail:
|
||||
return public.returnMsg(False, "Get worker time detail False")
|
||||
return public.return_msg_gettext(False, "Get worker time detail False")
|
||||
timedetail=timedetail.group(2)
|
||||
monthen = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]
|
||||
n = 0
|
||||
@@ -87,7 +87,7 @@ class apache:
|
||||
|
||||
reqpersec = re.search("ReqPerSec:\s+(.*)", result)
|
||||
if not reqpersec:
|
||||
return public.returnMsg(False, "Get worker reqpersec False")
|
||||
return public.return_msg_gettext(False, "Get worker reqpersec False")
|
||||
reqpersec = reqpersec.group(1)
|
||||
if re.match("^\.", reqpersec):
|
||||
reqpersec = "%s%s" % (0,reqpersec)
|
||||
@@ -95,20 +95,20 @@ class apache:
|
||||
data["UpTime"] = "%s day %s hour %s minute" % (str(int(days)),str(int(hours)),str(int(min)))
|
||||
total_acc = re.search("Total Accesses:\s+(\d+)",result)
|
||||
if not total_acc:
|
||||
return public.returnMsg(False, "Get worker TotalAccesses False")
|
||||
return public.return_msg_gettext(False, "Get worker TotalAccesses False")
|
||||
data["TotalAccesses"] = total_acc.group(1)
|
||||
total_kb = re.search("Total kBytes:\s+(\d+)",result)
|
||||
if not total_kb:
|
||||
return public.returnMsg(False, "Get worker TotalKBytes False")
|
||||
return public.return_msg_gettext(False, "Get worker TotalKBytes False")
|
||||
data["TotalKBytes"] = total_kb.group(1)
|
||||
data["ReqPerSec"] = round(float(reqpersec), 2)
|
||||
busywork = re.search("BusyWorkers:\s+(\d+)",result)
|
||||
if not busywork:
|
||||
return public.returnMsg(False, "Get worker BusyWorkers False")
|
||||
return public.return_msg_gettext(False, "Get worker BusyWorkers False")
|
||||
data["BusyWorkers"] = busywork.group(1)
|
||||
idlework = re.search("IdleWorkers:\s+(\d+)",result)
|
||||
if not idlework:
|
||||
return public.returnMsg(False, "Get worker IdleWorkers False")
|
||||
return public.return_msg_gettext(False, "Get worker IdleWorkers False")
|
||||
data["IdleWorkers"] = idlework.group(1)
|
||||
data["workercpu"] = round(float(process_cpu["httpd"]),2)
|
||||
data["workermem"] = "%s%s" % (int(workermen),"MB")
|
||||
@@ -120,10 +120,10 @@ class apache:
|
||||
if not "mpm_event_module" in apachempmcontent:
|
||||
return public.returnMsg(False,"mpm_event_module conf not found or /www/server/apache/conf/extra/httpd-mpm.conf is empty")
|
||||
apachempmcontent = re.search("\<IfModule mpm_event_module\>(\n|.)+?\</IfModule\>",apachempmcontent).group()
|
||||
ps = ["%s,%s" % (public.GetMsg("SECOND"),public.GetMsg("REQUEST_TIMEOUT_TIME")),
|
||||
public.GetMsg("KEEP_ALIVE"),
|
||||
"%s,%s" % (public.GetMsg("SECOND"),public.GetMsg("CONNECT_TIMEOUT_TIME")),
|
||||
public.GetMsg("MAX_KEEP_ALIVE_REQUESTS")]
|
||||
ps = ["%s,%s" % (public.get_msg_gettext('Second'),public.get_msg_gettext('Request timeout')),
|
||||
public.get_msg_gettext('Keep alive'),
|
||||
"%s,%s" % (public.get_msg_gettext('Second'),public.get_msg_gettext('Connection timeout')),
|
||||
public.get_msg_gettext('Max keep-alive requests per connection')]
|
||||
gets = ["Timeout","KeepAlive","KeepAliveTimeout","MaxKeepAliveRequests"]
|
||||
if public.get_webserver() == 'apache':
|
||||
shutil.copyfile(self.apachedefaultfile, '/tmp/apdefault_file_bk.conf')
|
||||
@@ -134,34 +134,34 @@ class apache:
|
||||
rep = "(%s)\s+(\w+)" % i
|
||||
k = re.search(rep, apachedefaultcontent)
|
||||
if not k:
|
||||
return public.returnMsg(False, "Get Key {} False".format(k))
|
||||
return public.return_msg_gettext(False, "Get Key {} False",(i,))
|
||||
k = k.group(1)
|
||||
v = re.search(rep, apachedefaultcontent)
|
||||
if not v:
|
||||
return public.returnMsg(False, "Get Value {} False".format(v))
|
||||
return public.return_msg_gettext(False, "Get Value {} False",(v,))
|
||||
v = v.group(2)
|
||||
psstr = ps[n]
|
||||
kv = {"name":k,"value":v,"ps":psstr}
|
||||
conflist.append(kv)
|
||||
n += 1
|
||||
|
||||
ps = [public.GetMsg("DEFUALT_PROCESSES"),
|
||||
public.GetMsg("MAX_SPARE_THREADS"),
|
||||
public.GetMsg("MIN_SPARE_THREADS"),
|
||||
public.GetMsg("THREADS_PER_CHILD"),
|
||||
public.GetMsg("MAX_REQUEST_WORKERS"),
|
||||
public.GetMsg("MaxConnectionsPerChild")]
|
||||
ps = [public.get_msg_gettext('Default processes'),
|
||||
public.get_msg_gettext('Maximum number of idle threads'),
|
||||
public.get_msg_gettext('Minimum number of idle threads available to handle request spikes'),
|
||||
public.get_msg_gettext('Number of threads created by each child process'),
|
||||
public.get_msg_gettext('Maximum number of connections that will be processed simultaneously'),
|
||||
public.get_msg_gettext('Limit on the number of connections that an individual child server will handle during its life')]
|
||||
gets = ["StartServers","MaxSpareThreads","MinSpareThreads","ThreadsPerChild","MaxRequestWorkers","MaxConnectionsPerChild"]
|
||||
n = 0
|
||||
for i in gets:
|
||||
rep = "(%s)\s+(\w+)" % i
|
||||
k = re.search(rep, apachempmcontent)
|
||||
if not k:
|
||||
return public.returnMsg(False, "Get Key {} False".format(k))
|
||||
return public.return_msg_gettext(False, "Get Key {} False",(i,))
|
||||
k = k.group(1)
|
||||
v = re.search(rep, apachempmcontent)
|
||||
if not v:
|
||||
return public.returnMsg(False, "Get Value {} False".format(v))
|
||||
return public.return_msg_gettext(False, "Get Value {} False",(v,))
|
||||
v = v.group(2)
|
||||
psstr = ps[n]
|
||||
kv = {"name": k, "value": v, "ps": psstr}
|
||||
@@ -173,7 +173,7 @@ class apache:
|
||||
apachedefaultcontent = public.readFile(self.apachedefaultfile)
|
||||
apachempmcontent = public.readFile(self.apachempmfile)
|
||||
if not "mpm_event_module" in apachempmcontent:
|
||||
return public.returnMsg(False,"mpm_event_module conf not found or /www/server/apache/conf/extra/httpd-mpm.conf is empty")
|
||||
return public.return_msg_gettext(False,"mpm_event_module conf not found or /www/server/apache/conf/extra/httpd-mpm.conf is empty")
|
||||
conflist = []
|
||||
getdict = get.__dict__
|
||||
for i in getdict.keys():
|
||||
@@ -186,12 +186,12 @@ class apache:
|
||||
for c in conflist:
|
||||
if c["name"] == "KeepAlive":
|
||||
if not re.search("on|off", c["value"]):
|
||||
return public.returnMsg(False, "INIT_ARGS_ERR")
|
||||
return public.return_msg_gettext(False, 'Parameter ERROR!')
|
||||
else:
|
||||
print(c["value"])
|
||||
if not re.search("\d+", c["value"]):
|
||||
print(c["name"],c["value"])
|
||||
return public.returnMsg(False, 'INIT_ARGS_ERR')
|
||||
return public.return_msg_gettext(False, 'Parameter ERROR!')
|
||||
|
||||
rep = "%s\s+\w+" % c["name"]
|
||||
if re.search(rep,apachedefaultcontent):
|
||||
@@ -206,10 +206,10 @@ class apache:
|
||||
if (isError != True):
|
||||
shutil.copyfile('/tmp/_file_bk.conf', self.apachedefaultfile)
|
||||
shutil.copyfile('/tmp/proxyfile_bk.conf', self.apachempmfile)
|
||||
return public.returnMsg(False, 'ERROR: %s<br><a style="color:red;">' % public.GetMsg("CONFIG_ERROR") + isError.replace("\n",
|
||||
return public.returnMsg(False, 'ERROR: %s<br><a style="color:red;">' % public.get_msg_gettext('Configuration ERROR') + isError.replace("\n",
|
||||
'<br>') + '</a>')
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True, 'SET_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
|
||||
def add_httpd_access_log_format(self,args):
|
||||
'''
|
||||
@@ -232,12 +232,12 @@ class apache:
|
||||
self.del_httpd_access_log_format(args)
|
||||
conf = public.readFile(self.httpdconf)
|
||||
if not conf:
|
||||
return public.returnMsg(False,'CONF_FILE_NOT_EXISTS')
|
||||
return public.return_msg_gettext(False,'Configuration file not exist')
|
||||
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')
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
except:
|
||||
return public.returnMsg(False, str(public.get_error_info()))
|
||||
|
||||
@@ -249,13 +249,13 @@ class apache:
|
||||
'''
|
||||
conf = public.readFile(self.httpdconf)
|
||||
if not conf:
|
||||
return public.returnMsg(False, 'CONF_FILE_NOT_EXISTS')
|
||||
return public.return_msg_gettext(False, 'Configuration file not exist')
|
||||
reg = '\s*#LOG_FORMAT_BEGIN_{n}(\n|.)+#LOG_FORMAT_END_{n}\n?'.format(n=args.log_format_name)
|
||||
conf = re.sub(reg,'',conf)
|
||||
self._del_format_log_of_website(args.log_format_name)
|
||||
public.writeFile(self.httpdconf,conf)
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True, 'SET_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
|
||||
def del_all_log_format(self,args):
|
||||
all_format = self.get_httpd_access_log_format(args)
|
||||
@@ -318,7 +318,7 @@ class apache:
|
||||
reg = "#LOG_FORMAT_BEGIN.*"
|
||||
conf = public.readFile(self.httpdconf)
|
||||
if not conf:
|
||||
return public.returnMsg(False, 'CONF_FILE_NOT_EXISTS')
|
||||
return public.return_msg_gettext(False, 'Configuration file not exist')
|
||||
data = re.findall(reg,conf)
|
||||
format_name = [i.split('LOG_FORMAT_BEGIN_')[-1] for i in data]
|
||||
format_log = {}
|
||||
@@ -349,7 +349,7 @@ class apache:
|
||||
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')
|
||||
return public.return_msg_gettext(False, 'Configuration file not exist')
|
||||
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):
|
||||
@@ -360,7 +360,7 @@ class apache:
|
||||
conf = re.sub(format_exist_reg,access_log,conf)
|
||||
public.writeFile(website_conf_file,conf)
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True, 'SET_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
except:
|
||||
return public.returnMsg(False, str(public.get_error_info()))
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ class SimpleCache(BaseCache):
|
||||
toremove.append(key)
|
||||
for key in toremove:
|
||||
self._cache.pop(key, None)
|
||||
self.del_session_by_file(key)
|
||||
|
||||
|
||||
def _normalize_timeout(self, timeout):
|
||||
@@ -48,70 +49,87 @@ class SimpleCache(BaseCache):
|
||||
timeout = time() + timeout
|
||||
return timeout
|
||||
|
||||
def get(self, key):
|
||||
try:
|
||||
|
||||
expires, value = self._cache[key]
|
||||
if expires == 0 or expires > time():
|
||||
return pickle.loads(value)
|
||||
|
||||
except (KeyError, pickle.PickleError):
|
||||
try:
|
||||
if key[:4] == self.__session_key:
|
||||
filename = '/'.join((self.__session_basedir,self.md5(key)))
|
||||
if not os.path.exists(filename): return None
|
||||
|
||||
with open(filename, 'rb') as fp:
|
||||
_val = fp.read()
|
||||
fp.close()
|
||||
|
||||
expires = struct.unpack('f',_val[:4])[0]
|
||||
if expires == 0 or expires > time():
|
||||
value = _val[4:]
|
||||
|
||||
self._cache[key] = (expires,value)
|
||||
return pickle.loads(value)
|
||||
except :pass
|
||||
return None
|
||||
|
||||
def set(self, key, value, timeout=None):
|
||||
|
||||
expires = self._normalize_timeout(timeout)
|
||||
self._prune()
|
||||
|
||||
_val = pickle.dumps(value, pickle.HIGHEST_PROTOCOL)
|
||||
self._cache[key] = (expires,_val)
|
||||
def get_session_by_file(self,key):
|
||||
try:
|
||||
if key[:4] == self.__session_key:
|
||||
filename = '/'.join((self.__session_basedir,self.md5(key)))
|
||||
if not os.path.exists(filename): return None
|
||||
|
||||
with open(filename, 'rb') as fp:
|
||||
_val = fp.read()
|
||||
fp.close()
|
||||
expires = struct.unpack('f',_val[:4])[0]
|
||||
if expires == 0 or expires > time():
|
||||
value = _val[4:]
|
||||
|
||||
self._cache[key] = (expires,value)
|
||||
return pickle.loads(value)
|
||||
except :pass
|
||||
|
||||
def set_session_by_file(self,key,_val,expires):
|
||||
try:
|
||||
if key[:4] == self.__session_key:
|
||||
if len(_val) < 256: return True
|
||||
if not os.path.exists(self.__session_basedir): os.makedirs(self.__session_basedir,384)
|
||||
|
||||
expires = struct.pack('f',expires)
|
||||
filename = '/'.join((self.__session_basedir,self.md5(key)))
|
||||
filename = '/'.join((self.__session_basedir,self.md5(key)))
|
||||
fp = open(filename, 'wb+')
|
||||
fp.write(expires + _val)
|
||||
fp.close()
|
||||
os.chmod(filename,384)
|
||||
except :pass
|
||||
|
||||
def del_session_by_file(self,key):
|
||||
try:
|
||||
if key[:4] == self.__session_key:
|
||||
filename = '/'.join((self.__session_basedir,self.md5(key)))
|
||||
if os.path.exists(filename): os.remove(filename)
|
||||
except : pass
|
||||
|
||||
def get(self, key):
|
||||
if not isinstance(key,str): return None
|
||||
try:
|
||||
expires, value = self._cache[key]
|
||||
if expires == 0 or expires > time():
|
||||
return pickle.loads(value)
|
||||
except (KeyError, pickle.PickleError):
|
||||
return self.get_session_by_file(key)
|
||||
|
||||
def set(self, key, value, timeout=None):
|
||||
|
||||
# 类型判断
|
||||
if not isinstance(key,str): return False
|
||||
type_list=(int,float,bool,str,list,dict,tuple,set,bytes)
|
||||
if not isinstance(value,type_list): return False
|
||||
|
||||
# 过期清理
|
||||
expires = self._normalize_timeout(timeout)
|
||||
self._prune()
|
||||
|
||||
# 转换
|
||||
_val = pickle.dumps(value, pickle.HIGHEST_PROTOCOL)
|
||||
self._cache[key] = (expires,_val)
|
||||
self.set_session_by_file(key,_val,expires)
|
||||
return True
|
||||
|
||||
def add(self, key, value, timeout=None):
|
||||
|
||||
# 类型判断
|
||||
if not isinstance(key,str): return False
|
||||
type_list=(int,float,bool,str,list,dict,tuple,set,bytes)
|
||||
if not isinstance(value,type_list): return False
|
||||
|
||||
expires = self._normalize_timeout(timeout)
|
||||
self._prune()
|
||||
item = (expires, pickle.dumps(value,
|
||||
pickle.HIGHEST_PROTOCOL))
|
||||
item = (expires, pickle.dumps(value,pickle.HIGHEST_PROTOCOL))
|
||||
if key in self._cache:
|
||||
return False
|
||||
self._cache.setdefault(key, item)
|
||||
self.set_session_by_file(key,item[1],expires)
|
||||
return True
|
||||
|
||||
def delete(self, key):
|
||||
result = self._cache.pop(key, None) is not None
|
||||
try:
|
||||
if key[:4] == self.__session_key:
|
||||
filename = '/'.join((self.__session_basedir,self.md5(key)))
|
||||
if os.path.exists(filename): os.remove(filename)
|
||||
except : pass
|
||||
self.del_session_by_file(key)
|
||||
return result
|
||||
|
||||
def has(self, key):
|
||||
@@ -119,8 +137,17 @@ class SimpleCache(BaseCache):
|
||||
expires, value = self._cache[key]
|
||||
return expires == 0 or expires > time()
|
||||
except KeyError:
|
||||
if self.get_session_by_file(key): return True
|
||||
return False
|
||||
|
||||
|
||||
def get_expire_time(self, key):
|
||||
try:
|
||||
expires, value = self._cache[key]
|
||||
return expires
|
||||
except KeyError:
|
||||
return 0
|
||||
|
||||
def md5(self,strings):
|
||||
"""
|
||||
生成MD5
|
||||
@@ -129,7 +156,7 @@ class SimpleCache(BaseCache):
|
||||
"""
|
||||
import hashlib
|
||||
m = hashlib.md5()
|
||||
|
||||
|
||||
m.update(strings.encode('utf-8'))
|
||||
return m.hexdigest()
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ class panelSetup:
|
||||
ua = g.ua.lower()
|
||||
if ua.find('spider') != -1 or g.ua.find('bot') != -1:
|
||||
return redirect('https://www.google.com')
|
||||
g.version = '6.8.21'
|
||||
g.version = '6.8.27'
|
||||
g.title = public.GetConfigValue('title')
|
||||
g.uri = request.path
|
||||
g.debug = os.path.exists('data/debug.pl')
|
||||
@@ -98,9 +98,9 @@ class panelAdmin(panelSetup):
|
||||
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["download"] = public.GetMsg("DOWNLOAD")
|
||||
session["top_tips"] = public.get_msg_gettext("The current IE browser version is too low to display some features, please use another browser. Or if you use a browser developed by a Chinese company, please switch to Extreme Mode!")
|
||||
session["bt_help"] = public.get_msg_gettext("For Support|Suggestions, please visit the aaPanel Forum")
|
||||
session["download"] = public.get_msg_gettext("Downloading:")
|
||||
if not 'brand' in session:
|
||||
session['brand'] = public.GetConfigValue('brand')
|
||||
session['product'] = public.GetConfigValue('product')
|
||||
@@ -114,7 +114,7 @@ class panelAdmin(panelSetup):
|
||||
if not 'lan' in session:
|
||||
session['lan'] = public.GetLanguage()
|
||||
if not 'home' in session:
|
||||
session['home'] = 'https://brandnew.aapanel.com'
|
||||
session['home'] = 'https://www.aapanel.com'
|
||||
return False
|
||||
|
||||
# 检查Web服务器类型
|
||||
@@ -150,7 +150,7 @@ class panelAdmin(panelSetup):
|
||||
if not 'login' in session:
|
||||
api_check = self.get_sk()
|
||||
if api_check:
|
||||
#session.clear()
|
||||
session.clear()
|
||||
return api_check
|
||||
g.api_request = True
|
||||
else:
|
||||
@@ -203,54 +203,61 @@ class panelAdmin(panelSetup):
|
||||
def get_sk(self):
|
||||
save_path = '/www/server/panel/config/api.json'
|
||||
if not os.path.exists(save_path):
|
||||
return redirect('/login')
|
||||
return public.error_not_login('/login')
|
||||
|
||||
|
||||
try:
|
||||
api_config = json.loads(public.ReadFile(save_path))
|
||||
except:
|
||||
os.remove(save_path)
|
||||
return redirect('/login')
|
||||
return public.error_not_login('/login')
|
||||
|
||||
if not api_config['open']:
|
||||
return redirect('/login')
|
||||
return public.error_not_login('/login')
|
||||
from BTPanel import get_input
|
||||
get = get_input()
|
||||
client_ip = public.GetClientIp()
|
||||
if not 'client_bind_token' in get:
|
||||
if not 'request_token' in get or not 'request_time' in get:
|
||||
return redirect('/login')
|
||||
return public.error_not_login('/login')
|
||||
|
||||
num_key = client_ip + '_api'
|
||||
if not public.get_error_num(num_key,20):
|
||||
return public.returnJson(False,'AUTH_FAILED1')
|
||||
return public.returnJson(False,'20 consecutive verification failures, prohibited for 1 hour')
|
||||
|
||||
|
||||
if not client_ip in api_config['limit_addr']:
|
||||
if not public.is_api_limit_ip(api_config['limit_addr'],client_ip): #client_ip in api_config['limit_addr']:
|
||||
public.set_error_num(num_key)
|
||||
return public.returnJson(False,'%s[' % public.GetMsg("AUTH_FAILED1")+client_ip+']')
|
||||
return public.returnJson(False,'%s[' % public.get_msg_gettext("20 consecutive verification failures, prohibited for 1 hour")+client_ip+']')
|
||||
else:
|
||||
num_key = client_ip + '_app'
|
||||
if not public.get_error_num(num_key,20):
|
||||
return public.returnJson(False,'AUTH_FAILED1')
|
||||
return public.returnJson(False,'20 consecutive verification failures, prohibited for 1 hour')
|
||||
a_file = '/dev/shm/' + get.client_bind_token
|
||||
|
||||
if not public.path_safe_check(get.client_bind_token):
|
||||
public.set_error_num(num_key)
|
||||
return public.returnJson(False, 'illegal request')
|
||||
|
||||
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.returnJson(False,'UNBOUND_DEVICE')
|
||||
return public.returnJson(False,'Unbound device')
|
||||
public.writeFile(a_file,'')
|
||||
|
||||
if not 'key' in api_config:
|
||||
public.set_error_num(num_key)
|
||||
return public.returnJson(False, 'KEY_ERR')
|
||||
return public.returnJson(False, 'Key verification failed')
|
||||
if not 'form_data' in get:
|
||||
public.set_error_num(num_key)
|
||||
return public.returnJson(False, 'FORM_DATA_ERR')
|
||||
return public.returnJson(False, 'No form_data data found')
|
||||
|
||||
g.form_data = json.loads(public.aes_decrypt(get.form_data, api_config['key']))
|
||||
|
||||
get = get_input()
|
||||
if not 'request_token' in get or not 'request_time' in get:
|
||||
return redirect('/login')
|
||||
return public.error_not_login('/login')
|
||||
g.is_aes = True
|
||||
g.aes_key = api_config['key']
|
||||
request_token = public.md5(get.request_time + api_config['token'])
|
||||
@@ -258,7 +265,7 @@ class panelAdmin(panelSetup):
|
||||
public.set_error_num(num_key,True)
|
||||
return False
|
||||
public.set_error_num(num_key)
|
||||
return public.returnJson(False,'SECRET_KEY_CHECK_FALSE')
|
||||
return public.returnJson(False,'Secret key verification failed')
|
||||
|
||||
# 检查系统配置
|
||||
|
||||
|
||||
@@ -33,27 +33,27 @@ class crontab:
|
||||
tmp = {}
|
||||
tmp=cront[i]
|
||||
if cront[i]['type']=="day":
|
||||
tmp['type']=public.getMsg('CRONTAB_TODAY')
|
||||
tmp['cycle']= public.getMsg('CRONTAB_TODAY_CYCLE',(str(cront[i]['where_hour']),str(cront[i]['where_minute'])))
|
||||
tmp['type']=public.get_msg_gettext('Per Day')
|
||||
tmp['cycle']= public.get_msg_gettext('Per Day, run at {} Hour {} Min',(str(cront[i]['where_hour']),str(cront[i]['where_minute'])))
|
||||
elif cront[i]['type']=="day-n":
|
||||
tmp['type']=public.getMsg('CRONTAB_N_TODAY',(str(cront[i]['where1']),))
|
||||
tmp['cycle']=public.getMsg('CRONTAB_N_TODAY_CYCLE',(str(cront[i]['where1']),str(cront[i]['where_hour']),str(cront[i]['where_minute'])))
|
||||
tmp['type']=public.get_msg_gettext('Every {} Days',(str(cront[i]['where1']),))
|
||||
tmp['cycle']=public.get_msg_gettext('Every {} Days, run at {} Hour {} Min',(str(cront[i]['where1']),str(cront[i]['where_hour']),str(cront[i]['where_minute'])))
|
||||
elif cront[i]['type']=="hour":
|
||||
tmp['type']=public.getMsg('CRONTAB_HOUR')
|
||||
tmp['cycle']=public.getMsg('CRONTAB_HOUR_CYCLE',(str(cront[i]['where_minute']),))
|
||||
tmp['type']=public.get_msg_gettext('Per Hour')
|
||||
tmp['cycle']=public.get_msg_gettext('Per Hour, run at {} Min',(str(cront[i]['where_minute']),))
|
||||
elif cront[i]['type']=="hour-n":
|
||||
tmp['type']=public.getMsg('CRONTAB_N_HOUR',(str(cront[i]['where1']),))
|
||||
tmp['cycle']=public.getMsg('CRONTAB_N_HOUR_CYCLE',(str(cront[i]['where1']),str(cront[i]['where_minute'])))
|
||||
tmp['type']=public.get_msg_gettext('Every {} Hours',(str(cront[i]['where1']),))
|
||||
tmp['cycle']=public.get_msg_gettext('Every {} Hours, run at {} Min',(str(cront[i]['where1']),str(cront[i]['where_minute'])))
|
||||
elif cront[i]['type']=="minute-n":
|
||||
tmp['type']=public.getMsg('CRONTAB_N_MINUTE',(str(cront[i]['where1']),))
|
||||
tmp['cycle']=public.getMsg('CRONTAB_N_MINUTE_CYCLE',(str(cront[i]['where1']),))
|
||||
tmp['type']=public.get_msg_gettext('Every {} Minutes',(str(cront[i]['where1']),))
|
||||
tmp['cycle']=public.get_msg_gettext('Run Every {} Minutes',(str(cront[i]['where1']),))
|
||||
elif cront[i]['type']=="week":
|
||||
tmp['type']=public.getMsg('CRONTAB_WEEK')
|
||||
tmp['type']=public.get_msg_gettext('Weekly')
|
||||
if not cront[i]['where1']: cront[i]['where1'] = '0'
|
||||
tmp['cycle']= public.getMsg('CRONTAB_WEEK_CYCLE',(self.toWeek(int(cront[i]['where1'])),str(cront[i]['where_hour']),str(cront[i]['where_minute'])))
|
||||
tmp['cycle']= public.get_msg_gettext('Every {}, run at {} Hour {} Min',(self.toWeek(int(cront[i]['where1'])),str(cront[i]['where_hour']),str(cront[i]['where_minute'])))
|
||||
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'])))
|
||||
tmp['type']=public.get_msg_gettext('Monthly')
|
||||
tmp['cycle']=public.get_msg_gettext('Monthly, run on {}Day {} Hour {}Min',(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):
|
||||
@@ -80,13 +80,13 @@ class crontab:
|
||||
#转换大写星期
|
||||
def toWeek(self,num):
|
||||
wheres={
|
||||
0 : public.getMsg('CRONTAB_SUNDAY'),
|
||||
1 : public.getMsg('CRONTAB_MONDAY'),
|
||||
2 : public.getMsg('CRONTAB_TUESDAY'),
|
||||
3 : public.getMsg('CRONTAB_WEDNESDAY'),
|
||||
4 : public.getMsg('CRONTAB_THURSDAY'),
|
||||
5 : public.getMsg('CRONTAB_FRIDAY'),
|
||||
6 : public.getMsg('CRONTAB_SATURDAY')
|
||||
0 : public.get_msg_gettext('Sunday'),
|
||||
1 : public.get_msg_gettext('Monday'),
|
||||
2 : public.get_msg_gettext('Tuesday'),
|
||||
3 : public.get_msg_gettext('Wednesday'),
|
||||
4 : public.get_msg_gettext('Thursday'),
|
||||
5 : public.get_msg_gettext('Friday'),
|
||||
6 : public.get_msg_gettext('Saturday')
|
||||
}
|
||||
try:
|
||||
return wheres[num]
|
||||
@@ -132,12 +132,12 @@ class crontab:
|
||||
|
||||
public.M('crontab').where('id=?',(id,)).setField('status',status)
|
||||
public.WriteLog('TYPE_CRON',"MODIFY_CRON_STATUS",(cronInfo['name'],str(status_msg[status])))
|
||||
return public.returnMsg(True,'SET_SUCCESS')
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
#修改计划任务
|
||||
def modify_crond(self,get):
|
||||
if len(get['name'])<1:
|
||||
return public.returnMsg(False,'CRONTAB_TASKNAME_EMPTY')
|
||||
return public.return_msg_gettext(False,'Name of task cannot be empty!')
|
||||
id = get['id']
|
||||
cuonConfig,get,name = self.GetCrondCycle(get)
|
||||
cronInfo = public.M('crontab').where('id=?',(id,)).field(self.field).find()
|
||||
@@ -167,7 +167,7 @@ class crontab:
|
||||
self.remove_for_crond(cronInfo['echo'])
|
||||
self.sync_to_crond(cronInfo)
|
||||
public.WriteLog('TYPE_CRON',"MODIFY_CRON",(cronInfo['name']))
|
||||
return public.returnMsg(True,'EDIT_SUCCESS')
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
|
||||
#获取指定任务数据
|
||||
@@ -196,7 +196,7 @@ class crontab:
|
||||
#添加计划任务
|
||||
def AddCrontab(self,get):
|
||||
if len(get['name'])<1:
|
||||
return public.returnMsg(False,'CRONTAB_TASKNAME_EMPTY')
|
||||
return public.return_msg_gettext(False,'Name of task cannot be empty!')
|
||||
cuonConfig,get,name = self.GetCrondCycle(get)
|
||||
cronPath=public.GetConfigValue('setup_path')+'/cron'
|
||||
cronName=self.GetShell(get)
|
||||
@@ -208,22 +208,22 @@ class crontab:
|
||||
self.CrondReload()
|
||||
columns = 'name,type,where1,where_hour,where_minute,echo,addtime,\
|
||||
status,save,backupTo,sType,sName,sBody,urladdress'
|
||||
values = (public.xssencode(get['name']),get['type'],get['where1'],get['hour'],
|
||||
values = (public.xssencode2(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 "save_local" in get:
|
||||
columns += ",save_local,notice,notice_channel"
|
||||
values = (public.xssencode(get['name']),get['type'],get['where1'],get['hour'],
|
||||
values = (public.xssencode2(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'], get["save_local"], get['notice'], get['notice_channel'])
|
||||
addData=public.M('crontab').add(columns,values)
|
||||
if addData>0:
|
||||
result = public.returnMsg(True,'ADD_SUCCESS')
|
||||
result = public.return_msg_gettext(True,'Setup successfully!')
|
||||
result['id'] = addData
|
||||
return result
|
||||
return public.returnMsg(False,'ADD_ERROR')
|
||||
return public.return_msg_gettext(False,'Failed to add')
|
||||
|
||||
#构造周期
|
||||
def GetCrondCycle(self,params):
|
||||
@@ -231,16 +231,16 @@ class crontab:
|
||||
name = ""
|
||||
if params['type']=="day":
|
||||
cuonConfig = self.GetDay(params)
|
||||
name = public.getMsg('CRONTAB_TODAY')
|
||||
name = public.get_msg_gettext('Per Day')
|
||||
elif params['type']=="day-n":
|
||||
cuonConfig = self.GetDay_N(params)
|
||||
name = public.getMsg('CRONTAB_N_TODAY',(params['where1'],))
|
||||
name = public.get_msg_gettext('Every {0} Days',(params['where1'],))
|
||||
elif params['type']=="hour":
|
||||
cuonConfig = self.GetHour(params)
|
||||
name = public.getMsg('CRONTAB_HOUR')
|
||||
name = public.get_msg_gettext('Per Hour')
|
||||
elif params['type']=="hour-n":
|
||||
cuonConfig = self.GetHour_N(params)
|
||||
name = public.getMsg('CRONTAB_HOUR')
|
||||
name = public.get_msg_gettext('Per Hour')
|
||||
elif params['type']=="minute-n":
|
||||
cuonConfig = self.Minute_N(params)
|
||||
elif params['type']=="week":
|
||||
@@ -252,36 +252,36 @@ class crontab:
|
||||
|
||||
#取任务构造Day
|
||||
def GetDay(self,param):
|
||||
cuonConfig ="{0} {1} * * * ".format(param['minute'],param['hour'])
|
||||
cuonConfig ="{} {} * * * ".format(param['minute'],param['hour'])
|
||||
return cuonConfig
|
||||
#取任务构造Day_n
|
||||
def GetDay_N(self,param):
|
||||
cuonConfig ="{0} {1} */{2} * * ".format(param['minute'],param['hour'],param['where1'])
|
||||
cuonConfig ="{} {} */{} * * ".format(param['minute'],param['hour'],param['where1'])
|
||||
return cuonConfig
|
||||
|
||||
#取任务构造Hour
|
||||
def GetHour(self,param):
|
||||
cuonConfig ="{0} * * * * ".format(param['minute'])
|
||||
cuonConfig ="{} * * * * ".format(param['minute'])
|
||||
return cuonConfig
|
||||
|
||||
#取任务构造Hour-N
|
||||
def GetHour_N(self,param):
|
||||
cuonConfig ="{0} */{1} * * * ".format(param['minute'],param['where1'])
|
||||
cuonConfig ="{} */{} * * * ".format(param['minute'],param['where1'])
|
||||
return cuonConfig
|
||||
|
||||
#取任务构造Minute-N
|
||||
def Minute_N(self,param):
|
||||
cuonConfig ="*/{0} * * * * ".format(param['where1'])
|
||||
cuonConfig ="*/{} * * * * ".format(param['where1'])
|
||||
return cuonConfig
|
||||
|
||||
#取任务构造week
|
||||
def Week(self,param):
|
||||
cuonConfig ="{0} {1} * * {2}".format(param['minute'],param['hour'],param['week'])
|
||||
cuonConfig ="{} {} * * {}".format(param['minute'],param['hour'],param['week'])
|
||||
return cuonConfig
|
||||
|
||||
#取任务构造Month
|
||||
def Month(self,param):
|
||||
cuonConfig = "{0} {1} {2} * * ".format(param['minute'],param['hour'],param['where1'])
|
||||
cuonConfig = "{} {} {} * * ".format(param['minute'],param['hour'],param['where1'])
|
||||
return cuonConfig
|
||||
|
||||
#取数据列表
|
||||
@@ -308,9 +308,9 @@ class crontab:
|
||||
id = get['id']
|
||||
echo = public.M('crontab').where("id=?",(id,)).field('echo').find()
|
||||
logFile = public.GetConfigValue('setup_path')+'/cron/'+echo['echo']+'.log'
|
||||
if not os.path.exists(logFile):return public.returnMsg(False, 'CRONTAB_TASKLOG_EMPTY')
|
||||
if not os.path.exists(logFile):return public.return_msg_gettext(False, 'log is empty')
|
||||
log = public.GetNumLines(logFile,2000)
|
||||
return public.returnMsg(True, log)
|
||||
return public.return_msg_gettext(True, log)
|
||||
|
||||
#清理任务日志
|
||||
def DelLogs(self,get):
|
||||
@@ -319,16 +319,16 @@ class crontab:
|
||||
echo = public.M('crontab').where("id=?",(id,)).getField('echo')
|
||||
logFile = public.GetConfigValue('setup_path')+'/cron/'+echo+'.log'
|
||||
os.remove(logFile)
|
||||
return public.returnMsg(True, 'CRONTAB_TASKLOG_CLOSE')
|
||||
return public.return_msg_gettext(True, 'Logs emptied')
|
||||
except:
|
||||
return public.returnMsg(False, 'CRONTAB_TASKLOG_CLOSE_ERR')
|
||||
return public.return_msg_gettext(False, 'Failed to empty task logs!')
|
||||
|
||||
#删除计划任务
|
||||
def DelCrontab(self,get):
|
||||
try:
|
||||
id = get['id']
|
||||
find = public.M('crontab').where("id=?",(id,)).field('name,echo').find()
|
||||
if not self.remove_for_crond(find['echo']): return public.returnMsg(False,'SYSSAFE_CANT_WRITE_FILE')
|
||||
if not self.remove_for_crond(find['echo']): return public.return_msg_gettext(False,'Unable to write to file, please check if system hardening is enabled!')
|
||||
cronPath = public.GetConfigValue('setup_path') + '/cron'
|
||||
sfile = cronPath + '/' + find['echo']
|
||||
if os.path.exists(sfile): os.remove(sfile)
|
||||
@@ -337,9 +337,9 @@ class crontab:
|
||||
|
||||
public.M('crontab').where("id=?",(id,)).delete()
|
||||
public.WriteLog('TYPE_CRON', 'CRONTAB_DEL',(find['name'],))
|
||||
return public.returnMsg(True, 'DEL_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Successfully deleted')
|
||||
except:
|
||||
return public.returnMsg(False, 'DEL_ERROR')
|
||||
return public.return_msg_gettext(False, 'Failed to delete')
|
||||
|
||||
#从crond删除
|
||||
def remove_for_crond(self,echo):
|
||||
@@ -419,7 +419,7 @@ echo "--------------------------------------------------------------------------
|
||||
public.ExecShell('chmod 750 ' + file)
|
||||
return cronName
|
||||
#except Exception as ex:
|
||||
#return public.returnMsg(False, 'FILE_WRITE_ERR' + str(ex))
|
||||
#return public.return_msg_gettext(False, 'Failed to write in file!' + str(ex))
|
||||
|
||||
#检查脚本
|
||||
def CheckScript(self,shell):
|
||||
@@ -443,7 +443,7 @@ echo "--------------------------------------------------------------------------
|
||||
file = self.get_cron_file()
|
||||
if not os.path.exists(file): public.writeFile(file,'')
|
||||
conf = public.readFile(file)
|
||||
if type(conf)==bool:return public.returnMsg(False,'Failed to read file!')
|
||||
if type(conf)==bool:return public.return_msg_gettext(False,'Failed to read file!')
|
||||
conf += config + "\n"
|
||||
if public.writeFile(file,conf):
|
||||
if not os.path.exists(u_file):
|
||||
@@ -451,7 +451,7 @@ echo "--------------------------------------------------------------------------
|
||||
else:
|
||||
public.ExecShell("chmod 600 '" + file + "' && chown root.crontab " + file)
|
||||
return True
|
||||
return public.returnMsg(False,'SYSSAFE_CANT_WRITE_FILE')
|
||||
return public.return_msg_gettext(False,'Unable to write to file, please check if system hardening is enabled!')
|
||||
|
||||
#立即执行任务
|
||||
def StartTask(self,get):
|
||||
@@ -459,7 +459,7 @@ echo "--------------------------------------------------------------------------
|
||||
execstr = public.GetConfigValue('setup_path') + '/cron/' + echo
|
||||
public.ExecShell('chmod +x ' + execstr)
|
||||
public.ExecShell('nohup ' + execstr + ' >> ' + execstr + '.log 2>&1 &')
|
||||
return public.returnMsg(True,'CRONTAB_TASK_EXEC')
|
||||
return public.return_msg_gettext(True,'Task has been executed!')
|
||||
|
||||
#获取计划任务文件位置
|
||||
def get_cron_file(self):
|
||||
|
||||
@@ -25,10 +25,10 @@ class data:
|
||||
'''
|
||||
def setPs(self,get):
|
||||
id = get.id
|
||||
get.ps = public.xssencode(get.ps)
|
||||
get.ps = public.xssencode2(get.ps)
|
||||
if public.M(get.table).where("id=?",(id,)).setField('ps',get.ps):
|
||||
return public.returnMsg(True,'EDIT_SUCCESS')
|
||||
return public.returnMsg(False,'EDIT_ERROR')
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
return public.return_msg_gettext(False,'Failed to modify')
|
||||
|
||||
#端口扫描
|
||||
def CheckPort(self,port):
|
||||
@@ -142,7 +142,7 @@ class data:
|
||||
conf = public.readFile(
|
||||
self.setupPath + '/panel/vhost/' + self.web_server + '/detail/' + siteName + '.conf')
|
||||
if self.web_server == 'nginx':
|
||||
rep = r"enable-php-(\w{2,5})\.conf"
|
||||
rep = r"enable-php-(\w{2,5})[-\w]*\.conf"
|
||||
elif self.web_server == 'apache':
|
||||
rep = r"php-cgi-(\w{2,5})\.sock"
|
||||
else:
|
||||
@@ -172,6 +172,37 @@ class data:
|
||||
except:
|
||||
return 0
|
||||
|
||||
def get_site_quota(self,path):
|
||||
'''
|
||||
@name 获取网站目录配额信息
|
||||
@author hwliang<2022-02-15>
|
||||
@param path<string> 网站目录
|
||||
@return dict
|
||||
'''
|
||||
res = {'size':0 ,'used':0 }
|
||||
try:
|
||||
from projectModel.quotaModel import main
|
||||
quota_info = main().get_quota_path_list(get_path = path)
|
||||
if isinstance(quota_info,dict):
|
||||
return quota_info
|
||||
return res
|
||||
except: return res
|
||||
|
||||
def get_database_quota(self,db_name):
|
||||
'''
|
||||
@name 获取网站目录配额信息
|
||||
@author hwliang<2022-02-15>
|
||||
@param path<string> 网站目录
|
||||
@return dict
|
||||
'''
|
||||
res = {'size':0 ,'used':0 }
|
||||
try:
|
||||
from projectModel.quotaModel import main
|
||||
quota_info = main().get_quota_mysql_list(get_name = db_name)
|
||||
if isinstance(quota_info,dict):
|
||||
return quota_info
|
||||
return res
|
||||
except: return res
|
||||
|
||||
'''
|
||||
* 取数据列表
|
||||
@@ -181,6 +212,7 @@ class data:
|
||||
* @return Json page.分页数 , count.总行数 data.取回的数据
|
||||
'''
|
||||
def getData(self,get):
|
||||
import one_key_wp
|
||||
try:
|
||||
table = get.table
|
||||
data = self.GetSql(get)
|
||||
@@ -188,29 +220,55 @@ class data:
|
||||
|
||||
if table == 'backup':
|
||||
import os
|
||||
backup_path = public.M('config').where('id=?',(1,)).getField('backup_path')
|
||||
for i in range(len(data['data'])):
|
||||
if data['data'][i]['size'] == 0:
|
||||
if os.path.exists(data['data'][i]['filename']): data['data'][i]['size'] = os.path.getsize(data['data'][i]['filename'])
|
||||
if os.path.exists(data['data'][i]['filename']):
|
||||
data['data'][i]['size'] = os.path.getsize(data['data'][i]['filename'])
|
||||
else:
|
||||
if not os.path.exists(data['data'][i]['filename']):
|
||||
if (data['data'][i]['filename'].find('/www/') != -1 or data['data'][i]['filename'].find(backup_path) != -1) and data['data'][i]['filename'][0] == '/' and data['data'][i]['filename'].find('|') == -1:
|
||||
data['data'][i]['size'] = 0
|
||||
data['data'][i]['ps'] = public.get_msg_gettext("File does not exist!")
|
||||
|
||||
elif table == 'sites' or table == 'databases':
|
||||
type = '0'
|
||||
if table == 'databases': type = '1'
|
||||
for i in range(len(data['data'])):
|
||||
data['data'][i]['backup_count'] = SQL.table('backup').where("pid=? AND type=?",(data['data'][i]['id'],type)).count()
|
||||
if table == 'databases': data['data'][i]['conn_config'] = json.loads(data['data'][i]['conn_config'])
|
||||
data['data'][i]['quota'] = self.get_database_quota(data['data'][i]['name'])
|
||||
if table == 'sites':
|
||||
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'])
|
||||
data['data'][i]['attack'] = self.get_analysis(get,data['data'][i])
|
||||
data['data'][i]['project_type'] = SQL.table('sites').where('id=?',(data['data'][i]['id'])).field('project_type').find()['project_type']
|
||||
if data['data'][i]['project_type'] == 'WP':
|
||||
data['data'][i]['cache_status'] = one_key_wp.one_key_wp().get_cache_status(data['data'][i]['id'])
|
||||
if not data['data'][i]['status'] in ['0','1',0,1]:
|
||||
data['data'][i]['status'] = '1'
|
||||
data['data'][i]['quota'] = self.get_site_quota(data['data'][i]['path'])
|
||||
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:
|
||||
data['data'][i]['status'] = -1
|
||||
else:
|
||||
data['data'][i]['status'] = self.CheckPort(int(data['data'][i]['port']))
|
||||
|
||||
|
||||
elif table == 'ftps':
|
||||
for i in range(len(data['data'])):
|
||||
data['data'][i]['quota'] = self.get_site_quota(data['data'][i]['path'])
|
||||
|
||||
try:
|
||||
for _find in data['data']:
|
||||
_keys = _find.keys()
|
||||
for _key in _keys:
|
||||
_find[_key] = public.xsssec(_find[_key])
|
||||
except:
|
||||
pass
|
||||
|
||||
#返回
|
||||
return data
|
||||
except:
|
||||
@@ -229,15 +287,21 @@ class data:
|
||||
SQL = public.M(tableName)
|
||||
where = "id=?"
|
||||
find = SQL.where(where,(id,)).field(field).find()
|
||||
try:
|
||||
_keys = find.keys()
|
||||
for _key in _keys:
|
||||
find[_key] = public.xsssec(find[_key])
|
||||
except:
|
||||
pass
|
||||
return find
|
||||
|
||||
|
||||
|
||||
|
||||
'''
|
||||
* 取字段值
|
||||
* @param String _GET['tab'] 数据库表名
|
||||
* @param String _GET['key'] 字段
|
||||
* @param String _GET['id'] 条件ID
|
||||
* @return String
|
||||
* @return String
|
||||
'''
|
||||
def getKey(self,get):
|
||||
tableName = get.table
|
||||
@@ -246,7 +310,7 @@ class data:
|
||||
SQL = db.Sql().table(tableName)
|
||||
where = "id=?"
|
||||
retuls = SQL.where(where,(id,)).getField(keyName)
|
||||
return retuls
|
||||
return public.xsssec(retuls)
|
||||
|
||||
'''
|
||||
* 获取数据与分页
|
||||
@@ -259,117 +323,138 @@ class data:
|
||||
def GetSql(self,get,result = '1,2,3,4,5,8'):
|
||||
#判断前端是否传入参数
|
||||
order = "id desc"
|
||||
if hasattr(get,'order'):
|
||||
order = get.order
|
||||
|
||||
if hasattr(get,'order'):
|
||||
# 验证参数格式
|
||||
if re.match(r"^[\w\s\-\.]+$",get.order):
|
||||
order = get.order
|
||||
|
||||
limit = 20
|
||||
if hasattr(get,'limit'):
|
||||
if hasattr(get,'limit'):
|
||||
limit = int(get.limit)
|
||||
|
||||
if hasattr(get,'result'):
|
||||
result = get.result
|
||||
|
||||
if limit < 1: limit = 20
|
||||
|
||||
if hasattr(get,'result'):
|
||||
# 验证参数格式
|
||||
if re.match(r"^[\d\,]+$",get.result):
|
||||
result = get.result
|
||||
|
||||
SQL = db.Sql()
|
||||
data = {}
|
||||
#取查询条件
|
||||
where = ''
|
||||
param = ()
|
||||
if hasattr(get,'search'):
|
||||
if sys.version_info[0] == 2: get.search = get.search.encode('utf-8')
|
||||
where = self.GetWhere(get.table,get.search)
|
||||
where,param = self.GetWhere(get.table,get.search)
|
||||
if get.table == 'backup':
|
||||
where += " and type='" + get.type+"'"
|
||||
|
||||
where += " and type='{}'".format(int(get.type))
|
||||
|
||||
if get.table == 'sites' and get.search:
|
||||
pid = SQL.table('domain').where("name LIKE '%"+get.search+"%'",()).getField('pid')
|
||||
pid = SQL.table('domain').where("name LIKE ?",("%{}%".format(get.search),)).getField('pid')
|
||||
if pid:
|
||||
if where:
|
||||
where += " or id=" + str(pid)
|
||||
else:
|
||||
where += "id=" + str(pid)
|
||||
|
||||
if get.table == 'sites' and hasattr(get,'type'):
|
||||
if get.type != '-1':
|
||||
type_where = "type_id=%s" % get.type
|
||||
if where == '':
|
||||
where = type_where
|
||||
else:
|
||||
where += " and " + type_where
|
||||
if get.table == 'sites':
|
||||
if where:
|
||||
where = "({}) AND project_type='PHP'".format(where)
|
||||
else:
|
||||
where = "project_type='PHP'"
|
||||
where = "(project_type='PHP' OR project_type='WP')"
|
||||
|
||||
if hasattr(get,'type'):
|
||||
if get.type != '-1':
|
||||
where += " AND type_id={}".format(int(get.type))
|
||||
|
||||
if get.table == 'databases':
|
||||
if hasattr(get,'db_type'):
|
||||
if where:
|
||||
where += " AND db_type='{}'".format(int(get.db_type))
|
||||
else:
|
||||
where = "db_type='{}'".format(int(get.db_type))
|
||||
if hasattr(get,'sid'):
|
||||
if where:
|
||||
where += " AND sid='{}'".format(int(get.sid))
|
||||
else:
|
||||
where = "sid='{}'".format(int(get.sid))
|
||||
|
||||
field = self.GetField(get.table)
|
||||
#实例化数据库对象
|
||||
|
||||
|
||||
|
||||
|
||||
#是否直接返回所有列表
|
||||
if hasattr(get,'list'):
|
||||
data = SQL.table(get.table).where(where,()).field(field).order(order).select()
|
||||
data = SQL.table(get.table).where(where,param).field(field).order(order).select()
|
||||
return data
|
||||
|
||||
|
||||
#取总行数
|
||||
count = SQL.table(get.table).where(where,()).count()
|
||||
count = SQL.table(get.table).where(where,param).count()
|
||||
#get.uri = get
|
||||
#包含分页类
|
||||
import page
|
||||
#实例化分页类
|
||||
page = page.Page()
|
||||
|
||||
|
||||
info = {}
|
||||
info['count'] = count
|
||||
info['row'] = limit
|
||||
|
||||
|
||||
info['p'] = 1
|
||||
if hasattr(get,'p'):
|
||||
info['p'] = int(get['p'])
|
||||
info['uri'] = get
|
||||
if info['p'] <1: info['p'] = 1
|
||||
|
||||
try:
|
||||
from flask import request
|
||||
info['uri'] = public.url_encode(request.full_path)
|
||||
except:
|
||||
info['uri'] = ''
|
||||
info['return_js'] = ''
|
||||
if hasattr(get,'tojs'):
|
||||
info['return_js'] = get.tojs
|
||||
|
||||
if re.match(r"^[\w\.\-]+$",get.tojs):
|
||||
info['return_js'] = get.tojs
|
||||
|
||||
data['where'] = where
|
||||
|
||||
|
||||
#获取分页数据
|
||||
data['page'] = page.GetPage(info,result)
|
||||
#取出数据
|
||||
data['data'] = SQL.table(get.table).where(where,()).order(order).field(field).limit(str(page.SHIFT)+','+str(page.ROW)).select()
|
||||
data['data'] = SQL.table(get.table).where(where,param).order(order).field(field).limit(str(page.SHIFT)+','+str(page.ROW)).select()
|
||||
return data
|
||||
|
||||
|
||||
#获取条件
|
||||
def GetWhere(self,tableName,search):
|
||||
if not search: return ""
|
||||
def GetWhere(self,tableName,search):
|
||||
if not search: return "",()
|
||||
|
||||
if type(search) == bytes: search = search.encode('utf-8').strip()
|
||||
try:
|
||||
search = re.search(r"[\w\x80-\xff\.]+",search).group()
|
||||
search = re.search(r"[\w\x80-\xff\.\_\-]+",search).group()
|
||||
except:
|
||||
return ''
|
||||
return '',()
|
||||
wheres = {
|
||||
'sites' : "id='"+search+"' or name like '%"+search+"%' or status like '%"+search+"%' or ps like '%"+search+"%'",
|
||||
'ftps' : "id='"+search+"' or name like '%"+search+"%' or ps like '%"+search+"%'",
|
||||
'databases' : "id='"+search+"' or name like '%"+search+"%' or ps like '%"+search+"%'",
|
||||
'logs' : "uid='"+search+"' or username='"+search+"' or type like '%"+search+"%' or log like '%"+search+"%' or addtime like '%"+search+"%'",
|
||||
'backup' : "pid="+search+"",
|
||||
'users' : "id='"+search+"' or username='"+search+"'",
|
||||
'domain' : "pid='"+search+"' or name='"+search+"'",
|
||||
'tasks' : "status='"+search+"' or type='"+search+"'"
|
||||
'sites' : ("name LIKE ? OR ps LIKE ?",('%'+search+'%','%'+search+'%')),
|
||||
'ftps' : ("name LIKE ? OR ps LIKE ?",('%'+search+'%','%'+search+'%')),
|
||||
'databases' : ("(name LIKE ? OR ps LIKE ?)",("%"+search+"%","%"+search+"%")),
|
||||
'logs' : ("username=? OR type LIKE ? OR log LIKE ?",(search,'%'+search+'%','%'+search+'%')),
|
||||
'backup' : ("pid=?",(search,)),
|
||||
'users' : ("id='?' OR username=?",(search,search)),
|
||||
'domain' : ("pid=? OR name=?",(search,search)),
|
||||
'tasks' : ("status=? OR type=?",(search,search)),
|
||||
}
|
||||
try:
|
||||
return wheres[tableName]
|
||||
except:
|
||||
return ''
|
||||
|
||||
return '',()
|
||||
|
||||
# 获取返回的字段
|
||||
def GetField(self,tableName):
|
||||
fields = {
|
||||
'sites' : "id,name,path,status,ps,addtime,edate",
|
||||
'ftps' : "id,pid,name,password,status,ps,addtime,path",
|
||||
'databases' : "id,pid,name,username,password,accept,ps,addtime",
|
||||
'databases' : "id,sid,pid,name,username,password,accept,ps,addtime,db_type,conn_config",
|
||||
'logs' : "id,uid,username,type,log,addtime",
|
||||
'backup' : "id,pid,name,filename,addtime,size",
|
||||
'backup' : "id,pid,name,filename,addtime,size,ps",
|
||||
'users' : "id,username,phone,email,login_ip,login_time",
|
||||
'firewall' : "id,port,ps,addtime",
|
||||
'domain' : "id,pid,name,port,addtime",
|
||||
@@ -379,3 +464,10 @@ class data:
|
||||
return fields[tableName]
|
||||
except:
|
||||
return ''
|
||||
|
||||
def get_analysis(self,get,i):
|
||||
import log_analysis
|
||||
get.path = '/www/wwwlogs/{}.log'.format(i['name'])
|
||||
get.action = 'get_result'
|
||||
data = log_analysis.log_analysis().get_result(get)
|
||||
return int(data['php']) + int(data['san']) + int(data['sql']) + int(data['xss'])
|
||||
@@ -25,17 +25,17 @@ class datatools:
|
||||
for d in ds:
|
||||
if size < 1024: return ('%.2f' % size) + d
|
||||
size = size / 1024
|
||||
return '0b';
|
||||
return '0b'
|
||||
|
||||
# 获取当前数据库信息
|
||||
def GetdataInfo(self,get):
|
||||
'''
|
||||
传递一个数据库名称即可 get.databases
|
||||
'''
|
||||
if not self.DB_MySQL:self.DB_MySQL = panelMysql.panelMysql()
|
||||
db_name=get.db_name
|
||||
|
||||
db_name=get.db_name
|
||||
if not db_name:return False
|
||||
if not self.DB_MySQL:self.DB_MySQL = public.get_mysql_obj(db_name)
|
||||
ret = {}
|
||||
tables = self.map_to_list(self.DB_MySQL.query('show tables from `%s`' % db_name))
|
||||
if type(tables) == list:
|
||||
@@ -50,7 +50,7 @@ class datatools:
|
||||
|
||||
ret3 = []
|
||||
for i in tables:
|
||||
if i == 1049: return public.returnMsg(False,'DB_NOT_EXIST')
|
||||
if i == 1049: return public.return_msg_gettext(False,'Database does NOT exist!')
|
||||
if type(i) == int: continue
|
||||
table = self.map_to_list(self.DB_MySQL.query("show table status from `%s` where name = '%s'" % (db_name, i[0])))
|
||||
if not table: continue
|
||||
@@ -80,7 +80,9 @@ class datatools:
|
||||
db_name = get.db_name
|
||||
tables = json.loads(get.tables)
|
||||
if not db_name or not tables: return False
|
||||
if not self.DB_MySQL:self.DB_MySQL = panelMysql.panelMysql()
|
||||
if not self.DB_MySQL:self.DB_MySQL = public.get_mysql_obj(db_name)
|
||||
m_version = self.DB_MySQL.query('select version();')[0][0]
|
||||
if m_version.find('5.1.')!=-1:return public.return_msg_gettext(False,"Nonsupport mysql5.1!")
|
||||
mysql_table = self.map_to_list(self.DB_MySQL.query('show tables from `%s`' % db_name))
|
||||
ret=[]
|
||||
if type(mysql_table)==list:
|
||||
@@ -112,10 +114,11 @@ class datatools:
|
||||
db_name=web
|
||||
tables=['web1','web2']
|
||||
'''
|
||||
if not self.DB_MySQL:self.DB_MySQL = panelMysql.panelMysql()
|
||||
|
||||
db_name = get.db_name
|
||||
tables = json.loads(get.tables)
|
||||
if not db_name or not tables: return False
|
||||
if not self.DB_MySQL:self.DB_MySQL = public.get_mysql_obj(db_name)
|
||||
mysql_table = self.map_to_list(self.DB_MySQL.query('show tables from `%s`' % db_name))
|
||||
ret=[]
|
||||
if type(mysql_table) == list:
|
||||
@@ -138,13 +141,12 @@ class datatools:
|
||||
table_type=innodb
|
||||
tables=['web1','web2']
|
||||
'''
|
||||
if not self.DB_MySQL:self.DB_MySQL = panelMysql.panelMysql()
|
||||
db_name = get.db_name
|
||||
table_type = get.table_type
|
||||
tables = json.loads(get.tables)
|
||||
|
||||
if not db_name or not tables: return False
|
||||
|
||||
if not self.DB_MySQL:self.DB_MySQL = public.get_mysql_obj(db_name)
|
||||
mysql_table = self.map_to_list(self.DB_MySQL.query('show tables from `%s`' % db_name))
|
||||
ret=[]
|
||||
if type(mysql_table)==list:
|
||||
|
||||
@@ -304,23 +304,26 @@ class Sql():
|
||||
|
||||
#是否有锁
|
||||
def is_lock(self):
|
||||
n = 0
|
||||
while os.path.exists(self.__LOCK):
|
||||
n+=1
|
||||
if n > 100:
|
||||
self.rm_lock()
|
||||
break
|
||||
time.sleep(0.01)
|
||||
return
|
||||
# n = 0
|
||||
# while os.path.exists(self.__LOCK):
|
||||
# n+=1
|
||||
# if n > 100:
|
||||
# self.rm_lock()
|
||||
# break
|
||||
# time.sleep(0.01)
|
||||
#写锁
|
||||
def write_lock(self):
|
||||
self.is_lock()
|
||||
with open(self.__LOCK,'wb+') as f:
|
||||
f.close()
|
||||
return
|
||||
# self.is_lock()
|
||||
# with open(self.__LOCK,'wb+') as f:
|
||||
# f.close()
|
||||
|
||||
#解锁
|
||||
def rm_lock(self):
|
||||
if os.path.exists(self.__LOCK):
|
||||
os.remove(self.__LOCK)
|
||||
return
|
||||
# if os.path.exists(self.__LOCK):
|
||||
# os.remove(self.__LOCK)
|
||||
|
||||
def query(self,sql,param = ()):
|
||||
#执行SQL语句返回数据集
|
||||
|
||||
@@ -6,73 +6,74 @@
|
||||
# +-------------------------------------------------------------------
|
||||
# | Author: hwliang <hwl@bt.cn>
|
||||
# +-------------------------------------------------------------------
|
||||
import re, os, sys, public, json
|
||||
|
||||
import re,os,sys,public,json
|
||||
import pymysql
|
||||
|
||||
|
||||
class mysql:
|
||||
__DB_PASS = ''
|
||||
__DB_USER = ''
|
||||
__DB_NAME = ''
|
||||
class panelMysql:
|
||||
__DB_PASS = None
|
||||
__DB_USER = 'root'
|
||||
__DB_NAME = None
|
||||
__DB_PORT = 3306
|
||||
__DB_HOST = 'localhost'
|
||||
__DB_PREFIX = ''
|
||||
__DB_CONN = None
|
||||
__DB_CUR = None
|
||||
__DB_ERR = None
|
||||
__DB_NET = None
|
||||
__DB_TABLE = "" # 被操作的表名称
|
||||
__OPT_WHERE = "" # where条件
|
||||
__OPT_LIMIT = "" # limit条件
|
||||
__OPT_ORDER = "" # order条件
|
||||
__OPT_FIELD = "*" # field条件
|
||||
__OPT_PARAM = () # where值
|
||||
__DB_CUR = None
|
||||
__DB_ERR = None
|
||||
__DB_TABLE = "" # 被操作的表名称
|
||||
__OPT_WHERE = "" # where条件
|
||||
__OPT_LIMIT = "" # limit条件
|
||||
__OPT_ORDER = "" # order条件
|
||||
__OPT_FIELD = "*" # field条件
|
||||
__OPT_PARAM = () # where值
|
||||
_USER = None
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def set_name(self, name):
|
||||
self.__DB_NAME = name
|
||||
def set_name(self,name):
|
||||
self.__DB_NAME = str(name)
|
||||
return self
|
||||
|
||||
def set_host(self, host, port, name, username, password, prefix=''):
|
||||
self.__DB_HOST = host
|
||||
self.__DB_PORT = port
|
||||
self.__DB_NAME = name
|
||||
self.__DB_USER = username
|
||||
self.__DB_PASS = password
|
||||
def set_prefix(self,prefix):
|
||||
self.__DB_PREFIX = prefix
|
||||
return self
|
||||
|
||||
def set_host(self,host,port,name,username,password,prefix = ''):
|
||||
self.__DB_HOST = host
|
||||
self.__DB_PORT = int(port)
|
||||
self.__DB_NAME = name
|
||||
if self.__DB_NAME: self.__DB_NAME = str(self.__DB_NAME)
|
||||
self.__DB_USER = str(username)
|
||||
self._USER = str(username)
|
||||
self.__DB_PASS = str(password)
|
||||
self.__DB_PREFIX = prefix
|
||||
self.__GetConn()
|
||||
return self
|
||||
|
||||
#连接MYSQL数据库
|
||||
def __GetConn(self):
|
||||
if self.__DB_NET: return True
|
||||
try:
|
||||
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST,
|
||||
port=self.__DB_PORT,
|
||||
user=self.__DB_USER,
|
||||
passwd=self.__DB_PASS)
|
||||
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST,user=self.__DB_USER,passwd=str(self.__DB_PASS),db=self.__DB_NAME,port=self.__DB_PORT,connect_timeout=15,read_timeout=60,write_timeout=60)
|
||||
except:
|
||||
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST,user=self.__DB_USER,passwd=str(self.__DB_PASS),db=self.__DB_NAME,port=self.__DB_PORT)
|
||||
self.__DB_CUR = self.__DB_CONN.cursor()
|
||||
return True
|
||||
|
||||
self.__DB_CUR = self.__DB_CONN.cursor()
|
||||
self.__DB_NET = True
|
||||
return True
|
||||
except pymysql.Error as e:
|
||||
self.__DB_ERR = e
|
||||
return False
|
||||
|
||||
def table(self, table):
|
||||
def table(self,table):
|
||||
#设置表名
|
||||
self.__DB_TABLE = self.__DB_PREFIX + table
|
||||
return self
|
||||
|
||||
def where(self, where, param):
|
||||
|
||||
def where(self,where,param):
|
||||
#WHERE条件
|
||||
if where:
|
||||
self.__OPT_WHERE = " WHERE " + where
|
||||
self.__OPT_PARAM = self.__to_tuple(param)
|
||||
return self
|
||||
|
||||
def __to_tuple(self, param):
|
||||
def __to_tuple(self,param):
|
||||
#将参数转换为tuple
|
||||
if type(param) != tuple:
|
||||
if type(param) == list:
|
||||
@@ -103,6 +104,7 @@ class mysql:
|
||||
def select(self):
|
||||
#查询数据集
|
||||
self.__GetConn()
|
||||
if not self.__DB_CUR: return self.__DB_ERR
|
||||
try:
|
||||
self.__get_columns()
|
||||
sql = "SELECT " + self.__OPT_FIELD + " FROM " + self.__DB_TABLE + self.__OPT_WHERE + self.__OPT_ORDER + self.__OPT_LIMIT
|
||||
@@ -119,18 +121,18 @@ class mysql:
|
||||
tmp1[key.strip('`')] = row[i]
|
||||
i += 1
|
||||
tmp.append(tmp1)
|
||||
del (tmp1)
|
||||
del(tmp1)
|
||||
data = tmp
|
||||
del (tmp)
|
||||
del(tmp)
|
||||
else:
|
||||
#将元组转换成列表
|
||||
tmp = list(map(list, data))
|
||||
data = tmp
|
||||
del (tmp)
|
||||
del(tmp)
|
||||
self.__close()
|
||||
return data
|
||||
except Exception as ex:
|
||||
return public.get_error_info()
|
||||
return "error: " + str(ex)
|
||||
|
||||
def get(self):
|
||||
self.__get_columns()
|
||||
@@ -291,30 +293,34 @@ class mysql:
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
def execute(self, sql, is_close=True):
|
||||
def execute(self,sql,param = ()):
|
||||
#执行SQL语句返回受影响行
|
||||
if not self.__GetConn(): return self.__DB_ERR
|
||||
try:
|
||||
result = self.__DB_CUR.execute(sql)
|
||||
self.__OPT_PARAM = list(self.__to_tuple(param))
|
||||
result = self.__DB_CUR.execute(sql,self.__OPT_PARAM)
|
||||
self.__DB_CONN.commit()
|
||||
if is_close: self.__close()
|
||||
self.__close()
|
||||
return result
|
||||
except Exception as ex:
|
||||
return ex
|
||||
|
||||
def query(self, sql, is_close=True):
|
||||
|
||||
def query(self,sql,is_close=True,param=()):
|
||||
#执行SQL语句返回数据集
|
||||
if not self.__GetConn(): return self.__DB_ERR
|
||||
try:
|
||||
self.__DB_CUR.execute(sql)
|
||||
self.__OPT_PARAM = list(self.__to_tuple(param))
|
||||
self.__DB_CUR.execute(sql,self.__OPT_PARAM)
|
||||
result = self.__DB_CUR.fetchall()
|
||||
#将元组转换成列表
|
||||
data = list(map(list, result))
|
||||
data = list(map(list,result))
|
||||
if is_close: self.__Close()
|
||||
return data
|
||||
except Exception as ex:
|
||||
return ex
|
||||
|
||||
|
||||
#关闭连接
|
||||
def __Close(self):
|
||||
self.__DB_CUR.close()
|
||||
|
||||
@@ -51,7 +51,7 @@ class FileExecuteDeny:
|
||||
deny_name.append(tmp[-1])
|
||||
result = []
|
||||
for i in deny_name:
|
||||
reg = '#BEGIN_DENY_{}\n\s*location\s*\~\*\s*\^(.*)\.\*.*\((.*)\)\$'.format(i)
|
||||
reg = '#BEGIN_DENY_{}\n\s*location\s*\~\*\s*\^(.*)\.\*.*\((.*)\)\$'.format(i.replace("|","\|"))
|
||||
deny_directory = re.search(reg,conf).groups()[0]
|
||||
deny_suffix = re.search(reg,conf).groups()[1]
|
||||
result.append({'name':i,'dir':deny_directory,'suffix':deny_suffix})
|
||||
@@ -71,7 +71,7 @@ class FileExecuteDeny:
|
||||
deny_name.append(tmp[-1])
|
||||
result = []
|
||||
for i in deny_name:
|
||||
reg = '#BEGIN_DENY_{}\n\s*<Directory\s*\~\s*"(.*)\.\*.*\((.*)\)\$'.format(i)
|
||||
reg = '#BEGIN_DENY_{}\n\s*<Directory\s*\~\s*"(.*)\.\*.*\((.*)\)\$'.format(i.replace("|","\|"))
|
||||
deny_directory = re.search(reg,conf).groups()[0]
|
||||
deny_suffix = re.search(reg,conf).groups()[1]
|
||||
result.append({'name':i,'dir':deny_directory,'suffix':deny_suffix})
|
||||
@@ -91,7 +91,7 @@ class FileExecuteDeny:
|
||||
deny_name.append(tmp[-1])
|
||||
result = []
|
||||
for i in deny_name:
|
||||
reg = '#BEGIN_DENY_{}\n\s*rules\s*RewriteRule\s*\^(.*)\.\*.*\((.*)\)\$'.format(i)
|
||||
reg = '#BEGIN_DENY_{}\n\s*rules\s*RewriteRule\s*\^(.*)\.\*.*\((.*)\)\$'.format(i.replace("|","\|"))
|
||||
deny_directory = re.search(reg, conf).groups()[0]
|
||||
deny_suffix = re.search(reg,conf).groups()[1]
|
||||
result.append({'name':i,'dir':deny_directory,'suffix':deny_suffix})
|
||||
@@ -116,6 +116,8 @@ class FileExecuteDeny:
|
||||
dir = args.dir
|
||||
suffix = args.suffix
|
||||
website = args.website
|
||||
if suffix[-1] == "|":
|
||||
suffix = suffix[:-1]
|
||||
self._init_conf(website)
|
||||
conf = public.readFile(self.ng_website_conf)
|
||||
if not conf:
|
||||
@@ -124,16 +126,16 @@ class FileExecuteDeny:
|
||||
exist_deny_name = [i.split('_')[-1] for i in data]
|
||||
if args.act == 'edit':
|
||||
if deny_name not in exist_deny_name:
|
||||
return public.returnMsg(False, 'The specify rule name is not exists! [ {} ]'.format(deny_name))
|
||||
return public.return_msg_gettext(False, 'The specify rule name is not exists! [ {} ]'.format(deny_name))
|
||||
self.del_file_deny(args)
|
||||
else:
|
||||
if deny_name in exist_deny_name:
|
||||
return public.returnMsg(False,'The specify rule name is already exists! [ {} ]'.format(deny_name))
|
||||
return public.return_msg_gettext(False,'The specify rule name is already exists! [ {} ]'.format(deny_name))
|
||||
self._set_nginx_file_deny(deny_name,dir,suffix)
|
||||
self._set_apache_file_deny(deny_name,dir,suffix)
|
||||
self._set_ols_file_deny(deny_name,dir,suffix)
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True,'Add Successfully')
|
||||
return public.returnMsg(True,'Setup successfully!')
|
||||
|
||||
def _set_nginx_file_deny(self,name,dir=None,suffix=None):
|
||||
conf = public.readFile(self.ng_website_conf)
|
||||
@@ -216,16 +218,16 @@ class FileExecuteDeny:
|
||||
self._set_apache_file_deny(deny_name)
|
||||
self._set_ols_file_deny(deny_name)
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True,'Delete Successfully')
|
||||
return public.returnMsg(True,'Successfully deleted!')
|
||||
|
||||
# 检查传入参数
|
||||
def _check_args(self,args):
|
||||
if hasattr(args,'deny_name'):
|
||||
if len(args.deny_name) < 3:
|
||||
return public.returnMsg(False, 'Rule name needs to be greater than 3 bytes')
|
||||
return public.return_msg_gettext(False, 'Rule name needs to be greater than 3 bytes')
|
||||
if hasattr(args,'suffix'):
|
||||
if not args.suffix:
|
||||
return public.returnMsg(False, 'File suffix cannot be empty')
|
||||
return public.return_msg_gettext(False, 'File suffix cannot be empty')
|
||||
if hasattr(args,'dir'):
|
||||
if not args.dir:
|
||||
return public.returnMsg(False, 'Directory cannot be empty')
|
||||
return public.return_msg_gettext(False, 'Directory cannot be empty')
|
||||
@@ -139,9 +139,9 @@ class firewalls:
|
||||
import time
|
||||
import re
|
||||
rep = "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$"
|
||||
if not re.search(rep,get.port): return public.returnMsg(False,'FIREWALL_IP_FORMAT');
|
||||
if not re.search(rep,get.port): return public.return_msg_gettext(False,'IP address youve entered is illegal!');
|
||||
address = get.port
|
||||
if public.M('firewall').where("port=?",(address,)).count() > 0: return public.returnMsg(False,'FIREWALL_IP_EXISTS')
|
||||
if public.M('firewall').where("port=?",(address,)).count() > 0: return public.return_msg_gettext(False,'The IP exists in block list, no need to repeat processing!')
|
||||
if self.__isUfw:
|
||||
public.ExecShell('ufw deny from ' + address + ' to any');
|
||||
else:
|
||||
@@ -154,11 +154,11 @@ class firewalls:
|
||||
else:
|
||||
public.ExecShell('iptables -I INPUT -s '+address+' -j DROP')
|
||||
|
||||
public.WriteLog("TYPE_FIREWALL", 'FIREWALL_DROP_IP',(address,))
|
||||
public.write_log_gettext("Firewall manager", 'Successfully blocked IP [{}]!',(address,))
|
||||
addtime = time.strftime('%Y-%m-%d %X',time.localtime())
|
||||
public.M('firewall').add('port,ps,addtime',(address,get.ps,addtime))
|
||||
self.FirewallReload()
|
||||
return public.returnMsg(True,'ADD_SUCCESS')
|
||||
return public.return_msg_gettext(True,'Successfully added')
|
||||
|
||||
|
||||
|
||||
@@ -178,11 +178,11 @@ class firewalls:
|
||||
else:
|
||||
public.ExecShell('iptables -D INPUT -s '+address+' -j DROP')
|
||||
|
||||
public.WriteLog("TYPE_FIREWALL",'FIREWALL_ACCEPT_IP',(address,))
|
||||
public.write_log_gettext("Firewall manager",'Unblocked IP [{}]!',(address,))
|
||||
public.M('firewall').where("id=?",(id,)).delete()
|
||||
|
||||
self.FirewallReload();
|
||||
return public.returnMsg(True,'DEL_SUCCESS')
|
||||
return public.return_msg_gettext(True,'Successfully deleted')
|
||||
|
||||
|
||||
#添加放行端口
|
||||
@@ -190,28 +190,28 @@ class firewalls:
|
||||
flag=False
|
||||
import re
|
||||
rep = "^\d{1,5}(:\d{1,5})?$"
|
||||
if not re.search(rep,get.port): return public.returnMsg(False,'PORT_CHECK_RANGE');
|
||||
if not re.search(rep,get.port): return public.return_msg_gettext(False,'Port range is incorrect!');
|
||||
import time
|
||||
port = get.port
|
||||
ps = get.ps
|
||||
types=get.type
|
||||
type_list=['tcp','udp']
|
||||
if types not in type_list:return public.returnMsg(False, 'FIREWALL_PORT_EXISTS')
|
||||
notudps = ['80', '443', '8888', '888', '39000:40000', '21', '22', '7800']
|
||||
if types not in type_list:return public.return_msg_gettext(False, 'The port exists, no need to repeat the release!')
|
||||
notudps = ['80', '443', '8888', '888', '39000:40000', '21', '22']
|
||||
if port in notudps:flag=True
|
||||
#return public.M('firewall').where("port=?", (port,)).count()
|
||||
if types=='tcp':
|
||||
if flag:
|
||||
if public.M('firewall').where("port=?", (port,)).count() > 0: return public.returnMsg(False, 'FIREWALL_PORT_EXISTS')
|
||||
if public.M('firewall').where("port=?", (port,)).count() > 0: return public.return_msg_gettext(False, 'The port exists, no need to repeat the release!')
|
||||
else:
|
||||
if public.M('firewall').where("port=? and type='tcp'",(port,)).count() > 0: return public.returnMsg(False,'FIREWALL_PORT_EXISTS')
|
||||
if public.M('firewall').where("port=? and type='tcp'",(port,)).count() > 0: return public.return_msg_gettext(False,'The port exists, no need to repeat the release!')
|
||||
elif types=='udp':
|
||||
if flag:
|
||||
if public.M('firewall').where("port=?", (port,)).count() > 0: return public.returnMsg( False, 'FIREWALL_PORT_EXISTS')
|
||||
if public.M('firewall').where("port=?", (port,)).count() > 0: return public.return_msg_gettext( False, 'The port exists, no need to repeat the release!')
|
||||
else:
|
||||
if public.M('firewall').where("port=? and type='udp'", (port,)).count() > 0: return public.returnMsg(False,'FIREWALL_PORT_EXISTS')
|
||||
if public.M('firewall').where("port=? and type='udp'", (port,)).count() > 0: return public.return_msg_gettext(False,'The port exists, no need to repeat the release!')
|
||||
else:
|
||||
return public.returnMsg(False, 'FIREWALL_PORT_EXISTS')
|
||||
return public.return_msg_gettext(False, 'The port exists, no need to repeat the release!')
|
||||
|
||||
if self.__isUfw:
|
||||
if port in notudps:
|
||||
@@ -231,12 +231,12 @@ class firewalls:
|
||||
else:
|
||||
public.ExecShell('iptables -I INPUT -p tcp -m state --state NEW -m ' + types +' --dport ' + port + ' -j ACCEPT' )
|
||||
|
||||
public.WriteLog("TYPE_FIREWALL", 'FIREWALL_ACCEPT_PORT',(port,))
|
||||
public.write_log_gettext("Firewall manager", 'Successfully accepted port [{}]!',(port,))
|
||||
addtime = time.strftime('%Y-%m-%d %X',time.localtime())
|
||||
result = public.M('firewall').add('port,ps,addtime,types',(port,ps,addtime,types))
|
||||
#return result
|
||||
self.FirewallReload()
|
||||
return public.returnMsg(True,'ADD_SUCCESS')
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
|
||||
#删除放行端口
|
||||
@@ -245,9 +245,9 @@ class firewalls:
|
||||
id = get.id
|
||||
types=get.type
|
||||
type_list = ['tcp', 'udp']
|
||||
if not types in type_list: return public.returnMsg(False, 'FIREWALL_PORT_EXISTS')
|
||||
if not types in type_list: return public.return_msg_gettext(False, 'The port exists, no need to repeat the release!')
|
||||
try:
|
||||
if(port == public.GetHost(True)): return public.returnMsg(False,'FIREWALL_PORT_PANEL')
|
||||
if(port == public.GetHost(True)): return public.return_msg_gettext(False,'Failed,cannot delete current port of the panel!')
|
||||
if self.__isUfw:
|
||||
public.ExecShell('ufw delete allow ' + port + '/' + types+ '');
|
||||
else:
|
||||
@@ -255,13 +255,13 @@ class firewalls:
|
||||
public.ExecShell('firewall-cmd --permanent --zone=public --remove-port='+port+'/' + types + '')
|
||||
else:
|
||||
public.ExecShell('iptables -D INPUT -p tcp -m state --state NEW -m ' + types +' --dport '+port+' -j ACCEPT')
|
||||
public.WriteLog("TYPE_FIREWALL", 'FIREWALL_DROP_PORT',(port,))
|
||||
public.write_log_gettext("Firewall manager", 'Successfully deleted accepted port [{}] on firewall!',(port,))
|
||||
public.M('firewall').where("id=?",(id,)).delete()
|
||||
|
||||
self.FirewallReload()
|
||||
return public.returnMsg(True,'DEL_SUCCESS')
|
||||
return public.return_msg_gettext(True,'Successfully deleted')
|
||||
except:
|
||||
return public.returnMsg(False,'DEL_ERROR')
|
||||
return public.return_msg_gettext(False,'Failed to delete')
|
||||
|
||||
|
||||
|
||||
@@ -269,10 +269,10 @@ class firewalls:
|
||||
def SetSshStatus(self,get):
|
||||
version = public.readFile('/etc/redhat-release')
|
||||
if int(get['status'])==1:
|
||||
msg = public.getMsg('FIREWALL_SSH_STOP')
|
||||
msg = public.get_msg_gettext('SSH service turned off')
|
||||
act = 'stop'
|
||||
else:
|
||||
msg = public.getMsg('FIREWALL_SSH_START')
|
||||
msg = public.get_msg_gettext('SSH service turned on')
|
||||
act = 'start'
|
||||
|
||||
if not os.path.exists('/etc/redhat-release'):
|
||||
@@ -282,8 +282,8 @@ class firewalls:
|
||||
else:
|
||||
public.ExecShell("/etc/init.d/sshd "+act)
|
||||
|
||||
public.WriteLog("TYPE_FIREWALL", msg)
|
||||
return public.returnMsg(True,'SUCCESS')
|
||||
public.write_log_gettext("Firewall manager", msg)
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
|
||||
|
||||
@@ -305,7 +305,7 @@ class firewalls:
|
||||
|
||||
public.writeFile(filename,conf)
|
||||
public.ExecShell('sysctl -p')
|
||||
return public.returnMsg(True,'SUCCESS')
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
|
||||
|
||||
@@ -313,9 +313,9 @@ class firewalls:
|
||||
def SetSshPort(self,get):
|
||||
#return public.returnMsg(False,'演示服务器,禁止此操作!');
|
||||
port = get.port
|
||||
if int(port) < 22 or int(port) > 65535: return public.returnMsg(False,'FIREWALL_SSH_PORT_ERR');
|
||||
ports = ['21','25','80','443','8080','888','8888', '7800']
|
||||
if port in ports: return public.returnMsg(False,'');
|
||||
if int(port) < 22 or int(port) > 65535: return public.return_msg_gettext(False,'Port range must be between 22 and 65535!');
|
||||
ports = ['21','25','80','443','8080','888','8888'];
|
||||
if port in ports: return public.return_msg_gettext(False,'');
|
||||
|
||||
file = '/etc/ssh/sshd_config'
|
||||
conf = public.readFile(file)
|
||||
@@ -337,9 +337,9 @@ class firewalls:
|
||||
public.ExecShell("/etc/init.d/sshd restart")
|
||||
|
||||
self.FirewallReload()
|
||||
public.M('firewall').where("ps=?",(public.GetMsg("SSH_SERVER"),)).setField('port',port)
|
||||
public.WriteLog("TYPE_FIREWALL", "FIREWALL_SSH_PORT",(port,))
|
||||
return public.returnMsg(True,'EDIT_SUCCESS')
|
||||
public.M('firewall').where("ps=?",(public.get_msg_gettext('SSH Server'),)).setField('port',port)
|
||||
public.write_log_gettext("Firewall manager", "Successfully changed SSH port to [{}]!",(port,))
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
#取SSH信息
|
||||
def GetSshInfo(self,get):
|
||||
@@ -398,11 +398,11 @@ class firewalls:
|
||||
import re
|
||||
# 判断端口是否正确
|
||||
rep = "^\d{1,5}(:\d{1,5})?$"
|
||||
if not re.search(rep, get.port): return public.returnMsg(False, 'PORT_CHECK_RANGE');
|
||||
if not re.search(rep, get.port): return public.return_msg_gettext(False, 'Port range is incorrect! should be between 100-65535');
|
||||
|
||||
# 判断IP是否正确
|
||||
rep2 = "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$"
|
||||
if not re.search(rep2, get.address): return public.returnMsg(False, 'FIREWALL_IP_FORMAT');
|
||||
if not re.search(rep2, get.address): return public.return_msg_gettext(False, 'IP address is illegal!');
|
||||
import time
|
||||
ports = get.port
|
||||
ps = get.ps
|
||||
@@ -414,19 +414,19 @@ class firewalls:
|
||||
type_list=['reject','accept']
|
||||
# 判断type类型是否正确
|
||||
|
||||
if types not in type_list:return public.returnMsg(False, 'FIREWALL_PORT_EXISTS')
|
||||
if types not in type_list:return public.return_msg_gettext(False, 'The port exists, no need to repeat the release!')
|
||||
# 判断protocol 类型是否正确
|
||||
|
||||
if protocol not in protocol_list: return public.returnMsg(False, 'FIREWALL_PORT_EXISTS')
|
||||
if protocol not in protocol_list: return public.return_msg_gettext(False, 'The port exists, no need to repeat the release!')
|
||||
|
||||
notudps = ['80', '443', '8888', '888', '39000:40000', '21', '22','7800']
|
||||
notudps = ['80', '443', '8888', '888', '39000:40000', '21', '22']
|
||||
if ports in notudps: flag = True
|
||||
|
||||
# sql 查询
|
||||
#sql="select * from firewall where ports='%s' and address_ip='%s' and protocol='%s' and types='%s';" % (str(ports), str(address_ip), str(protocol), str(types))
|
||||
query_result = public.M('firewall').where('ports=? and address_ip=? and protocol=? and types=?',(ports, address_ip, protocol, types)).count()
|
||||
# 这里大于0 表示存在
|
||||
if query_result > 0 : return public.returnMsg(False,'FIREWALL_PORT_EXISTS')
|
||||
if query_result > 0 : return public.return_msg_gettext(False,'The port exists, no need to repeat the release!')
|
||||
|
||||
if self.__isUfw:
|
||||
if type=='accept':
|
||||
@@ -447,11 +447,11 @@ class firewalls:
|
||||
'iptables -I INPUT -s ' + address_ip + ' -p ' + protocol + ' --dport ' + ports + ' -j DROP')
|
||||
|
||||
|
||||
public.WriteLog("TYPE_FIREWALL", 'FIREWALL_ACCEPT_PORT', (ports,))
|
||||
public.write_log_gettext("Firewall manager", 'Successfully accepted port [{}]!', (ports,))
|
||||
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
|
||||
result = public.M('firewall').add('protocol,types,port,address_ip,ps,addtime', (protocol,types,ports,address_ip,ps,addtime))
|
||||
self.FirewallReload()
|
||||
return public.returnMsg(True, 'ADD_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
|
||||
# 删除指定放行端口
|
||||
def DelSpecifiesIp(self, get):
|
||||
@@ -470,7 +470,7 @@ class firewalls:
|
||||
address_ip=get.address
|
||||
protocol_list = ['tcp', 'udp']
|
||||
id = get.id
|
||||
if protocol not in protocol_list: return public.returnMsg(False, 'DESIGNATED_POROTOCOL_NOT_EXIST')
|
||||
if protocol not in protocol_list: return public.return_msg_gettext(False, 'Specified protocol does NOT exist!')
|
||||
if self.__isUfw:
|
||||
if type=='accept':
|
||||
public.ExecShell('ufw delete allow proto ' + protocol + ' from ' + address_ip + ' to any port ' + ports + '')
|
||||
@@ -485,10 +485,10 @@ class firewalls:
|
||||
public.ExecShell('iptables -D INPUT -s ' + address_ip + ' -p ' + protocol + ' --dport ' + ports + ' -j ACCEPT')
|
||||
else:
|
||||
public.ExecShell('iptables -D INPUT -s ' + address_ip + ' -p ' + protocol + ' --dport ' + ports + ' -j DROP')
|
||||
public.WriteLog("TYPE_FIREWALL", 'FIREWALL_DROP_PORT', (ports,))
|
||||
public.write_log_gettext("Firewall manager", 'FIREWALL_DROP_PORT', (ports,))
|
||||
public.M('firewall').where("id=?", (id,)).delete()
|
||||
|
||||
self.FirewallReload()
|
||||
return public.returnMsg(True, 'DEL_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Successfully deleted')
|
||||
|
||||
|
||||
|
||||
@@ -321,7 +321,7 @@ class firewalld:
|
||||
# 服务控制
|
||||
def FirewalldService(self, type):
|
||||
public.ExecShell('systemctl ' + type + ' firewalld.service')
|
||||
return public.returnMsg(True, 'SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
|
||||
# 保存配置
|
||||
def Save(self):
|
||||
|
||||
@@ -11,10 +11,13 @@ class firewalls:
|
||||
__isFirewalld = False
|
||||
__isUfw = False
|
||||
__Obj = None
|
||||
__ufw_exec = 'ufw'
|
||||
|
||||
def __init__(self):
|
||||
if os.path.exists('/usr/sbin/firewalld'): self.__isFirewalld = True
|
||||
if os.path.exists('/usr/sbin/ufw'): self.__isUfw = True
|
||||
if os.path.exists('/usr/sbin/ufw'):
|
||||
self.__ufw_exec = '/usr/sbin/ufw'
|
||||
self.__isUfw = True
|
||||
if self.__isFirewalld:
|
||||
try:
|
||||
self.__Obj = firewalld.firewalld()
|
||||
@@ -53,38 +56,76 @@ class firewalls:
|
||||
#重载防火墙配置
|
||||
def FirewallReload(self):
|
||||
if self.__isUfw:
|
||||
public.ExecShell('/usr/sbin/ufw reload')
|
||||
public.ExecShell('{} reload &'.format(self.__ufw_exec))
|
||||
return
|
||||
if self.__isFirewalld:
|
||||
public.ExecShell('firewall-cmd --reload')
|
||||
else:
|
||||
public.ExecShell('/etc/init.d/iptables save')
|
||||
public.ExecShell('/etc/init.d/iptables restart')
|
||||
public.ExecShell('/etc/init.d/iptables save &')
|
||||
public.ExecShell('/etc/init.d/iptables restart &')
|
||||
|
||||
#取防火墙状态
|
||||
def CheckFirewallStatus(self):
|
||||
if self.__isUfw:
|
||||
return 1
|
||||
# if self.__isUfw:
|
||||
# res = public.ExecShell('ufw status verbose')[0]
|
||||
# if res.find('inactive') != -1: return False
|
||||
# return True
|
||||
|
||||
# if self.__isFirewalld:
|
||||
# res = public.ExecShell("systemctl status firewalld")[0]
|
||||
# if res.find('active (running)') != -1: return True
|
||||
# if res.find('disabled') != -1: return False
|
||||
# if res.find('inactive (dead)') != -1: return False
|
||||
# else:
|
||||
# res = public.ExecShell("/etc/init.d/iptables status")[0]
|
||||
# if res.find('not running') != -1: return False
|
||||
# return True
|
||||
return public.get_firewall_status() == 1
|
||||
|
||||
def SetFirewallStatus(self,get=None):
|
||||
'''
|
||||
@name 设置系统防火墙状态
|
||||
@author hwliang<2022-01-13>
|
||||
'''
|
||||
status = not self.CheckFirewallStatus()
|
||||
status_msg = {False: 'Close', True: 'Open'}
|
||||
if self.__isUfw:
|
||||
if status:
|
||||
public.ExecShell('echo y|{} enable'.format(self.__ufw_exec))
|
||||
else:
|
||||
public.ExecShell('echo y|{} disable'.format(self.__ufw_exec))
|
||||
if self.__isFirewalld:
|
||||
res = public.ExecShell("systemctl status firewalld")[0]
|
||||
if res.find('active (running)') != -1: return 1
|
||||
if res.find('disabled') != -1: return -1
|
||||
if res.find('inactive (dead)') != -1: return 0
|
||||
if status:
|
||||
public.ExecShell('systemctl enable firewalld')
|
||||
public.ExecShell('systemctl start firewalld')
|
||||
else:
|
||||
public.ExecShell('systemctl disable firewalld')
|
||||
public.ExecShell('systemctl stop firewalld')
|
||||
else:
|
||||
return 1
|
||||
if status:
|
||||
public.ExecShell("chkconfig iptables on")
|
||||
public.ExecShell('/etc/init.d/iptables start')
|
||||
else:
|
||||
public.ExecShell("chkconfig iptables off")
|
||||
public.ExecShell('/etc/init.d/iptables stop')
|
||||
public.write_log_gettext('Firewall manager','{} system firewall!',(status_msg[status],))
|
||||
return public.return_msg_gettext(True,'{} system firewall!',(status_msg[status],))
|
||||
|
||||
#添加屏蔽IP
|
||||
def AddDropAddress(self,get):
|
||||
if not self.CheckFirewallStatus(): return public.return_msg_gettext(False,'The system firewall is not open')
|
||||
import time
|
||||
import re
|
||||
ip_format = get.port.split('/')[0]
|
||||
if not public.check_ip(ip_format): return public.returnMsg(False,'FIREWALL_IP_FORMAT')
|
||||
if ip_format in ['0.0.0.0','127.0.0.0',"::1"]: return public.returnMsg(False,'请不要花样作死!')
|
||||
if not public.check_ip(ip_format): return public.return_msg_gettext(False,'IP address you entered is illegal!')
|
||||
if ip_format in ['0.0.0.0','127.0.0.0',"::1"]: return public.return_msg_gettext(False,'Disabling this IP will cause your server to fail')
|
||||
address = get.port
|
||||
if public.M('firewall').where("port=?",(address,)).count() > 0: return public.returnMsg(False,'FIREWALL_IP_EXISTS')
|
||||
if public.M('firewall').where("port=?",(address,)).count() > 0: return public.return_msg_gettext(False,'The IP exists in block list, no need to repeat processing!')
|
||||
if self.__isUfw:
|
||||
public.ExecShell('ufw insert 1 deny from ' + address + ' to any')
|
||||
if public.is_ipv6(ip_format):
|
||||
public.ExecShell('{} deny from '.format(self.__ufw_exec) + address + ' to any')
|
||||
else:
|
||||
public.ExecShell('{} insert 1 deny from '.format(self.__ufw_exec) + address + ' to any')
|
||||
else:
|
||||
if self.__isFirewalld:
|
||||
#self.__Obj.AddDropAddress(address)
|
||||
@@ -93,26 +134,26 @@ class firewalls:
|
||||
else:
|
||||
public.ExecShell('firewall-cmd --permanent --add-rich-rule=\'rule family=ipv4 source address="'+ address +'" drop\'')
|
||||
else:
|
||||
if public.is_ipv6(ip_format): return public.returnMsg(False,'FIREWALL_IP_FORMAT')
|
||||
if public.is_ipv6(ip_format): return public.return_msg_gettext(False,'IP address is illegal!')
|
||||
public.ExecShell('iptables -I INPUT -s '+address+' -j DROP')
|
||||
|
||||
public.WriteLog("TYPE_FIREWALL", 'FIREWALL_DROP_IP',(address,))
|
||||
addtime = time.strftime('%Y-%m-%d %X',time.localtime())
|
||||
public.M('firewall').add('port,ps,addtime',(address,get.ps,addtime))
|
||||
self.FirewallReload()
|
||||
return public.returnMsg(True,'ADD_SUCCESS')
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
|
||||
#删除IP屏蔽
|
||||
def DelDropAddress(self,get):
|
||||
if not self.CheckFirewallStatus(): return public.return_msg_gettext(False,'The system firewall is not open')
|
||||
address = get.port
|
||||
id = get.id
|
||||
ip_format = get.port.split('/')[0]
|
||||
if self.__isUfw:
|
||||
public.ExecShell('ufw delete deny from ' + address + ' to any')
|
||||
public.ExecShell('{} delete deny from '.format(self.__ufw_exec) + address + ' to any')
|
||||
else:
|
||||
if self.__isFirewalld:
|
||||
#self.__Obj.DelDropAddress(address)
|
||||
if public.is_ipv6(ip_format):
|
||||
public.ExecShell('firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv6 source address="'+ address +'" drop\'')
|
||||
else:
|
||||
@@ -124,73 +165,81 @@ class firewalls:
|
||||
public.M('firewall').where("id=?",(id,)).delete()
|
||||
|
||||
self.FirewallReload()
|
||||
return public.returnMsg(True,'DEL_SUCCESS')
|
||||
return public.return_msg_gettext(True,'Successfully deleted')
|
||||
|
||||
|
||||
#添加放行端口
|
||||
def AddAcceptPort(self,get):
|
||||
if not self.CheckFirewallStatus(): return public.return_msg_gettext(False,'The system firewall is not open')
|
||||
import re
|
||||
src_port = get.port
|
||||
get.port = get.port.replace('-',':')
|
||||
rep = r"^\d{1,5}(:\d{1,5})?$"
|
||||
if not re.search(rep,get.port):
|
||||
return public.returnMsg(False,'PORT_CHECK_RANGE')
|
||||
return public.return_msg_gettext(False,'Port range must be between 22 and 65535!')
|
||||
|
||||
import time
|
||||
port = get.port
|
||||
ps = public.xssencode(get.ps)
|
||||
ps = ""
|
||||
if get.ps:
|
||||
ps = public.xssencode2(get.ps)
|
||||
is_exists = public.M('firewall').where("port=? or port=?",(port,src_port)).count()
|
||||
if is_exists: return public.returnMsg(False,'FIREWALL_PORT_EXISTS')
|
||||
notudps = ['80','443','8888','888','39000:40000','21','22','7800']
|
||||
if is_exists: return public.return_msg_gettext(False,'The port exists, no need to repeat the release!')
|
||||
notudps = ['80','443','8888','888','39000:40000','21','22']
|
||||
if self.__isUfw:
|
||||
public.ExecShell('ufw allow ' + port + '/tcp')
|
||||
if not port in notudps: public.ExecShell('ufw allow ' + port + '/udp')
|
||||
public.ExecShell('{} allow '.format(self.__ufw_exec) + port + '/tcp')
|
||||
# if not port in notudps: public.ExecShell('ufw allow ' + port + '/udp')
|
||||
else:
|
||||
if self.__isFirewalld:
|
||||
#self.__Obj.AddAcceptPort(port)
|
||||
port = port.replace(':','-')
|
||||
public.ExecShell('firewall-cmd --permanent --zone=public --add-port='+port+'/tcp')
|
||||
if not port in notudps: public.ExecShell('firewall-cmd --permanent --zone=public --add-port='+port+'/udp')
|
||||
# if not port in notudps: public.ExecShell('firewall-cmd --permanent --zone=public --add-port='+port+'/udp')
|
||||
else:
|
||||
public.ExecShell('iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport '+port+' -j ACCEPT')
|
||||
if not port in notudps: public.ExecShell('iptables -I INPUT -p tcp -m state --state NEW -m udp --dport '+port+' -j ACCEPT')
|
||||
# if not port in notudps: public.ExecShell('iptables -I INPUT -p tcp -m state --state NEW -m udp --dport '+port+' -j ACCEPT')
|
||||
public.WriteLog("TYPE_FIREWALL", 'FIREWALL_ACCEPT_PORT',(port,))
|
||||
addtime = time.strftime('%Y-%m-%d %X',time.localtime())
|
||||
if not is_exists: public.M('firewall').add('port,ps,addtime',(port,ps,addtime))
|
||||
self.FirewallReload()
|
||||
return public.returnMsg(True,'ADD_SUCCESS')
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
|
||||
#添加放行端口
|
||||
def AddAcceptPortAll(self,port,ps):
|
||||
if not self.CheckFirewallStatus(): return public.return_msg_gettext(False,'The system firewall is not open')
|
||||
import re
|
||||
port = port.replace('-',':')
|
||||
rep = r"^\d{1,5}(:\d{1,5})?$"
|
||||
if not re.search(rep,port):
|
||||
return False
|
||||
if self.__isUfw:
|
||||
public.ExecShell('ufw allow ' + port + '/tcp')
|
||||
public.ExecShell('ufw allow ' + port + '/udp')
|
||||
public.ExecShell('{} allow '.format(self.__ufw_exec) + port + '/tcp')
|
||||
# public.ExecShell('ufw allow ' + port + '/udp')
|
||||
else:
|
||||
if self.__isFirewalld:
|
||||
port = port.replace(':','-')
|
||||
public.ExecShell('firewall-cmd --permanent --zone=public --add-port='+port+'/tcp')
|
||||
public.ExecShell('firewall-cmd --permanent --zone=public --add-port='+port+'/udp')
|
||||
# public.ExecShell('firewall-cmd --permanent --zone=public --add-port='+port+'/udp')
|
||||
else:
|
||||
public.ExecShell('iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport '+port+' -j ACCEPT')
|
||||
public.ExecShell('iptables -I INPUT -p tcp -m state --state NEW -m udp --dport '+port+' -j ACCEPT')
|
||||
# public.ExecShell('iptables -I INPUT -p tcp -m state --state NEW -m udp --dport '+port+' -j ACCEPT')
|
||||
return True
|
||||
|
||||
|
||||
#删除放行端口
|
||||
def DelAcceptPort(self,get):
|
||||
if not self.CheckFirewallStatus(): return public.return_msg_gettext(False,'The system firewall is not open')
|
||||
port = get.port
|
||||
id = get.id
|
||||
|
||||
if public.is_ipv6(str(port)): return self.DelDropAddress(get) # 如果是ipv6地址,则调用DelDropAddress
|
||||
|
||||
try:
|
||||
if(port == public.GetHost(True) or port == public.readFile('data/port.pl').strip()):
|
||||
return public.returnMsg(False,'FIREWALL_PORT_PANEL')
|
||||
return public.return_msg_gettext(False,'Failed,cannot delete current port of the panel')
|
||||
if self.__isUfw:
|
||||
public.ExecShell('ufw delete allow ' + port + '/tcp')
|
||||
public.ExecShell('ufw delete allow ' + port + '/udp')
|
||||
public.ExecShell('{} delete allow '.format(self.__ufw_exec) + port + '/tcp')
|
||||
public.ExecShell('{} delete allow '.format(self.__ufw_exec) + port + '/udp')
|
||||
else:
|
||||
if self.__isFirewalld:
|
||||
#self.__Obj.DelAcceptPort(port)
|
||||
@@ -201,35 +250,42 @@ class firewalls:
|
||||
public.ExecShell('iptables -D INPUT -p tcp -m state --state NEW -m udp --dport '+port+' -j ACCEPT')
|
||||
public.WriteLog("TYPE_FIREWALL", 'FIREWALL_DROP_PORT',(port,))
|
||||
public.M('firewall').where("id=?",(id,)).delete()
|
||||
|
||||
|
||||
self.FirewallReload()
|
||||
return public.returnMsg(True,'DEL_SUCCESS')
|
||||
return public.return_msg_gettext(True,'Successfully deleted')
|
||||
except:
|
||||
return public.returnMsg(False,'DEL_ERROR')
|
||||
return public.return_msg_gettext(False,'Failed to delete')
|
||||
|
||||
#设置远程端口状态
|
||||
def SetSshStatus(self,get):
|
||||
version = public.readFile('/etc/redhat-release')
|
||||
# version = public.readFile('/etc/redhat-release')
|
||||
if int(get['status'])==1:
|
||||
msg = public.getMsg('FIREWALL_SSH_STOP')
|
||||
msg = public.get_msg_gettext('SSH service turned off')
|
||||
act = 'stop'
|
||||
else:
|
||||
msg = public.getMsg('FIREWALL_SSH_START')
|
||||
msg = public.get_msg_gettext('SSH service turned on')
|
||||
act = 'start'
|
||||
|
||||
if not os.path.exists('/etc/redhat-release'):
|
||||
public.ExecShell('service ssh ' + act)
|
||||
elif version.find(' 7.') != -1 or version.find(' 8.') != -1 or version.find('Fedora') != -1:
|
||||
public.ExecShell("systemctl "+act+" sshd.service")
|
||||
else:
|
||||
public.ExecShell("/etc/init.d/sshd "+act)
|
||||
|
||||
public.WriteLog("TYPE_FIREWALL", msg)
|
||||
return public.returnMsg(True,'SUCCESS')
|
||||
|
||||
|
||||
|
||||
|
||||
# if not os.path.exists('/etc/redhat-release'):
|
||||
# public.ExecShell('service ssh ' + act)
|
||||
# elif version.find(' 7.') != -1 or version.find(' 8.') != -1 or version.find('Fedora') != -1:
|
||||
# public.ExecShell("systemctl "+act+" sshd")
|
||||
# else:
|
||||
# 全试一次?
|
||||
public.ExecShell("/etc/init.d/sshd "+act)
|
||||
public.ExecShell('service ssh ' + act)
|
||||
public.ExecShell("systemctl "+act+" sshd")
|
||||
public.ExecShell("systemctl "+act+" ssh")
|
||||
if act in ['start'] and not public.get_sshd_status():
|
||||
msg = 'Service SSHD start failed!'
|
||||
public.WriteLog("TYPE_FIREWALL", msg)
|
||||
return public.returnMsg(False,msg)
|
||||
public.WriteLog("TYPE_FIREWALL", msg)
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
|
||||
|
||||
|
||||
#设置ping
|
||||
def SetPing(self,get):
|
||||
if get.status == '1':
|
||||
@@ -243,20 +299,27 @@ class firewalls:
|
||||
conf = re.sub(rep,'net.ipv4.icmp_echo_ignore_all='+get.status,conf)
|
||||
else:
|
||||
conf += "\nnet.ipv4.icmp_echo_ignore_all="+get.status
|
||||
|
||||
|
||||
public.writeFile(filename,conf)
|
||||
public.ExecShell('sysctl -p')
|
||||
return public.returnMsg(True,'SUCCESS')
|
||||
|
||||
|
||||
|
||||
|
||||
if public.writeFile(filename,conf):
|
||||
public.ExecShell('sysctl -p')
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
else:
|
||||
return public.returnMsg(False,'Setup failed!')
|
||||
|
||||
|
||||
|
||||
#改远程端口
|
||||
def SetSshPort(self,get):
|
||||
port = get.port
|
||||
if int(port) < 22 or int(port) > 65535: return public.returnMsg(False,'FIREWALL_SSH_PORT_ERR')
|
||||
if not port:
|
||||
return public.return_msg_gettext(False, 'Port range must be between 22 and 65535!')
|
||||
try:
|
||||
if int(port) < 22 or int(port) > 65535: return public.return_msg_gettext(False,'Port range must be between 22 and 65535!')
|
||||
except:
|
||||
return public.return_msg_gettext(False, 'Port range must be between 22 and 65535!')
|
||||
ports = ['21','25','80','443','8080','888','8888','7800']
|
||||
if port in ports: return public.returnMsg(False,'DONT_USE_PORT')
|
||||
if port in ports: return public.return_msg_gettext(False,'Do NOT use common default port!')
|
||||
file = '/etc/ssh/sshd_config'
|
||||
conf = public.readFile(file)
|
||||
|
||||
@@ -270,47 +333,22 @@ class firewalls:
|
||||
public.ExecShell('sed -i "s#SELINUX=enforcing#SELINUX=disabled#" /etc/selinux/config')
|
||||
public.ExecShell("systemctl restart sshd.service")
|
||||
elif self.__isUfw:
|
||||
public.ExecShell('ufw allow ' + port + '/tcp')
|
||||
public.ExecShell('{} allow '.format(self.__ufw_exec) + port + '/tcp')
|
||||
public.ExecShell("service ssh restart")
|
||||
else:
|
||||
public.ExecShell('iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport '+port+' -j ACCEPT')
|
||||
public.ExecShell("/etc/init.d/sshd restart")
|
||||
|
||||
|
||||
self.FirewallReload()
|
||||
public.M('firewall').where("ps=? or ps=? or port=?",('SSH remote management service','SSH remote service',port)).delete()
|
||||
public.M('firewall').add('port,ps,addtime',(port,'SSH remote service',time.strftime('%Y-%m-%d %X',time.localtime())))
|
||||
public.WriteLog("TYPE_FIREWALL", "FIREWALL_SSH_PORT",(port,))
|
||||
return public.returnMsg(True,'EDIT_SUCCESS')
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
#取SSH信息
|
||||
def GetSshInfo(self,get):
|
||||
port = public.get_ssh_port()
|
||||
|
||||
pid_file = '/run/sshd.pid'
|
||||
if os.path.exists(pid_file):
|
||||
pid = int(public.readFile(pid_file))
|
||||
status = public.pid_exists(pid)
|
||||
else:
|
||||
import system
|
||||
panelsys = system.system()
|
||||
|
||||
version = panelsys.GetSystemVersion()
|
||||
if os.path.exists('/usr/bin/apt-get'):
|
||||
if os.path.exists('/etc/init.d/sshd'):
|
||||
status = public.ExecShell("service sshd status | grep -P '(dead|stop)'|grep -v grep")
|
||||
else:
|
||||
status = public.ExecShell("service ssh status | grep -P '(dead|stop)'|grep -v grep")
|
||||
else:
|
||||
if version.find(' 7.') != -1 or version.find(' 8.') != -1 or version.find('Fedora') != -1:
|
||||
status = public.ExecShell("systemctl status sshd.service | grep 'dead'|grep -v grep")
|
||||
else:
|
||||
status = public.ExecShell("/etc/init.d/sshd status | grep -e 'stopped' -e '已停'|grep -v grep")
|
||||
|
||||
# return status;
|
||||
if len(status[0]) > 3:
|
||||
status = False
|
||||
else:
|
||||
status = True
|
||||
port = public.get_sshd_port()
|
||||
status = public.get_sshd_status()
|
||||
isPing = True
|
||||
try:
|
||||
file = '/etc/sysctl.conf'
|
||||
@@ -325,6 +363,6 @@ class firewalls:
|
||||
data['port'] = port
|
||||
data['status'] = status
|
||||
data['ping'] = isPing
|
||||
data['firewall_status'] = self.CheckFirewallStatus()
|
||||
return data
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import sys,os
|
||||
from gzip import GzipFile
|
||||
from io import BytesIO
|
||||
|
||||
from flask import request, current_app,session,Response,g
|
||||
from flask import request, current_app,session,Response,g,abort
|
||||
|
||||
|
||||
if sys.version_info[:2] == (2, 6):
|
||||
@@ -80,7 +80,8 @@ class Compress(object):
|
||||
accept_encoding = request.headers.get('Accept-Encoding', '')
|
||||
response.headers['Server'] = 'nginx'
|
||||
response.headers['Connection'] = 'keep-alive'
|
||||
|
||||
if not 'tmp_login' in session:
|
||||
response.headers["X-Frame-Options"] = "SAMEORIGIN"
|
||||
if 'dologin' in g and app.config['SSL']:
|
||||
try:
|
||||
for k,v in request.cookies.items():
|
||||
@@ -104,6 +105,23 @@ class Compress(object):
|
||||
if request_token:
|
||||
response.set_cookie('request_token',request_token,path='/',max_age=86400 * 30)
|
||||
|
||||
if response.content_length is not None:
|
||||
if response.content_length < 512:
|
||||
if not session.get('login',None) or g.get('api_request',None):
|
||||
import public
|
||||
default_pl = "{}/default.pl".format(public.get_panel_path())
|
||||
default_body = public.readFile(default_pl,'rb')
|
||||
|
||||
if default_body:
|
||||
if not default_body: default_body = b""
|
||||
resp_body = response.get_data()
|
||||
|
||||
if default_body and resp_body.find(default_body.strip()) != -1:
|
||||
result = b'{"status":false,"msg":"Error: 403 Forbidden"}'
|
||||
response.set_data(result)
|
||||
response.headers['Content-Length'] = len(result)
|
||||
return response
|
||||
|
||||
|
||||
if (response.mimetype not in app.config['COMPRESS_MIMETYPES'] or
|
||||
'gzip' not in accept_encoding.lower() or
|
||||
|
||||
@@ -286,25 +286,21 @@ class MemcachedSessionInterface(SessionInterface):
|
||||
session_id = self._get_signer(app).sign(want_bytes(session.sid))
|
||||
else:
|
||||
session_id = session.sid
|
||||
from BTPanel import request, g, get_input
|
||||
from BTPanel import request,g,get_input
|
||||
if 'auth_error' in g: return
|
||||
if request.path in ['/', '/tips','/robots.txt']: return
|
||||
if request.path in ['/', '/tips', '/robots.txt', '/favicon.ico', '/hook', '/close', '/down/']: return
|
||||
if request.path in ['/public']:
|
||||
get = get_input()
|
||||
if 'get_ping' in get: return
|
||||
if not 'get_ping' in get: return
|
||||
if response.status_code in [401]: return
|
||||
|
||||
if request.full_path.find('/login?tmp_token=') != 0:
|
||||
if response.status_code not in [200, 308]: return
|
||||
if response.status_code not in [200,308]: return
|
||||
else:
|
||||
if response.status_code not in [302, 301]: return
|
||||
if response.status_code not in [302,301]: return
|
||||
if secure: samesite = 'None'
|
||||
|
||||
if response.status_code not in [200,302]: return
|
||||
if not request.cookies.get(app.session_cookie_name):
|
||||
if request.full_path.find('/login?tmp_token=') == 0:
|
||||
samesite = 'None'
|
||||
secure = True
|
||||
response.set_cookie(app.session_cookie_name, session_id,
|
||||
expires=expires, httponly=httponly,
|
||||
domain=domain, path=path, secure=secure,samesite=samesite)
|
||||
|
||||
@@ -20,94 +20,100 @@ class ftp:
|
||||
#添加FTP
|
||||
def AddUser(self,get):
|
||||
try:
|
||||
if not os.path.exists('/www/server/pure-ftpd/sbin/pure-ftpd'): return public.returnMsg(False,'Please install the Pure-FTPd service in the software store first.')
|
||||
if not os.path.exists('/www/server/pure-ftpd/sbin/pure-ftpd'): return public.return_msg_gettext(False,'Please install the Pure-FTPd service in the software store first.')
|
||||
import files,time
|
||||
fileObj=files.files()
|
||||
if re.search("\W + ",get['ftp_username']): return {'status':False,'code':501,'msg':public.getMsg('FTP_USERNAME_ERR_T')}
|
||||
if len(get['ftp_username']) < 3: return {'status':False,'code':501,'msg':public.getMsg('FTP_USERNAME_ERR_LEN')}
|
||||
if not fileObj.CheckDir(get['path']): return {'status':False,'code':501,'msg':public.getMsg('FTP_USERNAME_ERR_DIR')}
|
||||
if public.M('ftps').where('name=?',(get.ftp_username.strip(),)).count(): return public.returnMsg(False,'FTP_USERNAME_ERR_EXISTS',(get.ftp_username,))
|
||||
username = get['ftp_username'].replace(' ','')
|
||||
password = get['ftp_password']
|
||||
if get['ftp_username'].strip().find(' ') != -1: return public.returnMsg(False,'Username cannot contain spaces')
|
||||
if re.search("\W + ",get['ftp_username']): return {'status':False,'code':501,'msg':public.get_msg_gettext('Username is illegal, special characters are NOT allowed!')}
|
||||
if len(get['ftp_username']) < 3: return {'status':False,'code':501,'msg':public.get_msg_gettext('Username is illegal, cannot be less than 3 characters!')}
|
||||
if not fileObj.CheckDir(get['path']): return {'status':False,'code':501,'msg':public.get_msg_gettext('System critical directory cannot be used as FTP directory!')}
|
||||
if public.M('ftps').where('name=?',(get.ftp_username.strip(),)).count(): return public.return_msg_gettext(False,'User [{}] exists!',(get.ftp_username,))
|
||||
username = get['ftp_username'].strip()
|
||||
if re.search("[\/\\\:\*\?\"\'\<\>\|]+",username):
|
||||
return public.return_msg_gettext(False,"Name cannot contain /\:*?\"<>| symbol")
|
||||
password = get['ftp_password'].strip()
|
||||
if len(password) < 6: return public.return_msg_gettext(False, 'Password must be at least [{}] characters',("6",))
|
||||
get.path = get['path'].replace(' ','')
|
||||
get.path = get.path.replace("\\", "/")
|
||||
fileObj.CreateDir(get)
|
||||
public.ExecShell('chown www.www ' + get.path)
|
||||
public.ExecShell(self.__runPath + '/pure-pw useradd ' + username + ' -u www -d ' + get.path + '<<EOF \n' + password + '\n' + password + '\nEOF')
|
||||
public.ExecShell(self.__runPath + '/pure-pw useradd "' + username + '" -u www -d ' + get.path + '<<EOF \n' + password + '\n' + password + '\nEOF')
|
||||
self.FtpReload()
|
||||
ps=public.xssencode(get['ps'])
|
||||
if get['ps']=='': ps= public.getMsg('INPUT_PS');
|
||||
ps = public.xssencode2(get['ps'])
|
||||
if get['ps']=='': ps= public.get_msg_gettext('Edit notes');
|
||||
addtime=time.strftime('%Y-%m-%d %X',time.localtime())
|
||||
|
||||
pid = 0
|
||||
if hasattr(get,'pid'): pid = get.pid
|
||||
public.M('ftps').add('pid,name,password,path,status,ps,addtime',(pid,username,password,get.path,1,ps,addtime))
|
||||
public.WriteLog('TYPE_FTP', 'FTP_ADD_SUCCESS',(username,))
|
||||
return public.returnMsg(True,'ADD_SUCCESS')
|
||||
public.write_log_gettext('FTP manager', 'Successfully added FTP user [{}]!',(username,))
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
except Exception as ex:
|
||||
public.WriteLog('TYPE_FTP', 'FTP_ADD_ERR',(username,str(ex)))
|
||||
return public.returnMsg(False,'ADD_ERROR')
|
||||
public.write_log_gettext('FTP manager', 'Failed to add FTP user[{}]! => {}',(username,str(ex)))
|
||||
return public.return_msg_gettext(False,'Failed to add')
|
||||
|
||||
#删除用户
|
||||
def DeleteUser(self,get):
|
||||
try:
|
||||
username = get['username']
|
||||
id = get['id']
|
||||
public.ExecShell(self.__runPath + '/pure-pw userdel ' + username)
|
||||
public.ExecShell(self.__runPath + '/pure-pw userdel "' + username + '"')
|
||||
self.FtpReload()
|
||||
public.M('ftps').where("id=?",(id,)).delete()
|
||||
public.WriteLog('TYPE_FTP', 'FTP_DEL_SUCCESS',(username,))
|
||||
return public.returnMsg(True, "DEL_SUCCESS")
|
||||
public.write_log_gettext('FTP manager', 'Successfully deleted FTP user[{}]!',(username,))
|
||||
return public.return_msg_gettext(True, 'Successfully deleted')
|
||||
except Exception as ex:
|
||||
public.WriteLog('TYPE_FTP', 'FTP_DEL_ERR',(username,str(ex)))
|
||||
return public.returnMsg(False,'DEL_ERROR')
|
||||
public.write_log_gettext('FTP manager', 'Faided to delete FTP user[{}]! => {}',(username,str(ex)))
|
||||
return public.return_msg_gettext(False,'Failed to delete')
|
||||
|
||||
|
||||
#修改用户密码
|
||||
def SetUserPassword(self,get):
|
||||
try:
|
||||
id = get['id']
|
||||
username = get['ftp_username']
|
||||
password = get['new_password']
|
||||
public.ExecShell(self.__runPath + '/pure-pw passwd ' + username + '<<EOF \n' + password + '\n' + password + '\nEOF')
|
||||
username = get['ftp_username'].strip()
|
||||
password = get['new_password'].strip()
|
||||
if len(password) < 6: return public.return_msg_gettext(False,'Password must be at least [{}] characters',("6",))
|
||||
public.ExecShell(self.__runPath + '/pure-pw passwd "' + username + '"<<EOF \n' + password + '\n' + password + '\nEOF')
|
||||
self.FtpReload()
|
||||
public.M('ftps').where("id=?",(id,)).setField('password',password)
|
||||
public.WriteLog('TYPE_FTP', 'FTP_PASS_SUCCESS',(username,))
|
||||
return public.returnMsg(True,'EDIT_SUCCESS')
|
||||
public.write_log_gettext('FTP manager', 'Successfully changed password for FTP user[{}]!',(username,))
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
except Exception as ex:
|
||||
public.WriteLog('TYPE_FTP', 'FTP_PASS_ERR',(username,str(ex)))
|
||||
return public.returnMsg(False,'EDIT_ERROR')
|
||||
public.write_log_gettext('FTP manager', 'Failed to change password FTP user[{}]! => {}',(username,str(ex)))
|
||||
return public.return_msg_gettext(False,'Failed to modify')
|
||||
|
||||
|
||||
#设置用户状态
|
||||
def SetStatus(self,get):
|
||||
msg = public.getMsg('OFF');
|
||||
if get.status != '0': msg = public.getMsg('ON');
|
||||
msg = public.get_msg_gettext('Turn off');
|
||||
if get.status != '0': msg = public.get_msg_gettext('Turn on');
|
||||
try:
|
||||
id = get['id']
|
||||
username = get['username']
|
||||
status = get['status']
|
||||
if int(status)==0:
|
||||
public.ExecShell(self.__runPath + '/pure-pw usermod ' + username + ' -r 1')
|
||||
public.ExecShell(self.__runPath + '/pure-pw usermod "' + username + '" -r 1')
|
||||
else:
|
||||
public.ExecShell(self.__runPath + '/pure-pw usermod ' + username + " -r ''")
|
||||
public.ExecShell(self.__runPath + '/pure-pw usermod "' + username + "\" -r ''")
|
||||
self.FtpReload()
|
||||
public.M('ftps').where("id=?",(id,)).setField('status',status)
|
||||
public.WriteLog('TYPE_FTP','FTP_STATUS', (msg,username))
|
||||
return public.returnMsg(True, 'SUCCESS')
|
||||
public.write_log_gettext('FTP manager','Successfully {} FTP user [{}]!', (msg,username))
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
except Exception as ex:
|
||||
public.WriteLog('TYPE_FTP','FTP_STATUS_ERR', (msg,username,str(ex)))
|
||||
return public.returnMsg(False,'FTP_STATUS_ERR',(msg,))
|
||||
public.write_log_gettext('FTP manager','Failed to {} FTP user [{}]! => {}', (msg,username,str(ex)))
|
||||
return public.return_msg_gettext(False,'{} FTP user failed!',(msg,))
|
||||
|
||||
'''
|
||||
* 设置FTP端口
|
||||
* @param Int _GET['port'] 端口号
|
||||
* @param Int _GET['port'] 端口号
|
||||
* @return bool
|
||||
'''
|
||||
def setPort(self,get):
|
||||
try:
|
||||
port = get['port']
|
||||
if int(port) < 1 or int(port) > 65535: return public.returnMsg(False,'PORT_CHECK_RANGE')
|
||||
port = get['port'].strip()
|
||||
if not port: return public.returnMsg(False,'Please enter an integer for the port')
|
||||
if int(port) < 1 or int(port) > 65535: return public.return_msg_gettext(False,'Port range is incorrect!')
|
||||
file = '/www/server/pure-ftpd/etc/pure-ftpd.conf'
|
||||
conf = public.readFile(file)
|
||||
rep = u"\n#?\s*Bind\s+[0-9]+\.[0-9]+\.[0-9]+\.+[0-9]+,([0-9]+)"
|
||||
@@ -115,18 +121,66 @@ class ftp:
|
||||
conf = re.sub(rep,"\nBind 0.0.0.0," + port,conf)
|
||||
public.writeFile(file,conf)
|
||||
public.ExecShell('/etc/init.d/pure-ftpd restart')
|
||||
public.WriteLog('TYPE_FTP', "FTP_PORT",(port,))
|
||||
public.write_log_gettext('FTP manager', "Successfully modified FTP port to [{}]!",(port,))
|
||||
#添加防火墙
|
||||
#data = ftpinfo(port=port,ps = 'FTP端口')
|
||||
get.port=port
|
||||
get.ps = public.getMsg('FTP_PORT_PS');
|
||||
get.ps = public.get_msg_gettext('FTP port');
|
||||
firewalls.firewalls().AddAcceptPort(get)
|
||||
session['port']=port
|
||||
return public.returnMsg(True, 'EDIT_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
except Exception as ex:
|
||||
public.WriteLog('TYPE_FTP', 'FTP_PORT_ERR',(str(ex),))
|
||||
return public.returnMsg(False,'EDIT_ERROR')
|
||||
public.write_log_gettext('FTP manager', 'Failed to modify FTP port! => {}',(str(ex),))
|
||||
return public.return_msg_gettext(False,'Failed to modify')
|
||||
|
||||
#重载配置
|
||||
def FtpReload(self):
|
||||
public.ExecShell(self.__runPath + '/pure-pw mkdb /www/server/pure-ftpd/etc/pureftpd.pdb')
|
||||
|
||||
#修改用户密码
|
||||
def set_user_home(self,get):
|
||||
"""
|
||||
change user home
|
||||
id: ftp id
|
||||
path: the new ftp user home
|
||||
ftp_username: ftp username
|
||||
migrate: migrate ftp user data to the new home
|
||||
|
||||
"""
|
||||
try:
|
||||
id = get['id']
|
||||
path = get['path']
|
||||
username = get['ftp_username']
|
||||
# get the old path in the panel sqlite db
|
||||
old_path = public.M("ftps").where("id=?",(id,)).getField('path')
|
||||
# check the auth ftp user if exists
|
||||
auth_conf_file = '/www/server/pure-ftpd/etc/pureftpd.passwd'
|
||||
auth_conf = public.readFile(auth_conf_file)
|
||||
if not auth_conf:
|
||||
return public.returnMsg(False,'FTP account has not been set up')
|
||||
# get the user specified conf
|
||||
auth_conf_list = [i for i in auth_conf.split('\n')]
|
||||
rep = '^{}:.*'.format(username)
|
||||
macth_conf = [i for i in auth_conf_list if re.search(rep,i)]
|
||||
if not macth_conf:
|
||||
return public.returnMsg(False, 'FTP account has not been set up1')
|
||||
if len(macth_conf) > 1:
|
||||
return public.returnMsg(False, 'Matching multiple configurations, this operation has been stopped!')
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
public.ExecShell('chown www.www ' + path)
|
||||
# replace the old path
|
||||
result = macth_conf[0]
|
||||
specified_user_conf = result.replace(old_path,path)
|
||||
auth_conf = auth_conf.replace(result,specified_user_conf)
|
||||
public.writeFile(auth_conf_file,auth_conf)
|
||||
if get.migrate == '1':
|
||||
public.ExecShell('cp -rp {}/* {}'.format(old_path,path))
|
||||
self.FtpReload()
|
||||
public.M('ftps').where("id=?",(id,)).setField('path',path)
|
||||
public.write_log_gettext('FTP manager', 'Successfully changed password for FTP user[{}]!',(path,))
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
except Exception as ex:
|
||||
return public.get_error_info()
|
||||
public.write_log_gettext('FTP manager', 'FTP_PASS_ERR',(path,str(ex)))
|
||||
return public.returnMsg(False,'EDIT_ERROR')
|
||||
@@ -14,22 +14,31 @@ import os,sys,re
|
||||
import ssl
|
||||
import public
|
||||
import json
|
||||
import socket
|
||||
import requests
|
||||
import requests.packages.urllib3.util.connection as urllib3_conn
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
|
||||
class http:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def get(self,url,timeout = 60,headers = {},verify = False,type = 'python'):
|
||||
url = self.quote(url)
|
||||
if type == 'python':
|
||||
old_family = urllib3_conn.allowed_gai_family
|
||||
try:
|
||||
import requests
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
from requests import get as req_get
|
||||
return req_get(url,timeout=timeout,headers=get_headers(headers),verify=verify)
|
||||
# 默认使用IPv4
|
||||
urllib3_conn.allowed_gai_family = lambda: socket.AF_INET
|
||||
return requests.get(url,timeout=timeout,headers=get_headers(headers),verify=verify)
|
||||
except:
|
||||
result = self._get_curl(url,timeout,headers,verify)
|
||||
try:
|
||||
# IPV6?
|
||||
urllib3_conn.allowed_gai_family = lambda: socket.AF_INET6
|
||||
return requests.get(url,timeout=timeout,headers=get_headers(headers),verify=verify)
|
||||
except:
|
||||
# 使用CURL
|
||||
result = self._get_curl(url,timeout,headers,verify)
|
||||
urllib3_conn.allowed_gai_family = old_family
|
||||
|
||||
elif type == 'curl':
|
||||
result = self._get_curl(url,timeout,headers,verify)
|
||||
elif type == 'php':
|
||||
@@ -44,14 +53,20 @@ class http:
|
||||
def post(self,url,data,timeout = 60,headers = {},verify = False,type = 'python'):
|
||||
url = self.quote(url)
|
||||
if type == 'python':
|
||||
old_family = urllib3_conn.allowed_gai_family
|
||||
try:
|
||||
import requests
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
from requests import post as req_post
|
||||
return req_post(url,data,timeout=timeout,headers=headers,verify=verify)
|
||||
urllib3_conn.allowed_gai_family = lambda: socket.AF_INET
|
||||
return requests.post(url,data,timeout=timeout,headers=headers,verify=verify)
|
||||
except:
|
||||
result = self._post_curl(url,data,timeout,headers,verify)
|
||||
try:
|
||||
# IPV6?
|
||||
urllib3_conn.allowed_gai_family = lambda: socket.AF_INET6
|
||||
return requests.post(url,data,timeout=timeout,headers=headers,verify=verify)
|
||||
except:
|
||||
# 使用CURL
|
||||
result = self._post_curl(url,data,timeout,headers,verify)
|
||||
urllib3_conn.allowed_gai_family = old_family
|
||||
|
||||
elif type == 'curl':
|
||||
result = self._post_curl(url,data,timeout,headers,verify)
|
||||
elif type == 'php':
|
||||
@@ -63,6 +78,30 @@ class http:
|
||||
result = self._post_py3(url,data,timeout,headers,verify)
|
||||
return result
|
||||
|
||||
|
||||
def download_file(self,url,filename,data = None,timeout = 1800,speed_file='/dev/shm/download_speed.pl'):
|
||||
'''
|
||||
@name 下载文件
|
||||
@author hwliang<2021-07-08>
|
||||
@param url<string> 下载地址
|
||||
@param filename<string> 保存路径
|
||||
@param data<dict> POST参数,不传则使用GET方法,否则使用POST方法
|
||||
@param timeout<int> 超时时间,默认1800秒
|
||||
@param speed_file<string>
|
||||
'''
|
||||
import requests
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
headers = public.get_requests_headers()
|
||||
if data is None:
|
||||
res = requests.get(url,headers=headers,timeout=timeout,stream=True)
|
||||
else:
|
||||
res = requests.post(url,data,headers=headers,timeout=timeout,stream=True)
|
||||
with open(filename,"wb") as f:
|
||||
for _chunk in res.iter_content(chunk_size=8192):
|
||||
f.write(_chunk)
|
||||
|
||||
|
||||
#POST请求 Python2
|
||||
def _post_py2(self,url,data,timeout,headers,verify):
|
||||
import urllib2
|
||||
@@ -114,18 +153,21 @@ class http:
|
||||
raise Exception('No PHP version available!')
|
||||
tmp_file = '/dev/shm/http.php'
|
||||
http_php = '''<?php
|
||||
if(isset($_POST['data'])){
|
||||
error_reporting(E_ERROR);
|
||||
if(isset($_POST['data'])){{
|
||||
$data = json_decode($_POST['data'],1);
|
||||
}else{
|
||||
$data = json_decode(getopt('',array('post:'))['post'],1);
|
||||
}
|
||||
}}else{{
|
||||
$s = getopt('',array('post:'));
|
||||
$data = json_decode($s['post'],1);
|
||||
}}
|
||||
$url = $data['url'];
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER,$data['headers']);
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
curl_setopt($ch, CURLINFO_HEADER_OUT, TRUE);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data['data']));
|
||||
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data['data']);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $data['verify']);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $data['verify']);
|
||||
@@ -145,10 +187,13 @@ exit($header."\r\n\r\n".json_encode($body));
|
||||
# data = json.dumps(pdata)
|
||||
|
||||
data = json.dumps({"url":url,"timeout":timeout,"verify":verify,"headers":self._php_headers(headers),"data":data})
|
||||
if php_version in ['53']:
|
||||
php_version = '/www/server/php/' + php_version + '/bin/php'
|
||||
if php_version.find('/www/server/php') != -1:
|
||||
result = public.ExecShell(php_version + ' ' + tmp_file + " --post='" + data + "'" )[0]
|
||||
else:
|
||||
result = public.request_php(php_version,'/http.php','/dev/shm','POST',{"data":data})
|
||||
if isinstance(result,bytes): result = result.decode('utf-8')
|
||||
|
||||
if os.path.exists(tmp_file): os.remove(tmp_file)
|
||||
r_body,r_headers,r_status_code = self._curl_format(result)
|
||||
@@ -209,7 +254,7 @@ exit($header."\r\n\r\n".json_encode($body));
|
||||
headers_str = self._str_headers(headers)
|
||||
_ssl_verify = ''
|
||||
if not verify: _ssl_verify = ' -k'
|
||||
result = public.ExecShell("{} -sS -i --connect-timeout {} {} {} 2>&1".format(self._curl_bin() + _ssl_verify,timeout,headers_str,url))[0]
|
||||
result = public.ExecShell("{} -sS -i --connect-timeout {} {} {} 2>&1".format(self._curl_bin() + ' ' + str(_ssl_verify),timeout,headers_str,url))[0]
|
||||
r_body,r_headers,r_status_code = self._curl_format(result)
|
||||
return response(r_body,r_status_code,r_headers)
|
||||
|
||||
@@ -220,11 +265,13 @@ exit($header."\r\n\r\n".json_encode($body));
|
||||
raise Exception('No PHP version available!')
|
||||
tmp_file = '/dev/shm/http.php'
|
||||
http_php = '''<?php
|
||||
if(isset($_POST['data'])){
|
||||
error_reporting(E_ERROR);
|
||||
if(isset($_POST['data'])){{
|
||||
$data = json_decode($_POST['data'],1);
|
||||
}else{
|
||||
$data = json_decode(getopt('',array('post:'))['post'],1);
|
||||
}
|
||||
}}else{{
|
||||
$s = getopt('',array('post:'));
|
||||
$data = json_decode($s['post'],1);
|
||||
}}
|
||||
$url = $data['url'];
|
||||
$ch = curl_init();
|
||||
$user_agent = "BT-Panel";
|
||||
@@ -247,10 +294,14 @@ exit($header."\r\n\r\n".json_encode($body));
|
||||
?>'''
|
||||
public.writeFile(tmp_file,http_php)
|
||||
data = json.dumps({"url":url,"timeout":timeout,"verify":verify,"headers":self._php_headers(headers)})
|
||||
if php_version in ['53']:
|
||||
php_version = '/www/server/php/' + php_version + '/bin/php'
|
||||
if php_version.find('/www/server/php') != -1:
|
||||
result = public.ExecShell(php_version + ' ' + tmp_file + " --post='" + data + "'" )[0]
|
||||
else:
|
||||
result = public.request_php(php_version,'/http.php','/dev/shm','POST',{"data":data})
|
||||
if isinstance(result,bytes): result = result.decode('utf-8')
|
||||
|
||||
if os.path.exists(tmp_file): os.remove(tmp_file)
|
||||
r_body,r_headers,r_status_code = self._curl_format(result)
|
||||
return response(json.loads(r_body).strip(),r_status_code,r_headers)
|
||||
@@ -259,7 +310,8 @@ exit($header."\r\n\r\n".json_encode($body));
|
||||
|
||||
#取可用的PHP版本
|
||||
def _get_php_version(self):
|
||||
php_versions = ['52','53','54','55','56','70','71','72','73','74','80']
|
||||
php_versions = public.get_php_versions()
|
||||
php_versions = sorted(php_versions,reverse=True)
|
||||
php_path = '/www/server/php/{}/sbin/php-fpm'
|
||||
php_sock = '/tmp/php-cgi-{}.sock'
|
||||
for pv in php_versions:
|
||||
@@ -276,9 +328,11 @@ exit($header."\r\n\r\n".json_encode($body));
|
||||
#取CURL路径
|
||||
def _curl_bin(self):
|
||||
c_bin = ['/usr/local/curl2/bin/curl','/usr/local/curl/bin/curl','/usr/local/bin/curl','/usr/bin/curl']
|
||||
curl_bin = 'curl'
|
||||
for cb in c_bin:
|
||||
if os.path.exists(cb): curl_bin = cb
|
||||
if os.path.exists(cb): return cb
|
||||
return 'curl'
|
||||
return curl_bin
|
||||
|
||||
#格式化CURL响应头
|
||||
def _curl_format(self,req):
|
||||
@@ -396,7 +450,7 @@ class response:
|
||||
return self.text
|
||||
|
||||
DEFAULT_HEADERS = {"Content-type":"application/x-www-form-urlencoded","User-Agent":"BT-Panel"}
|
||||
s_types = ['python','php','curl']
|
||||
s_types = ['python','php','curl','src']
|
||||
DEFAULT_TYPE = 'python'
|
||||
__version__ = 1.0
|
||||
|
||||
|
||||
@@ -48,6 +48,19 @@ def control_init():
|
||||
if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'sites','%project_config%')).count():
|
||||
public.M('sites').execute("alter TABLE sites add project_config STRING DEFAULT '{}'",())
|
||||
|
||||
if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'backup','%ps%')).count():
|
||||
public.M('backup').execute("alter TABLE backup add ps STRING DEFAULT 'No'",())
|
||||
|
||||
if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'databases','%db_type%')).count():
|
||||
public.M('databases').execute("alter TABLE databases add db_type integer DEFAULT '0'",())
|
||||
|
||||
if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'databases','%conn_config%')).count():
|
||||
public.M('databases').execute("alter TABLE databases add conn_config STRING DEFAULT '{}'",())
|
||||
|
||||
if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'databases','%sid%')).count():
|
||||
public.M('databases').execute("alter TABLE databases add sid integer DEFAULT 0",())
|
||||
|
||||
|
||||
sql = db.Sql()
|
||||
if not sql.table('sqlite_master').where('type=? AND name=?', ('table', 'site_types')).count():
|
||||
csql = '''CREATE TABLE IF NOT EXISTS `site_types` (
|
||||
@@ -94,6 +107,18 @@ def control_init():
|
||||
`logout_time` INTEGER,
|
||||
`expire` INTEGER,
|
||||
`addtime` INTEGER
|
||||
)'''
|
||||
sql.execute(csql,())
|
||||
|
||||
if not sql.table('sqlite_master').where('type=? AND name=?', ('table', 'database_servers')).count():
|
||||
csql = '''CREATE TABLE IF NOT EXISTS `database_servers` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`db_host` REAL,
|
||||
`db_port` REAL,
|
||||
`db_user` INTEGER,
|
||||
`db_password` INTEGER,
|
||||
`ps` REAL,
|
||||
`addtime` INTEGER
|
||||
)'''
|
||||
sql.execute(csql,())
|
||||
|
||||
@@ -161,10 +186,19 @@ def control_init():
|
||||
public.ExecShell("rm -rf /www/server/panel/adminer")
|
||||
if os.path.exists('/dev/shm/session.db'):
|
||||
os.remove('/dev/shm/session.db')
|
||||
|
||||
node_service_bin = '/usr/bin/nodejs-service'
|
||||
node_service_src = '/www/server/panel/script/nodejs-service.py'
|
||||
if os.path.exists(node_service_src): public.ExecShell("chmod 700 " + node_service_src)
|
||||
if not os.path.exists(node_service_bin):
|
||||
if os.path.exists(node_service_src):
|
||||
public.ExecShell("ln -sf {} {}".format(node_service_src,node_service_bin))
|
||||
|
||||
#disable_putenv('putenv')
|
||||
#clean_session()
|
||||
#set_crond()
|
||||
test_ping()
|
||||
set_wp_cache_dir()
|
||||
clean_max_log('/www/server/panel/plugin/rsync/lsyncd.log')
|
||||
clean_max_log('/var/log/rsyncd.log',1024*1024*10)
|
||||
clean_max_log('/root/.pm2/pm2.log',1024*1024*20)
|
||||
@@ -182,7 +216,12 @@ def control_init():
|
||||
update_py37()
|
||||
run_script()
|
||||
set_php_cli_env()
|
||||
check_enable_php()
|
||||
|
||||
def set_wp_cache_dir():
|
||||
import one_key_wp
|
||||
one_key_wp.fast_cgi().set_nginx_conf()
|
||||
public.ExecShell("/etc/init.d/nginx restart")
|
||||
|
||||
def set_php_cli_env():
|
||||
'''
|
||||
@@ -209,7 +248,7 @@ def set_php_cli_env():
|
||||
|
||||
|
||||
# 设置所有已安装的PHP版本环境变量和别名
|
||||
php_versions_list = ['52','53','54','55','56','70','71','72','73','74','80','81','82','83','84','90','91']
|
||||
php_versions_list = public.get_php_versions()
|
||||
for php_version in php_versions_list:
|
||||
php_ini = "{}/{}/etc/php.ini".format(php_path,php_version)
|
||||
php_cli_ini = "{}/{}/etc/php-cli.ini".format(php_path,php_version)
|
||||
@@ -244,6 +283,30 @@ def set_php_cli_env():
|
||||
public.writeFile(bashrc,bashrc_body)
|
||||
|
||||
|
||||
def check_enable_php():
|
||||
'''
|
||||
@name 检查nginx下的php配置文件
|
||||
'''
|
||||
php_versions = public.get_php_versions()
|
||||
ngx_php_conf = public.get_setup_path() + '/nginx/conf/enable-php-00.conf'
|
||||
public.writeFile(ngx_php_conf,'')
|
||||
for php_v in php_versions:
|
||||
ngx_php_conf = public.get_setup_path() + '/nginx/conf/enable-php-{}.conf'.format(php_v)
|
||||
if os.path.exists(ngx_php_conf): continue
|
||||
enable_conf = '''
|
||||
location ~ [^/]\.php(/|$)
|
||||
{{
|
||||
try_files $uri =404;
|
||||
fastcgi_pass unix:/tmp/php-cgi-{}.sock;
|
||||
fastcgi_index index.php;
|
||||
include fastcgi.conf;
|
||||
include pathinfo.conf;
|
||||
}}
|
||||
'''.format(php_v)
|
||||
public.writeFile(ngx_php_conf,enable_conf)
|
||||
|
||||
|
||||
|
||||
def write_run_script_log(_log,rn='\n'):
|
||||
_log_file = '/www/server/panel/logs/run_script.log'
|
||||
public.writeFile(_log_file,_log + rn,'a+')
|
||||
@@ -319,7 +382,6 @@ def files_set_mode():
|
||||
["/www/server/stop","","root",755,True],
|
||||
["/www/server/redis","","redis",700,True],
|
||||
["/www/server/redis/redis.conf","","redis",600,False],
|
||||
["/www/Recycle_bin","","root",600,True],
|
||||
["/www/server/panel/class","","root",600,True],
|
||||
["/www/server/panel/data","","root",600,True],
|
||||
["/www/server/panel/plugin","","root",600,False],
|
||||
@@ -345,6 +407,10 @@ def files_set_mode():
|
||||
["/www/server/coll","","root",700,True]
|
||||
]
|
||||
|
||||
recycle_list = public.get_recycle_bin_list()
|
||||
for recycle_path in recycle_list:
|
||||
m_paths.append([recycle_path,'','root',600,True])
|
||||
|
||||
for m in m_paths:
|
||||
if not os.path.exists(m[0]): continue
|
||||
path = m[0] + m[1]
|
||||
@@ -409,7 +475,7 @@ def set_pma_access():
|
||||
|
||||
#尝试升级到独立环境
|
||||
def update_py37():
|
||||
pyenv='/www/server/panel/pyenv/bin/python'
|
||||
pyenv='/www/server/panel/pyenv/bin/python3'
|
||||
pyenv_exists='/www/server/panel/data/pyenv_exists.pl'
|
||||
if os.path.exists(pyenv) or os.path.exists(pyenv_exists): return False
|
||||
download_url = public.get_url()
|
||||
@@ -552,7 +618,7 @@ def disable_putenv(fun_name):
|
||||
try:
|
||||
is_set_disable = '/www/server/panel/data/disable_%s' % fun_name
|
||||
if os.path.exists(is_set_disable): return True
|
||||
php_vs = ('52','53','54','55','56','70','71','72','73','74')
|
||||
php_vs = public.get_php_versions()
|
||||
php_ini = "/www/server/php/{0}/etc/php.ini"
|
||||
rep = "disable_functions\s*=\s*.*"
|
||||
for pv in php_vs:
|
||||
@@ -619,3 +685,8 @@ def clean_session():
|
||||
except:return False
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
control_init()
|
||||
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import json
|
||||
import time
|
||||
import datetime
|
||||
import re
|
||||
import sqlite3
|
||||
|
||||
import public
|
||||
|
||||
@@ -40,6 +41,43 @@ class Monitor:
|
||||
return sites
|
||||
|
||||
def _statuscode_distribute_site(self, site_name):
|
||||
|
||||
try:
|
||||
day_401 = 0
|
||||
day_500 = 0
|
||||
day_502 = 0
|
||||
day_503 = 0
|
||||
conn = None
|
||||
ts = None
|
||||
start_date, end_date = self.get_time_interval(time.localtime())
|
||||
select_sql = "select time/100 as time1, sum(status_401), sum(status_500), sum(status_502), sum(status_503) from request_stat where time between {} and {}"\
|
||||
.format(start_date, end_date)
|
||||
|
||||
db_path = os.path.join("/www/server/total/", "logs/{}/logs.db".format(site_name))
|
||||
if os.path.isfile(db_path):
|
||||
conn = sqlite3.connect(db_path)
|
||||
ts = conn.cursor()
|
||||
ts.execute(select_sql)
|
||||
results = ts.fetchall()
|
||||
|
||||
if type(results) == list:
|
||||
for result in results:
|
||||
time_key = str(result[0])
|
||||
day_401 = result[1]
|
||||
day_500 = result[2]
|
||||
day_502 = result[3]
|
||||
day_503 = result[4]
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
if ts:
|
||||
ts.close()
|
||||
if conn:
|
||||
conn.close()
|
||||
|
||||
return day_401, day_500, day_502, day_503
|
||||
|
||||
def _statuscode_distribute_site_old(self, site_name):
|
||||
today = time.strftime('%Y-%m-%d', time.localtime())
|
||||
path = '/www/server/total/total/' + site_name + '/request/' + today + '.json'
|
||||
|
||||
@@ -52,10 +90,10 @@ class Monitor:
|
||||
|
||||
for c in spdata.values():
|
||||
for d in c:
|
||||
if '401' == d: day_401 += c['401']
|
||||
if '500' == d: day_500 += c['500']
|
||||
if '502' == d: day_502 += c['502']
|
||||
if '503' == d: day_503 += c['503']
|
||||
if '401' == d: day_401 += c['401'] or 0
|
||||
if '500' == d: day_500 += c['500'] or 0
|
||||
if '502' == d: day_502 += c['502'] or 0
|
||||
if '503' == d: day_503 += c['503'] or 0
|
||||
|
||||
return day_401, day_500, day_502, day_503
|
||||
|
||||
@@ -66,6 +104,10 @@ class Monitor:
|
||||
for site in sites:
|
||||
site_name = site['name']
|
||||
day_401, day_500, day_502, day_503 = self._statuscode_distribute_site(site_name)
|
||||
day_401 = day_401 or 0
|
||||
day_500 = day_500 or 0
|
||||
day_502 = day_502 or 0
|
||||
day_503 = day_503 or 0
|
||||
count_401 += day_401
|
||||
count_500 += day_500
|
||||
count_502 += day_502
|
||||
@@ -177,8 +219,45 @@ class Monitor:
|
||||
data.update(statuscode_distribute)
|
||||
return data
|
||||
|
||||
# 获取蜘蛛数量分布
|
||||
def get_spider(self, args):
|
||||
request_data = {}
|
||||
sites = public.M('sites').field('name').order("addtime").select();
|
||||
for site_info in sites:
|
||||
ts = None
|
||||
conn = None
|
||||
try:
|
||||
site_name = site_info["name"]
|
||||
start_date, end_date = self.get_time_interval(time.localtime())
|
||||
select_sql = "select time, spider from request_stat where time between {} and {}"\
|
||||
.format(start_date, end_date)
|
||||
|
||||
db_path = os.path.join("/www/server/total/", "logs/{}/logs.db".format(site_name))
|
||||
if not os.path.isfile(db_path): continue
|
||||
conn = sqlite3.connect(db_path)
|
||||
ts = conn.cursor()
|
||||
ts.execute(select_sql)
|
||||
results = ts.fetchall()
|
||||
|
||||
if type(results) == list:
|
||||
for result in results:
|
||||
time_key = str(result[0])
|
||||
hour = time_key[len(time_key)-2:]
|
||||
value = result[1]
|
||||
if hour not in request_data:
|
||||
request_data[hour] = value
|
||||
else:
|
||||
request_data[hour] += value
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
if ts:
|
||||
ts.close()
|
||||
if conn:
|
||||
conn.close()
|
||||
return request_data
|
||||
|
||||
# 获取蜘蛛数量分布
|
||||
def get_spider_old(self, args):
|
||||
today = time.strftime('%Y-%m-%d', time.localtime())
|
||||
sites = self._get_site_list()
|
||||
|
||||
@@ -210,8 +289,53 @@ class Monitor:
|
||||
|
||||
return {'load_five': load_five, 'cpu_count': cpu_count, 'up_flow': up_flow}
|
||||
|
||||
# 取每小时的请求数
|
||||
def get_time_interval(self, local_time):
|
||||
start = None
|
||||
end = None
|
||||
time_key_format = "%Y%m%d00"
|
||||
start = int(time.strftime(time_key_format, local_time))
|
||||
time_key_format = "%Y%m%d23"
|
||||
end = int(time.strftime(time_key_format, local_time))
|
||||
return start, end
|
||||
|
||||
def get_request_count_by_hour(self, args):
|
||||
# 获取站点每小时的请求数据
|
||||
request_data = {}
|
||||
import sqlite3
|
||||
sites = public.M('sites').field('name').order("addtime").select();
|
||||
for site_info in sites:
|
||||
ts = None
|
||||
conn = None
|
||||
try:
|
||||
site_name = site_info["name"]
|
||||
start_date, end_date = self.get_time_interval(time.localtime())
|
||||
select_sql = "select time, req from request_stat where time between {} and {}"\
|
||||
.format(start_date, end_date)
|
||||
db_path = os.path.join("/www/server/total/", "logs/{}/logs.db".format(site_name))
|
||||
if not os.path.isfile(db_path): continue
|
||||
conn = sqlite3.connect(db_path)
|
||||
ts = conn.cursor()
|
||||
ts.execute(select_sql)
|
||||
results = ts.fetchall()
|
||||
if type(results) == list:
|
||||
for result in results:
|
||||
time_key = str(result[0])
|
||||
hour = time_key[len(time_key)-2:]
|
||||
value = result[1]
|
||||
if hour not in request_data:
|
||||
request_data[hour] = value
|
||||
else:
|
||||
request_data[hour] += value
|
||||
except: pass
|
||||
finally:
|
||||
if ts:
|
||||
ts.close()
|
||||
if conn:
|
||||
conn.close()
|
||||
return request_data
|
||||
|
||||
# 取每小时的请求数
|
||||
def get_request_count_by_hour_old(self, args):
|
||||
today = time.strftime('%Y-%m-%d', time.localtime())
|
||||
|
||||
request_data = {}
|
||||
|
||||
@@ -23,29 +23,29 @@ class nginx:
|
||||
proxycontent = public.readFile(self.proxyfile)
|
||||
for i in [[ngconfcontent,self.nginxconf],[proxycontent,self.proxyfile]]:
|
||||
if not i[0]:
|
||||
return public.returnMsg(False,"Can not find nginx config file [ {} ]".format(i[1]))
|
||||
return public.return_msg_gettext(False,"Can not find nginx config file [ {} ]".format(i[1]))
|
||||
unitrep = "[kmgKMG]"
|
||||
conflist = []
|
||||
ps = ["%s,%s" % (public.GetMsg("WORKER_PROCESSES"),public.GetMsg("WORKER_PROCESSES_AUTO")),
|
||||
public.GetMsg("WORKER_CONNECTIONS"),
|
||||
public.GetMsg("CONNECT_TIMEOUT_TIME"),
|
||||
public.GetMsg("NGINX_ZIP"),
|
||||
public.GetMsg("NGINX_ZIP_MIN"),
|
||||
public.GetMsg("ZIP_COMP_LEVEL"),
|
||||
public.GetMsg("UPLOAD_MAX_FILE"),
|
||||
public.GetMsg("SERVER_NAME_HASH"),
|
||||
public.GetMsg("CLIENT_HEADER_BUFF")]
|
||||
ps = ["%s,%s" % (public.get_msg_gettext('Worker processes'),public.get_msg_gettext('Auto means automatic')),
|
||||
public.get_msg_gettext('Worker connections'),
|
||||
public.get_msg_gettext('Connection timeout'),
|
||||
public.get_msg_gettext('Whether to enable compressed transmission'),
|
||||
public.get_msg_gettext('Minimum file to compress'),
|
||||
public.get_msg_gettext('Compression level'),
|
||||
public.get_msg_gettext('Maximum file to upload'),
|
||||
public.get_msg_gettext('Hash table size of server name'),
|
||||
public.get_msg_gettext('Client header buffer size')]
|
||||
gets = ["worker_processes","worker_connections","keepalive_timeout","gzip","gzip_min_length","gzip_comp_level","client_max_body_size","server_names_hash_bucket_size","client_header_buffer_size"]
|
||||
n = 0
|
||||
for i in gets:
|
||||
rep = "(%s)\s+(\w+)" % i
|
||||
k = re.search(rep, ngconfcontent)
|
||||
if not k:
|
||||
return public.returnMsg(False,"Get key {} False".format(k))
|
||||
return public.return_msg_gettext(False,"Get key {} False".format(k))
|
||||
k = k.group(1)
|
||||
v = re.search(rep, ngconfcontent)
|
||||
if not v:
|
||||
return public.returnMsg(False,"Get value {} False".format(v))
|
||||
return public.return_msg_gettext(False,"Get value {} False".format(v))
|
||||
v = v.group(2)
|
||||
if re.search(unitrep,v):
|
||||
u = str.upper(v[-1])
|
||||
@@ -60,18 +60,18 @@ class nginx:
|
||||
kv = {"name":k,"value":v,"unit":u,"ps":psstr}
|
||||
conflist.append(kv)
|
||||
n += 1
|
||||
ps = [public.GetMsg("CLIENT_BODY_BUFF")]
|
||||
ps = [public.get_msg_gettext('Client body buffer')]
|
||||
gets = ["client_body_buffer_size"]
|
||||
n = 0
|
||||
for i in gets:
|
||||
rep = "(%s)\s+(\w+)" % i
|
||||
k = re.search(rep, proxycontent)
|
||||
if not k:
|
||||
return public.returnMsg(False,"Get key {} False".format(k))
|
||||
return public.return_msg_gettext(False,"Get key {} False".format(k))
|
||||
k=k.group(1)
|
||||
v = re.search(rep, proxycontent)
|
||||
if not v:
|
||||
return public.returnMsg(False,"Get value {} False".format(v))
|
||||
return public.return_msg_gettext(False,"Get value {} False".format(v))
|
||||
v = v.group(2)
|
||||
if re.search(unitrep, v):
|
||||
u = str.upper(v[-1])
|
||||
@@ -86,7 +86,6 @@ class nginx:
|
||||
kv = {"name":k, "value":v, "unit":u,"ps":psstr}
|
||||
conflist.append(kv)
|
||||
n+=1
|
||||
print(conflist)
|
||||
return conflist
|
||||
|
||||
def SetNginxValue(self,get):
|
||||
@@ -109,10 +108,10 @@ class nginx:
|
||||
rep = "%s\s+[^kKmMgG\;\n]+" % c["name"]
|
||||
if c["name"] == "worker_processes" or c["name"] == "gzip":
|
||||
if not re.search("auto|on|off|\d+", c["value"]):
|
||||
return public.returnMsg(False, 'INIT_ARGS_ERR')
|
||||
return public.return_msg_gettext(False, 'Parameter ERROR!')
|
||||
else:
|
||||
if not re.search("\d+", c["value"]):
|
||||
return public.returnMsg(False, 'INIT_ARGS_ERR')
|
||||
return public.return_msg_gettext(False, 'Parameter ERROR!')
|
||||
if re.search(rep,ngconfcontent):
|
||||
newconf = "%s %s" % (c["name"],c["value"])
|
||||
ngconfcontent = re.sub(rep,newconf,ngconfcontent)
|
||||
@@ -125,10 +124,10 @@ class nginx:
|
||||
if (isError != True):
|
||||
shutil.copyfile('/tmp/ng_file_bk.conf', self.nginxconf)
|
||||
shutil.copyfile('/tmp/proxyfile_bk.conf', self.proxyfile)
|
||||
return public.returnMsg(False, 'ERROR: <br><a style="color:red;">' + isError.replace("\n",
|
||||
return public.return_msg_gettext(False, 'ERROR: <br><a style="color:red;">' + isError.replace("\n",
|
||||
'<br>') + '</a>')
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True, 'SET_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
|
||||
def add_nginx_access_log_format(self,args):
|
||||
'''
|
||||
@@ -151,14 +150,14 @@ class nginx:
|
||||
self.del_nginx_access_log_format(args)
|
||||
conf = public.readFile(self.nginxconf)
|
||||
if not conf:
|
||||
return public.returnMsg(False,'NGINX_CONF_NOT_EXISTS')
|
||||
return public.return_msg_gettext(False,'Nginx configuration file does not exist!')
|
||||
reg = 'http(\n|\s)+{'
|
||||
conf = re.sub(reg,'http\n\t{'+data,conf)
|
||||
public.writeFile(self.nginxconf,conf)
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True, 'SET_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
except:
|
||||
return public.returnMsg(False, str(public.get_error_info()))
|
||||
return public.return_msg_gettext(False, str(public.get_error_info()))
|
||||
|
||||
def del_nginx_access_log_format(self,args):
|
||||
'''
|
||||
@@ -169,13 +168,13 @@ class nginx:
|
||||
log_format_name = args.log_format_name
|
||||
conf = public.readFile(self.nginxconf)
|
||||
if not conf:
|
||||
return public.returnMsg(False, 'NGINX_CONF_NOT_EXISTS')
|
||||
return public.return_msg_gettext(False, 'Nginx configuration file does not exist!')
|
||||
reg = '\s*#LOG_FORMAT_BEGIN_{n}(\n|.)+#LOG_FORMAT_END_{n}\n?'.format(n=args.log_format_name)
|
||||
conf = re.sub(reg,'',conf)
|
||||
self._del_format_log_of_website(log_format_name)
|
||||
public.writeFile(self.nginxconf,conf)
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True, 'SET_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
|
||||
def del_all_log_format(self,args):
|
||||
all_format = self.get_nginx_access_log_format(args)
|
||||
@@ -223,7 +222,7 @@ class nginx:
|
||||
reg = "#LOG_FORMAT_BEGIN.*"
|
||||
conf = public.readFile(self.nginxconf)
|
||||
if not conf:
|
||||
return public.returnMsg(False, 'NGINX_CONF_NOT_EXISTS')
|
||||
return public.return_msg_gettext(False, 'Nginx configuration file does not exist!')
|
||||
data = re.findall(reg,conf)
|
||||
format_name = [i.split('LOG_FORMAT_BEGIN_')[-1] for i in data]
|
||||
format_log = {}
|
||||
@@ -236,7 +235,7 @@ class nginx:
|
||||
format_log[i] = self._process_log_format(tmp)
|
||||
return format_log
|
||||
except:
|
||||
return public.returnMsg(False,public.get_error_info())
|
||||
return public.return_msg_gettext(False,public.get_error_info())
|
||||
|
||||
def set_format_log_to_website(self,args):
|
||||
'''
|
||||
@@ -254,7 +253,7 @@ class nginx:
|
||||
website_conf_file = '/www/server/panel/vhost/nginx/{}.conf'.format(site['name'])
|
||||
conf = public.readFile(website_conf_file)
|
||||
if not conf:
|
||||
return public.returnMsg(False, 'NGINX_CONF_NOT_EXISTS')
|
||||
return public.return_msg_gettext(False, 'Nginx configuration file does not exist!')
|
||||
format_exist_reg = '(access_log\s+/www.*\.log).*;'
|
||||
access_log = self.get_nginx_access_log(conf)
|
||||
if not access_log:
|
||||
@@ -267,9 +266,9 @@ class nginx:
|
||||
continue
|
||||
conf = re.sub(format_exist_reg,access_log,conf)
|
||||
public.writeFile(website_conf_file,conf)
|
||||
return public.returnMsg(True, 'SET_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
except:
|
||||
return public.returnMsg(False, str(public.get_error_info()))
|
||||
return public.return_msg_gettext(False, str(public.get_error_info()))
|
||||
|
||||
def get_nginx_access_log(self,nginx_conf):
|
||||
try:
|
||||
|
||||
@@ -51,7 +51,7 @@ class ols:
|
||||
conf = conf + '\n{} {}'.format(k,data[k])
|
||||
public.writeFile(self._main_conf_path,conf)
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True,"Setup Successfully")
|
||||
return public.return_msg_gettext(True,"Setup Successfully!")
|
||||
|
||||
# 获取站点静态文件缓存配置
|
||||
def get_static_cache(self,get):
|
||||
@@ -101,7 +101,7 @@ class ols:
|
||||
conf = conf.replace(old_cache,new_cache)
|
||||
public.writeFile(self._detail_conf_path.format(sitename),conf)
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True,'Setup Successfully')
|
||||
return public.return_msg_gettext(True,'Setup Successfully!')
|
||||
except Exception as e:
|
||||
return e
|
||||
|
||||
@@ -180,14 +180,14 @@ RewriteRule (.*\.php)?$ - [E=Cache-Control:private]
|
||||
f.write(conf)
|
||||
f.close()
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True,'Open successfully')
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
else:
|
||||
bt_conf_rep = '#.*BTLSCACHE_BEGIN(.|\n)+BTLSCACHE_END#*\n'
|
||||
conf = re.sub(bt_conf_rep,'',conf)
|
||||
print(conf)
|
||||
public.writeFile(file,conf)
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True,'Close successfully')
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
def set_private_cache(self,get):
|
||||
"""
|
||||
@@ -215,7 +215,7 @@ RewriteRule (.*\.php)?$ - [E=Cache-Control:private]
|
||||
conf = re.sub(bt_conf_rep,bt_conf,conf)
|
||||
public.writeFile(file_name,conf)
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True,'Setup Successfully')
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
def _get_site_domain(self):
|
||||
site = []
|
||||
|
||||
@@ -12,14 +12,14 @@ class Page():
|
||||
#--------------------------
|
||||
# 分页类 - JS回调版
|
||||
#--------------------------
|
||||
__PREV = public.GetMsg("PAGE")["PREV"]
|
||||
__NEXT = public.GetMsg("PAGE")["NEXT"]
|
||||
__START = public.GetMsg("PAGE")["START"]
|
||||
__END = public.GetMsg("PAGE")["END"]
|
||||
__COUNT_START = public.GetMsg("PAGE")["COUNT_START"]
|
||||
__COUNT_END = public.GetMsg("PAGE")["COUNT_END"]
|
||||
__FO = public.GetMsg("PAGE")["FO"]
|
||||
__LINE = public.GetMsg("PAGE")["LINE"]
|
||||
__PREV = public.get_msg_gettext('Prev')
|
||||
__NEXT = public.get_msg_gettext('Next')
|
||||
__START = public.get_msg_gettext('Start')
|
||||
__END = public.get_msg_gettext('Last')
|
||||
__COUNT_START = public.get_msg_gettext('Total')
|
||||
__COUNT_END = ''
|
||||
__FO = public.get_msg_gettext('From')
|
||||
__LINE = ''
|
||||
__LIST_NUM = 4
|
||||
SHIFT = None #偏移量
|
||||
ROW = None #每页行数
|
||||
@@ -30,18 +30,19 @@ class Page():
|
||||
__RTURN_JS = False #是否返回JS回调
|
||||
__START_NUM = None #起始行
|
||||
__END_NUM = None #结束行
|
||||
|
||||
|
||||
def __init__(self):
|
||||
tmp = public.GetMsg('PAGE');
|
||||
if tmp:
|
||||
self.__PREV = tmp['PREV'];
|
||||
self.__NEXT = tmp['NEXT'];
|
||||
self.__START = tmp['START'];
|
||||
self.__END = tmp['END'];
|
||||
self.__COUNT_START = tmp['COUNT_START'];
|
||||
self.__COUNT_END = tmp['COUNT_END'];
|
||||
self.__FO = tmp['FO'];
|
||||
self.__LINE = tmp['LINE'];
|
||||
pass
|
||||
# tmp = public.get_msg_gettext('Depends on the following software, please install [{1}] first')
|
||||
# if tmp:
|
||||
# self.__PREV = tmp['Prev']
|
||||
# self.__NEXT = tmp['Next']
|
||||
# self.__START = tmp['Start']
|
||||
# self.__END = tmp['Last']
|
||||
# self.__COUNT_START = tmp['Total']
|
||||
# self.__COUNT_END = tmp['']
|
||||
# self.__FO = tmp['From']
|
||||
# self.__LINE = tmp['']
|
||||
|
||||
def GetPage(self,pageInfo,limit = '1,2,3,4,5,6,7,8'):
|
||||
# 取分页信息
|
||||
@@ -56,9 +57,9 @@ class Page():
|
||||
self.__COUNT_PAGE = self.__GetCountPage()
|
||||
self.__URI = self.__SetUri(pageInfo['uri'])
|
||||
self.SHIFT = self.__START_NUM - 1
|
||||
|
||||
|
||||
keys = limit.split(',')
|
||||
|
||||
|
||||
pages = {}
|
||||
#起始页
|
||||
pages['1'] = self.__GetStart()
|
||||
@@ -70,23 +71,22 @@ class Page():
|
||||
pages['4'] = self.__GetNext()
|
||||
#尾页
|
||||
pages['5'] = self.__GetEnd()
|
||||
|
||||
|
||||
#当前显示页与总页数
|
||||
pages['6'] = "<span class='Pnumber'>" + str(self.__C_PAGE) + "/" + str(self.__COUNT_PAGE) + "</span>"
|
||||
#本页显示开始与结束行
|
||||
pages['7'] = "<span class='Pline'>" + self.__FO + str(self.__START_NUM) + "-" + str(self.__END_NUM) + self.__LINE + "</span>"
|
||||
#行数
|
||||
pages['8'] = "<span class='Pcount'>" + self.__COUNT_START + str(self.__COUNT_ROW) + self.__COUNT_END + "</span>"
|
||||
|
||||
pages['8'] = "<span class='Pcount'>" + self.__COUNT_START +' '+ str(self.__COUNT_ROW) + self.__COUNT_END + "</span>"
|
||||
#构造返回数据
|
||||
retuls = '<div>';
|
||||
for value in keys:
|
||||
retuls += pages[value]
|
||||
retuls +='</div>';
|
||||
|
||||
|
||||
#返回分页数据
|
||||
return retuls;
|
||||
|
||||
|
||||
def __GetEnd(self):
|
||||
#构造尾页
|
||||
endStr = ""
|
||||
@@ -98,7 +98,7 @@ class Page():
|
||||
else:
|
||||
endStr = "<a class='Pend' onclick='" + self.__RTURN_JS + "(" + str(self.__COUNT_PAGE) + ")'>" + self.__END + "</a>"
|
||||
return endStr
|
||||
|
||||
|
||||
def __GetNext(self):
|
||||
#构造下一页
|
||||
nextStr = ""
|
||||
@@ -107,11 +107,11 @@ class Page():
|
||||
else:
|
||||
if self.__RTURN_JS == "":
|
||||
nextStr = "<a class='Pnext' href='" + self.__URI + "p=" + str(self.__C_PAGE + 1) + "'>" + self.__NEXT + "</a>"
|
||||
else:
|
||||
else:
|
||||
nextStr = "<a class='Pnext' onclick='" + self.__RTURN_JS + "(" + str(self.__C_PAGE + 1) + ")'>" + self.__NEXT + "</a>"
|
||||
|
||||
|
||||
return nextStr
|
||||
|
||||
|
||||
def __GetPages(self):
|
||||
#构造分页
|
||||
pages = ''
|
||||
@@ -130,11 +130,11 @@ class Page():
|
||||
pages += "<a class='Pnum' href='" + self.__URI + "p=" + str(page) + "'>" + str(page) + "</a>"
|
||||
else:
|
||||
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + "(" + str(page) + ")'>" + str(page) + "</a>"
|
||||
|
||||
|
||||
#当前页
|
||||
if self.__C_PAGE > 0:
|
||||
pages += "<span class='Pcurrent'>" + str(self.__C_PAGE) + "</span>"
|
||||
|
||||
|
||||
#当前页之后
|
||||
if self.__C_PAGE <= self.__LIST_NUM:
|
||||
num = self.__LIST_NUM + (self.__LIST_NUM - self.__C_PAGE) + 1
|
||||
@@ -148,11 +148,11 @@ class Page():
|
||||
break;
|
||||
if self.__RTURN_JS == "":
|
||||
pages += "<a class='Pnum' href='" + self.__URI + "p=" + str(page) + "'>" + str(page) + "</a>"
|
||||
else:
|
||||
else:
|
||||
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + "(" + str(page) + ")'>" + str(page) + "</a>"
|
||||
|
||||
|
||||
return pages;
|
||||
|
||||
|
||||
def __GetPrev(self):
|
||||
#构造上一页
|
||||
startStr = ''
|
||||
@@ -161,10 +161,10 @@ class Page():
|
||||
else:
|
||||
if self.__RTURN_JS == "":
|
||||
startStr = "<a class='Ppren' href='" + self.__URI + "p=" + str(self.__C_PAGE - 1) + "'>" + self.__PREV + "</a>"
|
||||
else:
|
||||
else:
|
||||
startStr = "<a class='Ppren' onclick='" + self.__RTURN_JS + "(" + str(self.__C_PAGE - 1) + ")'>" + self.__PREV + "</a>"
|
||||
return startStr
|
||||
|
||||
|
||||
def __GetStart(self):
|
||||
#构造起始分页
|
||||
startStr = ''
|
||||
@@ -176,27 +176,27 @@ class Page():
|
||||
else:
|
||||
startStr = "<a class='Pstart' onclick='" + self.__RTURN_JS + "(1)'>" + self.__START + "</a>"
|
||||
return startStr;
|
||||
|
||||
|
||||
def __GetCpage(self,p):
|
||||
#取当前页
|
||||
if p:
|
||||
return p
|
||||
return 1
|
||||
|
||||
|
||||
def __StartRow(self):
|
||||
#从多少行开始
|
||||
return (self.__C_PAGE - 1) * self.ROW + 1
|
||||
|
||||
|
||||
def __EndRow(self):
|
||||
#从多少行结束
|
||||
if self.ROW > self.__COUNT_ROW:
|
||||
return self.__COUNT_ROW
|
||||
return self.__C_PAGE * self.ROW
|
||||
|
||||
|
||||
def __GetCountPage(self):
|
||||
#取总页数
|
||||
return int(math.ceil(self.__COUNT_ROW / float(self.ROW)))
|
||||
|
||||
|
||||
def __SetUri(self,request_uri):
|
||||
#构造URI
|
||||
try:
|
||||
@@ -207,4 +207,4 @@ class Page():
|
||||
else:
|
||||
if request_uri[-1] != '&': request_uri += '&'
|
||||
return request_uri
|
||||
except: return '';
|
||||
except: return ''
|
||||
|
||||
@@ -33,13 +33,27 @@ class panelApi:
|
||||
|
||||
def login_for_app(self,get):
|
||||
from BTPanel import cache
|
||||
import uuid
|
||||
tid = get.tid
|
||||
if(len(tid) != 12): return public.returnMsg(False,'Invalid login key')
|
||||
if(len(tid) != 32): return public.return_msg_gettext(False,'Invalid login key1')
|
||||
session_id = cache.get(tid)
|
||||
if not session_id: return public.returnMsg(False,'The specified key does not exist or has expired')
|
||||
if(len(session_id) != 64): return public.returnMsg(False,'Invalid login key')
|
||||
cache.set(session_id,'True',120)
|
||||
return public.returnMsg(True,'Scan code successfully, log in!')
|
||||
if not session_id: return public.return_msg_gettext(False,'The specified key does not exist or has expired1')
|
||||
if(len(session_id) != 64): return public.return_msg_gettext(False,'Invalid login key2')
|
||||
try:
|
||||
if not os.path.exists('/www/server/panel/data/app_login_check.pl'):return public.returnMsg(False,'Invalid login key3')
|
||||
key, init_time, tid2, status = public.readFile('/www/server/panel/data/app_login_check.pl').split(':')
|
||||
if session_id!=key:return public.returnMsg(False,'Invalid login key4')
|
||||
if tid != tid2: return public.returnMsg(False, 'The specified key does not exist or has expired5')
|
||||
if time.time() - float(init_time) > 60:
|
||||
return public.returnMsg(False, 'QR code validity time expired6')
|
||||
cache.set(session_id,public.md5(uuid.UUID(int=uuid.getnode()).hex),120)
|
||||
import uuid
|
||||
data = key + ':' + init_time + ':' + tid2 + ':' + uuid.UUID(int=uuid.getnode()).hex[-12:]
|
||||
public.writeFile("/www/server/panel/data/app_login_check.pl", data)
|
||||
return public.return_msg_gettext(True,'Scan code successfully, log in!')
|
||||
except:
|
||||
os.remove("/www/server/panel/data/app_login_check.pl")
|
||||
return public.return_msg_gettext(False, 'Invalid login key')
|
||||
|
||||
def get_api_config(self):
|
||||
tmp = public.ReadFile(self.save_path)
|
||||
@@ -81,11 +95,11 @@ class panelApi:
|
||||
|
||||
bind = self.get_bind_token(args.bind_token)
|
||||
if bind['token'] != args.bind_token:
|
||||
return 'The current QR code has expired, please refresh the page and rescan the code!'
|
||||
return public.get_msg_gettext('The current QR code has expired, please refresh the page and rescan the code!')
|
||||
|
||||
apps = self.get_apps()
|
||||
if len(apps) >= self.max_bind:
|
||||
return 'This server is bound to a maximum of {} devices, which has reached the limit!'.format(self.max_bind)
|
||||
return public.get_msg_gettext('This server is bound to a maximum of {} devices, which has reached the limit!',(self.max_bind,))
|
||||
|
||||
bind['status'] = 1
|
||||
bind['brand'] = args.client_brand
|
||||
@@ -94,8 +108,8 @@ class panelApi:
|
||||
return 1
|
||||
|
||||
def get_bind_status(self,args):
|
||||
if not public.cache_get("get_bind_status"):
|
||||
public.cache_set("get_bind_status",1,60)
|
||||
if not public.cache_get(public.Md5(os.uname().version)):
|
||||
public.cache_set(public.Md5(os.uname().version),1,60)
|
||||
bind = self.get_bind_token(args.bind_token)
|
||||
return bind
|
||||
|
||||
@@ -133,10 +147,10 @@ class panelApi:
|
||||
def add_bind_app(self,args):
|
||||
bind = self.get_bind_token(args.bind_token)
|
||||
if bind['status'] == 0:
|
||||
return public.returnMsg(False,'Failed verification!')
|
||||
return public.return_msg_gettext(False,'Failed verification!')
|
||||
apps = self.get_apps()
|
||||
if len(apps) >= self.max_bind:
|
||||
return public.returnMsg(False,'A server allows up to {} device bindings!'.format(self.max_bind))
|
||||
return public.return_msg_gettext(False,'A server allows up to {} device bindings!'.format(self.max_bind))
|
||||
|
||||
args.bind_app = args.bind_token
|
||||
self.remove_bind_app(args)
|
||||
@@ -144,7 +158,7 @@ class panelApi:
|
||||
data['apps'].append(bind)
|
||||
self.save_api_config(data)
|
||||
self.remove_bind_token(args.bind_token)
|
||||
return public.returnMsg(True,'Bind successfully!')
|
||||
return public.return_msg_gettext(True,'Bind successfully!')
|
||||
|
||||
def remove_bind_token(self,bind_token):
|
||||
data = self.get_api_config()
|
||||
@@ -168,7 +182,7 @@ class panelApi:
|
||||
s_file = '/dev/shm/{}'.format(args.bind_app)
|
||||
if os.path.exists(s_file):
|
||||
os.remove(s_file)
|
||||
return public.returnMsg(True,'successfully deleted!')
|
||||
return public.return_msg_gettext(True,'Successfully deleted!')
|
||||
|
||||
def get_bind_token(self,token = None):
|
||||
data = self.get_api_config()
|
||||
@@ -203,13 +217,13 @@ class panelApi:
|
||||
|
||||
|
||||
def set_token(self,get):
|
||||
if 'request_token' in get: return public.returnMsg(False,'Cannot configure API through API interface')
|
||||
if 'request_token' in get: return public.return_msg_gettext(False,'Cannot configure API through API interface')
|
||||
data = self.get_api_config()
|
||||
if get.t_type == '1':
|
||||
token = public.GetRandomString(32)
|
||||
data['token'] = public.md5(token)
|
||||
data['token_crypt'] = public.en_crypt(data['token'],token).decode('utf-8')
|
||||
public.WriteLog('SET_API','Regenerate API-Token')
|
||||
public.write_log_gettext('API configuration','Regenerate API-Token')
|
||||
elif get.t_type == '2':
|
||||
data['open'] = not data['open']
|
||||
stats = {True:'Open',False:'Close'}
|
||||
@@ -217,19 +231,19 @@ class panelApi:
|
||||
token = public.GetRandomString(32)
|
||||
data['token'] = public.md5(token)
|
||||
data['token_crypt'] = public.en_crypt(data['token'],token).decode('utf-8')
|
||||
public.WriteLog('SET_API','%s API interface' % stats[data['open']])
|
||||
public.write_log_gettext('API configuration','{} API interface',(stats[data['open']],))
|
||||
token = stats[data['open']] + ' success!'
|
||||
elif get.t_type == '3':
|
||||
data['limit_addr'] = get.limit_addr.split('\n')
|
||||
public.WriteLog('SET_API','Change IP limit to [%s]' % get.limit_addr)
|
||||
public.write_log_gettext('API configuration','Change IP limit to [{}]',(get.limit_addr,))
|
||||
token ='Saved successfully!'
|
||||
self.save_api_config(data)
|
||||
return public.returnMsg(True,token)
|
||||
return public.return_msg_gettext(True,token)
|
||||
|
||||
def get_tmp_token(self,get):
|
||||
if not 'request_token' in get: return public.returnMsg(False,'Temporary keys can only be obtained through the API interface')
|
||||
if not 'request_token' in get: return public.return_msg_gettext(False,'Temporary keys can only be obtained through the API interface')
|
||||
data = self.get_api_config()
|
||||
data['tmp_token'] = public.GetRandomString(64)
|
||||
data['tmp_time'] = time.time()
|
||||
self.save_api_config(data)
|
||||
return public.returnMsg(True,data['tmp_token'])
|
||||
return public.return_msg_gettext(True,data['tmp_token'])
|
||||
@@ -23,12 +23,12 @@ class panelAuth:
|
||||
def create_serverid(self,get):
|
||||
try:
|
||||
userPath = 'data/userInfo.json'
|
||||
if not os.path.exists(userPath): return public.returnMsg(False,'LOGIN_FIRST')
|
||||
if not os.path.exists(userPath): return public.return_msg_gettext(False,'Please login with account first')
|
||||
tmp = public.readFile(userPath)
|
||||
if len(tmp) < 2: tmp = '{}'
|
||||
data = json.loads(tmp)
|
||||
data['uid'] = data['id']
|
||||
if not data: return public.returnMsg(False,'LOGIN_FIRST')
|
||||
if not data: return public.return_msg_gettext(False,'Please login with account first')
|
||||
if not 'server_id' in data:
|
||||
s1 = public.get_mac_address() + public.get_hostname()
|
||||
s2 = self.get_cpuname()
|
||||
@@ -36,7 +36,7 @@ class panelAuth:
|
||||
data['server_id'] = serverid
|
||||
public.writeFile(userPath,json.dumps(data))
|
||||
return data
|
||||
except: return public.returnMsg(False,'LOGIN_FIRST')
|
||||
except: return public.return_msg_gettext(False,'Please login with account first')
|
||||
|
||||
|
||||
def create_plugin_other_order(self,get):
|
||||
@@ -63,22 +63,24 @@ class panelAuth:
|
||||
def get_plugin_price(self, get):
|
||||
try:
|
||||
userPath = 'data/userInfo.json'
|
||||
if not 'pluginName' in get and not 'product_id' in get: return public.returnMsg(False,'INIT_ARGS_ERR')
|
||||
if not os.path.exists(userPath): return public.returnMsg(False,'LOGIN_FIRST')
|
||||
if not 'pluginName' in get and not 'product_id' in get: return public.return_msg_gettext(False,'Parameter ERROR!')
|
||||
if not os.path.exists(userPath): return public.return_msg_gettext(False,'Please login with account first')
|
||||
params = {}
|
||||
if not hasattr(get,'product_id'):
|
||||
params['product_id'] = self.get_plugin_info(get.pluginName)['id']
|
||||
else:
|
||||
params['product_id'] = get.product_id
|
||||
data = self.send_cloud('{}/api/product/prices'.format(self.__official_url), params)
|
||||
if not data:
|
||||
return public.return_msg_gettext(False, 'Please log in to your aaPanel account on the panel first!')
|
||||
if not data['success']:
|
||||
return public.returnMsg(False,data['msg'])
|
||||
return public.return_msg_gettext(False,data['msg'])
|
||||
# if len(data['res']) == 6:
|
||||
# return data['res'][3:]
|
||||
return data['res']
|
||||
except:
|
||||
del(session['get_product_list'])
|
||||
return public.returnMsg(False,'Syncing information, please try again!\n' + public.get_error_info())
|
||||
return public.return_msg_gettext(False,'Syncing information, please try again!\n {}',(public.get_error_info(),))
|
||||
|
||||
def get_plugin_info(self,pluginName):
|
||||
data = self.get_business_plugin(None)
|
||||
@@ -104,6 +106,7 @@ class panelAuth:
|
||||
params['cycle_unit'] = get.cycle_unit
|
||||
params['product_id'] = get.pid
|
||||
params['src'] = 2
|
||||
params['trigger_entry'] = get.source
|
||||
params['pay_channel'] = 2
|
||||
params['charge_type'] = get.charge_type
|
||||
env_info = public.fetch_env_info()
|
||||
@@ -111,7 +114,7 @@ class panelAuth:
|
||||
params['server_id'] = env_info['install_code']
|
||||
data = self.send_cloud('{}/api/order/product/create'.format(self.__official_url), params)
|
||||
if not data['success']:
|
||||
return public.returnMsg(False,data['res'])
|
||||
return public.return_msg_gettext(False,data['res'])
|
||||
return data['res']
|
||||
|
||||
def get_stripe_session_id(self,get):
|
||||
@@ -125,7 +128,7 @@ class panelAuth:
|
||||
params = {}
|
||||
params['id'] = get.id
|
||||
data = self.send_cloud('check_product_pays', params)
|
||||
if not data: return public.returnMsg(False,'AJAX_CONN_ERR')
|
||||
if not data: return public.return_msg_gettext(False,'Fail to connect to the server!')
|
||||
if data['status'] == True:
|
||||
self.flush_pay_status(get)
|
||||
if 'get_product_bay' in session: del(session['get_product_bay'])
|
||||
@@ -134,8 +137,8 @@ class panelAuth:
|
||||
def flush_pay_status(self,get):
|
||||
if 'get_product_bay' in session: del(session['get_product_bay'])
|
||||
data = self.get_plugin_list(get)
|
||||
if not data: return public.returnMsg(False,'AJAX_CONN_ERR')
|
||||
return public.returnMsg(True,'FLUSH_STATUS_SUCCESS')
|
||||
if not data: return public.return_msg_gettext(False,'Fail to connect to the server!')
|
||||
return public.return_msg_gettext(True,'Flush status success')
|
||||
|
||||
def get_renew_code(self):
|
||||
pass
|
||||
@@ -163,7 +166,7 @@ class panelAuth:
|
||||
params = {}
|
||||
params['pid'] = getattr(get,'pid',0)
|
||||
data = self.send_cloud('get_re_order_status', params)
|
||||
if not data: return public.returnMsg(False,'AJAX_CONN_ERR')
|
||||
if not data: return public.return_msg_gettext(False,'Fail to connect to the server!')
|
||||
if data['status'] == True:
|
||||
self.flush_pay_status(get)
|
||||
if 'get_product_bay' in session: del(session['get_product_bay'])
|
||||
@@ -192,8 +195,8 @@ class panelAuth:
|
||||
data = self.send_cloud('{}/api/order/product/create'.format(self.__official_url), params)
|
||||
session['focre_cloud'] = True
|
||||
if data['success']:
|
||||
return public.returnMsg(True,'Activate successfully')
|
||||
return public.returnMsg(False, 'Activate failed')
|
||||
return public.return_msg_gettext(True,'Activate successfully')
|
||||
return public.return_msg_gettext(False, 'Activate failed')
|
||||
|
||||
def send_cloud(self,cloudURL,params):
|
||||
try:
|
||||
@@ -293,16 +296,21 @@ class panelAuth:
|
||||
return []
|
||||
if not data['success']: return []
|
||||
data = data['res']
|
||||
return [i for i in data['list'] if i['status'] != 'activated']
|
||||
# return [i for i in data['list'] if i['status'] != 'activated' and get.pid == i['product_id']]
|
||||
res = list()
|
||||
for i in data['list']:
|
||||
if i['status'] != 'activated' and str(get.pid) == str(i['product_id']):
|
||||
res.append(i)
|
||||
return res
|
||||
|
||||
def auth_activate(self,get):
|
||||
params = {}
|
||||
params['serial_no'] = get.serial_no
|
||||
params['environment_info'] = json.dumps(public.fetch_env_info())
|
||||
data = self.send_cloud('{}/api/authorize/product/activate'.format(self.__official_url), params)
|
||||
if not data['success']: return public.returnMsg(False,'Activate Failed')
|
||||
if not data['success']: return public.return_msg_gettext(False,'Activate Failed')
|
||||
session['focre_cloud'] = True
|
||||
return public.returnMsg(True,'Activate successfully')
|
||||
return public.return_msg_gettext(True,'Activate successfully')
|
||||
|
||||
def renew_product_auth(self,get):
|
||||
params = {}
|
||||
@@ -311,6 +319,7 @@ class panelAuth:
|
||||
params['cycle'] = get.cycle
|
||||
params['cycle_unit'] = get.cycle_unit
|
||||
params['src'] = 2
|
||||
params['trigger_entry'] = get.source
|
||||
params['environment_info'] = json.dumps(public.fetch_env_info())
|
||||
if hasattr(get,'coupon_id') and get.pay_channel == '10':
|
||||
params['coupon_id'] = get.coupon_id
|
||||
@@ -319,8 +328,8 @@ class panelAuth:
|
||||
# 使用抵扣券续费直接返回续费结果
|
||||
if get.pay_channel == '10':
|
||||
if not data['success']:
|
||||
return public.returnMsg(False, 'Renew Failed')
|
||||
return public.returnMsg(True,'Renew successfully')
|
||||
return public.return_msg_gettext(False, 'Renew Failed')
|
||||
return public.return_msg_gettext(True,'Renew successfully')
|
||||
# 使用支付续费返回stripe的请求数据
|
||||
return data['res']
|
||||
|
||||
@@ -335,5 +344,5 @@ class panelAuth:
|
||||
session['focre_cloud'] = True
|
||||
# 使用抵扣券续费直接返回续费结果
|
||||
if not data['success']:
|
||||
return public.returnMsg(False, 'Apply Failed')
|
||||
return public.returnMsg(True,'Apply successfully')
|
||||
return public.return_msg_gettext(False, 'Apply Failed')
|
||||
return public.return_msg_gettext(True,'Apply successfully')
|
||||
|
||||
@@ -56,12 +56,12 @@ class backup:
|
||||
|
||||
def echo_start(self):
|
||||
print("="*90)
|
||||
print("|-"+public.getMsg('START_BACKUP')+"[{}]".format(public.format_date()))
|
||||
print("|-"+public.get_msg_gettext('Start backup')+"[{}]".format(public.format_date()))
|
||||
print("="*90)
|
||||
|
||||
def echo_end(self):
|
||||
print("="*90)
|
||||
print("|-"+public.getMsg('BACKUP_COMPLETED')+"[{}]".format(public.format_date()))
|
||||
print("|-"+public.get_msg_gettext('Backup completed')+"[{}]".format(public.format_date()))
|
||||
print("="*90)
|
||||
print("\n")
|
||||
|
||||
@@ -98,8 +98,8 @@ class backup:
|
||||
|
||||
def GetDiskInfo2(self):
|
||||
#取磁盘分区信息
|
||||
temp = public.ExecShell("df -T -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev")[0]
|
||||
tempInodes = public.ExecShell("df -i -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev")[0]
|
||||
temp = public.ExecShell("df -T -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev|grep -v overlay")[0]
|
||||
tempInodes = public.ExecShell("df -i -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev|grep -v overlay")[0]
|
||||
temp1 = temp.split('\n')
|
||||
tempInodes1 = tempInodes.split('\n')
|
||||
diskInfo = []
|
||||
@@ -154,9 +154,9 @@ class backup:
|
||||
error_msg = ""
|
||||
self.echo_start()
|
||||
if not os.path.exists(spath):
|
||||
error_msg= public.getMsg('BACKUP_DIR_NOT_EXIST',(spath,))
|
||||
error_msg= public.get_msg_gettext('The specified directory {} does not exist!',(spath,))
|
||||
self.echo_error(error_msg)
|
||||
self.send_failture_notification(error_msg)
|
||||
self.send_failture_notification(error_msg, target=spath)
|
||||
return False
|
||||
|
||||
if spath[-1] == '/':
|
||||
@@ -170,25 +170,25 @@ class backup:
|
||||
if not self.backup_path_to(spath,dfile,exclude):
|
||||
if self._error_msg:
|
||||
error_msg = self._error_msg
|
||||
self.send_failture_notification(error_msg)
|
||||
self.send_failture_notification(error_msg, target=spath)
|
||||
return False
|
||||
|
||||
if self._cloud:
|
||||
self.echo_info(public.getMsg("BACKUP_UPLOADING",(self._cloud._title,)))
|
||||
self.echo_info(public.get_msg_gettext('Uploading to {}, please wait ...',(self._cloud._title,)))
|
||||
if self._cloud.upload_file(dfile,'path'):
|
||||
self.echo_info(public.getMsg("BACKUP_UPLOAD_SUCCESS",(self._cloud._title,)))
|
||||
self.echo_info(public.get_msg_gettext('Successfully uploaded to {}',(self._cloud._title,)))
|
||||
else:
|
||||
if hasattr(self._cloud, "error_msg"):
|
||||
if self._cloud.error_msg:
|
||||
error_msg = self._cloud.error_msg
|
||||
if not error_msg:
|
||||
error_msg = public.getMsg('BACKUP_UPLOAD_FAILED')
|
||||
error_msg = public.get_msg_gettext('File upload failed, skip this backup!')
|
||||
self.echo_error(error_msg)
|
||||
if os.path.exists(dfile):
|
||||
os.remove(dfile)
|
||||
|
||||
remark = "Backup to " + self._cloud._title
|
||||
self.send_failture_notification(error_msg, remark=remark)
|
||||
self.send_failture_notification(error_msg, target=spath, remark=remark)
|
||||
return False
|
||||
|
||||
filename = dfile
|
||||
@@ -228,9 +228,9 @@ class backup:
|
||||
if _not_save_local:
|
||||
if os.path.exists(dfile):
|
||||
os.remove(dfile)
|
||||
self.echo_info(public.getMsg("BACKUP_DEL",(dfile,)))
|
||||
self.echo_info(public.get_msg_gettext('User settings do not retain local backups, deleted {}',(dfile,)))
|
||||
else:
|
||||
self.echo_info(public.getMsg('KEEP_LOCAL'))
|
||||
self.echo_info(public.get_msg_gettext('Local backup has been kept'))
|
||||
|
||||
if not self._cloud:
|
||||
backups = public.M('backup').where("type=? and pid=? and name=? and filename NOT LIKE '%|%'",('2',0,spath)).field('id,name,filename').select()
|
||||
@@ -239,15 +239,16 @@ class backup:
|
||||
|
||||
self.delete_old(backups,save,'path')
|
||||
self.echo_end()
|
||||
self.save_backup_status(True, target=spath)
|
||||
return dfile
|
||||
|
||||
|
||||
#清理过期备份文件
|
||||
def delete_old(self,backups,save,data_type = None):
|
||||
if type(backups) == str:
|
||||
self.echo_info(public.getMsg('BACKUP_CLEAN_ERR',(backups,)))
|
||||
self.echo_info(public.get_msg_gettext('Failed to clean expired backup, error: {}',(backups,)))
|
||||
return
|
||||
self.echo_info(public.getMsg('BACKUP_KEEP',(str(save),)))
|
||||
self.echo_info(public.get_msg_gettext('Keep the latest number of backups: {} copies',(str(save),)))
|
||||
num = len(backups) - int(save)
|
||||
if num > 0:
|
||||
self._get_local_backdir()
|
||||
@@ -264,11 +265,11 @@ class backup:
|
||||
os.remove(backup['filename'])
|
||||
except:
|
||||
pass
|
||||
self.echo_info(public.getMsg("BACKUP_CLEAN",(backup['filename'],)))
|
||||
self.echo_info(public.get_msg_gettext('Expired backup files have been cleaned from disk: {}',(backup['filename'],)))
|
||||
#尝试删除远程文件
|
||||
if self._cloud:
|
||||
self._cloud.delete_file(backup['name'],data_type)
|
||||
self.echo_info(public.getMsg("BACKUP_CLEAN_REMOVE",(self._cloud._title,backup['name'])))
|
||||
self.echo_info(public.get_msg_gettext('Expired backup files have been cleaned from {}: {}',(self._cloud._title,backup['name'])))
|
||||
|
||||
#从数据库清理
|
||||
public.M('backup').where('id=?',(backup['id'],)).delete()
|
||||
@@ -282,7 +283,7 @@ class backup:
|
||||
#压缩目录
|
||||
def backup_path_to(self,spath,dfile,exclude = [],siteName = None):
|
||||
if not os.path.exists(spath):
|
||||
self.echo_error(public.getMsg('BACKUP_DIR_NOT_EXIST',(spath,)))
|
||||
self.echo_error(public.get_msg_gettext('The specified directory {} does not exist!',(spath,)))
|
||||
return False
|
||||
|
||||
if spath[-1] == '/':
|
||||
@@ -301,55 +302,55 @@ class backup:
|
||||
exclude_config = "Not set"
|
||||
|
||||
if siteName:
|
||||
self.echo_info(public.getMsg('BACKUP_SITE',(siteName,)))
|
||||
self.echo_info(public.getMsg('WEBSITE_DIR',(spath,)))
|
||||
self.echo_info(public.get_msg_gettext('Backup site: {}',(siteName,)))
|
||||
self.echo_info(public.get_msg_gettext('Website document root: {}',(spath,)))
|
||||
else:
|
||||
self.echo_info(public.getMsg('BACKUP_DIR',(spath,)))
|
||||
self.echo_info(public.get_msg_gettext('Backup directory: {}',(spath,)))
|
||||
|
||||
self.echo_info(public.getMsg(
|
||||
"DIR_SIZE",
|
||||
self.echo_info(public.get_msg_gettext(
|
||||
'Directory size: {}',
|
||||
(str(public.to_size(p_size),))
|
||||
))
|
||||
self.echo_info(public.getMsg('BACKUP_EXCLUSION',(exclude_config,)))
|
||||
self.echo_info(public.get_msg_gettext('Exclusion setting: {}',(exclude_config,)))
|
||||
disk_path,disk_free,disk_inode = self.get_disk_free(dfile)
|
||||
self.echo_info(public.getMsg(
|
||||
"PARTITION_INFO",
|
||||
self.echo_info(public.get_msg_gettext(
|
||||
'Partition {} available disk space is: {}, available Inode is: {}',
|
||||
(disk_path,str(public.to_size(disk_free)),str(disk_inode))
|
||||
))
|
||||
if disk_path:
|
||||
if disk_free < p_size:
|
||||
self.echo_error(public.getMsg(
|
||||
"PARTITION_LESS_THEN",
|
||||
self.echo_error(public.get_msg_gettext(
|
||||
'The available disk space of the target partition is less than {}, and the backup cannot be completed. Please increase the disk capacity or change the default backup directory on the settings page!',
|
||||
(str(public.to_size(p_size)),)
|
||||
))
|
||||
return False
|
||||
|
||||
if disk_inode < self._inode_min:
|
||||
self.echo_error(public.getMsg(
|
||||
"INODE_LESS_THEN",
|
||||
self.echo_error(public.get_msg_gettext(
|
||||
'The available Inode of the target partition is less than {}, and the backup cannot be completed. Please increase the disk capacity or change the default backup directory on the settings page!',
|
||||
(str(self._inode_min,))
|
||||
))
|
||||
return False
|
||||
|
||||
stime = time.time()
|
||||
self.echo_info(public.getMsg("START_COMPRESS",(public.format_date(times=stime),)))
|
||||
self.echo_info(public.get_msg_gettext('Start compressing files: {}',(public.format_date(times=stime),)))
|
||||
if os.path.exists(dfile):
|
||||
os.remove(dfile)
|
||||
public.ExecShell("cd " + os.path.dirname(spath) + " && tar zcvf '" + dfile + "' " + self._exclude + " '" + dirname + "' 2>{err_log} 1> /dev/null".format(err_log = self._err_log))
|
||||
tar_size = os.path.getsize(dfile)
|
||||
if tar_size < 1:
|
||||
self.echo_error(public.getMsg('ZIP_ERR'))
|
||||
self.echo_error(public.get_msg_gettext('Compression failed!'))
|
||||
self.echo_info(public.readFile(self._err_log))
|
||||
return False
|
||||
compression_time = str('{:.2f}'.format(time.time() - stime))
|
||||
self.echo_info(public.getMsg(
|
||||
'COMPRESS_TIME',
|
||||
self.echo_info(public.get_msg_gettext(
|
||||
'Compression completed, took {} seconds, compressed package size: {}',
|
||||
(compression_time,str(public.to_size(tar_size)))
|
||||
))
|
||||
if siteName:
|
||||
self.echo_info(public.getMsg("WEBSITE_BACKUP_TO",(dfile,)))
|
||||
self.echo_info(public.get_msg_gettext('Site backed up to: {}',(dfile,)))
|
||||
else:
|
||||
self.echo_info(public.getMsg("DIR_BACKUP_TO",(dfile,)))
|
||||
self.echo_info(public.get_msg_gettext('Directory has been backed up to: {}',(dfile,)))
|
||||
if os.path.exists(self._err_log):
|
||||
os.remove(self._err_log)
|
||||
return dfile
|
||||
@@ -366,25 +367,25 @@ class backup:
|
||||
if not self.backup_path_to(spath,dfile,exclude,siteName=siteName):
|
||||
if self._error_msg:
|
||||
error_msg = self._error_msg
|
||||
self.send_failture_notification(error_msg)
|
||||
self.send_failture_notification(error_msg, target=siteName)
|
||||
return False
|
||||
|
||||
if self._cloud:
|
||||
self.echo_info(public.getMsg("BACKUP_UPLOADING",(self._cloud._title,)))
|
||||
self.echo_info(public.get_msg_gettext('Uploading to {}, please wait ...',(self._cloud._title,)))
|
||||
if self._cloud.upload_file(dfile,'site'):
|
||||
self.echo_info(public.getMsg("BACKUP_UPLOAD_SUCCESS",(self._cloud._title,)))
|
||||
self.echo_info(public.get_msg_gettext('Successfully uploaded to {}',(self._cloud._title,)))
|
||||
else:
|
||||
if hasattr(self._cloud, "error_msg"):
|
||||
if self._cloud.error_msg:
|
||||
error_msg = self._cloud.error_msg
|
||||
if not error_msg:
|
||||
error_msg = public.getMsg('BACKUP_UPLOAD_FAILED')
|
||||
error_msg = public.get_msg_gettext('File upload failed, skip this backup!')
|
||||
self.echo_error(error_msg)
|
||||
if os.path.exists(dfile):
|
||||
os.remove(dfile)
|
||||
|
||||
remark = "Backup to " + self._cloud._title
|
||||
self.send_failture_notification(error_msg, remark=remark)
|
||||
self.send_failture_notification(error_msg, target=siteName, remark=remark)
|
||||
return False
|
||||
|
||||
filename = dfile
|
||||
@@ -424,9 +425,9 @@ class backup:
|
||||
if _not_save_local:
|
||||
if os.path.exists(dfile):
|
||||
os.remove(dfile)
|
||||
self.echo_info(public.getMsg("BACKUP_DEL",(dfile,)))
|
||||
self.echo_info(public.get_msg_gettext('User settings do not retain local backups, deleted {}',(dfile,)))
|
||||
else:
|
||||
self.echo_info(public.getMsg('KEEP_LOCAL'))
|
||||
self.echo_info(public.get_msg_gettext('Local backup has been kept'))
|
||||
|
||||
#清理多余备份
|
||||
if not self._cloud:
|
||||
@@ -450,6 +451,7 @@ class backup:
|
||||
if not result:
|
||||
failture_count += 1
|
||||
results.append((database['name'], result, self._error_msg,))
|
||||
self.save_backup_status(result, target=database['name'], msg=self._error_msg)
|
||||
|
||||
if failture_count > 0:
|
||||
self.send_all_failture_notification("database", results)
|
||||
@@ -467,6 +469,7 @@ class backup:
|
||||
if not result:
|
||||
failture_count += 1
|
||||
results.append((site['name'], result, self._error_msg,))
|
||||
self.save_backup_status(result, target=site['name'], msg=self._error_msg)
|
||||
|
||||
if failture_count > 0:
|
||||
self.send_all_failture_notification("site", results)
|
||||
@@ -519,58 +522,78 @@ class backup:
|
||||
os.makedirs(dpath,384)
|
||||
|
||||
error_msg = ""
|
||||
import panelMysql
|
||||
if not self._db_mysql:self._db_mysql = panelMysql.panelMysql()
|
||||
# ----- 判断是否为远程数据库START @author hwliang<2021-01-08>--------
|
||||
db_find = public.M('databases').where("name=?",(db_name,)).find()
|
||||
conn_config = {}
|
||||
self._db_mysql = public.get_mysql_obj(db_name)
|
||||
is_cloud_db = db_find['db_type'] in ['1',1,'2',2]
|
||||
if is_cloud_db:
|
||||
# 连接远程数据库
|
||||
if db_find['sid']:
|
||||
conn_config = public.M('database_servers').where('id=?',db_find['sid']).find()
|
||||
if not 'db_name' in conn_config: conn_config['db_name'] = None
|
||||
else:
|
||||
conn_config = json.loads(db_find['conn_config'])
|
||||
conn_config['db_port'] = str(int(conn_config['db_port']))
|
||||
self._db_mysql.set_host(conn_config['db_host'],int(conn_config['db_port']),conn_config['db_name'],conn_config['db_user'],conn_config['db_password'])
|
||||
# ----- 判断是否为远程数据库END @author hwliang<2021-01-08>------------
|
||||
d_tmp = self._db_mysql.query("select sum(DATA_LENGTH)+sum(INDEX_LENGTH) from information_schema.tables where table_schema='%s'" % db_name)
|
||||
try:
|
||||
p_size = self.map_to_list(d_tmp)[0][0]
|
||||
except:
|
||||
error_msg = public.getMsg('DB_CONN_ERR')
|
||||
error_msg = public.get_msg_gettext('The database connection is abnormal. Please check whether the root user authority or database configuration parameters are correct.')
|
||||
self.echo_error(error_msg)
|
||||
self.send_failture_notification(error_msg)
|
||||
self.send_failture_notification(error_msg, target=db_name)
|
||||
return False
|
||||
|
||||
if p_size == None:
|
||||
error_msg = public.getMsg('DB_BACKUP_ERR',(db_name,))
|
||||
error_msg = public.get_msg_gettext('The specified database [ {} ] has no data!',(db_name,))
|
||||
self.echo_error(error_msg)
|
||||
self.send_failture_notification(error_msg)
|
||||
self.send_failture_notification(error_msg, target=db_name)
|
||||
return False
|
||||
|
||||
character = public.get_database_character(db_name)
|
||||
|
||||
self.echo_info(public.getMsg('DB_BACKUP',(db_name,)))
|
||||
self.echo_info(public.getMsg("DB_SIZE",(public.to_size(p_size),)))
|
||||
self.echo_info(public.getMsg("DB_CHARACTER",(character,)))
|
||||
self.echo_info(public.get_msg_gettext('Backup database:{}',(db_name,)))
|
||||
self.echo_info(public.get_msg_gettext('Database size: {}',(public.to_size(p_size),)))
|
||||
self.echo_info(public.get_msg_gettext('Database character set: {}',(character,)))
|
||||
disk_path,disk_free,disk_inode = self.get_disk_free(dfile)
|
||||
self.echo_info(public.getMsg(
|
||||
"PARTITION_INFO",(
|
||||
self.echo_info(public.get_msg_gettext(
|
||||
'Partition {} available disk space is: {}, available Inode is: {}',(
|
||||
disk_path,str(public.to_size(disk_free)),str(disk_inode)
|
||||
)
|
||||
))
|
||||
if disk_path:
|
||||
if disk_free < p_size:
|
||||
error_msg = public.getMsg("PARTITION_LESS_THEN",(
|
||||
error_msg = public.get_msg_gettext('The available disk space of the target partition is less than {}, and the backup cannot be completed. Please increase the disk capacity or change the default backup directory on the settings page!',(
|
||||
str(public.to_size(p_size),)
|
||||
))
|
||||
self.echo_error(error_msg)
|
||||
self.send_failture_notification(error_msg)
|
||||
self.send_failture_notification(error_msg, target=db_name)
|
||||
return False
|
||||
|
||||
if disk_inode < self._inode_min:
|
||||
error_msg = public.getMsg("INODE_LESS_THEN",(self._inode_min,))
|
||||
error_msg = public.get_msg_gettext('The available Inode of the target partition is less than {}, and the backup cannot be completed. Please increase the disk capacity or change the default backup directory on the settings page!',(self._inode_min,))
|
||||
self.echo_error(error_msg)
|
||||
self.send_failture_notification(error_msg)
|
||||
self.send_failture_notification(error_msg, target=db_name)
|
||||
return False
|
||||
|
||||
stime = time.time()
|
||||
self.echo_info(public.getMsg("EXPORT_DB",(public.format_date(times=stime),)))
|
||||
self.echo_info(public.get_msg_gettext('Start exporting database: {}',(public.format_date(times=stime),)))
|
||||
if os.path.exists(dfile):
|
||||
os.remove(dfile)
|
||||
#self.mypass(True)
|
||||
mysqldump_bin = public.get_mysqldump_bin()
|
||||
try:
|
||||
password = public.M('config').where('id=?',(1,)).getField('mysql_root')
|
||||
os.environ["MYSQL_PWD"] = password
|
||||
backup_cmd = "/www/server/mysql/bin/mysqldump -E -R --default-character-set="+ character +" --force --hex-blob --opt " + db_name + " -u root" + " 2>"+self._err_log+"| gzip > " + dfile
|
||||
if not is_cloud_db:
|
||||
# 本地数据库 @author hwliang<2021-01-08>
|
||||
password = public.M('config').where('id=?',(1,)).getField('mysql_root')
|
||||
os.environ["MYSQL_PWD"] = password
|
||||
backup_cmd = mysqldump_bin + " -E -R --default-character-set="+ character +" --force --hex-blob --opt " + db_name + " -u root" + " 2>"+self._err_log+"| gzip > " + dfile
|
||||
else:
|
||||
# 远程数据库 @author hwliang<2021-01-08>
|
||||
os.environ["MYSQL_PWD"] = conn_config['db_password']
|
||||
backup_cmd = mysqldump_bin + " -h " + conn_config['db_host'] + " -P " + conn_config['db_port'] + " -E -R --default-character-set="+ character +" --force --hex-blob --opt " + db_name + " -u " + conn_config['db_user'] + " 2>"+self._err_log+"| gzip > " + dfile
|
||||
public.ExecShell(backup_cmd)
|
||||
except Exception as e:
|
||||
raise
|
||||
@@ -580,27 +603,27 @@ class backup:
|
||||
#self.mypass(False)
|
||||
gz_size = os.path.getsize(dfile)
|
||||
if gz_size < 400:
|
||||
error_msg = public.getMsg("EXPORT_DB_ERR")
|
||||
error_msg = public.get_msg_gettext('Database export failed!')
|
||||
self.echo_error(error_msg)
|
||||
self.send_failture_notification(error_msg)
|
||||
self.send_failture_notification(error_msg, target=db_name)
|
||||
self.echo_info(public.readFile(self._err_log))
|
||||
return False
|
||||
compressed_time = str('{:.2f}'.format(time.time() - stime))
|
||||
self.echo_info(
|
||||
public.getMsg("COMPRESS_TIME",(str(compressed_time),
|
||||
public.get_msg_gettext('Compression completed, took {} seconds, compressed package size: {}',(str(compressed_time),
|
||||
str(public.to_size(gz_size))
|
||||
))
|
||||
)
|
||||
if self._cloud:
|
||||
self.echo_info(public.getMsg("BACKUP_UPLOADING",(self._cloud._title,)))
|
||||
self.echo_info(public.get_msg_gettext('Uploading to {}, please wait ...',(self._cloud._title,)))
|
||||
if self._cloud.upload_file(dfile, 'database'):
|
||||
self.echo_info(public.getMsg("BACKUP_UPLOAD_SUCCESS",(self._cloud._title,)))
|
||||
self.echo_info(public.get_msg_gettext('Successfully uploaded to {}',(self._cloud._title,)))
|
||||
else:
|
||||
if hasattr(self._cloud, "error_msg"):
|
||||
if self._cloud.error_msg:
|
||||
error_msg = self._cloud.error_msg
|
||||
if not error_msg:
|
||||
error_msg = public.getMsg('BACKUP_UPLOAD_FAILED')
|
||||
error_msg = public.get_msg_gettext('File upload failed, skip this backup!')
|
||||
self.echo_error(error_msg)
|
||||
if os.path.exists(dfile):
|
||||
os.remove(dfile)
|
||||
@@ -612,7 +635,7 @@ class backup:
|
||||
filename = dfile
|
||||
if self._cloud:
|
||||
filename = dfile + '|' + self._cloud._name + '|' + fname
|
||||
self.echo_info(public.getMsg("DB_BACKUP_TO",(dfile,)))
|
||||
self.echo_info(public.get_msg_gettext('Database has been backed up to: {}',(dfile,)))
|
||||
if os.path.exists(self._err_log):
|
||||
os.remove(self._err_log)
|
||||
|
||||
@@ -651,9 +674,9 @@ class backup:
|
||||
if _not_save_local:
|
||||
if os.path.exists(dfile):
|
||||
os.remove(dfile)
|
||||
self.echo_info(public.getMsg("BACKUP_DEL",(dfile,)))
|
||||
self.echo_info(public.get_msg_gettext('User settings do not retain local backups, deleted {}',(dfile,)))
|
||||
else:
|
||||
self.echo_info(public.getMsg('KEEP_LOCAL'))
|
||||
self.echo_info(public.get_msg_gettext('Local backup has been kept'))
|
||||
|
||||
#清理多余备份
|
||||
if not self._cloud:
|
||||
@@ -662,6 +685,7 @@ class backup:
|
||||
backups = public.M('backup').where('type=? and pid=? and filename LIKE "%{}%"'.format(self._cloud._name),('1',pid)).field('id,name,filename').select()
|
||||
self.delete_old(backups,save,'database')
|
||||
self.echo_end()
|
||||
self.save_backup_status(True, target=db_name)
|
||||
return dfile
|
||||
|
||||
def generate_success_title(self, task_name):
|
||||
@@ -669,10 +693,10 @@ class backup:
|
||||
sm = send_mail()
|
||||
now = public.format_date(format="%Y-%m-%d %H:%M")
|
||||
server_ip = sm.GetLocalIp()
|
||||
title = public.getMsg("BACKUP_TASK_TITLE",(server_ip, task_name))
|
||||
title = public.get_msg_gettext('{}-{} The task was executed successfully',(server_ip, task_name))
|
||||
return title
|
||||
|
||||
def generate_failture_title(self):
|
||||
def generate_failture_title(self, task_name):
|
||||
title = "aaPanel backup task failed reminder"
|
||||
return title
|
||||
|
||||
@@ -743,13 +767,13 @@ class backup:
|
||||
""" 通过计划任务名称查找计划任务配置参数 """
|
||||
try:
|
||||
cron_info = public.M('crontab').where('echo=?',(cron_name,))\
|
||||
.field('name,save_local,notice,notice_channel').find()
|
||||
.field('name,save_local,notice,notice_channel,id').find()
|
||||
return cron_info
|
||||
except Exception as e:
|
||||
pass
|
||||
return {}
|
||||
|
||||
def send_failture_notification(self, error_msg, remark=""):
|
||||
def send_failture_notification(self, error_msg, target="", remark=""):
|
||||
"""发送任务失败消息
|
||||
|
||||
:error_msg 错误信息
|
||||
@@ -764,16 +788,18 @@ class backup:
|
||||
save_local = cron_info["save_local"]
|
||||
notice = cron_info["notice"]
|
||||
notice_channel = cron_info["notice_channel"]
|
||||
|
||||
self.save_backup_status(False, target, msg=error_msg)
|
||||
if notice == 0 or not notice_channel:
|
||||
return
|
||||
|
||||
if notice == 1 or notice == 2:
|
||||
title = self.generate_failture_title(cron_title)
|
||||
title = self.generate_failture_title()
|
||||
task_name = cron_title
|
||||
msg = self.generate_failture_notice(task_name, error_msg, remark)
|
||||
res = self.send_notification(notice_channel, title, msg)
|
||||
if res:
|
||||
self.echo_info(public.getMsg('NOTIFICATION_SENT'))
|
||||
self.echo_info(public.get_msg_gettext('Notification has been sent'))
|
||||
|
||||
def send_all_failture_notification(self, backup_type, results, remark=""):
|
||||
"""统一发送任务失败消息
|
||||
@@ -813,18 +839,18 @@ class backup:
|
||||
|
||||
if failture_count > 0:
|
||||
if self._cloud:
|
||||
remark = public.getMsg("BACKUP_MSG"),(
|
||||
remark = public.get_msg_gettext('Backup to {}, a total of {} {}, and failures {}.'),(
|
||||
self._cloud._title, total, backup_type_desc, failture_count)
|
||||
else:
|
||||
remark = public.getMsg("BACKUP_MSG1"),(
|
||||
remark = public.get_msg_gettext('Backup failed {}/total {} sites'),(
|
||||
failture_count, total, backup_type_desc)
|
||||
|
||||
msg = self.generate_all_failture_notice(task_name, content, backup_type_desc, remark)
|
||||
res = self.send_notification(notice_channel, title, msg)
|
||||
if res:
|
||||
self.echo_info(public.getMsg('NOTIFICATION_SENT'))
|
||||
self.echo_info(public.get_msg_gettext('Notification has been sent'))
|
||||
else:
|
||||
self.echo_error(public.getMsg('NOTIFICATION_ERR'))
|
||||
self.echo_error(public.get_msg_gettext('Failed to send notification'))
|
||||
|
||||
def send_notification(self, channel, title, msg = {}):
|
||||
try:
|
||||
@@ -876,5 +902,14 @@ class backup:
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
|
||||
def save_backup_status(self, status, target="", msg=""):
|
||||
"""保存备份的状态"""
|
||||
try:
|
||||
if not self.cron_info:
|
||||
return
|
||||
cron_id = self.cron_info["id"]
|
||||
sql = public.M("system").dbfile("system").table("backup_status")
|
||||
sql.add("id,target,status,msg,addtime", (cron_id, target, status, msg, time.time(),))
|
||||
except Exception as e:
|
||||
print("Backup status saving error :{}.".format(e))
|
||||
|
||||
|
||||
@@ -34,12 +34,12 @@ import hmac
|
||||
try:
|
||||
import requests
|
||||
except:
|
||||
public.ExecShell('pip install requests')
|
||||
public.ExecShell('btpip install requests')
|
||||
import requests
|
||||
try:
|
||||
import OpenSSL
|
||||
except:
|
||||
public.ExecShell('pip install pyopenssl')
|
||||
public.ExecShell('btpip install pyOpenSSL')
|
||||
import OpenSSL
|
||||
import random
|
||||
import datetime
|
||||
@@ -97,7 +97,7 @@ class BaseDns(object):
|
||||
|
||||
class DNSPodDns(BaseDns):
|
||||
dns_provider_name = "dnspod"
|
||||
|
||||
_type = 0 # 0:lest 1:锐成
|
||||
def __init__(self, DNSPOD_ID, DNSPOD_API_KEY, DNSPOD_API_BASE_URL="https://dnsapi.cn/"):
|
||||
self.DNSPOD_ID = DNSPOD_ID
|
||||
self.DNSPOD_API_KEY = DNSPOD_API_KEY
|
||||
@@ -113,7 +113,10 @@ class DNSPodDns(BaseDns):
|
||||
|
||||
def create_dns_record(self, domain_name, domain_dns_value):
|
||||
domain_name,_,subd = extract_zone(domain_name)
|
||||
self.add_record(domain_name,subd,domain_dns_value,'TXT')
|
||||
if self._type == 1:
|
||||
self.add_record(domain_name,subd.replace('_acme-challenge.',''),domain_dns_value,'CNAME')
|
||||
else:
|
||||
self.add_record(domain_name,subd,domain_dns_value,'TXT')
|
||||
|
||||
|
||||
|
||||
@@ -177,7 +180,7 @@ class DNSPodDns(BaseDns):
|
||||
|
||||
class CloudFlareDns(BaseDns):
|
||||
dns_provider_name = "cloudflare"
|
||||
|
||||
_type = 0 # 0:lest 1:锐成
|
||||
def __init__(
|
||||
self,
|
||||
CLOUDFLARE_EMAIL,
|
||||
@@ -278,6 +281,12 @@ class CloudFlareDns(BaseDns):
|
||||
"name": "_acme-challenge" + "." + domain_name + ".",
|
||||
"content": "{0}".format(domain_dns_value),
|
||||
}
|
||||
|
||||
if self._type == 1:
|
||||
body['type'] = 'CNAME'
|
||||
root, _, acme_txt = extract_zone(domain_name)
|
||||
body['name'] = acme_txt.replace('_acme-challenge.','')
|
||||
|
||||
create_cloudflare_dns_record_response = requests.post(
|
||||
url, headers=headers, json=body, timeout=self.HTTP_TIMEOUT
|
||||
)
|
||||
@@ -326,6 +335,7 @@ class CloudFlareDns(BaseDns):
|
||||
|
||||
|
||||
class AliyunDns(object):
|
||||
_type = 0 # 0:lest 1:锐成
|
||||
def __init__(self, key, secret, ):
|
||||
self.key = str(key).strip()
|
||||
self.secret = str(secret).strip()
|
||||
@@ -359,11 +369,14 @@ class AliyunDns(object):
|
||||
|
||||
def create_dns_record(self, domain_name, domain_dns_value):
|
||||
root, _, acme_txt = extract_zone(domain_name)
|
||||
self.add_record(root,'TXT',acme_txt,domain_dns_value)
|
||||
try:
|
||||
self.add_record(root,'CAA','@',caa_value)
|
||||
except:
|
||||
pass
|
||||
if self._type == 1:
|
||||
acme_txt = acme_txt.replace('_acme-challenge.','')
|
||||
self.add_record(root,'CNAME',acme_txt,domain_dns_value)
|
||||
else:
|
||||
try:
|
||||
self.add_record(root,'CAA','@',caa_value)
|
||||
except: pass
|
||||
self.add_record(root,'TXT',acme_txt,domain_dns_value)
|
||||
|
||||
|
||||
def add_record(self,domain,s_type,host,value):
|
||||
@@ -493,17 +506,6 @@ class CloudxnsDns(object):
|
||||
req = requests.post(url=url, headers=headers, data=parameter,verify=False)
|
||||
req = req.json()
|
||||
|
||||
data = {
|
||||
"domain_id": int(domain),
|
||||
"host": '@',
|
||||
"value": caa_value,
|
||||
"type": "CAA",
|
||||
"line_id": 1,
|
||||
}
|
||||
parameter = json.dumps(data)
|
||||
headers = self.get_headers(url, parameter)
|
||||
requests.post(url=url, headers=headers, data=parameter,verify=False)
|
||||
|
||||
return req
|
||||
|
||||
def delete_dns_record(self, domain_name, domain_dns_value):
|
||||
@@ -513,10 +515,6 @@ class CloudxnsDns(object):
|
||||
headers = self.get_headers(url, )
|
||||
req = requests.delete(url=url, headers=headers, verify=False)
|
||||
req = req.json()
|
||||
|
||||
url = "https://www.cloudxns.net/api2/record/{}/{}".format(self.get_record_id(root,'CAA'), self.get_domain_id(root))
|
||||
headers = self.get_headers(url, )
|
||||
req = requests.delete(url=url, headers=headers, verify=False)
|
||||
return req
|
||||
|
||||
def get_record_id(self, domain_name,s_type = 'TXT'):
|
||||
@@ -530,12 +528,12 @@ class CloudxnsDns(object):
|
||||
return False
|
||||
|
||||
class Dns_com(object):
|
||||
|
||||
_type = 0 # 0:lest 1:锐成
|
||||
def __init__(self, key, secret, ):
|
||||
pass
|
||||
|
||||
def get_dns_obj(self):
|
||||
p_path = '/www/server/panel/plugin/model'
|
||||
p_path = '/www/server/panel/plugin/dns'
|
||||
if not os.path.exists(p_path +'/dns_main.py'): return None
|
||||
sys.path.insert(0,p_path)
|
||||
import dns_main
|
||||
@@ -544,7 +542,13 @@ class Dns_com(object):
|
||||
|
||||
def create_dns_record(self, domain_name, domain_dns_value):
|
||||
root, _, acme_txt = extract_zone(domain_name)
|
||||
result = self.get_dns_obj().add_txt(acme_txt + '.' + root,domain_dns_value)
|
||||
|
||||
if self._type == 1:
|
||||
acme_txt = acme_txt.replace('_acme-challenge.','')
|
||||
result = self.add_record(acme_txt + '.' + root,domain_dns_value)
|
||||
else:
|
||||
result = self.get_dns_obj().add_txt(acme_txt + '.' + root,domain_dns_value)
|
||||
|
||||
if result == "False":
|
||||
raise ValueError('[DNS] This domain name does not exist in the currently bound Pagoda DNS cloud resolution account. Adding parsing failed!')
|
||||
time.sleep(5)
|
||||
|
||||
@@ -135,51 +135,51 @@ class panelLets:
|
||||
#格式化错误输出
|
||||
def get_error(self,error):
|
||||
if error.find("Max checks allowed") >= 0 :
|
||||
return "CA can't verify your domain name, please check if the domain name resolution is correct, or wait 5-10 minutes and try again."
|
||||
return public.get_msg_gettext("CA can't verify your domain name, please check if the domain name resolution is correct, or wait 5-10 minutes and try again.")
|
||||
elif error.find("Max retries exceeded with") >= 0 or error.find('status_code=0 ') != -1:
|
||||
return "The CA server connection timed out, please try again later."
|
||||
return public.get_msg_gettext("The CA server connection timed out, please try again later.")
|
||||
elif error.find("The domain name belongs") >= 0:
|
||||
return "The domain name does not belong to this DNS service provider. Please ensure that the domain name is filled in correctly."
|
||||
return public.get_msg_gettext("The domain name does not belong to this DNS service provider. Please ensure that the domain name is filled in correctly.")
|
||||
elif error.find('login token ID is invalid') >=0:
|
||||
return 'The DNS server connection failed. Please check if the key is correct.'
|
||||
return public.get_msg_gettext('The DNS server connection failed. Please check if the key is correct.')
|
||||
elif "too many certificates already issued for exact set of domains" in error:
|
||||
return 'The signing failed, the domain name %s exceeded the weekly number of repeated issuances!' % re.findall("exact set of domains: (.+):", error)
|
||||
return public.get_msg_gettext('The signing failed, the domain name exact set of domains: (.+): {} exceeded the weekly number of repeated issuances!',(error,))
|
||||
elif "Error creating new account :: too many registrations for this IP" in error:
|
||||
return 'The signing failed, the current server IP has reached the limit of creating up to 10 accounts every 3 hours..'
|
||||
return public.get_msg_gettext('The signing failed, the current server IP has reached the limit of creating up to 10 accounts every 3 hours..')
|
||||
elif "DNS problem: NXDOMAIN looking up A for" in error:
|
||||
return 'The verification failed, the domain name was not resolved, or the resolution did not take effect.!'
|
||||
return public.get_msg_gettext('The verification failed, the domain name was not resolved, or the resolution did not take effect.!')
|
||||
elif "Invalid response from" in error:
|
||||
return 'Authentication failed, domain name resolution error or verification URL could not be accessed!'
|
||||
return public.get_msg_gettext('Authentication failed, domain name resolution error or verification URL could not be accessed!')
|
||||
elif error.find('TLS Web Server Authentication') != -1:
|
||||
public.restart_panel()
|
||||
return "Failed to connect to CA server, please try again later."
|
||||
return public.get_msg_gettext("Failed to connect to CA server, please try again later.")
|
||||
elif error.find('Name does not end in a public suffix') != -1:
|
||||
return "Unsupported domain name %s, please check if the domain name is correct!" % re.findall("Cannot issue for \"(.+)\":", error)
|
||||
return public.get_msg_gettext("Unsupported domain name {}, please check if the domain name is correct!",(re.findall("Cannot issue for \"(.+)\":", error),))
|
||||
elif error.find('No valid IP addresses found for') != -1:
|
||||
return "The domain name %s did not find a resolution record. Please check if the domain name is resolved.!" % re.findall("No valid IP addresses found for (.+)", error)
|
||||
return public.get_msg_gettext("The domain name {} did not find a resolution record. Please check if the domain name is resolved.!",(re.findall("No valid IP addresses found for (.+)", error),))
|
||||
elif error.find('No TXT record found at') != -1:
|
||||
return "If a valid TXT resolution record is not found in the domain name %s, please check if the TXT record is correctly parsed. If it is applied by DNSAPI, please try again in 10 minutes.!" % re.findall(
|
||||
"No TXT record found at (.+)", error)
|
||||
return public.get_msg_gettext("If a valid TXT resolution record is not found in the domain name {}, please check if the TXT record is correctly parsed. If it is applied by DNSAPI, please try again in 10 minutes.!",(re.findall(
|
||||
"No TXT record found at (.+)", error),))
|
||||
elif error.find('Incorrect TXT record') != -1:
|
||||
return "Found the wrong TXT record on %s: %s, please check if the TXT resolution is correct. If it is applied by DNSAPI, please try again in 10 minutes.!" % (
|
||||
re.findall("found at (.+)", error), re.findall("Incorrect TXT record \"(.+)\"", error))
|
||||
return public.get_msg_gettext("Found the wrong TXT record on {}: {}, please check if the TXT resolution is correct. If it is applied by DNSAPI, please try again in 10 minutes.!",(
|
||||
re.findall("found at (.+)", error), re.findall("Incorrect TXT record \"(.+)\"", error)))
|
||||
elif error.find('Domain not under you or your user') != -1:
|
||||
return "This domain name does not exist under this dnspod account. Adding parsing failed.!"
|
||||
return public.get_msg_gettext("This domain name does not exist under this dnspod account. Adding parsing failed.!")
|
||||
elif error.find('SERVFAIL looking up TXT for') != -1:
|
||||
return "If a valid TXT resolution record is not found in the domain name %s, please check if the TXT record is correctly parsed. If it is applied by DNSAPI, please try again in 10 minutes.!" % re.findall(
|
||||
"looking up TXT for (.+)", error)
|
||||
return public.get_msg_gettext("If a valid TXT resolution record is not found in the domain name {}, please check if the TXT record is correctly parsed. If it is applied by DNSAPI, please try again in 10 minutes.!",(re.findall(
|
||||
"looking up TXT for (.+)", error),))
|
||||
elif error.find('Timeout during connect') != -1:
|
||||
return "Connection timed out, CA server could not access your website!"
|
||||
return public.get_msg_gettext("Connection timed out, CA server could not access your website!")
|
||||
elif error.find("DNS problem: SERVFAIL looking up CAA for") != -1:
|
||||
return "The domain name %s is currently required to verify the CAA record. Please manually resolve the CAA record, or try again after 1 hour.!" % re.findall("looking up CAA for (.+)", error)
|
||||
return public.get_msg_gettext("The domain name {} is currently required to verify the CAA record. Please manually resolve the CAA record, or try again after 1 hour.!" , (re.findall("looking up CAA for (.+)", error),))
|
||||
elif error.find("Read timed out.") != -1:
|
||||
return "Verification timeout, please check whether the domain name is correctly resolved. If dns is resolved, the connection between the server and Let'sEncrypt may be abnormal. Please try again later!"
|
||||
return public.get_msg_gettext("Verification timeout, please check whether the domain name is correctly resolved. If dns is resolved, the connection between the server and Let'sEncrypt may be abnormal. Please try again later!")
|
||||
elif error.find("Error creating new order") != -1:
|
||||
return "Order creation failed, please try again later!"
|
||||
return public.get_msg_gettext("Order creation failed, please try again later!")
|
||||
elif error.find("Too Many Requests") != -1:
|
||||
return "More than 5 verification failures in 1 hour, application is temporarily banned, please try again later!"
|
||||
return public.get_msg_gettext("More than 5 verification failures in 1 hour, application is temporarily banned, please try again later!")
|
||||
elif error.find('HTTP Error 400: Bad Request') != -1:
|
||||
return "CA server denied access, please try again later!"
|
||||
return public.get_msg_gettext("CA server denied access, please try again later!")
|
||||
else:
|
||||
return error;
|
||||
|
||||
@@ -211,10 +211,10 @@ class panelLets:
|
||||
def renew_lest_cert(self,data):
|
||||
#续签网站
|
||||
path = self.setupPath + '/panel/vhost/cert/'+ data['siteName']
|
||||
if not os.path.exists(path): return public.returnMsg(False, 'RENEW_FAILED')
|
||||
if not os.path.exists(path): return public.return_msg_gettext(False, 'The renewal failed and the certificate directory does not exist.')
|
||||
|
||||
account_path = path + "/account_key.key"
|
||||
if not os.path.exists(account_path): return public.returnMsg(False, 'RENEW_FAILED1')
|
||||
if not os.path.exists(account_path): return public.return_msg_gettext(False, 'Renewal failed, missing account_key.')
|
||||
|
||||
#续签
|
||||
data['account_key'] = public.readFile(account_path)
|
||||
@@ -226,7 +226,7 @@ class panelLets:
|
||||
else:
|
||||
certificate = self.crate_let_by_file(data)
|
||||
|
||||
if not certificate['status']: return public.returnMsg(False, certificate['msg'])
|
||||
if not certificate['status']: return public.return_msg_gettext(False, certificate['msg'])
|
||||
|
||||
#存储证书
|
||||
public.writeFile(path + "/privkey.pem",certificate['key'])
|
||||
@@ -238,7 +238,7 @@ class panelLets:
|
||||
pfx_buffer = p12.export()
|
||||
public.writeFile(path + "/fullchain.pfx",pfx_buffer,'wb+')
|
||||
|
||||
return public.returnMsg(True, 'RENEW_SUCCESS1',(data['siteName'],))
|
||||
return public.return_msg_gettext(True, '[ {} ] The certificate renewal was successful.',(data['siteName'],))
|
||||
|
||||
|
||||
|
||||
@@ -249,9 +249,9 @@ class panelLets:
|
||||
data['domains'] = json.loads(get.domains)
|
||||
data['email'] = get.email
|
||||
data['dnssleep'] = get.dnssleep
|
||||
self.write_log(public.getMsg("APPLY_SSL",(data['domains'],)))
|
||||
self.write_log(public.get_msg_gettext('Ready to apply for SSL, domain name {}',(data['domains'],)))
|
||||
self.write_log("="*50)
|
||||
if len(data['domains']) <=0 : return public.returnMsg(False, 'APPLY_SSL_DOMAIN_ERR')
|
||||
if len(data['domains']) <=0 : return public.return_msg_gettext(False, 'The list of applied domain names cannot be empty.')
|
||||
|
||||
data['first_domain'] = data['domains'][0]
|
||||
|
||||
@@ -296,7 +296,7 @@ class panelLets:
|
||||
if 'status' in result and not result['status']: return result
|
||||
result['status'] = True
|
||||
public.writeFile(domain_path, json.dumps(result))
|
||||
result['msg'] = public.getMsg('MANUALLY_RESOLVE_DOMAIN')
|
||||
result['msg'] = public.get_msg_gettext('Get successful, please manually resolve the domain name')
|
||||
result['code'] = 2
|
||||
return result
|
||||
elif get.dnsapi == 'dns_bt':
|
||||
@@ -314,10 +314,10 @@ class panelLets:
|
||||
data['site_dir'] = get.site_dir
|
||||
certificate = self.crate_let_by_file(data)
|
||||
|
||||
if not certificate['status']: return public.returnMsg(False, certificate['msg'])
|
||||
if not certificate['status']: return public.return_msg_gettext(False, certificate['msg'])
|
||||
|
||||
#保存续签
|
||||
self.write_log(public.getMsg("SAVEING_SSL"))
|
||||
self.write_log(public.get_msg_gettext('|-Saving certificate..'))
|
||||
cpath = self.setupPath + '/panel/vhost/cert/crontab.json'
|
||||
config = {}
|
||||
if os.path.exists(cpath):
|
||||
@@ -341,11 +341,11 @@ class panelLets:
|
||||
public.writeFile(path + "/README","let")
|
||||
|
||||
#计划任务续签
|
||||
self.write_log(public.getMsg("SET_AUTORENEW"))
|
||||
self.write_log(public.get_msg_gettext('|-Setting up auto-renewal configuration..'))
|
||||
self.set_crond()
|
||||
self.write_log(public.getMsg("DEPLOY_SSL_TO_SITE"))
|
||||
self.write_log(public.get_msg_gettext('|-The application is successful and it is being automatically deployed to the website!'))
|
||||
self.write_log("="*50)
|
||||
return public.returnMsg(True, 'APPLY_SSL_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Application successful.')
|
||||
|
||||
#创建计划任务
|
||||
def set_crond(self):
|
||||
@@ -380,15 +380,15 @@ class panelLets:
|
||||
|
||||
#手动解析记录值
|
||||
if not 'renew' in data:
|
||||
self.write_log(public.getMsg("INIT_ACME"))
|
||||
self.write_log(public.get_msg_gettext('|-Initializing ACME protocol...'))
|
||||
BTPanel.dns_client = sewer.Client(domain_name = data['first_domain'],dns_class = None,account_key = data['account_key'],domain_alt_names = data['domains'],contact_email = str(data['email']) ,ACME_AUTH_STATUS_WAIT_PERIOD = 15,ACME_AUTH_STATUS_MAX_CHECKS = 5,ACME_REQUEST_TIMEOUT = 20,ACME_DIRECTORY_URL = self.let_url)
|
||||
domain_dns_value = "placeholder"
|
||||
dns_names_to_delete = []
|
||||
self.write_log(public.getMsg("REGISTER_ACCOUNT"))
|
||||
self.write_log(public.get_msg_gettext('|-Registering account...'))
|
||||
BTPanel.dns_client.acme_register()
|
||||
authorizations, finalize_url = BTPanel.dns_client.apply_for_cert_issuance()
|
||||
responders = []
|
||||
self.write_log(public.getMsg("GET_VERIFICATION_INFO"))
|
||||
self.write_log(public.get_msg_gettext('|-Getting verification information...'))
|
||||
for url in authorizations:
|
||||
identifier_auth = BTPanel.dns_client.get_identifier_authorization(url)
|
||||
authorization_url = identifier_auth["url"]
|
||||
@@ -413,25 +413,25 @@ class panelLets:
|
||||
dns['dns_names'] = dns_names_to_delete
|
||||
dns['responders'] = responders
|
||||
dns['finalize_url'] = finalize_url
|
||||
self.write_log(public.getMsg("RETURN_VERIFICATION_INFO"))
|
||||
self.write_log(public.get_msg_gettext('|-Return the verification information to the front end, wait for the user to manually resolve the domain name and complete the verification...'))
|
||||
return dns
|
||||
else:
|
||||
self.write_log(public.getMsg("SUBMIT_V_REQUEST"))
|
||||
self.write_log(public.get_msg_gettext('|-User submits verification request...'))
|
||||
responders = data['dns']['responders']
|
||||
dns_names_to_delete = data['dns']['dns_names']
|
||||
finalize_url = data['dns']['finalize_url']
|
||||
for i in responders:
|
||||
self.write_log(public.getMsg("CA_V_DOMAIN",(i['dns_name'],)))
|
||||
self.write_log(public.get_msg_gettext('|-Requesting CA to verify domain name [{}]...',(i['dns_name'],)))
|
||||
auth_status_response = BTPanel.dns_client.check_authorization_status(i["authorization_url"])
|
||||
if auth_status_response.json()["status"] == "pending":
|
||||
BTPanel.dns_client.respond_to_challenge(i["acme_keyauthorization"], i["dns_challenge_url"])
|
||||
|
||||
for i in responders:
|
||||
self.write_log(public.getMsg("GET_CA_V_RES",(i['dns_name'],)))
|
||||
self.write_log(public.get_msg_gettext('|-Get CA verification results [{}]...',(i['dns_name'],)))
|
||||
BTPanel.dns_client.check_authorization_status(i["authorization_url"], ["valid","invalid"])
|
||||
self.write_log(public.getMsg("ALL_DOMAIN_V_PASS"))
|
||||
self.write_log(public.get_msg_gettext('|-All domain names are verified and CSR is being sent...'))
|
||||
certificate_url = BTPanel.dns_client.send_csr(finalize_url)
|
||||
self.write_log(public.getMsg("GET_CERT_CONTENT"))
|
||||
self.write_log(public.get_msg_gettext('|-Getting certificate content...'))
|
||||
certificate = BTPanel.dns_client.download_certificate(certificate_url)
|
||||
|
||||
if certificate:
|
||||
@@ -443,10 +443,10 @@ class panelLets:
|
||||
result['status'] = True
|
||||
BTPanel.dns_client = None
|
||||
else:
|
||||
result['msg'] = public.getMsg('CERT_APPLY_ERR')
|
||||
result['msg'] = public.get_msg_gettext('Certificate acquisition failed, please try again later.')
|
||||
|
||||
except Exception as e:
|
||||
self.write_log(public.getMsg("CERT_APPLY_ERR1",(e,)))
|
||||
self.write_log(public.get_msg_gettext('|-Error: {}, exited the application process.',(e,)))
|
||||
self.write_log("=" * 50)
|
||||
res = str(e).split('>>>>')
|
||||
err = False
|
||||
@@ -461,10 +461,10 @@ class panelLets:
|
||||
def crate_let_by_dns(self,data):
|
||||
dns_class = self.get_dns_class(data)
|
||||
if not dns_class:
|
||||
self.write_log(public.getMsg("DNS_APPLY_ERR"))
|
||||
self.write_log(public.getMsg("EXIT_APPLY_PROCESS"))
|
||||
self.write_log(public.get_msg_gettext('|-Error: {}, exit the application process.'))
|
||||
self.write_log(public.get_msg_gettext('|-Exited the application process!'))
|
||||
self.write_log("="*50)
|
||||
return public.returnMsg(False, 'DNS_APPLY_ERR1')
|
||||
return public.return_msg_gettext(False, 'An error occurred while requesting a certificate using dns')
|
||||
|
||||
result = {}
|
||||
result['status'] = False
|
||||
@@ -472,16 +472,16 @@ class panelLets:
|
||||
log_level = "INFO"
|
||||
if data['account_key']: log_level = 'ERROR'
|
||||
if not data['email']: data['email'] = public.M('users').getField('email')
|
||||
self.write_log(public.getMsg("INIT_ACME"))
|
||||
self.write_log(public.get_msg_gettext('|-Initializing ACME protocol...'))
|
||||
client = sewer.Client(domain_name = data['first_domain'],domain_alt_names = data['domains'],account_key = data['account_key'],contact_email = str(data['email']),LOG_LEVEL = log_level,ACME_AUTH_STATUS_WAIT_PERIOD = 15,ACME_AUTH_STATUS_MAX_CHECKS = 5,ACME_REQUEST_TIMEOUT = 20, dns_class = dns_class,ACME_DIRECTORY_URL = self.let_url)
|
||||
domain_dns_value = "placeholder"
|
||||
dns_names_to_delete = []
|
||||
try:
|
||||
self.write_log(public.getMsg("REGISTER_ACCOUNT"))
|
||||
self.write_log(public.get_msg_gettext('|-Registering account...'))
|
||||
client.acme_register()
|
||||
authorizations, finalize_url = client.apply_for_cert_issuance()
|
||||
responders = []
|
||||
self.write_log(public.getMsg("GET_VERIFICATION_INFO"))
|
||||
self.write_log(public.get_msg_gettext('|-Getting verification information...'))
|
||||
for url in authorizations:
|
||||
identifier_auth = client.get_identifier_authorization(url)
|
||||
authorization_url = identifier_auth["url"]
|
||||
@@ -489,7 +489,7 @@ class panelLets:
|
||||
dns_token = identifier_auth["dns_token"]
|
||||
dns_challenge_url = identifier_auth["dns_challenge_url"]
|
||||
acme_keyauthorization, domain_dns_value = client.get_keyauthorization(dns_token)
|
||||
self.write_log(public.getMsg("ADD_TXT_RECORD",(dns_name,domain_dns_value)))
|
||||
self.write_log(public.get_msg_gettext('|-Adding resolution record, domain name [{}], record value [{}]...',(dns_name,domain_dns_value)))
|
||||
dns_class.create_dns_record(public.de_punycode(dns_name), domain_dns_value)
|
||||
dns_names_to_delete.append({"dns_name": public.de_punycode(dns_name), "domain_dns_value": domain_dns_value})
|
||||
responders.append({"dns_name":dns_name,"domain_dns_value":domain_dns_value,"authorization_url": authorization_url, "acme_keyauthorization": acme_keyauthorization,"dns_challenge_url": dns_challenge_url} )
|
||||
@@ -498,33 +498,33 @@ class panelLets:
|
||||
|
||||
try:
|
||||
for i in responders:
|
||||
self.write_log(public.getMsg("CHECK_TXT_RECORD",(i['dns_name'],i['domain_dns_value'])))
|
||||
self.write_log(public.get_msg_gettext('|-Attempt to verify the resolution result, domain name [{}], record value [{}]...',(i['dns_name'],i['domain_dns_value'])))
|
||||
self.check_dns(self.get_acme_name(i['dns_name']),i['domain_dns_value'])
|
||||
self.write_log(public.getMsg("CA_CHECK_RECORD",(i['dns_name'])))
|
||||
self.write_log(public.get_msg_gettext('|-Request CA to verify domain name [{}]...',(i['dns_name'])))
|
||||
auth_status_response = client.check_authorization_status(i["authorization_url"])
|
||||
r_data = auth_status_response.json()
|
||||
if r_data["status"] == "pending":
|
||||
client.respond_to_challenge(i["acme_keyauthorization"], i["dns_challenge_url"])
|
||||
|
||||
for i in responders:
|
||||
self.write_log(public.getMsg("CHECK_CA_RES",(i['dns_name'],)))
|
||||
self.write_log(public.get_msg_gettext('|-Check CA verification results [{}]...',(i['dns_name'],)))
|
||||
client.check_authorization_status(i["authorization_url"], ["valid","invalid"])
|
||||
except Exception as ex:
|
||||
self.write_log(public.getMsg("APPLY_WITH_DNS_ERR",(str(ex),)))
|
||||
self.write_log(public.get_msg_gettext('|-An error occurred, try again [{}]',(str(ex),)))
|
||||
for i in responders:
|
||||
self.write_log(public.getMsg("CHECK_TXT_RECORD",(i['dns_name'],i['domain_dns_value'])))
|
||||
self.write_log(public.get_msg_gettext('|-Attempt to verify the resolution result, domain name [{}], record value [{}]...',(i['dns_name'],i['domain_dns_value'])))
|
||||
self.check_dns(self.get_acme_name(i['dns_name']),i['domain_dns_value'])
|
||||
self.write_log(public.getMsg("CA_CHECK_RECORD",(i['dns_name'])))
|
||||
self.write_log(public.get_msg_gettext('|-Request CA to verify domain name [{}]...',(i['dns_name'])))
|
||||
auth_status_response = client.check_authorization_status(i["authorization_url"])
|
||||
r_data = auth_status_response.json()
|
||||
if r_data["status"] == "pending":
|
||||
client.respond_to_challenge(i["acme_keyauthorization"], i["dns_challenge_url"])
|
||||
for i in responders:
|
||||
self.write_log(public.getMsg("CHECK_CA_RES",(i['dns_name'],)))
|
||||
self.write_log(public.get_msg_gettext('|-Check CA verification results [{}]...',(i['dns_name'],)))
|
||||
client.check_authorization_status(i["authorization_url"], ["valid","invalid"])
|
||||
self.write_log(public.getMsg("ALL_DOMAIN_V_PASS"))
|
||||
self.write_log(public.get_msg_gettext('|-All domain names are verified and CSR is being sent...'))
|
||||
certificate_url = client.send_csr(finalize_url)
|
||||
self.write_log(public.getMsg("FETCH_CERT_CONTENT"))
|
||||
self.write_log(public.get_msg_gettext('|-Fetching certificate content...'))
|
||||
certificate = client.download_certificate(certificate_url)
|
||||
if certificate:
|
||||
certificate = self.split_ca_data(certificate)
|
||||
@@ -539,7 +539,7 @@ class panelLets:
|
||||
finally:
|
||||
try:
|
||||
for i in dns_names_to_delete:
|
||||
self.write_log(public.getMsg("CLEAR_RESOLVE_HISTORY",(i["dns_name"])))
|
||||
self.write_log(public.get_msg_gettext('|-Clearing resolve history [{}]',(i["dns_name"])))
|
||||
dns_class.delete_dns_record(i["dns_name"], i["domain_dns_value"])
|
||||
except :
|
||||
pass
|
||||
@@ -547,10 +547,10 @@ class panelLets:
|
||||
except Exception as e:
|
||||
try:
|
||||
for i in dns_names_to_delete:
|
||||
self.write_log(public.getMsg("CLEAR_RESOLVE_HISTORY",(i["dns_name"])))
|
||||
self.write_log(public.get_msg_gettext('|-Clearing resolve history [{}]',(i["dns_name"])))
|
||||
dns_class.delete_dns_record(i["dns_name"], i["domain_dns_value"])
|
||||
except:pass
|
||||
self.write_log(public.getMsg("DNS_APPLY_ERR",(str(public.get_error_info()),)))
|
||||
self.write_log(public.get_msg_gettext('|-Error: {}, exit the application process.',(str(public.get_error_info()),)))
|
||||
self.write_log("=" * 50)
|
||||
res = str(e).split('>>>>')
|
||||
err = False
|
||||
@@ -566,17 +566,17 @@ class panelLets:
|
||||
result['status'] = False
|
||||
result['clecks'] = []
|
||||
try:
|
||||
self.write_log(public.getMsg("INIT_ACME"))
|
||||
self.write_log(public.get_msg_gettext('|-Initializing ACME protocol...'))
|
||||
log_level = "INFO"
|
||||
if data['account_key']: log_level = 'ERROR'
|
||||
if not data['email']: data['email'] = public.M('users').getField('email')
|
||||
client = sewer.Client(domain_name = data['first_domain'],dns_class = None,account_key = data['account_key'],domain_alt_names = data['domains'],contact_email = str(data['email']),LOG_LEVEL = log_level,ACME_AUTH_STATUS_WAIT_PERIOD = 15,ACME_AUTH_STATUS_MAX_CHECKS = 5,ACME_REQUEST_TIMEOUT = 20,ACME_DIRECTORY_URL = self.let_url)
|
||||
self.write_log(public.getMsg("REGISTER_ACCOUNT"))
|
||||
self.write_log(public.get_msg_gettext('|-Registering account...'))
|
||||
client.acme_register()
|
||||
authorizations, finalize_url = client.apply_for_cert_issuance()
|
||||
responders = []
|
||||
sucess_domains = []
|
||||
self.write_log(public.getMsg("GET_VERIFICATION_INFO"))
|
||||
self.write_log(public.get_msg_gettext('|-Getting verification information...'))
|
||||
for url in authorizations:
|
||||
identifier_auth = self.get_identifier_authorization(client,url)
|
||||
|
||||
@@ -591,21 +591,21 @@ class panelLets:
|
||||
|
||||
#写入token
|
||||
wellknown_path = acme_dir + '/' + http_token
|
||||
self.write_log(public.getMsg("CREATE_V_FILE",(wellknown_path,)))
|
||||
self.write_log(public.get_msg_gettext('|-Writing verification file [{}]...',(wellknown_path,)))
|
||||
public.writeFile(wellknown_path,acme_keyauthorization)
|
||||
wellknown_url = "http://{0}/.well-known/acme-challenge/{1}".format(http_name, http_token)
|
||||
wellknown_url = "http://{}/.well-known/acme-challenge/{}".format(http_name, http_token)
|
||||
|
||||
result['clecks'].append({'wellknown_url':wellknown_url,'http_token':http_token})
|
||||
is_check = False
|
||||
n = 0
|
||||
self.write_log(public.getMsg("CHECK_FILE_CONTENT",(wellknown_url)))
|
||||
self.write_log(public.get_msg_gettext('|-Attempt to verify file contents via HTTP [{}]...',(wellknown_url)))
|
||||
while n < 5:
|
||||
print("wait_check_authorization_status")
|
||||
try:
|
||||
retkey = public.httpGet(wellknown_url,20)
|
||||
if retkey == acme_keyauthorization:
|
||||
is_check = True
|
||||
self.write_log(public.getMsg("CHECK_FILE_CONTENT1",(retkey,)))
|
||||
self.write_log(public.get_msg_gettext('|-Verified, content [{}]...',(retkey,)))
|
||||
break
|
||||
except :
|
||||
pass
|
||||
@@ -617,18 +617,18 @@ class panelLets:
|
||||
if len(sucess_domains) > 0:
|
||||
#验证
|
||||
for i in responders:
|
||||
self.write_log(public.getMsg("CA_CHECK_RECORD",(i['http_name'],)))
|
||||
self.write_log(public.get_msg_gettext('|-Request CA to verify domain name [{}]...',(i['http_name'],)))
|
||||
auth_status_response = client.check_authorization_status(i["authorization_url"])
|
||||
if auth_status_response.json()["status"] == "pending":
|
||||
client.respond_to_challenge(i["acme_keyauthorization"], i["http_challenge_url"]).json()
|
||||
|
||||
for i in responders:
|
||||
self.write_log(public.getMsg("CHECK_CA_RES",(i['http_name'],)))
|
||||
self.write_log(public.get_msg_gettext('|-Check CA verification results [{}]...',(i['http_name'],)))
|
||||
client.check_authorization_status(i["authorization_url"], ["valid","invalid"])
|
||||
|
||||
self.write_log(public.getMsg("ALL_DOMAIN_V_PASS"))
|
||||
self.write_log(public.get_msg_gettext('|-All domain names are verified and CSR is being sent...'))
|
||||
certificate_url = client.send_csr(finalize_url)
|
||||
self.write_log(public.getMsg("GET_CERT_CONTENT"))
|
||||
self.write_log(public.get_msg_gettext('|-Getting certificate content...'))
|
||||
certificate = client.download_certificate(certificate_url)
|
||||
|
||||
if certificate:
|
||||
@@ -640,11 +640,11 @@ class panelLets:
|
||||
result['status'] = True
|
||||
|
||||
else:
|
||||
result['msg'] = public.getMsg('CERT_APPLY_ERR')
|
||||
result['msg'] = public.get_msg_gettext('Certificate acquisition failed, please try again later.')
|
||||
else:
|
||||
result['msg'] = public.getMsg("APPLY_SSL_ERROR_MSG")
|
||||
result['msg'] = public.get_msg_gettext('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>')
|
||||
except Exception as e:
|
||||
self.write_log(public.getMsg("DNS_APPLY_ERR",(str(public.get_error_info()),)))
|
||||
self.write_log(public.get_msg_gettext('|-Error: {}, exit the application process.',(str(public.get_error_info()),)))
|
||||
self.write_log("=" * 50)
|
||||
res = str(e).split('>>>>')
|
||||
err = False
|
||||
@@ -693,7 +693,7 @@ class panelLets:
|
||||
for i in j.items:
|
||||
txt_value = i.to_text().replace('"','').strip()
|
||||
if txt_value == value:
|
||||
self.write_log(public.getMsg("SUCCESS_V",(domain,type,txt_value)))
|
||||
self.write_log(public.get_msg_gettext('|-Successful verification, domain name [{}], record type [{}], record value [{}]!',(domain,type,txt_value)))
|
||||
print("Verification succeeded: %s" % txt_value)
|
||||
return True
|
||||
except:
|
||||
@@ -753,18 +753,18 @@ class panelLets:
|
||||
def renew_lets_ssl(self):
|
||||
cpath = self.setupPath + '/panel/vhost/cert/crontab.json'
|
||||
if not os.path.exists(cpath):
|
||||
print(public.getMsg("NO_ORDER_RENEW") )
|
||||
print(public.get_msg_gettext('|-There are currently no certificates to renew.') )
|
||||
else:
|
||||
old_list = json.loads(public.ReadFile(cpath))
|
||||
print('=======================================================================')
|
||||
print(public.getMsg('TOTAL_RENEW',(time.strftime('%Y-%m-%d %X',time.localtime()),str(len(old_list)))))
|
||||
print(public.get_msg_gettext('|-{} Total [{}] renewal of visa tasks',(time.strftime('%Y-%m-%d %X',time.localtime()),str(len(old_list)))))
|
||||
cron_list = self.get_renew_lets_bytimeout(old_list)
|
||||
|
||||
tlist = []
|
||||
for siteName in old_list:
|
||||
if not siteName in cron_list: tlist.append(siteName)
|
||||
print(public.getMsg('SSL_NOT_EXPIRED_OR_NOT_USE',(','.join(tlist),)))
|
||||
print(public.getMsg('WAIT_RENEW1',(time.strftime('%Y-%m-%d %X',time.localtime()),str(len(cron_list)))))
|
||||
print(public.get_msg_gettext('|-[{}] Not expired or the site does not use the Let\s Encrypt certificate.',(','.join(tlist),)))
|
||||
print(public.get_msg_gettext('|-{} Waiting for renewal [{}].',(time.strftime('%Y-%m-%d %X',time.localtime()),str(len(cron_list)))))
|
||||
|
||||
sucess_list = []
|
||||
err_list = []
|
||||
@@ -775,11 +775,11 @@ class panelLets:
|
||||
sucess_list.append(siteName)
|
||||
else:
|
||||
err_list.append({"siteName":siteName,"msg":ret['msg']})
|
||||
print(public.getMsg("RENEW_COMPLETED",(str(len(cron_list)),str(len(sucess_list)),str(len(err_list)))))
|
||||
print(public.get_msg_gettext('|-After the task is completed, a total of renewals are required.[{}], renewal success [%s], renewal failed [{}]. ',(str(len(cron_list)),str(len(sucess_list)),str(len(err_list)))))
|
||||
if len(sucess_list) > 0:
|
||||
print(public.getMsg("RENEW_SUCCESS2",(','.join(sucess_list),)))
|
||||
print(public.get_msg_gettext('|-Renewal success:{}',(','.join(sucess_list),)))
|
||||
if len(err_list) > 0:
|
||||
print(public.getMsg("RENEW_FAILED2"))
|
||||
print(public.get_msg_gettext('|-Renewal failed:'))
|
||||
for x in err_list:
|
||||
print(" %s ->> %s" % (x['siteName'],x['msg']))
|
||||
|
||||
|
||||
@@ -44,33 +44,36 @@ class panelMessage:
|
||||
|
||||
|
||||
"""
|
||||
获取官网推送消息,一小时获取一次
|
||||
获取官网推送消息,一天获取一次
|
||||
"""
|
||||
def get_cloud_messages(self,args):
|
||||
#ret = cache.get('get_cloud_messages')
|
||||
#if ret: return public.returnMsg(True,'同步成功1!')
|
||||
data = {}
|
||||
data['version'] = public.version()
|
||||
data['os'] = self.os
|
||||
sUrl = public.GetConfigValue('home') + '/api/wpanel/get_messages'
|
||||
import http_requests
|
||||
http_requests.DEFAULT_TYPE = 'src'
|
||||
info = http_requests.post(sUrl,data).json()
|
||||
# info = json.loads(public.httpPost(sUrl,data))
|
||||
for x in info:
|
||||
count = public.M('messages').where('level=? and msg=?',(x['level'],x['msg'],)).count()
|
||||
if count: continue
|
||||
try:
|
||||
ret = cache.get('get_cloud_messages')
|
||||
if ret: return public.returnMsg(True,'同步成功1!')
|
||||
data = {}
|
||||
data['version'] = public.version()
|
||||
data['os'] = self.os
|
||||
sUrl = public.GetConfigValue('home') + '/api/wpanel/get_messages'
|
||||
import http_requests
|
||||
http_requests.DEFAULT_TYPE = 'src'
|
||||
info = http_requests.post(sUrl,data).json()
|
||||
# info = json.loads(public.httpPost(sUrl,data))
|
||||
for x in info:
|
||||
count = public.M('messages').where('level=? and msg=?',(x['level'],x['msg'],)).count()
|
||||
if count: continue
|
||||
|
||||
pdata = {
|
||||
"level":x['level'],
|
||||
"msg":x['msg'],
|
||||
"state":1,
|
||||
"expire":int(time.time()) + (int(x['expire']) * 86400),
|
||||
"addtime": int(time.time())
|
||||
}
|
||||
public.M('messages').insert(pdata)
|
||||
#cache.set('get_cloud_messages',3600)
|
||||
return public.returnMsg(True,'同步成功!')
|
||||
pdata = {
|
||||
"level":x['level'],
|
||||
"msg":x['msg'],
|
||||
"state":1,
|
||||
"expire":int(time.time()) + (int(x['expire']) * 86400),
|
||||
"addtime": int(time.time())
|
||||
}
|
||||
public.M('messages').insert(pdata)
|
||||
cache.set('get_cloud_messages',86400)
|
||||
return public.returnMsg(True,'同步成功!')
|
||||
except:
|
||||
return public.returnMsg(False,'同步失败!')
|
||||
|
||||
def get_messages(self,args = None):
|
||||
'''
|
||||
@@ -78,7 +81,7 @@ class panelMessage:
|
||||
@author hwliang <2020-05-18>
|
||||
@return list
|
||||
'''
|
||||
self.get_cloud_messages(args)
|
||||
public.run_thread(self.get_cloud_messages,args=(args,))
|
||||
data = public.M('messages').where('state=? and expire>?',(1,int(time.time()))).order("id desc").select()
|
||||
return data
|
||||
|
||||
@@ -88,7 +91,7 @@ class panelMessage:
|
||||
@author hwliang <2020-05-18>
|
||||
@return list
|
||||
'''
|
||||
self.get_cloud_messages(args)
|
||||
public.run_thread(self.get_cloud_messages,args=(args,))
|
||||
data = public.M('messages').order("id desc").select()
|
||||
return data
|
||||
|
||||
|
||||
@@ -22,7 +22,13 @@ class panelMysql:
|
||||
def __Conn(self):
|
||||
if self.__DB_NET: return True
|
||||
try:
|
||||
socket = '/tmp/mysql.sock'
|
||||
myconf = public.readFile('/etc/my.cnf')
|
||||
socket_re = re.search(r"socket\s*=\s*(.+)",myconf)
|
||||
if socket_re:
|
||||
socket = socket_re.groups()[0]
|
||||
else:
|
||||
socket = '/tmp/mysql.sock'
|
||||
|
||||
try:
|
||||
if sys.version_info[0] != 2:
|
||||
try:
|
||||
@@ -34,7 +40,7 @@ class panelMysql:
|
||||
import MySQLdb
|
||||
if sys.version_info[0] == 2:
|
||||
reload(MySQLdb)
|
||||
except Exception as ex:
|
||||
except:
|
||||
try:
|
||||
import pymysql
|
||||
pymysql.install_as_MySQLdb()
|
||||
@@ -43,7 +49,7 @@ class panelMysql:
|
||||
self.__DB_ERR = e
|
||||
return False
|
||||
try:
|
||||
myconf = public.readFile('/etc/my.cnf')
|
||||
|
||||
rep = r"port\s*=\s*([0-9]+)"
|
||||
self.__DB_PORT = int(re.search(rep,myconf).groups()[0])
|
||||
except:
|
||||
@@ -65,12 +71,34 @@ class panelMysql:
|
||||
def connect_network(self,host,port,username,password):
|
||||
self.__DB_NET = True
|
||||
try:
|
||||
try:
|
||||
if sys.version_info[0] != 2:
|
||||
try:
|
||||
import pymysql
|
||||
except:
|
||||
public.ExecShell("pip install pymysql")
|
||||
import pymysql
|
||||
pymysql.install_as_MySQLdb()
|
||||
import MySQLdb
|
||||
if sys.version_info[0] == 2:
|
||||
reload(MySQLdb)
|
||||
except:
|
||||
try:
|
||||
import pymysql
|
||||
pymysql.install_as_MySQLdb()
|
||||
import MySQLdb
|
||||
except Exception as e:
|
||||
self.__DB_ERR = e
|
||||
return False
|
||||
self.__DB_CONN = MySQLdb.connect(host = host,user = username,passwd = password,port = port,charset="utf8",connect_timeout=10)
|
||||
self.__DB_CUR = self.__DB_CONN.cursor()
|
||||
return True
|
||||
except MySQLdb.Error as e:
|
||||
self.__DB_ERR = e
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def execute(self,sql):
|
||||
#执行SQL语句返回受影响行
|
||||
if not self.__Conn(): return self.__DB_ERR
|
||||
@@ -99,6 +127,7 @@ class panelMysql:
|
||||
except Exception as ex:
|
||||
return ex
|
||||
|
||||
|
||||
#关闭连接
|
||||
def __Close(self):
|
||||
self.__DB_CUR.close()
|
||||
|
||||
@@ -61,15 +61,8 @@ class panelPHP:
|
||||
data = {}
|
||||
data['GET'] = request.args.to_dict()
|
||||
data['POST'] = {}
|
||||
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():
|
||||
data['POST'][key] = str(request.form.get(key,''))
|
||||
if x_token:
|
||||
if len(data['POST'][key]) > 5:
|
||||
if data['POST'][key][:6] == 'BT-CRT':
|
||||
data['POST'][key] = public.aes_decrypt(data['POST'][key][6:],aes_pwd)
|
||||
data['POST']['client_ip'] = public.GetClientIp()
|
||||
data = json.dumps(data)
|
||||
public.writeFile(self.__args_tmp,data)
|
||||
@@ -93,7 +86,7 @@ class panelPHP:
|
||||
php_vs = json.loads(public.readFile(php_v_file).replace('.',''))
|
||||
else:
|
||||
#否则兼容所有版本
|
||||
php_vs = ["80","74","73","72","71","70","56","55","54","53","52"]
|
||||
php_vs = public.get_php_versions(True)
|
||||
#判段兼容的PHP版本是否安装
|
||||
php_path = "/www/server/php/"
|
||||
php_v = None
|
||||
@@ -125,7 +118,7 @@ class panelPHP:
|
||||
else:
|
||||
php_vs = sorted(php_version,reverse=True)
|
||||
else:
|
||||
php_vs = ["80","74","73","72","71","70","56","55","54","53","52"]
|
||||
php_vs = public.get_php_versions(True)
|
||||
php_path = "/www/server/php/"
|
||||
php_v = None
|
||||
for pv in php_vs:
|
||||
@@ -601,7 +594,7 @@ class FPM(object):
|
||||
'DOCUMENT_ROOT': self.document_root,
|
||||
'SERVER_PROTOCOL' : 'HTTP/1.1',
|
||||
'REMOTE_ADDR': '127.0.0.1',
|
||||
'REMOTE_PORT': '7800',
|
||||
'REMOTE_PORT': '8888',
|
||||
'SERVER_ADDR': '127.0.0.1',
|
||||
'SERVER_PORT': '80',
|
||||
'SERVER_NAME': 'BT-Panel'
|
||||
|
||||
@@ -29,11 +29,11 @@ class ProjectController:
|
||||
}
|
||||
'''
|
||||
try: # 表单验证
|
||||
if args['mod_name'] in ['base']: return public.return_status_code(1000,'错误的调用!')
|
||||
if args['mod_name'] in ['base']: return public.return_status_code(1000,'wrong call!')
|
||||
public.exists_args('def_name,mod_name',args)
|
||||
if args['def_name'].find('__') != -1: return public.return_status_code(1000,'调用的方法名称中不能包含“__”字符')
|
||||
if not re.match(r"^\w+$",args['mod_name']): return public.return_status_code(1000,'调用的模块名称中不能包含\w以外的字符')
|
||||
if not re.match(r"^\w+$",args['def_name']): return public.return_status_code(1000,'调用的方法名称中不能包含\w以外的字符')
|
||||
if args['def_name'].find('__') != -1: return public.return_status_code(1000,'Called method name cannot contain [ __ ] characters')
|
||||
if not re.match(r"^\w+$",args['mod_name']): return public.return_status_code(1000,'The called module name cannot contain characters other than \w')
|
||||
if not re.match(r"^\w+$",args['def_name']): return public.return_status_code(1000,'The called module name cannot contain characters other than \w')
|
||||
except:
|
||||
return public.get_error_object()
|
||||
# 参数处理
|
||||
@@ -59,7 +59,7 @@ class ProjectController:
|
||||
else:
|
||||
pdata = args.data
|
||||
else:
|
||||
pdata = public.dict_obj()
|
||||
pdata = args
|
||||
|
||||
# 前置HOOK
|
||||
hook_index = '{}_{}_LAST'.format(mod_name.upper(),def_name.upper())
|
||||
|
||||
@@ -83,7 +83,7 @@ class panelRedirect:
|
||||
else:
|
||||
sk.connect((d, 443))
|
||||
except:
|
||||
return public.returnMsg(False, "CANT_GET_URL")
|
||||
return public.return_msg_gettext(False, 'Can NOT get target URL')
|
||||
# 计算proxyname md5
|
||||
def __calc_md5(self,redirectname):
|
||||
import hashlib
|
||||
@@ -112,7 +112,7 @@ class panelRedirect:
|
||||
if get.sitename in sitenamelist:
|
||||
rep = "include.*\/redirect\/.*\*.conf;"
|
||||
if not re.search(rep,ng_conf):
|
||||
ng_conf = ng_conf.replace("#SSL-END","#SSL-END\n\t%s\n\t" % public.GetMsg("NGINX_REDIRECT_REP") + "include " + ng_redirectfile + ";")
|
||||
ng_conf = ng_conf.replace("#SSL-END","#SSL-END\n\t%s\n\t" % public.get_msg_gettext('#referenced redirect rule, if commented, the configured redirect rule will be invalid') + "include " + ng_redirectfile + ";")
|
||||
public.writeFile(ng_file,ng_conf)
|
||||
|
||||
else:
|
||||
@@ -130,18 +130,18 @@ class panelRedirect:
|
||||
if os.path.exists(ap_file):
|
||||
ap_conf = public.readFile(ap_file)
|
||||
if p_conf == "[]":
|
||||
rep = "\n*%s\n+\s+IncludeOptiona[\s\w\/\.\*]+" % public.GetMsg("NGINX_REDIRECT_REP")
|
||||
rep = "\n*%s\n+\s+IncludeOptiona[\s\w\/\.\*]+" % public.get_msg_gettext('#referenced redirect rule, if commented, the configured redirect rule will be invalid')
|
||||
ap_conf = re.sub(rep, '', ap_conf)
|
||||
public.writeFile(ap_file, ap_conf)
|
||||
return
|
||||
if sitename in p_conf:
|
||||
rep = "%s(\n|.)+IncludeOptional.*\/redirect\/.*conf" % public.GetMsg("NGINX_REDIRECT_REP1")
|
||||
rep = "%s(\n|.)+IncludeOptional.*\/redirect\/.*conf" % public.get_msg_gettext('#referenced redirect rule')
|
||||
rep1 = "combined"
|
||||
if not re.search(rep,ap_conf):
|
||||
ap_conf = ap_conf.replace(rep1, rep1 + "\n\t%s" % public.GetMsg("NGINX_REDIRECT_REP") +"\n\tIncludeOptional " + ap_redirectfile)
|
||||
ap_conf = ap_conf.replace(rep1, rep1 + "\n\t%s" % public.get_msg_gettext('#referenced redirect rule, if commented, the configured redirect rule will be invalid') +"\n\tIncludeOptional " + ap_redirectfile)
|
||||
public.writeFile(ap_file,ap_conf)
|
||||
else:
|
||||
rep = "\n*%s\n+\s+IncludeOptiona[\s\w\/\.\*]+" % public.GetMsg("NGINX_REDIRECT_REP")
|
||||
rep = "\n*%s\n+\s+IncludeOptiona[\s\w\/\.\*]+" % public.get_msg_gettext('#referenced redirect rule, if commented, the configured redirect rule will be invalid')
|
||||
ap_conf = re.sub(rep,'', ap_conf)
|
||||
public.writeFile(ap_file, ap_conf)
|
||||
|
||||
@@ -149,52 +149,52 @@ class panelRedirect:
|
||||
def __CheckRedirectStart(self,get,action=""):
|
||||
isError = public.checkWebConfig()
|
||||
if (isError != True):
|
||||
return public.returnMsg(False, 'GET_ERR_IN_CONFILE')
|
||||
return public.return_msg_gettext(False, 'An error was detected in the configuration file. Please solve it before proceeding')
|
||||
if action == "create":
|
||||
#检测名称是否重复
|
||||
if sys.version_info.major < 3:
|
||||
if len(get.redirectname) < 3 or len(get.redirectname) > 15:
|
||||
return public.returnMsg(False, 'NAME_LEN')
|
||||
return public.return_msg_gettext(False, 'Database name cannot be more than 16 characters!')
|
||||
else:
|
||||
if len(get.redirectname.encode("utf-8")) < 3 or len(get.redirectname.encode("utf-8")) > 15:
|
||||
return public.returnMsg(False, 'NAME_LEN')
|
||||
return public.return_msg_gettext(False, 'Database name cannot be more than 16 characters!')
|
||||
if self.__CheckRedirect(get.sitename,get.redirectname):
|
||||
return public.returnMsg(False, 'REDIRECT_EXIST')
|
||||
return public.return_msg_gettext(False, 'Specified redirect name already exists')
|
||||
#检测是否选择域名
|
||||
if get.domainorpath == "domain":
|
||||
if not json.loads(get.redirectdomain):
|
||||
return public.returnMsg(False, 'SELECT_RED_DOMAIN')
|
||||
return public.return_msg_gettext(False, 'Please select redirected domain')
|
||||
else:
|
||||
if not get.redirectpath:
|
||||
return public.returnMsg(False, 'INPUT_RED_DOMAIN')
|
||||
return public.return_msg_gettext(False, 'Please enter redirected path')
|
||||
#repte = "[\?\=\[\]\)\(\*\&\^\%\$\#\@\!\~\`{\}\>\<\,\',\"]+"
|
||||
# 检测路径格式
|
||||
if "/" not in get.redirectpath:
|
||||
return public.returnMsg(False, "PATH_ERR")
|
||||
return public.return_msg_gettext(False, 'Path format is incorrect, the format is /xxx')
|
||||
#if re.search(repte, get.redirectpath):
|
||||
# return public.returnMsg(False, "代理目录不能有以下特殊符号 ?,=,[,],),(,*,&,^,%,$,#,@,!,~,`,{,},>,<,\,',\"]")
|
||||
# return public.return_msg_gettext(False, "代理目录不能有以下特殊符号 ?,=,[,],),(,*,&,^,%,$,#,@,!,~,`,{,},>,<,\,',\"]")
|
||||
#检测域名是否已经存在配置文件
|
||||
repeatdomain = self.__CheckRepeatDomain(get,action)
|
||||
if repeatdomain:
|
||||
return public.returnMsg(False, 'RED_DOMAIN_EXIST' , (repeatdomain,))
|
||||
return public.return_msg_gettext(False, 'Redirected domain already exists {}' , (repeatdomain,))
|
||||
#检测路径是否有存在配置文件
|
||||
repeatpath = self.__CheckRepeatPath(get)
|
||||
if repeatpath:
|
||||
return public.returnMsg(False, 'RED_DOMAIN_EXIST' , (repeatpath,))
|
||||
return public.return_msg_gettext(False, 'Redirected domain already exists {}' , (repeatpath,))
|
||||
#检测目标URL格式
|
||||
rep = "http(s)?\:\/\/([a-zA-Z0-9][-a-zA-Z0-9]{0,62}\.)+([a-zA-Z0-9][a-zA-Z0-9]{0,62})+.?"
|
||||
if not re.match(rep, get.tourl):
|
||||
return public.returnMsg(False, 'URL_FORMAT_ERR' ,(get.tourl,))
|
||||
return public.return_msg_gettext(False, 'The target URL format is incorrect {}' ,(get.tourl,))
|
||||
#检测目标URL是否可用
|
||||
#if self.__CheckRedirectUrl(get):
|
||||
# return public.returnMsg(False, '目标URL无法访问')
|
||||
# return public.return_msg_gettext(False, '目标URL无法访问')
|
||||
|
||||
#检查目标URL的域名和被重定向的域名是否一样
|
||||
if get.domainorpath == "domain":
|
||||
for d in json.loads(get.redirectdomain):
|
||||
tu = self.GetToDomain(get.tourl)
|
||||
if d == tu:
|
||||
return public.returnMsg(False,public.GetMsg("DOMAIN_SAMEAS_URL",(d,)))
|
||||
return public.return_msg_gettext(False,public.get_msg_gettext('Domain name {} is the same as the target domain name, please deselect it',(d,)))
|
||||
|
||||
if get.domainorpath == "path":
|
||||
domains = self.GetAllDomain(get.sitename)
|
||||
@@ -203,7 +203,7 @@ class panelRedirect:
|
||||
for d in domains:
|
||||
ad = "%s%s" % (d,get.redirectpath) #站点域名+重定向路径
|
||||
if tu == ad:
|
||||
return public.GetMsg("URL_SAMEAS_REDPATH",(tu,))
|
||||
return public.get_msg_gettext('{}, the target URL is the same as the redirected path',(tu,))
|
||||
#创建重定向
|
||||
def CreateRedirect(self,get):
|
||||
|
||||
@@ -226,7 +226,7 @@ class panelRedirect:
|
||||
self.SetRedirectApache(get.sitename)
|
||||
self.SetRedirect(get)
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True, 'CREATE_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Successfully created file!')
|
||||
|
||||
# 设置重定向
|
||||
def SetRedirect(self,get):
|
||||
@@ -331,7 +331,7 @@ class panelRedirect:
|
||||
for i in range(len(p_conf) - 1, -1, -1):
|
||||
if get.sitename == p_conf[i]["sitename"] and p_conf[i]["redirectname"]:
|
||||
del(p_conf[i])
|
||||
return public.returnMsg(False, '%s<br><a style="color:red;">' % public.GetMsg("HAVE_ERR") + isError.replace("\n",'<br>') + '</a>')
|
||||
return public.return_msg_gettext(False, '%s<br><a style="color:red;">' % public.get_msg_gettext('Sorry, something went wrong') + isError.replace("\n",'<br>') + '</a>')
|
||||
|
||||
else:
|
||||
redirectname_md5 = self.__calc_md5(get.redirectname)
|
||||
@@ -361,7 +361,7 @@ class panelRedirect:
|
||||
self.SetRedirectApache(get.sitename)
|
||||
if not hasattr(get,'notreload'):
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True, 'EDIT_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Setup successfully!')
|
||||
|
||||
def del_redirect_multiple(self,get):
|
||||
'''
|
||||
@@ -384,9 +384,9 @@ class panelRedirect:
|
||||
continue
|
||||
del_successfully.append(redirectname)
|
||||
except:
|
||||
del_failed[redirectname]=public.getMsg('DEL_ERROR1')
|
||||
del_failed[redirectname]=public.get_msg_gettext('There was an error deleting, please try again.')
|
||||
public.serviceReload()
|
||||
return {'status': True, 'msg': public.getMsg('DEL_REDIRECT_MULTIPLE',(','.join(del_successfully),)), 'error': del_failed,
|
||||
return {'status': True, 'msg': public.get_msg_gettext('Delete redirects [{}] successfully',(','.join(del_successfully),)), 'error': del_failed,
|
||||
'success': del_successfully}
|
||||
|
||||
def DeleteRedirect(self,get,multiple=None):
|
||||
@@ -404,7 +404,7 @@ class panelRedirect:
|
||||
self.SetRedirectApache(get.sitename)
|
||||
if not multiple:
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True, 'DEL_SUCCESS')
|
||||
return public.return_msg_gettext(True, 'Successfully deleted')
|
||||
|
||||
def GetRedirectList(self,get):
|
||||
redirectconf = self.__read_config(self.__redirectfile)
|
||||
@@ -433,7 +433,7 @@ class panelRedirect:
|
||||
# get.redirectpath = "/"
|
||||
# get.redirectdomain = "[]"
|
||||
# get.sitename = sitename
|
||||
# get.redirectname = public.GetMsg("OLD_CONF")
|
||||
# get.redirectname = public.get_msg_gettext('Old configuration')
|
||||
# get.type = 1
|
||||
# get.holdpath = 1
|
||||
|
||||
@@ -470,7 +470,7 @@ class panelRedirect:
|
||||
conf = re.sub(rep, "", old_conf)
|
||||
public.writeFile(conf_path, conf)
|
||||
public.serviceReload()
|
||||
return public.returnMsg(False, 'CLEAR_OLD_RED')
|
||||
return public.return_msg_gettext(False, 'Old redirection cleaned')
|
||||
|
||||
# 取重定向配置文件
|
||||
def GetRedirectFile(self,get):
|
||||
@@ -484,7 +484,7 @@ class panelRedirect:
|
||||
get.path = "%s/panel/vhost/%s/redirect/%s/%s_%s.conf" % (self.setupPath, get.webserver, sitename,proxyname_md5,sitename)
|
||||
for i in conf:
|
||||
if redirectname == i["redirectname"] and sitename == i["sitename"] and i["type"] != 1:
|
||||
return public.returnMsg(False, 'RED_ALREADY_STOP')
|
||||
return public.return_msg_gettext(False, 'Redirection suspended')
|
||||
f = files.files()
|
||||
return f.GetFileBody(get),get.path
|
||||
|
||||
@@ -493,7 +493,7 @@ class panelRedirect:
|
||||
import files
|
||||
f = files.files()
|
||||
return f.SaveFileBody(get)
|
||||
# return public.returnMsg(True, '保存成功')
|
||||
# return public.return_msg_gettext(True, '保存成功')
|
||||
|
||||
def __CheckRedirect(self,sitename,redirectname):
|
||||
conf_data = self.__read_config(self.__redirectfile)
|
||||
|
||||
@@ -20,7 +20,7 @@ class panelRun:
|
||||
__run_config_path = '{}/config/run_config'.format(__panel_path)
|
||||
__run_pids_path = '{}/logs/run_pids'.format(__panel_path)
|
||||
__run_logs_path = '{}/logs/run_logs'.format(__panel_path)
|
||||
__log_name = '开机启动项'
|
||||
__log_name = 'Startup items'
|
||||
|
||||
|
||||
def __init__(self):
|
||||
@@ -69,7 +69,7 @@ class panelRun:
|
||||
if get: run_name = get['run_name']
|
||||
run_file = '{}/{}'.format(self.__run_config_path,run_name)
|
||||
if not os.path.isfile(run_file):
|
||||
return public.returnMsg(False,'启动配置不存在!')
|
||||
return public.return_msg_gettext(False,'Configuration file not exist')
|
||||
|
||||
run_info = json.loads(public.readFile(run_file))
|
||||
return run_info
|
||||
@@ -98,14 +98,14 @@ class panelRun:
|
||||
run_script_args = get['run_script_args']
|
||||
run_env = json.loads(get['run_env'])
|
||||
if not os.path.exists(run_path):
|
||||
return public.returnMsg(False,'指定运行目录{}不存在!'.format(run_path))
|
||||
return public.return_msg_gettext(False,'The specified run directory {} does not exist!'.format(run_path))
|
||||
|
||||
if not re.match(r'^\w+$',run_name):
|
||||
return public.returnMsg(False, '启动项名称格式不正确,支持:[a-zA-Z0-9_]!')
|
||||
return public.return_msg_gettext(False, 'The startup item name format is incorrect, support: [a-zA-Z0-9_]!')
|
||||
|
||||
run_file = '{}/{}'.format(self.__run_config_path,run_name)
|
||||
if os.path.exists(run_file):
|
||||
return public.returnMsg(False,'启动配置已存在!')
|
||||
return public.return_msg_gettext(False,'Launch configuration already exists!')
|
||||
|
||||
run_info = {
|
||||
'run_title': run_title,
|
||||
@@ -117,8 +117,8 @@ class panelRun:
|
||||
}
|
||||
run_info = json.dumps(run_info)
|
||||
public.writeFile(run_file,run_info)
|
||||
public.WriteLog(self.__log_name,'创建启动项[]成功!'.format(run_title))
|
||||
return public.returnMsg(True,'创建成功!')
|
||||
public.write_log_gettext(self.__log_name,'Create startup item [] successful!'.format(run_title))
|
||||
return public.return_msg_gettext(True,'Successfully created')
|
||||
|
||||
|
||||
def modify_run(self,get):
|
||||
@@ -145,15 +145,15 @@ class panelRun:
|
||||
run_env = json.loads(get['run_env'])
|
||||
|
||||
if not os.path.exists(run_path):
|
||||
return public.returnMsg(False,'指定运行目录{}不存在!'.format(run_path))
|
||||
return public.return_msg_gettext(False,'The specified run directory {} does not exist!',(run_path,))
|
||||
|
||||
if not re.match(r'^\w+$',run_name):
|
||||
return public.returnMsg(False, '启动项名称格式不正确,支持:[a-zA-Z0-9_]!')
|
||||
return public.return_msg_gettext(False, 'The startup item name format is incorrect, support: [a-zA-Z0-9_]!')
|
||||
|
||||
|
||||
run_file = '{}/{}'.format(self.__run_config_path,run_name)
|
||||
if not os.path.exists(run_file):
|
||||
return public.returnMsg(False,'启动配置不存在!')
|
||||
return public.return_msg_gettext(False,'The launch configuration does not exist!')
|
||||
|
||||
run_info = json.loads(public.readFile(run_file))
|
||||
run_info['run_title'] = run_title
|
||||
@@ -162,8 +162,8 @@ class panelRun:
|
||||
run_info['run_env'] = run_env
|
||||
run_info = json.dumps(run_info)
|
||||
public.writeFile(run_file,run_info)
|
||||
public.WriteLog(self.__log_name,'修改启动项[]成功!'.format(run_title))
|
||||
return public.returnMsg(True,'修改成功!')
|
||||
public.write_log_gettext(self.__log_name,'Modify startup item [{}] successful!',(run_title,))
|
||||
return public.return_msg_gettext(True,'Successfully modified')
|
||||
|
||||
|
||||
def remove_run(self,get):
|
||||
@@ -178,11 +178,11 @@ class panelRun:
|
||||
run_name = get['run_name']
|
||||
run_file = '{}/{}'.format(self.__run_config_path,run_name)
|
||||
if not os.path.isfile(run_file):
|
||||
return public.returnMsg(False,'启动配置不存在!')
|
||||
return public.return_msg_gettext(False,'The launch configuration does not exist!')
|
||||
|
||||
os.remove(run_file)
|
||||
public.WriteLog(self.__log_name,'删除启动项[]成功!'.format(run_name))
|
||||
return public.returnMsg(True,'删除成功!')
|
||||
public.write_log_gettext(self.__log_name,'Delete startup item [{}] successful!',(run_name,))
|
||||
return public.return_msg_gettext(True,'successfully deleted')
|
||||
|
||||
def set_run_status(self,get):
|
||||
'''
|
||||
@@ -199,14 +199,14 @@ class panelRun:
|
||||
|
||||
run_file = '{}/{}'.format(self.__run_config_path,run_name)
|
||||
if not os.path.isfile(run_file):
|
||||
return public.returnMsg(False,'启动配置不存在!')
|
||||
return public.return_msg_gettext(False,'launch configuration does not exist!')
|
||||
|
||||
run_info = json.loads(public.readFile(run_file))
|
||||
run_info['run_status'] = run_status
|
||||
run_info = json.dumps(run_info)
|
||||
public.writeFile(run_file,run_info)
|
||||
public.WriteLog(self.__log_name,'设置启动项[]状态成功!'.format(run_info['title']))
|
||||
return public.returnMsg(True,'设置成功!')
|
||||
public.write_log_gettext(self.__log_name,'Setting startup item [{}] status succeeded!',(run_info['title'],))
|
||||
return public.return_msg_gettext(True,'Setup successfully!')
|
||||
|
||||
|
||||
def stop_run(self,run_name = None):
|
||||
@@ -219,7 +219,7 @@ class panelRun:
|
||||
pid = self.get_run_pid(run_name)
|
||||
if not pid: return True
|
||||
os.kill(pid,signal.SIGKILL)
|
||||
public.WriteLog(self.__log_name,'关闭启动项[]成功!'.format(run_name))
|
||||
public.write_log_gettext(self.__log_name,'Close startup item [{}] successful!',(run_name,))
|
||||
return True
|
||||
|
||||
|
||||
@@ -267,9 +267,9 @@ class panelRun:
|
||||
@return dict
|
||||
'''
|
||||
pid = self.get_run_pid(run_name)
|
||||
if not pid: return public.returnMsg(False,'未启动')
|
||||
if not pid: return public.return_msg_gettext(False,'Not run')
|
||||
process_info = self.get_process_info(pid)
|
||||
if not process_info: return public.returnMsg(False,'无法获取进程信息')
|
||||
if not process_info: return public.return_msg_gettext(False,'Unable to get process information')
|
||||
return process_info
|
||||
|
||||
def get_process_info(self,pid):
|
||||
@@ -281,7 +281,7 @@ class panelRun:
|
||||
'''
|
||||
process_info = {}
|
||||
p = psutil.Process(pid)
|
||||
status_ps = {'sleeping':'睡眠','running':'活动'}
|
||||
status_ps = {'sleeping':'sleeping','running':'running'}
|
||||
with p.oneshot():
|
||||
p_mem = p.memory_full_info()
|
||||
if p_mem.uss + p_mem.rss + p_mem.pss + p_mem.data == 0: return False
|
||||
@@ -368,7 +368,7 @@ class panelRun:
|
||||
time.sleep(1)
|
||||
pid = self.get_script_pid(run_info)
|
||||
public.writeFile(pid_file,str(pid))
|
||||
public.WriteLog(self.__log_name, '开机启动{}成功, PID: {}'.format(run_name,pid))
|
||||
public.write_log_gettext(self.__log_name, 'Startup {} successful, PID:{}',(run_name,pid,))
|
||||
return True
|
||||
|
||||
|
||||
|
||||