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
5418d0b4
Commit
5418d0b4
authored
Apr 08, 2017
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Change] Using csv replace xlsx
parent
bcc065eb
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
243 additions
and
240 deletions
+243
-240
asset.py
apps/assets/models/asset.py
+0
-1
group.py
apps/assets/models/group.py
+1
-0
idc.py
apps/assets/models/idc.py
+1
-0
user.py
apps/assets/models/user.py
+0
-1
_asset_import_modal.html
apps/assets/templates/assets/_asset_import_modal.html
+4
-1
asset.py
apps/assets/views/asset.py
+94
-89
settings.py
apps/jumpserver/settings.py
+1
-1
django.mo
apps/locale/zh/LC_MESSAGES/django.mo
+0
-0
django.po
apps/locale/zh/LC_MESSAGES/django.po
+63
-81
_base_create_update.html
apps/templates/_base_create_update.html
+1
-1
base.html
apps/templates/base.html
+2
-2
first_login.html
apps/users/templates/users/first_login.html
+4
-2
user_detail.html
apps/users/templates/users/user_detail.html
+4
-0
user_pubkey_update.html
apps/users/templates/users/user_pubkey_update.html
+1
-0
group.py
apps/users/views/group.py
+1
-1
user.py
apps/users/views/user.py
+66
-60
No files found.
apps/assets/models/asset.py
View file @
5418d0b4
...
...
@@ -86,7 +86,6 @@ class Asset(models.Model):
def
__unicode__
(
self
):
return
'
%
s <
%
s:
%
s>'
%
(
self
.
hostname
,
self
.
ip
,
self
.
port
)
__str__
=
__unicode__
@property
...
...
apps/assets/models/group.py
View file @
5418d0b4
...
...
@@ -23,6 +23,7 @@ class AssetGroup(models.Model):
def
__unicode__
(
self
):
return
self
.
name
__str__
=
__unicode__
class
Meta
:
ordering
=
[
'name'
]
...
...
apps/assets/models/idc.py
View file @
5418d0b4
...
...
@@ -36,6 +36,7 @@ class IDC(models.Model):
def
__unicode__
(
self
):
return
self
.
name
__str__
=
__unicode__
@classmethod
def
initial
(
cls
):
...
...
apps/assets/models/user.py
View file @
5418d0b4
...
...
@@ -50,7 +50,6 @@ class AdminUser(models.Model):
def
__unicode__
(
self
):
return
self
.
name
__str__
=
__unicode__
@property
...
...
apps/assets/templates/assets/_asset_import_modal.html
View file @
5418d0b4
...
...
@@ -7,11 +7,14 @@
{% csrf_token %}
<div
class=
"form-group"
>
<label
class=
"control-label"
for=
"id_assets"
>
{% trans "Template" %}
</label>
<a
href=
"{
{ MEDIA_URL }}files/asset_import_template.xlsx
"
style=
"display: block"
>
{% trans 'Download' %}
</a>
<a
href=
"{
% url 'assets:asset-export' %}
"
style=
"display: block"
>
{% trans 'Download' %}
</a>
</div>
<div
class=
"form-group"
>
<label
class=
"control-label"
for=
"id_users"
>
{% trans "Asset excel file" %}
</label>
<input
id=
"id_assets"
type=
"file"
name=
"file"
/>
<span
class=
"help-block"
>
{% trans 'If set id, will use this id update asset existed' %}
</span>
</div>
</form>
<p>
...
...
apps/assets/views/asset.py
View file @
5418d0b4
# coding:utf-8
from
__future__
import
absolute_import
,
unicode_literals
import
csv
import
json
import
uuid
import
codecs
from
io
import
StringIO
from
openpyxl
import
Workbook
from
openpyxl.writer.excel
import
save_virtual_workbook
from
openpyxl
import
load_workbook
from
django.conf
import
settings
from
django.db
import
IntegrityError
from
django.urls
import
reverse
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.views.generic
import
TemplateView
,
ListView
,
View
from
django.views.generic.edit
import
CreateView
,
DeleteView
,
FormView
,
UpdateView
from
django.urls
import
reverse_lazy
...
...
@@ -206,45 +206,42 @@ class AssetModalListView(AdminUserRequiredMixin, ListView):
@method_decorator
(
csrf_exempt
,
name
=
'dispatch'
)
class
AssetExportView
(
View
):
@staticmethod
def
get_asset_attr
(
asset
,
attr
):
if
attr
in
[
'admin_user'
,
'idc'
]:
return
getattr
(
asset
,
attr
)
elif
attr
in
[
'status'
,
'type'
,
'env'
]:
return
getattr
(
asset
,
'get_{}_display'
.
format
(
attr
))()
else
:
return
getattr
(
asset
,
attr
)
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
spm
=
request
.
GET
.
get
(
'spm'
,
''
)
assets_id
=
cache
.
get
(
spm
)
if
not
assets_id
and
not
isinstance
(
assets_id
,
list
):
return
HttpResponse
(
'May be expired'
,
status
=
404
)
assets_id
=
cache
.
get
(
spm
,
[
Asset
.
objects
.
first
()
.
id
])
print
(
assets_id
)
fields
=
[
field
for
field
in
Asset
.
_meta
.
fields
if
field
.
name
not
in
[
'date_created'
]
]
filename
=
'assets-{}.csv'
.
format
(
timezone
.
localtime
(
timezone
.
now
())
.
strftime
(
'
%
Y-
%
m-
%
d_
%
H-
%
M-
%
S'
))
response
=
HttpResponse
(
content_type
=
'text/csv'
)
response
[
'Content-Disposition'
]
=
'attachment; filename="
%
s"'
%
filename
response
.
write
(
codecs
.
BOM_UTF8
)
assets
=
Asset
.
objects
.
filter
(
id__in
=
assets_id
)
wb
=
Workbook
()
ws
=
wb
.
active
ws
.
title
=
'Asset'
header
=
[
'hostname'
,
'ip'
,
'port'
,
'admin_user'
,
'idc'
,
'memory'
,
'disk'
,
'mac_address'
,
'other_ip'
,
'remote_card_ip'
,
'os'
,
'cabinet_no'
,
'cabinet_pos'
,
'number'
,
'status'
,
'type'
,
'env'
,
'sn'
,
'comment'
]
ws
.
append
(
header
)
writer
=
csv
.
writer
(
response
,
dialect
=
'excel'
,
quoting
=
csv
.
QUOTE_MINIMAL
)
for
asset
in
assets
:
ws
.
append
([
self
.
get_asset_attr
(
asset
,
attr
)
for
attr
in
header
])
header
=
[
field
.
verbose_name
for
field
in
fields
]
header
.
append
(
_
(
'Asset groups'
))
writer
.
writerow
(
header
)
filename
=
'assets-{}.xlsx'
.
format
(
timezone
.
localtime
(
timezone
.
now
())
.
strftime
(
'
%
Y-
%
m-
%
d_
%
H-
%
M-
%
S'
))
response
=
HttpResponse
(
save_virtual_workbook
(
wb
),
content_type
=
'applications/vnd.ms-excel'
)
response
[
'Content-Disposition'
]
=
'attachment; filename="
%
s"'
%
filename
for
asset
in
assets
:
groups
=
','
.
join
([
group
.
name
for
group
in
asset
.
groups
.
all
()])
data
=
[
getattr
(
asset
,
field
.
name
)
for
field
in
fields
]
data
.
append
(
groups
)
writer
.
writerow
(
data
)
return
response
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
try
:
assets_id
=
json
.
loads
(
request
.
body
)
.
get
(
'assets_id'
,
[])
print
(
assets_id
)
except
ValueError
:
return
HttpResponse
(
'Json object not valid'
,
status
=
400
)
spm
=
uuid
.
uuid4
()
.
get_hex
()
spm
=
uuid
.
uuid4
()
.
hex
cache
.
set
(
spm
,
assets_id
,
300
)
url
=
reverse_lazy
(
'assets:asset-export'
)
+
'?spm=
%
s'
%
spm
return
JsonResponse
({
'redirect'
:
url
})
...
...
@@ -254,67 +251,74 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
form_class
=
forms
.
FileForm
def
form_valid
(
self
,
form
):
try
:
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_all
=
[
'hostname'
,
'ip'
,
'port'
,
'admin_user'
,
'idc'
,
'cpu'
,
'memory'
,
'disk'
,
'mac_address'
,
'other_ip'
,
'remote_card_ip'
,
'os'
,
'cabinet_no'
,
'cabinet_pos'
,
'number'
,
'status'
,
'type'
,
'env'
,
'sn'
,
'comment'
]
header_min
=
[
'hostname'
,
'ip'
,
'port'
,
'admin_user'
,
'comment'
]
header
=
[
col
.
value
for
col
in
next
(
rows
)]
if
not
set
(
header
)
.
issubset
(
set
(
header_all
))
and
not
set
(
header
)
.
issuperset
(
set
(
header_min
)):
data
=
{
'valid'
:
False
,
'msg'
:
'Must be same format as template or export file'
}
file
=
form
.
cleaned_data
[
'file'
]
data
=
file
.
read
()
.
decode
(
'utf-8'
)
.
strip
(
codecs
.
BOM_UTF8
.
decode
(
'utf-8'
))
csv_file
=
StringIO
(
data
)
reader
=
csv
.
reader
(
csv_file
)
csv_data
=
[
row
for
row
in
reader
]
fields
=
[
field
for
field
in
Asset
.
_meta
.
fields
if
field
.
name
not
in
[
'date_created'
]
]
header_
=
csv_data
[
0
]
mapping_reverse
=
{
field
.
verbose_name
:
field
.
name
for
field
in
fields
}
mapping_reverse
[
_
(
'Asset groups'
)]
=
'groups'
attr
=
[
mapping_reverse
.
get
(
n
,
None
)
for
n
in
header_
]
if
None
in
attr
:
data
=
{
'valid'
:
False
,
'msg'
:
'Must be same format as '
'template or export file'
}
return
self
.
render_json_response
(
data
)
created
=
[]
updated
=
[]
failed
=
[]
for
row
in
rows
:
asset_dict
=
dict
(
zip
(
header
,
[
col
.
value
for
col
in
row
]))
if
asset_dict
.
get
(
'admin_user'
,
None
):
admin_user
=
get_object_or_none
(
AdminUser
,
name
=
asset_dict
[
'admin_user'
])
asset_dict
[
'admin_user'
]
=
admin_user
if
asset_dict
.
get
(
'idc'
):
idc
=
get_object_or_none
(
IDC
,
name
=
asset_dict
[
'idc'
])
asset_dict
[
'idc'
]
=
idc
if
asset_dict
.
get
(
'type'
):
asset_display_type_map
=
dict
(
zip
(
dict
(
Asset
.
TYPE_CHOICES
)
.
values
(),
dict
(
Asset
.
TYPE_CHOICES
)
.
keys
()))
asset_type
=
asset_display_type_map
.
get
(
asset_dict
[
'type'
],
'Server'
)
asset_dict
[
'type'
]
=
asset_type
if
asset_dict
.
get
(
'status'
):
asset_display_status_map
=
dict
(
zip
(
dict
(
Asset
.
STATUS_CHOICES
)
.
values
(),
dict
(
Asset
.
STATUS_CHOICES
)
.
keys
()))
asset_status
=
asset_display_status_map
.
get
(
asset_dict
[
'status'
],
'In use'
)
asset_dict
[
'status'
]
=
asset_status
if
asset_dict
.
get
(
'env'
):
asset_display_env_map
=
dict
(
zip
(
dict
(
Asset
.
ENV_CHOICES
)
.
values
(),
dict
(
Asset
.
ENV_CHOICES
)
.
keys
()))
asset_env
=
asset_display_env_map
.
get
(
asset_dict
[
'env'
],
'Prod'
)
asset_dict
[
'env'
]
=
asset_env
created
,
updated
,
failed
=
[],
[],
[]
for
row
in
csv_data
[
1
:]:
if
set
(
row
)
==
{
''
}:
continue
asset_dict
=
dict
(
zip
(
attr
,
row
))
id_
=
asset_dict
.
pop
(
'id'
,
0
)
asset
=
get_object_or_none
(
Asset
,
id
=
id_
)
for
k
,
v
in
asset_dict
.
items
():
if
k
==
'idc'
:
v
=
get_object_or_none
(
IDC
,
name
=
v
)
elif
k
==
'is_active'
:
v
=
bool
(
v
)
elif
k
==
'admin_user'
:
v
=
get_object_or_none
(
AdminUser
,
name
=
v
)
elif
k
in
[
'port'
,
'cabinet_pos'
,
'cpu_count'
,
'cpu_cores'
]:
try
:
Asset
.
objects
.
create
(
**
asset_dict
)
created
.
append
(
asset_dict
[
'ip'
])
except
IntegrityError
as
e
:
asset
=
Asset
.
objects
.
filter
(
ip
=
asset_dict
[
'ip'
],
port
=
asset_dict
[
'port'
])
v
=
int
(
v
)
except
ValueError
:
v
=
0
elif
k
==
'groups'
:
groups_name
=
v
.
split
(
','
)
v
=
AssetGroup
.
objects
.
filter
(
name__in
=
groups_name
)
else
:
continue
asset_dict
[
k
]
=
v
if
not
asset
:
failed
.
append
(
asset_dict
[
'ip'
])
try
:
groups
=
asset_dict
.
pop
(
'groups'
)
asset
=
Asset
.
objects
.
create
(
**
asset_dict
)
asset
.
groups
.
set
(
groups
)
created
.
append
(
asset_dict
[
'hostname'
])
except
IndexError
as
e
:
failed
.
append
(
'
%
s:
%
s'
%
(
asset_dict
[
'hostname'
],
str
(
e
)))
else
:
for
k
,
v
in
asset_dict
.
items
():
if
k
==
'groups'
:
asset
.
groups
.
set
(
v
)
continue
asset
.
update
(
**
asset_dict
)
updated
.
append
(
asset_dict
[
'ip'
])
except
TypeError
as
e
:
print
(
e
)
failed
.
append
(
asset_dict
[
'ip'
])
if
v
:
setattr
(
asset
,
k
,
v
)
try
:
asset
.
save
()
updated
.
append
(
asset_dict
[
'hostname'
])
except
Exception
as
e
:
failed
.
append
(
'
%
s:
%
s'
%
(
asset_dict
[
'hostname'
],
str
(
e
)))
data
=
{
'created'
:
created
,
...
...
@@ -324,7 +328,8 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
'failed'
:
failed
,
'failed_info'
:
'Failed {}'
.
format
(
len
(
failed
)),
'valid'
:
True
,
'msg'
:
'Created: {}. Updated: {}, Error: {}'
.
format
(
len
(
created
),
len
(
updated
),
len
(
failed
))
'msg'
:
'Created: {}. Updated: {}, Error: {}'
.
format
(
len
(
created
),
len
(
updated
),
len
(
failed
))
}
return
self
.
render_json_response
(
data
)
...
...
apps/jumpserver/settings.py
View file @
5418d0b4
...
...
@@ -260,7 +260,7 @@ MEDIA_URL = '/media/'
MEDIA_ROOT
=
os
.
path
.
join
(
BASE_DIR
,
'media'
)
.
replace
(
'
\\
'
,
'/'
)
+
'/'
# Use django-bootstrap-form to format template, input max width arg
BOOTSTRAP_COLUMN_COUNT
=
11
#
BOOTSTRAP_COLUMN_COUNT = 11
# Init data or generate fake data source for development
FIXTURE_DIRS
=
[
os
.
path
.
join
(
BASE_DIR
,
'fixtures'
),
]
...
...
apps/locale/zh/LC_MESSAGES/django.mo
View file @
5418d0b4
No preview for this file type
apps/locale/zh/LC_MESSAGES/django.po
View file @
5418d0b4
...
...
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-04-0
7 17:03
+0800\n"
"POT-Creation-Date: 2017-04-0
8 21:58
+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
...
...
@@ -78,7 +78,7 @@ msgstr "登录地址"
#: assets/templates/assets/system_user_list.html:21 perms/models.py:40
#: perms/templates/perms/asset_permission_detail.html:98
#: users/models/group.py:19 users/models/user.py:43
#: users/templates/users/user_detail.html:1
09
#: users/templates/users/user_detail.html:1
13
#: users/templates/users/user_group_detail.html:70
#: users/templates/users/user_group_list.html:14
#: users/templates/users/user_profile.html:118
...
...
@@ -134,7 +134,7 @@ msgstr "在线session"
#: assets/templates/assets/asset_list.html:74 perms/models.py:33
#: perms/templates/perms/asset_permission_create_update.html:47
#: users/templates/users/_select_user_modal.html:18
#: users/templates/users/user_detail.html:1
26
#: users/templates/users/user_detail.html:1
30
#: users/templates/users/user_list.html:29
#: users/templates/users/user_profile.html:63
msgid "Active"
...
...
@@ -234,8 +234,8 @@ msgstr "其它"
#: assets/templates/assets/system_user_detail.html:137
#: perms/templates/perms/asset_permission_create_update.html:67
#: users/templates/users/_user.html:49
#: users/templates/users/user_detail.html:1
58
#: users/templates/users/user_detail.html:1
66
#: users/templates/users/user_detail.html:1
62
#: users/templates/users/user_detail.html:1
70
#: users/templates/users/user_password_update.html:58
#: users/templates/users/user_profile.html:139
#: users/templates/users/user_profile.html:147
...
...
@@ -259,7 +259,7 @@ msgstr "重置"
#: audits/templates/audits/proxy_log_online_list.html:124
#: perms/templates/perms/asset_permission_create_update.html:68
#: users/templates/users/_user.html:50
#: users/templates/users/first_login.html:6
0
#: users/templates/users/first_login.html:6
2
#: users/templates/users/forgot_password.html:44
#: users/templates/users/user_asset_permission.html:100
#: users/templates/users/user_group_asset_permission.html:100
...
...
@@ -569,7 +569,7 @@ msgstr "主机名原始"
#: assets/templates/assets/idc_detail.html:93
#: assets/templates/assets/system_user_detail.html:94 perms/models.py:37
#: perms/templates/perms/asset_permission_detail.html:94
#: users/models/user.py:47 users/templates/users/user_detail.html:
97
#: users/models/user.py:47 users/templates/users/user_detail.html:
101
msgid "Created by"
msgstr "创建者"
...
...
@@ -733,22 +733,17 @@ msgstr "选择系统用户"
msgid "Import asset"
msgstr "导入资产"
#: assets/templates/assets/_asset_import_modal.html:6
#: users/templates/users/_user_import_modal.html:6
msgid "Download template or use export excel format"
msgstr "下载模板"
#: assets/templates/assets/_asset_import_modal.html:10
#: assets/templates/assets/_asset_import_modal.html:9
#: users/templates/users/_user_import_modal.html:10
msgid "Template"
msgstr "模板"
#: assets/templates/assets/_asset_import_modal.html:1
1
#: assets/templates/assets/_asset_import_modal.html:1
0
#: users/templates/users/_user_import_modal.html:11
msgid "Download"
msgstr "下载"
#: assets/templates/assets/_asset_import_modal.html:1
4
#: assets/templates/assets/_asset_import_modal.html:1
3
msgid "Asset excel file"
msgstr "资产excel"
...
...
@@ -888,13 +883,13 @@ msgid "Platform"
msgstr ""
#: assets/templates/assets/asset_detail.html:152
#: users/templates/users/user_detail.html:10
1
#: users/templates/users/user_detail.html:10
5
#: users/templates/users/user_profile.html:88
msgid "Date joined"
msgstr "创建日期"
#: assets/templates/assets/asset_detail.html:168
#: users/templates/users/user_detail.html:12
0
#: users/templates/users/user_detail.html:12
4
#: users/templates/users/user_profile.html:130
msgid "Quick modify"
msgstr "快速修改"
...
...
@@ -929,9 +924,9 @@ msgstr "添加到资产组"
#: assets/templates/assets/system_user_asset.html:96
#: assets/templates/assets/system_user_list.html:102
#: assets/templates/assets/user_asset_list.html:167 templates/_modal.html:16
#: users/templates/users/user_detail.html:3
37
#: users/templates/users/user_detail.html:36
2
#: users/templates/users/user_detail.html:38
5
#: users/templates/users/user_detail.html:3
41
#: users/templates/users/user_detail.html:36
6
#: users/templates/users/user_detail.html:38
9
#: users/templates/users/user_group_create_update.html:45
#: users/templates/users/user_group_list.html:92
#: users/templates/users/user_list.html:171
...
...
@@ -940,8 +935,8 @@ msgid "Confirm"
msgstr "确认"
#: assets/templates/assets/asset_detail.html:374
#: users/templates/users/user_detail.html:27
1
#: users/templates/users/user_detail.html:28
4
#: users/templates/users/user_detail.html:27
5
#: users/templates/users/user_detail.html:28
8
msgid "Update successfully!"
msgstr "更新成功"
...
...
@@ -985,8 +980,8 @@ msgstr "批量更新"
#: assets/templates/assets/idc_list.html:94
#: assets/templates/assets/system_user_list.html:97
#: assets/templates/assets/user_asset_list.html:162
#: users/templates/users/user_detail.html:33
2
#: users/templates/users/user_detail.html:3
57
#: users/templates/users/user_detail.html:33
6
#: users/templates/users/user_detail.html:3
61
#: users/templates/users/user_group_list.html:87
#: users/templates/users/user_list.html:166
msgid "Are you sure?"
...
...
@@ -1149,10 +1144,8 @@ msgstr "IDC删除失败"
#: assets/templates/assets/system_user_asset.html:20
#: assets/templates/assets/system_user_detail.html:21
#, fuzzy
#| msgid "Attach Asset"
msgid "Attached assets"
msgstr "关联资产"
msgstr "关联
的
资产"
#: assets/templates/assets/system_user_asset.html:28
msgid "Assets of "
...
...
@@ -1179,7 +1172,6 @@ msgid "Attach AssetGroup"
msgstr "添加到资产组"
#: assets/templates/assets/system_user_detail.html:79
#: templates/_header_bar.html:41
msgid "Home"
msgstr ""
...
...
@@ -1494,7 +1486,7 @@ msgid "Select user groups"
msgstr "添加到用户组"
#: perms/models.py:35 perms/templates/perms/asset_permission_detail.html:86
#: users/models/user.py:46 users/templates/users/user_detail.html:9
3
#: users/models/user.py:46 users/templates/users/user_detail.html:9
7
#: users/templates/users/user_profile.html:96
msgid "Date expired"
msgstr "失效日期"
...
...
@@ -1527,7 +1519,7 @@ msgstr "添加资产组"
#: perms/templates/perms/asset_permission_asset.html:146
#: perms/templates/perms/asset_permission_detail.html:170
#: users/templates/users/user_detail.html:19
4
#: users/templates/users/user_detail.html:19
8
msgid "Join"
msgstr "加入"
...
...
@@ -1570,7 +1562,7 @@ msgstr "创建授权规则"
#: perms/templates/perms/asset_permission_list.html:13 templates/_nav.html:13
#: users/models/user.py:34 users/templates/users/_select_user_modal.html:16
#: users/templates/users/user_detail.html:1
77
#: users/templates/users/user_detail.html:1
81
#: users/templates/users/user_list.html:28
msgid "User group"
msgstr "用户组"
...
...
@@ -1659,18 +1651,18 @@ msgstr "注销登录"
msgid "Login"
msgstr "登录"
#: templates/_header_bar.html:41 templates/_nav.html:4
msgid "Dashboard"
msgstr "仪表盘"
#: templates/_modal.html:15
msgid "Close"
msgstr "关闭"
#: templates/_nav.html:4
msgid "Dashboard"
msgstr "仪表盘"
#: templates/_nav.html:9 users/templates/users/user_group_create_update.html:28
#: users/views/group.py:31 users/views/group.py:45 users/views/group.py:80
#: users/views/group.py:105 users/views/login.py:185 users/views/user.py:5
4
#: users/views/user.py:7
0 users/views/user.py:106 users/views/user.py:118
#: users/views/group.py:105 users/views/login.py:185 users/views/user.py:5
8
#: users/views/user.py:7
4 users/views/user.py:110 users/views/user.py:122
msgid "Users"
msgstr "用户管理"
...
...
@@ -1734,22 +1726,20 @@ msgid ""
" "
msgstr ""
"\n"
" 你的信息不完整,请点击 <a href="
"
\"%(first_login_url)s\"> 链接 </a>to
补充完整\n"
" 你的信息不完整,请点击 <a href=
\"%(first_login_url)s\"> 链接
"
"
</a>
补充完整\n"
" "
#: templates/base.html:37
#, python-format
msgid ""
"\n"
" Your ssh-public-key has been expired. Please click <a href="
"\"%(
profile_url
)s\"> this link </a>to update your ssh-public-key.\n"
"\"%(
user_pubkey_update
)s\"> this link </a>to update your ssh-public-key.\n"
" "
msgstr ""
"\n"
" 你的SSH key已经过期,点击 <a href="
"
\"%(profile_url)s\"> 链接
</a>更新 \n"
" 你的SSH key已经过期,点击 <a href=
\"%(user_pubkey_update)s\"> 链接
"
"</a>更新 \n"
" "
#: templates/captcha/image.html:3
...
...
@@ -1815,7 +1805,7 @@ msgstr ""
msgid "Invalid token or cache refreshed."
msgstr ""
#: users/forms.py:36 users/templates/users/user_detail.html:18
5
#: users/forms.py:36 users/templates/users/user_detail.html:18
9
msgid "Join user groups"
msgstr "添加到用户组"
...
...
@@ -1876,7 +1866,8 @@ msgid "Wechat"
msgstr "微信"
#: users/models/user.py:39 users/templates/users/_user.html:36
#: users/templates/users/user_detail.html:140
#: users/templates/users/user_detail.html:93
#: users/templates/users/user_detail.html:144
msgid "Enable OTP"
msgstr "二次验证"
...
...
@@ -1917,6 +1908,10 @@ msgstr "组"
msgid "Import user"
msgstr "导入"
#: users/templates/users/_user_import_modal.html:6
msgid "Download template or use export excel format"
msgstr "下载模板"
#: users/templates/users/_user_import_modal.html:14
msgid "Users excel file"
msgstr "用户excel"
...
...
@@ -1934,11 +1929,11 @@ msgstr "首次登陆"
msgid "Step"
msgstr "Step"
#: users/templates/users/first_login.html:5
7
#: users/templates/users/first_login.html:5
9
msgid "First step"
msgstr "第一步"
#: users/templates/users/first_login.html:
58
#: users/templates/users/first_login.html:
60
msgid "Prev step"
msgstr "上一步"
...
...
@@ -1968,8 +1963,8 @@ msgid "Captcha invalid"
msgstr "验证码错误"
#: users/templates/users/reset_password.html:45
#: users/templates/users/user_detail.html:15
5
#: users/templates/users/user_detail.html:32
3
#: users/templates/users/user_detail.html:15
9
#: users/templates/users/user_detail.html:32
7
#: users/templates/users/user_profile.html:136 users/utils.py:71
msgid "Reset password"
msgstr "重置密码"
...
...
@@ -1987,7 +1982,7 @@ msgstr "设置"
#: users/templates/users/user_granted_asset.html:18
#: users/templates/users/user_group_asset_permission.html:18
#: users/templates/users/user_group_granted_asset.html:18
#: users/views/user.py:1
19
#: users/views/user.py:1
23
msgid "User detail"
msgstr "用户详情"
...
...
@@ -2015,7 +2010,7 @@ msgid "Revoke Successfully!"
msgstr "回收成功"
#: users/templates/users/user_create.html:4
#: users/templates/users/user_list.html:16 users/views/user.py:7
0
#: users/templates/users/user_list.html:16 users/views/user.py:7
4
msgid "Create user"
msgstr "创建用户"
...
...
@@ -2023,47 +2018,47 @@ msgstr "创建用户"
msgid "Reset link will be generated and sent to the user. "
msgstr "生成重置密码连接,通过邮件发送给用户"
#: users/templates/users/user_detail.html:10
5
#: users/templates/users/user_detail.html:10
9
#: users/templates/users/user_profile.html:92
msgid "Last login"
msgstr "最后登录"
#: users/templates/users/user_detail.html:16
3
#: users/templates/users/user_detail.html:16
7
msgid "Reset ssh key"
msgstr "重置密钥"
#: users/templates/users/user_detail.html:32
2
#: users/templates/users/user_detail.html:32
6
msgid "An e-mail has been sent to the user\\'s mailbox."
msgstr "已发送邮件到用户邮箱"
#: users/templates/users/user_detail.html:33
3
#: users/templates/users/user_detail.html:33
7
msgid ""
"This will reset the user's password. A password-reset email will be sent to "
"the user\\'s mailbox."
msgstr ""
#: users/templates/users/user_detail.html:3
47
#: users/templates/users/user_detail.html:3
51
msgid ""
"The reset-ssh-public-key E-mail has been sent successfully. Please inform "
"the user to update his new ssh public key."
msgstr ""
#: users/templates/users/user_detail.html:3
48
#: users/templates/users/user_detail.html:3
52
#: users/templates/users/user_profile.html:144
msgid "Reset SSH public key"
msgstr "重置SSH密钥"
#: users/templates/users/user_detail.html:3
58
#: users/templates/users/user_detail.html:3
62
msgid "This will reset the user\\"
msgstr "重置"
#: users/templates/users/user_detail.html:37
5
#: users/templates/users/user_detail.html:37
9
#: users/templates/users/user_profile.html:170
msgid "Successfully updated the SSH public key."
msgstr ""
#: users/templates/users/user_detail.html:376
#: users/templates/users/user_detail.html:380
#: users/templates/users/user_detail.html:384
#: users/templates/users/user_profile.html:171
#: users/templates/users/user_profile.html:176
msgid "User SSH Public Key Update"
...
...
@@ -2071,23 +2066,17 @@ msgstr "ssh密钥"
#: users/templates/users/user_granted_asset.html:32
#: users/templates/users/user_group_granted_asset.html:32
#, fuzzy
#| msgid "Asset group list"
msgid "Assets granted of "
msgstr "
资产组列表
"
msgstr "
授权资产
"
#: users/templates/users/user_granted_asset.html:68
#: users/templates/users/user_group_granted_asset.html:68
#, fuzzy
#| msgid "Asset group list"
msgid "Asset groups granted of "
msgstr "
资产组列表
"
msgstr "
授权资产组
"
#: users/templates/users/user_group_asset_permission.html:71
#, fuzzy
#| msgid "Create perm"
msgid "Quick create permission for user group"
msgstr "
创建权限
"
msgstr "
快速授权
"
#: users/templates/users/user_group_create_update.html:30
msgid "Select User"
...
...
@@ -2194,7 +2183,7 @@ msgstr "指纹"
msgid "Update public key"
msgstr "更新密钥"
#: users/templates/users/user_update.html:3 users/views/user.py:1
06
#: users/templates/users/user_update.html:3 users/views/user.py:1
10
msgid "Update user"
msgstr "编辑用户"
...
...
@@ -2336,12 +2325,6 @@ msgstr "用户组列表"
msgid "Update user group"
msgstr "编辑用户组"
#: users/views/group.py:106
#, fuzzy
#| msgid "User group detail"
msgid "User Group Detail"
msgstr "资产组详情"
#: users/views/login.py:76
msgid "Logout success"
msgstr "退出登录成功"
...
...
@@ -2383,16 +2366,15 @@ msgstr "密码不一致"
msgid "First login"
msgstr "首次登陆"
#: users/views/user.py:5
5
#: users/views/user.py:5
9
msgid "User list"
msgstr "用户列表"
#: users/views/user.py:
66 users/views/user.py:33
4
#: users/views/user.py:
70 users/views/user.py:34
4
#, python-brace-format
msgid "Create user <a href=\"{url}\">{name}</a> successfully."
msgstr "创建用户 <a href=\"{url}\">{name}</a> 成功"
#: users/views/user.py:1
75
#: users/views/user.py:1
88
msgid "Invalid file."
msgstr "文件错误"
apps/templates/_base_create_update.html
View file @
5418d0b4
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load bootstrap %}
{% load bootstrap
3
%}
{% block custom_head_css_js %}
<link
href=
"{% static "
css
/
plugins
/
select2
/
select2
.
min
.
css
"
%}"
rel=
"stylesheet"
>
<script
src=
"{% static "
js
/
plugins
/
select2
/
select2
.
full
.
min
.
js
"
%}"
></script>
...
...
apps/templates/base.html
View file @
5418d0b4
...
...
@@ -33,9 +33,9 @@
{% block update_public_key_message %}
{% if user.is_authenticated and not user.is_public_key_valid %}
<div
class=
"alert alert-danger"
style=
"margin: 20px auto 0px"
>
{% url 'users:user-p
rofile' as profile_url
%}
{% url 'users:user-p
ubkey-update' as user_pubkey_update
%}
{% blocktrans %}
Your ssh-public-key has been expired. Please click
<a
href=
"{{
profile_url
}}"
>
this link
</a>
to update your ssh-public-key.
Your ssh-public-key has been expired. Please click
<a
href=
"{{
user_pubkey_update
}}"
>
this link
</a>
to update your ssh-public-key.
{% endblocktrans %}
</div>
{% endif %}
...
...
apps/users/templates/users/first_login.html
View file @
5418d0b4
...
...
@@ -44,10 +44,12 @@
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form|bootstrap }}
{% bootstrap_form form %}
{# {{ form|bootstrap }}#}
{% endfor %}
{% else %}
{{ wizard.form|bootstrap }}
{# {{ wizard.form|bootstrap }}#}
{% bootstrap_form wizard.form %}
{% endif %}
</form>
</div>
...
...
apps/users/templates/users/user_detail.html
View file @
5418d0b4
...
...
@@ -89,6 +89,10 @@
<td>
{% trans 'Role' %}:
</td>
<td><b>
{{ user_object.get_role_display }}
</b></td>
</tr>
<tr>
<td>
{% trans 'Enable OTP' %}:
</td>
<td><b>
{{ user_object.enable_otp|yesno:"Yes,No,Unknown"}}
</b></td>
</tr>
<tr>
<td>
{% trans 'Date expired' %}:
</td>
<td><b>
{{ user_object.date_expired|date:"Y-m-j H:i:s" }}
</b></td>
...
...
apps/users/templates/users/user_pubkey_update.html
View file @
5418d0b4
...
...
@@ -61,6 +61,7 @@
<label>
{{ user.public_key_obj.hash_md5 }}
</label>
</div>
</div>
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Update public key' %}
</h3>
{% bootstrap_field form.public_key layout="horizontal" %}
<div
class=
"hr-line-dashed"
></div>
...
...
apps/users/views/group.py
View file @
5418d0b4
...
...
@@ -103,7 +103,7 @@ class UserGroupDetailView(AdminUserRequiredMixin, DetailView):
users
=
User
.
objects
.
exclude
(
id__in
=
self
.
object
.
users
.
all
())
context
=
{
'app'
:
_
(
'Users'
),
'action'
:
_
(
'User
Group D
etail'
),
'action'
:
_
(
'User
group d
etail'
),
'users'
:
users
,
}
kwargs
.
update
(
context
)
...
...
apps/users/views/user.py
View file @
5418d0b4
...
...
@@ -4,10 +4,9 @@ from __future__ import unicode_literals
import
json
import
uuid
from
openpyxl
import
load_workbook
from
openpyxl
import
Workbook
from
openpyxl.writer.excel
import
save_virtual_workbook
import
csv
import
codecs
from
io
import
StringIO
from
django.contrib.auth.mixins
import
LoginRequiredMixin
from
django.contrib.messages.views
import
SuccessMessageMixin
...
...
@@ -31,7 +30,7 @@ from .. import forms
from
..models
import
User
,
UserGroup
from
..utils
import
AdminUserRequiredMixin
,
user_add_success_next
from
common.mixins
import
JSONResponseMixin
from
common.utils
import
get_logger
from
common.utils
import
get_logger
,
get_object_or_none
from
perms.models
import
AssetPermission
__all__
=
[
'UserListView'
,
'UserCreateView'
,
'UserDetailView'
,
...
...
@@ -123,34 +122,44 @@ class UserDetailView(AdminUserRequiredMixin, DetailView):
return
super
(
UserDetailView
,
self
)
.
get_context_data
(
**
kwargs
)
USER_ATTR_MAPPING
=
(
(
'name'
,
'Name'
),
(
'username'
,
'Username'
),
(
'email'
,
'Email'
),
(
'groups'
,
'User groups'
),
(
'role'
,
'Role'
),
(
'phone'
,
'Phone'
),
(
'wechat'
,
'Wechat'
),
(
'comment'
,
'Comment'
),
)
@method_decorator
(
csrf_exempt
,
name
=
'dispatch'
)
class
UserExportView
(
View
):
def
get
(
self
,
request
):
mapping
=
[
(
k
,
_
(
v
))
for
k
,
v
in
USER_ATTR_MAPPING
]
spm
=
request
.
GET
.
get
(
'spm'
,
''
)
users_id
=
cache
.
get
(
spm
)
if
not
users_id
and
not
isinstance
(
users_id
,
list
):
return
HttpResponse
(
'May be expired'
,
status
=
404
)
users_id
=
cache
.
get
(
spm
,
[
'1'
])
filename
=
'users-{}.csv'
.
format
(
timezone
.
localtime
(
timezone
.
now
())
.
strftime
(
'
%
Y-
%
m-
%
d_
%
H-
%
M-
%
S'
))
response
=
HttpResponse
(
content_type
=
'text/csv'
)
response
[
'Content-Disposition'
]
=
'attachment; filename="
%
s"'
%
filename
response
.
write
(
codecs
.
BOM_UTF8
)
users
=
User
.
objects
.
filter
(
id__in
=
users_id
)
print
(
users
)
wb
=
Workbook
()
ws
=
wb
.
active
ws
.
title
=
'User'
header
=
[
"name"
,
'username'
,
'email'
,
'groups'
,
"role"
,
"phone"
,
"wechat"
,
"comment"
]
ws
.
append
(
header
)
writer
=
csv
.
writer
(
response
,
dialect
=
'excel'
,
quoting
=
csv
.
QUOTE_MINIMAL
)
header
=
[
v
for
k
,
v
in
mapping
]
writer
.
writerow
(
header
)
for
user
in
users
:
ws
.
append
([
user
.
name
,
user
.
username
,
user
.
email
,
','
.
join
([
group
.
name
for
group
in
user
.
groups
.
all
()]),
user
.
role
,
user
.
phone
,
user
.
wechat
,
user
.
comment
])
groups
=
','
.
join
([
group
.
name
for
group
in
user
.
groups
.
all
()])
writer
.
writerow
([
user
.
name
,
user
.
username
,
user
.
email
,
groups
,
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
=
'applications/vnd.ms-excel'
)
response
[
'Content-Disposition'
]
=
'attachment; filename="
%
s"'
%
filename
return
response
def
post
(
self
,
request
):
...
...
@@ -158,7 +167,7 @@ class UserExportView(View):
users_id
=
json
.
loads
(
request
.
body
)
.
get
(
'users_id'
,
[])
except
ValueError
:
return
HttpResponse
(
'Json object not valid'
,
status
=
400
)
spm
=
uuid
.
uuid4
()
.
get_hex
()
spm
=
uuid
.
uuid4
()
.
hex
cache
.
set
(
spm
,
users_id
,
300
)
url
=
reverse
(
'users:user-export'
)
+
'?spm=
%
s'
%
spm
return
JsonResponse
({
'redirect'
:
url
})
...
...
@@ -179,54 +188,51 @@ class UserBulkImportView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
return
self
.
render_json_response
(
data
)
def
form_valid
(
self
,
form
):
try
:
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
=
[
col
.
value
for
col
in
next
(
rows
)]
print
(
header
)
if
header
!=
header_need
:
data
=
{
'valid'
:
False
,
'msg'
:
'Must be same format as '
file
=
form
.
cleaned_data
[
'file'
]
data
=
file
.
read
()
.
decode
(
'utf-8'
)
.
strip
(
codecs
.
BOM_UTF8
.
decode
(
'utf-8'
))
csv_file
=
StringIO
(
data
)
reader
=
csv
.
reader
(
csv_file
)
csv_data
=
[
row
for
row
in
reader
]
header_
=
csv_data
[
0
]
mapping_reverse
=
{
_
(
v
):
k
for
k
,
v
in
USER_ATTR_MAPPING
}
user_attr
=
[
mapping_reverse
.
get
(
n
,
None
)
for
n
in
header_
]
if
None
in
user_attr
:
data
=
{
'valid'
:
False
,
'msg'
:
'Must be same format as '
'template or export file'
}
return
self
.
render_json_response
(
data
)
created
=
[]
updated
=
[]
failed
=
[]
for
row
in
rows
:
user_dict
=
dict
(
zip
(
header
,
[
col
.
value
for
col
in
row
]
))
created
,
updated
,
failed
=
[],
[],
[]
for
row
in
csv_data
[
1
:]:
if
set
(
row
)
==
{
''
}:
continue
user_dict
=
dict
(
zip
(
user_attr
,
row
))
groups_name
=
user_dict
.
pop
(
'groups'
)
if
groups_name
:
groups_name
=
groups_name
.
split
(
','
)
groups
=
UserGroup
.
objects
.
filter
(
name__in
=
groups_name
)
else
:
groups
=
None
username
=
user_dict
[
'username'
]
user
=
get_object_or_none
(
User
,
username
=
username
)
if
not
user
:
try
:
user
=
User
.
objects
.
create
(
**
user_dict
)
user_add_success_next
(
user
)
created
.
append
(
user_dict
[
'username'
])
except
User
.
IntegrityError
as
e
:
user
=
User
.
objects
.
filter
(
username
=
user_dict
[
'username'
])
if
not
user
:
failed
.
append
(
user_dict
[
'username'
])
continue
user
.
update
(
**
user_dict
)
user
=
user
[
0
]
user_add_success_next
(
user
)
except
Exception
as
e
:
failed
.
append
(
'
%
s:
%
s'
%
(
user_dict
[
'username'
],
str
(
e
)))
else
:
for
k
,
v
in
user_dict
.
items
():
if
v
:
setattr
(
user
,
k
,
v
)
try
:
user
.
save
()
updated
.
append
(
user_dict
[
'username'
])
except
TypeError
as
e
:
print
(
e
)
failed
.
append
(
user_dict
[
'username'
])
user
=
None
except
Exception
as
e
:
failed
.
append
(
'
%
s:
%
s'
%
(
user_dict
[
'username'
],
str
(
e
)))
if
user
and
groups
:
user
.
groups
.
add
(
*
tuple
(
groups
))
user
.
groups
=
groups
user
.
save
()
data
=
{
...
...
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