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
948214ca
Commit
948214ca
authored
Jan 20, 2017
by
ibuler
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'audits'
parents
09794801
df94d11f
Hide whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
895 additions
and
645 deletions
+895
-645
api.py
apps/applications/api.py
+12
-9
serializers.py
apps/applications/serializers.py
+4
-2
forms.py
apps/assets/forms.py
+25
-30
serializers.py
apps/assets/serializers.py
+9
-3
system_user_create_update.html
apps/assets/templates/assets/system_user_create_update.html
+49
-21
views.py
apps/assets/views.py
+4
-0
api.py
apps/audits/api.py
+1
-11
models.py
apps/audits/models.py
+10
-5
serializers.py
apps/audits/serializers.py
+4
-2
command_log_list.html
apps/audits/templates/audits/command_log_list.html
+1
-1
proxy_log_detail.html
apps/audits/templates/audits/proxy_log_detail.html
+1
-25
views.py
apps/audits/views.py
+12
-7
celery.py
apps/common/celery.py
+2
-1
api.py
apps/perms/api.py
+46
-15
serializers.py
apps/perms/serializers.py
+1
-1
api_urls.py
apps/perms/urls/api_urls.py
+34
-14
utils.py
apps/perms/utils.py
+8
-1
views.py
apps/perms/views.py
+55
-35
api.py
apps/users/api.py
+17
-14
authentication.py
apps/users/authentication.py
+44
-13
authentication.py
apps/users/models/authentication.py
+2
-1
api_urls.py
apps/users/urls/api_urls.py
+6
-3
views_urls.py
apps/users/urls/views_urls.py
+55
-22
__init__.py
apps/users/views/__init__.py
+5
-0
group.py
apps/users/views/group.py
+169
-0
login.py
apps/users/views/login.py
+202
-0
user.py
apps/users/views/user.py
+117
-409
No files found.
apps/applications/api.py
View file @
948214ca
...
@@ -23,17 +23,20 @@ class TerminalRegisterView(ListCreateAPIView):
...
@@ -23,17 +23,20 @@ class TerminalRegisterView(ListCreateAPIView):
def
create
(
self
,
request
,
*
args
,
**
kwargs
):
def
create
(
self
,
request
,
*
args
,
**
kwargs
):
name
=
request
.
data
.
get
(
'name'
,
''
)
name
=
request
.
data
.
get
(
'name'
,
''
)
remote_addr
=
request
.
META
.
get
(
'X-Real-IP'
)
or
request
.
META
.
get
(
'REMOTE_ADDR'
)
remote_addr
=
request
.
META
.
get
(
'X-Real-IP'
)
or
\
serializer
=
self
.
serializer_class
(
data
=
{
'name'
:
name
,
'remote_addr'
:
remote_addr
})
request
.
META
.
get
(
'REMOTE_ADDR'
)
serializer
=
self
.
serializer_class
(
data
=
{
'name'
:
name
,
'remote_addr'
:
remote_addr
})
if
get_object_or_none
(
Terminal
,
name
=
name
):
if
get_object_or_none
(
Terminal
,
name
=
name
):
return
Response
({
'msg'
:
'Already register, Need administrator active it'
},
status
=
200
)
return
Response
({
'msg'
:
'Already register, Need '
'administrator active it'
},
status
=
200
)
if
serializer
.
is_valid
():
if
serializer
.
is_valid
():
terminal
=
serializer
.
save
()
terminal
=
serializer
.
save
()
app_user
,
access_key
=
terminal
.
create_related_app_user
()
app_user
,
access_key
=
terminal
.
create_related_app_user
()
data
=
{}
data
=
{}
data
[
'
applications
'
]
=
copy
.
deepcopy
(
serializer
.
data
)
data
[
'
terminal
'
]
=
copy
.
deepcopy
(
serializer
.
data
)
data
[
'user'
]
=
app_user
.
to_json
()
data
[
'user'
]
=
app_user
.
to_json
()
data
[
'access_key_id'
]
=
access_key
.
id
data
[
'access_key_id'
]
=
access_key
.
id
data
[
'access_key_secret'
]
=
access_key
.
secret
data
[
'access_key_secret'
]
=
access_key
.
secret
...
@@ -54,11 +57,11 @@ class TerminalViewSet(viewsets.ModelViewSet):
...
@@ -54,11 +57,11 @@ class TerminalViewSet(viewsets.ModelViewSet):
def
create
(
self
,
request
,
*
args
,
**
kwargs
):
def
create
(
self
,
request
,
*
args
,
**
kwargs
):
return
Response
({
'msg'
:
'Use register view except that'
},
status
=
404
)
return
Response
({
'msg'
:
'Use register view except that'
},
status
=
404
)
def
destroy
(
self
,
request
,
*
args
,
**
kwargs
):
#
def destroy(self, request, *args, **kwargs):
instance
=
self
.
get_object
()
#
instance = self.get_object()
if
instance
.
user
is
not
None
:
#
if instance.user is not None:
instance
.
user
.
delete
()
#
instance.user.delete()
return
super
(
TerminalViewSet
,
self
)
.
destroy
(
request
,
*
args
,
**
kwargs
)
#
return super(TerminalViewSet, self).destroy(request, *args, **kwargs)
class
TerminalHeatbeatViewSet
(
viewsets
.
ModelViewSet
):
class
TerminalHeatbeatViewSet
(
viewsets
.
ModelViewSet
):
...
...
apps/applications/serializers.py
View file @
948214ca
...
@@ -14,8 +14,9 @@ class TerminalSerializer(serializers.ModelSerializer):
...
@@ -14,8 +14,9 @@ class TerminalSerializer(serializers.ModelSerializer):
class
Meta
:
class
Meta
:
model
=
Terminal
model
=
Terminal
fields
=
[
'id'
,
'name'
,
'remote_addr'
,
'type'
,
'url'
,
'comment'
,
'is_accepted'
,
fields
=
[
'id'
,
'name'
,
'remote_addr'
,
'type'
,
'url'
,
'comment'
,
'is_active'
,
'get_type_display'
,
'proxy_online'
,
'is_alive'
]
'is_accepted'
,
'is_active'
,
'get_type_display'
,
'proxy_online'
,
'is_alive'
]
@staticmethod
@staticmethod
def
get_proxy_online
(
obj
):
def
get_proxy_online
(
obj
):
...
@@ -31,6 +32,7 @@ class TerminalSerializer(serializers.ModelSerializer):
...
@@ -31,6 +32,7 @@ class TerminalSerializer(serializers.ModelSerializer):
class
TerminalHeatbeatSerializer
(
serializers
.
ModelSerializer
):
class
TerminalHeatbeatSerializer
(
serializers
.
ModelSerializer
):
date_start
=
serializers
.
DateTimeField
class
Meta
:
class
Meta
:
model
=
TerminalHeatbeat
model
=
TerminalHeatbeat
...
...
apps/assets/forms.py
View file @
948214ca
...
@@ -214,23 +214,9 @@ class AdminUserForm(forms.ModelForm):
...
@@ -214,23 +214,9 @@ class AdminUserForm(forms.ModelForm):
class
SystemUserForm
(
forms
.
ModelForm
):
class
SystemUserForm
(
forms
.
ModelForm
):
# Admin user assets define, let user select, save it in form not in view
# Admin user assets define, let user select, save it in form not in view
assets
=
forms
.
ModelMultipleChoiceField
(
queryset
=
Asset
.
objects
.
all
(),
auto_generate_key
=
forms
.
BooleanField
(
initial
=
True
,
required
=
False
)
label
=
_
(
'Asset'
),
required
=
False
,
widget
=
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select assets'
)})
)
asset_groups
=
forms
.
ModelMultipleChoiceField
(
queryset
=
AssetGroup
.
objects
.
all
(),
label
=
_
(
'Asset group'
),
required
=
False
,
widget
=
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select asset groups'
)})
)
auto_generate_key
=
forms
.
BooleanField
(
initial
=
True
)
# Form field name can not start with `_`, so redefine it,
# Form field name can not start with `_`, so redefine it,
password
=
forms
.
CharField
(
widget
=
forms
.
PasswordInput
,
max_length
=
100
,
min_length
=
8
,
strip
=
True
,
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
)
# Need use upload private key file except paste private key content
# Need use upload private key file except paste private key content
private_key_file
=
forms
.
FileField
(
required
=
False
)
private_key_file
=
forms
.
FileField
(
required
=
False
)
...
@@ -242,24 +228,15 @@ class SystemUserForm(forms.ModelForm):
...
@@ -242,24 +228,15 @@ class SystemUserForm(forms.ModelForm):
initial
[
'asset_groups'
]
=
kwargs
[
'instance'
]
.
asset_groups
.
all
()
initial
[
'asset_groups'
]
=
kwargs
[
'instance'
]
.
asset_groups
.
all
()
super
(
SystemUserForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
super
(
SystemUserForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
_save_m2m
(
self
):
# Save assets relation with admin user
super
(
SystemUserForm
,
self
)
.
_save_m2m
()
assets
=
self
.
cleaned_data
[
'assets'
]
asset_groups
=
self
.
cleaned_data
[
'asset_groups'
]
self
.
instance
.
assets
.
clear
()
self
.
instance
.
assets
.
add
(
*
tuple
(
assets
))
self
.
instance
.
asset_groups
.
clear
()
self
.
instance
.
asset_groups
.
add
(
*
tuple
(
asset_groups
))
def
save
(
self
,
commit
=
True
):
def
save
(
self
,
commit
=
True
):
# Because we define custom field, so we need rewrite :method: `save`
# Because we define custom field, so we need rewrite :method: `save`
system_user
=
super
(
SystemUserForm
,
self
)
.
save
(
commit
=
commit
)
system_user
=
super
(
SystemUserForm
,
self
)
.
save
(
commit
=
commit
)
password
=
self
.
cleaned_data
[
'password'
]
password
=
self
.
cleaned_data
[
'password'
]
private_key_file
=
self
.
cleaned_data
[
'private_key_file'
]
private_key_file
=
self
.
cleaned_data
[
'private_key_file'
]
if
password
:
if
system_user
.
auth_method
==
'P'
:
system_user
.
password
=
password
if
password
:
system_user
.
password
=
password
print
(
password
)
print
(
password
)
# Todo: Validate private key file, and generate public key
# Todo: Validate private key file, and generate public key
# Todo: Auto generate private key and public key
# Todo: Auto generate private key and public key
...
@@ -268,11 +245,30 @@ class SystemUserForm(forms.ModelForm):
...
@@ -268,11 +245,30 @@ class SystemUserForm(forms.ModelForm):
system_user
.
save
()
system_user
.
save
()
return
self
.
instance
return
self
.
instance
# Todo: check valid
# def clean_private_key_file(self):
# if not self.cleaned_data['auto_generate_key']:
# if not self.cleaned_data['private_key_file']:
# raise forms.ValidationError(_('Private key required'))
# def clean_password(self):
# if self.cleaned_data['auth_method'] == 'P':
# if not self.cleaned_data['password']:
# raise forms.ValidationError(_('Password required'))
# return self.cleaned_data['password']
# def clean(self):
# 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'))
class
Meta
:
class
Meta
:
model
=
SystemUser
model
=
SystemUser
fields
=
[
fields
=
[
'name'
,
'username'
,
'protocol'
,
'auto_generate_key'
,
'password'
,
'private_key_file'
,
'auth_method'
,
'name'
,
'username'
,
'protocol'
,
'auto_generate_key'
,
'password'
,
'private_key_file'
,
'auth_method'
,
'auto_push'
,
'
auto_update'
,
'
sudo'
,
'comment'
,
'shell'
,
'home'
,
'uid'
,
'auto_push'
,
'sudo'
,
'comment'
,
'shell'
,
'home'
,
'uid'
,
]
]
widgets
=
{
widgets
=
{
'name'
:
forms
.
TextInput
(
attrs
=
{
'placeholder'
:
_
(
'Name'
)}),
'name'
:
forms
.
TextInput
(
attrs
=
{
'placeholder'
:
_
(
'Name'
)}),
...
@@ -282,7 +278,6 @@ class SystemUserForm(forms.ModelForm):
...
@@ -282,7 +278,6 @@ class SystemUserForm(forms.ModelForm):
'name'
:
'* required'
,
'name'
:
'* required'
,
'username'
:
'* required'
,
'username'
:
'* required'
,
'auto_push'
:
'Auto push system user to asset'
,
'auto_push'
:
'Auto push system user to asset'
,
'auto_update'
:
'Auto update system user ssh key'
,
}
}
...
...
apps/assets/serializers.py
View file @
948214ca
...
@@ -99,6 +99,12 @@ class SystemUserSerializer(serializers.ModelSerializer):
...
@@ -99,6 +99,12 @@ class SystemUserSerializer(serializers.ModelSerializer):
return
fields
return
fields
class
AssetSystemUserSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
SystemUser
fields
=
(
'id'
,
'name'
,
'username'
,
'protocol'
,
'auth_method'
,
'comment'
)
class
SystemUserUpdateAssetsSerializer
(
serializers
.
ModelSerializer
):
class
SystemUserUpdateAssetsSerializer
(
serializers
.
ModelSerializer
):
assets
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
queryset
=
Asset
.
objects
.
all
())
assets
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
queryset
=
Asset
.
objects
.
all
())
...
@@ -145,13 +151,13 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
...
@@ -145,13 +151,13 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
class
AssetGrantedSerializer
(
serializers
.
ModelSerializer
):
class
AssetGrantedSerializer
(
serializers
.
ModelSerializer
):
system_users
=
SystemUserSerializer
(
many
=
True
,
read_only
=
True
)
system_users
_granted
=
Asset
SystemUserSerializer
(
many
=
True
,
read_only
=
True
)
is_inherited
=
serializers
.
SerializerMethodField
()
is_inherited
=
serializers
.
SerializerMethodField
()
system_users_join
=
serializers
.
SerializerMethodField
()
system_users_join
=
serializers
.
SerializerMethodField
()
class
Meta
(
object
):
class
Meta
(
object
):
model
=
Asset
model
=
Asset
fields
=
(
"id"
,
"hostname"
,
"ip"
,
"port"
,
"system_users"
,
"is_inherited"
,
fields
=
(
"id"
,
"hostname"
,
"ip"
,
"port"
,
"system_users
_granted
"
,
"is_inherited"
,
"is_active"
,
"system_users_join"
,
"comment"
)
"is_active"
,
"system_users_join"
,
"comment"
)
@staticmethod
@staticmethod
...
@@ -163,7 +169,7 @@ class AssetGrantedSerializer(serializers.ModelSerializer):
...
@@ -163,7 +169,7 @@ class AssetGrantedSerializer(serializers.ModelSerializer):
@staticmethod
@staticmethod
def
get_system_users_join
(
obj
):
def
get_system_users_join
(
obj
):
return
', '
.
join
([
system_user
.
username
for
system_user
in
obj
.
system_users
.
all
()
])
return
', '
.
join
([
system_user
.
username
for
system_user
in
obj
.
system_users
_granted
])
class
IDCSerializer
(
BulkSerializerMixin
,
serializers
.
ModelSerializer
):
class
IDCSerializer
(
BulkSerializerMixin
,
serializers
.
ModelSerializer
):
...
...
apps/assets/templates/assets/system_user_create_update.html
View file @
948214ca
...
@@ -27,23 +27,31 @@
...
@@ -27,23 +27,31 @@
</div>
</div>
</div>
</div>
<div
class=
"ibox-content"
>
<div
class=
"ibox-content"
>
{% if form.no_field_errors %}
<div
class=
"alert alert-danger"
>
{{ form.non_field_errors }}
</div>
{% endif %}
<form
enctype=
"multipart/form-data"
method=
"post"
class=
"form-horizontal"
action=
""
>
<form
enctype=
"multipart/form-data"
method=
"post"
class=
"form-horizontal"
action=
""
>
{% csrf_token %}
{% csrf_token %}
<h3>
{% trans 'Basic' %}
</h3>
{{ form.name|bootstrap_horizontal }}
{{ form.name|bootstrap_horizontal }}
{{ form.username|bootstrap_horizontal }}
{{ form.username|bootstrap_horizontal }}
{{ form.protocol|bootstrap_horizontal }}
{{ form.protocol|bootstrap_horizontal }}
<div
class=
"form-group"
>
<h3>
{% trans 'Auth' %}
</h3>
<label
for=
"{{ form.auto_generate_key.id_for_label }}"
class=
"col-sm-2 control-label"
>
{% trans 'Auto generate key' %}
</label>
{{ form.auth_method|bootstrap_horizontal }}
<div
class=
"col-sm-8"
>
<div
class=
"password-auth hidden"
>
{{ form.auto_generate_key}}
{{ form.password|bootstrap_horizontal }}
</div>
</div>
</div>
{{ form.password|bootstrap_horizontal }}
<div
class=
"public-key-auth"
>
{{ form.private_key_file|bootstrap_horizontal }}
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<label
for=
"{{ form.auto_generate_key.id_for_label }}"
class=
"col-sm-2 control-label"
>
{% trans 'Auto generate key' %}
</label>
<label
for=
"{{ form.as_default.id_for_label }}"
class=
"col-sm-2 control-label"
>
{% trans 'As default' %}
</label>
<div
class=
"col-sm-8"
>
<div
class=
"col-sm-8"
>
{{ form.auto_generate_key}}
{{ form.as_default}}
</div>
</div>
<div>
{{ form.private_key_file|bootstrap_horizontal }}
</div>
</div>
</div>
</div>
<div
class=
"form-group"
>
<div
class=
"form-group"
>
...
@@ -52,20 +60,12 @@
...
@@ -52,20 +60,12 @@
{{ form.auto_push}}
{{ form.auto_push}}
</div>
</div>
</div>
</div>
<div
class=
"form-group"
>
<h3>
{% trans 'Other' %}
</h3>
<label
for=
"{{ form.as_update.id_for_label }}"
class=
"col-sm-2 control-label"
>
{% trans 'Auto update' %}
</label>
<div
class=
"col-sm-8"
>
{{ form.auto_update}}
</div>
</div>
{{ form.assets|bootstrap_horizontal }}
{{ form.asset_groups|bootstrap_horizontal }}
{{ form.sudo|bootstrap_horizontal }}
{{ form.sudo|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }}
{{ form.home|bootstrap_horizontal }}
{{ form.home|bootstrap_horizontal }}
{{ form.shell|bootstrap_horizontal }}
{{ form.shell|bootstrap_horizontal }}
{{ form.uid|bootstrap_horizontal }}
{{ form.uid|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }}
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<div
class=
"col-sm-4 col-sm-offset-2"
>
<div
class=
"col-sm-4 col-sm-offset-2"
>
<button
class=
"btn btn-white"
type=
"reset"
>
{% trans 'Reset' %}
</button>
<button
class=
"btn btn-white"
type=
"reset"
>
{% trans 'Reset' %}
</button>
...
@@ -81,8 +81,36 @@
...
@@ -81,8 +81,36 @@
{% endblock %}
{% endblock %}
{% block custom_foot_js %}
{% block custom_foot_js %}
<script>
<script>
var
auth_method
=
'#'
+
'{{ form.auth_method.id_for_label }}'
;
var
auto_generate_key
=
'#'
+
'{{ form.auto_generate_key.id_for_label }}'
;
function
authMethodDisplay
()
{
if
(
$
(
auth_method
).
val
()
==
'P'
)
{
$
(
'.password-auth'
).
removeClass
(
'hidden'
);
$
(
'.public-key-auth'
).
addClass
(
'hidden'
);
$
(
'#'
+
'{{ form.password.id_for_label }}'
).
attr
(
'required'
,
'required'
);
}
else
if
(
$
(
auth_method
).
val
()
==
'K'
)
{
$
(
'.password-auth'
).
addClass
(
'hidden'
);
$
(
'.public-key-auth'
).
removeClass
(
'hidden'
);
if
(
$
(
auto_generate_key
).
prop
(
'checked'
)){
$
(
'#'
+
'{{ form.private_key_file.id_for_label }}'
).
closest
(
'.form-group'
).
addClass
(
'hidden'
);
}
else
{
$
(
'#'
+
'{{ form.private_key_file.id_for_label }}'
).
closest
(
'.form-group'
).
removeClass
(
'hidden'
);
{
#
$
(
'#'
+
'{{ form.private_key_file.id_for_label }}'
).
attr
(
'required'
,
'required'
);
#
}
}
}
}
$
(
document
).
ready
(
function
()
{
$
(
document
).
ready
(
function
()
{
$
(
'.select2'
).
select2
();
$
(
'.select2'
).
select2
();
authMethodDisplay
();
$
(
auth_method
).
change
(
function
()
{
authMethodDisplay
();
});
$
(
auto_generate_key
).
change
(
function
()
{
authMethodDisplay
();
});
if
(
$
(
'#'
+
'{{ form.protocol.id_for_label }}'
).
val
()
==
'telnet'
)
{
if
(
$
(
'#'
+
'{{ form.protocol.id_for_label }}'
).
val
()
==
'telnet'
)
{
$
(
'#'
+
'{{ form.auto_generate_key.id_for_label }}'
).
closest
(
'.form-group'
).
remove
();
$
(
'#'
+
'{{ form.auto_generate_key.id_for_label }}'
).
closest
(
'.form-group'
).
remove
();
...
...
apps/assets/views.py
View file @
948214ca
...
@@ -547,6 +547,10 @@ class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVi
...
@@ -547,6 +547,10 @@ class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVi
kwargs
.
update
(
context
)
kwargs
.
update
(
context
)
return
super
(
SystemUserCreateView
,
self
)
.
get_context_data
(
**
kwargs
)
return
super
(
SystemUserCreateView
,
self
)
.
get_context_data
(
**
kwargs
)
def
form_invalid
(
self
,
form
):
print
(
form
.
errors
)
return
super
(
SystemUserCreateView
,
self
)
.
form_invalid
(
form
)
def
get_success_message
(
self
,
cleaned_data
):
def
get_success_message
(
self
,
cleaned_data
):
success_message
=
_
(
'Create system user <a href="
%
s">
%
s</a> successfully.'
%
success_message
=
_
(
'Create system user <a href="
%
s">
%
s</a> successfully.'
%
(
(
...
...
apps/audits/api.py
View file @
948214ca
...
@@ -6,6 +6,7 @@ from __future__ import absolute_import, unicode_literals
...
@@ -6,6 +6,7 @@ from __future__ import absolute_import, unicode_literals
from
rest_framework
import
generics
,
viewsets
from
rest_framework
import
generics
,
viewsets
from
rest_framework.views
import
APIView
,
Response
from
rest_framework.views
import
APIView
,
Response
from
rest_framework_bulk
import
BulkModelViewSet
from
.
import
models
,
serializers
from
.
import
models
,
serializers
from
.hands
import
IsSuperUserOrAppUser
,
Terminal
,
IsAppUser
from
.hands
import
IsSuperUserOrAppUser
,
Terminal
,
IsAppUser
...
@@ -51,13 +52,3 @@ class CommandLogViewSet(viewsets.ModelViewSet):
...
@@ -51,13 +52,3 @@ class CommandLogViewSet(viewsets.ModelViewSet):
serializer_class
=
serializers
.
CommandLogSerializer
serializer_class
=
serializers
.
CommandLogSerializer
permission_classes
=
(
IsSuperUserOrAppUser
,)
permission_classes
=
(
IsSuperUserOrAppUser
,)
# class CommandLogTitleApi(APIView):
# def get(self, request):
# response = [
# {"name": "command_no", "title": "ID", "type": "number"},
# {"name": "command", "title": "Title", "visible": True, "filterable": True},
# {"name": "datetime", "title": "Datetime", "type"},
# {"name": "output", "title": "Output", "filterable": True},
# ]
#
\ No newline at end of file
apps/audits/models.py
View file @
948214ca
...
@@ -17,10 +17,13 @@ class LoginLog(models.Model):
...
@@ -17,10 +17,13 @@ class LoginLog(models.Model):
username
=
models
.
CharField
(
max_length
=
20
,
verbose_name
=
_
(
'Username'
))
username
=
models
.
CharField
(
max_length
=
20
,
verbose_name
=
_
(
'Username'
))
name
=
models
.
CharField
(
max_length
=
20
,
blank
=
True
,
verbose_name
=
_
(
'Name'
))
name
=
models
.
CharField
(
max_length
=
20
,
blank
=
True
,
verbose_name
=
_
(
'Name'
))
login_type
=
models
.
CharField
(
choices
=
LOGIN_TYPE_CHOICE
,
max_length
=
2
,
verbose_name
=
_
(
'Login type'
))
login_type
=
models
.
CharField
(
choices
=
LOGIN_TYPE_CHOICE
,
max_length
=
2
,
verbose_name
=
_
(
'Login type'
))
login_ip
=
models
.
GenericIPAddressField
(
verbose_name
=
_
(
'Login ip'
))
login_ip
=
models
.
GenericIPAddressField
(
verbose_name
=
_
(
'Login ip'
))
login_city
=
models
.
CharField
(
max_length
=
100
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Login city'
))
login_city
=
models
.
CharField
(
max_length
=
100
,
blank
=
True
,
null
=
True
,
user_agent
=
models
.
CharField
(
max_length
=
100
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'User agent'
))
verbose_name
=
_
(
'Login city'
))
user_agent
=
models
.
CharField
(
max_length
=
100
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'User agent'
))
date_login
=
models
.
DateTimeField
(
auto_now_add
=
True
,
verbose_name
=
_
(
'Date login'
))
date_login
=
models
.
DateTimeField
(
auto_now_add
=
True
,
verbose_name
=
_
(
'Date login'
))
class
Meta
:
class
Meta
:
...
@@ -66,7 +69,8 @@ class ProxyLog(models.Model):
...
@@ -66,7 +69,8 @@ class ProxyLog(models.Model):
class
CommandLog
(
models
.
Model
):
class
CommandLog
(
models
.
Model
):
proxy_log
=
models
.
ForeignKey
(
ProxyLog
,
on_delete
=
models
.
CASCADE
,
related_name
=
'commands'
)
proxy_log
=
models
.
ForeignKey
(
ProxyLog
,
on_delete
=
models
.
CASCADE
,
related_name
=
'commands'
)
command_no
=
models
.
IntegerField
()
command_no
=
models
.
IntegerField
()
command
=
models
.
CharField
(
max_length
=
1000
,
blank
=
True
)
command
=
models
.
CharField
(
max_length
=
1000
,
blank
=
True
)
output
=
models
.
TextField
(
blank
=
True
)
output
=
models
.
TextField
(
blank
=
True
)
...
@@ -78,7 +82,8 @@ class CommandLog(models.Model):
...
@@ -78,7 +82,8 @@ class CommandLog(models.Model):
@property
@property
def
output_decode
(
self
):
def
output_decode
(
self
):
try
:
try
:
return
base64
.
b64decode
(
self
.
output
)
.
replace
(
'
\n
'
,
'<br />'
)
return
base64
.
b64decode
(
self
.
output
)
.
decode
(
'utf-8'
)
\
.
replace
(
'
\n
'
,
'<br />'
)
except
UnicodeDecodeError
:
except
UnicodeDecodeError
:
return
'UnicodeDecodeError'
return
'UnicodeDecodeError'
...
...
apps/audits/serializers.py
View file @
948214ca
...
@@ -13,8 +13,9 @@ class ProxyLogSerializer(serializers.ModelSerializer):
...
@@ -13,8 +13,9 @@ class ProxyLogSerializer(serializers.ModelSerializer):
class
Meta
:
class
Meta
:
model
=
models
.
ProxyLog
model
=
models
.
ProxyLog
fields
=
[
'id'
,
'name'
,
'username'
,
'hostname'
,
'ip'
,
'system_user'
,
'login_type'
,
'terminal'
,
fields
=
[
'id'
,
'name'
,
'username'
,
'hostname'
,
'ip'
,
'system_user'
,
'log_file'
,
'was_failed'
,
'is_finished'
,
'date_start'
,
'date_finished'
,
'time'
,
'login_type'
,
'terminal'
,
'log_file'
,
'was_failed'
,
'is_finished'
,
'date_start'
,
'date_finished'
,
'time'
,
'command_length'
,
"commands_dict"
]
'command_length'
,
"commands_dict"
]
@staticmethod
@staticmethod
...
@@ -32,3 +33,4 @@ class ProxyLogSerializer(serializers.ModelSerializer):
...
@@ -32,3 +33,4 @@ class ProxyLogSerializer(serializers.ModelSerializer):
class
CommandLogSerializer
(
serializers
.
ModelSerializer
):
class
CommandLogSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
class
Meta
:
model
=
models
.
CommandLog
model
=
models
.
CommandLog
fields
=
'__all__'
apps/audits/templates/audits/command_log_list.html
View file @
948214ca
...
@@ -83,7 +83,7 @@
...
@@ -83,7 +83,7 @@
<td>
{{ command.proxy_log.system_user }}
</td>
<td>
{{ command.proxy_log.system_user }}
</td>
<td><a
href=
"{% url 'audits:proxy-log-detail' pk=command.proxy_log.id %}"
>
{{ command.proxy_log.id}}
</a></td>
<td><a
href=
"{% url 'audits:proxy-log-detail' pk=command.proxy_log.id %}"
>
{{ command.proxy_log.id}}
</a></td>
<td>
{{ command.datetime }}
</td>
<td>
{{ command.datetime }}
</td>
<td>
{{ command.output_decode
|safe }}
</td>
<td>
{{ command.output_decode|safe }}
</td>
</tr>
</tr>
{% endfor %}
{% endfor %}
</tbody>
</tbody>
...
...
apps/audits/templates/audits/proxy_log_detail.html
View file @
948214ca
...
@@ -52,7 +52,7 @@
...
@@ -52,7 +52,7 @@
<tr>
<tr>
<td>
{{ command.command_no }}
</td>
<td>
{{ command.command_no }}
</td>
<td>
{{ command.command }}
</td>
<td>
{{ command.command }}
</td>
<td>
{{ command.output_decode
|safe }}
</td>
<td>
{{ command.output_decode|safe }}
</td>
<td>
{{ command.datetime }}
</td>
<td>
{{ command.datetime }}
</td>
</tr>
</tr>
{% endfor %}
{% endfor %}
...
@@ -68,30 +68,6 @@
...
@@ -68,30 +68,6 @@
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"col-sm-5"
style=
"padding-left: 0;padding-right: 0"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox-title"
>
<span
style=
"float: left"
>
{% trans 'Detail' %}
<b>
{{ user_object.name }}
</b></span>
<div
class=
"ibox-tools"
>
<a
class=
"collapse-link"
>
<i
class=
"fa fa-chevron-up"
></i>
</a>
<a
class=
"dropdown-toggle"
data-toggle=
"dropdown"
href=
"#"
>
<i
class=
"fa fa-wrench"
></i>
</a>
<ul
class=
"dropdown-menu dropdown-user"
>
</ul>
<a
class=
"close-link"
>
<i
class=
"fa fa-times"
></i>
</a>
</div>
</div>
<div
class=
"ibox-content"
>
<table
class=
"table2 table-stripped toggle-arrow-tiny"
data-page-size=
"8"
>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
...
...
apps/audits/views.py
View file @
948214ca
...
@@ -14,17 +14,16 @@ from .models import ProxyLog, CommandLog, LoginLog
...
@@ -14,17 +14,16 @@ from .models import ProxyLog, CommandLog, LoginLog
from
.hands
import
User
,
Asset
,
SystemUser
,
AdminUserRequiredMixin
from
.hands
import
User
,
Asset
,
SystemUser
,
AdminUserRequiredMixin
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'
)
class
ProxyLogListView
(
AdminUserRequiredMixin
,
ListView
):
class
ProxyLogListView
(
AdminUserRequiredMixin
,
ListView
):
model
=
ProxyLog
model
=
ProxyLog
template_name
=
'audits/proxy_log_list.html'
template_name
=
'audits/proxy_log_list.html'
context_object_name
=
'proxy_log_list'
context_object_name
=
'proxy_log_list'
def
get_queryset
(
self
):
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'
)
self
.
queryset
=
super
(
ProxyLogListView
,
self
)
.
get_queryset
()
self
.
queryset
=
super
(
ProxyLogListView
,
self
)
.
get_queryset
()
self
.
keyword
=
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
self
.
keyword
=
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
self
.
username
=
username
=
self
.
request
.
GET
.
get
(
'username'
,
''
)
self
.
username
=
username
=
self
.
request
.
GET
.
get
(
'username'
,
''
)
...
@@ -37,7 +36,8 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
...
@@ -37,7 +36,8 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
date_from
=
timezone
.
datetime
.
strptime
(
date_from_s
,
'
%
m/
%
d/
%
Y'
)
date_from
=
timezone
.
datetime
.
strptime
(
date_from_s
,
'
%
m/
%
d/
%
Y'
)
self
.
queryset
=
self
.
queryset
.
filter
(
date_start__gt
=
date_from
)
self
.
queryset
=
self
.
queryset
.
filter
(
date_start__gt
=
date_from
)
if
date_to_s
:
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_start__lt
=
date_to
)
self
.
queryset
=
self
.
queryset
.
filter
(
date_start__lt
=
date_to
)
if
username
:
if
username
:
self
.
queryset
=
self
.
queryset
.
filter
(
username
=
username
)
self
.
queryset
=
self
.
queryset
.
filter
(
username
=
username
)
...
@@ -54,7 +54,6 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
...
@@ -54,7 +54,6 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
return
self
.
queryset
return
self
.
queryset
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
print
(
self
.
date_to_s
)
context
=
{
context
=
{
'app'
:
_
(
'Audits'
),
'app'
:
_
(
'Audits'
),
'action'
:
_
(
'Proxy log list'
),
'action'
:
_
(
'Proxy log list'
),
...
@@ -110,6 +109,9 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
...
@@ -110,6 +109,9 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
context_object_name
=
'command_list'
context_object_name
=
'command_list'
def
get_queryset
(
self
):
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'
)
self
.
queryset
=
super
(
CommandLogListView
,
self
)
.
get_queryset
()
self
.
queryset
=
super
(
CommandLogListView
,
self
)
.
get_queryset
()
self
.
keyword
=
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
self
.
keyword
=
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
self
.
sort
=
sort
=
self
.
request
.
GET
.
get
(
'sort'
,
'-datetime'
)
self
.
sort
=
sort
=
self
.
request
.
GET
.
get
(
'sort'
,
'-datetime'
)
...
@@ -161,6 +163,9 @@ class LoginLogListView(AdminUserRequiredMixin, ListView):
...
@@ -161,6 +163,9 @@ class LoginLogListView(AdminUserRequiredMixin, ListView):
context_object_name
=
'login_log_list'
context_object_name
=
'login_log_list'
def
get_queryset
(
self
):
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'
)
self
.
queryset
=
super
(
LoginLogListView
,
self
)
.
get_queryset
()
self
.
queryset
=
super
(
LoginLogListView
,
self
)
.
get_queryset
()
self
.
keyword
=
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
self
.
keyword
=
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
self
.
username
=
username
=
self
.
request
.
GET
.
get
(
'username'
,
''
)
self
.
username
=
username
=
self
.
request
.
GET
.
get
(
'username'
,
''
)
...
...
apps/common/celery.py
View file @
948214ca
...
@@ -16,5 +16,6 @@ app = Celery('jumpserver')
...
@@ -16,5 +16,6 @@ app = Celery('jumpserver')
# Using a string here means the worker will not have to
# Using a string here means the worker will not have to
# pickle the object when using Windows.
# pickle the object when using Windows.
app
.
config_from_object
(
'django.conf:settings'
)
app
.
config_from_object
(
'django.conf:settings'
)
app
.
autodiscover_tasks
(
lambda
:
[
app_config
.
split
(
'.'
)[
0
]
for
app_config
in
settings
.
INSTALLED_APPS
])
app
.
autodiscover_tasks
(
lambda
:
[
app_config
.
split
(
'.'
)[
0
]
for
app_config
in
settings
.
INSTALLED_APPS
])
apps/perms/api.py
View file @
948214ca
# ~*~ coding: utf-8 ~*~
# ~*~ coding: utf-8 ~*~
#
#
from
django.shortcuts
import
get_object_or_404
from
rest_framework.views
import
APIView
,
Response
from
rest_framework.views
import
APIView
,
Response
from
rest_framework.decorators
import
api_view
from
rest_framework.generics
import
ListAPIView
,
get_object_or_404
from
rest_framework.generics
import
ListAPIView
,
get_object_or_404
from
rest_framework
import
viewsets
from
rest_framework
import
viewsets
from
users.permissions
import
IsValidUser
,
IsSuperUser
from
users.permissions
import
IsValidUser
,
IsSuperUser
,
IsAppUser
from
common.utils
import
get_object_or_none
from
common.utils
import
get_object_or_none
from
.utils
import
get_user_granted_assets
,
get_user_granted_asset_groups
,
get_user_asset_permissions
,
\
from
.utils
import
get_user_granted_assets
,
get_user_granted_asset_groups
,
\
get_user_group_asset_permissions
,
get_user_group_granted_assets
,
get_user_group_granted_asset_groups
get_user_asset_permissions
,
get_user_group_asset_permissions
,
\
get_user_group_granted_assets
,
get_user_group_granted_asset_groups
from
.models
import
AssetPermission
from
.models
import
AssetPermission
from
.hands
import
AssetGrantedSerializer
,
User
,
UserGroup
,
AssetGroup
,
Asset
,
AssetGroup
,
AssetGroupSerializer
from
.hands
import
AssetGrantedSerializer
,
User
,
UserGroup
,
AssetGroup
,
Asset
,
\
AssetGroup
,
AssetGroupSerializer
,
SystemUser
from
.
import
serializers
from
.
import
serializers
...
@@ -80,11 +82,12 @@ class UserGrantedAssetsApi(ListAPIView):
...
@@ -80,11 +82,12 @@ class UserGrantedAssetsApi(ListAPIView):
def
get_queryset
(
self
):
def
get_queryset
(
self
):
user_id
=
self
.
kwargs
.
get
(
'pk'
,
''
)
user_id
=
self
.
kwargs
.
get
(
'pk'
,
''
)
queryset
=
[]
if
user_id
:
if
user_id
:
user
=
get_object_or_404
(
User
,
id
=
user_id
)
user
=
get_object_or_404
(
User
,
id
=
user_id
)
queryset
=
get_user_granted_assets
(
user
)
for
k
,
v
in
get_user_granted_assets
(
user
)
.
items
():
else
:
k
.
system_users_granted
=
v
queryset
=
[]
queryset
.
append
(
k
)
return
queryset
return
queryset
...
@@ -104,19 +107,26 @@ class UserGrantedAssetGroupsApi(ListAPIView):
...
@@ -104,19 +107,26 @@ class UserGrantedAssetGroupsApi(ListAPIView):
class
MyGrantedAssetsApi
(
ListAPIView
):
class
MyGrantedAssetsApi
(
ListAPIView
):
"""授权给用户的资产列表
[{'hostname': 'x','ip': 'x', ..,
'system_users_granted': [{'name': 'x', .}, ...]
"""
permission_classes
=
(
IsValidUser
,)
permission_classes
=
(
IsValidUser
,)
serializer_class
=
AssetGrantedSerializer
serializer_class
=
AssetGrantedSerializer
def
get_queryset
(
self
):
def
get_queryset
(
self
):
queryset
=
[]
user
=
self
.
request
.
user
user
=
self
.
request
.
user
if
user
:
if
user
:
queryset
=
get_user_granted_assets
(
user
)
for
asset
,
system_users
in
get_user_granted_assets
(
user
)
.
items
():
else
:
asset
.
system_users_granted
=
system_users
queryset
=
[]
queryset
.
append
(
asset
)
return
queryset
return
queryset
class
MyGrantedAssetsGroupsApi
(
APIView
):
class
MyGrantedAssetsGroupsApi
(
APIView
):
"""授权给用户的资产组列表, 非直接通过授权规则授权的资产组列表, 而是授权资产的所有
资产组之和"""
permission_classes
=
(
IsValidUser
,)
permission_classes
=
(
IsValidUser
,)
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
...
@@ -141,6 +151,7 @@ class MyGrantedAssetsGroupsApi(APIView):
...
@@ -141,6 +151,7 @@ class MyGrantedAssetsGroupsApi(APIView):
class
MyAssetGroupAssetsApi
(
ListAPIView
):
class
MyAssetGroupAssetsApi
(
ListAPIView
):
"""授权用户资产组下的资产列表, 非该资产组的所有资产,而是被授权的"""
permission_classes
=
(
IsValidUser
,)
permission_classes
=
(
IsValidUser
,)
serializer_class
=
AssetGrantedSerializer
serializer_class
=
AssetGrantedSerializer
...
@@ -152,8 +163,9 @@ class MyAssetGroupAssetsApi(ListAPIView):
...
@@ -152,8 +163,9 @@ class MyAssetGroupAssetsApi(ListAPIView):
if
user
and
asset_group
:
if
user
and
asset_group
:
assets
=
get_user_granted_assets
(
user
)
assets
=
get_user_granted_assets
(
user
)
for
asset
in
assets
:
for
asset
in
asset_group
.
assets
.
all
():
if
asset_group
in
asset
.
groups
.
all
():
if
asset
in
assets
:
asset
.
system_users_granted
=
assets
[
asset
]
queryset
.
append
(
asset
)
queryset
.
append
(
asset
)
return
queryset
return
queryset
...
@@ -185,4 +197,24 @@ class UserGroupGrantedAssetGroupsApi(ListAPIView):
...
@@ -185,4 +197,24 @@ class UserGroupGrantedAssetGroupsApi(ListAPIView):
queryset
=
get_user_group_granted_asset_groups
(
user_group
)
queryset
=
get_user_group_granted_asset_groups
(
user_group
)
else
:
else
:
queryset
=
[]
queryset
=
[]
return
queryset
return
queryset
\ No newline at end of file
class
ValidateUserAssetPermissionView
(
APIView
):
permission_classes
=
(
IsAppUser
,)
@staticmethod
def
get
(
request
):
user_id
=
request
.
query_params
.
get
(
'user_id'
,
''
)
asset_id
=
request
.
query_params
.
get
(
'asset_id'
,
''
)
system_id
=
request
.
query_params
.
get
(
'system_user_id'
,
''
)
user
=
get_object_or_404
(
User
,
id
=
user_id
)
asset
=
get_object_or_404
(
Asset
,
id
=
asset_id
)
system_user
=
get_object_or_404
(
SystemUser
,
id
=
system_id
)
assets_granted
=
get_user_granted_assets
(
user
)
if
system_user
in
assets_granted
.
get
(
asset
,
[]):
return
Response
({
'msg'
:
True
},
status
=
200
)
else
:
return
Response
({
'msg'
:
False
},
status
=
403
)
apps/perms/serializers.py
View file @
948214ca
...
@@ -11,6 +11,7 @@ from .hands import User
...
@@ -11,6 +11,7 @@ from .hands import User
class
AssetPermissionSerializer
(
serializers
.
ModelSerializer
):
class
AssetPermissionSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
class
Meta
:
model
=
AssetPermission
model
=
AssetPermission
fields
=
'__all__'
class
UserAssetPermissionSerializer
(
AssetPermissionSerializer
):
class
UserAssetPermissionSerializer
(
AssetPermissionSerializer
):
...
@@ -23,4 +24,3 @@ class UserAssetPermissionSerializer(AssetPermissionSerializer):
...
@@ -23,4 +24,3 @@ class UserAssetPermissionSerializer(AssetPermissionSerializer):
else
:
else
:
return
False
return
False
apps/perms/urls/api_urls.py
View file @
948214ca
...
@@ -7,30 +7,50 @@ from .. import api
...
@@ -7,30 +7,50 @@ from .. import api
app_name
=
'perms'
app_name
=
'perms'
router
=
routers
.
DefaultRouter
()
router
=
routers
.
DefaultRouter
()
router
.
register
(
'v1/asset-permissions'
,
api
.
AssetPermissionViewSet
,
'asset-permission'
)
router
.
register
(
'v1/asset-permissions'
,
api
.
AssetPermissionViewSet
,
'asset-permission'
)
urlpatterns
=
[
urlpatterns
=
[
url
(
r'^v1/user/my/assets/$'
,
api
.
MyGrantedAssetsApi
.
as_view
(),
name
=
'my-assets'
),
# 用户可以使用自己的Token或其它认证查看自己授权的资产,资产组等
url
(
r'^v1/user/my/asset-groups/$'
,
api
.
MyGrantedAssetsGroupsApi
.
as_view
(),
name
=
'my-asset-groups'
),
url
(
r'^v1/user/my/assets/$'
,
url
(
r'^v1/user/my/asset-group/(?P<pk>[0-9]+)/assets/$'
,
api
.
MyAssetGroupAssetsApi
.
as_view
(),
api
.
MyGrantedAssetsApi
.
as_view
(),
name
=
'my-assets'
),
url
(
r'^v1/user/my/asset-groups/$'
,
api
.
MyGrantedAssetsGroupsApi
.
as_view
(),
name
=
'my-asset-groups'
),
url
(
r'^v1/user/my/asset-group/(?P<pk>[0-9]+)/assets/$'
,
api
.
MyAssetGroupAssetsApi
.
as_view
(),
name
=
'user-my-asset-group-assets'
),
name
=
'user-my-asset-group-assets'
),
# Select user permission of asset and asset group
# 查询某个用户授权的资产和资产组
url
(
r'^v1/user/(?P<pk>[0-9]+)/assets/$'
,
api
.
UserGrantedAssetsApi
.
as_view
(),
name
=
'user-assets'
),
url
(
r'^v1/user/(?P<pk>[0-9]+)/assets/$'
,
url
(
r'^v1/user/(?P<pk>[0-9]+)/asset-groups/$'
,
api
.
UserGrantedAssetGroupsApi
.
as_view
(),
api
.
UserGrantedAssetsApi
.
as_view
(),
name
=
'user-assets'
),
url
(
r'^v1/user/(?P<pk>[0-9]+)/asset-groups/$'
,
api
.
UserGrantedAssetGroupsApi
.
as_view
(),
name
=
'user-asset-groups'
),
name
=
'user-asset-groups'
),
# Select user group permission of asset and asset group
# 查询某个用户组授权的资产和资产组
url
(
r'^v1/user-group/(?P<pk>[0-9]+)/assets/$'
,
api
.
UserGroupGrantedAssetsApi
.
as_view
(),
name
=
'user-group-assets'
),
url
(
r'^v1/user-group/(?P<pk>[0-9]+)/assets/$'
,
url
(
r'^v1/user-group/(?P<pk>[0-9]+)/asset-groups/$'
,
api
.
UserGroupGrantedAssetGroupsApi
.
as_view
(),
api
.
UserGroupGrantedAssetsApi
.
as_view
(),
name
=
'user-group-assets'
),
url
(
r'^v1/user-group/(?P<pk>[0-9]+)/asset-groups/$'
,
api
.
UserGroupGrantedAssetGroupsApi
.
as_view
(),
name
=
'user-group-asset-groups'
),
name
=
'user-group-asset-groups'
),
# 回收用户或用户组授权
# Revoke permission api
url
(
r'^v1/asset-permissions/user/revoke/$'
,
url
(
r'^v1/asset-permissions/user/revoke/'
,
api
.
RevokeUserAssetPermission
.
as_view
(),
api
.
RevokeUserAssetPermission
.
as_view
(),
name
=
'revoke-user-asset-permission'
),
name
=
'revoke-user-asset-permission'
),
url
(
r'^v1/asset-permissions/user-group/revoke/'
,
api
.
RevokeUserGroupAssetPermission
.
as_view
(),
url
(
r'^v1/asset-permissions/user-group/revoke/$'
,
api
.
RevokeUserGroupAssetPermission
.
as_view
(),
name
=
'revoke-user-group-asset-permission'
),
name
=
'revoke-user-group-asset-permission'
),
# 验证用户是否有某个资产和系统用户的权限
url
(
r'v1/asset-permission/user/validate/$'
,
api
.
ValidateUserAssetPermissionView
.
as_view
(),
name
=
'validate-user-asset-permission'
)
]
]
urlpatterns
+=
router
.
urls
urlpatterns
+=
router
.
urls
...
...
apps/perms/utils.py
View file @
948214ca
...
@@ -37,6 +37,8 @@ def get_user_group_granted_assets(user_group):
...
@@ -37,6 +37,8 @@ def get_user_group_granted_assets(user_group):
if
not
asset_permission
.
is_valid
:
if
not
asset_permission
.
is_valid
:
continue
continue
for
asset
in
asset_permission
.
get_granted_assets
():
for
asset
in
asset_permission
.
get_granted_assets
():
if
not
asset
.
is_active
:
continue
if
asset
in
assets
:
if
asset
in
assets
:
assets
[
asset
]
|=
set
(
asset_permission
.
system_users
.
all
())
assets
[
asset
]
|=
set
(
asset_permission
.
system_users
.
all
())
else
:
else
:
...
@@ -127,6 +129,8 @@ def get_user_granted_assets_direct(user):
...
@@ -127,6 +129,8 @@ def get_user_granted_assets_direct(user):
if
not
asset_permission
.
is_valid
:
if
not
asset_permission
.
is_valid
:
continue
continue
for
asset
in
asset_permission
.
get_granted_assets
():
for
asset
in
asset_permission
.
get_granted_assets
():
if
not
asset
.
is_active
:
continue
if
asset
in
assets
:
if
asset
in
assets
:
assets
[
asset
]
|=
set
(
asset_permission
.
system_users
.
all
())
assets
[
asset
]
|=
set
(
asset_permission
.
system_users
.
all
())
else
:
else
:
...
@@ -147,12 +151,13 @@ def get_user_granted_assets_inherit_from_user_groups(user):
...
@@ -147,12 +151,13 @@ def get_user_granted_assets_inherit_from_user_groups(user):
for
user_group
in
user_groups
:
for
user_group
in
user_groups
:
assets_inherited
=
get_user_group_granted_assets
(
user_group
)
assets_inherited
=
get_user_group_granted_assets
(
user_group
)
for
asset
in
assets_inherited
:
for
asset
in
assets_inherited
:
if
not
asset
.
is_active
:
continue
if
asset
in
assets
:
if
asset
in
assets
:
assets
[
asset
]
|=
assets_inherited
[
asset
]
assets
[
asset
]
|=
assets_inherited
[
asset
]
else
:
else
:
setattr
(
asset
,
'inherited'
,
True
)
setattr
(
asset
,
'inherited'
,
True
)
assets
[
asset
]
=
assets_inherited
[
asset
]
assets
[
asset
]
=
assets_inherited
[
asset
]
return
assets
return
assets
...
@@ -167,6 +172,8 @@ def get_user_granted_assets(user):
...
@@ -167,6 +172,8 @@ def get_user_granted_assets(user):
assets
=
assets_inherited
assets
=
assets_inherited
for
asset
in
assets_direct
:
for
asset
in
assets_direct
:
if
not
asset
.
is_active
:
continue
if
asset
in
assets
:
if
asset
in
assets
:
assets
[
asset
]
|=
assets_direct
[
asset
]
assets
[
asset
]
|=
assets_direct
[
asset
]
else
:
else
:
...
...
apps/perms/views.py
View file @
948214ca
...
@@ -39,22 +39,25 @@ class AssetPermissionListView(AdminUserRequiredMixin, ListView):
...
@@ -39,22 +39,25 @@ class AssetPermissionListView(AdminUserRequiredMixin, ListView):
self
.
sort
=
sort
=
self
.
request
.
GET
.
get
(
'sort'
,
'-date_created'
)
self
.
sort
=
sort
=
self
.
request
.
GET
.
get
(
'sort'
,
'-date_created'
)
if
keyword
:
if
keyword
:
self
.
queryset
=
self
.
queryset
.
filter
(
Q
(
users__name__contains
=
keyword
)
|
self
.
queryset
=
self
.
queryset
\
Q
(
users__username__contains
=
keyword
)
|
.
filter
(
Q
(
users__name__contains
=
keyword
)
|
Q
(
user_groups__name__contains
=
keyword
)
|
Q
(
users__username__contains
=
keyword
)
|
Q
(
assets__ip__contains
=
keyword
)
|
Q
(
user_groups__name__contains
=
keyword
)
|
Q
(
assets__hostname__contains
=
keyword
)
|
Q
(
assets__ip__contains
=
keyword
)
|
Q
(
system_users__username__icontains
=
keyword
)
|
Q
(
assets__hostname__contains
=
keyword
)
|
Q
(
system_users__name__icontains
=
keyword
)
|
Q
(
system_users__username__icontains
=
keyword
)
|
Q
(
asset_groups__name__icontains
=
keyword
)
|
Q
(
system_users__name__icontains
=
keyword
)
|
Q
(
comment__icontains
=
keyword
)
|
Q
(
asset_groups__name__icontains
=
keyword
)
|
Q
(
name__icontains
=
keyword
))
.
distinct
()
Q
(
comment__icontains
=
keyword
)
|
Q
(
name__icontains
=
keyword
))
.
distinct
()
if
sort
:
if
sort
:
self
.
queryset
=
self
.
queryset
.
order_by
(
sort
)
self
.
queryset
=
self
.
queryset
.
order_by
(
sort
)
return
self
.
queryset
return
self
.
queryset
class
AssetPermissionCreateView
(
AdminUserRequiredMixin
,
SuccessMessageMixin
,
CreateView
):
class
AssetPermissionCreateView
(
AdminUserRequiredMixin
,
SuccessMessageMixin
,
CreateView
):
model
=
AssetPermission
model
=
AssetPermission
form_class
=
AssetPermissionForm
form_class
=
AssetPermissionForm
template_name
=
'perms/asset_permission_create_update.html'
template_name
=
'perms/asset_permission_create_update.html'
...
@@ -69,11 +72,11 @@ class AssetPermissionCreateView(AdminUserRequiredMixin, SuccessMessageMixin, Cre
...
@@ -69,11 +72,11 @@ class AssetPermissionCreateView(AdminUserRequiredMixin, SuccessMessageMixin, Cre
return
super
(
AssetPermissionCreateView
,
self
)
.
get_context_data
(
**
kwargs
)
return
super
(
AssetPermissionCreateView
,
self
)
.
get_context_data
(
**
kwargs
)
def
get_success_message
(
self
,
cleaned_data
):
def
get_success_message
(
self
,
cleaned_data
):
success_message
=
_
(
'Create asset permission <a href="
%
s">
%
s </a> successfully.'
%
success_message
=
_
(
(
'Create asset permission <a href="
%
s">
%
s </a> '
reverse_lazy
(
'perms:asset-permission-detail'
,
kwargs
=
{
'pk'
:
self
.
object
.
pk
})
,
'successfully.'
%
(
reverse_lazy
(
'perms:asset-permission-detail'
,
self
.
object
.
name
,
kwargs
=
{
'pk'
:
self
.
object
.
pk
})
,
))
self
.
object
.
name
,
))
return
success_message
return
success_message
...
@@ -81,7 +84,8 @@ class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
...
@@ -81,7 +84,8 @@ class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
model
=
AssetPermission
model
=
AssetPermission
form_class
=
AssetPermissionForm
form_class
=
AssetPermissionForm
template_name
=
'perms/asset_permission_create_update.html'
template_name
=
'perms/asset_permission_create_update.html'
success_message
=
_
(
'Update asset permission <a href="
%
s">
%
s </a> successfully.'
)
success_message
=
_
(
'Update asset permission '
'<a href="
%
s">
%
s </a> successfully.'
)
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
context
=
{
...
@@ -92,7 +96,8 @@ class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
...
@@ -92,7 +96,8 @@ class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
return
super
(
AssetPermissionUpdateView
,
self
)
.
get_context_data
(
**
kwargs
)
return
super
(
AssetPermissionUpdateView
,
self
)
.
get_context_data
(
**
kwargs
)
def
get_success_url
(
self
):
def
get_success_url
(
self
):
success_url
=
reverse_lazy
(
'perms:asset-permission-detail'
,
kwargs
=
{
'pk'
:
self
.
object
.
pk
})
success_url
=
reverse_lazy
(
'perms:asset-permission-detail'
,
kwargs
=
{
'pk'
:
self
.
object
.
pk
})
return
success_url
return
success_url
...
@@ -105,8 +110,9 @@ class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView):
...
@@ -105,8 +110,9 @@ class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView):
context
=
{
context
=
{
'app'
:
_
(
'Perms'
),
'app'
:
_
(
'Perms'
),
'action'
:
_
(
'Asset permission detail'
),
'action'
:
_
(
'Asset permission detail'
),
'system_users_remain'
:
[
system_user
for
system_user
in
SystemUser
.
objects
.
all
()
'system_users_remain'
:
[
if
system_user
not
in
self
.
object
.
system_users
.
all
()],
system_user
for
system_user
in
SystemUser
.
objects
.
all
()
if
system_user
not
in
self
.
object
.
system_users
.
all
()],
'system_users'
:
self
.
object
.
system_users
.
all
(),
'system_users'
:
self
.
object
.
system_users
.
all
(),
}
}
kwargs
.
update
(
context
)
kwargs
.
update
(
context
)
...
@@ -119,7 +125,9 @@ class AssetPermissionDeleteView(AdminUserRequiredMixin, DeleteView):
...
@@ -119,7 +125,9 @@ class AssetPermissionDeleteView(AdminUserRequiredMixin, DeleteView):
success_url
=
reverse_lazy
(
'perms:asset-permission-list'
)
success_url
=
reverse_lazy
(
'perms:asset-permission-list'
)
class
AssetPermissionUserView
(
AdminUserRequiredMixin
,
SingleObjectMixin
,
ListView
):
class
AssetPermissionUserView
(
AdminUserRequiredMixin
,
SingleObjectMixin
,
ListView
):
template_name
=
'perms/asset_permission_user.html'
template_name
=
'perms/asset_permission_user.html'
context_object_name
=
'asset_permission'
context_object_name
=
'asset_permission'
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
...
@@ -132,9 +140,11 @@ class AssetPermissionUserView(AdminUserRequiredMixin, SingleObjectMixin, ListVie
...
@@ -132,9 +140,11 @@ class AssetPermissionUserView(AdminUserRequiredMixin, SingleObjectMixin, ListVie
def
get_queryset
(
self
):
def
get_queryset
(
self
):
queryset
=
self
.
object
.
get_granted_users
()
queryset
=
self
.
object
.
get_granted_users
()
if
self
.
keyword
:
if
self
.
keyword
:
search_func
=
functools
.
partial
(
search_object_attr
,
value
=
self
.
keyword
,
search_func
=
functools
.
partial
(
attr_list
=
[
'username'
,
'name'
,
'email'
],
search_object_attr
,
ignore_case
=
True
)
value
=
self
.
keyword
,
attr_list
=
[
'username'
,
'name'
,
'email'
],
ignore_case
=
True
)
queryset
=
filter
(
search_func
,
queryset
)
queryset
=
filter
(
search_func
,
queryset
)
return
queryset
return
queryset
...
@@ -144,17 +154,22 @@ class AssetPermissionUserView(AdminUserRequiredMixin, SingleObjectMixin, ListVie
...
@@ -144,17 +154,22 @@ class AssetPermissionUserView(AdminUserRequiredMixin, SingleObjectMixin, ListVie
context
=
{
context
=
{
'app'
:
_
(
'Perms'
),
'app'
:
_
(
'Perms'
),
'action'
:
_
(
'Asset permission user list'
),
'action'
:
_
(
'Asset permission user list'
),
'users_remain'
:
[
user
for
user
in
User
.
objects
.
all
()
if
user
not
in
users_granted
],
'users_remain'
:
[
user
for
user
in
User
.
objects
.
all
()
if
user
not
in
users_granted
],
'user_groups'
:
self
.
object
.
user_groups
.
all
(),
'user_groups'
:
self
.
object
.
user_groups
.
all
(),
'user_groups_remain'
:
[
user_group
for
user_group
in
UserGroup
.
objects
.
all
()
'user_groups_remain'
:
[
if
user_group
not
in
user_groups_granted
],
user_group
for
user_group
in
UserGroup
.
objects
.
all
()
if
user_group
not
in
user_groups_granted
],
'keyword'
:
self
.
keyword
,
'keyword'
:
self
.
keyword
,
}
}
kwargs
.
update
(
context
)
kwargs
.
update
(
context
)
return
super
(
AssetPermissionUserView
,
self
)
.
get_context_data
(
**
kwargs
)
return
super
(
AssetPermissionUserView
,
self
)
.
get_context_data
(
**
kwargs
)
class
AssetPermissionAssetView
(
AdminUserRequiredMixin
,
SingleObjectMixin
,
ListView
):
class
AssetPermissionAssetView
(
AdminUserRequiredMixin
,
SingleObjectMixin
,
ListView
):
template_name
=
'perms/asset_permission_asset.html'
template_name
=
'perms/asset_permission_asset.html'
context_object_name
=
'asset_permission'
context_object_name
=
'asset_permission'
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
...
@@ -162,14 +177,16 @@ class AssetPermissionAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListVi
...
@@ -162,14 +177,16 @@ class AssetPermissionAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListVi
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
(
queryset
=
AssetPermission
.
objects
.
all
())
self
.
object
=
self
.
get_object
(
queryset
=
AssetPermission
.
objects
.
all
())
self
.
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
self
.
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
return
super
(
AssetPermissionAssetView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
return
super
(
AssetPermissionAssetView
,
self
)
\
.
get
(
request
,
*
args
,
**
kwargs
)
def
get_queryset
(
self
):
def
get_queryset
(
self
):
queryset
=
self
.
object
.
get_granted_assets
()
queryset
=
self
.
object
.
get_granted_assets
()
if
self
.
keyword
:
if
self
.
keyword
:
search_func
=
functools
.
partial
(
search_object_attr
,
value
=
self
.
keyword
,
search_func
=
functools
.
partial
(
attr_list
=
[
'hostname'
,
'ip'
],
search_object_attr
,
value
=
self
.
keyword
,
ignore_case
=
True
)
attr_list
=
[
'hostname'
,
'ip'
],
ignore_case
=
True
)
queryset
=
filter
(
search_func
,
queryset
)
queryset
=
filter
(
search_func
,
queryset
)
return
queryset
return
queryset
...
@@ -179,10 +196,13 @@ class AssetPermissionAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListVi
...
@@ -179,10 +196,13 @@ class AssetPermissionAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListVi
context
=
{
context
=
{
'app'
:
_
(
'Perms'
),
'app'
:
_
(
'Perms'
),
'action'
:
_
(
'Asset permission asset list'
),
'action'
:
_
(
'Asset permission asset list'
),
'assets_remain'
:
(
asset
for
asset
in
Asset
.
objects
.
all
()
if
asset
not
in
assets_granted
),
'assets_remain'
:
[
asset
for
asset
in
Asset
.
objects
.
all
()
if
asset
not
in
assets_granted
],
'asset_groups'
:
self
.
object
.
asset_groups
.
all
(),
'asset_groups'
:
self
.
object
.
asset_groups
.
all
(),
'asset_groups_remain'
:
[
asset_group
for
asset_group
in
AssetGroup
.
objects
.
all
()
'asset_groups_remain'
:
[
if
asset_group
not
in
asset_groups_granted
],
asset_group
for
asset_group
in
AssetGroup
.
objects
.
all
()
if
asset_group
not
in
asset_groups_granted
],
'keyword'
:
self
.
keyword
,
'keyword'
:
self
.
keyword
,
}
}
kwargs
.
update
(
context
)
kwargs
.
update
(
context
)
...
...
apps/users/api.py
View file @
948214ca
# ~*~ coding: utf-8 ~*~
# ~*~ coding: utf-8 ~*~
#
#
import
base64
from
django.core.cache
import
cache
from
django.conf
import
settings
from
rest_framework
import
generics
,
viewsets
from
rest_framework
import
generics
,
viewsets
from
rest_framework.response
import
Response
from
rest_framework.response
import
Response
from
rest_framework.views
import
APIView
from
rest_framework.views
import
APIView
from
rest_framework.decorators
import
api_view
from
rest_framework.permissions
import
AllowAny
from
rest_framework.permissions
import
AllowAny
from
rest_framework.authentication
import
SessionAuthentication
from
rest_framework_bulk
import
BulkModelViewSet
from
rest_framework_bulk
import
BulkModelViewSet
# from django_filters.rest_framework import DjangoFilterBackend
# from django_filters.rest_framework import DjangoFilterBackend
...
@@ -19,7 +13,8 @@ from common.utils import get_logger
...
@@ -19,7 +13,8 @@ from common.utils import get_logger
from
.utils
import
check_user_valid
,
generate_token
from
.utils
import
check_user_valid
,
generate_token
from
.models
import
User
,
UserGroup
from
.models
import
User
,
UserGroup
from
.hands
import
write_login_log_async
from
.hands
import
write_login_log_async
from
.permissions
import
IsSuperUser
,
IsAppUser
,
IsValidUser
,
IsSuperUserOrAppUser
from
.permissions
import
(
IsSuperUser
,
IsAppUser
,
IsValidUser
)
from
.
import
serializers
from
.
import
serializers
...
@@ -98,8 +93,9 @@ class UserToken(APIView):
...
@@ -98,8 +93,9 @@ class UserToken(APIView):
password
=
request
.
data
.
get
(
'password'
,
''
)
password
=
request
.
data
.
get
(
'password'
,
''
)
public_key
=
request
.
data
.
get
(
'public_key'
,
''
)
public_key
=
request
.
data
.
get
(
'public_key'
,
''
)
user
,
msg
=
check_user_valid
(
username
=
username
,
email
=
email
,
user
,
msg
=
check_user_valid
(
password
=
password
,
public_key
=
public_key
)
username
=
username
,
email
=
email
,
password
=
password
,
public_key
=
public_key
)
else
:
else
:
user
=
request
.
user
user
=
request
.
user
msg
=
None
msg
=
None
...
@@ -116,24 +112,31 @@ class UserProfile(APIView):
...
@@ -116,24 +112,31 @@ class UserProfile(APIView):
def
get
(
self
,
request
):
def
get
(
self
,
request
):
return
Response
(
request
.
user
.
to_json
())
return
Response
(
request
.
user
.
to_json
())
def
post
(
self
,
request
):
return
Response
(
request
.
user
.
to_json
())
class
UserAuthApi
(
APIView
):
class
UserAuthApi
(
APIView
):
permission_classes
=
(
AllowAny
,)
permission_classes
=
(
AllowAny
,)
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
def
post
(
self
,
request
):
username
=
request
.
data
.
get
(
'username'
,
''
)
username
=
request
.
data
.
get
(
'username'
,
''
)
password
=
request
.
data
.
get
(
'password'
,
''
)
password
=
request
.
data
.
get
(
'password'
,
''
)
public_key
=
request
.
data
.
get
(
'public_key'
,
''
)
public_key
=
request
.
data
.
get
(
'public_key'
,
''
)
login_type
=
request
.
data
.
get
(
'login_type'
,
''
)
login_type
=
request
.
data
.
get
(
'login_type'
,
''
)
login_ip
=
request
.
data
.
get
(
'remote_addr'
,
None
)
or
request
.
META
.
get
(
'REMOTE_ADDR'
,
''
)
login_ip
=
request
.
data
.
get
(
'remote_addr'
,
None
)
user_agent
=
request
.
data
.
get
(
'HTTP_USER_AGENT'
,
''
)
user_agent
=
request
.
data
.
get
(
'HTTP_USER_AGENT'
,
''
)
user
,
msg
=
check_user_valid
(
username
=
username
,
password
=
password
,
public_key
=
public_key
)
user
,
msg
=
check_user_valid
(
username
=
username
,
password
=
password
,
public_key
=
public_key
)
if
user
:
if
user
:
token
=
generate_token
(
request
,
user
)
token
=
generate_token
(
request
,
user
)
write_login_log_async
.
delay
(
user
.
username
,
name
=
user
.
name
,
user_agent
=
user_agent
,
write_login_log_async
.
delay
(
login_ip
=
login_ip
,
login_type
=
login_type
)
user
.
username
,
name
=
user
.
name
,
user_agent
=
user_agent
,
login_ip
=
login_ip
,
login_type
=
login_type
)
return
Response
({
'token'
:
token
,
'user'
:
user
.
to_json
()})
return
Response
({
'token'
:
token
,
'user'
:
user
.
to_json
()})
else
:
else
:
return
Response
({
'msg'
:
msg
},
status
=
401
)
return
Response
({
'msg'
:
msg
},
status
=
401
)
apps/users/authentication.py
View file @
948214ca
...
@@ -2,16 +2,18 @@
...
@@ -2,16 +2,18 @@
#
#
import
base64
import
base64
import
uuid
import
hashlib
import
hashlib
import
time
import
time
from
django.core.cache
import
cache
from
django.core.cache
import
cache
from
django.conf
import
settings
from
django.conf
import
settings
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
rest_framework
import
authentication
,
exceptions
,
permissions
from
django.utils.six
import
text_type
from
django.utils.six
import
text_type
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
rest_framework
import
HTTP_HEADER_ENCODING
from
rest_framework
import
HTTP_HEADER_ENCODING
from
rest_framework
import
authentication
,
exceptions
,
permissions
from
rest_framework.authentication
import
CSRFCheck
from
common.utils
import
get_object_or_none
,
make_signature
,
http_to_unixtime
from
common.utils
import
get_object_or_none
,
make_signature
,
http_to_unixtime
from
.utils
import
refresh_token
from
.utils
import
refresh_token
...
@@ -27,6 +29,21 @@ def get_request_date_header(request):
...
@@ -27,6 +29,21 @@ def get_request_date_header(request):
class
AccessKeyAuthentication
(
authentication
.
BaseAuthentication
):
class
AccessKeyAuthentication
(
authentication
.
BaseAuthentication
):
"""App使用Access key进行签名认证, 目前签名算法比较简单,
app注册或者手动建立后,会生成 access_key_id 和 access_key_secret,
然后使用 如下算法生成签名:
Signature = md5(access_key_secret + '
\n
' + Date)
example: Signature = md5('d32d2b8b-9a10-4b8d-85bb-1a66976f6fdc' + '
\n
' +
'Thu, 12 Jan 2017 08:19:41 GMT')
请求时设置请求header
header['Authorization'] = 'Sign access_key_id:Signature' 如:
header['Authorization'] =
'Sign d32d2b8b-9a10-4b8d-85bb-1a66976f6fdc:OKOlmdxgYPZ9+SddnUUDbQ=='
验证时根据相同算法进行验证, 取到access_key_id对应的access_key_id, 从request
headers取到Date, 然后进行md5, 判断得到的结果是否相同, 如果是认证通过, 否则 认证
失败
"""
keyword
=
'Sign'
keyword
=
'Sign'
model
=
AccessKey
model
=
AccessKey
...
@@ -40,22 +57,30 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
...
@@ -40,22 +57,30 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
msg
=
_
(
'Invalid signature header. No credentials provided.'
)
msg
=
_
(
'Invalid signature header. No credentials provided.'
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
elif
len
(
auth
)
>
2
:
elif
len
(
auth
)
>
2
:
msg
=
_
(
'Invalid signature header. Signature string should not contain spaces.'
)
msg
=
_
(
'Invalid signature header. Signature '
'string should not contain spaces.'
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
try
:
try
:
sign
=
auth
[
1
]
.
decode
()
.
split
(
':'
)
sign
=
auth
[
1
]
.
decode
()
.
split
(
':'
)
if
len
(
sign
)
!=
2
:
if
len
(
sign
)
!=
2
:
msg
=
_
(
'Invalid signature header. Format like AccessKeyId:Signature'
)
msg
=
_
(
'Invalid signature header. '
'Format like AccessKeyId:Signature'
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
except
UnicodeError
:
except
UnicodeError
:
msg
=
_
(
'Invalid signature header. Signature string should not contain invalid characters.'
)
msg
=
_
(
'Invalid signature header. '
'Signature string should not contain invalid characters.'
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
access_key_id
=
sign
[
0
]
access_key_id
=
sign
[
0
]
try
:
uuid
.
UUID
(
access_key_id
)
except
ValueError
:
raise
exceptions
.
AuthenticationFailed
(
'Access key id invalid'
)
request_signature
=
sign
[
1
]
request_signature
=
sign
[
1
]
return
self
.
authenticate_credentials
(
request
,
access_key_id
,
request_signature
)
return
self
.
authenticate_credentials
(
request
,
access_key_id
,
request_signature
)
@staticmethod
@staticmethod
def
authenticate_credentials
(
request
,
access_key_id
,
request_signature
):
def
authenticate_credentials
(
request
,
access_key_id
,
request_signature
):
...
@@ -68,14 +93,17 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
...
@@ -68,14 +93,17 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
try
:
try
:
request_unix_time
=
http_to_unixtime
(
request_date
)
request_unix_time
=
http_to_unixtime
(
request_date
)
except
ValueError
:
except
ValueError
:
raise
exceptions
.
AuthenticationFailed
(
_
(
'HTTP header: Date not provide or not
%
a,
%
d
%
b
%
Y
%
H:
%
M:
%
S GMT'
))
raise
exceptions
.
AuthenticationFailed
(
_
(
'HTTP header: Date not provide '
'or not
%
a,
%
d
%
b
%
Y
%
H:
%
M:
%
S GMT'
))
if
int
(
time
.
time
())
-
request_unix_time
>
15
*
60
:
if
int
(
time
.
time
())
-
request_unix_time
>
15
*
60
:
raise
exceptions
.
AuthenticationFailed
(
_
(
'Expired, more than 15 minutes'
))
raise
exceptions
.
AuthenticationFailed
(
_
(
'Expired, more than 15 minutes'
))
signature
=
make_signature
(
access_key_secret
,
request_date
)
signature
=
make_signature
(
access_key_secret
,
request_date
)
if
not
signature
==
request_signature
:
if
not
signature
==
request_signature
:
raise
exceptions
.
AuthenticationFailed
(
_
(
'Invalid signature.
%
s:
%
s'
%
(
signature
,
request_signature
)
))
raise
exceptions
.
AuthenticationFailed
(
_
(
'Invalid signature.
'
))
if
not
access_key
.
user
.
is_active
:
if
not
access_key
.
user
.
is_active
:
raise
exceptions
.
AuthenticationFailed
(
_
(
'User disabled.'
))
raise
exceptions
.
AuthenticationFailed
(
_
(
'User disabled.'
))
...
@@ -97,13 +125,15 @@ class AccessTokenAuthentication(authentication.BaseAuthentication):
...
@@ -97,13 +125,15 @@ class AccessTokenAuthentication(authentication.BaseAuthentication):
msg
=
_
(
'Invalid token header. No credentials provided.'
)
msg
=
_
(
'Invalid token header. No credentials provided.'
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
elif
len
(
auth
)
>
2
:
elif
len
(
auth
)
>
2
:
msg
=
_
(
'Invalid token header. Sign string should not contain spaces.'
)
msg
=
_
(
'Invalid token header. Sign string '
'should not contain spaces.'
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
try
:
try
:
token
=
auth
[
1
]
.
decode
()
token
=
auth
[
1
]
.
decode
()
except
UnicodeError
:
except
UnicodeError
:
msg
=
_
(
'Invalid token header. Sign string should not contain invalid characters.'
)
msg
=
_
(
'Invalid token header. Sign string '
'should not contain invalid characters.'
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
return
self
.
authenticate_credentials
(
token
)
return
self
.
authenticate_credentials
(
token
)
...
@@ -125,4 +155,6 @@ class PrivateTokenAuthentication(authentication.TokenAuthentication):
...
@@ -125,4 +155,6 @@ class PrivateTokenAuthentication(authentication.TokenAuthentication):
class
SessionAuthentication
(
authentication
.
SessionAuthentication
):
class
SessionAuthentication
(
authentication
.
SessionAuthentication
):
def
enforce_csrf
(
self
,
request
):
def
enforce_csrf
(
self
,
request
):
return
None
reason
=
CSRFCheck
()
.
process_view
(
request
,
None
,
(),
{})
\ No newline at end of file
if
reason
:
raise
exceptions
.
AuthenticationFailed
(
reason
)
apps/users/models/authentication.py
View file @
948214ca
...
@@ -16,7 +16,8 @@ class AccessKey(models.Model):
...
@@ -16,7 +16,8 @@ class AccessKey(models.Model):
default
=
uuid
.
uuid4
,
editable
=
False
)
default
=
uuid
.
uuid4
,
editable
=
False
)
secret
=
models
.
UUIDField
(
verbose_name
=
'AccessKeySecret'
,
secret
=
models
.
UUIDField
(
verbose_name
=
'AccessKeySecret'
,
default
=
uuid
.
uuid4
,
editable
=
False
)
default
=
uuid
.
uuid4
,
editable
=
False
)
user
=
models
.
ForeignKey
(
User
,
verbose_name
=
'User'
,
related_name
=
'access_key'
)
user
=
models
.
ForeignKey
(
User
,
verbose_name
=
'User'
,
related_name
=
'access_key'
)
def
get_id
(
self
):
def
get_id
(
self
):
return
str
(
self
.
id
)
return
str
(
self
.
id
)
...
...
apps/users/urls/api_urls.py
View file @
948214ca
...
@@ -18,9 +18,12 @@ urlpatterns = [
...
@@ -18,9 +18,12 @@ urlpatterns = [
url
(
r'^v1/token/$'
,
api
.
UserToken
.
as_view
(),
name
=
'user-token'
),
url
(
r'^v1/token/$'
,
api
.
UserToken
.
as_view
(),
name
=
'user-token'
),
url
(
r'^v1/profile/$'
,
api
.
UserProfile
.
as_view
(),
name
=
'user-profile'
),
url
(
r'^v1/profile/$'
,
api
.
UserProfile
.
as_view
(),
name
=
'user-profile'
),
url
(
r'^v1/auth/$'
,
api
.
UserAuthApi
.
as_view
(),
name
=
'user-auth'
),
url
(
r'^v1/auth/$'
,
api
.
UserAuthApi
.
as_view
(),
name
=
'user-auth'
),
url
(
r'^v1/users/(?P<pk>\d+)/password/reset/$'
,
api
.
UserResetPasswordApi
.
as_view
(),
name
=
'user-reset-password'
),
url
(
r'^v1/users/(?P<pk>\d+)/password/reset/$'
,
url
(
r'^v1/users/(?P<pk>\d+)/public-key/reset/$'
,
api
.
UserResetPKApi
.
as_view
(),
name
=
'user-public-key-reset'
),
api
.
UserResetPasswordApi
.
as_view
(),
name
=
'user-reset-password'
),
url
(
r'^v1/users/(?P<pk>\d+)/public-key/update/$'
,
api
.
UserUpdatePKApi
.
as_view
(),
name
=
'user-public-key-update'
),
url
(
r'^v1/users/(?P<pk>\d+)/public-key/reset/$'
,
api
.
UserResetPKApi
.
as_view
(),
name
=
'user-public-key-reset'
),
url
(
r'^v1/users/(?P<pk>\d+)/public-key/update/$'
,
api
.
UserUpdatePKApi
.
as_view
(),
name
=
'user-public-key-update'
),
url
(
r'^v1/users/(?P<pk>\d+)/groups/$'
,
url
(
r'^v1/users/(?P<pk>\d+)/groups/$'
,
api
.
UserUpdateGroupApi
.
as_view
(),
name
=
'user-update-group'
),
api
.
UserUpdateGroupApi
.
as_view
(),
name
=
'user-update-group'
),
url
(
r'^v1/user-groups/(?P<pk>\d+)/users/$'
,
url
(
r'^v1/user-groups/(?P<pk>\d+)/users/$'
,
...
...
apps/users/urls/views_urls.py
View file @
948214ca
...
@@ -6,39 +6,72 @@ from .. import views
...
@@ -6,39 +6,72 @@ from .. import views
app_name
=
'users'
app_name
=
'users'
urlpatterns
=
[
urlpatterns
=
[
# Login view
url
(
r'^login$'
,
views
.
UserLoginView
.
as_view
(),
name
=
'login'
),
url
(
r'^login$'
,
views
.
UserLoginView
.
as_view
(),
name
=
'login'
),
url
(
r'^logout$'
,
views
.
UserLogoutView
.
as_view
(),
name
=
'logout'
),
url
(
r'^logout$'
,
views
.
UserLogoutView
.
as_view
(),
name
=
'logout'
),
url
(
r'^password/forgot$'
,
views
.
UserForgotPasswordView
.
as_view
(),
name
=
'forgot-password'
),
url
(
r'^password/forgot$'
,
views
.
UserForgotPasswordView
.
as_view
(),
name
=
'forgot-password'
),
url
(
r'^password/forgot/sendmail-success$'
,
url
(
r'^password/forgot/sendmail-success$'
,
views
.
UserForgotPasswordSendmailSuccessView
.
as_view
(),
name
=
'forgot-password-sendmail-success'
),
views
.
UserForgotPasswordSendmailSuccessView
.
as_view
(),
url
(
r'^password/reset$'
,
views
.
UserResetPasswordView
.
as_view
(),
name
=
'reset-password'
),
name
=
'forgot-password-sendmail-success'
),
url
(
r'^password/reset/success$'
,
views
.
UserResetPasswordSuccessView
.
as_view
(),
url
(
r'^password/reset$'
,
views
.
UserResetPasswordView
.
as_view
(),
name
=
'reset-password'
),
url
(
r'^password/reset/success$'
,
views
.
UserResetPasswordSuccessView
.
as_view
(),
name
=
'reset-password-success'
),
name
=
'reset-password-success'
),
# User view
# User view
url
(
r'^user$'
,
views
.
UserListView
.
as_view
(),
name
=
'user-list'
),
url
(
r'^user$'
,
views
.
UserListView
.
as_view
(),
name
=
'user-list'
),
url
(
r'^user/(?P<pk>[0-9]+)$'
,
views
.
UserDetailView
.
as_view
(),
name
=
'user-detail'
),
url
(
r'^user/(?P<pk>[0-9]+)$'
,
views
.
UserDetailView
.
as_view
(),
url
(
r'^user/(?P<pk>[0-9]+)/asset-permission$'
,
views
.
UserAssetPermissionView
.
as_view
(),
name
=
'user-detail'
),
url
(
r'^user/(?P<pk>[0-9]+)/asset-permission$'
,
views
.
UserAssetPermissionView
.
as_view
(),
name
=
'user-asset-permission'
),
name
=
'user-asset-permission'
),
url
(
r'^user/(?P<pk>[0-9]+)/asset-permission/create$'
,
views
.
UserAssetPermissionCreateView
.
as_view
(),
url
(
r'^user/(?P<pk>[0-9]+)/asset-permission/create$'
,
views
.
UserAssetPermissionCreateView
.
as_view
(),
name
=
'user-asset-permission-create'
),
name
=
'user-asset-permission-create'
),
url
(
r'^user/(?P<pk>[0-9]+)/assets'
,
views
.
UserGrantedAssetView
.
as_view
(),
name
=
'user-granted-asset'
),
url
(
r'^user/(?P<pk>[0-9]+)/assets'
,
url
(
r'^user/(?P<pk>[0-9]+)/login-history'
,
views
.
UserDetailView
.
as_view
(),
name
=
'user-login-history'
),
views
.
UserGrantedAssetView
.
as_view
(),
url
(
r'^user/export/'
,
views
.
UserExportView
.
as_view
(),
name
=
'user-export'
),
name
=
'user-granted-asset'
),
url
(
r'^first-login/$'
,
views
.
UserFirstLoginView
.
as_view
(),
name
=
'user-first-login'
),
url
(
r'^user/(?P<pk>[0-9]+)/login-history'
,
url
(
r'^user/import/$'
,
views
.
BulkImportUserView
.
as_view
(),
name
=
'user-import'
),
views
.
UserDetailView
.
as_view
(),
# url(r'^user/(?P<pk>[0-9]+)/assets-perm$', views.UserDetailView.as_view(), name='user-detail'),
name
=
'user-login-history'
),
url
(
r'^user/create$'
,
views
.
UserCreateView
.
as_view
(),
name
=
'user-create'
),
url
(
r'^user/export/'
,
url
(
r'^user/(?P<pk>[0-9]+)/update$'
,
views
.
UserUpdateView
.
as_view
(),
name
=
'user-update'
),
views
.
UserExportView
.
as_view
(),
name
=
'user-export'
),
url
(
r'^first-login/$'
,
views
.
UserFirstLoginView
.
as_view
(),
name
=
'user-first-login'
),
url
(
r'^user/import/$'
,
views
.
UserBulkImportView
.
as_view
(),
name
=
'user-import'
),
url
(
r'^user/create$'
,
views
.
UserCreateView
.
as_view
(),
name
=
'user-create'
),
url
(
r'^user/(?P<pk>[0-9]+)/update$'
,
views
.
UserUpdateView
.
as_view
(),
name
=
'user-update'
),
# User group view
# User group view
url
(
r'^user-group$'
,
views
.
UserGroupListView
.
as_view
(),
name
=
'user-group-list'
),
url
(
r'^user-group$'
,
url
(
r'^user-group/(?P<pk>[0-9]+)$'
,
views
.
UserGroupDetailView
.
as_view
(),
name
=
'user-group-detail'
),
views
.
UserGroupListView
.
as_view
(),
url
(
r'^user-group/create$'
,
views
.
UserGroupCreateView
.
as_view
(),
name
=
'user-group-create'
),
name
=
'user-group-list'
),
url
(
r'^user-group/(?P<pk>[0-9]+)/update$'
,
views
.
UserGroupUpdateView
.
as_view
(),
name
=
'user-group-update'
),
url
(
r'^user-group/(?P<pk>[0-9]+)$'
,
url
(
r'^user-group/(?P<pk>[0-9]+)/asset-permission$'
,
views
.
UserGroupAssetPermissionView
.
as_view
(),
views
.
UserGroupDetailView
.
as_view
(),
name
=
'user-group-detail'
),
url
(
r'^user-group/create$'
,
views
.
UserGroupCreateView
.
as_view
(),
name
=
'user-group-create'
),
url
(
r'^user-group/(?P<pk>[0-9]+)/update$'
,
views
.
UserGroupUpdateView
.
as_view
(),
name
=
'user-group-update'
),
url
(
r'^user-group/(?P<pk>[0-9]+)/asset-permission$'
,
views
.
UserGroupAssetPermissionView
.
as_view
(),
name
=
'user-group-asset-permission'
),
name
=
'user-group-asset-permission'
),
url
(
r'^user-group/(?P<pk>[0-9]+)/asset-permission/create$'
,
views
.
UserGroupAssetPermissionCreateView
.
as_view
(),
url
(
r'^user-group/(?P<pk>[0-9]+)/asset-permission/create$'
,
views
.
UserGroupAssetPermissionCreateView
.
as_view
(),
name
=
'user-group-asset-permission-create'
),
name
=
'user-group-asset-permission-create'
),
url
(
r'^user-group/(?P<pk>[0-9]+)/assets'
,
views
.
UserGroupGrantedAssetView
.
as_view
(),
url
(
r'^user-group/(?P<pk>[0-9]+)/assets'
,
views
.
UserGroupGrantedAssetView
.
as_view
(),
name
=
'user-group-granted-asset'
),
name
=
'user-group-granted-asset'
),
]
]
apps/users/views/__init__.py
0 → 100644
View file @
948214ca
# ~*~ coding: utf-8 ~*~
from
.login
import
*
from
.user
import
*
from
.group
import
*
apps/users/views/group.py
0 → 100644
View file @
948214ca
# ~*~ coding: utf-8 ~*~
from
__future__
import
unicode_literals
from
django
import
forms
from
django.shortcuts
import
reverse
,
redirect
from
django.utils.translation
import
ugettext
as
_
from
django.urls
import
reverse_lazy
from
django.views.generic
import
ListView
from
django.views.generic.base
import
TemplateView
from
django.views.generic.edit
import
CreateView
,
UpdateView
,
FormMixin
from
django.views.generic.detail
import
DetailView
,
SingleObjectMixin
from
common.utils
import
get_logger
from
perms.models
import
AssetPermission
from
..models
import
User
,
UserGroup
from
..utils
import
AdminUserRequiredMixin
from
..
import
forms
__all__
=
[
'UserGroupListView'
,
'UserGroupCreateView'
,
'UserGroupDetailView'
,
'UserGroupUpdateView'
,
'UserGroupAssetPermissionCreateView'
,
'UserGroupAssetPermissionView'
,
'UserGroupGrantedAssetView'
]
logger
=
get_logger
(
__name__
)
class
UserGroupListView
(
AdminUserRequiredMixin
,
TemplateView
):
template_name
=
'users/user_group_list.html'
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
UserGroupListView
,
self
)
.
get_context_data
(
**
kwargs
)
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'User group list'
)})
return
context
class
UserGroupCreateView
(
AdminUserRequiredMixin
,
CreateView
):
model
=
UserGroup
form_class
=
forms
.
UserGroupForm
template_name
=
'users/user_group_create_update.html'
success_url
=
reverse_lazy
(
'users:user-group-list'
)
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
UserGroupCreateView
,
self
)
.
get_context_data
(
**
kwargs
)
users
=
User
.
objects
.
all
()
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'Create user group'
),
'users'
:
users
})
return
context
def
form_valid
(
self
,
form
):
user_group
=
form
.
save
()
users_id_list
=
self
.
request
.
POST
.
getlist
(
'users'
,
[])
users
=
User
.
objects
.
filter
(
id__in
=
users_id_list
)
user_group
.
created_by
=
self
.
request
.
user
.
username
or
'Admin'
user_group
.
users
.
add
(
*
users
)
user_group
.
save
()
return
super
(
UserGroupCreateView
,
self
)
.
form_valid
(
form
)
class
UserGroupUpdateView
(
AdminUserRequiredMixin
,
UpdateView
):
model
=
UserGroup
form_class
=
forms
.
UserGroupForm
template_name
=
'users/user_group_create_update.html'
success_url
=
reverse_lazy
(
'users:user-group-list'
)
def
get_context_data
(
self
,
**
kwargs
):
# self.object = self.get_object()
context
=
super
(
UserGroupUpdateView
,
self
)
.
get_context_data
(
**
kwargs
)
users
=
User
.
objects
.
all
()
group_users
=
[
user
.
id
for
user
in
self
.
object
.
users
.
all
()]
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'Update User Group'
),
'users'
:
users
,
'group_users'
:
group_users
})
return
context
def
form_valid
(
self
,
form
):
user_group
=
form
.
save
()
users_id_list
=
self
.
request
.
POST
.
getlist
(
'users'
,
[])
users
=
User
.
objects
.
filter
(
id__in
=
users_id_list
)
user_group
.
users
.
clear
()
user_group
.
users
.
add
(
*
users
)
user_group
.
save
()
return
super
(
UserGroupUpdateView
,
self
)
.
form_valid
(
form
)
class
UserGroupDetailView
(
AdminUserRequiredMixin
,
DetailView
):
model
=
UserGroup
context_object_name
=
'user_group'
template_name
=
'users/user_group_detail.html'
def
get_context_data
(
self
,
**
kwargs
):
users
=
User
.
objects
.
exclude
(
id__in
=
self
.
object
.
users
.
all
())
context
=
{
'app'
:
_
(
'Users'
),
'action'
:
_
(
'User Group Detail'
),
'users'
:
users
,
}
kwargs
.
update
(
context
)
return
super
(
UserGroupDetailView
,
self
)
.
get_context_data
(
**
kwargs
)
class
UserGroupAssetPermissionView
(
AdminUserRequiredMixin
,
FormMixin
,
SingleObjectMixin
,
ListView
):
model
=
UserGroup
template_name
=
'users/user_group_asset_permission.html'
context_object_name
=
'user_group'
form_class
=
forms
.
UserPrivateAssetPermissionForm
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
(
queryset
=
UserGroup
.
objects
.
all
())
return
super
(
UserGroupAssetPermissionView
,
self
)
\
.
get
(
request
,
*
args
,
**
kwargs
)
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
'Users'
,
'action'
:
'User group asset permissions'
,
}
kwargs
.
update
(
context
)
return
super
(
UserGroupAssetPermissionView
,
self
)
\
.
get_context_data
(
**
kwargs
)
class
UserGroupAssetPermissionCreateView
(
AdminUserRequiredMixin
,
CreateView
):
form_class
=
forms
.
UserGroupPrivateAssetPermissionForm
model
=
AssetPermission
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
user_group
=
self
.
get_object
(
queryset
=
UserGroup
.
objects
.
all
())
return
redirect
(
reverse
(
'users:user-group-asset-permission'
,
kwargs
=
{
'pk'
:
user_group
.
id
}))
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
user_group
=
self
.
get_object
(
queryset
=
UserGroup
.
objects
.
all
())
return
super
(
UserGroupAssetPermissionCreateView
,
self
)
\
.
post
(
request
,
*
args
,
**
kwargs
)
def
get_form
(
self
,
form_class
=
None
):
form
=
super
(
UserGroupAssetPermissionCreateView
,
self
)
\
.
get_form
(
form_class
=
form_class
)
form
.
user_group
=
self
.
user_group
return
form
def
form_invalid
(
self
,
form
):
return
redirect
(
reverse
(
'users:user-group-asset-permission'
,
kwargs
=
{
'pk'
:
self
.
user_group
.
id
}))
def
get_success_url
(
self
):
return
reverse
(
'users:user-group-asset-permission'
,
kwargs
=
{
'pk'
:
self
.
user_group
.
id
})
class
UserGroupGrantedAssetView
(
AdminUserRequiredMixin
,
DetailView
):
model
=
User
template_name
=
'users/user_group_granted_asset.html'
context_object_name
=
'user_group'
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
(
queryset
=
UserGroup
.
objects
.
all
())
return
super
(
UserGroupGrantedAssetView
,
self
)
\
.
get
(
request
,
*
args
,
**
kwargs
)
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
'User'
,
'action'
:
'User group granted asset'
,
}
kwargs
.
update
(
context
)
return
super
(
UserGroupGrantedAssetView
,
self
)
.
get_context_data
(
**
kwargs
)
apps/users/views/login.py
0 → 100644
View file @
948214ca
# ~*~ coding: utf-8 ~*~
from
__future__
import
unicode_literals
from
django
import
forms
from
django.contrib.auth
import
login
as
auth_login
,
logout
as
auth_logout
from
django.contrib.auth.mixins
import
LoginRequiredMixin
from
django.core.files.storage
import
default_storage
from
django.http
import
HttpResponseRedirect
from
django.shortcuts
import
reverse
,
redirect
from
django.utils.decorators
import
method_decorator
from
django.utils.translation
import
ugettext
as
_
from
django.views.decorators.cache
import
never_cache
from
django.views.decorators.csrf
import
csrf_protect
from
django.views.decorators.debug
import
sensitive_post_parameters
from
django.views.generic.base
import
TemplateView
from
django.views.generic.edit
import
FormView
from
formtools.wizard.views
import
SessionWizardView
from
common.utils
import
get_object_or_none
from
..models
import
User
from
..utils
import
send_reset_password_mail
from
..hands
import
write_login_log_async
from
..
import
forms
__all__
=
[
'UserLoginView'
,
'UserLogoutView'
,
'UserForgotPasswordView'
,
'UserForgotPasswordSendmailSuccessView'
,
'UserResetPasswordView'
,
'UserResetPasswordSuccessView'
,
'UserFirstLoginView'
]
@method_decorator
(
sensitive_post_parameters
(),
name
=
'dispatch'
)
@method_decorator
(
csrf_protect
,
name
=
'dispatch'
)
@method_decorator
(
never_cache
,
name
=
'dispatch'
)
class
UserLoginView
(
FormView
):
template_name
=
'users/login.html'
form_class
=
forms
.
UserLoginForm
redirect_field_name
=
'next'
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
if
request
.
user
.
is_staff
:
return
redirect
(
self
.
get_success_url
())
return
super
(
UserLoginView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
form_valid
(
self
,
form
):
auth_login
(
self
.
request
,
form
.
get_user
())
login_ip
=
self
.
request
.
META
.
get
(
'REMOTE_ADDR'
,
''
)
user_agent
=
self
.
request
.
META
.
get
(
'HTTP_USER_AGENT'
,
''
)
write_login_log_async
.
delay
(
self
.
request
.
user
.
username
,
self
.
request
.
user
.
name
,
login_type
=
'W'
,
login_ip
=
login_ip
,
user_agent
=
user_agent
)
return
redirect
(
self
.
get_success_url
())
def
get_success_url
(
self
):
if
self
.
request
.
user
.
is_first_login
:
return
reverse
(
'users:user-first-login'
)
return
self
.
request
.
POST
.
get
(
self
.
redirect_field_name
,
self
.
request
.
GET
.
get
(
self
.
redirect_field_name
,
reverse
(
'index'
)))
@method_decorator
(
never_cache
,
name
=
'dispatch'
)
class
UserLogoutView
(
TemplateView
):
template_name
=
'flash_message_standalone.html'
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
auth_logout
(
request
)
return
super
(
UserLogoutView
,
self
)
.
get
(
request
)
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'title'
:
_
(
'Logout success'
),
'messages'
:
_
(
'Logout success, return login page'
),
'redirect_url'
:
reverse
(
'users:login'
),
'auto_redirect'
:
True
,
}
kwargs
.
update
(
context
)
return
super
(
UserLogoutView
,
self
)
.
get_context_data
(
**
kwargs
)
class
UserForgotPasswordView
(
TemplateView
):
template_name
=
'users/forgot_password.html'
def
post
(
self
,
request
):
email
=
request
.
POST
.
get
(
'email'
)
user
=
get_object_or_none
(
User
,
email
=
email
)
if
not
user
:
return
self
.
get
(
request
,
errors
=
_
(
'Email address invalid, '
'please input again'
))
else
:
send_reset_password_mail
(
user
)
return
HttpResponseRedirect
(
reverse
(
'users:forgot-password-sendmail-success'
))
class
UserForgotPasswordSendmailSuccessView
(
TemplateView
):
template_name
=
'flash_message_standalone.html'
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'title'
:
_
(
'Send reset password message'
),
'messages'
:
_
(
'Send reset password mail success, '
'login your mail box and follow it '
),
'redirect_url'
:
reverse
(
'users:login'
),
}
kwargs
.
update
(
context
)
return
super
(
UserForgotPasswordSendmailSuccessView
,
self
)
\
.
get_context_data
(
**
kwargs
)
class
UserResetPasswordSuccessView
(
TemplateView
):
template_name
=
'flash_message_standalone.html'
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'title'
:
_
(
'Reset password success'
),
'messages'
:
_
(
'Reset password success, return to login page'
),
'redirect_url'
:
reverse
(
'users:login'
),
'auto_redirect'
:
True
,
}
kwargs
.
update
(
context
)
return
super
(
UserResetPasswordSuccessView
,
self
)
\
.
get_context_data
(
**
kwargs
)
class
UserResetPasswordView
(
TemplateView
):
template_name
=
'users/reset_password.html'
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
token
=
request
.
GET
.
get
(
'token'
)
user
=
User
.
validate_reset_token
(
token
)
if
not
user
:
kwargs
.
update
({
'errors'
:
_
(
'Token invalid or expired'
)})
return
super
(
UserResetPasswordView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
password
=
request
.
POST
.
get
(
'password'
)
password_confirm
=
request
.
POST
.
get
(
'password-confirm'
)
token
=
request
.
GET
.
get
(
'token'
)
if
password
!=
password_confirm
:
return
self
.
get
(
request
,
errors
=
_
(
'Password not same'
))
user
=
User
.
validate_reset_token
(
token
)
if
not
user
:
return
self
.
get
(
request
,
errors
=
_
(
'Token invalid or expired'
))
user
.
reset_password
(
password
)
return
HttpResponseRedirect
(
reverse
(
'users:reset-password-success'
))
class
UserFirstLoginView
(
LoginRequiredMixin
,
SessionWizardView
):
template_name
=
'users/first_login.html'
form_list
=
[
forms
.
UserInfoForm
,
forms
.
UserKeyForm
]
file_storage
=
default_storage
def
dispatch
(
self
,
request
,
*
args
,
**
kwargs
):
if
request
.
user
.
is_authenticated
()
and
not
request
.
user
.
is_first_login
:
return
redirect
(
reverse
(
'index'
))
return
super
(
UserFirstLoginView
,
self
)
.
dispatch
(
request
,
*
args
,
**
kwargs
)
def
done
(
self
,
form_list
,
form_dict
,
**
kwargs
):
user
=
self
.
request
.
user
for
form
in
form_list
:
for
field
in
form
:
if
field
.
value
():
setattr
(
user
,
field
.
name
,
field
.
value
())
if
field
.
name
==
'enable_otp'
:
user
.
enable_otp
=
field
.
value
()
user
.
is_first_login
=
False
user
.
is_public_key_valid
=
True
user
.
save
()
return
redirect
(
reverse
(
'index'
))
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
UserFirstLoginView
,
self
)
.
get_context_data
(
**
kwargs
)
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'First Login'
)})
return
context
def
get_form_initial
(
self
,
step
):
user
=
self
.
request
.
user
if
step
==
'0'
:
return
{
'name'
:
user
.
name
or
user
.
username
,
'enable_otp'
:
user
.
enable_otp
or
True
,
'wechat'
:
user
.
wechat
or
''
,
'phone'
:
user
.
phone
or
''
}
return
super
(
UserFirstLoginView
,
self
)
.
get_form_initial
(
step
)
def
get_form
(
self
,
step
=
None
,
data
=
None
,
files
=
None
):
form
=
super
(
UserFirstLoginView
,
self
)
.
get_form
(
step
,
data
,
files
)
if
step
is
None
:
step
=
self
.
steps
.
current
if
step
==
'1'
:
form
.
user
=
self
.
request
.
user
return
form
apps/users/views.py
→
apps/users/views
/user
.py
View file @
948214ca
# ~*~ coding: utf-8 ~*~
# ~*~ coding: utf-8 ~*~
from
__future__
import
unicode_literals
from
__future__
import
unicode_literals
import
json
import
uuid
import
uuid
import
json
from
django.shortcuts
import
redirect
from
openpyxl
import
Workbook
from
openpyxl
import
Workbook
from
openpyxl.writer.excel
import
save_virtual_workbook
from
openpyxl.writer.excel
import
save_virtual_workbook
from
openpyxl
import
load_workbook
from
openpyxl
import
load_workbook
from
django
import
forms
from
django
import
forms
from
django.utils
import
timezone
from
django.core.cache
import
cache
from
django.core.cache
import
cache
from
django.db
import
IntegrityError
from
django.http
import
HttpResponse
,
JsonResponse
from
django.contrib.auth
import
login
as
auth_login
,
logout
as
auth_logout
from
django.contrib.auth.mixins
import
LoginRequiredMixin
from
django.contrib.messages.views
import
SuccessMessageMixin
from
django.contrib.messages.views
import
SuccessMessageMixin
from
django.core.files.storage
import
default_storage
from
django.urls
import
reverse_lazy
,
reverse
from
django.http
import
HttpResponseRedirect
,
HttpResponse
,
JsonResponse
from
django.utils
import
timezone
from
django.shortcuts
import
reverse
,
redirect
from
django.utils.decorators
import
method_decorator
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
django.u
rls
import
reverse_lazy
from
django.u
tils.decorators
import
method_decorator
from
django.views
import
View
from
django.views
import
View
from
django.views.decorators.cache
import
never_cache
from
django.views.generic
import
ListView
from
django.views.decorators.csrf
import
csrf_protect
,
csrf_exempt
from
django.views.decorators.debug
import
sensitive_post_parameters
from
django.views.generic.base
import
TemplateView
from
django.views.generic.base
import
TemplateView
from
django.views.generic.
list
import
ListView
from
django.views.generic.
edit
import
CreateView
,
UpdateView
,
FormMixin
,
\
from
django.views.generic.edit
import
CreateView
,
DeleteView
,
UpdateView
,
FormView
,
SingleObjectMixin
,
FormMixin
FormView
from
django.views.generic.detail
import
DetailView
from
django.views.generic.detail
import
DetailView
,
SingleObjectMixin
from
formtools.wizard.views
import
SessionWizardView
from
django.views.decorators.csrf
import
csrf_exempt
from
common.mixins
import
JSONResponseMixin
from
common.mixins
import
JSONResponseMixin
from
common.utils
import
get_
object_or_none
,
get_
logger
from
common.utils
import
get_logger
from
perms.models
import
AssetPermission
from
perms.models
import
AssetPermission
from
.models
import
User
,
UserGroup
from
..models
import
User
,
UserGroup
from
.utils
import
AdminUserRequiredMixin
,
user_add_success_next
,
send_reset_password_mail
from
..utils
import
AdminUserRequiredMixin
,
user_add_success_next
from
.hands
import
write_login_log_async
from
..
import
forms
from
.
import
forms
__all__
=
[
'UserListView'
,
'UserCreateView'
,
'UserDetailView'
,
'UserUpdateView'
,
'UserAssetPermissionCreateView'
,
'UserAssetPermissionView'
,
'UserGrantedAssetView'
,
'UserExportView'
,
'UserBulkImportView'
]
logger
=
get_logger
(
__name__
)
logger
=
get_logger
(
__name__
)
@method_decorator
(
sensitive_post_parameters
(),
name
=
'dispatch'
)
@method_decorator
(
csrf_protect
,
name
=
'dispatch'
)
@method_decorator
(
never_cache
,
name
=
'dispatch'
)
class
UserLoginView
(
FormView
):
template_name
=
'users/login.html'
form_class
=
forms
.
UserLoginForm
redirect_field_name
=
'next'
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
if
request
.
user
.
is_staff
:
return
redirect
(
self
.
get_success_url
())
return
super
(
UserLoginView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
form_valid
(
self
,
form
):
auth_login
(
self
.
request
,
form
.
get_user
())
login_ip
=
self
.
request
.
META
.
get
(
'REMOTE_ADDR'
,
''
)
user_agent
=
self
.
request
.
META
.
get
(
'HTTP_USER_AGENT'
,
''
)
write_login_log_async
.
delay
(
self
.
request
.
user
.
username
,
self
.
request
.
user
.
name
,
login_type
=
'W'
,
login_ip
=
login_ip
,
user_agent
=
user_agent
)
return
redirect
(
self
.
get_success_url
())
def
get_success_url
(
self
):
if
self
.
request
.
user
.
is_first_login
:
return
reverse
(
'users:user-first-login'
)
return
self
.
request
.
POST
.
get
(
self
.
redirect_field_name
,
self
.
request
.
GET
.
get
(
self
.
redirect_field_name
,
reverse
(
'index'
)))
@method_decorator
(
never_cache
,
name
=
'dispatch'
)
class
UserLogoutView
(
TemplateView
):
template_name
=
'flash_message_standalone.html'
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
auth_logout
(
request
)
return
super
(
UserLogoutView
,
self
)
.
get
(
request
)
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'title'
:
_
(
'Logout success'
),
'messages'
:
_
(
'Logout success, return login page'
),
'redirect_url'
:
reverse
(
'users:login'
),
'auto_redirect'
:
True
,
}
kwargs
.
update
(
context
)
return
super
(
UserLogoutView
,
self
)
.
get_context_data
(
**
kwargs
)
class
UserListView
(
AdminUserRequiredMixin
,
TemplateView
):
class
UserListView
(
AdminUserRequiredMixin
,
TemplateView
):
template_name
=
'users/user_list.html'
template_name
=
'users/user_list.html'
...
@@ -159,327 +107,55 @@ class UserDetailView(AdminUserRequiredMixin, DetailView):
...
@@ -159,327 +107,55 @@ class UserDetailView(AdminUserRequiredMixin, DetailView):
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
groups
=
UserGroup
.
objects
.
exclude
(
id__in
=
self
.
object
.
groups
.
all
())
groups
=
UserGroup
.
objects
.
exclude
(
id__in
=
self
.
object
.
groups
.
all
())
context
=
{
'app'
:
_
(
'Users'
),
'action'
:
_
(
'User detail'
),
'groups'
:
groups
}
kwargs
.
update
(
context
)
return
super
(
UserDetailView
,
self
)
.
get_context_data
(
**
kwargs
)
class
UserGroupListView
(
AdminUserRequiredMixin
,
TemplateView
):
template_name
=
'users/user_group_list.html'
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
UserGroupListView
,
self
)
.
get_context_data
(
**
kwargs
)
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'User group list'
)})
return
context
class
UserGroupCreateView
(
AdminUserRequiredMixin
,
CreateView
):
model
=
UserGroup
form_class
=
forms
.
UserGroupForm
template_name
=
'users/user_group_create_update.html'
success_url
=
reverse_lazy
(
'users:user-group-list'
)
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
UserGroupCreateView
,
self
)
.
get_context_data
(
**
kwargs
)
users
=
User
.
objects
.
all
()
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'Create user group'
),
'users'
:
users
})
return
context
def
form_valid
(
self
,
form
):
user_group
=
form
.
save
()
users_id_list
=
self
.
request
.
POST
.
getlist
(
'users'
,
[])
users
=
User
.
objects
.
filter
(
id__in
=
users_id_list
)
user_group
.
created_by
=
self
.
request
.
user
.
username
or
'Admin'
user_group
.
users
.
add
(
*
users
)
user_group
.
save
()
return
super
(
UserGroupCreateView
,
self
)
.
form_valid
(
form
)
class
UserGroupUpdateView
(
AdminUserRequiredMixin
,
UpdateView
):
model
=
UserGroup
form_class
=
forms
.
UserGroupForm
template_name
=
'users/user_group_create_update.html'
success_url
=
reverse_lazy
(
'users:user-group-list'
)
def
get_context_data
(
self
,
**
kwargs
):
# self.object = self.get_object()
context
=
super
(
UserGroupUpdateView
,
self
)
.
get_context_data
(
**
kwargs
)
users
=
User
.
objects
.
all
()
group_users
=
[
user
.
id
for
user
in
self
.
object
.
users
.
all
()]
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'Update User Group'
),
'users'
:
users
,
'group_users'
:
group_users
})
return
context
def
form_valid
(
self
,
form
):
user_group
=
form
.
save
()
users_id_list
=
self
.
request
.
POST
.
getlist
(
'users'
,
[])
users
=
User
.
objects
.
filter
(
id__in
=
users_id_list
)
user_group
.
users
.
clear
()
user_group
.
users
.
add
(
*
users
)
user_group
.
save
()
return
super
(
UserGroupUpdateView
,
self
)
.
form_valid
(
form
)
class
UserGroupDetailView
(
AdminUserRequiredMixin
,
DetailView
):
model
=
UserGroup
context_object_name
=
'user_group'
template_name
=
'users/user_group_detail.html'
def
get_context_data
(
self
,
**
kwargs
):
users
=
User
.
objects
.
exclude
(
id__in
=
self
.
object
.
users
.
all
())
context
=
{
context
=
{
'app'
:
_
(
'Users'
),
'app'
:
_
(
'Users'
),
'action'
:
_
(
'User Group Detail'
),
'action'
:
_
(
'User detail'
),
'users'
:
users
,
'groups'
:
groups
}
kwargs
.
update
(
context
)
return
super
(
UserGroupDetailView
,
self
)
.
get_context_data
(
**
kwargs
)
class
UserForgotPasswordView
(
TemplateView
):
template_name
=
'users/forgot_password.html'
def
post
(
self
,
request
):
email
=
request
.
POST
.
get
(
'email'
)
user
=
get_object_or_none
(
User
,
email
=
email
)
if
not
user
:
return
self
.
get
(
request
,
errors
=
_
(
'Email address invalid, input again'
))
else
:
send_reset_password_mail
(
user
)
return
HttpResponseRedirect
(
reverse
(
'users:forgot-password-sendmail-success'
))
class
UserForgotPasswordSendmailSuccessView
(
TemplateView
):
template_name
=
'flash_message_standalone.html'
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'title'
:
_
(
'Send reset password message'
),
'messages'
:
_
(
'Send reset password mail success, login your mail box and follow it '
),
'redirect_url'
:
reverse
(
'users:login'
),
}
}
kwargs
.
update
(
context
)
kwargs
.
update
(
context
)
return
super
(
UserForgotPasswordSendmailSuccessView
,
self
)
.
get_context_data
(
**
kwargs
)
return
super
(
UserDetailView
,
self
)
.
get_context_data
(
**
kwargs
)
class
UserResetPasswordSuccessView
(
TemplateView
):
template_name
=
'flash_message_standalone.html'
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'title'
:
_
(
'Reset password success'
),
'messages'
:
_
(
'Reset password success, return to login page'
),
'redirect_url'
:
reverse
(
'users:login'
),
'auto_redirect'
:
True
,
}
kwargs
.
update
(
context
)
return
super
(
UserResetPasswordSuccessView
,
self
)
.
get_context_data
(
**
kwargs
)
class
UserResetPasswordView
(
TemplateView
):
template_name
=
'users/reset_password.html'
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
token
=
request
.
GET
.
get
(
'token'
)
user
=
User
.
validate_reset_token
(
token
)
if
not
user
:
kwargs
.
update
({
'errors'
:
_
(
'Token invalid or expired'
)})
return
super
(
UserResetPasswordView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
password
=
request
.
POST
.
get
(
'password'
)
password_confirm
=
request
.
POST
.
get
(
'password-confirm'
)
token
=
request
.
GET
.
get
(
'token'
)
if
password
!=
password_confirm
:
return
self
.
get
(
request
,
errors
=
_
(
'Password not same'
))
user
=
User
.
validate_reset_token
(
token
)
if
not
user
:
return
self
.
get
(
request
,
errors
=
_
(
'Token invalid or expired'
))
user
.
reset_password
(
password
)
return
HttpResponseRedirect
(
reverse
(
'users:reset-password-success'
))
class
UserFirstLoginView
(
LoginRequiredMixin
,
SessionWizardView
):
template_name
=
'users/first_login.html'
form_list
=
[
forms
.
UserInfoForm
,
forms
.
UserKeyForm
]
file_storage
=
default_storage
def
dispatch
(
self
,
request
,
*
args
,
**
kwargs
):
if
request
.
user
.
is_authenticated
()
and
not
request
.
user
.
is_first_login
:
return
redirect
(
reverse
(
'index'
))
return
super
(
UserFirstLoginView
,
self
)
.
dispatch
(
request
,
*
args
,
**
kwargs
)
def
done
(
self
,
form_list
,
form_dict
,
**
kwargs
):
user
=
self
.
request
.
user
for
form
in
form_list
:
for
field
in
form
:
if
field
.
value
():
setattr
(
user
,
field
.
name
,
field
.
value
())
if
field
.
name
==
'enable_otp'
:
user
.
enable_otp
=
field
.
value
()
user
.
is_first_login
=
False
user
.
is_public_key_valid
=
True
user
.
save
()
return
redirect
(
reverse
(
'index'
))
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
UserFirstLoginView
,
self
)
.
get_context_data
(
**
kwargs
)
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'First Login'
)})
return
context
def
get_form_initial
(
self
,
step
):
user
=
self
.
request
.
user
if
step
==
'0'
:
return
{
'name'
:
user
.
name
or
user
.
username
,
'enable_otp'
:
user
.
enable_otp
or
True
,
'wechat'
:
user
.
wechat
or
''
,
'phone'
:
user
.
phone
or
''
}
return
super
(
UserFirstLoginView
,
self
)
.
get_form_initial
(
step
)
def
get_form
(
self
,
step
=
None
,
data
=
None
,
files
=
None
):
form
=
super
(
UserFirstLoginView
,
self
)
.
get_form
(
step
,
data
,
files
)
if
step
is
None
:
step
=
self
.
steps
.
current
if
step
==
'1'
:
form
.
user
=
self
.
request
.
user
return
form
class
UserAssetPermissionView
(
AdminUserRequiredMixin
,
FormMixin
,
SingleObjectMixin
,
ListView
):
model
=
User
template_name
=
'users/user_asset_permission.html'
context_object_name
=
'user'
form_class
=
forms
.
UserPrivateAssetPermissionForm
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
(
queryset
=
User
.
objects
.
all
())
return
super
(
UserAssetPermissionView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
'Users'
,
'action'
:
'User asset permissions'
,
}
kwargs
.
update
(
context
)
return
super
(
UserAssetPermissionView
,
self
)
.
get_context_data
(
**
kwargs
)
class
UserGroupAssetPermissionView
(
AdminUserRequiredMixin
,
FormMixin
,
SingleObjectMixin
,
ListView
):
model
=
UserGroup
template_name
=
'users/user_group_asset_permission.html'
context_object_name
=
'user_group'
form_class
=
forms
.
UserPrivateAssetPermissionForm
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
(
queryset
=
UserGroup
.
objects
.
all
())
return
super
(
UserGroupAssetPermissionView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
'Users'
,
'action'
:
'User group asset permissions'
,
}
kwargs
.
update
(
context
)
return
super
(
UserGroupAssetPermissionView
,
self
)
.
get_context_data
(
**
kwargs
)
class
UserAssetPermissionCreateView
(
AdminUserRequiredMixin
,
CreateView
):
form_class
=
forms
.
UserPrivateAssetPermissionForm
model
=
AssetPermission
@method_decorator
(
csrf_exempt
,
name
=
'dispatch'
)
class
UserExportView
(
View
):
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
user
=
self
.
get_object
(
queryset
=
User
.
objects
.
all
())
spm
=
request
.
GET
.
get
(
'spm'
,
''
)
return
redirect
(
reverse
(
'users:user-asset-permission'
,
kwargs
=
{
'pk'
:
user
.
id
}))
users_id
=
cache
.
get
(
spm
)
if
not
users_id
and
not
isinstance
(
users_id
,
list
):
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
return
HttpResponse
(
'May be expired'
,
status
=
404
)
self
.
user
=
self
.
get_object
(
queryset
=
User
.
objects
.
all
())
return
super
(
UserAssetPermissionCreateView
,
self
)
.
post
(
request
,
*
args
,
**
kwargs
)
def
get_form
(
self
,
form_class
=
None
):
form
=
super
(
UserAssetPermissionCreateView
,
self
)
.
get_form
(
form_class
=
form_class
)
form
.
user
=
self
.
user
return
form
def
form_invalid
(
self
,
form
):
return
redirect
(
reverse
(
'users:user-asset-permission'
,
kwargs
=
{
'pk'
:
self
.
user
.
id
}))
def
get_success_url
(
self
):
return
reverse
(
'users:user-asset-permission'
,
kwargs
=
{
'pk'
:
self
.
user
.
id
})
users
=
User
.
objects
.
filter
(
id__in
=
users_id
)
wb
=
Workbook
()
ws
=
wb
.
active
ws
.
title
=
'User'
header
=
[
"name"
,
'username'
,
'email'
,
'groups'
,
"role"
,
"phone"
,
"wechat"
,
"comment"
]
ws
.
append
(
header
)
class
UserGroupAssetPermissionCreateView
(
AdminUserRequiredMixin
,
CreateView
):
for
user
in
users
:
form_class
=
forms
.
UserGroupPrivateAssetPermissionForm
ws
.
append
([
user
.
name
,
user
.
username
,
user
.
email
,
model
=
AssetPermission
','
.
join
([
group
.
name
for
group
in
user
.
groups
.
all
()]),
user
.
role
,
user
.
phone
,
user
.
wechat
,
user
.
comment
])
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
filename
=
'users-{}.xlsx'
.
format
(
user_group
=
self
.
get_object
(
queryset
=
UserGroup
.
objects
.
all
())
timezone
.
localtime
(
timezone
.
now
())
.
strftime
(
'
%
Y-
%
m-
%
d_
%
H-
%
M-
%
S'
))
return
redirect
(
reverse
(
'users:user-group-asset-permission'
,
kwargs
=
{
'pk'
:
user_group
.
id
}))
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
,
*
args
,
**
kwargs
):
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
user_group
=
self
.
get_object
(
queryset
=
UserGroup
.
objects
.
all
())
try
:
return
super
(
UserGroupAssetPermissionCreateView
,
self
)
.
post
(
request
,
*
args
,
**
kwargs
)
users_id
=
json
.
loads
(
request
.
body
)
.
get
(
'users_id'
,
[])
except
ValueError
:
def
get_form
(
self
,
form_class
=
None
):
return
HttpResponse
(
'Json object not valid'
,
status
=
400
)
form
=
super
(
UserGroupAssetPermissionCreateView
,
self
)
.
get_form
(
form_class
=
form_class
)
spm
=
uuid
.
uuid4
()
.
get_hex
()
form
.
user_group
=
self
.
user_group
cache
.
set
(
spm
,
users_id
,
300
)
return
form
url
=
reverse
(
'users:user-export'
)
+
'?spm=
%
s'
%
spm
return
JsonResponse
({
'redirect'
:
url
})
def
form_invalid
(
self
,
form
):
return
redirect
(
reverse
(
'users:user-group-asset-permission'
,
kwargs
=
{
'pk'
:
self
.
user_group
.
id
}))
def
get_success_url
(
self
):
return
reverse
(
'users:user-group-asset-permission'
,
kwargs
=
{
'pk'
:
self
.
user_group
.
id
})
class
UserGrantedAssetView
(
AdminUserRequiredMixin
,
DetailView
):
model
=
User
template_name
=
'users/user_granted_asset.html'
context_object_name
=
'user'
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
(
queryset
=
User
.
objects
.
all
())
return
super
(
UserGrantedAssetView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
'User'
,
'action'
:
'User granted asset'
,
}
kwargs
.
update
(
context
)
return
super
(
UserGrantedAssetView
,
self
)
.
get_context_data
(
**
kwargs
)
class
UserGroupGrantedAssetView
(
AdminUserRequiredMixin
,
DetailView
):
model
=
User
template_name
=
'users/user_group_granted_asset.html'
context_object_name
=
'user_group'
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
(
queryset
=
UserGroup
.
objects
.
all
())
return
super
(
UserGroupGrantedAssetView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
'User'
,
'action'
:
'User group granted asset'
,
}
kwargs
.
update
(
context
)
return
super
(
UserGroupGrantedAssetView
,
self
)
.
get_context_data
(
**
kwargs
)
class
BulkImportUser
View
(
AdminUserRequiredMixin
,
JSONResponseMixin
,
FormView
):
class
UserBulkImport
View
(
AdminUserRequiredMixin
,
JSONResponseMixin
,
FormView
):
form_class
=
forms
.
FileForm
form_class
=
forms
.
FileForm
def
form_invalid
(
self
,
form
):
def
form_invalid
(
self
,
form
):
...
@@ -526,7 +202,7 @@ class BulkImportUserView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
...
@@ -526,7 +202,7 @@ class BulkImportUserView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
user
=
User
.
objects
.
create
(
**
user_dict
)
user
=
User
.
objects
.
create
(
**
user_dict
)
user_add_success_next
(
user
)
user_add_success_next
(
user
)
created
.
append
(
user_dict
[
'username'
])
created
.
append
(
user_dict
[
'username'
])
except
IntegrityError
as
e
:
except
User
.
IntegrityError
as
e
:
user
=
User
.
objects
.
filter
(
username
=
user_dict
[
'username'
])
user
=
User
.
objects
.
filter
(
username
=
user_dict
[
'username'
])
if
not
user
:
if
not
user
:
failed
.
append
(
user_dict
[
'username'
])
failed
.
append
(
user_dict
[
'username'
])
...
@@ -551,43 +227,74 @@ class BulkImportUserView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
...
@@ -551,43 +227,74 @@ class BulkImportUserView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
'failed'
:
failed
,
'failed'
:
failed
,
'failed_info'
:
'Failed {}'
.
format
(
len
(
failed
)),
'failed_info'
:
'Failed {}'
.
format
(
len
(
failed
)),
'valid'
:
True
,
'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
)
return
self
.
render_json_response
(
data
)
@method_decorator
(
csrf_exempt
,
name
=
'dispatch'
)
class
UserAssetPermissionView
(
AdminUserRequiredMixin
,
FormMixin
,
class
UserExportView
(
View
):
SingleObjectMixin
,
ListView
):
model
=
User
template_name
=
'users/user_asset_permission.html'
context_object_name
=
'user'
form_class
=
forms
.
UserPrivateAssetPermissionForm
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
spm
=
request
.
GET
.
get
(
'spm'
,
''
)
self
.
object
=
self
.
get_object
(
queryset
=
User
.
objects
.
all
())
users_id
=
cache
.
get
(
spm
)
return
super
(
UserAssetPermissionView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
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
)
def
get_context_data
(
self
,
**
kwargs
):
wb
=
Workbook
()
context
=
{
ws
=
wb
.
active
'app'
:
'Users'
,
ws
.
title
=
'User'
'action'
:
'User asset permissions'
,
header
=
[
"name"
,
'username'
,
'email'
,
'groups'
,
"role"
,
"phone"
,
"wechat"
,
"comment"
]
}
ws
.
append
(
header
)
kwargs
.
update
(
context
)
return
super
(
UserAssetPermissionView
,
self
)
.
get_context_data
(
**
kwargs
)
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
])
filename
=
'users-{}.xlsx'
.
format
(
timezone
.
localtime
(
timezone
.
now
())
.
strftime
(
'
%
Y-
%
m-
%
d_
%
H-
%
M-
%
S'
))
class
UserAssetPermissionCreateView
(
AdminUserRequiredMixin
,
CreateView
):
response
=
HttpResponse
(
save_virtual_workbook
(
wb
),
content_type
=
'applications/vnd.ms-excel'
)
form_class
=
forms
.
UserPrivateAssetPermissionForm
response
[
'Content-Disposition'
]
=
'attachment; filename="
%
s"'
%
filename
model
=
AssetPermission
return
response
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
user
=
self
.
get_object
(
queryset
=
User
.
objects
.
all
())
return
redirect
(
reverse
(
'users:user-asset-permission'
,
kwargs
=
{
'pk'
:
user
.
id
}))
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
try
:
self
.
user
=
self
.
get_object
(
queryset
=
User
.
objects
.
all
())
users_id
=
json
.
loads
(
request
.
body
)
.
get
(
'users_id'
,
[])
return
super
(
UserAssetPermissionCreateView
,
self
)
\
except
ValueError
:
.
post
(
request
,
*
args
,
**
kwargs
)
return
HttpResponse
(
'Json object not valid'
,
status
=
400
)
spm
=
uuid
.
uuid4
()
.
get_hex
()
def
get_form
(
self
,
form_class
=
None
):
cache
.
set
(
spm
,
users_id
,
300
)
form
=
super
(
UserAssetPermissionCreateView
,
self
)
\
url
=
reverse
(
'users:user-export'
)
+
'?spm=
%
s'
%
spm
.
get_form
(
form_class
=
form_class
)
return
JsonResponse
({
'redirect'
:
url
})
form
.
user
=
self
.
user
return
form
def
form_invalid
(
self
,
form
):
return
redirect
(
reverse
(
'users:user-asset-permission'
,
kwargs
=
{
'pk'
:
self
.
user
.
id
}))
def
get_success_url
(
self
):
return
reverse
(
'users:user-asset-permission'
,
kwargs
=
{
'pk'
:
self
.
user
.
id
})
class
UserGrantedAssetView
(
AdminUserRequiredMixin
,
DetailView
):
model
=
User
template_name
=
'users/user_granted_asset.html'
context_object_name
=
'user'
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
(
queryset
=
User
.
objects
.
all
())
return
super
(
UserGrantedAssetView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
'User'
,
'action'
:
'User granted asset'
,
}
kwargs
.
update
(
context
)
return
super
(
UserGrantedAssetView
,
self
)
.
get_context_data
(
**
kwargs
)
\ No newline at end of file
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