Commit eae580e5 authored by ibuler's avatar ibuler

Update user import and export

parent e28f7a3b
...@@ -44,6 +44,7 @@ def join_attr(seq, attr=None, sep=None): ...@@ -44,6 +44,7 @@ def join_attr(seq, attr=None, sep=None):
print(seq) print(seq)
return sep.join(seq) return sep.join(seq)
@register.filter @register.filter
def IntToStr(value): def int_to_str(value):
return str(value) return str(value)
\ No newline at end of file
...@@ -98,6 +98,7 @@ TEMPLATES = [ ...@@ -98,6 +98,7 @@ TEMPLATES = [
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'django.template.context_processors.static', 'django.template.context_processors.static',
'django.template.context_processors.request', 'django.template.context_processors.request',
'django.template.context_processors.media',
], ],
}, },
}, },
......
...@@ -141,4 +141,4 @@ class UserGroupPrivateAssetPermissionForm(forms.ModelForm): ...@@ -141,4 +141,4 @@ class UserGroupPrivateAssetPermissionForm(forms.ModelForm):
class FileForm(forms.Form): class FileForm(forms.Form):
users = forms.FileField() file = forms.FileField()
...@@ -3,13 +3,25 @@ ...@@ -3,13 +3,25 @@
{% block modal_id %}user_import_modal{% endblock %} {% block modal_id %}user_import_modal{% endblock %}
{% block modal_title%}{% trans "Import user" %}{% endblock %} {% block modal_title%}{% trans "Import user" %}{% endblock %}
{% block modal_body %} {% block modal_body %}
<p class="text-success">{% trans " * CSV format should be same as export" %}</p> <p class="text-success">{% trans "Download template or use export excel format" %}</p>
<form method="post" 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 %} {% csrf_token %}
<div class="form-group"> <div class="form-group">
<label class="control-label" for="id_users">{% trans "Users csv file" %}</label> <label class="control-label" for="id_users">{% trans "Template" %}</label>
<input id="id_users" type="file" name="users" /> <a href="{{ MEDIA_URL }}files/user_import_template.xlsx" style="display: block">{% trans 'Download' %}</a>
</div>
<div class="form-group">
<label class="control-label" for="id_users">{% trans "Users excel file" %}</label>
<input id="id_users" type="file" name="file" />
</div> </div>
</form> </form>
<p>
<p class="text-success" id="id_created"></p>
<p id="id_created_detail"></p>
<p class="text-warning" id="id_updated"></p>
<p id="id_updated_detail"></p>
<p class="text-danger" id="id_failed"></p>
<p id="id_failed_detail"></p>
</p>
{% endblock %} {% endblock %}
{% block modal_confirm_id %}btn_user_import{% endblock %} {% block modal_confirm_id %}btn_user_import{% endblock %}
...@@ -114,16 +114,16 @@ $(document).ready(function(){ ...@@ -114,16 +114,16 @@ $(document).ready(function(){
$form.find('.help-block').remove(); $form.find('.help-block').remove();
function success (data) { function success (data) {
if (data.valid === false) { if (data.valid === false) {
var $help = $form.find('.help-block');
$('<span />', {class: 'help-block text-danger'}).html(data.msg).insertAfter($('#id_users')); $('<span />', {class: 'help-block text-danger'}).html(data.msg).insertAfter($('#id_users'));
} else { } else {
{# $('#user_import_modal').modal('hide');#} $('#id_created').html(data.created_info);
{# var $data_table = $('#user_list_table').DataTable();#} $('#id_created_detail').html(data.created.join(','));
{# toastr.success("{% trans 'Import User Success.' %}");#} $('#id_updated').html(data.updated_info);
$('<span />', {class: 'help-block text-danger'}).html(data.errors.join(',')).insertAfter($('#id_users')); $('#id_updated_detail').html(data.updated.join(','));
$('<span />', {class: 'help-block text-warning'}).html(data.updated.join(',')).insertAfter($('#id_users')); $('#id_failed').html(data.failed_info);
$('<span />', {class: 'help-block text-primary'}).html(data.created.join(',')).insertAfter($('#id_users')); $('#id_failed_detail').html(data.failed.join(','));
{# $data_table.ajax.reload();#} var $data_table = $('#user_list_table').DataTable();
$data_table.ajax.reload();
} }
} }
$form.ajaxSubmit({success: success}); $form.ajaxSubmit({success: success});
......
...@@ -3,8 +3,11 @@ ...@@ -3,8 +3,11 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import json import json
import uuid import uuid
from io import BytesIO import codecs
from openpyxl import Workbook
from openpyxl.writer.excel import save_virtual_workbook
from openpyxl import load_workbook
import unicodecsv as csv import unicodecsv as csv
from django import forms from django import forms
from django.utils import timezone from django.utils import timezone
...@@ -37,8 +40,6 @@ from .utils import AdminUserRequiredMixin, user_add_success_next, send_reset_pas ...@@ -37,8 +40,6 @@ from .utils import AdminUserRequiredMixin, user_add_success_next, send_reset_pas
from .hands import write_login_log_async from .hands import write_login_log_async
from . import forms from . import forms
logger = get_logger(__name__) logger = get_logger(__name__)
...@@ -96,7 +97,11 @@ class UserListView(AdminUserRequiredMixin, TemplateView): ...@@ -96,7 +97,11 @@ class UserListView(AdminUserRequiredMixin, TemplateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(UserListView, self).get_context_data(**kwargs) context = super(UserListView, self).get_context_data(**kwargs)
context.update({'app': _('Users'), 'action': _('User list'), 'groups': UserGroup.objects.all()}) context.update({
'app': _('Users'),
'action': _('User list'),
'groups': UserGroup.objects.all()
})
return context return context
...@@ -496,41 +501,61 @@ class BulkImportUserView(AdminUserRequiredMixin, JSONResponseMixin, FormView): ...@@ -496,41 +501,61 @@ class BulkImportUserView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
return self.render_json_response(data) return self.render_json_response(data)
def form_valid(self, form): def form_valid(self, form):
users_csv = form.cleaned_data['users'] try:
users_csv_f = csv.reader(users_csv, encoding='utf-8') wb = load_workbook(form.cleaned_data['file'])
ws = wb.get_active_sheet()
except Exception as e:
print(e)
data = {'valid': False, 'msg': 'Not a valid Excel file'}
return self.render_json_response(data)
rows = ws.rows
header_need = ["name", 'username', 'email', 'groups', "role", "phone", "wechat", "comment"] header_need = ["name", 'username', 'email', 'groups', "role", "phone", "wechat", "comment"]
header = next(users_csv_f) header = [col.value for col in next(rows)]
print(header) print(header)
if header != header_need: if header != header_need:
data = {'valid': False, 'msg': 'Must be same format as export csv: name, ...'} data = {'valid': False, 'msg': 'Must be same format as template or export file'}
return self.render_json_response(data) return self.render_json_response(data)
created = [] created = []
updated = [] updated = []
errors = [] failed = []
for row in users_csv_f: for row in rows:
user_dict = dict(zip(header, row)) user_dict = dict(zip(header, [col.value for col in row]))
groups_name = user_dict.pop('groups').split(',') groups_name = user_dict.pop('groups')
if groups_name:
groups_name = groups_name.split(',')
groups = UserGroup.objects.filter(name__in=groups_name) groups = UserGroup.objects.filter(name__in=groups_name)
else:
groups = None
try: try:
user = User.objects.create(**user_dict) user = User.objects.create(**user_dict)
user.groups.add(*tuple(groups))
user.save()
created.append(user_dict['username']) created.append(user_dict['username'])
except IntegrityError: except IntegrityError:
user = User.objects.filter(username=user_dict['username']) user = User.objects.filter(username=user_dict['username'])
if not user:
failed.append(user_dict['username'])
continue
user.update(**user_dict) user.update(**user_dict)
user[0].groups.add(*tuple(groups)) user = user[0]
updated.append(user_dict['username']) updated.append(user_dict['username'])
except TypeError: except TypeError:
errors.append(user_dict['username']) failed.append(user_dict['username'])
user = None
if user and groups:
user.groups.add(*tuple(groups))
user.save()
data = { data = {
'created': created, 'created': created,
'created_info': 'Created {}'.format(len(created)),
'updated': updated, 'updated': updated,
'errors': errors, 'updated_info': 'Updated {}'.format(len(updated)),
'failed': failed,
'failed_info': 'Failed {}'.format(len(failed)),
'valid': True, 'valid': True,
'msg': 'Created: {}. Updated: {}, Error: {}'.format(len(created), len(updated), len(errors)) 'msg': 'Created: {}. Updated: {}, Error: {}'.format(len(created), len(updated), len(failed))
} }
return self.render_json_response(data) return self.render_json_response(data)
...@@ -544,22 +569,24 @@ class ExportUserCsvView(View): ...@@ -544,22 +569,24 @@ class ExportUserCsvView(View):
return HttpResponse('May be expired', status=404) return HttpResponse('May be expired', status=404)
users = User.objects.filter(id__in=users_id) users = User.objects.filter(id__in=users_id)
filename = 'users-%s.csv' % timezone.localtime(timezone.now()).strftime('%Y-%m-%d_%H-%M-%S') wb = Workbook()
response = HttpResponse(content_type='application/csv') ws = wb.active
response['Content-Disposition'] = 'attachment; filename="%s"' % filename ws.title = 'User'
writer = csv.writer(response, delimiter=str(","), lineterminator='\n',
quoting=csv.QUOTE_ALL, dialect='excel')
header = ["name", 'username', 'email', 'groups', "role", "phone", "wechat", "comment"] header = ["name", 'username', 'email', 'groups', "role", "phone", "wechat", "comment"]
writer.writerow(header) ws.append(header)
for user in users: for user in users:
writer.writerow([user.name, user.username, user.email, ws.append([user.name, user.username, user.email,
','.join([group.name for group in user.groups.all()]), ','.join([group.name for group in user.groups.all()]),
user.role, user.phone, user.wechat, user.comment]) user.role, user.phone, user.wechat, user.comment])
filename = 'users-{}.xlsx'.format(timezone.localtime(timezone.now()).strftime('%Y-%m-%d_%H-%M-%S'))
response = HttpResponse(save_virtual_workbook(wb), content_type='application/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
return response return response
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
try: try:
print(request.body)
users_id = json.loads(request.body).get('users_id', []) users_id = json.loads(request.body).get('users_id', [])
except ValueError: except ValueError:
return HttpResponse('Json object not valid', status=400) return HttpResponse('Json object not valid', status=400)
......
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