修正了一堆MySQL的SQL语句的问题。准备发布技术预览版。

pull/105/head
Apex Liu 2017-11-26 03:20:14 +08:00
parent e94dcd30af
commit 2fac0b76a5
29 changed files with 404 additions and 1200 deletions

View File

@ -68,6 +68,7 @@
#define TPE_NEED_MORE_DATA 1 // 需要更多数据(不一定是错误)
#define TPE_NEED_LOGIN 2 // 需要登录
#define TPE_PRIVILEGE 3 // 没有操作权限
#define TPE_NOT_IMPLEMENT 7 // 功能尚未实现
#define TPE_EXISTS 8 // 目标已经存在
#define TPE_NOT_EXISTS 9 // 目标不存在

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$/../packages/packages-common" />
<content url="file://$MODULE_DIR$/static" />
<content url="file://$MODULE_DIR$/view" />
<content url="file://$MODULE_DIR$/webroot">

View File

@ -2,9 +2,12 @@
$app.on_init = function (cb_stack) {
$app.dom = {
storage_info: $('#storage-info'),
btn_refresh_record: $('#btn-refresh-record')
};
$app.dom.storage_info.html('总 ' + tp_size2str($app.options.total_size, 2) + '' + '可用 ' + tp_size2str($app.options.free_size, 2));
cb_stack
.add($app.create_controls)
.add($app.load_role_list);

View File

@ -30,15 +30,11 @@ $app.on_init = function (cb_stack, cb_args) {
var _t = [];
_t.push('<div class="alert alert-warning">');
_t.push('注意请确保您在执行后续创建操作之前已经在MySQL数据库中创建了数据库"');
_t.push('<i class="fa fa-warning"></i> 注意请确保您在执行后续创建操作之前已经在MySQL中使用 <span class="bold">UTF8字符集</span> 创建了库“');
_t.push($app.options.db.mysql_db);
_t.push('"和用户"');
_t.push('”,并且用户“');
_t.push($app.options.db.mysql_user);
_t.push('",并为用户"');
_t.push($app.options.db.mysql_user);
_t.push('"设置了在数据库"');
_t.push($app.options.db.mysql_db);
_t.push('"创建表的权限!');
_t.push('”拥有在此库创建表的权限!');
_t.push('</div>');
$app.dom.db_info.after(_t.join(''));
} else {
@ -73,7 +69,7 @@ $app.on_init = function (cb_stack, cb_args) {
$app.dom.email.focus();
return;
}
if(!tp_check_email(str_email)) {
if (!tp_check_email(str_email)) {
$app.show_op_box('error', '电子邮件地址格式错啦,你会收不到邮件的!');
$app.dom.email.focus();
return;

View File

@ -23,8 +23,8 @@ $app.on_init = function (cb_stack) {
dom: {}
};
$('#btn-test').click(function () {
$app.on_test();
$('#btn-rebuild').click(function () {
$app.on_rebuild();
});
// $app.dragging = false;
@ -43,7 +43,7 @@ $app.on_init = function (cb_stack) {
cb_stack.exec();
};
$app.on_test = function () {
$app.on_rebuild = function () {
$tp.ajax_post_json('/ops/build-auz-map', {},
function (ret) {
if (ret.code === TPE_OK) {

View File

@ -7,6 +7,7 @@ $app.on_init = function (cb_stack) {
$app.dom = {
role_list: $('#role-list'),
area_action: $('#area-action'),
btn_edit_role: $('#btn-edit-role'),
btn_remove_role: $('#btn-remove-role'),
btn_save_role: $('#btn-save-role'),
@ -154,6 +155,12 @@ $app.show_role = function (role_id, edit_mode) {
var edit = edit_mode || false;
var role = null;
if (role_id === 1 || role_id === 0 || edit_mode) {
$app.dom.area_action.hide();
} else {
$app.dom.area_action.show();
}
if (role_id === 1 && edit_mode) {
$tp.notify_error('禁止修改管理员角色!');
return;
@ -254,7 +261,7 @@ $app.save_role = function () {
$app.dom.btn_create_role.before($(html.join('')));
$app.dom.role_list.find('[data-role-id="'+role_id+'"]').click(function () {
$app.dom.role_list.find('[data-role-id="' + role_id + '"]').click(function () {
var obj = $(this);
if (obj.hasClass('active')) {
return;
@ -295,33 +302,45 @@ $app.remove_role = function () {
return;
}
$tp.ajax_post_json('/system/role-remove',
{
role_id: $app.selected_role_id
},
function (ret) {
if (ret.code === TPE_OK) {
$tp.notify_success('角色删除成功!');
for (var i = 0; i < $app.role_list; ++i) {
if ($app.role_list[i].id === $app.selected_role_id) {
delete $app.role_list[i];
break;
var _fn_sure = function (cb_stack, cb_args) {
$tp.ajax_post_json('/system/role-remove',
{
role_id: $app.selected_role_id
},
function (ret) {
if (ret.code === TPE_OK) {
$tp.notify_success('角色删除成功!');
for (var i = 0; i < $app.role_list; ++i) {
if ($app.role_list[i].id === $app.selected_role_id) {
delete $app.role_list[i];
break;
}
}
$app.dom.role_list.find('[data-role-id="' + $app.selected_role_id + '"]').remove();
if ($app.last_role_id === $app.selected_role_id)
$app.last_role_id = 1;
$app.show_role($app.last_role_id, false);
cb_stack.exec();
} else {
$tp.notify_error('角色删除失败:' + tp_error_msg(ret.code, ret.message));
cb_stack.exec();
}
$app.dom.role_list.find('[data-role-id="' + $app.selected_role_id + '"]').remove();
if ($app.last_role_id === $app.selected_role_id)
$app.last_role_id = 1;
$app.show_role($app.last_role_id, false);
} else {
$tp.notify_error('角色删除失败:' + tp_error_msg(ret.code, ret.message));
},
function () {
$tp.notify_error('网路故障,角色删除失败!');
}
},
function () {
$tp.notify_error('网路故障,角色删除失败!');
}
);
);
};
var cb_stack = CALLBACK_STACK.create();
$tp.dlg_confirm(cb_stack, {
msg: '<p>删除角色后,属于此角色的用户将没有任何操作权限,直到为用户重新指定角色!</p><p>您确定要将删除此角色吗?</p>',
fn_yes: _fn_sure
});
};

View File

@ -183,6 +183,7 @@ var TPE_NEED_MORE_DATA = 1; // 需要更多数据(不一定是错误)
var TPE_NEED_LOGIN = 2;
var TPE_PRIVILEGE = 3;
var TPE_NOT_IMPLEMENT = 7; // 尚未实现
var TPE_EXISTS = 8;
var TPE_NOT_EXISTS = 9;

View File

@ -286,6 +286,40 @@ function tp_gen_random_string(len) {
return ret;
}
// 生成一个随机密码
function tp_gen_password(len) {
len = len || 8;
var _chars = ['ABCDEFGHJKMNPQRSTWXYZ', 'abcdefhijkmnprstwxyz', '2345678']; // 默认去掉了容易混淆的字符oO,Ll,9gq,Vv,Uu,I1
var _chars_len = [];
var i = 0;
for (i = 0; i < _chars.length; ++i) {
_chars_len[i] = _chars[i].length;
}
var ret = '';
var have_CHAR = false;
var have_char = false;
var have_num = false;
for(;;) {
ret = '';
for (i = 0; i < len; i++) {
var idx = Math.floor(Math.random() * _chars.length);
if(idx === 0)
have_CHAR = true;
else if(idx === 1)
have_char = true;
else
have_num = true;
ret += _chars[idx].charAt(Math.floor(Math.random() * _chars_len[idx]));
}
if(have_CHAR && have_char && have_num)
break;
}
return ret;
}
// 弱密码检测
function tp_check_strong_password(p) {
var s = 0;

View File

@ -2,33 +2,20 @@
$app.on_init = function (cb_stack, cb_args) {
$app.dom = {
btn_reset_oath_code: $('#btn-reset-oath-code'),
btn_verify_oath_code: $('#btn-verify-oath-code'),
btn_verify_oath_code_and_save: $('#btn-verify-oath-and-save'),
btn_modify_password: $('#btn-modify-password'),
btn_toggle_oath_download: $('#toggle-oath-download'),
oath_app_download_box: $('#oath-app-download-box'),
input_current_password: $('#current-password'),
input_new_password: $('#new-password-1'),
input_new_password_confirm: $('#new-password-2'),
input_oath_code: $('#oath-code'),
input_oath_code_verify: $('#oath-code-verify'),
dlg_reset_oath_code: $('#dialog-reset-oath-code'),
oath_secret_image: $('#oath-secret-qrcode'),
tmp_oath_secret: $('#tmp-oath-secret'),
tp_time: $('#teleport-time')
input_new_password_confirm: $('#new-password-2')
};
$app.tp_time = 0;
$app.fix_time_display = function(selector) {
var obj = $('[data-field="'+selector+'"]');
var val = parseInt(obj.attr('data-value'));
obj.text(tp_format_datetime(tp_utc2local(val)));
if(val === 0)
obj.text('-');
else
obj.text(tp_format_datetime(tp_utc2local(val)));
};
$app.fix_time_display('create-time');
@ -59,7 +46,7 @@ $app.on_init = function (cb_stack, cb_args) {
$app.dom.input_new_password_confirm.focus();
return;
}
$tp.ajax_post_json('/auth/modify-pwd', {o_pwd: old_pwd, n_pwd: new_pwd_1, callback: 1},
$tp.ajax_post_json('/user/do-reset-password', {mode: 5, current_password: old_pwd, password: new_pwd_1},
function (ret) {
if (ret.code === TPE_OK) {
$tp.notify_success('密码修改成功!');
@ -67,7 +54,7 @@ $app.on_init = function (cb_stack, cb_args) {
} else if (ret.code === -101) {
$tp.notify_error('密码错误!');
} else {
$tp.notify_error('密码修改失败:' + ret.message);
$tp.notify_error('密码修改失败:' + tp_error_msg(ret.code, ret.message));
}
},
@ -77,108 +64,5 @@ $app.on_init = function (cb_stack, cb_args) {
);
});
$app.dom.btn_toggle_oath_download.click(function () {
if ($app.dom.oath_app_download_box.is(':hidden')) {
$app.dom.oath_app_download_box.slideDown('fast', function () {
$app.dom.btn_toggle_oath_download.html('收起 <i class="fa fa-angle-up"></i>');
});
} else {
$app.dom.oath_app_download_box.slideUp('fast', function () {
$app.dom.btn_toggle_oath_download.html('显示下载地址 <i class="fa fa-angle-down"></i>');
});
}
});
$app.dom.btn_verify_oath_code.click(function () {
var code = $app.dom.input_oath_code.val().trim();
if (code.length !== 6) {
$tp.notify_error('动态验证码错误应该是6位数字');
$app.dom.input_oath_code_verify.focus();
return;
}
$tp.ajax_post_json('/auth/oath-verify', {code: code},
function (ret) {
if (ret.code === TPE_OK) {
$tp.notify_success('动态验证码验证成功!');
} else if (ret.code === -3) {
$tp.notify_error('动态验证码验证失败!');
} else {
$tp.notify_error('发生内部错误!' + tp_error_msg(ret.code, ret.message));
}
},
function () {
$tp.notify_error('网路故障,无法连接到服务器!');
}
);
});
$app.dom.btn_reset_oath_code.click(function () {
$tp.ajax_post_json('/user/gen-oath-secret', {},
function (ret) {
if (ret.code === TPE_OK) {
$app.dom.oath_secret_image.attr('src', '/user/oath-secret-qrcode?' + Math.random());
$app.dom.tmp_oath_secret.text(ret.data.tmp_oath_secret);
$app.dom.dlg_reset_oath_code.modal({backdrop: 'static'});
} else {
$tp.notify_error('无法绑定身份验证器:' + tp_error_msg(ret.code, ret.message));
}
},
function () {
$tp.notify_error('网路故障,无法连接到服务器!');
}
);
});
$app.dom.btn_verify_oath_code_and_save.click(function () {
var code = $app.dom.input_oath_code_verify.val().trim();
if (code.length !== 6) {
$tp.notify_error('动态验证码错误应该是6位数字');
$app.dom.input_oath_code_verify.focus();
return;
}
$tp.ajax_post_json('/auth/oath-update-secret', {code: code},
function (ret) {
if (ret.code === TPE_OK) {
$tp.notify_success('身份验证器绑定成功!您可以用此身份验证器登录系统了!');
$app.dom.dlg_reset_oath_code.modal('hide');
} else {
$tp.notify_error('发生内部错误!' + tp_error_msg(ret.code, ret.message));
}
},
function () {
$tp.notify_error('网路故障,无法连接到服务器!');
}
);
});
// 获取服务器时间
$app.sync_tp_time = function () {
$tp.ajax_post_json('/system/get-time', {},
function (ret) {
if (ret.code === TPE_OK) {
$app.tp_time = tp_utc2local(ret.data);
$app.show_tp_time();
}
},
function () {
}
);
};
$app.sync_tp_time();
$app.show_tp_time = function () {
if ($app.tp_time === 0)
return;
$app.dom.tp_time.text(tp_format_datetime($app.tp_time));
$app.tp_time += 1;
};
setInterval($app.show_tp_time, 1000);
// 每五分钟同步一次服务器时间,避免长时间误差积累导致显示不正确
setInterval($app.sync_tp_time, 1000 * 60 * 5);
cb_stack.exec();
};

View File

@ -1046,7 +1046,7 @@ $app.create_dlg_reset_password = function () {
dlg.dom.btn_reset_password.click(dlg.do_reset_password);
dlg.dom.btn_gen_random_password.click(function () {
dlg.dom.password.val(tp_gen_random_string(8));
dlg.dom.password.val(tp_gen_password(8));
dlg.dom.password.attr('type', 'text');
dlg.dom.btn_switch_password_icon.removeClass('fa-eye').addClass('fa-eye-slash')
});

View File

@ -111,17 +111,17 @@
'name': '系统',
'icon': 'fa-cog',
'sub': [
{
'privilege': const.TP_PRIVILEGE_SYS_ROLE,
'id': 'role',
'link': '/system/role',
'name': '角色管理',
},
{
'privilege': const.TP_PRIVILEGE_SYS_LOG,
'id': 'syslog',
'link': '/system/syslog',
'name': '系统日志',
},
{
'privilege': const.TP_PRIVILEGE_SYS_ROLE,
'id': 'role',
'link': '/system/role',
'name': '角色管理',
},
{
'privilege': const.TP_PRIVILEGE_SYS_CONFIG,
@ -136,77 +136,78 @@
## <div id="sidebar-menu-slim-scroll">
<!-- begin sidebar nav -->
<div class="nav">
<ul class="nav nav-menu">
%for menu in _sidebar:
%if menu['id'] == 'me':
<li id="sidebar_menu_${menu['id']}" class="profile">
<div class="image">
<img src="/static/img/avatar/001.png" width="36"/>
</div>
<div class="nav">
<ul class="nav nav-menu">
%for menu in _sidebar:
%if menu['id'] == 'me':
<li id="sidebar_menu_${menu['id']}" class="profile">
<div class="image">
<img src="/static/img/avatar/001.png" width="36"/>
</div>
<div class="dropdown">
<a class="title" href="#" id="user-profile" data-target="#" data-toggle="dropdown" role="button"
aria-haspopup="true" aria-expanded="false">
<span class="name">${ current_user['surname'] }</span>
<span class="role">${ current_user['role'] } <i class="fa fa-caret-right"></i></span>
</a>
<ul class="dropdown-menu dropdown-menu-right">
<li><a href="/user/me"><i class="fa fa-vcard-o fa-fw"></i> 个人中心</a></li>
<li role="separator" class="divider"></li>
<li><a href="/auth/logout" id="btn-sidebar-menu-logout"><i class="fa fa-sign-out fa-fw"></i> 退出</a></li>
</ul>
</div>
</li>
%else:
%if 'sub' in menu and len(menu['sub']) > 0:
<div class="dropdown">
<a class="title" href="#" id="user-profile" data-target="#" data-toggle="dropdown" role="button"
aria-haspopup="true" aria-expanded="false">
<span class="name">${ current_user['surname'] }</span>
<span class="role">${ current_user['role'] } <i class="fa fa-caret-right"></i></span>
</a>
<ul class="dropdown-menu dropdown-menu-right">
<li><a href="/user/me"><i class="fa fa-vcard-o fa-fw"></i> 个人中心</a></li>
<li role="separator" class="divider"></li>
<li><a href="/auth/logout" id="btn-sidebar-menu-logout"><i class="fa fa-sign-out fa-fw"></i> 退出</a></li>
</ul>
</div>
</li>
%else:
%if 'sub' in menu and len(menu['sub']) > 0:
<%
menu['privilege'] = 0
%>
%for sub in menu['sub']:
<%
menu['privilege'] = 0
menu['privilege'] |= sub['privilege']
%>
%for sub in menu['sub']:
<%
menu['privilege'] |= sub['privilege']
%>
%endfor
%endif
%if menu['privilege'] & current_user['privilege'] != 0:
%if 'sub' in menu and len(menu['sub']) > 0:
<li id="sidebar_menu_${menu['id']}">
<a href="javascript:;" onclick="$app.sidebar_menu.toggle_submenu('${menu['id']}');">
<i class="fa ${menu['icon']} fa-fw icon"></i>
<span>${menu['name']}</span>
<i class="menu-caret"></i>
</a>
<ul class="sub-menu" id="sidebar_submenu_${menu['id']}" style="display:none;">
%for sub in menu['sub']:
%if (sub['privilege'] & current_user['privilege']) != 0:
<li id="sidebar_menu_${menu['id']}_${sub['id']}"><a href="${sub['link']}"><span>${sub['name']}</span></a></li>
%endif
%endfor
</ul>
</li>
%else:
<li id="sidebar_menu_${menu['id']}"><a href="${menu['link']}"
%if 'target' in menu:
target="${menu['target']}"
%endif
><i class="fa ${menu['icon']} fa-fw icon"></i><span>${menu['name']}</span></a></li>
%endif
%endif
%endfor
%endif
%if menu['privilege'] & current_user['privilege'] != 0:
%if 'sub' in menu and len(menu['sub']) > 0:
<li id="sidebar_menu_${menu['id']}">
<a href="javascript:;" onclick="$app.sidebar_menu.toggle_submenu('${menu['id']}');">
<i class="fa ${menu['icon']} fa-fw icon"></i>
<span>${menu['name']}</span>
<i class="menu-caret"></i>
</a>
<ul class="sub-menu" id="sidebar_submenu_${menu['id']}" style="display:none;">
%for sub in menu['sub']:
%if (sub['privilege'] & current_user['privilege']) != 0:
<li id="sidebar_menu_${menu['id']}_${sub['id']}"><a href="${sub['link']}"><span>${sub['name']}</span></a></li>
%endif
%endfor
</ul>
</li>
%else:
<li id="sidebar_menu_${menu['id']}"><a href="${menu['link']}"
%if 'target' in menu:
target="${menu['target']}"
%endif
><i class="fa ${menu['icon']} fa-fw icon"></i><span>${menu['name']}</span></a></li>
%endif
%endif
%endif
%endfor
</ul>
</div>
<!-- end sidebar nav -->
%endfor
<hr style="border:none;border-bottom:1px dotted #4a4a4a;margin-bottom:0;"/>
<div style="color:#717171;font-size:90%;margin-top:5px;"><span style="display:inline-block;width:70px;text-align: right">服务端:</span><span class="mono">v${app_ver.TP_SERVER_VER}</span></div>
## <div style="color:#717171;font-size:90%;margin-top:5px;"><span style="display:inline-block;width:70px;text-align: right">助手:</span><span class="mono" id="tp-assist-version" data-req-version=$ { app_ver.TP_ASSIST_REQUIRE}>v$ { app_ver.TP_ASSIST_LAST_VER}</span></div>
## <div style="color:#717171;font-size:90%;margin-top:5px;"><span style="display:inline-block;width:70px;text-align: right">助手:</span><span class="mono" id="tp-assist-version">未连接</span></div>
<hr style="border:none;border-bottom:1px dotted #4a4a4a;margin-bottom:20px;margin-top:5px;"/>
</ul>
</div>
<!-- end sidebar nav -->
<hr style="border:none;border-bottom:1px dotted #4a4a4a;margin-bottom:0;"/>
<div style="color:#717171;font-size:90%;margin-top:5px;text-align:center;">
<div style="margin-top:5px;text-align:center;">服务端:<span class="mono">v${app_ver.TP_SERVER_VER}</span></div>
<div style="font-size:80%;margin-top:5px;text-align:center;"><span class="error">技术预览版</span></div>
</div>
<hr style="border:none;border-bottom:1px dotted #4a4a4a;margin-bottom:20px;margin-top:5px;"/>
## </div>

View File

@ -9,73 +9,25 @@
<script type="text/javascript" src="${ static_url('js/audit/record-list.js') }"></script>
</%block>
## <%block name="breadcrumb">
## <ol class="breadcrumb">
## <li><i class="fa fa-database fa-fw"></i> ${self.attr.page_title_}</li>
## </ol>
## </%block>
## Begin Main Body.
<div class="page-content-inner">
<!-- begin box -->
<div class="box">
<!-- begin filter -->
## <div class="page-filter">
## <div class="" style="float:right;">
## ## <span id="disk-status" class="badge badge-info" style="margin-right:10px;">磁盘状态</span>
## <a href="javascript:;" class="btn btn-sm btn-primary" ywl-filter="reload"><i class="fa fa-repeat fa-fw"></i> 刷新</a>
## </div>
##
## <div class="">
##
## <div class="input-group input-group-sm" style="display:inline-block;margin-right:10px;">
## <span class="input-group-addon" style="display:inline-block;width:auto; line-height:28px;height:30px;padding:0 10px;font-size:13px;">用户名</span>
## <div class="input-group-btn" ywl-filter="user-name" style="display:inline-block;margin-left:-4px;">
## <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"><span>所有</span> <span class="caret"></span></button>
## <ul class="dropdown-menu">
## <li>所有</li>
## </ul>
## </div>
## </div>
##
##
## <div class="input-group input-group-sm" ywl-filter="search" style="display:inline-block;">
## <input type="text" class="form-control" placeholder="搜索 ID 或 IP" style="display:inline-block;">
## <span class="input-group-btn" style="display:inline-block;margin-left:-4px;">
## <button type="button" class="btn btn-default"><i class="fa fa-search fa-fw"></i></button>
## </span>
## </div>
##
## </div>
## </div>
<div class="table-prefix-area">
<div class="table-extend-cell">
<span class="table-name"><i class="fa fa-list fa-fw"></i> 会话列表</span>
<button id="btn-refresh-record" class="btn btn-sm btn-default"><i class="fa fa-rotate-right fa-fw"></i> 刷新列表</button>
</div>
## <div class="table-extend-cell table-extend-cell-right group-actions">
##<button id="btn-add-host" class="btn btn-sm btn-primary"><i class="fa fa-plus-circle fa-fw"></i> 添加主机</button>
## <button id="btn-add-temp-account" class="btn btn-sm btn-success"><i class="fa fa-plus-circle fa-fw"></i> 添加主机</button>
##<button id="btn-import-host" class="btn btn-sm btn-default"><i class="fa fa-plus-square fa-fw"></i> 导入主机和账号</button>
## </div>
<div class="table-extend-cell table-extend-cell-right group-actions">
<div class="label label-ignore">存储空间:<span id="storage-info"></span></div>
</div>
</div>
<!-- end filter -->
<table class="table table-striped table-bordered table-hover table-data no-footer dtr-inline" id="table-record"></table>
<!-- begin page-nav -->
<div class="table-extend-area">
## <div class="table-extend-cell checkbox-select-all"><input id="table-record-select-all" type="checkbox"/></div>
## <div class="table-extend-cell group-actions">
## <div class="btn-group" role="group">
## ## <button id="btn-edit-host" type="button" class="btn btn-default"><i class="fa fa-edit fa-fw"></i> 编辑</button>
## ## <button id="btn-lock-host" type="button" class="btn btn-default"><i class="fa fa-lock fa-fw"></i> 禁用</button>
## ## <button id="btn-unlock-host" type="button" class="btn btn-default"><i class="fa fa-unlock fa-fw"></i> 解禁</button>
## <button id="btn-remove-record" type="button" class="btn btn-default"><i class="fa fa-times-circle fa-fw"></i> 删除</button>
## </div>
## </div>
<div class="table-extend-cell table-item-counter">
<ol id="table-record-paging"></ol>
</div>
@ -90,7 +42,6 @@
</div>
</div>
</div>
<!-- end page-nav -->
</div>
<!-- end of box -->

View File

@ -19,7 +19,7 @@
<div class="page-content">
<div class="info-box">
<div class="info-icon-box">
<i class="fa fa-unlink" style="color:#ff7545;"></i>
<i id="icon" class="fa" style="color:#ff7545;"></i>
</div>
<div class="info-message-box">
<div id="title" class="title"></div>
@ -35,17 +35,19 @@
$app.add_options(${page_param});
var err_info = {};
err_info['err_' + TPE_PRIVILEGE] = ['权限不足', '您没有访问权限!<br/><br/>如果您确定应该具有此访问权限,请联系系统管理员!<br/><br/>或者您可以选择访问<a href="/">起始页面</a>。'];
err_info['err_' + TPE_HTTP_404_NOT_FOUND] = ['404 NOT FOUND', '您访问的地址不存在!请向系统管理员汇报此问题!<br/><br/>或者您可以选择访问<a href="/">起始页面</a>。'];
err_info['err_unknown'] = ['未知错误', '发生未知错误,错误编号:' + $app.options.err_code + '。<br/><br/>请联系系统管理员进行处理!'];
err_info['err_' + TPE_PRIVILEGE] = ['fa-ban', '权限不足', '您没有此访问权限!<br/><br/>如果您确定应该具有此访问权限,请联系系统管理员!<br/><br/>或者您可以选择访问<a href="/">起始页面</a>。'];
err_info['err_' + TPE_HTTP_404_NOT_FOUND] = ['fa-unlink', '404 NOT FOUND', '您访问的地址不存在!请向系统管理员汇报此问题!<br/><br/>或者您可以选择访问<a href="/">起始页面</a>。'];
err_info['err_' + TPE_NOT_IMPLEMENT] = ['fa-coffee', '功能未实现', '哎呀呀~~~<br/><br/>很抱歉,此功能尚未实现!敬请期待新版本!'];
err_info['err_unknown'] = ['fa-exclamation-circle', '未知错误', '发生未知错误,错误编号:' + $app.options.err_code + '。<br/><br/>请联系系统管理员进行处理!'];
var err_index = 'err_' + $app.options.err_code;
if (!err_info.hasOwnProperty(err_index)) {
err_index = 'err_unknown';
}
$('#page-title').html(err_info[err_index][0]);
$('#title').html(err_info[err_index][0]);
$('#content').html(err_info[err_index][1]);
$('#icon').addClass(err_info[err_index][0]);
$('#page-title').html(err_info[err_index][1]);
$('#title').html(err_info[err_index][1]);
$('#content').html(err_info[err_index][2]);
</script>
</%block>

View File

@ -2,19 +2,9 @@
import app.app_ver as app_ver
page_title_ = '安装配置TELEPORT服务'
%>
## <%inherit file="../page_maintenance_base.mako"/>
<%inherit file="../page_single_base.mako"/>
## <%block name="breadcrumb">
## <ol class="breadcrumb">
## <li><i class="fa fa-cog fa-fw"></i> ${self.attr.page_title_}</li>
## </ol>
## </%block>
<%block name="extend_css_file">
## <link href="${ static_url('css/maintenance.css') }" rel="stylesheet" type="text/css"/>
</%block>
<%block name="extend_js_file">
<script type="text/javascript" src="${ static_url('js/maintenance/install.js') }"></script>
</%block>
@ -25,16 +15,6 @@
</script>
</%block>
## <%block name="page_header">
## <div id="page-header" class="header header-fixed-top">
## <nav class="navbar navbar-fixed-top">
## <div class="container">
## <h1><i class="fa fa-cog fa-fw"></i> ${self.attr.page_title_}</h1>
## </div>
## </nav>
## </div>
## </%block>
<%block name="page_header">
<div class="container-fluid top-navbar">
<div class="brand"><a href="/" target="_blank"><span class="site-logo"></span></a></div>

View File

@ -6,10 +6,7 @@
<%inherit file="../page_base.mako"/>
<%block name="extend_js_file">
## <script type="text/javascript" src="${ static_url('js/tp-assist.js') }"></script>
<script type="text/javascript" src="${ static_url('js/ops/auz-list.js') }"></script>
## <script type="text/javascript" src="${ static_url('plugins/jquery/ajaxfileupload.js') }"></script>
</%block>
<%block name="embed_css">
@ -41,7 +38,7 @@
<div class="table-extend-cell">
<span class="table-name"><i class="fa fa-list fa-fw"></i> 授权策略列表</span>
<button id="btn-refresh-policy" class="btn btn-sm btn-default"><i class="fa fa-rotate-right fa-fw"></i> 刷新列表</button>
<button id="btn-test" class="btn btn-sm btn-primary"><i class="fa fa-flash fa-fw"></i> 测试:重建映射</button>
<button id="btn-rebuild" class="btn btn-sm btn-danger"><i class="fa fa-flash fa-fw"></i> 重建授权映射</button>
</div>
<div class="table-extend-cell table-extend-cell-right group-actions">
<button id="btn-create-policy" class="btn btn-sm btn-primary"><i class="fa fa-plus-circle fa-fw"></i> 新建授权策略</button>
@ -89,6 +86,7 @@
<div class="box">
<p>说明:</p>
<ul class="help-list">
<li><span class="error">编辑了授权策略或调整策略顺序之后,请点击“重建授权映射”来使之生效!</span>正式版本将会改进为自动进行重建。</li>
<li>上下拖动“顺序”栏中的 <i class="fa fa-reorder fa-fw"></i> 可以调节策略的检查顺序。</li>
<li>可以在“快速查找”中快速定位用户或主机的授权关系。</li>
</ul>
@ -134,8 +132,3 @@
</div>
</div>
</%block>
## <%block name="embed_js">
## <script type="text/javascript">
## </script>
## </%block>

View File

@ -34,7 +34,7 @@
<div id="page-header" class="page-header navbar navbar-default navbar-fixed-top">
<div class="container-fluid">
<div class="brand"><a href="http://teleport.eomsoft.net" target="_blank"><span class="logo"></span></a></div>
<div class="brand"><a href="/"><span class="logo"></span></a></div>
<div class="breadcrumb-container">
<%block name="breadcrumb">
@ -70,26 +70,6 @@
</div>
<!-- end #page-content -->
## <div class="modal fade" id="dlg-ywl-message-box" tabindex="-1" role="dialog">
## <div class="modal-dialog" role="document">
## <div class="modal-content">
## <div class="modal-header">
## <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
## <h4 class="modal-title" ywl-title></h4>
## </div>
## <div class="modal-body" ywl-content style="font-size: 20px">
##
## </div>
## <div class="modal-footer">
## <input type="hidden" ywl-record-id="" ywl-row-id="">
## <button type="button" class="btn btn-success btn-sm" ywl-btn-ok="ok"><i class="glyphicon glyphicon-ok"></i></button>
## <button type="button" class="btn btn-danger btn-sm" data-dismiss="modal"><i class="glyphicon glyphicon-remove"></i></button>
## </div>
## </div>
## </div>
## </div>
<%block name="extend_content" />
<script type="text/javascript" src="${ static_url('plugins/underscore/underscore.js') }"></script>
<script type="text/javascript" src="${ static_url('plugins/jquery/jquery-2.2.3.min.js') }"></script>

View File

@ -9,11 +9,6 @@
<script type="text/javascript" src="${ static_url('js/system/role.js') }"></script>
</%block>
## <%block name="embed_css">
## <style>
## </style>
## </%block>
<div class="page-content-inner">
<div class="box">
<div class="alert alert-info">
@ -38,7 +33,7 @@
</div>
</div>
</div>
<div style="float:right;">
<div style="float:right;" id="area-action">
<button id="btn-edit-role" class="btn btn-sm btn-primary"><i class="fa fa-edit fa-fw"></i> 编辑角色</button>
<button id="btn-remove-role" class="btn btn-sm btn-danger"><i class="fa fa-trash-o fa-fw"></i> 删除角色</button>
</div>

View File

@ -31,7 +31,6 @@
<ul class="nav nav-tabs">
<li class="active"><a href="#info" data-toggle="tab">个人信息</a></li>
<li><a href="#password" data-toggle="tab">修改密码</a></li>
<li><a href="#oath" data-toggle="tab">身份验证器</a></li>
</ul>
<!-- Tab panes -->
@ -87,121 +86,8 @@
</div>
</div>
<div class="tab-pane" id="oath">
<p>请在你的手机上安装身份验证器,然后在验证器中添加你的登录账号。</p>
<div id="oath-app-download-box" style="display:none;">
<p>选择你喜欢的身份验证器,扫描二维码进行安装:</p>
<div class="row">
<div class="col-md-2">
<p style="text-align: center;">
<i class="fa fa-apple"></i> iOSApple Store<br/>
<img src="${ static_url('img/qrcode/google-oath-appstore.png') }"><br/>
Google身份验证器
</p>
</div>
<div class="col-md-2">
<p style="text-align: center;">
<i class="fa fa-android"></i> Android百度手机助手<br/>
<img src="${ static_url('img/qrcode/google-oath-baidu.png') }"><br/>
Google身份验证器
</p>
</div>
<div class="col-md-2">
<p style="text-align: center;">
<i class="fa fa-android"></i> AndroidGoogle Play<br/>
<img src="${ static_url('img/qrcode/google-oath-googleplay.png') }"><br/>
Google身份验证器
</p>
</div>
<div class="col-md-2">
<p style="text-align: center;">
<i class="fa fa-apple"></i> iOSApple Store<br/>
<img src="${ static_url('img/qrcode/xiaomi-oath-appstore.png') }"><br/>
小米安全令牌
</p>
</div>
<div class="col-md-2">
<p style="text-align: center;">
<i class="fa fa-android"></i> Android小米应用商店<br/>
<img src="${ static_url('img/qrcode/xiaomi-oath-xiaomi.png') }"><br/>
小米安全令牌
</p>
</div>
</div>
</div>
<p style="margin-top:5px;"><a href="javascript:;" id="toggle-oath-download">显示下载地址 <i class="fa fa-angle-down"></i></a></p>
<hr/>
<p>要验证已经绑定的身份验证器,可在下面的输入框中输入验证器器上显示的动态验证码,然后点击验证。</p>
<p>如果验证失败,请注意检查您的身份验证器的时间与服务器时间是否一致,如果两者时间偏差超过两分钟则无法验证通过!</p>
<div style="width:360px;">
<div style="text-align:center;margin:20px 0 10px 0;">TELEPORT服务器时间<span style="font-weight:bold;" class="mono" id="teleport-time">-</span></div>
<div class="input-group input-group-sm" style="margin-top: 10px">
<span class="input-group-addon">动态验证码6位数字</span>
<input type="text" class="form-control" id="oath-code">
<div class="input-group-btn">
<button id="btn-verify-oath-code" class="btn btn-primary"><i class="fa fa-check"></i> 验证</button>
</div>
</div>
</div>
<hr/>
<p>要将你的登录账号添加到身份验证器中,请点击下面的“绑定身份验证器”按钮。</p>
<p>
<button id="btn-reset-oath-code" class="btn btn-sm btn-success"><i class="fa fa-refresh"></i> 绑定身份验证器</button>
</p>
</div>
</div>
</div>
</div>
<%block name="extend_content">
<div class="modal fade" id="dialog-reset-oath-code" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">绑定身份验证器</h3>
</div>
<div class="modal-body">
<p>请在手机上打开身份验证器,点击增加账号按钮,然后选择“扫描条形码”并扫描下面的二维码来完成账号绑定。</p>
<p style="text-align: center;"><img id="oath-secret-qrcode" src=""></p>
<p>如果无法扫描二维码,则可以选择“手动输入验证码”,设置一个容易记忆的账号名称,并确保“基于时间”一项是选中的,然后在“密钥”一项中输入下列密钥:</p>
<div class="row">
<div class="col-sm-4" style="text-align:right;">
<span style="line-height:25px;">密钥:</span>
</div>
<div class="col-sm-8">
<span class="oath-code"><span id="tmp-oath-secret"></span></span>
</div>
</div>
<hr/>
<p>然后请在下面的动态验证码输入框中输入身份验证器提供的6位数字</p>
<div class="row">
<div class="col-sm-4" style="text-align:right;">
<span style="line-height:34px;">动态验证码:</span>
</div>
<div class="col-sm-4">
<input type="text" class="form-control" id="oath-code-verify">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-sm btn-primary" id="btn-verify-oath-and-save"><i class="fa fa-check fa-fw"></i> 验证动态验证码并完成绑定</button>
<button type="button" class="btn btn-sm btn-default" data-dismiss="modal"><i class="fa fa-close fa-fw"></i> 取消</button>
</div>
</div>
</div>
</div>
</%block>

View File

@ -89,10 +89,10 @@ class DatabaseInit:
# name: 角色名称
f.append('`name` varchar(128) NOT NULL')
# desc: 角色描述
f.append('`desc` varchar(255) DEFAULT NULL')
f.append('`desc` varchar(255) DEFAULT ""')
# privilege: 权限,可按位异或组合,请参考 TP_PRIVILEGE_XXXX 定义
f.append('`privilege` int(11) DEFAULT 0')
f.append('`privilege` bigint(11) DEFAULT 0')
# creator_id: 创建者的id0=系统默认创建
f.append('`creator_id` int(11) DEFAULT 0')
@ -118,15 +118,17 @@ class DatabaseInit:
# username: teleport系统登录名
f.append('`username` varchar(32) NOT NULL')
# surname: 真实姓名
f.append('`surname` varchar(64) DEFAULT NULL')
f.append('`surname` varchar(64) DEFAULT ""')
# type 1=本地账号2=LDAP待扩展
f.append('`type` int(11) DEFAULT 1')
# avatar: 用户头像图片地址
f.append('`avatar` varchar(64) DEFAULT ""')
# auth_type: 0=使用全局设置,其他参考 TP_LOGIN_AUTH_XXX 系列值
f.append('`auth_type` int(11) DEFAULT 0')
# password: 登录密码如果是LDAP账号则忽略此字段
f.append('`password` varchar(128) DEFAULT NULL')
f.append('`password` varchar(128) DEFAULT ""')
# oath_secret: 身份验证器密钥(使用核心服务加密存储)
f.append('`oath_secret` varchar(64) DEFAULT NULL')
f.append('`oath_secret` varchar(64) DEFAULT ""')
# state: 状态1=正常2=禁用3=临时锁定
f.append('`state` int(3) DEFAULT 1')
# fail_count: 连续登录失败的次数(根据设置,超过一定数量时将临时锁定)
@ -136,20 +138,20 @@ class DatabaseInit:
# last_chpass: 最近一次修改密码时间(根据设置,密码可能有有效期限制)
f.append('`last_chpass` int(11) DEFAULT 0')
# email: 用户邮箱
f.append('`email` varchar(64) DEFAULT NULL')
f.append('`mobile` varchar(24) DEFAULT NULL')
f.append('`qq` varchar(24) DEFAULT NULL')
f.append('`wechat` varchar(32) DEFAULT NULL')
f.append('`desc` varchar(255) DEFAULT NULL')
f.append('`email` varchar(64) DEFAULT ""')
f.append('`mobile` varchar(24) DEFAULT ""')
f.append('`qq` varchar(24) DEFAULT ""')
f.append('`wechat` varchar(32) DEFAULT ""')
f.append('`desc` varchar(255) DEFAULT ""')
# login_time: 本次成功登录时间
f.append('`login_time` int(11) DEFAULT 0')
# last_login: 最近一次成功登录时间
f.append('`last_login` int(11) DEFAULT 0')
# login_ip: 本次成功登录IP
f.append('`login_ip` varchar(40) DEFAULT NULL')
f.append('`login_ip` varchar(40) DEFAULT ""')
# last_ip: 最近一次成功登录IP
f.append('`last_ip` varchar(40) DEFAULT NULL')
f.append('`last_ip` varchar(40) DEFAULT ""')
# creator_id: 创建者的用户id0=系统默认创建
f.append('`creator_id` int(11) DEFAULT 0')
@ -171,7 +173,7 @@ class DatabaseInit:
# user_id: user's id
f.append('`user_id` int(11) DEFAULT 0')
# token: token
f.append('`token` varchar(48) DEFAULT NULL')
f.append('`token` varchar(48) DEFAULT ""')
# create_time: 创建时间
f.append('`create_time` int(11) DEFAULT 0')
@ -190,9 +192,9 @@ class DatabaseInit:
# type 1=用户组2=主机组3=账号组
f.append('`type` int(11) DEFAULT 1')
# name: 组名称
f.append('`name` varchar(128) DEFAULT NULL')
f.append('`name` varchar(128) DEFAULT ""')
# desc: 详细描述
f.append('`desc` varchar(255) DEFAULT NULL')
f.append('`desc` varchar(255) DEFAULT ""')
# state: 状态1=正常2=禁用
f.append('`state` int(3) DEFAULT 1')
@ -241,14 +243,14 @@ class DatabaseInit:
# os_type: 操作系统类型1=win101=win2003srv102=win2008srvetc...2=linux201=ubuntu202=centosetc...3=others.
f.append('`os_type` int(11) DEFAULT 1')
# os_ver: 操作系统具体名称和版本,可选(手工填写,将来可以通过自动发现功能自动获取)
f.append('`os_ver` varchar(128) DEFAULT NULL')
f.append('`os_ver` varchar(128) DEFAULT ""')
# name: 名称,用于快速区分
f.append('`name` varchar(64) DEFAULT NULL')
f.append('`name` varchar(64) DEFAULT ""')
# ip: IP地址长度40是为了将来的ipv6准备的IPV6=X:X:X:X:X:X:X:X每个X为最长4字节总计39字节
f.append('`ip` varchar(40) NOT NULL')
# router_ip: 路由IP仅用于路由连接模式teleport与远程主机之间有路由网关该路由网关通过端口映射不同的远程主机
f.append('`router_ip` varchar(40) DEFAULT NULL')
f.append('`router_ip` varchar(40) DEFAULT ""')
# router_port: 路由端口,仅用于路由连接模式
f.append('`router_port` int(11) DEFAULT 0')
@ -257,10 +259,10 @@ class DatabaseInit:
# acc_count: 远程账号数量(注意创建/删除远程账号时更新此数据)
f.append('`acc_count` int(11) DEFAULT 0')
# cid: 公司内部用,资产统一编号
f.append('`cid` varchar(64) DEFAULT NULL')
f.append('`cid` varchar(64) DEFAULT ""')
# desc: 对此资产的详细描述
f.append('`desc` varchar(255) DEFAULT NULL')
f.append('`desc` varchar(255) DEFAULT ""')
# creator_id: 账号创建者的id0=系统默认创建
f.append('`creator_id` int(11) DEFAULT 0')
@ -288,7 +290,7 @@ class DatabaseInit:
# host_ip: 主机IP地址
f.append('`host_ip` varchar(40) NOT NULL')
# router_ip: 路由IP
f.append('`router_ip` varchar(40) DEFAULT NULL')
f.append('`router_ip` varchar(40) DEFAULT ""')
# router_port: 路由端口
f.append('`router_port` int(11) DEFAULT 0')
@ -308,15 +310,15 @@ class DatabaseInit:
# auth_type: 登录认证类型0=无认证1=password2=public-key
f.append('`auth_type` int(11) DEFAULT 0')
# username: 登录账号
f.append('`username` varchar(128) DEFAULT NULL')
f.append('`username` varchar(128) DEFAULT ""')
# username_prompt: 输入用户名的提示仅用于telnet协议
f.append('`username_prompt` varchar(128) DEFAULT NULL')
f.append('`username_prompt` varchar(128) DEFAULT ""')
# password_prompt: 输入密码的提示仅用于telnet协议
f.append('`password_prompt` varchar(128) DEFAULT NULL')
f.append('`password_prompt` varchar(128) DEFAULT ""')
# password: 登录密码仅当auth=1时有效
f.append('`password` varchar(255) DEFAULT NULL')
f.append('`password` varchar(255) DEFAULT ""')
# pri_key: 私钥仅当auth=2时有效
f.append('`pri_key` varchar(4096) DEFAULT NULL')
f.append('`pri_key` varchar(4096) DEFAULT ""')
# creator_id: 账号创建者的id0=系统默认创建
f.append('`creator_id` int(11) DEFAULT 0')
@ -337,20 +339,20 @@ class DatabaseInit:
# id: 自增主键
f.append('`id` integer PRIMARY KEY {}'.format(self.db.auto_increment))
# name: 此条账号认证信息的名称,用于显示
f.append('`name` varchar(128) DEFAULT NULL')
f.append('`name` varchar(128) DEFAULT ""')
# auth_type: 登录认证类型0=无认证1=password2=public-key
f.append('`auth_type` int(11) DEFAULT 0')
# username: 登录账号
f.append('`username` varchar(128) DEFAULT NULL')
f.append('`username` varchar(128) DEFAULT ""')
# username_prompt: 输入用户名的提示仅用于telnet协议
f.append('`username_prompt` varchar(128) DEFAULT NULL')
f.append('`username_prompt` varchar(128) DEFAULT ""')
# password_prompt: 输入密码的提示仅用于telnet协议
f.append('`password_prompt` varchar(128) DEFAULT NULL')
f.append('`password_prompt` varchar(128) DEFAULT ""')
# password: 登录密码仅当auth=1时有效
f.append('password varchar(255) DEFAULT NULL')
f.append('password varchar(255) DEFAULT ""')
# pri_key: 私钥仅当auth=2时有效
f.append('`pri_key` varchar(4096) DEFAULT NULL')
f.append('`pri_key` varchar(4096) DEFAULT ""')
# creator_id: 创建者的id0=系统默认创建
f.append('`creator_id` int(11) DEFAULT 0')
@ -373,9 +375,9 @@ class DatabaseInit:
f.append('`rank` int(11) DEFAULT 0')
# name: 策略名称
f.append('`name` varchar(128) DEFAULT NULL')
f.append('`name` varchar(128) DEFAULT ""')
# desc: 策略描述
f.append('`desc` varchar(255) DEFAULT NULL')
f.append('`desc` varchar(255) DEFAULT ""')
# start_time: 策略有效期起始时间(为0则忽略)
f.append('`start_time` int(11) DEFAULT 0')
# end_time: 策略有效期结束时间(为0则忽略)
@ -387,7 +389,7 @@ class DatabaseInit:
# limit_ip: 是否启用来源限制0=不限制1=白名单2=黑名单(尚未实现)
f.append('`limit_ip` int(3) DEFAULT 0')
# ip_list: 限制IP列表白名单或者黑名单
f.append('`ip_list` TEXT DEFAULT NULL')
f.append('`ip_list` TEXT')
# limit_time: 是否启用限时连接0=不限制1=限制(尚未实现)
f.append('`limit_time` int(3) DEFAULT 0')
@ -452,7 +454,7 @@ class DatabaseInit:
# rid: 外链对象的ID
f.append('`rid` int(11) DEFAULT 0')
# name: 外链对象的名称
f.append('`name` varchar(64) DEFAULT NULL')
f.append('`name` varchar(64) DEFAULT ""')
# state: 状态1=正常2=禁用3=临时锁定
f.append('`state` int(3) DEFAULT 1')
@ -518,21 +520,21 @@ class DatabaseInit:
# 后续字段仅用于显示
# u_name: 用户登录名
f.append('`u_name` varchar(32) DEFAULT NULL')
f.append('`u_name` varchar(32) DEFAULT ""')
# u_surname: 用户姓名
f.append('`u_surname` varchar(64) DEFAULT NULL')
f.append('`u_surname` varchar(64) DEFAULT ""')
# h_name: 主机名称
f.append('`h_name` varchar(64) DEFAULT NULL')
f.append('`h_name` varchar(64) DEFAULT ""')
# ip: IP地址
f.append('`ip` varchar(40) NOT NULL')
# router_ip: 路由IP
f.append('`router_ip` varchar(40) DEFAULT NULL')
f.append('`router_ip` varchar(40) DEFAULT ""')
# router_port: 路由端口
f.append('`router_port` int(11) DEFAULT 0')
# a_name: 登录账号
f.append('`a_name` varchar(128) DEFAULT NULL')
f.append('`a_name` varchar(128) DEFAULT ""')
# protocol_type: 协议类型0=1=SSH2=RDP3=TELNET
f.append('`protocol_type` int(11) DEFAULT 0')
# protocol_port: 协议端口
@ -550,18 +552,37 @@ class DatabaseInit:
# id: 自增主键
f.append('`id` integer PRIMARY KEY {}'.format(self.db.auto_increment))
# rank: 排序,非常重要,影响到策略生效的顺序
f.append('`rank` int(11) DEFAULT 0')
# name: 策略名称
f.append('`name` varchar(128) DEFAULT NULL')
f.append('`name` varchar(128) DEFAULT ""')
# desc: 策略描述
f.append('`desc` varchar(255) DEFAULT NULL')
f.append('`desc` varchar(255) DEFAULT ""')
# start_time: 策略有效期起始时间(为0则忽略)
f.append('`start_time` int(11) DEFAULT 0')
# end_time: 策略有效期结束时间(为0则忽略)
f.append('`end_time` int(11) DEFAULT 0')
# state: 状态1=正常2=禁用3=临时锁定
# state: 状态1=正常2=禁用
f.append('`state` int(3) DEFAULT 1')
# limit_ip: 是否启用来源限制0=不限制1=白名单2=黑名单(尚未实现)
f.append('`limit_ip` int(3) DEFAULT 0')
# ip_list: 限制IP列表白名单或者黑名单
f.append('`ip_list` TEXT')
# limit_time: 是否启用限时连接0=不限制1=限制(尚未实现)
f.append('`limit_time` int(3) DEFAULT 0')
# 每一个weekX表示一天的时间段按位异或表示24个小时的每个小时是否限制连接对应位为0表示不限制允许连接
f.append('`limit_week1` int(11) DEFAULT 0')
f.append('`limit_week2` int(11) DEFAULT 0')
f.append('`limit_week3` int(11) DEFAULT 0')
f.append('`limit_week4` int(11) DEFAULT 0')
f.append('`limit_week5` int(11) DEFAULT 0')
f.append('`limit_week6` int(11) DEFAULT 0')
f.append('`limit_week7` int(11) DEFAULT 0')
# creator_id: 授权者的id0=系统默认创建
f.append('`creator_id` int(11) DEFAULT 0')
# create_time: 授权时间
@ -595,6 +616,10 @@ class DatabaseInit:
f.append('`rtype` int(11) DEFAULT 0')
# sid: 外链的ID
f.append('`rid` int(11) DEFAULT 0')
# name: 外链对象的名称
f.append('`name` varchar(64) DEFAULT ""')
# state: 状态1=正常2=禁用3=临时锁定
f.append('`state` int(3) DEFAULT 1')
# creator_id: 创建者的id0=系统默认创建
f.append('`creator_id` int(11) DEFAULT 0')
@ -613,19 +638,48 @@ class DatabaseInit:
# id: 自增主键
f.append('`id` integer PRIMARY KEY {}'.format(self.db.auto_increment))
# uid: 用户ID
f.append('`uid` int(11) DEFAULT 0')
# host_id: 主机ID
f.append('`host_id` int(11) DEFAULT 0')
# uni_id: 快速定位的索引 "pid-guid-uid-ghid-hid"
f.append('`uni_id` varchar(128) NOT NULL')
# uh_id: 快速定位的索引 "user_id - host-id"
f.append('`uh_id` varchar(36) NOT NULL')
# p_id: 授权策略ID
f.append('`p_id` int(11) DEFAULT 0')
# p_rank: 授权策略顺序
f.append('`p_rank` int(11) DEFAULT 0')
# p_state: 授权策略状态
f.append('`p_state` int(11) DEFAULT 0')
# policy_auth_type: 授权方式0=未知3=用户:主机4=用户:主机组7=用户组:主机8=用户组:主机组)
f.append('`policy_auth_type` int(11) DEFAULT 0')
# u_id: 用户ID
f.append('`u_id` int(11) DEFAULT 0')
# u_state: 用户状态
f.append('`u_state` int(11) DEFAULT 0')
# gu_id: 用户组ID
f.append('`gu_id` int(11) DEFAULT 0')
# gu_state: 用户组状态
f.append('`gu_state` int(11) DEFAULT 0')
# h_id: 主机ID
f.append('`h_id` int(11) DEFAULT 0')
# gh_id: 主机组ID
f.append('`gh_id` int(11) DEFAULT 0')
# 后续字段仅用于显示
# host_name: 主机名称
f.append('`host_name` varchar(64) DEFAULT NULL')
# u_name: 用户登录名
f.append('`u_name` varchar(32) DEFAULT ""')
# u_surname: 用户姓名
f.append('`u_surname` varchar(64) DEFAULT ""')
# h_name: 主机名称
f.append('`h_name` varchar(64) DEFAULT ""')
# ip: IP地址
f.append('`ip` varchar(40) NOT NULL')
# router_ip: 路由IP
f.append('`router_ip` varchar(40) DEFAULT NULL')
f.append('`router_ip` varchar(40) DEFAULT ""')
# router_port: 路由端口
f.append('`router_port` int(11) DEFAULT 0')
@ -642,20 +696,20 @@ class DatabaseInit:
f.append('`id` integer PRIMARY KEY {}'.format(self.db.auto_increment))
# user_name: 用户名
f.append('`user_name` varchar(32) DEFAULT NULL')
f.append('`user_name` varchar(32) DEFAULT ""')
# user_surname: 用户真实姓名
f.append('`user_surname` varchar(64) DEFAULT NULL')
f.append('`user_surname` varchar(64) DEFAULT ""')
# client_ip: 操作发起的IP地址
f.append('`client_ip` varchar(40) DEFAULT NULL')
f.append('`client_ip` varchar(40) DEFAULT ""')
# code: 操作结果(成功还是失败 TPE_XXXX
f.append('`code` int(11) DEFAULT 0')
# time: 日志发生时间
f.append('`log_time` int(11) DEFAULT 0')
# message: 说明
f.append('`message` varchar(255) DEFAULT NULL')
f.append('`message` varchar(255) DEFAULT ""')
# detail: 详细描述
f.append('`detail` TEXT DEFAULT NULL')
f.append('`detail` TEXT')
self._db_exec(
'创建系统日志表...',
@ -670,7 +724,7 @@ class DatabaseInit:
f.append('`id` integer PRIMARY KEY {}'.format(self.db.auto_increment))
# sid: 会话ID
f.append('`sid` varchar(32) DEFAULT NULL')
f.append('`sid` varchar(32) DEFAULT ""')
# 下列三个ID主要用于在线会话管理强行终止会话
# user_id: 操作的用户
@ -684,20 +738,20 @@ class DatabaseInit:
f.append('`state` int(11) DEFAULT 0')
# user_name: 用户名
f.append('`user_username` varchar(32) DEFAULT NULL')
f.append('`user_username` varchar(32) DEFAULT ""')
# user_surname: 用户姓名
f.append('`user_surname` varchar(64) DEFAULT NULL')
f.append('`user_surname` varchar(64) DEFAULT ""')
# host_ip: 目标主机IP
f.append('`host_ip` varchar(40) DEFAULT NULL')
f.append('`host_ip` varchar(40) DEFAULT ""')
# conn_ip: 端口转发模式=路由主机IP直连模式=目标主机IP
f.append('`conn_ip` varchar(40) DEFAULT NULL')
f.append('`conn_ip` varchar(40) DEFAULT ""')
f.append('`conn_port` int(11) DEFAULT 0')
# client_ip: 操作发起的IP地址
f.append('`client_ip` varchar(40) DEFAULT NULL')
f.append('`client_ip` varchar(40) DEFAULT ""')
# acc_username: 账号(远程主机登录账号名称)
f.append('`acc_username` varchar(128) DEFAULT NULL')
f.append('`acc_username` varchar(128) DEFAULT ""')
# auth_type: 远程登录认证方式
f.append('`auth_type` int(11) DEFAULT 0')

View File

@ -1,562 +0,0 @@
# -*- coding: utf-8 -*-
import json
import os
import shutil
from app.base.logger import log
class DatabaseUpgrade:
def __init__(self, db, step_begin, step_end):
self.db = db
self.step_begin = step_begin
self.step_end = step_end
def do_upgrade(self):
for i in range(self.db.DB_VERSION):
if self.db.current_ver < i + 1:
_f_name = '_upgrade_to_v{}'.format(i + 1)
if _f_name in dir(self):
if self.__getattribute__(_f_name)():
self.db.current_ver = i + 1
else:
return False
return True
def _upgrade_to_v2(self):
# 服务端升级到版本1.2.102.3时,管理员后台和普通用户后台合并了,数据库略有调整
_step = self.step_begin('检查数据库版本v2...')
try:
# 判断依据:
# 如果存在名为 ${prefix}sys_user 的表,说明是旧版本,需要升级
ret = self.db.is_table_exists('{}sys_user'.format(self.db.table_prefix))
if ret is None:
self.step_end(_step, -1, '无法连接到数据库')
return False
elif not ret:
self.step_end(_step, 0, '跳过 v1 到 v2 的升级操作')
return True
self.step_end(_step, 0, '需要升级到v2')
if self.db.db_type == self.db.DB_TYPE_SQLITE:
_step = self.step_begin(' - 备份数据库文件')
_bak_file = '{}.before-v1-to-v2'.format(self.db.sqlite_file)
if not os.path.exists(_bak_file):
shutil.copy(self.db.sqlite_file, _bak_file)
self.step_end(_step, 0)
# 将原来的普通用户的account_type从 0 改为 1
_step = self.step_begin(' - 调整用户账号类型...')
if not self.db.exec('UPDATE `{}account` SET `account_type`=1 WHERE `account_type`=0;'.format(self.db.table_prefix)):
self.step_end(_step, -1)
return False
else:
self.step_end(_step, 0)
# 将原来的管理员合并到用户账号表中
_step = self.step_begin(' - 合并管理员和普通用户账号...')
db_ret = self.db.query('SELECT * FROM `{}sys_user`;'.format(self.db.table_prefix))
if db_ret is None:
self.step_end(_step, 0)
return True
for i in range(len(db_ret)):
user_name = db_ret[i][1]
user_pwd = db_ret[i][2]
if not self.db.exec("""INSERT INTO `{}account`
(`account_type`, `account_name`, `account_pwd`, `account_status`, `account_lock`, `account_desc`)
VALUES (100,"{}","{}",0,0,"{}");""".format(self.db.table_prefix, user_name, user_pwd, '超级管理员')):
self.step_end(_step, -1)
return False
# 移除旧的表(暂时改名而不是真的删除)
_step = self.step_begin(' - 移除不再使用的数据表...')
if not self.db.exec('ALTER TABLE `{}sys_user` RENAME TO `_bak_ts_sys_user`;'.format(self.db.table_prefix)):
self.step_end(_step, 0)
return False
else:
self.step_end(_step, -1)
return True
except:
log.e('failed.\n')
self.step_end(_step, -1)
return False
def _upgrade_to_v3(self):
# 服务端升级到版本1.5.217.9时,为了支持一机多用户多协议,数据库结构有较大程度改动
_step = self.step_begin('检查数据库版本v3...')
try:
# 判断依据:
# 如果不存在名为 ts_host_info 的表,说明是旧版本,需要升级
ret = self.db.is_table_exists('{}host_info'.format(self.db.table_prefix))
if ret is None:
self.step_end(_step, -1)
return False
elif ret:
self.step_end(_step, 0, '跳过 v2 到 v3 的升级操作')
return True
self.step_end(_step, 0, '需要升级到v3')
if self.db.db_type == self.db.DB_TYPE_SQLITE:
_step = self.step_begin(' - 备份数据库文件')
_bak_file = '{}.before-v2-to-v3'.format(self.db.sqlite_file)
if not os.path.exists(_bak_file):
shutil.copy(self.db.sqlite_file, _bak_file)
self.step_end(_step, 0)
_step = self.step_begin(' - 调整数据表...')
if not self.db.exec('ALTER TABLE `{}auth` ADD `host_auth_id` INTEGER;'.format(self.db.table_prefix)):
self.step_end(_step, -1, '无法在auth表中加入host_auth_id字段')
return False
if not self.db.exec('UPDATE `{}auth` SET `host_auth_id`=`host_id`;'.format(self.db.table_prefix)):
self.step_end(_step, -1, '无法将auth表中host_auth_id字段的值均调整为host_id字段的值')
return False
if not self.db.exec('ALTER TABLE `{}log` ADD `protocol` INTEGER;'.format(self.db.table_prefix)):
self.step_end(_step, -1, '无法在log表中加入protocol字段')
return False
if not self.db.exec('UPDATE `{}log` SET `protocol`=1 WHERE `sys_type`=1;'.format(self.db.table_prefix)):
self.step_end(_step, -1, '无法修正log表中的protocol字段数据(1)')
return False
if not self.db.exec('UPDATE `{}log` SET `protocol`=2 WHERE `sys_type`=2;'.format(self.db.table_prefix)):
self.step_end(_step, -1, '无法修正log表中的protocol字段数据(2)')
return False
if not self.db.exec('UPDATE `{}log` SET `ret_code`=9999 WHERE `ret_code`=0;'.format(self.db.table_prefix)):
self.step_end(_step, -1, '无法修正log表中的ret_code字段数据')
return False
self.step_end(_step, 0)
_step = self.step_begin(' - 拆分数据表...')
# 新建两个表,用于拆分原来的 ts_host 表
if not self.db.exec("""CREATE TABLE `{}host_info` (
`host_id` integer PRIMARY KEY {},
`group_id` int(11) DEFAULT 0,
`host_sys_type` int(11) DEFAULT 1,
`host_ip` varchar(32) DEFAULT '',
`pro_port` varchar(255) NULL,
`host_lock` int(11) DEFAULT 0,
`host_desc` varchar(128) DEFAULT ''
);""".format(self.db.table_prefix, self.db.auto_increment)):
self.step_end(_step, -1)
return False
if not self.db.exec("""CREATE TABLE `{}auth_info` (
`id` INTEGER PRIMARY KEY {},
`host_id` INTEGER,
`pro_type` INTEGER,
`auth_mode` INTEGER,
`user_name` varchar(255),
`user_pswd` varchar(255),
`cert_id` INTEGER,
`encrypt` INTEGER,
`log_time` varchar(60)
);""".format(self.db.table_prefix, self.db.auto_increment)):
self.step_end(_step, -1)
return False
# 将原来的 ts_host 表改名
if not self.db.exec('ALTER TABLE `{}host` RENAME TO `_bak_{}host;`'.format(self.db.table_prefix, self.db.table_prefix)):
self.step_end(_step, -1)
return False
self.step_end(_step, 0)
_step = self.step_begin(' - 调整数据内容...')
# 从原来 ts_host 表中查询出所有数据
db_ret = self.db.query('SELECT * FROM `_bak_{}host;`'.format(self.db.table_prefix))
if db_ret is not None:
for i in range(len(db_ret)):
host_id = db_ret[i][0]
group_id = db_ret[i][1]
host_sys_type = db_ret[i][2]
host_ip = db_ret[i][3]
host_pro_port = db_ret[i][4]
host_user_name = db_ret[i][5]
host_user_pwd = db_ret[i][6]
host_pro_type = db_ret[i][7]
cert_id = db_ret[i][8]
host_lock = db_ret[i][9]
host_encrypt = db_ret[i][10]
host_auth_mode = db_ret[i][11]
host_desc = db_ret[i][12]
_pro_port = {}
_pro_port['ssh'] = {}
_pro_port['ssh']['enable'] = 0
_pro_port['ssh']['port'] = 22
_pro_port['rdp'] = {}
_pro_port['rdp']['enable'] = 0
_pro_port['rdp']['port'] = 3389
if host_pro_type == 1:
_pro_port['rdp']['enable'] = 1
_pro_port['rdp']['port'] = host_pro_port
elif host_pro_type == 2:
_pro_port['ssh']['enable'] = 1
_pro_port['ssh']['port'] = host_pro_port
pro_port = json.dumps(_pro_port)
sql = 'INSERT INTO `{}host_info` (`host_id`, `group_id`, `host_sys_type`, `host_ip`, `pro_port`, `host_lock`, `host_desc`) ' \
'VALUES ({}, {}, {}, "{}", "{}", {}, "{}");'.format(self.db.table_prefix, host_id, group_id, host_sys_type, host_ip, pro_port, host_lock, host_desc)
if not self.db.exec(sql):
self.step_end(_step, -1)
return False
sql = 'INSERT INTO `{}auth_info` (`host_id`, `pro_type`, `auth_mode`, `user_name`, `user_pswd`, `cert_id`, `encrypt`, `log_time`) ' \
'VALUES ({}, {}, {}, "{}", "{}", {}, {}, "{}");'.format(self.db.table_prefix, host_id, host_pro_type, host_auth_mode, host_user_name, host_user_pwd, cert_id, host_encrypt, '1')
if not self.db.exec(sql):
self.step_end(_step, -1)
return False
self.step_end(_step, 0)
return True
except:
log.e('failed.\n')
self.step_end(_step, -1)
return False
def _upgrade_to_v4(self):
_step = self.step_begin('检查数据库版本v4...')
# 服务端升级到版本1.6.224.3时加入telnet支持数据库有调整
try:
# 判断依据:
# 如果ts_host_info表中还有pro_port字段说明是旧版本需要升级
db_ret = self.db.query('SELECT `pro_port` FROM `{}host_info` LIMIT 0;'.format(self.db.table_prefix))
if db_ret is None:
self.step_end(_step, 0, '跳过 v3 到 v4 的升级操作')
return True
self.step_end(_step, 0, '需要升级到v4')
if self.db.db_type == self.db.DB_TYPE_SQLITE:
_step = self.step_begin(' - 备份数据库文件')
_bak_file = '{}.before-v3-to-v4'.format(self.db.sqlite_file)
if not os.path.exists(_bak_file):
shutil.copy(self.db.sqlite_file, _bak_file)
self.step_end(_step, 0)
_step = self.step_begin(' - 为telnet增加默认配置')
# 如果ts_config表中没有ts_server_telnet_port项则增加默认值52389
db_ret = self.db.query('SELECT * FROM `{}config` WHERE `name`="ts_server_telnet_port";'.format(self.db.table_prefix))
if len(db_ret) == 0:
if not self.db.exec('INSERT INTO `{}config` (`name`, `value`) VALUES ("ts_server_telnet_port", "52389");'.format(self.db.table_prefix)):
self.step_end(_step, -1)
return False
self.step_end(_step, 0)
_step = self.step_begin(' - 调整认证数据表数据...')
auth_info_ret = self.db.query('SELECT `id`, `host_id`, `pro_type`, `auth_mode`, `user_name`, `user_pswd`, `cert_id`, `encrypt`, `log_time` FROM `{}auth_info`;'.format(self.db.table_prefix))
auth_ret = self.db.query('SELECT `auth_id`, `account_name`, `host_id`, `host_auth_id` FROM `{}auth`;'.format(self.db.table_prefix))
max_host_id = 0
new_host_info = []
new_auth_info = []
new_auth = []
# 从原来的表中查询数据
host_info_ret = self.db.query('SELECT `host_id`, `group_id`, `host_sys_type`, `host_ip`, `pro_port`, `host_lock`, `host_desc` FROM {}host_info;'.format(self.db.table_prefix))
if host_info_ret is None:
self.step_end(_step, 0, '尚无认证数据,跳过处理')
return True
# 先找出最大的host_id这样如果要拆分一个host就知道新的host_id应该是多少了
for i in range(len(host_info_ret)):
if host_info_ret[i][0] > max_host_id:
max_host_id = host_info_ret[i][0]
max_host_id += 1
# 然后构建新的host列表
for i in range(len(host_info_ret)):
host_info = {}
host_info_alt = None
protocol = json.loads(host_info_ret[i][4])
host_info['host_id'] = host_info_ret[i][0]
host_info['group_id'] = host_info_ret[i][1]
host_info['host_sys_type'] = host_info_ret[i][2]
host_info['host_ip'] = host_info_ret[i][3]
host_info['host_lock'] = host_info_ret[i][5]
host_info['host_desc'] = host_info_ret[i][6]
host_info['_old_host_id'] = host_info_ret[i][0]
host_info['host_port'] = 0
host_info['protocol'] = 0
have_rdp = False
have_ssh = False
if auth_info_ret is not None:
for j in range(len(auth_info_ret)):
if auth_info_ret[j][1] == host_info['host_id']:
if auth_info_ret[j][2] == 1: # 用到了此主机的RDP
have_rdp = True
elif auth_info_ret[j][2] == 2: # 用到了此主机的SSH
have_ssh = True
if have_rdp and have_ssh:
# 需要拆分
host_info['protocol'] = 1
host_info['host_port'] = protocol['rdp']['port']
host_info_alt = {}
host_info_alt['host_id'] = max_host_id
max_host_id += 1
host_info_alt['group_id'] = host_info_ret[i][1]
host_info_alt['host_sys_type'] = host_info_ret[i][2]
host_info_alt['host_ip'] = host_info_ret[i][3]
host_info_alt['host_lock'] = host_info_ret[i][5]
host_info_alt['host_desc'] = host_info_ret[i][6]
host_info_alt['_old_host_id'] = host_info_ret[i][0]
host_info_alt['host_port'] = protocol['ssh']['port']
host_info_alt['protocol'] = 2
elif have_rdp:
host_info['protocol'] = 1
host_info['host_port'] = protocol['rdp']['port']
elif have_ssh:
host_info['host_port'] = protocol['ssh']['port']
host_info['protocol'] = 2
new_host_info.append(host_info)
if host_info_alt is not None:
new_host_info.append(host_info_alt)
# 现在有了新的ts_host_info表重构ts_auth_info表
if auth_info_ret is not None:
for i in range(len(auth_info_ret)):
auth_info = {}
auth_info['id'] = auth_info_ret[i][0]
auth_info['auth_mode'] = auth_info_ret[i][3]
auth_info['user_name'] = auth_info_ret[i][4]
auth_info['user_pswd'] = auth_info_ret[i][5]
auth_info['cert_id'] = auth_info_ret[i][6]
auth_info['encrypt'] = auth_info_ret[i][7]
auth_info['log_time'] = auth_info_ret[i][8]
auth_info['user_param'] = 'ogin:\nassword:'
found = False
for j in range(len(new_host_info)):
if auth_info_ret[i][1] == new_host_info[j]['_old_host_id'] and auth_info_ret[i][2] == new_host_info[j]['protocol']:
found = True
auth_info['host_id'] = new_host_info[j]['host_id']
auth_info['_old_host_id'] = new_host_info[j]['_old_host_id']
break
if found:
new_auth_info.append(auth_info)
# 最后重构ts_auth表
if auth_ret is not None:
for i in range(len(auth_ret)):
auth = {}
auth['auth_id'] = auth_ret[i][0]
auth['account_name'] = auth_ret[i][1]
found = False
for j in range(len(new_auth_info)):
if auth_ret[i][2] == new_auth_info[j]['_old_host_id'] and auth_ret[i][3] == new_auth_info[j]['id']:
found = True
auth['host_id'] = new_auth_info[j]['host_id']
auth['host_auth_id'] = new_auth_info[j]['id']
break
if found:
new_auth.append(auth)
self.step_end(_step, 0)
_step = self.step_begin(' - 重新整理认证数据表结构及数据...')
# 将整理好的数据写入新的临时表
# 先创建三个临时表
if not self.db.exec("""CREATE TABLE `{}auth_tmp` (
`auth_id` INTEGER PRIMARY KEY {},
`account_name` varchar(255),
`host_id` INTEGER,
`host_auth_id` int(11) NOT NULL
);""".format(self.db.table_prefix, self.db.auto_increment)):
self.step_end(_step, -1, '无法创建认证数据临时表')
return False
if not self.db.exec("""CREATE TABLE `{}host_info_tmp` (
`host_id` integer PRIMARY KEY {},
`group_id` int(11) DEFAULT 0,
`host_sys_type` int(11) DEFAULT 1,
`host_ip` varchar(32) DEFAULT '',
`host_port` int(11) DEFAULT 0,
`protocol` int(11) DEFAULT 0,
`host_lock` int(11) DEFAULT 0,
`host_desc` DEFAULT ''
);""".format(self.db.table_prefix, self.db.auto_increment)):
self.step_end(_step, -1, '无法创建主机信息数据临时表')
return False
if not self.db.exec("""CREATE TABLE `{}auth_info_tmp` (
`id` INTEGER PRIMARY KEY {},
`host_id` INTEGER,
`auth_mode` INTEGER,
`user_name` varchar(255),
`user_pswd` varchar(255),
`user_param` varchar(255),
`cert_id` INTEGER,
`encrypt` INTEGER,
`log_time` varchar(60)
);""".format(self.db.table_prefix, self.db.auto_increment)):
self.step_end(_step, -1, '无法创建认证信息数据临时表')
return False
for i in range(len(new_host_info)):
sql = 'INSERT INTO `{}host_info_tmp` (`host_id`, `group_id`, `host_sys_type`, `host_ip`, `host_port`, `protocol`, `host_lock`, `host_desc`) ' \
'VALUES ({}, {}, {}, \'{}\', {}, {}, {}, "{}");'.format(
self.db.table_prefix,
new_host_info[i]['host_id'], new_host_info[i]['group_id'], new_host_info[i]['host_sys_type'],
new_host_info[i]['host_ip'], new_host_info[i]['host_port'], new_host_info[i]['protocol'],
new_host_info[i]['host_lock'], new_host_info[i]['host_desc']
)
if not self.db.exec(sql):
self.step_end(_step, -1, '无法调整数据(1)')
return False
for i in range(len(new_auth_info)):
sql = 'INSERT INTO `{}auth_info_tmp` (`id`, `host_id`, `auth_mode`, `user_name`, `user_pswd`, `user_param`, `cert_id`, `encrypt`, `log_time`) ' \
'VALUES ({}, {}, {}, "{}", "{}", "{}", {}, {}, "{}");'.format(
self.db.table_prefix,
new_auth_info[i]['id'], new_auth_info[i]['host_id'], new_auth_info[i]['auth_mode'],
new_auth_info[i]['user_name'], new_auth_info[i]['user_pswd'], new_auth_info[i]['user_param'],
new_auth_info[i]['cert_id'], new_auth_info[i]['encrypt'], '1'
)
if not self.db.exec(sql):
self.step_end(_step, -1, '无法调整数据(2)')
return False
for i in range(len(new_auth)):
sql = 'INSERT INTO `{}auth_tmp` (`auth_id`, `account_name`, `host_id`, `host_auth_id`) ' \
'VALUES ({}, \'{}\', {}, {});'.format(
self.db.table_prefix,
new_auth[i]['auth_id'], new_auth[i]['account_name'], new_auth[i]['host_id'], new_auth[i]['host_auth_id']
)
if not self.db.exec(sql):
self.step_end(_step, -1, '无法调整数据(3)')
return False
# 表改名
if not self.db.exec('ALTER TABLE `{}auth` RENAME TO `__bak_{}auth`;'.format(self.db.table_prefix, self.db.table_prefix)):
self.step_end(_step, -1, '无法处理临时表(1)')
return False
if not self.db.exec('ALTER TABLE `{}auth_info` RENAME TO `__bak_{}auth_info`;'.format(self.db.table_prefix, self.db.table_prefix)):
self.step_end(_step, -1, '无法处理临时表(2)')
return False
if not self.db.exec('ALTER TABLE `{}host_info` RENAME TO `__bak_{}host_info`;'.format(self.db.table_prefix, self.db.table_prefix)):
self.step_end(_step, -1, '无法处理临时表(3)')
return False
if not self.db.exec('ALTER TABLE `{}auth_tmp` RENAME TO `{}auth`;'.format(self.db.table_prefix, self.db.table_prefix)):
self.step_end(_step, -1, '无法处理临时表(4)')
return False
if not self.db.exec('ALTER TABLE `{}auth_info_tmp` RENAME TO `{}auth_info`;'.format(self.db.table_prefix, self.db.table_prefix)):
self.step_end(_step, -1, '无法处理临时表(5)')
return False
if not self.db.exec('ALTER TABLE `{}host_info_tmp` RENAME TO `{}host_info`;'.format(self.db.table_prefix, self.db.table_prefix)):
self.step_end(_step, -1, '无法处理临时表(6)')
return False
self.step_end(_step, 0)
return True
except:
log.e('failed.\n')
self.step_end(_step, -1)
return False
def _upgrade_to_v5(self):
_step = self.step_begin('检查数据库版本v5...')
# 服务端升级到版本2.1.0.1时,为解决将来数据库升级的问题,在 ts_config 表中加入 db_ver 指明当前数据结构版本
try:
# 判断依据:
# 如果 config 表中不存在名为db_ver的数据说明是旧版本需要升级
if not self.db.is_table_exists('{}config'.format(self.db.table_prefix)):
if not self.db.exec("""CREATE TABLE `{}config` (
`name` varchar(128) NOT NULL,
`value` varchar(255),
PRIMARY KEY (`name` ASC)
);""".format(self.db.table_prefix)):
self.step_end(_step, -1, 'config表不存在且无法创建')
return False
db_ret = self.db.query('SELECT `value` FROM `{}config` WHERE `name`="db_ver";'.format(self.db.table_prefix))
if db_ret is None:
self.step_end(_step, -1)
return False
if len(db_ret) > 0 and int(db_ret[0][0]) >= self.db.DB_VERSION:
self.step_end(_step, 0, '跳过 v4 到 v5 的升级操作')
return True
self.step_end(_step, 0, '需要升级到v5')
_step = self.step_begin(' - 调整数据表字段名与表名')
if not self.db.exec('ALTER TABLE `{}cert` RENAME TO `{}key`;'.format(self.db.table_prefix, self.db.table_prefix)):
self.step_end(_step, -1)
return False
self.step_end(_step, 0)
_step = self.step_begin(' - 更新数据库版本号')
if not self.db.exec('INSERT INTO `{}config` VALUES ("db_ver", "{}");'.format(self.db.table_prefix, self.db.DB_VERSION)):
self.step_end(_step, -1)
return False
else:
self.step_end(_step, 0)
return True
except:
log.e('failed.\n')
self.step_end(_step, -1)
return False
def _upgrade_to_v6(self):
_step = self.step_begin('检查数据库版本v6...')
# 服务端升级到版本2.2.9时为增加双因子认证为account表增加oath_secret字段
db_ret = self.db.is_field_exists('{}account'.format(self.db.table_prefix), 'oath_secret')
if db_ret is None:
self.step_end(_step, -1, '无法连接到数据库')
return False
if db_ret:
self.step_end(_step, 0, '跳过 v5 到 v6 的升级操作')
return True
self.step_end(_step, 0, '需要升级到v6')
try:
_step = self.step_begin(' - 在account表中加入oath_secret字段')
if not self.db.exec('ALTER TABLE {}account ADD oath_secret VARCHAR(64) DEFAULT ""'.format(self.db.table_prefix)):
self.step_end(_step, -1, '失败')
return False
_step = self.step_begin(' - 更新数据库版本号')
if not self.db.exec('UPDATE `{}config` SET `value`="6" WHERE `name`="db_ver";'.format(self.db.table_prefix)):
self.step_end(_step, -1, '无法更新数据库版本号')
return False
else:
self.step_end(_step, 0)
return True
except:
log.e('failed.\n')
self.step_end(_step, -1)
return False

View File

@ -12,7 +12,7 @@ from app.base.configs import get_cfg
from app.base.utils import AttrDict, tp_make_dir
from app.base.logger import log
from .database.create import DatabaseInit
from .database.upgrade import DatabaseUpgrade
#from .database.upgrade import DatabaseUpgrade
from .database.export import export_database
__all__ = ['get_db', 'SQL']

View File

@ -167,6 +167,7 @@ TPE_NEED_MORE_DATA = 1
TPE_NEED_LOGIN = 2
TPE_PRIVILEGE = 3
TPE_NOT_IMPLEMENT = 7
TPE_EXISTS = 8
TPE_NOT_EXISTS = 9

View File

@ -1,43 +1,38 @@
# -*- coding: utf-8 -*-
#import os
from app.base.configs import get_cfg
from app.controller import auth
from . import index
# from . import cert
# from . import config
from . import dashboard
# from . import group
from . import host
from . import account
from . import maintenance
from . import audit
from . import rpc
from . import user
from . import dashboard
from . import group
from . import host
from . import index
from . import maintenance
from . import ops
from . import rpc
from . import system
from . import user
__all__ = ['controllers', 'fix_controller']
controllers = [
(r'/', index.IndexHandler),
# (r'/', user.UserListHandler),
# ====================================================
# 控制台
# ====================================================
# - 控制台页面
(r'/dashboard', dashboard.IndexHandler),
# ====================================================
# 远程调用
# 外部调用接口
# ====================================================
(r'/rpc', rpc.RpcHandler),
#
# ====================================================
# 登录认证相关
# ====================================================
# - 登录页面
(r'/auth/login', auth.LoginHandler),
# - [json] 执行登录操作
@ -50,25 +45,10 @@ controllers = [
(r'/auth/captcha', auth.CaptchaHandler),
# - [json] 执行验证码验证操作
(r'/auth/verify-captcha', auth.VerifyCaptchaHandler),
# (r'/auth/modify-pwd', auth.ModifyPwd),
# (r'/auth/oath-verify', auth.OathVerifyHandler),
# (r'/auth/oath-secret-qrcode', auth.OathSecretQrCodeHandler),
# (r'/auth/oath-secret-reset', auth.OathSecretResetHandler),
# (r'/auth/oath-update-secret', auth.OathUpdateSecretHandler),
#
# # (r"/log/replay/(.*)", tornado.web.StaticFileHandler, {"path": os.path.join(cfg.data_path, 'replay')}),
# (r"/log/replay/(.*)", record.ReplayStaticFileHandler, {"path": os.path.join(get_cfg().data_path, 'replay')}),
#
# (r'/log/list', record.LogList),
# (r'/log/get-record-header', record.RecordGetHeader),
# (r'/log/get-record-file-info', record.RecordGetInfo),
# (r'/log/delete-log', record.DeleteLog),
# # (r'/log/play-rdp/(.*)/(.*)', record.PlayRdpHandler),
# (r'/log/', record.LogHandler),
# (r'/log', record.LogHandler),
#
# ====================================================
# 用户相关
# ====================================================
# 用户账号相关
# - 个人中心页面
(r'/user/me', user.MeHandler),
# - 用户管理页面
@ -97,7 +77,7 @@ controllers = [
(r'/user/verify-user', user.DoVerifyUserHandler),
# - [json] 绑定身份认证器
(r'/user/do-bind-oath', user.DoBindOathHandler),
#
# - 用户组管理页面
(r'/user/group', user.GroupListHandler),
# - 某个用户组的管理页面
@ -109,11 +89,14 @@ controllers = [
# - [json] 批量设置角色
(r'/user/set-role', user.DoSetRoleForUsersHandler),
# ====================================================
# 资产相关
# ====================================================
# - 主机及账号管理页面
(r'/asset/host', host.HostListHandler),
# - [json] 批量导入
(r'/asset/upload-import', host.DoImportHandler),
#
# - 主机分组管理页面
(r'/asset/host-group', host.HostGroupListHandler),
# - 某个主机组的管理页面
@ -128,7 +111,7 @@ controllers = [
(r'/asset/get-hosts', host.DoGetHostsHandler),
# - [json] 获取账号组列表包括不超过5个组内成员
(r'/asset/get-host-groups-with-member', host.DoGetHostGroupWithMemberHandler),
#
# - 远程账号分组管理页面
(r'/asset/account-group', account.AccGroupListHandler),
# - 某个账号组的管理页面
@ -143,6 +126,9 @@ controllers = [
(r'/asset/get-account-groups-with-member', account.DoGetAccountGroupWithMemberHandler),
# ====================================================
# 远程运维相关
# ====================================================
# - 运维授权管理页面
(r'/ops/auz', ops.AuzListHandler),
# - 远程运维页面
@ -176,11 +162,16 @@ controllers = [
# - [json] 构建授权映射表
(r'/ops/build-auz-map', ops.DoBuildAuzMapHandler),
# ====================================================
# 审计相关
# ====================================================
# - 审计授权管理页面
(r'/audit/auz', audit.AuzListHandler),
# - 审计页面(录像列表)
(r'/audit/record', audit.RecordHandler),
# - [json] 审计页面(录像列表)
(r'/audit/get-records', audit.DoGetRecordsHandler),
#
# - ssh录像回放页面
(r'/audit/replay/(.*)/(.*)', audit.ReplayHandler),
# - ssh命令日志页面
@ -191,15 +182,12 @@ controllers = [
(r'/audit/get-record-data', audit.DoGetRecordDataHandler),
# (r'/host/export-host', host.ExportHostHandler),
# (r'/host/get-session-id', host.GetSessionId),
# (r'/host/admin-get-session-id', host.AdminGetSessionId),
# (r'/host/admin-fast-get-session-id', host.AdminFastGetSessionId),
#
# (r'/config/export-database', config.ExportDatabaseHandler),
# (r'/config/import-database', config.ImportDatabaseHandler),
# ====================================================
# 分组操作相关
# ====================================================
# - [json] 创建或更新分组
(r'/group/update', group.DoUpdateGroupHandler),
# - [json] 禁用分组
@ -217,6 +205,7 @@ controllers = [
# ====================================================
# 系统管理设置相关
# ====================================================
# - 角色管理页面
(r'/system/role', system.RoleHandler),
# - [json] 创建/更新 角色
@ -235,20 +224,19 @@ controllers = [
(r'/system/send-test-mail', system.DoSendTestMailHandler),
# - [json] 系统配置-清理存储空间
(r'/system/cleanup-storage', system.DoCleanupStorageHandler),
#
# - [json] 获取服务器时间
(r'/system/get-time', system.DoGetTimeHandler),
# ====================================================
# 安装维护相关
# ====================================================
# - 初始安装设置(新安装,未创建数据库时自动跳转到此页面)
(r'/maintenance/install', maintenance.InstallHandler),
# - 升级(数据库版本发生变化时跳转到此页面)
# (r'/maintenance/upgrade', maintenance.UpgradeHandler),
# - [json] 维护过程中页面与后台的通讯接口
(r'/maintenance/rpc', maintenance.RpcHandler),
# (r'/maintenance/index', maintenance.IndexHandler),
# # (r'/maintenance', maintenance.IndexHandler),
(r'/.*', index.CatchAllHandler),
]

View File

@ -25,22 +25,13 @@ def get_free_space_bytes(folder):
except:
return 0, 0
# if platform.system() == 'Windows':
# _free_bytes = ctypes.c_ulonglong(0)
# _total_bytes = ctypes.c_ulonglong(0)
# ctypes.windll.kernel32.GetDiskFreeSpaceExW(folder, None, ctypes.pointer(_total_bytes), ctypes.pointer(_free_bytes))
# total_bytes = _total_bytes.value
# free_bytes = _free_bytes.value
# else:
# try:
# st = os.statvfs(folder)
# total_bytes = st.f_blocks * st.f_frsize
# free_bytes = st.f_bavail * st.f_frsize
# except:
# total_bytes = 0
# free_bytes = 0
#
# return total_bytes, free_bytes
class AuzListHandler(TPBaseHandler):
def get(self):
ret = self.check_privilege(TP_PRIVILEGE_AUDIT_AUZ)
if ret != TPE_OK:
return
self.show_error_page(TPE_NOT_IMPLEMENT)
class RecordHandler(TPBaseHandler):
@ -56,7 +47,6 @@ class RecordHandler(TPBaseHandler):
total_size, free_size = get_free_space_bytes(get_cfg().core.replay_path)
param = {
# 'user_list': user.get_user_list(with_admin=True),
'total_size': total_size,
'free_size': free_size,
}

View File

@ -291,13 +291,12 @@ class DoGetUsersHandler(TPBaseJsonHandler):
class DoImportHandler(TPBaseHandler):
IDX_USERNAME = 0
IDX_SURNAME = 1
IDX_AUTH_TYPE = 2
IDX_EMAIL = 3
IDX_MOBILE = 4
IDX_QQ = 5
IDX_WECHAT = 6
IDX_GROUP = 7
IDX_DESC = 8
IDX_EMAIL = 2
IDX_MOBILE = 3
IDX_QQ = 4
IDX_WECHAT = 5
IDX_GROUP = 6
IDX_DESC = 7
@tornado.gen.coroutine
def post(self):
@ -375,7 +374,7 @@ class DoImportHandler(TPBaseHandler):
continue
# 格式错误则记录在案,然后继续
if len(csv_recorder) != 9:
if len(csv_recorder) != 8:
failed.append({'line': line, 'error': '格式错误,字段数量不匹配。'})
continue
@ -385,20 +384,7 @@ class DoImportHandler(TPBaseHandler):
failed.append({'line': line, 'error': '格式错误,用户账号必须填写。'})
continue
# _auth = csv_recorder[self.IDX_AUTH_TYPE].strip()
# if len(_auth) == 0:
# failed.append({'line': line, 'error': '格式错误,用户认证类型必须填写。'})
# continue
# try:
# _auth = int(_auth)
# except:
# failed.append({'line': line, 'error': '格式错误,用户认证类型必须是数字。'})
# continue
_email = csv_recorder[self.IDX_EMAIL].strip()
# if len(_email) == 0:
# failed.append({'line': line, 'error': '格式错误,用户邮箱必须填写。'})
# continue
_group = csv_recorder[self.IDX_GROUP].split('|')
@ -636,15 +622,25 @@ class DoResetPasswordHandler(TPBaseJsonHandler):
except:
return self.write_json(TPE_PARAM)
# 根据需要进行弱密码检测
if get_cfg().sys.password.force_strong:
if not tp_check_strong_password(password):
return self.write_json(TPE_FAILED, '抱歉,不能使用弱密码!')
err, user_id = user.check_reset_token(token)
if err != TPE_OK:
return self.write_json(err)
elif mode == 5:
# 用户输入当前密码和新密码进行设置
try:
current_password = args['current_password']
password = args['password']
except:
return self.write_json(TPE_PARAM)
err, user_info = user.get_by_username(self.get_current_user()['username'])
if err != TPE_OK:
return self.write_json(err)
if not tp_password_verify(current_password, user_info['password']):
return self.write_json(TPE_USER_AUTH)
user_id = user_info['id']
else:
return self.write_json(TPE_PARAM)
@ -673,10 +669,15 @@ class DoResetPasswordHandler(TPBaseJsonHandler):
return self.write_json(err, msg)
elif mode == 2 or mode == 4:
elif mode == 2 or mode == 4 or mode == 5:
if len(password) == 0:
return self.write_json(TPE_PARAM)
# 根据需要进行弱密码检测
if get_cfg().sys.password.force_strong:
if not tp_check_strong_password(password):
return self.write_json(TPE_FAILED, '密码强度太弱强密码需要至少8个英文字符必须包含大写字母、小写字母和数字。')
password = tp_password_generate_secret(password)
err = user.set_password(self, user_id, password)

View File

@ -144,7 +144,7 @@ def update(handler, gid, name, desc):
return TPE_NOT_EXISTS
# 2. 更新记录
sql = 'UPDATE `{}group` SET name="{name}", desc="{desc}" WHERE id={gid};' \
sql = 'UPDATE `{}group` SET `name`="{name}", `desc`="{desc}" WHERE id={gid};' \
''.format(db.table_prefix, name=name, desc=desc, gid=gid)
db_ret = db.exec(sql)
if not db_ret:
@ -157,7 +157,7 @@ def add_members(gtype, gid, members):
db = get_db()
sql = []
for uid in members:
sql.append('INSERT INTO `{}group_map` (type, gid, mid) VALUES ({}, {}, {});'.format(db.table_prefix, gtype, gid, uid))
sql.append('INSERT INTO `{}group_map` (`type`, `gid`, `mid`) VALUES ({}, {}, {});'.format(db.table_prefix, gtype, gid, uid))
if db.transaction(sql):
return TPE_OK
else:

View File

@ -97,7 +97,7 @@ def add_host(handler, args):
if db_ret is not None and len(db_ret) > 0:
return TPE_EXISTS, 0
sql = 'INSERT INTO `{}host` (type, os_type, name, ip, router_ip, router_port, state, creator_id, create_time, cid, desc) VALUES ' \
sql = 'INSERT INTO `{}host` (`type`, `os_type`, `name`, `ip`, `router_ip`, `router_port`, `state`, `creator_id`, `create_time`, `cid`, `desc`) VALUES ' \
'(1, {os_type}, "{name}", "{ip}", "{router_ip}", {router_port}, {state}, {creator_id}, {create_time}, "{cid}", "{desc}");' \
''.format(db.table_prefix,
os_type=args['os_type'], name=args['name'], ip=args['ip'], router_ip=args['router_ip'], router_port=args['router_port'],
@ -221,7 +221,7 @@ def update_host(handler, args):
return TPE_NOT_EXISTS
sql_list = []
sql = 'UPDATE `{}host` SET os_type="{os_type}", name="{name}", ip="{ip}", router_ip="{router_ip}", router_port={router_port}, cid="{cid}", desc="{desc}" WHERE id={host_id};' \
sql = 'UPDATE `{}host` SET `os_type`="{os_type}", `name`="{name}", `ip`="{ip}", `router_ip`="{router_ip}", `router_port`={router_port}, `cid`="{cid}", `desc`="{desc}" WHERE `id`={host_id};' \
''.format(db.table_prefix,
os_type=args['os_type'], name=args['name'], ip=args['ip'], router_ip=args['router_ip'], router_port=args['router_port'],
cid=args['cid'], desc=args['desc'], host_id=args['id']
@ -229,7 +229,7 @@ def update_host(handler, args):
sql_list.append(sql)
# 更新所有此主机相关的账号
sql = 'UPDATE `{}acc` SET host_ip="{ip}", router_ip="{router_ip}", router_port={router_port} WHERE host_id={id};' \
sql = 'UPDATE `{}acc` SET `host_ip`="{ip}", `router_ip`="{router_ip}", `router_port`={router_port} WHERE `host_id`={id};' \
''.format(db.table_prefix,
ip=args['ip'], router_ip=args['router_ip'], router_port=args['router_port'], id=args['id'])
sql_list.append(sql)
@ -247,16 +247,16 @@ def update_hosts_state(handler, host_ids, state):
sql_list = []
sql = 'UPDATE `{}host` SET state={state} WHERE id IN ({host_ids});' \
sql = 'UPDATE `{}host` SET `state`={state} WHERE `id` IN ({host_ids});' \
''.format(db.table_prefix, state=state, host_ids=host_ids)
sql_list.append(sql)
# sync to update the ops-audit table.
sql = 'UPDATE `{}ops_auz` SET state={state} WHERE rtype={rtype} AND rid IN ({rid});' \
sql = 'UPDATE `{}ops_auz` SET `state`={state} WHERE `rtype`={rtype} AND `rid` IN ({rid});' \
''.format(db.table_prefix, state=state, rtype=TP_ACCOUNT, rid=host_ids)
sql_list.append(sql)
sql = 'UPDATE `{}ops_map` SET h_state={state} WHERE h_id IN ({host_ids});' \
sql = 'UPDATE `{}ops_map` SET `h_state`={state} WHERE `h_id` IN ({host_ids});' \
''.format(db.table_prefix, state=state, host_ids=host_ids)
sql_list.append(sql)

View File

@ -103,7 +103,7 @@ def create_policy(handler, args):
return TPE_DATABASE, 0
rank = db_ret[0][0] + 1
sql = 'INSERT INTO `{}ops_policy` (rank, name, desc, creator_id, create_time) VALUES ' \
sql = 'INSERT INTO `{}ops_policy` (`rank`, `name`, `desc`, `creator_id`, `create_time`) VALUES ' \
'({rank}, "{name}", "{desc}", {creator_id}, {create_time});' \
''.format(db.table_prefix,
rank=rank, name=args['name'], desc=args['desc'],
@ -131,7 +131,7 @@ def update_policy(handler, args):
if len(s.recorder) == 0:
return TPE_NOT_EXISTS
sql = 'UPDATE `{}ops_policy` SET name="{name}", desc="{desc}" WHERE id={p_id};' \
sql = 'UPDATE `{}ops_policy` SET `name`="{name}", `desc`="{desc}" WHERE `id`={p_id};' \
''.format(db.table_prefix,
name=args['name'], desc=args['desc'], p_id=args['id']
)
@ -149,13 +149,13 @@ def update_policies_state(handler, p_ids, state):
sql_list = []
sql = 'UPDATE `{}ops_policy` SET state={state} WHERE id IN ({p_ids});'.format(db.table_prefix, state=state, p_ids=p_ids)
sql = 'UPDATE `{}ops_policy` SET `state`={state} WHERE `id` IN ({p_ids});'.format(db.table_prefix, state=state, p_ids=p_ids)
sql_list.append(sql)
sql = 'UPDATE `{}ops_auz` SET state={state} WHERE policy_id IN ({p_ids});'.format(db.table_prefix, state=state, p_ids=p_ids)
sql = 'UPDATE `{}ops_auz` SET `state`={state} WHERE `policy_id` IN ({p_ids});'.format(db.table_prefix, state=state, p_ids=p_ids)
sql_list.append(sql)
sql = 'UPDATE `{}ops_map` SET p_state={state} WHERE p_id IN ({p_ids});'.format(db.table_prefix, state=state, p_ids=p_ids)
sql = 'UPDATE `{}ops_map` SET `p_state`={state} WHERE `p_id` IN ({p_ids});'.format(db.table_prefix, state=state, p_ids=p_ids)
sql_list.append(sql)
if db.transaction(sql_list):
@ -171,13 +171,13 @@ def remove_policies(handler, p_ids):
sql_list = []
sql = 'DELETE FROM `{}ops_policy` WHERE id IN ({p_ids});'.format(db.table_prefix, p_ids=p_ids)
sql = 'DELETE FROM `{}ops_policy` WHERE `id` IN ({p_ids});'.format(db.table_prefix, p_ids=p_ids)
sql_list.append(sql)
sql = 'DELETE FROM `{}ops_auz` WHERE policy_id IN ({p_ids});'.format(db.table_prefix, p_ids=p_ids)
sql = 'DELETE FROM `{}ops_auz` WHERE `policy_id` IN ({p_ids});'.format(db.table_prefix, p_ids=p_ids)
sql_list.append(sql)
sql = 'DELETE FROM `{}ops_map` WHERE p_id IN ({p_ids});'.format(db.table_prefix, p_ids=p_ids)
sql = 'DELETE FROM `{}ops_map` WHERE `p_id` IN ({p_ids});'.format(db.table_prefix, p_ids=p_ids)
sql_list.append(sql)
if db.transaction(sql_list):
@ -212,7 +212,7 @@ def add_members(handler, policy_id, policy_type, ref_type, members):
for m in members:
if m['id'] in exists_ids:
continue
str_sql = 'INSERT INTO `{}ops_auz` (policy_id, type, rtype, rid, name, creator_id, create_time) VALUES ' \
str_sql = 'INSERT INTO `{}ops_auz` (policy_id, type, rtype, rid, `name`, creator_id, create_time) VALUES ' \
'({pid}, {t}, {rtype}, {rid}, "{name}", {creator_id}, {create_time});' \
''.format(db.table_prefix,
pid=policy_id, t=policy_type, rtype=ref_type,
@ -523,7 +523,7 @@ def get_remotes(handler, sql_filter, sql_order, sql_limit):
######################################################
# step 2.
######################################################
sql_2 = 'SELECT * FROM ({}) GROUP BY ua_id'.format(sql_1)
sql_2 = 'SELECT * FROM ({}) AS s1 GROUP BY ua_id'.format(sql_1)
_f = ['id', 'p_id', 'h_id', 'h_state', 'gh_state', 'h_name', 'ip', 'router_ip', 'router_port']
@ -533,7 +533,7 @@ def get_remotes(handler, sql_filter, sql_order, sql_limit):
sql = []
sql.append('SELECT {}'.format(','.join(_f)))
sql.append('FROM')
sql.append('({})'.format(sql_2))
sql.append('({}) AS s2'.format(sql_2))
sql.append('GROUP BY h_id')
sql.append('ORDER BY ip')
sql.append('LIMIT {},{}'.format(sql_limit['page_index'] * sql_limit['per_page'], sql_limit['per_page']))
@ -542,11 +542,14 @@ def get_remotes(handler, sql_filter, sql_order, sql_limit):
sql_counter = []
sql_counter.append('SELECT COUNT(*)')
sql_counter.append('FROM')
sql_counter.append('({})'.format(sql_2))
sql_counter.append('({}) AS s3'.format(sql_2))
sql_counter.append('GROUP BY h_id')
sql_counter.append(';')
db_ret = db.query(' '.join(sql_counter))
if db_ret is None or len(db_ret) == 0:
return TPE_OK, 0, 1, []
total = len(db_ret)
ret_recorder = [] # 用于构建最终返回的数据
@ -580,11 +583,13 @@ def get_remotes(handler, sql_filter, sql_order, sql_limit):
_f = ['id', 'uni_id', 'policy_auth_type', 'p_id', 'h_id', 'a_id', 'a_state', 'ga_state', 'a_name', 'protocol_type']
sql.append('SELECT {}'.format(','.join(_f)))
sql.append('FROM')
sql.append('({})'.format(sql_4))
sql.append('({}) AS s4'.format(sql_4))
sql.append('GROUP BY ua_id')
sql.append(';')
db_ret = db.query(' '.join(sql))
if db_ret is None:
return TPE_OK, 0, 1, []
p_ids = [] # 涉及到的策略的ID列表
@ -601,7 +606,7 @@ def get_remotes(handler, sql_filter, sql_order, sql_limit):
ret_recorder[j].accounts_.append(item)
# 查询所有相关的授权策略的详细信息
print('p-ids:', p_ids)
# print('p-ids:', p_ids)
policy_ids = [str(i) for i in p_ids]
_f = ['id', 'flag_rdp', 'flag_ssh']
sql = []
@ -610,7 +615,7 @@ def get_remotes(handler, sql_filter, sql_order, sql_limit):
sql.append('WHERE id IN ({})'.format(','.join(policy_ids)))
sql.append(';')
db_ret = db.query(' '.join(sql))
print('', db_ret)
# print('', db_ret)
for db_item in db_ret:
item = AttrDict()
for i in range(len(_f)):
@ -621,7 +626,7 @@ def get_remotes(handler, sql_filter, sql_order, sql_limit):
if ret_recorder[i].accounts_[j].p_id == item.id:
ret_recorder[i].accounts_[j].policy_ = item
print(json.dumps(ret_recorder, indent=' '))
# print(json.dumps(ret_recorder, indent=' '))
return TPE_OK, total, sql_limit['page_index'], ret_recorder

View File

@ -256,7 +256,7 @@ def update_user(handler, args):
if db_ret is None or len(db_ret) == 0:
return TPE_NOT_EXISTS
sql = 'UPDATE `{}user` SET surname="{surname}", auth_type={auth_type}, role_id={role}, email="{email}", mobile="{mobile}", qq="{qq}", wechat="{wechat}", `desc`="{desc}" WHERE id={user_id};' \
sql = 'UPDATE `{}user` SET `surname`="{surname}", `auth_type`={auth_type}, `role_id`={role}, `email`="{email}", `mobile`="{mobile}", `qq`="{qq}", `wechat`="{wechat}", `desc`="{desc}" WHERE `id`={user_id};' \
''.format(db.table_prefix,
surname=args['surname'], auth_type=args['auth_type'], role=args['role'], email=args['email'],
mobile=args['mobile'], qq=args['qq'], wechat=args['wechat'], desc=args['desc'],