Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
J
jumpserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
jumpserver
Commits
eae580e5
Commit
eae580e5
authored
Nov 24, 2016
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update user import and export
parent
e28f7a3b
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
84 additions
and
42 deletions
+84
-42
common_tags.py
apps/common/templatetags/common_tags.py
+3
-1
settings.py
apps/jumpserver/settings.py
+1
-0
user_import_template.xlsx
apps/media/files/user_import_template.xlsx
+0
-0
forms.py
apps/users/forms.py
+1
-1
_user_import_modal.html
apps/users/templates/users/_user_import_modal.html
+15
-3
user_list.html
apps/users/templates/users/user_list.html
+8
-8
views.py
apps/users/views.py
+56
-29
No files found.
apps/common/templatetags/common_tags.py
View file @
eae580e5
...
@@ -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
IntToS
tr
(
value
):
def
int_to_s
tr
(
value
):
return
str
(
value
)
return
str
(
value
)
\ No newline at end of file
apps/jumpserver/settings.py
View file @
eae580e5
...
@@ -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'
,
],
],
},
},
},
},
...
...
apps/media/files/user_import_template.xlsx
0 → 100644
View file @
eae580e5
File added
apps/users/forms.py
View file @
eae580e5
...
@@ -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
()
apps/users/templates/users/_user_import_modal.html
View file @
eae580e5
...
@@ -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 expor
t" %}
</p>
<p
class=
"text-success"
>
{% trans "
Download template or use export excel forma
t" %}
</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 %}
apps/users/templates/users/user_list.html
View file @
eae580e5
...
@@ -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
});
...
...
apps/users/views.py
View file @
eae580e5
...
@@ -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'
)
groups
=
UserGroup
.
objects
.
filter
(
name__in
=
groups_name
)
if
groups_name
:
groups_name
=
groups_name
.
split
(
','
)
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
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment