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
Show whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
869 additions
and
618 deletions
+869
-618
api.py
apps/applications/api.py
+12
-9
serializers.py
apps/applications/serializers.py
+4
-2
forms.py
apps/assets/forms.py
+23
-28
serializers.py
apps/assets/serializers.py
+9
-3
system_user_create_update.html
apps/assets/templates/assets/system_user_create_update.html
+43
-15
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
+45
-13
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
+39
-19
api.py
apps/users/api.py
+16
-13
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):
def
create
(
self
,
request
,
*
args
,
**
kwargs
):
name
=
request
.
data
.
get
(
'name'
,
''
)
remote_addr
=
request
.
META
.
get
(
'X-Real-IP'
)
or
request
.
META
.
get
(
'REMOTE_ADDR'
)
serializer
=
self
.
serializer_class
(
data
=
{
'name'
:
name
,
'remote_addr'
:
remote_addr
})
remote_addr
=
request
.
META
.
get
(
'X-Real-IP'
)
or
\
request
.
META
.
get
(
'REMOTE_ADDR'
)
serializer
=
self
.
serializer_class
(
data
=
{
'name'
:
name
,
'remote_addr'
:
remote_addr
})
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
():
terminal
=
serializer
.
save
()
app_user
,
access_key
=
terminal
.
create_related_app_user
()
data
=
{}
data
[
'
applications
'
]
=
copy
.
deepcopy
(
serializer
.
data
)
data
[
'
terminal
'
]
=
copy
.
deepcopy
(
serializer
.
data
)
data
[
'user'
]
=
app_user
.
to_json
()
data
[
'access_key_id'
]
=
access_key
.
id
data
[
'access_key_secret'
]
=
access_key
.
secret
...
...
@@ -54,11 +57,11 @@ class TerminalViewSet(viewsets.ModelViewSet):
def
create
(
self
,
request
,
*
args
,
**
kwargs
):
return
Response
({
'msg'
:
'Use register view except that'
},
status
=
404
)
def
destroy
(
self
,
request
,
*
args
,
**
kwargs
):
instance
=
self
.
get_object
()
if
instance
.
user
is
not
None
:
instance
.
user
.
delete
()
return
super
(
TerminalViewSet
,
self
)
.
destroy
(
request
,
*
args
,
**
kwargs
)
#
def destroy(self, request, *args, **kwargs):
#
instance = self.get_object()
#
if instance.user is not None:
#
instance.user.delete()
#
return super(TerminalViewSet, self).destroy(request, *args, **kwargs)
class
TerminalHeatbeatViewSet
(
viewsets
.
ModelViewSet
):
...
...
apps/applications/serializers.py
View file @
948214ca
...
...
@@ -14,8 +14,9 @@ class TerminalSerializer(serializers.ModelSerializer):
class
Meta
:
model
=
Terminal
fields
=
[
'id'
,
'name'
,
'remote_addr'
,
'type'
,
'url'
,
'comment'
,
'is_accepted'
,
'is_active'
,
'get_type_display'
,
'proxy_online'
,
'is_alive'
]
fields
=
[
'id'
,
'name'
,
'remote_addr'
,
'type'
,
'url'
,
'comment'
,
'is_accepted'
,
'is_active'
,
'get_type_display'
,
'proxy_online'
,
'is_alive'
]
@staticmethod
def
get_proxy_online
(
obj
):
...
...
@@ -31,6 +32,7 @@ class TerminalSerializer(serializers.ModelSerializer):
class
TerminalHeatbeatSerializer
(
serializers
.
ModelSerializer
):
date_start
=
serializers
.
DateTimeField
class
Meta
:
model
=
TerminalHeatbeat
...
...
apps/assets/forms.py
View file @
948214ca
...
...
@@ -214,23 +214,9 @@ class AdminUserForm(forms.ModelForm):
class
SystemUserForm
(
forms
.
ModelForm
):
# Admin user assets define, let user select, save it in form not in view
assets
=
forms
.
ModelMultipleChoiceField
(
queryset
=
Asset
.
objects
.
all
(),
label
=
_
(
'Asset'
),
required
=
False
,
widget
=
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Select assets'
)})
)
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
)
auto_generate_key
=
forms
.
BooleanField
(
initial
=
True
,
required
=
False
)
# Form field name can not start with `_`, so redefine it,
password
=
forms
.
CharField
(
widget
=
forms
.
PasswordInput
,
max_length
=
100
,
min_length
=
8
,
strip
=
True
,
help_text
=
_
(
'If also set private key, use that first'
),
required
=
False
)
password
=
forms
.
CharField
(
widget
=
forms
.
PasswordInput
,
max_length
=
100
,
min_length
=
8
,
strip
=
True
)
# Need use upload private key file except paste private key content
private_key_file
=
forms
.
FileField
(
required
=
False
)
...
...
@@ -242,22 +228,13 @@ class SystemUserForm(forms.ModelForm):
initial
[
'asset_groups'
]
=
kwargs
[
'instance'
]
.
asset_groups
.
all
()
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
):
# Because we define custom field, so we need rewrite :method: `save`
system_user
=
super
(
SystemUserForm
,
self
)
.
save
(
commit
=
commit
)
password
=
self
.
cleaned_data
[
'password'
]
private_key_file
=
self
.
cleaned_data
[
'private_key_file'
]
if
system_user
.
auth_method
==
'P'
:
if
password
:
system_user
.
password
=
password
print
(
password
)
...
...
@@ -268,11 +245,30 @@ class SystemUserForm(forms.ModelForm):
system_user
.
save
()
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
:
model
=
SystemUser
fields
=
[
'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
=
{
'name'
:
forms
.
TextInput
(
attrs
=
{
'placeholder'
:
_
(
'Name'
)}),
...
...
@@ -282,7 +278,6 @@ class SystemUserForm(forms.ModelForm):
'name'
:
'* required'
,
'username'
:
'* required'
,
'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):
return
fields
class
AssetSystemUserSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
SystemUser
fields
=
(
'id'
,
'name'
,
'username'
,
'protocol'
,
'auth_method'
,
'comment'
)
class
SystemUserUpdateAssetsSerializer
(
serializers
.
ModelSerializer
):
assets
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
queryset
=
Asset
.
objects
.
all
())
...
...
@@ -145,13 +151,13 @@ class AssetSerializer(BulkSerializerMixin, 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
()
system_users_join
=
serializers
.
SerializerMethodField
()
class
Meta
(
object
):
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"
)
@staticmethod
...
...
@@ -163,7 +169,7 @@ class AssetGrantedSerializer(serializers.ModelSerializer):
@staticmethod
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
):
...
...
apps/assets/templates/assets/system_user_create_update.html
View file @
948214ca
...
...
@@ -27,23 +27,31 @@
</div>
</div>
<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=
""
>
{% csrf_token %}
<h3>
{% trans 'Basic' %}
</h3>
{{ form.name|bootstrap_horizontal }}
{{ form.username|bootstrap_horizontal }}
{{ form.protocol|bootstrap_horizontal }}
<h3>
{% trans 'Auth' %}
</h3>
{{ form.auth_method|bootstrap_horizontal }}
<div
class=
"password-auth hidden"
>
{{ form.password|bootstrap_horizontal }}
</div>
<div
class=
"public-key-auth"
>
<div
class=
"form-group"
>
<label
for=
"{{ form.auto_generate_key.id_for_label }}"
class=
"col-sm-2 control-label"
>
{% trans 'Auto generate key' %}
</label>
<div
class=
"col-sm-8"
>
{{ form.auto_generate_key}}
</div>
</div>
{{ form.password|bootstrap_horizontal }}
<div>
{{ form.private_key_file|bootstrap_horizontal }}
<div
class=
"form-group"
>
<label
for=
"{{ form.as_default.id_for_label }}"
class=
"col-sm-2 control-label"
>
{% trans 'As default' %}
</label>
<div
class=
"col-sm-8"
>
{{ form.as_default}}
</div>
</div>
<div
class=
"form-group"
>
...
...
@@ -52,20 +60,12 @@
{{ form.auto_push}}
</div>
</div>
<div
class=
"form-group"
>
<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 }}
<h3>
{% trans 'Other' %}
</h3>
{{ form.sudo|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }}
{{ form.home|bootstrap_horizontal }}
{{ form.shell|bootstrap_horizontal }}
{{ form.uid|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }}
<div
class=
"form-group"
>
<div
class=
"col-sm-4 col-sm-offset-2"
>
<button
class=
"btn btn-white"
type=
"reset"
>
{% trans 'Reset' %}
</button>
...
...
@@ -81,8 +81,36 @@
{% endblock %}
{% block custom_foot_js %}
<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
()
{
$
(
'.select2'
).
select2
();
authMethodDisplay
();
$
(
auth_method
).
change
(
function
()
{
authMethodDisplay
();
});
$
(
auto_generate_key
).
change
(
function
()
{
authMethodDisplay
();
});
if
(
$
(
'#'
+
'{{ form.protocol.id_for_label }}'
).
val
()
==
'telnet'
)
{
$
(
'#'
+
'{{ 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
kwargs
.
update
(
context
)
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
):
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
from
rest_framework
import
generics
,
viewsets
from
rest_framework.views
import
APIView
,
Response
from
rest_framework_bulk
import
BulkModelViewSet
from
.
import
models
,
serializers
from
.hands
import
IsSuperUserOrAppUser
,
Terminal
,
IsAppUser
...
...
@@ -51,13 +52,3 @@ class CommandLogViewSet(viewsets.ModelViewSet):
serializer_class
=
serializers
.
CommandLogSerializer
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):
username
=
models
.
CharField
(
max_length
=
20
,
verbose_name
=
_
(
'Username'
))
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_city
=
models
.
CharField
(
max_length
=
100
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Login city'
))
user_agent
=
models
.
CharField
(
max_length
=
100
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'User agent'
))
login_city
=
models
.
CharField
(
max_length
=
100
,
blank
=
True
,
null
=
True
,
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'
))
class
Meta
:
...
...
@@ -66,7 +69,8 @@ class ProxyLog(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
=
models
.
CharField
(
max_length
=
1000
,
blank
=
True
)
output
=
models
.
TextField
(
blank
=
True
)
...
...
@@ -78,7 +82,8 @@ class CommandLog(models.Model):
@property
def
output_decode
(
self
):
try
:
return
base64
.
b64decode
(
self
.
output
)
.
replace
(
'
\n
'
,
'<br />'
)
return
base64
.
b64decode
(
self
.
output
)
.
decode
(
'utf-8'
)
\
.
replace
(
'
\n
'
,
'<br />'
)
except
UnicodeDecodeError
:
return
'UnicodeDecodeError'
...
...
apps/audits/serializers.py
View file @
948214ca
...
...
@@ -13,8 +13,9 @@ class ProxyLogSerializer(serializers.ModelSerializer):
class
Meta
:
model
=
models
.
ProxyLog
fields
=
[
'id'
,
'name'
,
'username'
,
'hostname'
,
'ip'
,
'system_user'
,
'login_type'
,
'terminal'
,
'log_file'
,
'was_failed'
,
'is_finished'
,
'date_start'
,
'date_finished'
,
'time'
,
fields
=
[
'id'
,
'name'
,
'username'
,
'hostname'
,
'ip'
,
'system_user'
,
'login_type'
,
'terminal'
,
'log_file'
,
'was_failed'
,
'is_finished'
,
'date_start'
,
'date_finished'
,
'time'
,
'command_length'
,
"commands_dict"
]
@staticmethod
...
...
@@ -32,3 +33,4 @@ class ProxyLogSerializer(serializers.ModelSerializer):
class
CommandLogSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
models
.
CommandLog
fields
=
'__all__'
apps/audits/templates/audits/command_log_list.html
View file @
948214ca
...
...
@@ -83,7 +83,7 @@
<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>
{{ command.datetime }}
</td>
<td>
{{ command.output_decode
|safe }}
</td>
<td>
{{ command.output_decode|safe }}
</td>
</tr>
{% endfor %}
</tbody>
...
...
apps/audits/templates/audits/proxy_log_detail.html
View file @
948214ca
...
...
@@ -52,7 +52,7 @@
<tr>
<td>
{{ command.command_no }}
</td>
<td>
{{ command.command }}
</td>
<td>
{{ command.output_decode
|safe }}
</td>
<td>
{{ command.output_decode|safe }}
</td>
<td>
{{ command.datetime }}
</td>
</tr>
{% endfor %}
...
...
@@ -68,30 +68,6 @@
</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>
...
...
apps/audits/views.py
View file @
948214ca
...
...
@@ -14,17 +14,16 @@ from .models import ProxyLog, CommandLog, LoginLog
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
):
model
=
ProxyLog
template_name
=
'audits/proxy_log_list.html'
context_object_name
=
'proxy_log_list'
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
.
keyword
=
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
self
.
username
=
username
=
self
.
request
.
GET
.
get
(
'username'
,
''
)
...
...
@@ -37,7 +36,8 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
date_from
=
timezone
.
datetime
.
strptime
(
date_from_s
,
'
%
m/
%
d/
%
Y'
)
self
.
queryset
=
self
.
queryset
.
filter
(
date_start__gt
=
date_from
)
if
date_to_s
:
date_to
=
timezone
.
datetime
.
strptime
(
date_to_s
+
' 23:59:59'
,
'
%
m/
%
d/
%
Y
%
H:
%
M:
%
S'
)
date_to
=
timezone
.
datetime
.
strptime
(
date_to_s
+
' 23:59:59'
,
'
%
m/
%
d/
%
Y
%
H:
%
M:
%
S'
)
self
.
queryset
=
self
.
queryset
.
filter
(
date_start__lt
=
date_to
)
if
username
:
self
.
queryset
=
self
.
queryset
.
filter
(
username
=
username
)
...
...
@@ -54,7 +54,6 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
return
self
.
queryset
def
get_context_data
(
self
,
**
kwargs
):
print
(
self
.
date_to_s
)
context
=
{
'app'
:
_
(
'Audits'
),
'action'
:
_
(
'Proxy log list'
),
...
...
@@ -110,6 +109,9 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
context_object_name
=
'command_list'
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
.
keyword
=
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
self
.
sort
=
sort
=
self
.
request
.
GET
.
get
(
'sort'
,
'-datetime'
)
...
...
@@ -161,6 +163,9 @@ class LoginLogListView(AdminUserRequiredMixin, ListView):
context_object_name
=
'login_log_list'
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
.
keyword
=
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
self
.
username
=
username
=
self
.
request
.
GET
.
get
(
'username'
,
''
)
...
...
apps/common/celery.py
View file @
948214ca
...
...
@@ -16,5 +16,6 @@ app = Celery('jumpserver')
# Using a string here means the worker will not have to
# pickle the object when using Windows.
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 ~*~
#
from
django.shortcuts
import
get_object_or_404
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
import
viewsets
from
users.permissions
import
IsValidUser
,
IsSuperUser
from
users.permissions
import
IsValidUser
,
IsSuperUser
,
IsAppUser
from
common.utils
import
get_object_or_none
from
.utils
import
get_user_granted_assets
,
get_user_granted_asset_groups
,
get_user_asset_permissions
,
\
get_user_group_asset_permissions
,
get_user_group_granted_assets
,
get_user_group_granted_asset_groups
from
.utils
import
get_user_granted_assets
,
get_user_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
.hands
import
AssetGrantedSerializer
,
User
,
UserGroup
,
AssetGroup
,
Asset
,
AssetGroup
,
AssetGroupSerializer
from
.hands
import
AssetGrantedSerializer
,
User
,
UserGroup
,
AssetGroup
,
Asset
,
\
AssetGroup
,
AssetGroupSerializer
,
SystemUser
from
.
import
serializers
...
...
@@ -80,11 +82,12 @@ class UserGrantedAssetsApi(ListAPIView):
def
get_queryset
(
self
):
user_id
=
self
.
kwargs
.
get
(
'pk'
,
''
)
queryset
=
[]
if
user_id
:
user
=
get_object_or_404
(
User
,
id
=
user_id
)
queryset
=
get_user_granted_assets
(
user
)
else
:
queryset
=
[]
for
k
,
v
in
get_user_granted_assets
(
user
)
.
items
():
k
.
system_users_granted
=
v
queryset
.
append
(
k
)
return
queryset
...
...
@@ -104,19 +107,26 @@ class UserGrantedAssetGroupsApi(ListAPIView):
class
MyGrantedAssetsApi
(
ListAPIView
):
"""授权给用户的资产列表
[{'hostname': 'x','ip': 'x', ..,
'system_users_granted': [{'name': 'x', .}, ...]
"""
permission_classes
=
(
IsValidUser
,)
serializer_class
=
AssetGrantedSerializer
def
get_queryset
(
self
):
queryset
=
[]
user
=
self
.
request
.
user
if
user
:
queryset
=
get_user_granted_assets
(
user
)
else
:
queryset
=
[]
for
asset
,
system_users
in
get_user_granted_assets
(
user
)
.
items
():
asset
.
system_users_granted
=
system_users
queryset
.
append
(
asset
)
return
queryset
class
MyGrantedAssetsGroupsApi
(
APIView
):
"""授权给用户的资产组列表, 非直接通过授权规则授权的资产组列表, 而是授权资产的所有
资产组之和"""
permission_classes
=
(
IsValidUser
,)
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
...
...
@@ -141,6 +151,7 @@ class MyGrantedAssetsGroupsApi(APIView):
class
MyAssetGroupAssetsApi
(
ListAPIView
):
"""授权用户资产组下的资产列表, 非该资产组的所有资产,而是被授权的"""
permission_classes
=
(
IsValidUser
,)
serializer_class
=
AssetGrantedSerializer
...
...
@@ -152,8 +163,9 @@ class MyAssetGroupAssetsApi(ListAPIView):
if
user
and
asset_group
:
assets
=
get_user_granted_assets
(
user
)
for
asset
in
assets
:
if
asset_group
in
asset
.
groups
.
all
():
for
asset
in
asset_group
.
assets
.
all
():
if
asset
in
assets
:
asset
.
system_users_granted
=
assets
[
asset
]
queryset
.
append
(
asset
)
return
queryset
...
...
@@ -186,3 +198,23 @@ class UserGroupGrantedAssetGroupsApi(ListAPIView):
else
:
queryset
=
[]
return
queryset
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
class
AssetPermissionSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
AssetPermission
fields
=
'__all__'
class
UserAssetPermissionSerializer
(
AssetPermissionSerializer
):
...
...
@@ -23,4 +24,3 @@ class UserAssetPermissionSerializer(AssetPermissionSerializer):
else
:
return
False
apps/perms/urls/api_urls.py
View file @
948214ca
...
...
@@ -7,30 +7,50 @@ from .. import api
app_name
=
'perms'
router
=
routers
.
DefaultRouter
()
router
.
register
(
'v1/asset-permissions'
,
api
.
AssetPermissionViewSet
,
'asset-permission'
)
router
.
register
(
'v1/asset-permissions'
,
api
.
AssetPermissionViewSet
,
'asset-permission'
)
urlpatterns
=
[
url
(
r'^v1/user/my/assets/$'
,
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
(),
# 用户可以使用自己的Token或其它认证查看自己授权的资产,资产组等
url
(
r'^v1/user/my/assets/$'
,
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'
),
# 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]+)/asset-groups/$'
,
api
.
UserGrantedAssetGroupsApi
.
as_view
(),
# 查询某个用户授权的资产和资产组
url
(
r'^v1/user/(?P<pk>[0-9]+)/assets/$'
,
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'
),
# 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]+)/asset-groups/$'
,
api
.
UserGroupGrantedAssetGroupsApi
.
as_view
(),
# 查询某个用户组授权的资产和资产组
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]+)/asset-groups/$'
,
api
.
UserGroupGrantedAssetGroupsApi
.
as_view
(),
name
=
'user-group-asset-groups'
),
# Revoke permission api
url
(
r'^v1/asset-permissions/user/revoke/'
,
api
.
RevokeUserAssetPermission
.
as_view
(),
# 回收用户或用户组授权
url
(
r'^v1/asset-permissions/user/revoke/$'
,
api
.
RevokeUserAssetPermission
.
as_view
(),
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'
),
# 验证用户是否有某个资产和系统用户的权限
url
(
r'v1/asset-permission/user/validate/$'
,
api
.
ValidateUserAssetPermissionView
.
as_view
(),
name
=
'validate-user-asset-permission'
)
]
urlpatterns
+=
router
.
urls
...
...
apps/perms/utils.py
View file @
948214ca
...
...
@@ -37,6 +37,8 @@ def get_user_group_granted_assets(user_group):
if
not
asset_permission
.
is_valid
:
continue
for
asset
in
asset_permission
.
get_granted_assets
():
if
not
asset
.
is_active
:
continue
if
asset
in
assets
:
assets
[
asset
]
|=
set
(
asset_permission
.
system_users
.
all
())
else
:
...
...
@@ -127,6 +129,8 @@ def get_user_granted_assets_direct(user):
if
not
asset_permission
.
is_valid
:
continue
for
asset
in
asset_permission
.
get_granted_assets
():
if
not
asset
.
is_active
:
continue
if
asset
in
assets
:
assets
[
asset
]
|=
set
(
asset_permission
.
system_users
.
all
())
else
:
...
...
@@ -147,12 +151,13 @@ def get_user_granted_assets_inherit_from_user_groups(user):
for
user_group
in
user_groups
:
assets_inherited
=
get_user_group_granted_assets
(
user_group
)
for
asset
in
assets_inherited
:
if
not
asset
.
is_active
:
continue
if
asset
in
assets
:
assets
[
asset
]
|=
assets_inherited
[
asset
]
else
:
setattr
(
asset
,
'inherited'
,
True
)
assets
[
asset
]
=
assets_inherited
[
asset
]
return
assets
...
...
@@ -167,6 +172,8 @@ def get_user_granted_assets(user):
assets
=
assets_inherited
for
asset
in
assets_direct
:
if
not
asset
.
is_active
:
continue
if
asset
in
assets
:
assets
[
asset
]
|=
assets_direct
[
asset
]
else
:
...
...
apps/perms/views.py
View file @
948214ca
...
...
@@ -39,7 +39,8 @@ class AssetPermissionListView(AdminUserRequiredMixin, ListView):
self
.
sort
=
sort
=
self
.
request
.
GET
.
get
(
'sort'
,
'-date_created'
)
if
keyword
:
self
.
queryset
=
self
.
queryset
.
filter
(
Q
(
users__name__contains
=
keyword
)
|
self
.
queryset
=
self
.
queryset
\
.
filter
(
Q
(
users__name__contains
=
keyword
)
|
Q
(
users__username__contains
=
keyword
)
|
Q
(
user_groups__name__contains
=
keyword
)
|
Q
(
assets__ip__contains
=
keyword
)
|
...
...
@@ -54,7 +55,9 @@ class AssetPermissionListView(AdminUserRequiredMixin, ListView):
return
self
.
queryset
class
AssetPermissionCreateView
(
AdminUserRequiredMixin
,
SuccessMessageMixin
,
CreateView
):
class
AssetPermissionCreateView
(
AdminUserRequiredMixin
,
SuccessMessageMixin
,
CreateView
):
model
=
AssetPermission
form_class
=
AssetPermissionForm
template_name
=
'perms/asset_permission_create_update.html'
...
...
@@ -69,11 +72,11 @@ class AssetPermissionCreateView(AdminUserRequiredMixin, SuccessMessageMixin, Cre
return
super
(
AssetPermissionCreateView
,
self
)
.
get_context_data
(
**
kwargs
)
def
get_success_message
(
self
,
cleaned_data
):
success_message
=
_
(
'Create asset permission <a href="
%
s">
%
s </a> successfully.'
%
(
reverse_lazy
(
'perms:asset-permission-detail'
,
kwargs
=
{
'pk'
:
self
.
object
.
pk
})
,
self
.
object
.
name
,
))
success_message
=
_
(
'Create asset permission <a href="
%
s">
%
s </a> '
'successfully.'
%
(
reverse_lazy
(
'perms:asset-permission-detail'
,
kwargs
=
{
'pk'
:
self
.
object
.
pk
})
,
self
.
object
.
name
,
))
return
success_message
...
...
@@ -81,7 +84,8 @@ class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
model
=
AssetPermission
form_class
=
AssetPermissionForm
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
):
context
=
{
...
...
@@ -92,7 +96,8 @@ class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView):
return
super
(
AssetPermissionUpdateView
,
self
)
.
get_context_data
(
**
kwargs
)
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
...
...
@@ -105,7 +110,8 @@ class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView):
context
=
{
'app'
:
_
(
'Perms'
),
'action'
:
_
(
'Asset permission detail'
),
'system_users_remain'
:
[
system_user
for
system_user
in
SystemUser
.
objects
.
all
()
'system_users_remain'
:
[
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
(),
}
...
...
@@ -119,7 +125,9 @@ class AssetPermissionDeleteView(AdminUserRequiredMixin, DeleteView):
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'
context_object_name
=
'asset_permission'
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
...
...
@@ -132,7 +140,9 @@ class AssetPermissionUserView(AdminUserRequiredMixin, SingleObjectMixin, ListVie
def
get_queryset
(
self
):
queryset
=
self
.
object
.
get_granted_users
()
if
self
.
keyword
:
search_func
=
functools
.
partial
(
search_object_attr
,
value
=
self
.
keyword
,
search_func
=
functools
.
partial
(
search_object_attr
,
value
=
self
.
keyword
,
attr_list
=
[
'username'
,
'name'
,
'email'
],
ignore_case
=
True
)
queryset
=
filter
(
search_func
,
queryset
)
...
...
@@ -144,9 +154,12 @@ class AssetPermissionUserView(AdminUserRequiredMixin, SingleObjectMixin, ListVie
context
=
{
'app'
:
_
(
'Perms'
),
'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_remain'
:
[
user_group
for
user_group
in
UserGroup
.
objects
.
all
()
'user_groups_remain'
:
[
user_group
for
user_group
in
UserGroup
.
objects
.
all
()
if
user_group
not
in
user_groups_granted
],
'keyword'
:
self
.
keyword
,
}
...
...
@@ -154,7 +167,9 @@ class AssetPermissionUserView(AdminUserRequiredMixin, SingleObjectMixin, ListVie
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'
context_object_name
=
'asset_permission'
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
...
...
@@ -162,12 +177,14 @@ class AssetPermissionAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListVi
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
(
queryset
=
AssetPermission
.
objects
.
all
())
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
):
queryset
=
self
.
object
.
get_granted_assets
()
if
self
.
keyword
:
search_func
=
functools
.
partial
(
search_object_attr
,
value
=
self
.
keyword
,
search_func
=
functools
.
partial
(
search_object_attr
,
value
=
self
.
keyword
,
attr_list
=
[
'hostname'
,
'ip'
],
ignore_case
=
True
)
queryset
=
filter
(
search_func
,
queryset
)
...
...
@@ -179,9 +196,12 @@ class AssetPermissionAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListVi
context
=
{
'app'
:
_
(
'Perms'
),
'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_remain'
:
[
asset_group
for
asset_group
in
AssetGroup
.
objects
.
all
()
'asset_groups_remain'
:
[
asset_group
for
asset_group
in
AssetGroup
.
objects
.
all
()
if
asset_group
not
in
asset_groups_granted
],
'keyword'
:
self
.
keyword
,
}
...
...
apps/users/api.py
View file @
948214ca
# ~*~ 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.response
import
Response
from
rest_framework.views
import
APIView
from
rest_framework.decorators
import
api_view
from
rest_framework.permissions
import
AllowAny
from
rest_framework.authentication
import
SessionAuthentication
from
rest_framework_bulk
import
BulkModelViewSet
# from django_filters.rest_framework import DjangoFilterBackend
...
...
@@ -19,7 +13,8 @@ from common.utils import get_logger
from
.utils
import
check_user_valid
,
generate_token
from
.models
import
User
,
UserGroup
from
.hands
import
write_login_log_async
from
.permissions
import
IsSuperUser
,
IsAppUser
,
IsValidUser
,
IsSuperUserOrAppUser
from
.permissions
import
(
IsSuperUser
,
IsAppUser
,
IsValidUser
)
from
.
import
serializers
...
...
@@ -98,7 +93,8 @@ class UserToken(APIView):
password
=
request
.
data
.
get
(
'password'
,
''
)
public_key
=
request
.
data
.
get
(
'public_key'
,
''
)
user
,
msg
=
check_user_valid
(
username
=
username
,
email
=
email
,
user
,
msg
=
check_user_valid
(
username
=
username
,
email
=
email
,
password
=
password
,
public_key
=
public_key
)
else
:
user
=
request
.
user
...
...
@@ -116,24 +112,31 @@ class UserProfile(APIView):
def
get
(
self
,
request
):
return
Response
(
request
.
user
.
to_json
())
def
post
(
self
,
request
):
return
Response
(
request
.
user
.
to_json
())
class
UserAuthApi
(
APIView
):
permission_classes
=
(
AllowAny
,)
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
def
post
(
self
,
request
):
username
=
request
.
data
.
get
(
'username'
,
''
)
password
=
request
.
data
.
get
(
'password'
,
''
)
public_key
=
request
.
data
.
get
(
'public_key'
,
''
)
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
,
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
:
token
=
generate_token
(
request
,
user
)
write_login_log_async
.
delay
(
user
.
username
,
name
=
user
.
name
,
user_agent
=
user_agent
,
login_ip
=
login_ip
,
login_type
=
login_type
)
write_login_log_async
.
delay
(
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
()})
else
:
return
Response
({
'msg'
:
msg
},
status
=
401
)
apps/users/authentication.py
View file @
948214ca
...
...
@@ -2,16 +2,18 @@
#
import
base64
import
uuid
import
hashlib
import
time
from
django.core.cache
import
cache
from
django.conf
import
settings
from
django.utils.translation
import
ugettext
as
_
from
rest_framework
import
authentication
,
exceptions
,
permissions
from
django.utils.six
import
text_type
from
django.utils.translation
import
ugettext_lazy
as
_
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
.utils
import
refresh_token
...
...
@@ -27,6 +29,21 @@ def get_request_date_header(request):
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'
model
=
AccessKey
...
...
@@ -40,22 +57,30 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
msg
=
_
(
'Invalid signature header. No credentials provided.'
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
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
)
try
:
sign
=
auth
[
1
]
.
decode
()
.
split
(
':'
)
if
len
(
sign
)
!=
2
:
msg
=
_
(
'Invalid signature header. Format like AccessKeyId:Signature'
)
msg
=
_
(
'Invalid signature header. '
'Format like AccessKeyId:Signature'
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
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
)
access_key_id
=
sign
[
0
]
try
:
uuid
.
UUID
(
access_key_id
)
except
ValueError
:
raise
exceptions
.
AuthenticationFailed
(
'Access key id invalid'
)
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
def
authenticate_credentials
(
request
,
access_key_id
,
request_signature
):
...
...
@@ -68,14 +93,17 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
try
:
request_unix_time
=
http_to_unixtime
(
request_date
)
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
:
raise
exceptions
.
AuthenticationFailed
(
_
(
'Expired, more than 15 minutes'
))
if
int
(
time
.
time
())
-
request_unix_time
>
15
*
60
:
raise
exceptions
.
AuthenticationFailed
(
_
(
'Expired, more than 15 minutes'
))
signature
=
make_signature
(
access_key_secret
,
request_date
)
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
:
raise
exceptions
.
AuthenticationFailed
(
_
(
'User disabled.'
))
...
...
@@ -97,13 +125,15 @@ class AccessTokenAuthentication(authentication.BaseAuthentication):
msg
=
_
(
'Invalid token header. No credentials provided.'
)
raise
exceptions
.
AuthenticationFailed
(
msg
)
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
)
try
:
token
=
auth
[
1
]
.
decode
()
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
)
return
self
.
authenticate_credentials
(
token
)
...
...
@@ -125,4 +155,6 @@ class PrivateTokenAuthentication(authentication.TokenAuthentication):
class
SessionAuthentication
(
authentication
.
SessionAuthentication
):
def
enforce_csrf
(
self
,
request
):
return
None
\ No newline at end of file
reason
=
CSRFCheck
()
.
process_view
(
request
,
None
,
(),
{})
if
reason
:
raise
exceptions
.
AuthenticationFailed
(
reason
)
apps/users/models/authentication.py
View file @
948214ca
...
...
@@ -16,7 +16,8 @@ class AccessKey(models.Model):
default
=
uuid
.
uuid4
,
editable
=
False
)
secret
=
models
.
UUIDField
(
verbose_name
=
'AccessKeySecret'
,
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
):
return
str
(
self
.
id
)
...
...
apps/users/urls/api_urls.py
View file @
948214ca
...
...
@@ -18,9 +18,12 @@ urlpatterns = [
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/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+)/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+)/password/reset/$'
,
api
.
UserResetPasswordApi
.
as_view
(),
name
=
'user-reset-password'
),
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/$'
,
api
.
UserUpdateGroupApi
.
as_view
(),
name
=
'user-update-group'
),
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
app_name
=
'users'
urlpatterns
=
[
# Login view
url
(
r'^login$'
,
views
.
UserLoginView
.
as_view
(),
name
=
'login'
),
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$'
,
views
.
UserForgotPasswordSendmailSuccessView
.
as_view
(),
name
=
'forgot-password-sendmail-success'
),
url
(
r'^password/reset$'
,
views
.
UserResetPasswordView
.
as_view
(),
name
=
'reset-password'
),
url
(
r'^password/reset/success$'
,
views
.
UserResetPasswordSuccessView
.
as_view
(),
views
.
UserForgotPasswordSendmailSuccessView
.
as_view
(),
name
=
'forgot-password-sendmail-success'
),
url
(
r'^password/reset$'
,
views
.
UserResetPasswordView
.
as_view
(),
name
=
'reset-password'
),
url
(
r'^password/reset/success$'
,
views
.
UserResetPasswordSuccessView
.
as_view
(),
name
=
'reset-password-success'
),
# User view
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]+)/asset-permission$'
,
views
.
UserAssetPermissionView
.
as_view
(),
url
(
r'^user/(?P<pk>[0-9]+)$'
,
views
.
UserDetailView
.
as_view
(),
name
=
'user-detail'
),
url
(
r'^user/(?P<pk>[0-9]+)/asset-permission$'
,
views
.
UserAssetPermissionView
.
as_view
(),
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'
),
url
(
r'^user/(?P<pk>[0-9]+)/assets'
,
views
.
UserGrantedAssetView
.
as_view
(),
name
=
'user-granted-asset'
),
url
(
r'^user/(?P<pk>[0-9]+)/login-history'
,
views
.
UserDetailView
.
as_view
(),
name
=
'user-login-history'
),
url
(
r'^user/export/'
,
views
.
UserExportView
.
as_view
(),
name
=
'user-export'
),
url
(
r'^first-login/$'
,
views
.
UserFirstLoginView
.
as_view
(),
name
=
'user-first-login'
),
url
(
r'^user/import/$'
,
views
.
BulkImportUserView
.
as_view
(),
name
=
'user-import'
),
# url(r'^user/(?P<pk>[0-9]+)/assets-perm$', views.UserDetailView.as_view(), name='user-detail'),
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'
),
url
(
r'^user/(?P<pk>[0-9]+)/assets'
,
views
.
UserGrantedAssetView
.
as_view
(),
name
=
'user-granted-asset'
),
url
(
r'^user/(?P<pk>[0-9]+)/login-history'
,
views
.
UserDetailView
.
as_view
(),
name
=
'user-login-history'
),
url
(
r'^user/export/'
,
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
url
(
r'^user-group$'
,
views
.
UserGroupListView
.
as_view
(),
name
=
'user-group-list'
),
url
(
r'^user-group/(?P<pk>[0-9]+)$'
,
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
(),
url
(
r'^user-group$'
,
views
.
UserGroupListView
.
as_view
(),
name
=
'user-group-list'
),
url
(
r'^user-group/(?P<pk>[0-9]+)$'
,
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'
),
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'
),
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'
),
]
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 ~*~
from
__future__
import
unicode_literals
import
json
import
uuid
import
json
from
django.shortcuts
import
redirect
from
openpyxl
import
Workbook
from
openpyxl.writer.excel
import
save_virtual_workbook
from
openpyxl
import
load_workbook
from
django
import
forms
from
django.utils
import
timezone
from
django.core.cache
import
cache
from
django.db
import
IntegrityError
from
django.contrib.auth
import
login
as
auth_login
,
logout
as
auth_logout
from
django.contrib.auth.mixins
import
LoginRequiredMixin
from
django.http
import
HttpResponse
,
JsonResponse
from
django.contrib.messages.views
import
SuccessMessageMixin
from
django.core.files.storage
import
default_storage
from
django.http
import
HttpResponseRedirect
,
HttpResponse
,
JsonResponse
from
django.shortcuts
import
reverse
,
redirect
from
django.utils.decorators
import
method_decorator
from
django.urls
import
reverse_lazy
,
reverse
from
django.utils
import
timezone
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.decorators.cache
import
never_cache
from
django.views.decorators.csrf
import
csrf_protect
,
csrf_exempt
from
django.views.decorators.debug
import
sensitive_post_parameters
from
django.views.generic
import
ListView
from
django.views.generic.base
import
TemplateView
from
django.views.generic.
list
import
ListView
from
django.views.generic.edit
import
CreateView
,
DeleteView
,
UpdateView
,
FormView
,
SingleObjectMixin
,
FormMixin
from
django.views.generic.detail
import
DetailView
from
formtools.wizard.views
import
SessionWizardView
from
django.views.generic.
edit
import
CreateView
,
UpdateView
,
FormMixin
,
\
FormView
from
django.views.generic.detail
import
DetailView
,
SingleObjectMixin
from
django.views.decorators.csrf
import
csrf_exempt
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
.models
import
User
,
UserGroup
from
.utils
import
AdminUserRequiredMixin
,
user_add_success_next
,
send_reset_password_mail
from
.hands
import
write_login_log_async
from
.
import
forms
from
..models
import
User
,
UserGroup
from
..utils
import
AdminUserRequiredMixin
,
user_add_success_next
from
..
import
forms
__all__
=
[
'UserListView'
,
'UserCreateView'
,
'UserDetailView'
,
'UserUpdateView'
,
'UserAssetPermissionCreateView'
,
'UserAssetPermissionView'
,
'UserGrantedAssetView'
,
'UserExportView'
,
'UserBulkImportView'
]
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
):
template_name
=
'users/user_list.html'
...
...
@@ -159,327 +107,55 @@ class UserDetailView(AdminUserRequiredMixin, DetailView):
def
get_context_data
(
self
,
**
kwargs
):
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
=
{
'app'
:
_
(
'Users'
),
'action'
:
_
(
'User
Group D
etail'
),
'
users'
:
users
,
'action'
:
_
(
'User
d
etail'
),
'
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
)
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
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
)
return
super
(
UserDetailView
,
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
):
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
):
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
})
spm
=
request
.
GET
.
get
(
'spm'
,
''
)
users_id
=
cache
.
get
(
spm
)
if
not
users_id
and
not
isinstance
(
users_id
,
list
):
return
HttpResponse
(
'May be expired'
,
status
=
404
)
users
=
User
.
objects
.
filter
(
id__in
=
users_id
)
wb
=
Workbook
()
ws
=
wb
.
active
ws
.
title
=
'User'
header
=
[
"name"
,
'username'
,
'email'
,
'groups'
,
"role"
,
"phone"
,
"wechat"
,
"comment"
]
ws
.
append
(
header
)
class
UserGroupAssetPermissionCreateView
(
AdminUserRequiredMixin
,
CreateView
):
form_class
=
forms
.
UserGroupPrivateAssetPermissionForm
model
=
AssetPermission
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
])
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
}))
filename
=
'users-{}.xlsx'
.
format
(
timezone
.
localtime
(
timezone
.
now
())
.
strftime
(
'
%
Y-
%
m-
%
d_
%
H-
%
M-
%
S'
))
response
=
HttpResponse
(
save_virtual_workbook
(
wb
),
content_type
=
'applications/vnd.ms-excel'
)
response
[
'Content-Disposition'
]
=
'attachment; filename="
%
s"'
%
filename
return
response
def
post
(
self
,
request
,
*
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
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
)
try
:
users_id
=
json
.
loads
(
request
.
body
)
.
get
(
'users_id'
,
[])
except
ValueError
:
return
HttpResponse
(
'Json object not valid'
,
status
=
400
)
spm
=
uuid
.
uuid4
()
.
get_hex
()
cache
.
set
(
spm
,
users_id
,
300
)
url
=
reverse
(
'users:user-export'
)
+
'?spm=
%
s'
%
spm
return
JsonResponse
({
'redirect'
:
url
})
class
BulkImportUser
View
(
AdminUserRequiredMixin
,
JSONResponseMixin
,
FormView
):
class
UserBulkImport
View
(
AdminUserRequiredMixin
,
JSONResponseMixin
,
FormView
):
form_class
=
forms
.
FileForm
def
form_invalid
(
self
,
form
):
...
...
@@ -526,7 +202,7 @@ class BulkImportUserView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
user
=
User
.
objects
.
create
(
**
user_dict
)
user_add_success_next
(
user
)
created
.
append
(
user_dict
[
'username'
])
except
IntegrityError
as
e
:
except
User
.
IntegrityError
as
e
:
user
=
User
.
objects
.
filter
(
username
=
user_dict
[
'username'
])
if
not
user
:
failed
.
append
(
user_dict
[
'username'
])
...
...
@@ -551,43 +227,74 @@ class BulkImportUserView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
'failed'
:
failed
,
'failed_info'
:
'Failed {}'
.
format
(
len
(
failed
)),
'valid'
:
True
,
'msg'
:
'Created: {}. Updated: {}, Error: {}'
.
format
(
len
(
created
),
len
(
updated
),
len
(
failed
))
'msg'
:
'Created: {}. Updated: {}, Error: {}'
.
format
(
len
(
created
),
len
(
updated
),
len
(
failed
))
}
return
self
.
render_json_response
(
data
)
@method_decorator
(
csrf_exempt
,
name
=
'dispatch'
)
class
UserExportView
(
View
):
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
):
spm
=
request
.
GET
.
get
(
'spm'
,
''
)
users_id
=
cache
.
get
(
spm
)
if
not
users_id
and
not
isinstance
(
users_id
,
list
):
return
HttpResponse
(
'May be expired'
,
status
=
404
)
self
.
object
=
self
.
get_object
(
queryset
=
User
.
objects
.
all
())
return
super
(
UserAssetPermissionView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
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
)
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
'app'
:
'Users'
,
'action'
:
'User asset permissions'
,
}
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'
))
response
=
HttpResponse
(
save_virtual_workbook
(
wb
),
content_type
=
'applications/vnd.ms-excel'
)
response
[
'Content-Disposition'
]
=
'attachment; filename="
%
s"'
%
filename
return
response
class
UserAssetPermissionCreateView
(
AdminUserRequiredMixin
,
CreateView
):
form_class
=
forms
.
UserPrivateAssetPermissionForm
model
=
AssetPermission
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
):
try
:
users_id
=
json
.
loads
(
request
.
body
)
.
get
(
'users_id'
,
[])
except
ValueError
:
return
HttpResponse
(
'Json object not valid'
,
status
=
400
)
spm
=
uuid
.
uuid4
()
.
get_hex
()
cache
.
set
(
spm
,
users_id
,
300
)
url
=
reverse
(
'users:user-export'
)
+
'?spm=
%
s'
%
spm
return
JsonResponse
({
'redirect'
:
url
})
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
})
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