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
0869931e
Commit
0869931e
authored
Jan 20, 2017
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Bugfix] 修改了一些issue上的bug
parent
948214ca
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
285 additions
and
233 deletions
+285
-233
forms.py
apps/assets/forms.py
+16
-28
admin_user_create_update.html
apps/assets/templates/assets/admin_user_create_update.html
+5
-0
admin_user_detail.html
apps/assets/templates/assets/admin_user_detail.html
+47
-3
asset_group_detail.html
apps/assets/templates/assets/asset_group_detail.html
+0
-1
idc_create_update.html
apps/assets/templates/assets/idc_create_update.html
+1
-1
idc_detail.html
apps/assets/templates/assets/idc_detail.html
+0
-1
views.py
apps/assets/views.py
+13
-26
login_log_list.html
apps/audits/templates/audits/login_log_list.html
+1
-0
proxy_log_list.html
apps/audits/templates/audits/proxy_log_list.html
+7
-6
views.py
apps/audits/views.py
+49
-25
forms.py
apps/perms/forms.py
+15
-10
asset_permission_detail.html
apps/perms/templates/perms/asset_permission_detail.html
+14
-18
asset_permission_list.html
apps/perms/templates/perms/asset_permission_list.html
+16
-3
jumpserver.js
apps/static/js/jumpserver.js
+6
-2
_pagination.html
apps/templates/_pagination.html
+1
-1
group.py
apps/users/models/group.py
+3
-2
_user.html
apps/users/templates/users/_user.html
+45
-40
user_detail.html
apps/users/templates/users/user_detail.html
+13
-1
user_group_create_update.html
apps/users/templates/users/user_group_create_update.html
+5
-0
user_group_detail.html
apps/users/templates/users/user_group_detail.html
+12
-0
utils.py
apps/users/utils.py
+1
-56
user.py
apps/users/views/user.py
+13
-7
config_example.py
config_example.py
+2
-2
No files found.
apps/assets/forms.py
View file @
0869931e
...
...
@@ -6,23 +6,6 @@ from .models import IDC, Asset, AssetGroup, AdminUser, SystemUser, Tag
from
common.utils
import
validate_ssh_private_key
,
ssh_pubkey_gen
# class AssetForm(forms.ModelForm):
# class Meta:
# model = Asset
#
# fields = [
# 'ip', 'other_ip', 'remote_card_ip', 'hostname', 'port', 'groups', 'username', 'password',
# 'idc', 'mac_address', 'brand', 'cpu', 'memory', 'disk', 'os', 'cabinet_no', 'cabinet_pos',
# 'number', 'status', 'type', 'env', 'sn', 'is_active', 'comment', 'admin_user', 'system_users'
# ]
#
# widgets = {
# 'groups': forms.SelectMultiple(attrs={'class': 'select2-groups', 'data-placeholder': _('Select asset groups')}),
# 'system_user': forms.SelectMultiple(attrs={'class': 'select2-system-user', 'data-placeholder': _('Select asset system user')}),
# 'admin_user': forms.SelectMultiple(attrs={'class': 'select2-admin-user', 'data-placeholder': _('Select asset admin user')}),
# }
#
class
AssetCreateForm
(
forms
.
ModelForm
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
instance
=
kwargs
.
get
(
'instance'
,
None
)
...
...
@@ -142,15 +125,19 @@ class IDCForm(forms.ModelForm):
class
AdminUserForm
(
forms
.
ModelForm
):
# Admin user assets define, let user select, save it in form not in view
assets
=
forms
.
ModelMultipleChoiceField
(
queryset
=
Asset
.
objects
.
all
(),
label
=
_
(
'Asset'
),
required
=
False
,
widget
=
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select assets'
)})
)
assets
=
forms
.
ModelMultipleChoiceField
(
queryset
=
Asset
.
objects
.
all
(),
label
=
_
(
'Asset'
),
required
=
False
,
widget
=
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select assets'
)})
)
# Form field name can not start with `_`, so redefine it,
password
=
forms
.
CharField
(
widget
=
forms
.
PasswordInput
,
max_length
=
100
,
min_length
=
8
,
strip
=
True
,
help_text
=
_
(
'If also set private key, use that first'
),
required
=
False
)
password
=
forms
.
CharField
(
widget
=
forms
.
PasswordInput
,
max_length
=
100
,
min_length
=
8
,
strip
=
True
,
required
=
False
,
help_text
=
_
(
'If also set private key, use that first'
),
)
# Need use upload private key file except paste private key content
private_key_file
=
forms
.
FileField
(
required
=
False
)
...
...
@@ -173,11 +160,11 @@ class AdminUserForm(forms.ModelForm):
admin_user
=
super
(
AdminUserForm
,
self
)
.
save
(
commit
=
commit
)
password
=
self
.
cleaned_data
[
'password'
]
private_key
=
self
.
cleaned_data
[
'private_key_file'
]
public_key
=
ssh_pubkey_gen
(
private_key
)
if
password
:
admin_user
.
password
=
password
if
private_key
:
public_key
=
ssh_pubkey_gen
(
private_key
)
admin_user
.
private_key
=
private_key
admin_user
.
public_key
=
public_key
admin_user
.
save
()
...
...
@@ -196,8 +183,9 @@ class AdminUserForm(forms.ModelForm):
password
=
self
.
cleaned_data
[
'password'
]
private_key_file
=
self
.
cleaned_data
.
get
(
'private_key_file'
,
''
)
if
not
(
password
or
private_key_file
):
raise
forms
.
ValidationError
(
_
(
'Password and private key file must be input one'
))
if
not
self
.
instance
and
not
(
password
or
private_key_file
):
raise
forms
.
ValidationError
(
_
(
'Password and private key file must be input one'
))
class
Meta
:
model
=
AdminUser
...
...
apps/assets/templates/assets/admin_user_create_update.html
View file @
0869931e
...
...
@@ -27,6 +27,11 @@
</div>
</div>
<div
class=
"ibox-content"
>
{% if form.non_field_errors %}
<div
class=
"alert alert-danger"
>
{{ form.non_field_errors }}
</div>
{% endif %}
<form
enctype=
"multipart/form-data"
method=
"post"
class=
"form-horizontal"
action=
""
>
{% csrf_token %}
{{ form.name|bootstrap_horizontal }}
...
...
apps/assets/templates/assets/admin_user_detail.html
View file @
0869931e
...
...
@@ -21,6 +21,11 @@
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline btn-default"
href=
"{% url 'assets:admin-user-update' pk=admin_user.id %}"
><i
class=
"fa fa-edit"
></i>
Update
</a>
</li>
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline btn-danger btn-delete-admin-user"
>
<i
class=
"fa fa-edit"
></i>
Delete
</a>
</li>
</ul>
</div>
<div
class=
"tab-content"
>
...
...
@@ -311,6 +316,38 @@ $(document).ready(function () {
op_html
:
$
(
'#actions'
).
html
()
};
jumpserver
.
initDataTable
(
options
);
function
adminUserDelete
(
name
,
url
)
{
function
doDelete
()
{
var
body
=
{};
var
success
=
function
()
{
swal
(
'Deleted!'
,
"[ "
+
name
+
"]"
+
" has been deleted "
,
"success"
);
window
.
location
.
href
=
"{% url 'assets:idc-list' %}"
;
};
var
fail
=
function
()
{
swal
(
"Failed"
,
"Delete"
+
"[ "
+
name
+
" ]"
+
"failed"
,
"error"
);
};
APIUpdateAttr
({
url
:
url
,
body
:
JSON
.
stringify
(
body
),
method
:
'DELETE'
,
success
:
success
,
error
:
fail
});
}
swal
({
title
:
'Are you sure delete ?'
,
text
:
" ["
+
name
+
"] "
,
type
:
"warning"
,
showCancelButton
:
true
,
cancelButtonText
:
'Cancel'
,
confirmButtonColor
:
"#DD6B55"
,
confirmButtonText
:
'Confirm'
,
closeOnConfirm
:
false
},
function
()
{
doDelete
()
});
}
})
.
on
(
'click'
,
'.btn-replace-asset-admin_user'
,
function
()
{
...
...
@@ -392,8 +429,14 @@ $(document).ready(function () {
var
data
=
{
"assets"
:
assets
};
objectRemove
(
$this
,
name
,
the_url
,
data
);
}
});
});
})
}).
on
(
'click'
,
'.btn-delete-admin-user'
,
function
()
{
var
$this
=
$
(
this
);
var
name
=
"{{ admin_user.name }}"
;
var
uid
=
"{{ admin_user.id }}"
;
var
the_url
=
'{% url "api-assets:admin-user-detail" pk=99991937 %}'
.
replace
(
'99991937'
,
uid
);
var
redirect_url
=
"{% url 'assets:admin-user-list' %}"
;
objectDelete
(
$this
,
name
,
the_url
,
redirect_url
);
})
</script>
{% endblock %}
\ No newline at end of file
apps/assets/templates/assets/asset_group_detail.html
View file @
0869931e
...
...
@@ -16,7 +16,6 @@
<div
class=
"panel-options"
>
<ul
class=
"nav nav-tabs"
>
<li
class=
"active"
><a
href=
""
class=
"text-center"
><i
class=
"fa fa-laptop"
></i>
{% trans 'Detail' %}
</a></li>
<li><a
href=
""
class=
"text-center"
><i
class=
"fa fa-bar-chart-o"
></i>
{% trans 'Asset group perm' %}
</a></li>
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline btn-default"
href=
"{% url 'assets:asset-group-update' pk=asset_group.id %}"
><i
class=
"fa fa-edit"
></i>
Update
</a>
</li>
...
...
apps/assets/templates/assets/idc_create_update.html
View file @
0869931e
...
...
@@ -38,12 +38,12 @@
{{ form.address|bootstrap_horizontal }}
{{ form.contact|bootstrap_horizontal }}
{{ form.phone|bootstrap_horizontal }}
<div
class=
"hr-line-dashed"
></div>
<h3
class=
"widget-head-color-box"
>
IP段
</h3>
{{ form.intranet|bootstrap_horizontal }}
{{ form.extranet|bootstrap_horizontal }}
<div
class=
"hr-line-dashed"
></div>
<div
class=
"form-group"
>
<div
class=
"col-sm-4 col-sm-offset-5"
>
...
...
apps/assets/templates/assets/idc_detail.html
View file @
0869931e
...
...
@@ -109,7 +109,6 @@
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
...
...
apps/assets/views.py
View file @
0869931e
...
...
@@ -412,35 +412,20 @@ class IDCDeleteView(AdminUserRequiredMixin, DeleteView):
class
AdminUserListView
(
AdminUserRequiredMixin
,
TemplateView
):
model
=
AdminUser
# paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
# context_object_name = 'admin_user_list'
template_name
=
'assets/admin_user_list.html'
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
_
(
'Assets'
),
'action'
:
_
(
'Admin user list'
),
# 'keyword': self.request.GET.get('keyword', '')
}
kwargs
.
update
(
context
)
return
super
(
AdminUserListView
,
self
)
.
get_context_data
(
**
kwargs
)
# def get_queryset(self):
# Todo: Default order by lose asset connection num
# self.queryset = super(AdminUserListView, self).get_queryset()
# self.keyword = keyword = self.request.GET.get('keyword', '')
# self.sort = sort = self.request.GET.get('sort', '-date_created')
#
# if keyword:
# self.queryset = self.queryset.filter(Q(name__icontains=keyword) |
# Q(comment__icontains=keyword))
#
# if sort:
# self.queryset = self.queryset.order_by(sort)
# return self.queryset
class
AdminUserCreateView
(
AdminUserRequiredMixin
,
SuccessMessageMixin
,
CreateView
):
class
AdminUserCreateView
(
AdminUserRequiredMixin
,
SuccessMessageMixin
,
CreateView
):
model
=
AdminUser
form_class
=
forms
.
AdminUserForm
template_name
=
'assets/admin_user_create_update.html'
...
...
@@ -455,11 +440,12 @@ class AdminUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVie
return
super
(
AdminUserCreateView
,
self
)
.
get_context_data
(
**
kwargs
)
def
get_success_message
(
self
,
cleaned_data
):
success_message
=
_
(
'Create admin user <a href="
%
s">
%
s</a> successfully.'
%
(
reverse_lazy
(
'assets:admin-user-detail'
,
kwargs
=
{
'pk'
:
self
.
object
.
pk
}),
self
.
object
.
name
,
))
success_message
=
_
(
'Create admin user <a href="
%
s">
%
s</a> successfully.'
%
(
reverse_lazy
(
'assets:admin-user-detail'
,
kwargs
=
{
'pk'
:
self
.
object
.
pk
}),
self
.
object
.
name
,
))
return
success_message
def
form_invalid
(
self
,
form
):
...
...
@@ -480,7 +466,8 @@ class AdminUserUpdateView(AdminUserRequiredMixin, UpdateView):
return
super
(
AdminUserUpdateView
,
self
)
.
get_context_data
(
**
kwargs
)
def
get_success_url
(
self
):
success_url
=
reverse_lazy
(
'assets:admin-user-detail'
,
pk
=
self
.
object
.
pk
)
success_url
=
reverse_lazy
(
'assets:admin-user-detail'
,
kwargs
=
{
'pk'
:
self
.
object
.
pk
})
return
success_url
...
...
@@ -787,7 +774,7 @@ class AssetExportView(View):
return
HttpResponse
(
'Json object not valid'
,
status
=
400
)
spm
=
uuid
.
uuid4
()
.
get_hex
()
cache
.
set
(
spm
,
assets_id
,
300
)
url
=
reverse
(
'assets:asset-export'
)
+
'?spm=
%
s'
%
spm
url
=
reverse
_lazy
(
'assets:asset-export'
)
+
'?spm=
%
s'
%
spm
return
JsonResponse
({
'redirect'
:
url
})
...
...
apps/audits/templates/audits/login_log_list.html
View file @
0869931e
...
...
@@ -84,6 +84,7 @@
$
(
document
).
ready
(
function
()
{
$
(
'table'
).
DataTable
({
"searching"
:
false
,
"bInfo"
:
false
,
"paging"
:
false
,
"order"
:
[]
});
...
...
apps/audits/templates/audits/proxy_log_list.html
View file @
0869931e
...
...
@@ -24,17 +24,17 @@
</div>
<div
class=
"input-group"
>
<select
class=
"select2 form-control"
name=
"username"
>
<option
value=
""
>
{% trans '
Select u
ser' %}
</option>
<option
value=
""
>
{% trans '
U
ser' %}
</option>
{% for user in user_list %}
<option
value=
"{{ user
.username }}"
{%
if
user
.
username =
=
username
%}
selected
{%
endif
%}
>
{{ user.username
}}
</option>
<option
value=
"{{ user
}}"
{%
if
user =
=
username
%}
selected
{%
endif
%}
>
{{ user
}}
</option>
{% endfor %}
</select>
</div>
<div
class=
"input-group"
>
<select
class=
"select2 form-control"
name=
"ip"
>
<option
value=
""
>
{% trans '
Select a
sset' %}
</option>
<option
value=
""
>
{% trans '
A
sset' %}
</option>
{% for asset in asset_list %}
<option
value=
"{{ asset
.ip }}"
{%
if
asset
.
ip =
=
ip
%}
selected
{%
endif
%}
>
{{ asset.ip
}}
</option>
<option
value=
"{{ asset
}}"
{%
if
asset =
=
ip
%}
selected
{%
endif
%}
>
{{ asset
}}
</option>
{% endfor %}
</select>
</div>
...
...
@@ -42,12 +42,12 @@
<select
class=
"select2 form-control"
name=
"system_user"
>
<option
value=
""
>
{% trans 'System user' %}
</option>
{% for su in system_user_list %}
<option
value=
"{{ su
.username }}"
{%
if
su
.
username =
=
system_user
%}
selected
{%
endif
%}
>
{{ su.username
}}
</option>
<option
value=
"{{ su
}}"
{%
if
su =
=
system_user
%}
selected
{%
endif
%}
>
{{ su
}}
</option>
{% endfor %}
</select>
</div>
<div
class=
"input-group"
>
<input
type=
"text"
class=
"form-control input-sm"
name=
"keyword"
placeholder=
"
Search
"
value=
"{{ keyword }}"
>
<input
type=
"text"
class=
"form-control input-sm"
name=
"keyword"
placeholder=
"
Command
"
value=
"{{ keyword }}"
>
</div>
<div
class=
"input-group"
>
<div
class=
"input-group-btn"
>
...
...
@@ -108,6 +108,7 @@
$
(
'table'
).
DataTable
({
"searching"
:
false
,
"paging"
:
false
,
"bInfo"
:
false
,
"order"
:
[]
});
$
(
'.select2'
).
select2
();
...
...
apps/audits/views.py
View file @
0869931e
...
...
@@ -18,6 +18,9 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
model
=
ProxyLog
template_name
=
'audits/proxy_log_list.html'
context_object_name
=
'proxy_log_list'
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
keyword
=
username
=
ip
=
system_user
=
date_from_s
=
date_to_s
=
''
def
get_queryset
(
self
):
date_now
=
timezone
.
localtime
(
timezone
.
now
())
...
...
@@ -46,20 +49,24 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
if
system_user
:
self
.
queryset
=
self
.
queryset
.
filter
(
system_user
=
system_user
)
if
keyword
:
self
.
queryset
=
self
.
queryset
.
filter
(
Q
(
username__contains
=
keyword
)
|
Q
(
name__icontains
=
keyword
)
|
Q
(
hostname__icontains
=
keyword
)
|
Q
(
ip__icontains
=
keyword
)
|
Q
(
system_user__icontains
=
keyword
))
.
distinct
()
self
.
queryset
=
self
.
queryset
.
filter
(
Q
(
username__contains
=
keyword
)
|
Q
(
name__icontains
=
keyword
)
|
Q
(
hostname__icontains
=
keyword
)
|
Q
(
ip__icontains
=
keyword
)
|
Q
(
system_user__icontains
=
keyword
))
.
distinct
()
return
self
.
queryset
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
_
(
'Audits'
),
'action'
:
_
(
'Proxy log list'
),
'user_list'
:
User
.
objects
.
all
()
.
order_by
(
'username'
),
'asset_list'
:
Asset
.
objects
.
all
()
.
order_by
(
'ip'
),
'system_user_list'
:
SystemUser
.
objects
.
all
()
.
order_by
(
'name'
),
'user_list'
:
set
(
list
(
ProxyLog
.
objects
.
values_list
(
'username'
,
flat
=
True
))),
'asset_list'
:
set
(
list
(
ProxyLog
.
objects
.
values_list
(
'ip'
,
flat
=
True
))),
'system_user_list'
:
set
(
list
(
ProxyLog
.
objects
.
values_list
(
'system_user'
,
flat
=
True
))),
'keyword'
:
self
.
keyword
,
'date_from'
:
self
.
date_from_s
,
'date_to'
:
self
.
date_to_s
,
...
...
@@ -71,9 +78,12 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
return
super
(
ProxyLogListView
,
self
)
.
get_context_data
(
**
kwargs
)
class
ProxyLogDetailView
(
AdminUserRequiredMixin
,
SingleObjectMixin
,
ListView
):
class
ProxyLogDetailView
(
AdminUserRequiredMixin
,
SingleObjectMixin
,
ListView
):
template_name
=
'audits/proxy_log_detail.html'
context_object_name
=
'proxy_log'
object
=
''
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
(
queryset
=
ProxyLog
.
objects
.
all
())
...
...
@@ -91,12 +101,16 @@ class ProxyLogDetailView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
return
super
(
ProxyLogDetailView
,
self
)
.
get_context_data
(
**
kwargs
)
class
ProxyLogCommandsListView
(
AdminUserRequiredMixin
,
SingleObjectMixin
,
ListView
):
class
ProxyLogCommandsListView
(
AdminUserRequiredMixin
,
SingleObjectMixin
,
ListView
):
template_name
=
'audits/proxy_log_commands_list_modal.html'
object
=
''
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
(
queryset
=
ProxyLog
.
objects
.
all
())
return
super
(
ProxyLogCommandsListView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
return
super
(
ProxyLogCommandsListView
,
self
)
.
\
get
(
request
,
*
args
,
**
kwargs
)
def
get_queryset
(
self
):
return
list
(
self
.
object
.
command_log
.
all
())
...
...
@@ -107,6 +121,7 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
template_name
=
'audits/command_log_list.html'
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
context_object_name
=
'command_list'
keyword
=
username
=
ip
=
system_user
=
date_from_s
=
date_to_s
=
''
def
get_queryset
(
self
):
date_now
=
timezone
.
localtime
(
timezone
.
now
())
...
...
@@ -114,29 +129,30 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
seven_days_ago_s
=
(
date_now
-
timezone
.
timedelta
(
7
))
.
strftime
(
'
%
m/
%
d/
%
Y'
)
self
.
queryset
=
super
(
CommandLogListView
,
self
)
.
get_queryset
()
self
.
keyword
=
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
self
.
sort
=
sort
=
self
.
request
.
GET
.
get
(
'sort'
,
'-datetime'
)
self
.
username
=
username
=
self
.
request
.
GET
.
get
(
'username'
,
''
)
self
.
ip
=
ip
=
self
.
request
.
GET
.
get
(
'ip'
,
''
)
self
.
system_user
=
system_user
=
self
.
request
.
GET
.
get
(
'system_user'
,
''
)
self
.
date_from_s
=
date_from_s
=
self
.
request
.
GET
.
get
(
'date_from'
,
'
%
s'
%
seven_days_ago_s
)
self
.
date_to_s
=
date_to_s
=
self
.
request
.
GET
.
get
(
'date_to'
,
'
%
s'
%
now_s
)
self
.
date_from_s
=
date_from_s
=
\
self
.
request
.
GET
.
get
(
'date_from'
,
'
%
s'
%
seven_days_ago_s
)
self
.
date_to_s
=
date_to_s
=
\
self
.
request
.
GET
.
get
(
'date_to'
,
'
%
s'
%
now_s
)
if
date_from_s
:
date_from
=
timezone
.
datetime
.
strptime
(
date_from_s
,
'
%
m/
%
d/
%
Y'
)
self
.
queryset
=
self
.
queryset
.
filter
(
datetime__gt
=
date_from
)
if
date_to_s
:
date_to
=
timezone
.
datetime
.
strptime
(
date_to_s
+
' 23:59:59'
,
'
%
m/
%
d/
%
Y
%
H:
%
M:
%
S'
)
date_to
=
timezone
.
datetime
.
strptime
(
date_to_s
+
' 23:59:59'
,
'
%
m/
%
d/
%
Y
%
H:
%
M:
%
S'
)
self
.
queryset
=
self
.
queryset
.
filter
(
datetime__lt
=
date_to
)
if
username
:
self
.
queryset
=
self
.
queryset
.
filter
(
proxy_log__username
=
username
)
if
ip
:
self
.
queryset
=
self
.
queryset
.
filter
(
proxy_log__ip
=
ip
)
if
system_user
:
self
.
queryset
=
self
.
queryset
.
filter
(
proxy_log__system_user
=
system_user
)
self
.
queryset
=
self
.
queryset
.
filter
(
proxy_log__system_user
=
system_user
)
if
keyword
:
self
.
queryset
=
self
.
queryset
.
filter
(
command
=
keyword
)
if
sort
:
self
.
queryset
=
self
.
queryset
.
order_by
(
sort
)
return
self
.
queryset
def
get_context_data
(
self
,
**
kwargs
):
...
...
@@ -159,31 +175,39 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
class
LoginLogListView
(
AdminUserRequiredMixin
,
ListView
):
model
=
LoginLog
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
template_name
=
'audits/login_log_list.html'
context_object_name
=
'login_log_list'
keyword
=
username
=
date_from_s
=
date_to_s
=
''
def
get_queryset
(
self
):
date_now
=
timezone
.
localtime
(
timezone
.
now
())
now_s
=
date_now
.
strftime
(
'
%
m/
%
d/
%
Y'
)
seven_days_ago_s
=
(
date_now
-
timezone
.
timedelta
(
7
))
.
strftime
(
'
%
m/
%
d/
%
Y'
)
seven_days_ago_s
=
(
date_now
-
timezone
.
timedelta
(
7
))
\
.
strftime
(
'
%
m/
%
d/
%
Y'
)
self
.
queryset
=
super
(
LoginLogListView
,
self
)
.
get_queryset
()
self
.
keyword
=
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
self
.
username
=
username
=
self
.
request
.
GET
.
get
(
'username'
,
''
)
self
.
date_from_s
=
date_from_s
=
self
.
request
.
GET
.
get
(
'date_from'
,
'
%
s'
%
seven_days_ago_s
)
self
.
date_to_s
=
date_to_s
=
self
.
request
.
GET
.
get
(
'date_to'
,
'
%
s'
%
now_s
)
self
.
date_from_s
=
date_from_s
=
self
.
request
.
GET
.
get
(
'date_from'
,
'
%
s'
%
seven_days_ago_s
)
self
.
date_to_s
=
date_to_s
=
self
.
request
.
GET
.
get
(
'date_to'
,
'
%
s'
%
now_s
)
if
date_from_s
:
date_from
=
timezone
.
datetime
.
strptime
(
date_from_s
,
'
%
m/
%
d/
%
Y'
)
self
.
queryset
=
self
.
queryset
.
filter
(
date_login__gt
=
date_from
)
if
date_to_s
:
date_to
=
timezone
.
datetime
.
strptime
(
date_to_s
+
' 23:59:59'
,
'
%
m/
%
d/
%
Y
%
H:
%
M:
%
S'
)
date_to
=
timezone
.
datetime
.
strptime
(
date_to_s
+
' 23:59:59'
,
'
%
m/
%
d/
%
Y
%
H:
%
M:
%
S'
)
self
.
queryset
=
self
.
queryset
.
filter
(
date_login__lt
=
date_to
)
if
username
:
self
.
queryset
=
self
.
queryset
.
filter
(
username
=
username
)
if
keyword
:
self
.
queryset
=
self
.
queryset
.
filter
(
Q
(
username__contains
=
keyword
)
|
Q
(
name__icontains
=
keyword
)
|
Q
(
login_ip
=
keyword
))
.
distinct
()
self
.
queryset
=
self
.
queryset
.
filter
(
Q
(
username__contains
=
keyword
)
|
Q
(
name__icontains
=
keyword
)
|
Q
(
login_ip
=
keyword
))
.
distinct
()
return
self
.
queryset
def
get_context_data
(
self
,
**
kwargs
):
...
...
apps/perms/forms.py
View file @
0869931e
...
...
@@ -26,16 +26,21 @@ class AssetPermissionForm(forms.ModelForm):
'system_users'
,
'is_active'
,
'date_expired'
,
'comment'
,
]
widgets
=
{
'users'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select users'
)}),
'user_groups'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select user groups'
)}),
'assets'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select assets'
)}),
'asset_groups'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select asset groups'
)}),
'system_users'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select system users'
)}),
'users'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select users'
)}),
'user_groups'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select user groups'
)}),
'assets'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select assets'
)}),
'asset_groups'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select asset groups'
)}),
'system_users'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select system users'
)}),
}
help_texts
=
{
'name'
:
'* required'
,
...
...
apps/perms/templates/perms/asset_permission_detail.html
View file @
0869931e
...
...
@@ -31,6 +31,11 @@
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline btn-default"
href=
"{% url 'perms:asset-permission-update' pk=asset_permission.id %}"
><i
class=
"fa fa-edit"
></i>
Update
</a>
</li>
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline btn-danger btn-delete-perm"
>
<i
class=
"fa fa-edit"
></i>
Delete
</a>
</li>
</ul>
</div>
<div
class=
"tab-content"
>
...
...
@@ -191,25 +196,15 @@
{% endblock %}
{% block custom_foot_js %}
<script>
{
#
function
switch_user_status
(
obj
)
{
#
}
{
#
var
status
=
$
(
obj
).
prop
(
'checked'
);
#
}
{
##
}
{
#
$
.
ajax
({
#
}
{
#
url
:
"{% url 'users:user-active-api' pk=user.id %}"
,
#
}
{
#
type
:
"PUT"
,
#
}
{
#
data
:
{
#
}
{
#
'is_active'
:
status
#
}
{
#
},
#
}
{
#
success
:
function
(
data
,
status
)
{
#
}
{
#
console
.
log
(
data
)
#
}
{
#
},
#
}
{
#
error
:
function
()
{
#
}
{
#
console
.
log
(
'error'
)
#
}
{
#
}
#
}
{
#
})
#
}
{
#
}
#
}
$
(
document
).
ready
(
function
()
{
$
(
'.select2'
).
select2
();
});
}).
on
(
'click'
,
'.btn-delete-perm'
,
function
()
{
var
$this
=
$
(
this
);
var
name
=
"{{ asset_permission.name }}"
;
var
uid
=
"{{ asset_permission.id }}"
;
var
the_url
=
'{% url "api-perms:asset-permission-detail" pk=99991937 %}'
.
replace
(
'99991937'
,
uid
);
var
redirect_url
=
"{% url 'perms:asset-permission-list' %}"
;
objectDelete
(
$this
,
name
,
the_url
,
redirect_url
);
})
</script>
{% endblock %}
\ No newline at end of file
apps/perms/templates/perms/asset_permission_list.html
View file @
0869931e
...
...
@@ -2,7 +2,9 @@
{% load i18n %}
{% load common_tags %}
{% block content_left_head %}
<a
href=
"{% url 'perms:asset-permission-create' %}"
class=
"btn btn-sm btn-primary "
>
{% trans "Create permission" %}
</a>
<a
href=
"{% url 'perms:asset-permission-create' %}"
class=
"btn btn-sm btn-primary"
>
{% trans "Create permission" %}
</a>
{% endblock %}
{% block table_head %}
...
...
@@ -39,8 +41,12 @@
{% endif %}
</td>
<td
class=
"text-center"
>
<a
href=
"{% url 'perms:asset-permission-update' pk=asset_permission.id %}"
class=
"btn btn-xs btn-info"
>
{% trans 'Update' %}
</a>
<a
href=
"{% url 'perms:asset-permission-delete' pk=asset_permission.id %}"
class=
"btn btn-xs btn-danger del"
>
{% trans 'Delete' %}
</a>
<a
href=
"{% url 'perms:asset-permission-update' pk=asset_permission.id %}"
class=
"btn btn-xs btn-info"
>
{% trans 'Update' %}
</a>
<a
class=
"btn btn-xs btn-danger btn-del"
data-name=
"{{ asset_permission.name }}"
data-uid=
"{{ asset_permission.id }}"
>
{% trans 'Delete' %}
</a>
</td>
</tr>
{% endfor %}
...
...
@@ -54,6 +60,13 @@
"paging"
:
false
,
"order"
:
[]
})
}).
on
(
'click'
,
'.btn-del'
,
function
()
{
var
$this
=
$
(
this
);
var
name
=
$this
.
data
(
'name'
);
var
uid
=
$this
.
data
(
'uid'
);
var
the_url
=
'{% url "api-perms:asset-permission-detail" pk=99991937 %}'
.
replace
(
'99991937'
,
uid
);
objectDelete
(
$this
,
name
,
the_url
);
})
</script>
{% endblock %}
apps/static/js/jumpserver.js
View file @
0869931e
...
...
@@ -213,12 +213,16 @@ function APIUpdateAttr(props) {
}
// Sweet Alert for Delete
function
objectDelete
(
obj
,
name
,
url
)
{
function
objectDelete
(
obj
,
name
,
url
,
redirectTo
)
{
function
doDelete
()
{
var
body
=
{};
var
success
=
function
()
{
swal
(
'Deleted!'
,
"[ "
+
name
+
"]"
+
" has been deleted "
,
"success"
);
$
(
obj
).
parent
().
parent
().
remove
();
if
(
!
redirectTo
)
{
$
(
obj
).
parent
().
parent
().
remove
();
}
else
{
window
.
location
.
href
=
redirectTo
;
}
};
var
fail
=
function
()
{
swal
(
"Failed"
,
"Delete"
+
"[ "
+
name
+
" ]"
+
"failed"
,
"error"
);
...
...
apps/templates/_pagination.html
View file @
0869931e
...
...
@@ -2,7 +2,7 @@
{% if is_paginated %}
<div
class=
"col-sm-4"
>
<div
class=
"dataTables_info text-center"
id=
"editable_info"
role=
"status"
aria-live=
"polite"
>
{{ page_obj.start_index }} - {{ page_obj.end_index }} of {{ paginator.count }}
显示第 {{ page_obj.start_index }} 至 {{ page_obj.end_index }} 项结果,共 {{ paginator.count }} 项
</div>
</div>
<div
class=
"col-sm-4"
>
...
...
apps/users/models/group.py
View file @
0869931e
...
...
@@ -33,8 +33,9 @@ class UserGroup(NoDeleteModelMixin, Group):
@classmethod
def
initial
(
cls
):
group
,
created
=
cls
.
objects
.
get_or_create
(
name
=
'Default'
,
comment
=
'Default user group for all user'
,
created_by
=
'System'
)
group
,
created
=
cls
.
objects
.
get_or_create
(
name
=
'Default'
,
created_by
=
'System'
,
comment
=
'Default user group for all user'
)
return
group
@classmethod
...
...
apps/users/templates/users/_user.html
View file @
0869931e
...
...
@@ -3,49 +3,54 @@
{% load static %}
{% load bootstrap %}
{% block form %}
<form
method=
"post"
class=
"form-horizontal"
action=
""
enctype=
"multipart/form-data"
>
{% csrf_token %}
<h3>
{% trans 'Account' %}
</h3>
{{ form.username|bootstrap_horizontal }}
{{ form.name|bootstrap_horizontal }}
{{ form.email|bootstrap_horizontal }}
{{ form.groups|bootstrap_horizontal }}
{% if form.non_field_errors %}
<div
class=
"alert alert-danger"
>
{{ form.non_field_errors }}
</div>
{% endif %}
<form
method=
"post"
class=
"form-horizontal"
action=
""
enctype=
"multipart/form-data"
>
{% csrf_token %}
<h3>
{% trans 'Account' %}
</h3>
{{ form.username|bootstrap_horizontal }}
{{ form.name|bootstrap_horizontal }}
{{ form.email|bootstrap_horizontal }}
{{ form.groups|bootstrap_horizontal }}
<div
class=
"hr-line-dashed"
></div>
{% block password %} {% endblock %}
<div
class=
"hr-line-dashed"
></div>
{% block password %} {% endblock %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Security and Role' %}
</h3>
{{ form.role|bootstrap_horizontal }}
<div
class=
"form-group {% if form.date_expired.errors %} has-error {% endif %}"
id=
"date_5"
>
<label
for=
"{{ form.date_expired.id_for_label }}"
class=
"col-sm-2 control-label"
>
{{ form.date_expired.label }}
</label>
<div
class=
"col-sm-9"
>
<div
class=
"input-group date"
>
<span
class=
"input-group-addon"
><i
class=
"fa fa-calendar"
></i></span>
<input
id=
"{{ form.date_expired.id_for_label }}"
name=
"{{ form.date_expired.html_name }}"
type=
"text"
class=
"form-control"
value=
"{{ form.date_expired.value|date:'Y-m-d' }}"
>
</div>
<span
class=
"help-block "
>
{{ form.date_expired.errors }}
</span>
</div>
</div>
<div
class=
"form-group"
>
<label
for=
"{{ form.enable_otp.id_for_label }}"
class=
"col-sm-2 control-label"
>
{% trans 'Enable OTP' %}
</label>
<div
class=
"col-sm-8"
>
{{ form.enable_otp }}
</div>
</div>
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Profile' %}
</h3>
{{ form.phone|bootstrap_horizontal }}
{{ form.wechat|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }}
<div
class=
"hr-line-dashed"
></div>
<div
class=
"form-group"
>
<div
class=
"col-sm-4 col-sm-offset-2"
>
<button
class=
"btn btn-white"
type=
"reset"
>
{% trans 'Reset' %}
</button>
<button
id=
"submit_button"
class=
"btn btn-primary"
type=
"submit"
>
{% trans 'Submit' %}
</button>
</div>
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Security and Role' %}
</h3>
{{ form.role|bootstrap_horizontal }}
<div
class=
"form-group {% if form.date_expired.errors %} has-error {% endif %}"
id=
"date_5"
>
<label
for=
"{{ form.date_expired.id_for_label }}"
class=
"col-sm-2 control-label"
>
{{ form.date_expired.label }}
</label>
<div
class=
"col-sm-9"
>
<div
class=
"input-group date"
>
<span
class=
"input-group-addon"
><i
class=
"fa fa-calendar"
></i></span>
<input
id=
"{{ form.date_expired.id_for_label }}"
name=
"{{ form.date_expired.html_name }}"
type=
"text"
class=
"form-control"
value=
"{{ form.date_expired.value|date:'Y-m-d' }}"
>
</div>
<span
class=
"help-block "
>
{{ form.date_expired.errors }}
</span>
</div>
</div>
</form>
<div
class=
"form-group"
>
<label
for=
"{{ form.enable_otp.id_for_label }}"
class=
"col-sm-2 control-label"
>
{% trans 'Enable OTP' %}
</label>
<div
class=
"col-sm-8"
>
{{ form.enable_otp }}
</div>
</div>
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Profile' %}
</h3>
{{ form.phone|bootstrap_horizontal }}
{{ form.wechat|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }}
<div
class=
"hr-line-dashed"
></div>
<div
class=
"form-group"
>
<div
class=
"col-sm-4 col-sm-offset-2"
>
<button
class=
"btn btn-white"
type=
"reset"
>
{% trans 'Reset' %}
</button>
<button
id=
"submit_button"
class=
"btn btn-primary"
type=
"submit"
>
{% trans 'Submit' %}
</button>
</div>
</div>
</form>
{% endblock %}
{% block custom_foot_js %}
<script
src=
"{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"
></script>
...
...
apps/users/templates/users/user_detail.html
View file @
0869931e
...
...
@@ -29,6 +29,11 @@
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline btn-default"
href=
"{% url 'users:user-update' pk=user.id %}"
><i
class=
"fa fa-edit"
></i>
Update
</a>
</li>
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline btn-danger btn-delete-user"
>
<i
class=
"fa fa-edit"
></i>
Delete
</a>
</li>
</ul>
</div>
<div
class=
"tab-content"
>
...
...
@@ -395,6 +400,13 @@ $(document).ready(function() {
);
};
APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success, error: fail});
});
}).on('click', '.btn-delete-user', function () {
var $this = $(this);
var name = "
{{
user
.
name
}}
";
var uid = "
{{
user
.
id
}}
";
var the_url = '{% url "
api
-
users
:
user
-
detail
" pk=99991937 %}'.replace('99991937', uid);
var redirect_url = "
{
%
url
'users:user-list'
%
}
";
objectDelete($this, name, the_url, redirect_url);
})
</script>
{% endblock %}
apps/users/templates/users/user_group_create_update.html
View file @
0869931e
...
...
@@ -16,6 +16,11 @@
<h5>
{{ action }}
</h5>
</div>
<div
class=
"ibox-content"
>
{% if form.non_field_errors %}
<div
class=
"alert alert-danger"
>
{{ form.non_field_errors }}
</div>
{% endif %}
<form
method=
"post"
class=
"form-horizontal"
action=
""
>
{% csrf_token %}
{{ form.name|bootstrap_horizontal }}
...
...
apps/users/templates/users/user_group_detail.html
View file @
0869931e
...
...
@@ -30,6 +30,11 @@
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline btn-default"
href=
"{% url 'users:user-group-update' pk=user_group.id %}"
><i
class=
"fa fa-edit"
></i>
Update
</a>
</li>
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline btn-danger btn-delete-user-group"
>
<i
class=
"fa fa-edit"
></i>
Delete
</a>
</li>
</ul>
</div>
<div
class=
"tab-content"
>
...
...
@@ -184,6 +189,13 @@ $(document).ready(function () {
});
console
.
log
(
users
);
updateGroupMember
(
users
)
}).
on
(
'click'
,
'.btn-delete-user-group'
,
function
()
{
var
$this
=
$
(
this
);
var
name
=
"{{ user_group.name }}"
;
var
uid
=
"{{ user_group.id }}"
;
var
the_url
=
'{% url "api-users:user-group-detail" pk=99991937 %}'
.
replace
(
'99991937'
,
uid
);
var
redirect_url
=
"{% url 'users:user-group-list' %}"
;
objectDelete
(
$this
,
name
,
the_url
,
redirect_url
);
})
</script>
{% endblock %}
apps/users/utils.py
View file @
0869931e
...
...
@@ -33,7 +33,7 @@ class AdminUserRequiredMixin(UserPassesTestMixin):
login_url
=
reverse_lazy
(
'users:login'
)
def
test_func
(
self
):
return
self
.
request
.
user
.
is_s
taff
return
self
.
request
.
user
.
is_s
uperuser
def
user_add_success_next
(
user
):
...
...
@@ -122,61 +122,6 @@ def send_reset_ssh_key_mail(user):
send_mail_async
.
delay
(
subject
,
message
,
recipient_list
,
html_message
=
message
)
# def validate_ssh_pk(text):
# """
# Expects a SSH private key as string.
# Returns a boolean and a error message.
# If the text is parsed as private key successfully,
# (True,'') is returned. Otherwise,
# (False, <message describing the error>) is returned.
#
# from https://github.com/githubnemo/SSH-private-key-validator/blob/master/validate.py
#
# """
#
# if not text:
# return False, 'No text given'
#
# startPattern = re.compile("^-----BEGIN [A-Z]+ PRIVATE KEY-----")
# optionPattern = re.compile("^.+: .+")
# contentPattern = re.compile("^([a-zA-Z0-9+/]{64}|[a-zA-Z0-9+/]{1,64}[=]{0,2})$")
# endPattern = re.compile("^-----END [A-Z]+ PRIVATE KEY-----")
#
# def contentState(text):
# for i in range(0, len(text)):
# line = text[i]
#
# if endPattern.match(line):
# if i == len(text) - 1 or len(text[i + 1]) == 0:
# return True, ''
# else:
# return False, 'At end but content coming'
#
# elif not contentPattern.match(line):
# return False, 'Wrong string in content section'
#
# return False, 'No content or missing end line'
#
# def optionState(text):
# for i in range(0, len(text)):
# line = text[i]
#
# if line[-1:] == '\\':
# return optionState(text[i + 2:])
#
# if not optionPattern.match(line):
# return contentState(text[i + 1:])
#
# return False, 'Expected option, found nothing'
# def startState(text):
# if len(text) == 0 or not startPattern.match(text[0]):
# return False, 'Header is wrong'
# return optionState(text[1:])
#
# return startState([n.strip() for n in text.splitlines()])
#
def
check_user_valid
(
**
kwargs
):
password
=
kwargs
.
pop
(
'password'
,
None
)
public_key
=
kwargs
.
pop
(
'public_key'
,
None
)
...
...
apps/users/views/user.py
View file @
0869931e
...
...
@@ -118,13 +118,14 @@ class UserDetailView(AdminUserRequiredMixin, DetailView):
@method_decorator
(
csrf_exempt
,
name
=
'dispatch'
)
class
UserExportView
(
View
):
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
def
get
(
self
,
request
):
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
=
User
.
objects
.
filter
(
id__in
=
users_id
)
print
(
users
)
wb
=
Workbook
()
ws
=
wb
.
active
ws
.
title
=
'User'
...
...
@@ -133,9 +134,12 @@ class UserExportView(View):
ws
.
append
(
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
])
print
(
user
.
name
)
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
,
])
filename
=
'users-{}.xlsx'
.
format
(
timezone
.
localtime
(
timezone
.
now
())
.
strftime
(
'
%
Y-
%
m-
%
d_
%
H-
%
M-
%
S'
))
...
...
@@ -144,7 +148,7 @@ class UserExportView(View):
response
[
'Content-Disposition'
]
=
'attachment; filename="
%
s"'
%
filename
return
response
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
def
post
(
self
,
request
):
try
:
users_id
=
json
.
loads
(
request
.
body
)
.
get
(
'users_id'
,
[])
except
ValueError
:
...
...
@@ -180,11 +184,13 @@ class UserBulkImportView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
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
=
[
col
.
value
for
col
in
next
(
rows
)]
print
(
header
)
if
header
!=
header_need
:
data
=
{
'valid'
:
False
,
'msg'
:
'Must be same format as template or export file'
}
data
=
{
'valid'
:
False
,
'msg'
:
'Must be same format as '
'template or export file'
}
return
self
.
render_json_response
(
data
)
created
=
[]
...
...
config_example.py
View file @
0869931e
...
...
@@ -18,8 +18,8 @@ class Config:
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY
=
os
.
environ
.
get
(
'SECRET_KEY'
)
or
'2vym+ky!997d5kkcc64mnz06y1mmui3lut#(^wd=
%
s_qj$1
%
x'
# How many line display every page, default 2
0
DISPLAY_PER_PAGE
=
2
0
# How many line display every page, default 2
5
DISPLAY_PER_PAGE
=
2
5
# It's used to identify your site, When we send a create mail to user, we only know login url is /login/
# But we should know the absolute url like: http://jms.jumpserver.org/login/, so SITE_URL is
...
...
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