diff --git a/.gitignore b/.gitignore index 4eaa616d2..983fedd49 100644 --- a/.gitignore +++ b/.gitignore @@ -37,11 +37,9 @@ nosetests.xml .mr.developer.cfg .project .pydevproject -*.xlsx -node_modules -logs -keys +*.log +logs/* +keys/* jumpserver.conf nohup.out tmp/* -db.sqlite3 diff --git a/connect.py b/connect.py index 930452a36..60f0daebb 100644 --- a/connect.py +++ b/connect.py @@ -25,7 +25,7 @@ from jumpserver.settings import LOG_DIR login_user = get_object(User, username=getpass.getuser()) - +VIM_FLAG = False try: import termios @@ -68,127 +68,7 @@ def check_vim_status(command, ssh): return False -def deal_command(str_r, ssh): - - """ - 处理命令中特殊字符 - """ - t = time.time() - str_r = re.sub('\x07','',str_r) #删除响铃 - patch_char = re.compile('\x08\x1b\[C') #删除方向左右一起的按键 - while patch_char.search(str_r): - str_r = patch_char.sub('', str_r.rstrip()) - - result_command = '' #最后的结果 - backspace_num = 0 #光标移动的个数 - backspace_list = [] - reach_backspace_flag = False #没有检测到光标键则为true - reach_backspace_second_flag = False - pattern_list = [] - pattern_str='' - while str_r: - tmp = re.match(r'\s*\w+\s*', str_r) #获取字符串,其它特殊字符匹配暂时还不知道。。 - if tmp: - if reach_backspace_flag : - if not reach_backspace_second_flag: - pattern_str +=str(tmp.group(0)) - else: - pattern_list.append(pattern_str) - pattern_str=str(tmp.group(0)) - reach_backspace_second_flag=False - str_r = str_r[len(str(tmp.group(0))):] - continue - else: - result_command += str(tmp.group(0)) - str_r = str_r[len(str(tmp.group(0))):] - continue - - tmp = re.match(r'\x1b\[K[\x08]*', str_r) #遇到删除确认符,确定删除数据 - if tmp: - for x in backspace_list: - backspace_num += int(x) - if backspace_num > 0: - if backspace_num > len(result_command) : - result_command += ''.join(pattern_list) - result_command += pattern_str - result_command = result_command[0:-backspace_num] - else: - result_command = result_command[0:-backspace_num] - result_command += ''.join(pattern_list) - result_command += pattern_str - del_len = len(str(tmp.group(0)))-3 - if del_len > 0: - result_command = result_command[0:-del_len] - reach_backspace_flag = False - reach_backspace_second_flag =False - backspace_num =0 - del pattern_list[:] - del backspace_list[:] - pattern_str='' - str_r = str_r[len(str(tmp.group(0))):] - continue - - tmp = re.match(r'\x08+', str_r) #将遇到的退格数字存放到队列中 - if tmp: - if reach_backspace_flag: - reach_backspace_second_flag = True - else: - reach_backspace_flag = True - str_r = str_r[len(str(tmp.group(0))):] - if len(str_r) != 0: #如果退格键在最后,则放弃 - backspace_list.append(len(str(tmp.group(0)))) - continue - - if reach_backspace_flag : - if not reach_backspace_second_flag: - pattern_str +=str_r[0] - else: - pattern_list.append(pattern_str) - pattern_str=str_r[0] - reach_backspace_second_flag=False - else : - result_command += str_r[0] - str_r = str_r[1:] - if pattern_str !='': - pattern_list.append(pattern_str) - - #退格队列中还有腿哥键,则进行删除操作 - if len(backspace_list) > 0 : - for backspace in backspace_list: - if int(backspace) >= len(result_command): - result_command = pattern_list[0] - else: - result_command = result_command[:-int(backspace)] - result_command += pattern_list[0] - pattern_list = pattern_list[1:] - - control_char = re.compile(r""" - \x1b[ #%()*+\-.\/]. | - \r | #匹配 回车符(CR) - (?:\x1b\[|\x9b) [ -?]* [@-~] | #匹配 控制顺序描述符(CSI)... Cmd - (?:\x1b\]|\x9d) .*? (?:\x1b\\|[\a\x9c]) | \x07 | #匹配 操作系统指令(OSC)...终止符或振铃符(ST|BEL) - (?:\x1b[P^_]|[\x90\x9e\x9f]) .*? (?:\x1b\\|\x9c) | #匹配 设备控制串或私讯或应用程序命令(DCS|PM|APC)...终止符(ST) - \x1b. #匹配 转义过后的字符 - [\x80-\x9f] | (?:\x1b\]0.*) | \[.*@.*\][\$#] | (.*mysql>.*) #匹配 所有控制字符 - """, re.X) - result_command = control_char.sub('', result_command.strip()) - global VIM_FLAG - global VIM_COMMAND - if not VIM_FLAG: - if result_command.startswith('vi'): - VIM_FLAG = True - VIM_COMMAND = result_command - return result_command.decode('utf8',"ignore") - else: - if check_vim_status(VIM_COMMAND, ssh): - VIM_FLAG = False - VIM_COMMAND='' - if result_command.endswith(':wq') or result_command.endswith(':wq!') or result_command.endswith(':q!'): - return '' - return result_command.decode('utf8',"ignore") - else: - return '' class Tty(object): @@ -217,6 +97,127 @@ class Tty(object): return True return False + @staticmethod + def deal_command(str_r, ssh): + """ + 处理命令中特殊字符 + """ + str_r = re.sub('\x07','',str_r) #删除响铃 + patch_char = re.compile('\x08\x1b\[C') #删除方向左右一起的按键 + while patch_char.search(str_r): + str_r = patch_char.sub('', str_r.rstrip()) + + result_command = '' #最后的结果 + backspace_num = 0 #光标移动的个数 + backspace_list = [] + reach_backspace_flag = False #没有检测到光标键则为true + reach_backspace_second_flag = False + pattern_list = [] + pattern_str='' + while str_r: + tmp = re.match(r'\s*\w+\s*', str_r) #获取字符串,其它特殊字符匹配暂时还不知道。。 + if tmp: + if reach_backspace_flag : + if not reach_backspace_second_flag: + pattern_str +=str(tmp.group(0)) + else: + pattern_list.append(pattern_str) + pattern_str=str(tmp.group(0)) + reach_backspace_second_flag=False + str_r = str_r[len(str(tmp.group(0))):] + continue + else: + result_command += str(tmp.group(0)) + str_r = str_r[len(str(tmp.group(0))):] + continue + + tmp = re.match(r'\x1b\[K[\x08]*', str_r) #遇到删除确认符,确定删除数据 + if tmp: + for x in backspace_list: + backspace_num += int(x) + if backspace_num > 0: + if backspace_num > len(result_command) : + result_command += ''.join(pattern_list) + result_command += pattern_str + result_command = result_command[0:-backspace_num] + else: + result_command = result_command[0:-backspace_num] + result_command += ''.join(pattern_list) + result_command += pattern_str + del_len = len(str(tmp.group(0)))-3 + if del_len > 0: + result_command = result_command[0:-del_len] + reach_backspace_flag = False + reach_backspace_second_flag =False + backspace_num =0 + del pattern_list[:] + del backspace_list[:] + pattern_str='' + str_r = str_r[len(str(tmp.group(0))):] + continue + + tmp = re.match(r'\x08+', str_r) #将遇到的退格数字存放到队列中 + if tmp: + if reach_backspace_flag: + reach_backspace_second_flag = True + else: + reach_backspace_flag = True + str_r = str_r[len(str(tmp.group(0))):] + if len(str_r) != 0: #如果退格键在最后,则放弃 + backspace_list.append(len(str(tmp.group(0)))) + continue + + if reach_backspace_flag : + if not reach_backspace_second_flag: + pattern_str +=str_r[0] + else: + pattern_list.append(pattern_str) + pattern_str=str_r[0] + reach_backspace_second_flag=False + else : + result_command += str_r[0] + str_r = str_r[1:] + + if pattern_str !='': + pattern_list.append(pattern_str) + + #退格队列中还有腿哥键,则进行删除操作 + if len(backspace_list) > 0 : + for backspace in backspace_list: + if int(backspace) >= len(result_command): + result_command = pattern_list[0] + else: + result_command = result_command[:-int(backspace)] + result_command += pattern_list[0] + pattern_list = pattern_list[1:] + + control_char = re.compile(r""" + \x1b[ #%()*+\-.\/]. | + \r | #匹配 回车符(CR) + (?:\x1b\[|\x9b) [ -?]* [@-~] | #匹配 控制顺序描述符(CSI)... Cmd + (?:\x1b\]|\x9d) .*? (?:\x1b\\|[\a\x9c]) | \x07 | #匹配 操作系统指令(OSC)...终止符或振铃符(ST|BEL) + (?:\x1b[P^_]|[\x90\x9e\x9f]) .*? (?:\x1b\\|\x9c) | #匹配 设备控制串或私讯或应用程序命令(DCS|PM|APC)...终止符(ST) + \x1b. #匹配 转义过后的字符 + [\x80-\x9f] | (?:\x1b\]0.*) | \[.*@.*\][\$#] | (.*mysql>.*) #匹配 所有控制字符 + """, re.X) + result_command = control_char.sub('', result_command.strip()) + global VIM_FLAG + global VIM_COMMAND + if not VIM_FLAG: + if result_command.startswith('vi'): + VIM_FLAG = True + VIM_COMMAND = result_command + return result_command.decode('utf8',"ignore") + else: + if check_vim_status(VIM_COMMAND, ssh): + VIM_FLAG = False + VIM_COMMAND='' + if result_command.endswith(':wq') or result_command.endswith(':wq!') or result_command.endswith(':q!'): + return '' + return result_command.decode('utf8',"ignore") + else: + return '' + @staticmethod def remove_control_char(str_r): """ @@ -402,7 +403,7 @@ class SshTty(Tty): input_mode = True 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() data = '' diff --git a/docs/requirements.txt b/docs/requirements.txt index ea56ab0c6..28d7b9137 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,6 +1,5 @@ sphinx-me==0.3 django==1.6 -python-ldap==2.4.19 pycrypto==2.6.1 paramiko==1.15.2 ecdsa==0.13 @@ -9,4 +8,9 @@ django-uuidfield==0.5.0 psutil==2.2.1 xlsxwriter==0.7.7 xlrd==0.9.4 -django-bootstrap-form \ No newline at end of file +django-bootstrap-form +tornado +ansible +pyinotify +passlib +argparse \ No newline at end of file diff --git a/jumpserver.conf b/jumpserver.conf index c7b3332ed..6297ab00a 100644 --- a/jumpserver.conf +++ b/jumpserver.conf @@ -9,11 +9,11 @@ log = debug host = 127.0.0.1 port = 3306 user = jumpserver -password = mysql1234 +password = mysql234 database = jumpserver [websocket] -web_socket_host = 127.0.0.1:3000 +web_socket_host = j:3000 [mail] mail_enable = 1 diff --git a/jumpserver/api.py b/jumpserver/api.py index 5b964586c..97fc659bb 100644 --- a/jumpserver/api.py +++ b/jumpserver/api.py @@ -197,9 +197,9 @@ def require_role(role='user'): def _deco(func): def __deco(request, *args, **kwargs): + request.session['pre_url'] = request.path if not request.user.is_authenticated(): return HttpResponseRedirect('/login/') - if role == 'admin': # if request.session.get('role_id', 0) < 1: if request.user.role == 'CU': diff --git a/jumpserver/templatetags/__init__.pyc b/jumpserver/templatetags/__init__.pyc deleted file mode 100644 index ecc9dea24..000000000 Binary files a/jumpserver/templatetags/__init__.pyc and /dev/null differ diff --git a/jumpserver/views.py b/jumpserver/views.py index 89bc75fd8..a907ced4f 100644 --- a/jumpserver/views.py +++ b/jumpserver/views.py @@ -235,7 +235,7 @@ def Login(request): request.session['role_id'] = 1 else: 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('seed', PyCrypt.md5_crypt(password), expires=604800) # return response diff --git a/juser/urls.py b/juser/urls.py index 833ed99c7..9764c01ce 100644 --- a/juser/urls.py +++ b/juser/urls.py @@ -11,17 +11,21 @@ urlpatterns = patterns('juser.views', (r'^group_list/$', group_list), (r'^group_del/$', group_del), (r'^group_edit/$', group_edit), + (r'^user_add/$', user_add), + (r'^user_del/$', 'user_del'), (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'^reset_password/$', reset_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'^regen_ssh_key/$', 'regen_ssh_key'), (r'^change_role/$', 'chg_role'), + (r'^regen_ssh_key/$', 'regen_ssh_key'), (r'^down_key/$', 'down_key'), ) diff --git a/juser/user_api.py b/juser/user_api.py index 0a54d7b65..911c554ee 100644 --- a/juser/user_api.py +++ b/juser/user_api.py @@ -86,13 +86,14 @@ def db_update_user(**kwargs): groups_post = kwargs.pop('groups') admin_groups_post = kwargs.pop('admin_groups') 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: pwd = kwargs.pop('password') user.update(**kwargs) if pwd != '': - user.set_password(pwd) - user.save() + user_get.set_password(pwd) + user_get.save() else: return None @@ -101,10 +102,10 @@ def db_update_user(**kwargs): for group_id in groups_post: group = UserGroup.objects.filter(id=group_id) group_select.extend(group) - user.group = group_select + user_get.group = group_select if admin_groups_post != '': - user.admingroup_set.all().delete() + user_get.admingroup_set.all().delete() for group_id in admin_groups_post: group = get_object(UserGroup, id=group_id) AdminGroup(user=user, group=group).save() @@ -121,8 +122,7 @@ def db_del_user(username): def gen_ssh_key(username, password='', - - key_dir=os.path.join(BASE_DIR, 'role_keys/user/'), + key_dir=os.path.join(KEY_DIR, 'user'), authorized_keys=True, home="/home", length=2048): """ @@ -130,9 +130,10 @@ def gen_ssh_key(username, password='', 生成一个用户ssh密钥对 """ private_key_file = os.path.join(key_dir, username) + mkdir(private_key_file, username) if os.path.isfile(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: auth_key_dir = os.path.join(home, username, '.ssh') diff --git a/juser/views.py b/juser/views.py index e5668bc93..f0f04c79e 100644 --- a/juser/views.py +++ b/juser/views.py @@ -8,14 +8,11 @@ import uuid as uuid_r from django.contrib.auth.decorators import login_required 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 jperm.perm_api import _public_perm_api, perm_user_api, user_permed MAIL_FROM = EMAIL_HOST_USER + def chg_role(request): role = {'SU': 2, 'GA': 1, 'CU': 0} if request.session['role_id'] > 0: @@ -142,54 +139,6 @@ def group_edit(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') @require_role(role='super') def user_add(request): @@ -210,7 +159,7 @@ def user_add(request): uuid = uuid_r.uuid1() ssh_key_pwd = PyCrypt.gen_rand_pass(16) 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 send_mail_need = True if '2' in extra else False @@ -437,7 +386,6 @@ def user_edit(request): admin_groups=admin_groups, role=role_post, is_active=is_active) - _public_perm_api({'type': 'del_user', 'user': user, 'asset': user_permed(user)}) if email_need: msg = u""" @@ -475,7 +423,7 @@ def profile(request): def change_info(request): header_title, path1, path2 = '修改信息', '用户管理', '修改个人信息' user_id = request.user.id - user = get_object(User, id=user_id) + user = User.objects.get(id=user_id) error = '' if not user: return HttpResponseRedirect('/') @@ -485,18 +433,19 @@ def change_info(request): password = request.POST.get('password', '') email = request.POST.get('email', '') - if '' in [name, password, email]: + if '' in [name, email]: error = '不能为空' - - if len(password) < 6: + if len(password) > 0 and len(password) < 6: error = '密码须大于6位' if not error: # if password != user.password: # password = CRYPTOR.md5_crypt(password) - user.update(name=name, email=email) - user.set_password(password) + User.objects.filter(id=user_id).update(name=name, email=email) + if len(password) > 0: + user.set_password(password) + user.save() msg = '修改成功' return render_to_response('juser/change_info.html', locals(), context_instance=RequestContext(request)) @@ -528,7 +477,7 @@ def down_key(request): user = get_object(User, id=user_id) if user: 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): f = open(private_key_file) data = f.read() diff --git a/keys/README.md b/keys/README.md new file mode 100644 index 000000000..9e060e41d --- /dev/null +++ b/keys/README.md @@ -0,0 +1,3 @@ +看山是山,看水是水 +看山不是山,看水不是水 +看山是山,看水是水 diff --git a/log_handler.py b/log_handler.py deleted file mode 100644 index 199afe1cb..000000000 --- a/log_handler.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/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) diff --git a/logs/README.md b/logs/README.md new file mode 100644 index 000000000..309d1a147 --- /dev/null +++ b/logs/README.md @@ -0,0 +1 @@ +永远年轻,永远热泪盈眶 diff --git a/logs/jumpserver.log b/logs/jumpserver.log deleted file mode 100644 index e69de29bb..000000000 diff --git a/playbook/user_perm.yaml b/playbook/user_perm.yaml deleted file mode 100644 index 4bcfd72e6..000000000 --- a/playbook/user_perm.yaml +++ /dev/null @@ -1,17 +0,0 @@ -- 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 ] diff --git a/run_websocket.py b/run_websocket.py index ff0cbdace..9d565fe42 100644 --- a/run_websocket.py +++ b/run_websocket.py @@ -236,7 +236,7 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler): if data.get('data'): self.term.input_mode = True 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.input_mode = False self.term.channel.send(data['data']) diff --git a/static/files/excels/asset.xlsx b/static/files/excels/asset.xlsx new file mode 100644 index 000000000..1b92db891 Binary files /dev/null and b/static/files/excels/asset.xlsx differ diff --git a/static/js/base.js b/static/js/base.js index b6ac16196..15b54dd49 100644 --- a/static/js/base.js +++ b/static/js/base.js @@ -17,10 +17,19 @@ function check_all(form) { } function checkAll(){ - // 选择该页面所有checkbox - $('input[type=checkbox]').each(function(){ - $(this).attr('checked', true) - }) + var checklist = document.getElementsByName ("checked"); + if(document.getElementById("check_all").checked) + { + for(var i=0;i 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); diff --git a/templates/index.html b/templates/index.html index af6966ef6..0d8baf9f9 100644 --- a/templates/index.html +++ b/templates/index.html @@ -14,7 +14,6 @@

{{ users.count}}

-{#
{{ percent_user }}
#} All user
@@ -27,7 +26,6 @@

{{ hosts.count }}

-{#
{{ percent_host }}
#} All host
@@ -37,7 +35,7 @@
Online -
实时在线用户
+
在线用户

{{ online_user | length }}

@@ -55,7 +53,6 @@

{{ online_host | length }}

-{#
{{ percent_online_host }}
#} Connected host
@@ -169,7 +166,7 @@
-

一周Top10资产

+

一周Top10资产

登录次数及最近一次登录记录.
@@ -309,14 +306,7 @@
- - - - - - - - + {% endblock %} diff --git a/templates/juser/change_info.html b/templates/juser/change_info.html index bd5031c26..40ec3cd55 100644 --- a/templates/juser/change_info.html +++ b/templates/juser/change_info.html @@ -41,7 +41,7 @@
- +
@@ -91,7 +91,7 @@ $('#userForm').validator({ fields: { "password": { - rule: "required;length[6~50]", + rule: "length[6~50]", tip: "输入密码", ok: "", msg: {required: "必须填写!"} diff --git a/templates/juser/group_list.html b/templates/juser/group_list.html index 092c75776..d3fdf7027 100644 --- a/templates/juser/group_list.html +++ b/templates/juser/group_list.html @@ -43,7 +43,7 @@ - + 组名 成员数目 @@ -55,7 +55,8 @@ {% for group in user_groups.object_list %} - + {{ group.name }} {{ group.id | members_count }} @@ -83,6 +84,10 @@
{% endblock %} +{% block self_head_css_js %} + {% load staticfiles %} + +{% endblock %} {% block self_footer_js %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/juser/user_add.html b/templates/juser/user_add.html index 38bed2118..53d0351ec 100644 --- a/templates/juser/user_add.html +++ b/templates/juser/user_add.html @@ -93,10 +93,10 @@
-
+
- +
diff --git a/templates/juser/user_list.html b/templates/juser/user_list.html index 9d6fa45cf..18b527373 100644 --- a/templates/juser/user_list.html +++ b/templates/juser/user_list.html @@ -42,7 +42,7 @@ - + 用户名 姓名 @@ -57,7 +57,7 @@ {% for user in users.object_list %} - + {{ user.username }} {{ user.name }} @@ -91,10 +91,15 @@ {% endblock %} {% block self_head_css_js %} + {% load staticfiles %} + +{% endblock %} +{% block self_footer_js %} {% endblock %} \ No newline at end of file diff --git a/templates/nav.html b/templates/nav.html index 3f3e76d42..32d31bcc4 100644 --- a/templates/nav.html +++ b/templates/nav.html @@ -4,10 +4,10 @@