diff --git a/apps/users/forms.py b/apps/users/forms.py
index a5827d960..472a8892c 100644
--- a/apps/users/forms.py
+++ b/apps/users/forms.py
@@ -141,4 +141,4 @@ class UserGroupPrivateAssetPermissionForm(forms.ModelForm):
class FileForm(forms.Form):
- excel = forms.FileField()
+ users = forms.FileField()
diff --git a/apps/users/templates/users/_user_import_modal.html b/apps/users/templates/users/_user_import_modal.html
index 0993d26fe..4ee538908 100644
--- a/apps/users/templates/users/_user_import_modal.html
+++ b/apps/users/templates/users/_user_import_modal.html
@@ -1,16 +1,14 @@
{% extends '_modal.html' %}
{% load i18n %}
{% block modal_id %}user_import_modal{% endblock %}
-{% block modal_title%}{% trans "Import User" %}{% endblock %}
+{% block modal_title%}{% trans "Import user" %}{% endblock %}
{% block modal_body %}
{% trans " * CSV format should be same as export" %}
-
{% endblock %}
diff --git a/apps/users/templates/users/user_list.html b/apps/users/templates/users/user_list.html
index 87fd018cc..dd2747102 100644
--- a/apps/users/templates/users/user_list.html
+++ b/apps/users/templates/users/user_list.html
@@ -3,17 +3,18 @@
{% block table_search %}
{% endblock %}
{% block table_container %}
-
+{##}
@@ -88,7 +89,7 @@ $(document).ready(function(){
};
var table = jumpserver.initDataTable(options);
- $('.buttons-csv').click(function () {
+ $('.btn_export').click(function () {
var users = [];
var rows = table.rows('.selected').data();
$.each(rows, function (index, obj) {
@@ -108,6 +109,26 @@ $(document).ready(function(){
})
});
+ $('#btn_user_import').click(function() {
+ var $form = $('#fm_user_import');
+ $form.find('.help-block').remove();
+ function success (data) {
+ if (data.valid === false) {
+ var $help = $form.find('.help-block');
+ $('', {class: 'help-block text-danger'}).html(data.msg).insertAfter($('#id_users'));
+ } else {
+{# $('#user_import_modal').modal('hide');#}
+{# var $data_table = $('#user_list_table').DataTable();#}
+{# toastr.success("{% trans 'Import User Success.' %}");#}
+ $('', {class: 'help-block text-danger'}).html(data.errors.join(',')).insertAfter($('#id_users'));
+ $('', {class: 'help-block text-warning'}).html(data.updated.join(',')).insertAfter($('#id_users'));
+ $('', {class: 'help-block text-primary'}).html(data.created.join(',')).insertAfter($('#id_users'));
+{# $data_table.ajax.reload();#}
+ }
+ }
+ $form.ajaxSubmit({success: success});
+ })
+
}).on('click', '#btn_bulk_update', function(){
var action = $('#slct_bulk_update').val();
var $data_table = $('#user_list_table').DataTable();
@@ -219,7 +240,7 @@ $(document).ready(function(){
new_groups = body.groups.map(Number);
body.groups = new_groups;
}
- var $data_table = $('#user_list_table').DataTable()
+ var $data_table = $('#user_list_table').DataTable();
var post_list = [];
$data_table.rows({selected: true}).every(function(){
var content = Object.assign({id: this.data().id}, body);
@@ -237,22 +258,7 @@ $(document).ready(function(){
};
APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(post_list), success: success});
$('#user_bulk_update_modal').modal('hide');
-}).on('click', '#btn_user_import', function() {
- var $form = $('#fm_user_import');
- $form.find('.help-block').remove();
- function success (data) {
- if (data.success === false) {
- var $help = $form.find('.help-block');
- $('', {class: 'help-block text-danger'}).html(data.msg).insertAfter($('#id_excel'));
- } else {
- $('#user_import_modal').modal('hide');
- var $data_table = $('#user_list_table').DataTable();
- toastr.success("{% trans 'Import User Success.' %}");
- $data_table.ajax.reload();
- }
- }
- $form.ajaxSubmit({success: success});
-})
+});
{% endblock %}
diff --git a/apps/users/urls/views_urls.py b/apps/users/urls/views_urls.py
index a80b33d38..b51285800 100644
--- a/apps/users/urls/views_urls.py
+++ b/apps/users/urls/views_urls.py
@@ -24,7 +24,7 @@ urlpatterns = [
url(r'^user/(?P[0-9]+)/assets', views.UserGrantedAssetView.as_view(), name='user-granted-asset'),
url(r'^user/(?P[0-9]+)/login-history', views.UserDetailView.as_view(), name='user-login-history'),
url(r'^first-login/$', views.UserFirstLoginView.as_view(), name='user-first-login'),
- url(r'^import/$', views.BulkImportUserView.as_view(), name='user-import'),
+ url(r'^user/import/$', views.BulkImportUserView.as_view(), name='user-import'),
# url(r'^user/(?P[0-9]+)/assets-perm$', views.UserDetailView.as_view(), name='user-detail'),
url(r'^user/create$', views.UserCreateView.as_view(), name='user-create'),
url(r'^user/(?P[0-9]+)/update$', views.UserUpdateView.as_view(), name='user-update'),
diff --git a/apps/users/views.py b/apps/users/views.py
index 6bc35f8f6..37c398012 100644
--- a/apps/users/views.py
+++ b/apps/users/views.py
@@ -5,11 +5,11 @@ import json
import uuid
from io import BytesIO
-from reportlab.pdfgen import canvas
import unicodecsv as csv
from django import forms
from django.utils import timezone
from django.core.cache import cache
+from django.db import IntegrityError
from django.contrib.auth import login as auth_login, logout as auth_logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
@@ -496,45 +496,41 @@ class BulkImportUserView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
return self.render_json_response(data)
def form_valid(self, form):
- from openpyxl import load_workbook
- try:
- wb = load_workbook(form.cleaned_data['excel'])
- ws = wb['users']
- except Exception as e:
- print e
- error = _('Not a valid Excel file.')
- data = {
- 'success': False,
- 'msg': error
- }
+ users_csv = form.cleaned_data['users']
+ users_csv_f = csv.reader(users_csv, encoding='utf-8')
+ header_need = ["name", 'username', 'email', 'groups', "role", "phone", "wechat", "comment"]
+ header = next(users_csv_f)
+ print(header)
+ if header != header_need:
+ data = {'valid': False, 'msg': 'Must be same format as export csv: name, ...'}
return self.render_json_response(data)
+ created = []
+ updated = []
errors = []
- for index, row in enumerate(ws.rows):
- user_data = [cell.value for cell in row]
- if len(user_data) != 4:
- errors.append("Row {}: invalid user data format.".format(index))
- continue
- username, email, enable_otp, role = user_data
- data = {
- 'username': username,
- 'email': email,
- 'enable_otp': True if enable_otp in ['T', '1', 1, True] else False,
- 'role': role
- }
- form = forms.UserBulkImportForm(data, auto_id=False)
- if form.is_valid():
- form.save()
- else:
- form_errors = form.errors.as_data()
- for key, err_list in form_errors.iteritems():
- error_line = "{} :".format(key)
- for errs in err_list:
- error_line = "{}{}".format(error_line, ";".join([err for err in errs.messages]))
- errors.append("Row {}: {}".format(index, error_line))
+ for row in users_csv_f:
+ user_dict = dict(zip(header, row))
+ groups_name = user_dict.pop('groups').split(',')
+ groups = UserGroup.objects.filter(name__in=groups_name)
+ try:
+ user = User.objects.create(**user_dict)
+ user.groups.add(*tuple(groups))
+ user.save()
+ created.append(user_dict['username'])
+ except IntegrityError:
+ user = User.objects.filter(username=user_dict['username'])
+ user.update(**user_dict)
+ user[0].groups.add(*tuple(groups))
+ updated.append(user_dict['username'])
+ except TypeError:
+ errors.append(user_dict['username'])
+
data = {
- 'success': True if not errors else False,
- 'msg': 'ok' if not errors else '
'.join(errors)
+ 'created': created,
+ 'updated': updated,
+ 'errors': errors,
+ 'valid': True,
+ 'msg': 'Created: {}. Updated: {}, Error: {}'.format(len(created), len(updated), len(errors))
}
return self.render_json_response(data)
@@ -543,22 +539,21 @@ class BulkImportUserView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
class ExportUserCsvView(View):
def get(self, request, *args, **kwargs):
spm = request.GET.get('spm', '')
- print(spm)
users_id = cache.get(spm)
if not users_id and not isinstance(users_id, list):
return HttpResponse('May be expired', status=404)
users = User.objects.filter(id__in=users_id)
- filename = 'users-%s.csv' % timezone.localtime(timezone.now()).strftime('%Y-%m-%d_%H:%M:%D')
+ filename = 'users-%s.csv' % timezone.localtime(timezone.now()).strftime('%Y-%m-%d_%H-%M-%S')
response = HttpResponse(content_type='application/csv')
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
writer = csv.writer(response, delimiter=str(","), lineterminator='\n',
quoting=csv.QUOTE_ALL, dialect='excel')
- header = [_("name"), _('username'), _('email'), _('user group'),
- _('role'), _('phone'), _('wechat'), _('comment')]
+ header = ["name", 'username', 'email', 'groups', "role", "phone", "wechat", "comment"]
writer.writerow(header)
for user in users:
- writer.writerow([user.name, user.username, user.email, ','.join([group.name for group in user.groups.all()]),
+ writer.writerow([user.name, user.username, user.email,
+ ','.join([group.name for group in user.groups.all()]),
user.role, user.phone, user.wechat, user.comment])
return response