Commit 70e6904e authored by yumaojun's avatar yumaojun

Merge branch 'dev' of https://git.coding.net/jumpserver/jumpserver into dev

parents 8d941dc0 42745c52
...@@ -37,11 +37,9 @@ nosetests.xml ...@@ -37,11 +37,9 @@ nosetests.xml
.mr.developer.cfg .mr.developer.cfg
.project .project
.pydevproject .pydevproject
*.xlsx *.log
node_modules logs/*
logs keys/*
keys
jumpserver.conf jumpserver.conf
nohup.out nohup.out
tmp/* tmp/*
db.sqlite3
...@@ -25,7 +25,7 @@ from jumpserver.settings import LOG_DIR ...@@ -25,7 +25,7 @@ from jumpserver.settings import LOG_DIR
login_user = get_object(User, username=getpass.getuser()) login_user = get_object(User, username=getpass.getuser())
VIM_FLAG = False
try: try:
import termios import termios
...@@ -68,12 +68,40 @@ def check_vim_status(command, ssh): ...@@ -68,12 +68,40 @@ def check_vim_status(command, ssh):
return False return False
def deal_command(str_r, ssh):
class Tty(object):
"""
A virtual tty class
一个虚拟终端类,实现连接ssh和记录日志,基类
"""
def __init__(self, username, asset_name):
self.username = username
self.asset_name = asset_name
self.ip = None
self.port = 22
self.channel = None
#self.asset = get_object(Asset, name=asset_name)
#self.user = get_object(User, username=username)
self.role = None
self.ssh = None
self.connect_info = None
self.login_type = 'ssh'
@staticmethod
def is_output(strings):
newline_char = ['\n', '\r', '\r\n']
for char in newline_char:
if char in strings:
return True
return False
@staticmethod
def deal_command(str_r, ssh):
""" """
处理命令中特殊字符 处理命令中特殊字符
""" """
t = time.time()
str_r = re.sub('\x07','',str_r) #删除响铃 str_r = re.sub('\x07','',str_r) #删除响铃
patch_char = re.compile('\x08\x1b\[C') #删除方向左右一起的按键 patch_char = re.compile('\x08\x1b\[C') #删除方向左右一起的按键
while patch_char.search(str_r): while patch_char.search(str_r):
...@@ -190,33 +218,6 @@ def deal_command(str_r, ssh): ...@@ -190,33 +218,6 @@ def deal_command(str_r, ssh):
else: else:
return '' return ''
class Tty(object):
"""
A virtual tty class
一个虚拟终端类,实现连接ssh和记录日志,基类
"""
def __init__(self, username, asset_name):
self.username = username
self.asset_name = asset_name
self.ip = None
self.port = 22
self.channel = None
#self.asset = get_object(Asset, name=asset_name)
#self.user = get_object(User, username=username)
self.role = None
self.ssh = None
self.connect_info = None
self.login_type = 'ssh'
@staticmethod
def is_output(strings):
newline_char = ['\n', '\r', '\r\n']
for char in newline_char:
if char in strings:
return True
return False
@staticmethod @staticmethod
def remove_control_char(str_r): def remove_control_char(str_r):
""" """
...@@ -402,7 +403,7 @@ class SshTty(Tty): ...@@ -402,7 +403,7 @@ class SshTty(Tty):
input_mode = True input_mode = True
if str(x) in ['\r', '\n', '\r\n']: if str(x) in ['\r', '\n', '\r\n']:
data = self.remove_control_char(data) data = self.deal_command(data, self.ssh)
TtyLog(log=log, datetime=datetime.datetime.now(), cmd=data).save() TtyLog(log=log, datetime=datetime.datetime.now(), cmd=data).save()
data = '' data = ''
......
sphinx-me==0.3 sphinx-me==0.3
django==1.6 django==1.6
python-ldap==2.4.19
pycrypto==2.6.1 pycrypto==2.6.1
paramiko==1.15.2 paramiko==1.15.2
ecdsa==0.13 ecdsa==0.13
...@@ -10,3 +9,8 @@ psutil==2.2.1 ...@@ -10,3 +9,8 @@ psutil==2.2.1
xlsxwriter==0.7.7 xlsxwriter==0.7.7
xlrd==0.9.4 xlrd==0.9.4
django-bootstrap-form django-bootstrap-form
tornado
ansible
pyinotify
passlib
argparse
\ No newline at end of file
...@@ -9,11 +9,11 @@ log = debug ...@@ -9,11 +9,11 @@ log = debug
host = 127.0.0.1 host = 127.0.0.1
port = 3306 port = 3306
user = jumpserver user = jumpserver
password = mysql1234 password = mysql234
database = jumpserver database = jumpserver
[websocket] [websocket]
web_socket_host = 127.0.0.1:3000 web_socket_host = j:3000
[mail] [mail]
mail_enable = 1 mail_enable = 1
......
...@@ -197,9 +197,9 @@ def require_role(role='user'): ...@@ -197,9 +197,9 @@ def require_role(role='user'):
def _deco(func): def _deco(func):
def __deco(request, *args, **kwargs): def __deco(request, *args, **kwargs):
request.session['pre_url'] = request.path
if not request.user.is_authenticated(): if not request.user.is_authenticated():
return HttpResponseRedirect('/login/') return HttpResponseRedirect('/login/')
if role == 'admin': if role == 'admin':
# if request.session.get('role_id', 0) < 1: # if request.session.get('role_id', 0) < 1:
if request.user.role == 'CU': if request.user.role == 'CU':
......
...@@ -235,7 +235,7 @@ def Login(request): ...@@ -235,7 +235,7 @@ def Login(request):
request.session['role_id'] = 1 request.session['role_id'] = 1
else: else:
request.session['role_id'] = 0 request.session['role_id'] = 0
return HttpResponseRedirect(request.GET.get('next', '/'), ) return HttpResponseRedirect(request.session.get('pre_url', '/'))
# response.set_cookie('username', username, expires=604800) # response.set_cookie('username', username, expires=604800)
# response.set_cookie('seed', PyCrypt.md5_crypt(password), expires=604800) # response.set_cookie('seed', PyCrypt.md5_crypt(password), expires=604800)
# return response # return response
......
...@@ -11,17 +11,21 @@ urlpatterns = patterns('juser.views', ...@@ -11,17 +11,21 @@ urlpatterns = patterns('juser.views',
(r'^group_list/$', group_list), (r'^group_list/$', group_list),
(r'^group_del/$', group_del), (r'^group_del/$', group_del),
(r'^group_edit/$', group_edit), (r'^group_edit/$', group_edit),
(r'^user_add/$', user_add), (r'^user_add/$', user_add),
(r'^user_del/$', 'user_del'),
(r'^user_list/$', user_list), (r'^user_list/$', user_list),
(r'^user_edit/$', user_edit),
(r'^user_detail/$', 'user_detail'),
(r'^profile/$', 'profile'),
(r'^send_mail_retry/$', send_mail_retry), (r'^send_mail_retry/$', send_mail_retry),
(r'^reset_password/$', reset_password), (r'^reset_password/$', reset_password),
(r'^forget_password/$', forget_password), (r'^forget_password/$', forget_password),
(r'^user_detail/$', 'user_detail'),
(r'^user_del/$', 'user_del'),
(r'^user_edit/$', user_edit),
(r'^profile/$', 'profile'),
(r'^change_info/$', 'change_info'), (r'^change_info/$', 'change_info'),
(r'^regen_ssh_key/$', 'regen_ssh_key'),
(r'^change_role/$', 'chg_role'), (r'^change_role/$', 'chg_role'),
(r'^regen_ssh_key/$', 'regen_ssh_key'),
(r'^down_key/$', 'down_key'), (r'^down_key/$', 'down_key'),
) )
...@@ -86,13 +86,14 @@ def db_update_user(**kwargs): ...@@ -86,13 +86,14 @@ def db_update_user(**kwargs):
groups_post = kwargs.pop('groups') groups_post = kwargs.pop('groups')
admin_groups_post = kwargs.pop('admin_groups') admin_groups_post = kwargs.pop('admin_groups')
user_id = kwargs.pop('user_id') user_id = kwargs.pop('user_id')
user = User.objects.get(id=user_id) user = User.objects.filter(id=user_id)
user_get = User.objects.get(id=user_id)
if user: if user:
pwd = kwargs.pop('password') pwd = kwargs.pop('password')
user.update(**kwargs) user.update(**kwargs)
if pwd != '': if pwd != '':
user.set_password(pwd) user_get.set_password(pwd)
user.save() user_get.save()
else: else:
return None return None
...@@ -101,10 +102,10 @@ def db_update_user(**kwargs): ...@@ -101,10 +102,10 @@ def db_update_user(**kwargs):
for group_id in groups_post: for group_id in groups_post:
group = UserGroup.objects.filter(id=group_id) group = UserGroup.objects.filter(id=group_id)
group_select.extend(group) group_select.extend(group)
user.group = group_select user_get.group = group_select
if admin_groups_post != '': if admin_groups_post != '':
user.admingroup_set.all().delete() user_get.admingroup_set.all().delete()
for group_id in admin_groups_post: for group_id in admin_groups_post:
group = get_object(UserGroup, id=group_id) group = get_object(UserGroup, id=group_id)
AdminGroup(user=user, group=group).save() AdminGroup(user=user, group=group).save()
...@@ -121,8 +122,7 @@ def db_del_user(username): ...@@ -121,8 +122,7 @@ def db_del_user(username):
def gen_ssh_key(username, password='', def gen_ssh_key(username, password='',
key_dir=os.path.join(KEY_DIR, 'user'),
key_dir=os.path.join(BASE_DIR, 'role_keys/user/'),
authorized_keys=True, home="/home", length=2048): authorized_keys=True, home="/home", length=2048):
""" """
...@@ -130,9 +130,10 @@ def gen_ssh_key(username, password='', ...@@ -130,9 +130,10 @@ def gen_ssh_key(username, password='',
生成一个用户ssh密钥对 生成一个用户ssh密钥对
""" """
private_key_file = os.path.join(key_dir, username) private_key_file = os.path.join(key_dir, username)
mkdir(private_key_file, username)
if os.path.isfile(private_key_file): if os.path.isfile(private_key_file):
os.unlink(private_key_file) os.unlink(private_key_file)
ret = bash('ssh-keygen -t rsa -f %s -b %s -P "%s"' % (private_key_file, length, password)) ret = bash('echo -e "y\n"|ssh-keygen -t rsa -f %s -b %s -P "%s"' % (private_key_file, length, password))
if authorized_keys: if authorized_keys:
auth_key_dir = os.path.join(home, username, '.ssh') auth_key_dir = os.path.join(home, username, '.ssh')
......
...@@ -8,14 +8,11 @@ import uuid as uuid_r ...@@ -8,14 +8,11 @@ import uuid as uuid_r
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.db.models import Q from django.db.models import Q
from django.template import RequestContext
from django.db.models import ObjectDoesNotExist
from jumpserver.settings import EMAIL_HOST_USER
from juser.user_api import * from juser.user_api import *
from jperm.perm_api import _public_perm_api, perm_user_api, user_permed
MAIL_FROM = EMAIL_HOST_USER MAIL_FROM = EMAIL_HOST_USER
def chg_role(request): def chg_role(request):
role = {'SU': 2, 'GA': 1, 'CU': 0} role = {'SU': 2, 'GA': 1, 'CU': 0}
if request.session['role_id'] > 0: if request.session['role_id'] > 0:
...@@ -142,54 +139,6 @@ def group_edit(request): ...@@ -142,54 +139,6 @@ def group_edit(request):
return my_render('juser/group_edit.html', locals(), request) return my_render('juser/group_edit.html', locals(), request)
# @require_role(role='admin')
# def group_edit_adm(request):
# error = ''
# msg = ''
# header_title, path1, path2 = '修改小组信息', '用户管理', '编辑小组'
# user, dept = get_session_user_dept(request)
# if request.method == 'GET':
# group_id = request.GET.get('id', '')
# if not validate(request, user_group=[group_id]):
# return HttpResponseRedirect('/juser/group_list/')
# group = UserGroup.objects.filter(id=group_id)
# if group:
# group = group[0]
# users_all = dept.user_set.all()
# users_selected = group.user_set.all()
# users = [user for user in users_all if user not in users_selected]
#
# return render_to_response('juser/group_edit.html', locals(), context_instance=RequestContext(request))
# else:
# group_id = request.POST.get('group_id', '')
# group_name = request.POST.get('group_name', '')
# comment = request.POST.get('comment', '')
# users_selected = request.POST.getlist('users_selected')
#
# users = []
# try:
# if not validate(request, user=users_selected):
# raise ServerError(u'右侧非部门用户')
#
# if not validate(request, user_group=[group_id]):
# raise ServerError(u'没有权限修改本组')
#
# for user_id in users_selected:
# users.extend(User.objects.filter(id=user_id))
#
# user_group = UserGroup.objects.filter(id=group_id)
# if user_group:
# user_group.update(name=group_name, comment=comment, dept=dept)
# user_group = user_group[0]
# user_group.user_set.clear()
# user_group.user_set = users
#
# except ServerError, e:
# error = e
#
# return HttpResponseRedirect('/juser/group_list/')
@login_required(login_url='/login') @login_required(login_url='/login')
@require_role(role='super') @require_role(role='super')
def user_add(request): def user_add(request):
...@@ -210,7 +159,7 @@ def user_add(request): ...@@ -210,7 +159,7 @@ def user_add(request):
uuid = uuid_r.uuid1() uuid = uuid_r.uuid1()
ssh_key_pwd = PyCrypt.gen_rand_pass(16) ssh_key_pwd = PyCrypt.gen_rand_pass(16)
extra = request.POST.getlist('extra', []) extra = request.POST.getlist('extra', [])
is_active = True if '0' in extra else False is_active = False if '0' in extra else True
ssh_key_login_need = True if '1' in extra else False ssh_key_login_need = True if '1' in extra else False
send_mail_need = True if '2' in extra else False send_mail_need = True if '2' in extra else False
...@@ -437,7 +386,6 @@ def user_edit(request): ...@@ -437,7 +386,6 @@ def user_edit(request):
admin_groups=admin_groups, admin_groups=admin_groups,
role=role_post, role=role_post,
is_active=is_active) is_active=is_active)
_public_perm_api({'type': 'del_user', 'user': user, 'asset': user_permed(user)})
if email_need: if email_need:
msg = u""" msg = u"""
...@@ -475,7 +423,7 @@ def profile(request): ...@@ -475,7 +423,7 @@ def profile(request):
def change_info(request): def change_info(request):
header_title, path1, path2 = '修改信息', '用户管理', '修改个人信息' header_title, path1, path2 = '修改信息', '用户管理', '修改个人信息'
user_id = request.user.id user_id = request.user.id
user = get_object(User, id=user_id) user = User.objects.get(id=user_id)
error = '' error = ''
if not user: if not user:
return HttpResponseRedirect('/') return HttpResponseRedirect('/')
...@@ -485,18 +433,19 @@ def change_info(request): ...@@ -485,18 +433,19 @@ def change_info(request):
password = request.POST.get('password', '') password = request.POST.get('password', '')
email = request.POST.get('email', '') email = request.POST.get('email', '')
if '' in [name, password, email]: if '' in [name, email]:
error = '不能为空' error = '不能为空'
if len(password) > 0 and len(password) < 6:
if len(password) < 6:
error = '密码须大于6位' error = '密码须大于6位'
if not error: if not error:
# if password != user.password: # if password != user.password:
# password = CRYPTOR.md5_crypt(password) # password = CRYPTOR.md5_crypt(password)
user.update(name=name, email=email) User.objects.filter(id=user_id).update(name=name, email=email)
if len(password) > 0:
user.set_password(password) user.set_password(password)
user.save()
msg = '修改成功' msg = '修改成功'
return render_to_response('juser/change_info.html', locals(), context_instance=RequestContext(request)) return render_to_response('juser/change_info.html', locals(), context_instance=RequestContext(request))
...@@ -528,7 +477,7 @@ def down_key(request): ...@@ -528,7 +477,7 @@ def down_key(request):
user = get_object(User, id=user_id) user = get_object(User, id=user_id)
if user: if user:
username = user.username username = user.username
private_key_file = os.path.join(BASE_DIR, 'role_keys/jumpserver', username + ".pem") private_key_file = os.path.join(KEY_DIR, 'user', username)
if os.path.isfile(private_key_file): if os.path.isfile(private_key_file):
f = open(private_key_file) f = open(private_key_file)
data = f.read() data = f.read()
......
看山是山,看水是水
看山不是山,看水不是水
看山是山,看水是水
#!/usr/bin/python
# coding: utf-8
import os
import re
import time
import psutil
from datetime import datetime
os.environ['DJANGO_SETTINGS_MODULE'] = 'jumpserver.settings'
import django
#django.setup()
from jlog.models import Log
def log_hanler(id):
log = Log.objects.get(id=id)
pattern = re.compile(r'([\[.*@.*\][\$#].*)|(.*mysql>.*)')
if log:
filename = log.log_path
if os.path.isfile(filename):
f_his = filename + '.his'
f1 = open(filename)
f2 = open(f_his, 'a')
lines = f1.readlines()
for line in lines[7:]:
match = pattern.match(line)
if match:
newline = re.sub('\[[A-Z]', '', line)
f2.write(newline)
f1.close()
f2.close()
log.log_finished = True
log.save()
def set_finish(id):
log = Log.objects.filter(id=id)
if log:
log.update(is_finished=1, end_time=datetime.now())
def kill_pid(pid):
try:
os.kill(pid, 9)
except OSError:
pass
def get_pids():
pids1, pids2 = [], []
pids1_obj = Log.objects.filter(is_finished=0)
pids2_obj = Log.objects.filter(is_finished=1, log_finished=0)
for pid_obj in pids1_obj:
pids1.append((pid_obj.id, pid_obj.pid, pid_obj.log_path, pid_obj.is_finished, pid_obj.log_finished, pid_obj.start_time))
for pid_obj in pids2_obj:
pids2.append(pid_obj.id)
return pids1, pids2
def run():
pids1, pids2 = get_pids()
for pid_id in pids2:
log_hanler(pid_id)
for pid_id, pid, log_path, is_finished, log_finished, start_time in pids1:
try:
file_time = int(os.stat(log_path).st_ctime)
now_time = int(time.time())
if now_time - file_time > 18000:
if psutil.pid_exists(pid):
kill_pid(pid)
set_finish(pid_id)
log_hanler(pid_id)
except OSError:
pass
if __name__ == '__main__':
while True:
run()
time.sleep(5)
永远年轻,永远热泪盈眶
- hosts: the_del_group
tasks:
- name: del user
user: name={{ item }} state=absent remove=yes
with_items: [ the_del_users ]
- hosts: the_new_group
tasks:
- name: add user
user: name={{ item }} state=present
with_items: [ the_new_users ]
- name: .ssh direcotory
file: name=/home/{{ item }}/.ssh mode=700 owner={{ item }} group={{ item }} state=directory
with_items: [ the_new_users ]
- name: set authorizied_file
copy: src=KEY_DIR/{{ item }}.pub dest=/home/{{ item }}/.ssh/authorizied_keys owner={{ item }} group={{ item }} mode=600
with_items: [ the_new_users ]
...@@ -236,7 +236,7 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler): ...@@ -236,7 +236,7 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
if data.get('data'): if data.get('data'):
self.term.input_mode = True self.term.input_mode = True
if str(data['data']) in ['\r', '\n', '\r\n']: if str(data['data']) in ['\r', '\n', '\r\n']:
TtyLog(log=self.log, datetime=datetime.datetime.now(), cmd=self.term.remove_control_char(self.term.data)).save() TtyLog(log=self.log, datetime=datetime.datetime.now(), cmd=self.term.deal_command(self.term.data, self.term.ssh)).save()
self.term.data = '' self.term.data = ''
self.term.input_mode = False self.term.input_mode = False
self.term.channel.send(data['data']) self.term.channel.send(data['data'])
......
...@@ -17,10 +17,19 @@ function check_all(form) { ...@@ -17,10 +17,19 @@ function check_all(form) {
} }
function checkAll(){ function checkAll(){
// 选择该页面所有checkbox var checklist = document.getElementsByName ("checked");
$('input[type=checkbox]').each(function(){ if(document.getElementById("check_all").checked)
$(this).attr('checked', true) {
}) for(var i=0;i<checklist.length;i++)
{
checklist[i].checked = 1;
}
}else{
for(var j=0;j<checklist.length;j++)
{
checklist[j].checked = 0;
}
}
} }
//提取指定行的数据,JSON格式 //提取指定行的数据,JSON格式
......
/* ShiftCheckbox jQuery plugin
*
* Copyright (C) 2011-2012 James Nylen
*
* Released under MIT license
* For details see:
* https://github.com/nylen/shiftcheckbox
*
* Requires jQuery v1.7 or higher.
*/
(function($) {
var ns = '.shiftcheckbox';
$.fn.shiftcheckbox = function(opts) {
opts = $.extend({
checkboxSelector : null,
selectAll : null,
onChange : null,
ignoreClick : null
}, opts);
if (typeof opts.onChange != 'function') {
opts.onChange = function(checked) { };
}
$.fn.scb_changeChecked = function(opts, checked) {
this.prop('checked', checked);
opts.onChange.call(this, checked);
return this;
}
var $containers,
$checkboxes,
$containersSelectAll,
$checkboxesSelectAll,
$otherSelectAll,
$containersAll,
$checkboxesAll;
if (opts.selectAll) {
// We need to set up a "select all" control
$containersSelectAll = $(opts.selectAll);
if ($containersSelectAll && !$containersSelectAll.length) {
$containersSelectAll = false;
}
}
if ($containersSelectAll) {
$checkboxesSelectAll = $containersSelectAll
.filter(':checkbox')
.add($containersSelectAll.find(':checkbox'));
$containersSelectAll = $containersSelectAll.not(':checkbox');
$otherSelectAll = $containersSelectAll.filter(function() {
return !$(this).find($checkboxesSelectAll).length;
});
$containersSelectAll = $containersSelectAll.filter(function() {
return !!$(this).find($checkboxesSelectAll).length;
}).each(function() {
$(this).data('childCheckbox', $(this).find($checkboxesSelectAll)[0]);
});
}
if (opts.checkboxSelector) {
// checkboxSelector means that the elements we need to attach handlers to
// ($containers) are not actually checkboxes but contain them instead
$containersAll = this.filter(function() {
return !!$(this).find(opts.checkboxSelector).filter(':checkbox').length;
}).each(function() {
$(this).data('childCheckbox', $(this).find(opts.checkboxSelector).filter(':checkbox')[0]);
}).add($containersSelectAll);
$checkboxesAll = $containersAll.map(function() {
return $(this).data('childCheckbox');
});
} else {
$checkboxesAll = this.filter(':checkbox');
}
if ($checkboxesSelectAll && !$checkboxesSelectAll.length) {
$checkboxesSelectAll = false;
} else {
$checkboxesAll = $checkboxesAll.add($checkboxesSelectAll);
}
if ($otherSelectAll && !$otherSelectAll.length) {
$otherSelectAll = false;
}
if ($containersAll) {
$containers = $containersAll.not($containersSelectAll);
}
$checkboxes = $checkboxesAll.not($checkboxesSelectAll);
if (!$checkboxes.length) {
return;
}
var lastIndex = -1;
var checkboxClicked = function(e) {
var checked = !!$(this).prop('checked');
var curIndex = $checkboxes.index(this);
if (curIndex < 0) {
if ($checkboxesSelectAll.filter(this).length) {
$checkboxesAll.scb_changeChecked(opts, checked);
}
return;
}
if (e.shiftKey && lastIndex != -1) {
var di = (curIndex > lastIndex ? 1 : -1);
for (var i = lastIndex; i != curIndex; i += di) {
$checkboxes.eq(i).scb_changeChecked(opts, checked);
}
}
if ($checkboxesSelectAll) {
if (checked && !$checkboxes.not(':checked').length) {
$checkboxesSelectAll.scb_changeChecked(opts, true);
} else if (!checked) {
$checkboxesSelectAll.scb_changeChecked(opts, false);
}
}
lastIndex = curIndex;
};
if ($checkboxesSelectAll) {
$checkboxesSelectAll
.prop('checked', !$checkboxes.not(':checked').length)
.filter(function() {
return !$containersAll.find(this).length;
}).on('click' + ns, checkboxClicked);
}
if ($otherSelectAll) {
$otherSelectAll.on('click' + ns, function() {
var checked;
if ($checkboxesSelectAll) {
checked = !!$checkboxesSelectAll.eq(0).prop('checked');
} else {
checked = !!$checkboxes.eq(0).prop('checked');
}
$checkboxesAll.scb_changeChecked(opts, !checked);
});
}
if (opts.checkboxSelector) {
$containersAll.on('click' + ns, function(e) {
if ($(e.target).closest(opts.ignoreClick).length) {
return;
}
var $checkbox = $($(this).data('childCheckbox'));
$checkbox.not(e.target).each(function() {
var checked = !$checkbox.prop('checked');
$(this).scb_changeChecked(opts, checked);
});
$checkbox[0].focus();
checkboxClicked.call($checkbox, e);
// If the user clicked on a label inside the row that points to the
// current row's checkbox, cancel the event.
var $label = $(e.target).closest('label');
var labelFor = $label.attr('for');
if (labelFor && labelFor == $checkbox.attr('id')) {
if ($label.find($checkbox).length) {
// Special case: The label contains the checkbox.
if ($checkbox[0] != e.target) {
return false;
}
} else {
return false;
}
}
}).on('mousedown' + ns, function(e) {
if (e.shiftKey) {
// Prevent selecting text by Shift+click
return false;
}
});
} else {
$checkboxes.on('click' + ns, checkboxClicked);
}
return this;
};
})(jQuery);
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
</div> </div>
<div class="ibox-content"> <div class="ibox-content">
<h1 class="no-margins"><a href="/juser/user_list/">{{ users.count}}</a></h1> <h1 class="no-margins"><a href="/juser/user_list/">{{ users.count}}</a></h1>
{# <div class="stat-percent font-bold text-success">{{ percent_user }} <i class="fa fa-bolt"></i></div>#}
<small>All user</small> <small>All user</small>
</div> </div>
</div> </div>
...@@ -27,7 +26,6 @@ ...@@ -27,7 +26,6 @@
</div> </div>
<div class="ibox-content"> <div class="ibox-content">
<h1 class="no-margins"><a href="/jasset/host_list/">{{ hosts.count }}</a></h1> <h1 class="no-margins"><a href="/jasset/host_list/">{{ hosts.count }}</a></h1>
{# <div class="stat-percent font-bold text-info">{{ percent_host }} <i class="fa fa-level-up"></i></div>#}
<small>All host</small> <small>All host</small>
</div> </div>
</div> </div>
...@@ -37,7 +35,7 @@ ...@@ -37,7 +35,7 @@
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-primary pull-right">Online</span> <span class="label label-primary pull-right">Online</span>
<h5>实时在线用户</h5> <h5>在线用户</h5>
</div> </div>
<div class="ibox-content"> <div class="ibox-content">
<h1 class="no-margins"><a href="/jlog/log_list/online/"> <span id="online_users">{{ online_user | length }}</span></a></h1> <h1 class="no-margins"><a href="/jlog/log_list/online/"> <span id="online_users">{{ online_user | length }}</span></a></h1>
...@@ -55,7 +53,6 @@ ...@@ -55,7 +53,6 @@
</div> </div>
<div class="ibox-content"> <div class="ibox-content">
<h1 class="no-margins"><a href="/jlog/log_list/online/"> <span id="online_hosts">{{ online_host | length }}</span></a></h1> <h1 class="no-margins"><a href="/jlog/log_list/online/"> <span id="online_hosts">{{ online_host | length }}</span></a></h1>
{# <div class="stat-percent font-bold text-danger">{{ percent_online_host }} <i class="fa fa-level-down"></i></div>#}
<small>Connected host</small> <small>Connected host</small>
</div> </div>
</div> </div>
...@@ -169,7 +166,7 @@ ...@@ -169,7 +166,7 @@
</div> </div>
</div> </div>
<div class="ibox-content ibox-heading"> <div class="ibox-content ibox-heading">
<h3><i class="fa fa-user"></i> 一周Top10资产 </h3> <h3><i class="fa fa-inbox"></i> 一周Top10资产 </h3>
<small><i class="fa fa-map-marker"></i> 登录次数及最近一次登录记录. </small> <small><i class="fa fa-map-marker"></i> 登录次数及最近一次登录记录. </small>
</div> </div>
<div class="ibox-content inspinia-timeline"> <div class="ibox-content inspinia-timeline">
...@@ -309,14 +306,7 @@ ...@@ -309,14 +306,7 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<!--</div>-->
<!--<div class="col-xm-6" id="top10" style="width:50%;height:400px;"></div>-->
<!--<div class="col-xm-6" id="usertop10" style="width:50%;height:400px;"></div>-->
<!--<div class="row">-->
<!--<div class="col-lg-6" id="hosttop10" style="width:50%;height:400px; margin-top: 20px"></div>-->
<!--</div>-->
</div>
</div> </div>
{% endblock %} {% endblock %}
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
</div> </div>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<div class="form-group"> <div class="form-group">
<label for="password" class="col-sm-2 control-label">密码<span class="red-fonts">*</span></label> <label for="password" class="col-sm-2 control-label">密码</label>
<div class="col-sm-8"> <div class="col-sm-8">
<input id="password" name="password" placeholder="Password" type="password" class="form-control"> <input id="password" name="password" placeholder="Password" type="password" class="form-control">
<span class="help-block m-b-none"> <span class="help-block m-b-none">
...@@ -91,7 +91,7 @@ $('#userForm').validator({ ...@@ -91,7 +91,7 @@ $('#userForm').validator({
fields: { fields: {
"password": { "password": {
rule: "required;length[6~50]", rule: "length[6~50]",
tip: "输入密码", tip: "输入密码",
ok: "", ok: "",
msg: {required: "必须填写!"} msg: {required: "必须填写!"}
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
<thead> <thead>
<tr> <tr>
<th class="text-center"> <th class="text-center">
<input type="checkbox" id="select_all" onclick="selectAll()" name="select_all"> <input type="checkbox" id="select_all" name="select_all">
</th> </th>
<th class="text-center">组名</th> <th class="text-center">组名</th>
<th class="text-center">成员数目</th> <th class="text-center">成员数目</th>
...@@ -55,7 +55,8 @@ ...@@ -55,7 +55,8 @@
{% for group in user_groups.object_list %} {% for group in user_groups.object_list %}
<tr class="gradeX"> <tr class="gradeX">
<td class="text-center"> <td class="text-center">
<input type="checkbox" name="selected" value="{{ group.id }}"> <input class="shiftCheckbox"
type="checkbox" name="selected" value="{{ group.id }}">
</td> </td>
<td class="text-center"> {{ group.name }} </td> <td class="text-center"> {{ group.name }} </td>
<td class="text-center"><a href="/juser/user_list/?gid={{ group.id }}"> {{ group.id | members_count }}</a> </td> <td class="text-center"><a href="/juser/user_list/?gid={{ group.id }}"> {{ group.id | members_count }}</a> </td>
...@@ -83,6 +84,10 @@ ...@@ -83,6 +84,10 @@
</div> </div>
{% endblock %} {% endblock %}
{% block self_head_css_js %}
{% load staticfiles %}
<script src="{% static 'js/jquery.shiftcheckbox.js' %}"></script>
{% endblock %}
{% block self_footer_js %} {% block self_footer_js %}
<script> <script>
$(document).ready(function(){ $(document).ready(function(){
...@@ -115,7 +120,13 @@ ...@@ -115,7 +120,13 @@
) )
} }
}) });
$("tbody tr").shiftcheckbox({
checkboxSelector: 'input:checkbox',
selectAll: $('#select_all'),
ignoreClick: 'a'
});
$('.shiftCheckbox').shiftcheckbox();
}); });
</script> </script>
{% endblock %} {% endblock %}
...@@ -93,10 +93,10 @@ ...@@ -93,10 +93,10 @@
</div> </div>
</div> </div>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label">额外</label> <div class="form-group"><label class="col-sm-2 control-label">其它</label>
<div class="col-sm-2"> <div class="col-sm-2">
<div class="checkbox i-checks"> <div class="checkbox i-checks">
<label><input type="checkbox" value="0" name="extra" ></label> <label><input type="checkbox" value="0" name="extra" ></label>
</div> </div>
</div> </div>
<div class="col-sm-2"> <div class="col-sm-2">
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
<thead> <thead>
<tr> <tr>
<th class="text-center"> <th class="text-center">
<input type="checkbox" id="select_all" onclick="selectAll()" name="select_all"> <input type="checkbox" id="check_all" onclick="checkAll()">
</th> </th>
<th class="text-center">用户名</th> <th class="text-center">用户名</th>
<th class="text-center">姓名</th> <th class="text-center">姓名</th>
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
{% for user in users.object_list %} {% for user in users.object_list %}
<tr class="gradeX"> <tr class="gradeX">
<td class="text-center"> <td class="text-center">
<input type="checkbox" name="selected" value="{{ user.id }}"> <input type="checkbox" name="checked" value="{{ user.id }}">
</td> </td>
<td class="text-center"> {{ user.username }} </td> <td class="text-center"> {{ user.username }} </td>
<td class="text-center"> {{ user.name }} </td> <td class="text-center"> {{ user.name }} </td>
...@@ -91,10 +91,15 @@ ...@@ -91,10 +91,15 @@
{% endblock %} {% endblock %}
{% block self_head_css_js %} {% block self_head_css_js %}
{% load staticfiles %}
<script src="{% static 'js/jquery.shiftcheckbox.js' %}"></script>
{% endblock %}
{% block self_footer_js %}
<script> <script>
$(document).ready(function(){ $(document).ready(function(){
$('.del').click(function(){ $('.del').click(function(){
var row = $(this).closest('tr'); var row = $(this).closest('tr');
if (confirm("确定删除")) {
$.get( $.get(
$(this).attr('value'), $(this).attr('value'),
{}, {},
...@@ -102,7 +107,7 @@ ...@@ -102,7 +107,7 @@
row.remove(); row.remove();
alert(data); alert(data);
} }
) )}
}); });
$('#del_btn').click(function(){ $('#del_btn').click(function(){
...@@ -129,7 +134,13 @@ ...@@ -129,7 +134,13 @@
alert(data) alert(data)
} }
) )
}) });
$("tbody tr").shiftcheckbox({
checkboxSelector: 'input:checkbox',
selectAll: $('#select_all'),
ignoreClick: 'a'
});
$('.shiftCheckbox').shiftcheckbox();
}); });
</script> </script>
{% endblock %} {% endblock %}
\ No newline at end of file
...@@ -4,10 +4,10 @@ ...@@ -4,10 +4,10 @@
<ul class="nav" id="side-menu"> <ul class="nav" id="side-menu">
{% include 'nav_li_profile.html' %} {% include 'nav_li_profile.html' %}
<li id="index"> <li id="index">
<a href="/"><i class="fa fa-th-large"></i> <span class="nav-label">仪表盘</span><span class="label label-info pull-right"></span></a> <a href="/"><i class="fa fa-dashboard"></i> <span class="nav-label">仪表盘</span><span class="label label-info pull-right"></span></a>
</li> </li>
<li id="juser"> <li id="juser">
<a href="#"><i class="fa fa-rebel"></i> <span class="nav-label">用户管理</span><span class="fa arrow"></span></a> <a href="#"><i class="fa fa-group"></i> <span class="nav-label">用户管理</span><span class="fa arrow"></span></a>
<ul class="nav nav-second-level"> <ul class="nav nav-second-level">
<li class="group_list group_edit"><a href="/juser/group_list/">查看用户组</a></li> <li class="group_list group_edit"><a href="/juser/group_list/">查看用户组</a></li>
<li class="group_add"><a href="/juser/group_add/">添加用户组</a></li> <li class="group_add"><a href="/juser/group_add/">添加用户组</a></li>
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
</ul> </ul>
</li> </li>
<li id="jasset"> <li id="jasset">
<a><i class="fa fa-cube"></i> <span class="nav-label">资产管理</span><span class="fa arrow"></span></a> <a><i class="fa fa-inbox"></i> <span class="nav-label">资产管理</span><span class="fa arrow"></span></a>
<ul class="nav nav-second-level"> <ul class="nav nav-second-level">
<li class="group_add"><a href="/jasset/group_add/">添加资产组</a></li> <li class="group_add"><a href="/jasset/group_add/">添加资产组</a></li>
<li class="group_list group_detail group_edit"><a href="/jasset/group_list/">查看资产组</a></li> <li class="group_list group_detail group_edit"><a href="/jasset/group_list/">查看资产组</a></li>
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
<a href="/jlog/log_list/online/"><i class="fa fa-files-o"></i> <span class="nav-label">日志审计</span><span class="label label-info pull-right"></span></a> <a href="/jlog/log_list/online/"><i class="fa fa-files-o"></i> <span class="nav-label">日志审计</span><span class="label label-info pull-right"></span></a>
</li> </li>
<li id="setting"> <li id="setting">
<a href="/setting/"><i class="fa fa-files-o"></i> <span class="nav-label">设置</span><span class="label label-info pull-right"></span></a> <a href="/setting/"><i class="fa fa-gears"></i> <span class="nav-label">设置</span><span class="label label-info pull-right"></span></a>
</li> </li>
<li class="special_link"> <li class="special_link">
<a href="http://www.jumpserver.org" target="_blank"><i class="fa fa-database"></i> <span class="nav-label">访问官网</span></a> <a href="http://www.jumpserver.org" target="_blank"><i class="fa fa-database"></i> <span class="nav-label">访问官网</span></a>
......
...@@ -47,13 +47,19 @@ ...@@ -47,13 +47,19 @@
var old_href = $(this).attr('href').replace('?', ''); var old_href = $(this).attr('href').replace('?', '');
var searchArray = searchStr.split('&'); var searchArray = searchStr.split('&');
if (searchStr == ''){
searchStr = '?page=1'
}
if (searchStr.indexOf('page')>=0){ if (searchStr.indexOf('page')>=0){
searchArray.pop(); searchArray.pop();
} }
searchArray.push(old_href); searchArray.push(old_href);
if (searchArray.length > 1){ if (searchArray.length > 1) {
$(this).attr('href', searchArray.join('&')); $(this).attr('href', searchArray.join('&'));
} }
{# sleep(1000)#}
}) })
}); });
......
1.1
\ No newline at end of file
#!/usr/bin/env node
var program = require('commander');
nodetail = require('../src/node-tail.js');
var options = {};
program
.usage('[options] file...')
.option('-p, --port <port>', 'custom port');
program.parse(process.argv);
nodetail.run({
port: program.port,
file: program.args[0]
});
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var spawn = require('child_process').spawn;
var request = require("request");
var fs = require("fs");
var Tail = require('tail').Tail;
app.get('/', function(req, res){
res.send('<h1>Welcome Realtime Server</h1>');
});
//在线用户
var onlineUsers = {};
//当前在线人数
var onlineCount = 0;
io.on('connection', function(socket){
//console.log('a user connected');
//监听新用户加入
socket.on('login', function(obj){
request({
uri:"http://127.0.0.1/node_auth/",
method:"POST",
form:{
username:obj.username,
seed:obj.seed,
filename:obj.filename
}
},function(error,response,body){
try{
var result = JSON.parse(body)
console.log(body);
if(result['auth']['result'] != 'failed'){
fs.exists(obj.filename, function(result) {
//将新加入用户的唯一标识当作socket的名称,后面退出的时候会用到
socket.name = obj.userid;
socket.fileName = obj.filename;
var tail = new Tail(obj.filename);
//2015-03-06 当用户打开监控窗口时,会把已存在的文件内容打印出来
fs.readFile(obj.filename, 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
var existData = {userid:obj.userid,username:obj.username,content:data,option:'exist'};
socket.emit('message',existData);
});
tail.on('line',function(data) {
//console.log(data);
var newData = {userid:obj.userid,username:obj.username,content:data,option:'new'};
socket.emit('message',newData);
});
socket.tail = tail;
//检查在线列表,如果不在里面就加入
if(!onlineUsers.hasOwnProperty(obj.userid)) {
onlineUsers[obj.userid] = obj.username;
//在线人数+1
onlineCount++;
}
});
}
}catch(err){
console.log(err)
}
});
//var tail = spawn("tail", ['-f', obj.filename]);
//tail.stdout.on('data',function(data){
// var content = data.toString();
// //console.log(content);
// var newData = {userid:obj.userid,username:obj.username,content:content};
// socket.emit('message',newData);
//});
//向所有客户端广播用户加入
//io.emit('login', {onlineUsers:onlineUsers, onlineCount:onlineCount, user:obj});
//console.log(obj.username+'加入了聊天室');
});
//监听用户退出
socket.on('disconnect', function(){
//将退出的用户从在线列表中删除
if(onlineUsers.hasOwnProperty(socket.name)) {
//退出用户的信息
var obj = {userid:socket.name, username:onlineUsers[socket.name]};
if( socket.tail){
socket.tail.unwatch();
}
//删除
delete onlineUsers[socket.name];
//在线人数-1
onlineCount--;
//向所有客户端广播用户退出
//io.emit('logout', {onlineUsers:onlineUsers, onlineCount:onlineCount, user:obj});
////console.log(obj.username+'退出了聊天室');
}
});
//监听用户发布聊天内容
socket.on('message', function(obj){
//向所有客户端广播发布的消息
//io.emit('message', obj);
socket.emit('message',obj);
////console.log(obj.username+'说:'+obj.content);
});
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
This diff is collapsed.
{
"name": "web-socket",
"version": "0.0.1",
"description": "my first realtime server",
"dependencies": {
"express": "~4.10.1",
"socket.io": "~1.2.0",
"node-tail": "0.0.4",
"tail": "~0.4.0",
"request": "~2.55.0"
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment