Add export and import

pull/530/head
ibuler 8 years ago
parent be99eb82e8
commit e28f7a3bec

@ -141,4 +141,4 @@ class UserGroupPrivateAssetPermissionForm(forms.ModelForm):
class FileForm(forms.Form):
excel = forms.FileField()
users = forms.FileField()

@ -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 %}
<p class="text-success">{% trans " * CSV format should be same as export" %}</p>
<form method="post" class="form-horizontal" action="{% url 'users:user-import' %}" id="fm_user_import" enctype="multipart/form-data">
<form method="post" action="{% url 'users:user-import' %}" id="fm_user_import" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<label class="control-label col-sm-2 col-lg-2 " for="id_excel">{% trans "CSV" %}</label>
<div class=" col-sm-9 col-lg-9 ">
<input id="id_excel" type="file" name="excel" />
</div>
<label class="control-label" for="id_users">{% trans "Users csv file" %}</label>
<input id="id_users" type="file" name="users" />
</div>
</form>
{% endblock %}

@ -3,17 +3,18 @@
{% block table_search %}
<div class="html5buttons">
<div class="dt-buttons btn-group">
{# <a class="btn btn-default buttons-pdf" tabindex="0" href="#">#}
{# <span>PDF</span></a>#}
<a class="btn btn-default buttons-csv" tabindex="0" href="#">
<span>CSV</span>
<a class="btn btn-default btn_import" data-toggle="modal" data-target="#user_import_modal" tabindex="0">
<span>{% trans "Import" %}</span>
</a>
<a class="btn btn-default btn_export" tabindex="0">
<span>{% trans "Export" %}</span>
</a>
</div>
</div>
{% endblock %}
{% block table_container %}
<div class="uc pull-left m-l-5 m-r-5"><a href="{% url "users:user-create" %}" class="btn btn-sm btn-primary"> {% trans "Create user" %} </a></div>
<div class="uc pull-left"><a href="javascript:void(0);" class="btn btn-sm btn-primary" data-toggle="modal" data-target="#user_import_modal"> {% trans "Import user" %} </a></div>
{#<div class="uc pull-left"><a href="javascript:void(0);" class="btn btn-sm btn-primary" data-toggle="modal" data-target="#user_import_modal"> {% trans "Import user" %} </a></div>#}
<table class="table table-striped table-bordered table-hover " id="user_list_table" >
<thead>
<tr>
@ -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');
$('<span />', {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.' %}");#}
$('<span />', {class: 'help-block text-danger'}).html(data.errors.join(',')).insertAfter($('#id_users'));
$('<span />', {class: 'help-block text-warning'}).html(data.updated.join(',')).insertAfter($('#id_users'));
$('<span />', {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');
$('<span />', {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});
})
});
</script>
{% endblock %}

@ -24,7 +24,7 @@ urlpatterns = [
url(r'^user/(?P<pk>[0-9]+)/assets', views.UserGrantedAssetView.as_view(), name='user-granted-asset'),
url(r'^user/(?P<pk>[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<pk>[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<pk>[0-9]+)/update$', views.UserUpdateView.as_view(), name='user-update'),

@ -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 '<br />'.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

Loading…
Cancel
Save