From de9ce6dd190677d25038d298acc879811f708158 Mon Sep 17 00:00:00 2001 From: liuzheng712 Date: Mon, 16 Nov 2015 22:28:02 +0800 Subject: [PATCH 01/11] select all --- static/js/jquery.shiftcheckbox.js | 196 ++++++++++++++++++++++++++++++ templates/juser/group_list.html | 17 ++- templates/juser/user_list.html | 12 +- 3 files changed, 221 insertions(+), 4 deletions(-) create mode 100644 static/js/jquery.shiftcheckbox.js diff --git a/static/js/jquery.shiftcheckbox.js b/static/js/jquery.shiftcheckbox.js new file mode 100644 index 000000000..f2d01210d --- /dev/null +++ b/static/js/jquery.shiftcheckbox.js @@ -0,0 +1,196 @@ +/* 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); diff --git a/templates/juser/group_list.html b/templates/juser/group_list.html index 092c75776..88d8dd32c 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 diff --git a/templates/juser/user_list.html b/templates/juser/user_list.html index 9d6fa45cf..60bb38853 100644 --- a/templates/juser/user_list.html +++ b/templates/juser/user_list.html @@ -91,6 +91,10 @@ {% endblock %} {% block self_head_css_js %} + {% load staticfiles %} + +{% endblock %} +{% block self_footer_js %} {% endblock %} \ No newline at end of file From adf20f188eda3048dddf856a9a9ee2385cffacbe Mon Sep 17 00:00:00 2001 From: liuzheng712 Date: Tue, 17 Nov 2015 10:16:51 +0800 Subject: [PATCH 02/11] user.update --- juser/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/juser/views.py b/juser/views.py index 16fa1e7a3..005175b5a 100644 --- a/juser/views.py +++ b/juser/views.py @@ -423,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('/') From 738c6353ef56610af312e492c31117b460e1cdd8 Mon Sep 17 00:00:00 2001 From: liuzheng712 Date: Tue, 17 Nov 2015 10:44:34 +0800 Subject: [PATCH 03/11] user.update --- juser/user_api.py | 2 +- juser/views.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/juser/user_api.py b/juser/user_api.py index 321006e79..d9d1022da 100644 --- a/juser/user_api.py +++ b/juser/user_api.py @@ -86,7 +86,7 @@ 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) if user: pwd = kwargs.pop('password') user.update(**kwargs) diff --git a/juser/views.py b/juser/views.py index 005175b5a..09decb300 100644 --- a/juser/views.py +++ b/juser/views.py @@ -423,7 +423,7 @@ def profile(request): def change_info(request): header_title, path1, path2 = '修改信息', '用户管理', '修改个人信息' user_id = request.user.id - user = User.objects.get(id=user_id) + user = User.objects.filter(id=user_id) error = '' if not user: return HttpResponseRedirect('/') @@ -443,8 +443,8 @@ def change_info(request): # if password != user.password: # password = CRYPTOR.md5_crypt(password) - user.update(name=name, email=email) - user.set_password(password) + user.update(username=name, email=email) + User.objects.get(id=user_id).set_password(password) msg = '修改成功' return render_to_response('juser/change_info.html', locals(), context_instance=RequestContext(request)) From a99f024dfca753b9b8755578938b6a499f8337a4 Mon Sep 17 00:00:00 2001 From: liuzheng712 Date: Tue, 17 Nov 2015 11:07:40 +0800 Subject: [PATCH 04/11] user.update --- juser/user_api.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/juser/user_api.py b/juser/user_api.py index d9d1022da..0dfd3be21 100644 --- a/juser/user_api.py +++ b/juser/user_api.py @@ -87,12 +87,13 @@ def db_update_user(**kwargs): admin_groups_post = kwargs.pop('admin_groups') user_id = kwargs.pop('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.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() From 1c3b66c1a86a42abac398036fd398bc8596da2f6 Mon Sep 17 00:00:00 2001 From: liuzheng712 Date: Tue, 17 Nov 2015 11:13:52 +0800 Subject: [PATCH 05/11] user.update --- juser/user_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/juser/user_api.py b/juser/user_api.py index 0dfd3be21..e66c02ccd 100644 --- a/juser/user_api.py +++ b/juser/user_api.py @@ -93,7 +93,7 @@ def db_update_user(**kwargs): user.update(**kwargs) if pwd != '': user_get.set_password(pwd) - # user.save() + user_get.save() else: return None From ee443361b9e0c3936567cd534c8ebb95f869a287 Mon Sep 17 00:00:00 2001 From: liuzheng712 Date: Tue, 17 Nov 2015 19:51:16 +0800 Subject: [PATCH 06/11] bug of user.update --- juser/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/juser/views.py b/juser/views.py index 09decb300..8fad83645 100644 --- a/juser/views.py +++ b/juser/views.py @@ -443,7 +443,7 @@ def change_info(request): # if password != user.password: # password = CRYPTOR.md5_crypt(password) - user.update(username=name, email=email) + user.update(name=name, email=email) User.objects.get(id=user_id).set_password(password) msg = '修改成功' From 4397819b44c311aebcb602845d789ef48f654239 Mon Sep 17 00:00:00 2001 From: liuzheng712 Date: Tue, 17 Nov 2015 19:55:38 +0800 Subject: [PATCH 07/11] user.update bug fix --- juser/views.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/juser/views.py b/juser/views.py index 8fad83645..d140410b2 100644 --- a/juser/views.py +++ b/juser/views.py @@ -423,7 +423,7 @@ def profile(request): def change_info(request): header_title, path1, path2 = '修改信息', '用户管理', '修改个人信息' user_id = request.user.id - user = User.objects.filter(id=user_id) + user = User.objects.get(id=user_id) error = '' if not user: return HttpResponseRedirect('/') @@ -443,8 +443,9 @@ def change_info(request): # if password != user.password: # password = CRYPTOR.md5_crypt(password) - user.update(name=name, email=email) - User.objects.get(id=user_id).set_password(password) + User.objects.filter(id=user_id).update(name=name, email=email) + user.set_password(password) + user.save() msg = '修改成功' return render_to_response('juser/change_info.html', locals(), context_instance=RequestContext(request)) From 84992746de1643945fcbba714b538d106f9427bd Mon Sep 17 00:00:00 2001 From: liuzheng712 Date: Tue, 17 Nov 2015 20:06:25 +0800 Subject: [PATCH 08/11] juser/change_info/ fix password can be ignore --- juser/views.py | 10 +++++----- templates/juser/change_info.html | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/juser/views.py b/juser/views.py index d140410b2..f0f04c79e 100644 --- a/juser/views.py +++ b/juser/views.py @@ -433,10 +433,9 @@ 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: @@ -444,8 +443,9 @@ def change_info(request): # password = CRYPTOR.md5_crypt(password) User.objects.filter(id=user_id).update(name=name, email=email) - user.set_password(password) - user.save() + if len(password) > 0: + user.set_password(password) + user.save() msg = '修改成功' return render_to_response('juser/change_info.html', locals(), context_instance=RequestContext(request)) 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: "必须填写!"} From 4027a87e7f39230452448cdb5cc841d2c4f02b96 Mon Sep 17 00:00:00 2001 From: liuzheng712 Date: Tue, 17 Nov 2015 20:25:15 +0800 Subject: [PATCH 09/11] user delete with alert confirm --- templates/juser/user_list.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/juser/user_list.html b/templates/juser/user_list.html index b885f3840..18b527373 100644 --- a/templates/juser/user_list.html +++ b/templates/juser/user_list.html @@ -99,6 +99,7 @@ $(document).ready(function(){ $('.del').click(function(){ var row = $(this).closest('tr'); + if (confirm("确定删除")) { $.get( $(this).attr('value'), {}, @@ -106,7 +107,7 @@ row.remove(); alert(data); } - ) + )} }); $('#del_btn').click(function(){ From 37b91c40b6bc1dce7f0cc18dd79b3f1c91e8babc Mon Sep 17 00:00:00 2001 From: liuzheng712 Date: Tue, 17 Nov 2015 20:27:38 +0800 Subject: [PATCH 10/11] url --- juser/urls.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) 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'), ) From ee7675f7ae23e234269507eb7561afeba01acaf4 Mon Sep 17 00:00:00 2001 From: liuzheng712 Date: Tue, 17 Nov 2015 21:06:38 +0800 Subject: [PATCH 11/11] fix when ./keys/user/ didn't exist bug --- juser/user_api.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/juser/user_api.py b/juser/user_api.py index e66c02ccd..911c554ee 100644 --- a/juser/user_api.py +++ b/juser/user_api.py @@ -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')