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
0983f294
Commit
0983f294
authored
Mar 29, 2017
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Fixture] 添加用户profile
parent
4e7b665e
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
229 additions
and
59 deletions
+229
-59
广宏伟蓝底.jpg
apps/media/avatar/广宏伟蓝底.jpg
+0
-0
cropper.min.css
apps/static/css/plugins/cropper/cropper.min.css
+10
-0
_nav_user.html
apps/templates/_nav_user.html
+1
-1
forms.py
apps/users/forms.py
+14
-0
user.py
apps/users/models/user.py
+10
-0
user_profile.html
apps/users/templates/users/user_profile.html
+81
-50
user_profile_update.html
apps/users/templates/users/user_profile_update.html
+77
-0
views_urls.py
apps/users/urls/views_urls.py
+3
-0
user.py
apps/users/views/user.py
+33
-8
No files found.
apps/media/avatar/广宏伟蓝底.jpg
deleted
100644 → 0
View file @
4e7b665e
98.2 KB
apps/static/css/plugins/cropper/cropper.min.css
0 → 100755
View file @
0983f294
/*!
* Cropper v0.7.6-beta
* https://github.com/fengyuanchen/cropper
*
* Copyright 2014 Fengyuan Chen
* Released under the MIT license
*/
.cropper-container
{
position
:
relative
;
overflow
:
hidden
;
-webkit-user-select
:
none
;
-moz-user-select
:
none
;
-ms-user-select
:
none
;
user-select
:
none
;
-webkit-tap-highlight-color
:
transparent
;
-webkit-touch-callout
:
none
}
.cropper-container
img
{
width
:
100%
;
height
:
100%
;
min-width
:
0
!important
;
min-height
:
0
!important
;
max-width
:
none
!important
;
max-height
:
none
!important
}
.cropper-modal
,
.cropper-canvas
{
position
:
absolute
;
top
:
0
;
right
:
0
;
bottom
:
0
;
left
:
0
}
.cropper-canvas
{
background-color
:
#fff
;
opacity
:
0
;
filter
:
alpha
(
opacity
=
0
)}
.cropper-modal
{
background-color
:
#000
;
opacity
:
.5
;
filter
:
alpha
(
opacity
=
50
)}
.cropper-dragger
{
position
:
absolute
;
top
:
10%
;
left
:
10%
;
width
:
80%
;
height
:
80%
}
.cropper-viewer
{
display
:
block
;
width
:
100%
;
height
:
100%
;
overflow
:
hidden
;
outline-width
:
1px
;
outline-style
:
solid
;
outline-color
:
#69f
;
outline-color
:
rgba
(
51
,
102
,
255
,
.75
)}
.cropper-dashed
{
position
:
absolute
;
display
:
block
;
border
:
0
dashed
#fff
;
opacity
:
.5
;
filter
:
alpha
(
opacity
=
50
)}
.cropper-dashed.dashed-h
{
top
:
33.3%
;
left
:
0
;
width
:
100%
;
height
:
33.3%
;
border-top-width
:
1px
;
border-bottom-width
:
1px
}
.cropper-dashed.dashed-v
{
top
:
0
;
left
:
33.3%
;
width
:
33.3%
;
height
:
100%
;
border-right-width
:
1px
;
border-left-width
:
1px
}
.cropper-face
,
.cropper-line
,
.cropper-point
{
position
:
absolute
;
display
:
block
;
width
:
100%
;
height
:
100%
;
opacity
:
.1
;
filter
:
alpha
(
opacity
=
10
)}
.cropper-face
{
top
:
0
;
left
:
0
;
cursor
:
move
;
background-color
:
#fff
}
.cropper-line
{
background-color
:
#69f
}
.cropper-line.line-e
{
top
:
0
;
right
:
-3px
;
width
:
5px
;
cursor
:
e-resize
}
.cropper-line.line-n
{
top
:
-3px
;
left
:
0
;
height
:
5px
;
cursor
:
n-resize
}
.cropper-line.line-w
{
top
:
0
;
left
:
-3px
;
width
:
5px
;
cursor
:
w-resize
}
.cropper-line.line-s
{
bottom
:
-3px
;
left
:
0
;
height
:
5px
;
cursor
:
s-resize
}
.cropper-point
{
width
:
5px
;
height
:
5px
;
background-color
:
#69f
;
opacity
:
.75
;
filter
:
alpha
(
opacity
=
75
)}
.cropper-point.point-e
{
top
:
50%
;
right
:
-3px
;
margin-top
:
-3px
;
cursor
:
e-resize
}
.cropper-point.point-n
{
top
:
-3px
;
left
:
50%
;
margin-left
:
-3px
;
cursor
:
n-resize
}
.cropper-point.point-w
{
top
:
50%
;
left
:
-3px
;
margin-top
:
-3px
;
cursor
:
w-resize
}
.cropper-point.point-s
{
bottom
:
-3px
;
left
:
50%
;
margin-left
:
-3px
;
cursor
:
s-resize
}
.cropper-point.point-ne
{
top
:
-3px
;
right
:
-3px
;
cursor
:
ne-resize
}
.cropper-point.point-nw
{
top
:
-3px
;
left
:
-3px
;
cursor
:
nw-resize
}
.cropper-point.point-sw
{
bottom
:
-3px
;
left
:
-3px
;
cursor
:
sw-resize
}
.cropper-point.point-se
{
right
:
-3px
;
bottom
:
-3px
;
width
:
20px
;
height
:
20px
;
cursor
:
se-resize
;
opacity
:
1
;
filter
:
alpha
(
opacity
=
100
)}
.cropper-point.point-se
:before
{
position
:
absolute
;
right
:
-50%
;
bottom
:
-50%
;
display
:
block
;
width
:
200%
;
height
:
200%
;
content
:
" "
;
background-color
:
#69f
;
opacity
:
0
;
filter
:
alpha
(
opacity
=
0
)}
@media
(
min-width
:
768px
){
.cropper-point.point-se
{
width
:
15px
;
height
:
15px
}}
@media
(
min-width
:
992px
){
.cropper-point.point-se
{
width
:
10px
;
height
:
10px
}}
@media
(
min-width
:
1200px
){
.cropper-point.point-se
{
width
:
5px
;
height
:
5px
;
opacity
:
.75
;
filter
:
alpha
(
opacity
=
75
)}}
.cropper-hidden
{
display
:
none
!important
}
.cropper-invisible
{
position
:
fixed
;
top
:
0
;
left
:
0
;
z-index
:
-1
;
width
:
auto
!important
;
max-width
:
none
!important
;
height
:
auto
!important
;
max-height
:
none
!important
;
opacity
:
0
;
filter
:
alpha
(
opacity
=
0
)}
.cropper-move
{
cursor
:
move
}
.cropper-crop
{
cursor
:
crosshair
}
.cropper-disabled
.cropper-canvas
,
.cropper-disabled
.cropper-face
,
.cropper-disabled
.cropper-line
,
.cropper-disabled
.cropper-point
{
cursor
:
not-allowed
}
\ No newline at end of file
apps/templates/_nav_user.html
View file @
0983f294
...
...
@@ -16,7 +16,7 @@
</li>
<li
id=
"applications"
>
<a
href=
"{% url 'users:user-profile' %}"
>
<i
class=
"fa fa-
user
"
></i>
<span
class=
"nav-label"
>
{% trans 'Terminal' %}
</span><span
class=
"label label-info pull-right"
></span>
<i
class=
"fa fa-
terminal
"
></i>
<span
class=
"nav-label"
>
{% trans 'Terminal' %}
</span><span
class=
"label label-info pull-right"
></span>
</a>
</li>
<li
class=
"special_link"
>
...
...
apps/users/forms.py
View file @
0983f294
...
...
@@ -37,6 +37,20 @@ class UserCreateUpdateForm(forms.ModelForm):
}
class
UserProfileForm
(
forms
.
ModelForm
):
class
Meta
:
model
=
User
fields
=
[
'username'
,
'name'
,
'email'
,
'groups'
,
'wechat'
,
'phone'
,
]
help_texts
=
{
'username'
:
'* required'
,
'name'
:
'* required'
,
'email'
:
'* required'
,
}
class
UserBulkImportForm
(
forms
.
ModelForm
):
class
Meta
:
model
=
User
...
...
apps/users/models/user.py
View file @
0983f294
...
...
@@ -100,6 +100,16 @@ class User(AbstractUser):
def
public_key
(
self
,
public_key_raw
):
self
.
_public_key
=
signer
.
sign
(
public_key_raw
)
@property
def
public_key_hash
(
self
):
if
self
.
public_key
:
import
sshpubkeys
try
:
return
sshpubkeys
.
SSHKey
(
self
.
public_key
)
.
hash_md5
()
except
TabError
:
pass
return
'None'
@property
def
is_superuser
(
self
):
if
self
.
role
==
'Admin'
:
...
...
apps/users/templates/users/user_profile.html
View file @
0983f294
...
...
@@ -17,7 +17,7 @@
<a
href=
""
class=
"text-center"
><i
class=
"fa fa-laptop"
></i>
{% trans 'Profile' %}
</a>
</li>
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline btn-default"
href=
""
><i
class=
"fa fa-edit"
></i>
{% trans 'Settings' %}
</a>
<a
class=
"btn btn-outline btn-default"
href=
"
{% url 'users:user-profile-update' %}
"
><i
class=
"fa fa-edit"
></i>
{% trans 'Settings' %}
</a>
</li>
</ul>
</div>
...
...
@@ -38,67 +38,72 @@
<div
class=
"ibox-content"
>
<div
class=
"text-left"
>
<table
class=
"table"
>
<tr>
<td
class=
"text-navy"
>
用户名
</td>
<tr
class=
"no-borders-tr"
>
<td
colspan=
"2"
>
<img
src=
"{{ user.avatar_url }}"
class=
"img-circle"
width=
"64"
height=
"64"
>
</td>
</tr>
<tr
class=
"no-borders-tr"
>
<td
class=
"text-navy"
>
{% trans 'Username' %}
</td>
<td>
{{ user.username }}
</td>
</tr>
<tr>
<td
class=
"text-navy"
>
姓名
</td>
<td
class=
"text-navy"
>
{% trans 'Name' %}
</td>
<td>
{{ user.name }}
</td>
</tr>
<tr>
<td
class=
"text-navy"
>
权限
</td>
<td
class=
"text-navy"
>
{% trans 'Role' %}
</td>
<td>
{{ user.get_role_display }}
</td>
</tr>
<tr>
<td
class=
"text-navy"
>
Email
</td>
<td
class=
"text-navy"
>
{% trans 'Email' %}
</td>
<td>
{{ user.email }}
</td>
</tr>
<tr>
<td
class=
"text-navy"
>
激活
</td>
<td
class=
"text-navy"
>
{% trans 'Active' %}
</td>
<td>
{{ user.is_active|yesno:"Yes,No,Unkown" }}
</td>
</tr>
<tr>
<td
class=
"text-navy"
>
添加日期
</td>
<td
class=
"text-navy"
>
{% trans 'OTP' %}
</td>
<td>
{{ user.enable_otp|yesno:"Yes,No,Unkown" }}
</td>
</tr>
<tr>
<td
class=
"text-navy"
>
{% trans 'Public key fingerprint' %}
</td>
<td>
{{ user.public_key_hash }}
</td>
</tr>
<tr>
<td
class=
"text-navy"
>
{% trans 'Date joined' %}
</td>
<td>
{{ user.date_joined|date:"Y-m-d H:i:s" }}
</td>
</tr>
<tr>
<td
class=
"text-navy"
>
最后登录
</td>
<td
class=
"text-navy"
>
{% trans 'Last login' %}
</td>
<td>
{{ user.last_login|date:"Y-m-d H:i:s" }}
</td>
</tr>
<tr>
<td
class=
"text-navy"
>
所在用户组
</td>
<td
class=
"text-navy"
>
{% trans 'Date expired' %}
</td>
<td>
{{ user.date_expired|date:"Y-m-d H:i:s" }}
</td>
</tr>
<tr>
<td
class=
"text-navy"
>
{% trans 'User groups' %}
</td>
<td>
{% for group in user.groups.all %}
<span
class=
"simple-tag with-link"
>
<a
href=
"{% url 'users:user-group-detail' group.id %}"
>
{{ group.name }}
</a>
</span>
{% endfor %}
<table>
{% for group in user.groups.all %}
<tr>
<td>
{{ group.name }}
</td>
</tr>
{% endfor %}
</table>
</td>
</tr>
<tr>
<td
class=
"text-navy"
>
授权主机数量
</td>
<td
class=
"text-navy"
>
{% trans 'Perm assets' %}
</td>
<td>
{{ assets | length }}
</td>
</tr>
<tr>
<td
class=
"text-navy"
>
授权主机组
</td>
<td>
{% for group in asset_groups %}
<span
class=
"simple-tag with-link"
>
<a
href=
"{% url 'assets:asset-group-detail' group.id %}"
>
{{ group.name }}
</a>
</span>
{% endfor %}
</td>
</tr>
<tr>
<td
class=
"text-navy"
>
授权规则
</td>
<td>
{% for perm in permissions %}
<span
class=
"simple-tag with-link"
>
<a
href=
"{% url 'perms:asset-permission-detail' perm.id %}"
>
{{ perm.name }}
</a>
</span>
{% endfor %}
</td>
<td
class=
"text-navy"
>
{% trans 'Comment' %}:
</td>
<td><b>
{{ user.comment }}
</b></td>
</tr>
</table>
</div>
...
...
@@ -106,23 +111,49 @@
</div>
</div>
</div>
<div
class=
"col-sm-5"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox-title"
>
<span
class=
"label label-primary"
><b>
{% trans "Update Public Key" %}
</b></span>
<div
class=
"ibox-tools"
>
<a
class=
"collapse-link"
>
<i
class=
"fa fa-chevron-up"
></i>
</a>
<a
class=
"close-link"
>
<i
class=
"fa fa-times"
></i>
</a>
</div>
<div
class=
"col-sm-5"
style=
"padding-left: 0;padding-right: 0"
>
<div
class=
"panel panel-primary"
>
<div
class=
"panel-heading"
>
<i
class=
"fa fa-info-circle"
></i>
{% trans 'Quick modify' %}
</div>
<div
class=
"ibox-content"
>
<p>
{% trans "Paste your SSH Public Key here" %}
</p>
<textarea
id=
"txt_pk"
class=
"form-control"
cols=
"30"
rows=
"10"
placeholder=
"ssh-rsa AAAAB3NzaC1yc2EAA....."
></textarea>
<button
id=
"btn_update_pk"
class=
"btn btn-primary m-t-15"
>
{% trans 'Update' %}
</button>
<div
class=
"panel-body"
>
<table
class=
"table"
>
<tbody>
<tr
class=
"no-borders-tr"
>
<td>
{% trans 'Reset password' %}:
</td>
<td>
<span
class=
"pull-right"
>
<button
type=
"button"
class=
"btn btn-primary btn-xs"
style=
"width: 54px"
>
{% trans 'Reset' %}
</button>
</span>
</td>
</tr>
<tr>
<td>
{% trans 'Reset public key' %}:
</td>
<td>
<span
class=
"pull-right"
>
<button
type=
"button"
class=
"btn btn-primary btn-xs"
style=
"width: 54px"
>
{% trans 'Reset' %}
</button>
</span>
</td>
</tr>
<tr>
<td>
{% trans 'Test admin user' %}:
</td>
<td>
<span
class=
"pull-right"
>
<button
type=
"button"
class=
"btn btn-primary btn-xs"
id=
"btn_reset_pk"
style=
"width: 54px;"
>
{% trans 'Test' %}
</button>
</span>
</td>
</tr>
<tr>
<td>
{% trans 'Test system pingpong' %}:
</td>
<td>
<span
class=
"pull-right"
>
<button
type=
"button"
class=
"btn btn-primary btn-xs"
id=
"btn_reset_pk"
style=
"width: 54px;"
>
{% trans 'Test' %}
</button>
</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
...
...
apps/users/templates/users/user_profile_update.html
0 → 100644
View file @
0983f294
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% load bootstrap %}
{% block custom_head_css_js %}
<link
href=
"{% static "
css
/
plugins
/
cropper
/
cropper
.
min
.
css
"
%}"
rel=
"stylesheet"
>
<link
href=
"{% static "
css
/
plugins
/
sweetalert
/
sweetalert
.
css
"
%}"
rel=
"stylesheet"
>
<script
src=
"{% static "
js
/
plugins
/
sweetalert
/
sweetalert
.
min
.
js
"
%}"
></script>
<style>
.crop
{
width
:
200px
;
height
:
150px
;
overflow
:
hidden
;
}
.img-preview-sm
img
{
width
:
64px
;
height
:
64px
;
margin
:
-75px
0
0
-100px
;
}
</style>
{% endblock %}
{% block content %}
<div
class=
"wrapper wrapper-content animated fadeInRight"
>
<div
class=
"row"
>
<div
class=
"col-sm-12"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"panel-options"
>
<ul
class=
"nav nav-tabs"
>
<li
class=
"active"
>
<a
href=
""
class=
"text-center"
>
{% trans 'Profile' %}
</a>
</li>
<li>
<a
href=
""
class=
"text-center"
>
{% trans 'Password' %}
</a>
</li>
<li>
<a
href=
""
class=
"text-center"
>
{% trans 'Public key' %}
</a>
</li>
</ul>
</div>
<div
class=
"tab-content"
style=
"background-color: #ffffff"
>
<div
class=
"wrapper wrapper-content animated fadeInRight"
>
<form
method=
"post"
class=
"form-horizontal"
action=
""
enctype=
"multipart/form-data"
>
{% csrf_token %}
<h3>
{% trans 'Account' %}
</h3>
{# {{ form.avatar|bootstrap_horizontal }}#}
{{ form.username|bootstrap_horizontal }}
{{ form.name|bootstrap_horizontal }}
{{ form.email|bootstrap_horizontal }}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Profile' %}
</h3>
{{ form.phone|bootstrap_horizontal }}
{{ form.wechat|bootstrap_horizontal }}
<div
class=
"hr-line-dashed"
></div>
<div
class=
"form-group"
>
<div
class=
"col-sm-4 col-sm-offset-2"
>
<button
class=
"btn btn-white"
type=
"reset"
>
{% trans 'Reset' %}
</button>
<button
id=
"submit_button"
class=
"btn btn-primary"
type=
"submit"
>
{% trans 'Submit' %}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script
src=
"{% static 'js/plugins/cropper/cropper.min.js' %}"
></script>
<script>
</script>
{% endblock %}
apps/users/urls/views_urls.py
View file @
0983f294
...
...
@@ -25,6 +25,9 @@ urlpatterns = [
url
(
r'^profile/$'
,
views
.
UserProfileView
.
as_view
(),
name
=
'user-profile'
),
url
(
r'^profile/update/$'
,
views
.
UserProfileUpdateView
.
as_view
(),
name
=
'user-profile-update'
),
# User view
url
(
r'^user$'
,
views
.
UserListView
.
as_view
(),
name
=
'user-list'
),
...
...
apps/users/views/user.py
View file @
0983f294
...
...
@@ -36,7 +36,9 @@ from perms.models import AssetPermission
__all__
=
[
'UserListView'
,
'UserCreateView'
,
'UserDetailView'
,
'UserUpdateView'
,
'UserAssetPermissionCreateView'
,
'UserAssetPermissionView'
,
'UserGrantedAssetView'
,
'UserExportView'
,
'UserBulkImportView'
,
'UserProfileView'
]
'UserExportView'
,
'UserBulkImportView'
,
'UserProfileView'
,
'UserProfileUpdateView'
,
]
logger
=
get_logger
(
__name__
)
...
...
@@ -311,18 +313,40 @@ class UserProfileView(LoginRequiredMixin, TemplateView):
template_name
=
'users/user_profile.html'
def
get_context_data
(
self
,
**
kwargs
):
from
perms.utils
import
(
get_user_granted_assets
,
get_user_granted_asset_groups
,
get_user_asset_permissions
)
from
perms.utils
import
get_user_granted_assets
assets
=
get_user_granted_assets
(
self
.
request
.
user
)
asset_groups
=
get_user_granted_asset_groups
(
self
.
request
.
user
)
permissions
=
get_user_asset_permissions
(
self
.
request
.
user
)
context
=
{
'app'
:
'User'
,
'action'
:
'User Profile'
,
'assets'
:
assets
,
'asset_groups'
:
asset_groups
,
'permissions'
:
permissions
}
kwargs
.
update
(
context
)
return
super
(
UserProfileView
,
self
)
.
get_context_data
(
**
kwargs
)
class
UserProfileUpdateView
(
LoginRequiredMixin
,
UpdateView
):
template_name
=
'users/user_profile_update.html'
model
=
User
form_class
=
forms
.
UserProfileForm
success_url
=
reverse_lazy
(
'users:user-profile'
)
success_message
=
_
(
'Create user <a href="
%
s">
%
s</a> successfully.'
)
def
get_object
(
self
,
queryset
=
None
):
return
self
.
request
.
user
def
get_success_message
(
self
,
cleaned_data
):
return
self
.
success_message
%
(
reverse_lazy
(
'users:user-detail'
,
kwargs
=
{
'pk'
:
self
.
object
.
pk
}),
self
.
object
.
name
,
)
def
get_context_data
(
self
,
**
kwargs
):
from
perms.utils
import
get_user_granted_assets
assets
=
get_user_granted_assets
(
self
.
request
.
user
)
context
=
{
'app'
:
'User'
,
'action'
:
'User Profile'
,
'assets'
:
assets
,
}
kwargs
.
update
(
context
)
return
super
(
UserProfileUpdateView
,
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