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
f2746844
Commit
f2746844
authored
Sep 03, 2016
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add translation for support i18n
parent
ba3f46fb
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
156 additions
and
240 deletions
+156
-240
flash_message_standalone.html
apps/common/templates/common/flash_message_standalone.html
+1
-1
settings.py
apps/jumpserver/settings.py
+4
-2
django.mo
apps/locale/zh_CN/LC_MESSAGES/django.mo
+0
-0
django.po
apps/locale/zh_CN/LC_MESSAGES/django.po
+0
-0
_header_bar.html
apps/templates/_header_bar.html
+5
-4
_nav.html
apps/templates/_nav.html
+22
-20
_pagination.html
apps/templates/_pagination.html
+4
-4
_user_profile.html
apps/templates/_user_profile.html
+4
-4
base.html
apps/templates/base.html
+1
-1
forms.py
apps/users/forms.py
+5
-4
models.py
apps/users/models.py
+23
-21
_user.html
apps/users/templates/users/_user.html
+8
-7
forget_password.html
apps/users/templates/users/forget_password.html
+4
-3
login.html
apps/users/templates/users/login.html
+6
-11
reset_password.html
apps/users/templates/users/reset_password.html
+5
-7
user_add.html
apps/users/templates/users/user_add.html
+5
-3
user_delete_confirm.html
apps/users/templates/users/user_delete_confirm.html
+2
-1
user_detail.html
apps/users/templates/users/user_detail.html
+0
-0
user_edit.html
apps/users/templates/users/user_edit.html
+4
-3
user_list.bak.html
apps/users/templates/users/user_list.bak.html
+0
-92
user_list.html
apps/users/templates/users/user_list.html
+15
-15
utils.py
apps/users/utils.py
+20
-19
views.py
apps/users/views.py
+17
-18
config-example.py
config-example.py
+1
-0
No files found.
apps/common/templates/common/flash_message_standalone.html
View file @
f2746844
...
@@ -71,7 +71,7 @@
...
@@ -71,7 +71,7 @@
}
}
}
}
{
%
if
auto_redirect
%
}
{
%
if
auto_redirect
%
}
window
.
onload
=
redirect_page
window
.
onload
=
redirect_page
;
{
%
endif
%
}
{
%
endif
%
}
</script>
</script>
</html>
</html>
apps/jumpserver/settings.py
View file @
f2746844
...
@@ -215,7 +215,7 @@ LOGGING = {
...
@@ -215,7 +215,7 @@ LOGGING = {
# Internationalization
# Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/
# https://docs.djangoproject.com/en/1.10/topics/i18n/
LANGUAGE_CODE
=
'en
-us
'
LANGUAGE_CODE
=
'en
_US
'
TIME_ZONE
=
'Asia/Shanghai'
TIME_ZONE
=
'Asia/Shanghai'
...
@@ -225,6 +225,9 @@ USE_L10N = True
...
@@ -225,6 +225,9 @@ USE_L10N = True
USE_TZ
=
True
USE_TZ
=
True
# I18N translation
LOCALE_PATHS
=
[
os
.
path
.
join
(
BASE_DIR
,
'locale'
),]
# Static files (CSS, JavaScript, Images)
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/
# https://docs.djangoproject.com/en/1.10/howto/static-files/
...
@@ -246,7 +249,6 @@ BOOTSTRAP_COLUMN_COUNT = 11
...
@@ -246,7 +249,6 @@ BOOTSTRAP_COLUMN_COUNT = 11
# Init data or generate fake data source for development
# Init data or generate fake data source for development
FIXTURE_DIRS
=
[
os
.
path
.
join
(
BASE_DIR
,
'fixtures'
),
]
FIXTURE_DIRS
=
[
os
.
path
.
join
(
BASE_DIR
,
'fixtures'
),
]
# Email config
# Email config
EMAIL_HOST
=
CONFIG
.
EMAIL_HOST
EMAIL_HOST
=
CONFIG
.
EMAIL_HOST
EMAIL_PORT
=
CONFIG
.
EMAIL_PORT
EMAIL_PORT
=
CONFIG
.
EMAIL_PORT
...
...
apps/locale/zh_CN/LC_MESSAGES/django.mo
0 → 100644
View file @
f2746844
File added
apps/locale/zh_CN/LC_MESSAGES/django.po
0 → 100644
View file @
f2746844
This diff is collapsed.
Click to expand it.
apps/templates/_header_bar.html
View file @
f2746844
{% load i18n %}
<div
class=
"row border-bottom"
>
<div
class=
"row border-bottom"
>
<nav
class=
"navbar navbar-static-top white-bg"
role=
"navigation"
style=
"margin-bottom: 0"
>
<nav
class=
"navbar navbar-static-top white-bg"
role=
"navigation"
style=
"margin-bottom: 0"
>
<div
class=
"navbar-header"
>
<div
class=
"navbar-header"
>
<a
class=
"navbar-minimalize minimalize-styl-2 btn btn-primary "
href=
"#"
><i
class=
"fa fa-bars"
></i>
</a>
<a
class=
"navbar-minimalize minimalize-styl-2 btn btn-primary "
href=
"#"
><i
class=
"fa fa-bars"
></i>
</a>
<form
role=
"search"
class=
"navbar-form-custom"
method=
"get"
action=
""
>
<form
role=
"search"
class=
"navbar-form-custom"
method=
"get"
action=
""
>
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<input
type=
"text"
placeholder=
"
输入搜索
..."
class=
"form-control"
name=
"search"
id=
"top-search"
>
<input
type=
"text"
placeholder=
"
{% trans 'Search' %}
..."
class=
"form-control"
name=
"search"
id=
"top-search"
>
</div>
</div>
</form>
</form>
</div>
</div>
<ul
class=
"nav navbar-top-links navbar-right"
>
<ul
class=
"nav navbar-top-links navbar-right"
>
<li>
<li>
<span
class=
"m-r-sm text-muted welcome-message"
>
欢迎使用Jumpserver开源跳板机系统
</span>
<span
class=
"m-r-sm text-muted welcome-message"
>
{% trans 'Welcome use Jumpserver system' %}
</span>
</li>
</li>
<li
class=
"dropdown"
>
<li
class=
"dropdown"
>
<a
class=
"dropdown-toggle count-info"
data-toggle=
"dropdown"
href=
"#"
>
<a
class=
"dropdown-toggle count-info"
data-toggle=
"dropdown"
href=
"#"
>
<span
class=
"m-r-sm text-muted welcome-message"
>
帮助
</span>
<span
class=
"m-r-sm text-muted welcome-message"
>
{% trans 'Help' %}
</span>
</a>
</a>
</li>
</li>
<li>
<li>
...
@@ -31,7 +32,7 @@
...
@@ -31,7 +32,7 @@
<h2></h2>
<h2></h2>
<ol
class=
"breadcrumb"
>
<ol
class=
"breadcrumb"
>
<li>
<li>
<a
href=
""
>
仪表盘
</a>
<a
href=
""
>
{% trans 'Home' %}
</a>
</li>
</li>
<li>
<li>
{% if app %}
{% if app %}
...
...
apps/templates/_nav.html
View file @
f2746844
{% load i18n %}
<li
id=
"index"
>
<li
id=
"index"
>
<a
href=
""
>
<a
href=
""
>
<i
class=
"fa fa-dashboard"
></i>
<span
class=
"nav-label"
>
仪表盘
</span><span
class=
"label label-info pull-right"
></span>
<i
class=
"fa fa-dashboard"
></i>
<span
class=
"nav-label"
>
{% trans 'Home' %}
</span><span
class=
"label label-info pull-right"
></span>
</a>
</a>
</li>
</li>
<li
id=
"users"
>
<li
id=
"users"
>
<a
href=
"#"
>
<a
href=
"#"
>
<i
class=
"fa fa-group"
></i>
<span
class=
"nav-label"
>
用户管理
</span><span
class=
"fa arrow"
></span>
<i
class=
"fa fa-group"
></i>
<span
class=
"nav-label"
>
{% trans 'Users' %}
</span><span
class=
"fa arrow"
></span>
</a>
</a>
<ul
class=
"nav nav-second-level active"
>
<ul
class=
"nav nav-second-level active"
>
<li
class=
"users"
><a
href=
"{% url 'users:user-list' %}"
>
用户列表
</a></li>
<li
class=
"users"
><a
href=
"{% url 'users:user-list' %}"
>
{% trans 'User' %}
</a></li>
<li
class=
"usergroups"
><a
href=
"{% url 'users:usergroup-list' %}"
>
用户组列表
</a></li>
<li
class=
"usergroups"
><a
href=
"{% url 'users:usergroup-list' %}"
>
{% trans 'Usergroup' %}
</a></li>
</ul>
</ul>
</li>
</li>
<li
id=
""
>
<li
id=
""
>
<a>
<a>
<i
class=
"fa fa-inbox"
></i>
<span
class=
"nav-label"
>
资产管理
</span><span
class=
"fa arrow"
></span>
<i
class=
"fa fa-inbox"
></i>
<span
class=
"nav-label"
>
{% trans 'Assets' %}
</span><span
class=
"fa arrow"
></span>
</a>
</a>
<ul
class=
"nav nav-second-level"
>
<ul
class=
"nav nav-second-level"
>
<li
class=
""
><a
href=
""
>
资产列表
</a></li>
<li
class=
""
><a
href=
""
>
{% trans 'Asset' %}
</a></li>
<li
class=
""
><a
href=
""
>
资产组列表
</a></li>
<li
class=
""
><a
href=
""
>
{% trans 'Assetgroup' %}
</a></li>
<li
class=
""
><a
href=
""
>
机房列表
</a></li>
<li
class=
""
><a
href=
""
>
{% trans 'IDC' %}
</a></li>
<li
class=
""
><a
href=
""
>
管理用户
</a></li>
<li
class=
""
><a
href=
""
>
{% trans 'Opsuser' %}
</a></li>
<li
class=
""
><a
href=
""
>
系统用户
</a></li>
<li
class=
""
><a
href=
""
>
{% trans 'Sysuser' %}
</a></li>
<li
class=
""
><a
href=
""
>
标签列表
</a></li>
<li
class=
""
><a
href=
""
>
{% trans 'Label' %}
</a></li>
</ul>
</ul>
</li>
</li>
<li
id=
""
>
<li
id=
""
>
<a
href=
"#"
><i
class=
"fa fa-edit"
></i>
<span
class=
"nav-label"
>
授权管理
</span><span
class=
"fa arrow"
></span></a>
<a
href=
"#"
><i
class=
"fa fa-edit"
></i>
<span
class=
"nav-label"
>
{% trans 'Perms' %}
</span><span
class=
"fa arrow"
></span></a>
<ul
class=
"nav nav-second-level"
>
<ul
class=
"nav nav-second-level"
>
<li
class=
"sudo"
>
<li
class=
"sudo"
>
<a
class=
"sudo"
href=
""
>
授权列表
</a>
<a
class=
"sudo"
href=
""
>
{% trans 'Perm' %}
</a>
</li>
</li>
<li
class=
"role"
>
<li
class=
"role"
>
<a
href=
""
>
添加授权
</a>
<a
href=
""
>
{% trans 'Create perm' %}
</a>
</li>
</li>
</ul>
</ul>
</li>
</li>
<li
id=
""
>
<li
id=
""
>
<a
href=
""
>
<a
href=
""
>
<i
class=
"fa fa-files-o"
></i><span
class=
"nav-label"
>
审计管理
</span><span
class=
"label label-info pull-right"
></span>
<i
class=
"fa fa-files-o"
></i><span
class=
"nav-label"
>
{% trans 'Audit' %}
</span><span
class=
"label label-info pull-right"
></span>
</a>
</a>
</li>
</li>
<li
id=
""
>
<li
id=
""
>
<a
href=
"#"
>
<a
href=
"#"
>
<i
class=
"fa fa-download"
></i>
<span
class=
"nav-label"
>
上传下载
</span><span
class=
"fa arrow"
></span>
<i
class=
"fa fa-download"
></i>
<span
class=
"nav-label"
>
{% trans 'File' %}
</span><span
class=
"fa arrow"
></span>
</a>
</a>
<ul
class=
"nav nav-second-level"
>
<ul
class=
"nav nav-second-level"
>
<li
class=
"upload"
><a
href=
""
>
文件上传
</a></li>
<li
class=
"upload"
><a
href=
""
>
{% trans 'File upload' %}
</a></li>
<li
class=
"download"
><a
href=
""
>
文件下载
</a></li>
<li
class=
"download"
><a
href=
""
>
{% trans 'File download' %}
</a></li>
</ul>
</ul>
</li>
</li>
<li
id=
""
>
<li
id=
""
>
<a
href=
""
>
<a
href=
""
>
<i
class=
"fa fa-gears"
></i>
<span
class=
"nav-label"
>
设置
</span><span
class=
"label label-info pull-right"
></span>
<i
class=
"fa fa-gears"
></i>
<span
class=
"nav-label"
>
{% trans 'Settings' %}
</span><span
class=
"label label-info pull-right"
></span>
</a>
</a>
</li>
</li>
<li
class=
"special_link"
>
<li
class=
"special_link"
>
<a
href=
"http://www.jumpserver.org"
target=
"_blank"
><i
class=
"fa fa-database"
></i>
<a
href=
"http://www.jumpserver.org"
target=
"_blank"
><i
class=
"fa fa-database"
></i>
<span
class=
"nav-label"
>
访问官网
</span>
<span
class=
"nav-label"
>
{% trans 'Visit us' %}
</span>
</a>
</a>
</li>
</li>
\ No newline at end of file
apps/templates/_pagination.html
View file @
f2746844
...
@@ -34,10 +34,10 @@
...
@@ -34,10 +34,10 @@
</div>
</div>
{% endif %}
{% endif %}
<script>
<script>
function
sleep
(
n
)
{
//n表示的毫秒数
{
#
function
sleep
(
n
)
{
//n表示的毫秒数#}
var
start
=
new
Date
().
getTime
();
{
#
var
start
=
new
Date
().
getTime
();
#
}
while
(
true
)
if
(
new
Date
().
getTime
()
-
start
>
n
)
break
;
{
#
while
(
true
)
if
(
new
Date
().
getTime
()
-
start
>
n
)
break
;
#
}
}
{
#
}
#
}
$
(
document
).
ready
(
function
()
{
$
(
document
).
ready
(
function
()
{
$
(
'.page'
).
click
(
function
()
{
$
(
'.page'
).
click
(
function
()
{
...
...
apps/templates/_user_profile.html
View file @
f2746844
{% load static %}
{% load static %}
{% load i18n %}
<li
class=
"nav-header"
>
<li
class=
"nav-header"
>
<div
class=
"dropdown profile-element"
>
<div
class=
"dropdown profile-element"
>
<span>
<span>
...
@@ -10,15 +11,14 @@
...
@@ -10,15 +11,14 @@
<strong
class=
"font-bold"
>
{{ request.user.name }}
<span
style=
"color: #8095a8"
></span></strong>
<strong
class=
"font-bold"
>
{{ request.user.name }}
<span
style=
"color: #8095a8"
></span></strong>
</span>
</span>
<span
class=
"text-muted text-xs block"
>
<span
class=
"text-muted text-xs block"
>
{{ request.user.get_role_display | default:
'普通用户'
}}
<b
class=
"caret"
></b>
{{ request.user.get_role_display | default:
"{% trans 'User' %}"
}}
<b
class=
"caret"
></b>
</span>
</span>
</span>
</span>
</a>
</a>
<ul
class=
"dropdown-menu animated fadeInRight m-t-xs"
>
<ul
class=
"dropdown-menu animated fadeInRight m-t-xs"
>
<li><a
value=
""
>
个人信息
</a></li>
<li><a
value=
""
>
{% trans 'Profile' %}
</a></li>
<li><a
href=
""
>
修改信息
</a></li>
<li
class=
"divider"
></li>
<li
class=
"divider"
></li>
<li><a
href=
""
>
注销
</a></li>
<li><a
href=
""
>
{% trans 'Logout' %}
</a></li>
</ul>
</ul>
</div>
</div>
<div
class=
"logo-element"
>
<div
class=
"logo-element"
>
...
...
apps/templates/base.html
View file @
f2746844
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0"
>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0"
>
<meta
name=
"renderer"
content=
"webkit"
>
<meta
name=
"renderer"
content=
"webkit"
>
<title>
Jumpserver
| 开源跳板机系统
</title>
<title>
Jumpserver
</title>
<link
rel=
"shortcut icon"
href=
{%
static
"
img
/
facio
.
ico
"
%}
type=
"image/x-icon"
>
<link
rel=
"shortcut icon"
href=
{%
static
"
img
/
facio
.
ico
"
%}
type=
"image/x-icon"
>
{% include '_head_css_js.html' %}
{% include '_head_css_js.html' %}
...
...
apps/users/forms.py
View file @
f2746844
...
@@ -3,13 +3,14 @@
...
@@ -3,13 +3,14 @@
from
django.forms
import
ModelForm
from
django.forms
import
ModelForm
from
django
import
forms
from
django
import
forms
from
captcha.fields
import
CaptchaField
from
captcha.fields
import
CaptchaField
from
django.utils.translation
import
gettext_lazy
as
_
from
.models
import
User
,
UserGroup
from
.models
import
User
,
UserGroup
class
UserLoginForm
(
forms
.
Form
):
class
UserLoginForm
(
forms
.
Form
):
username
=
forms
.
CharField
(
label
=
'用户名'
,
max_length
=
100
)
username
=
forms
.
CharField
(
label
=
_
(
'Username'
)
,
max_length
=
100
)
password
=
forms
.
CharField
(
label
=
'密码'
,
widget
=
forms
.
PasswordInput
,
max_length
=
100
)
password
=
forms
.
CharField
(
label
=
_
(
'Password'
)
,
widget
=
forms
.
PasswordInput
,
max_length
=
100
)
captcha
=
CaptchaField
()
captcha
=
CaptchaField
()
...
@@ -27,7 +28,7 @@ class UserAddForm(ModelForm):
...
@@ -27,7 +28,7 @@ class UserAddForm(ModelForm):
}
}
widgets
=
{
widgets
=
{
'groups'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
'请选择用户组'
}),
'groups'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Join usergroups'
)
}),
}
}
...
@@ -46,7 +47,7 @@ class UserUpdateForm(ModelForm):
...
@@ -46,7 +47,7 @@ class UserUpdateForm(ModelForm):
}
}
widgets
=
{
widgets
=
{
'groups'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
'请选择用户组'
}),
'groups'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Join usergroups'
)
}),
}
}
...
...
apps/users/models.py
View file @
f2746844
...
@@ -12,6 +12,7 @@ from django.contrib.auth.models import AbstractUser, Permission
...
@@ -12,6 +12,7 @@ from django.contrib.auth.models import AbstractUser, Permission
from
django.db.models.signals
import
post_save
from
django.db.models.signals
import
post_save
from
django.dispatch
import
receiver
from
django.dispatch
import
receiver
from
django.db
import
IntegrityError
from
django.db
import
IntegrityError
from
django.utils.translation
import
ugettext_lazy
as
_
from
rest_framework.authtoken.models
import
Token
from
rest_framework.authtoken.models
import
Token
from
django.core
import
signing
from
django.core
import
signing
...
@@ -56,8 +57,8 @@ from django.core import signing
...
@@ -56,8 +57,8 @@ from django.core import signing
class
UserGroup
(
models
.
Model
):
class
UserGroup
(
models
.
Model
):
name
=
models
.
CharField
(
max_length
=
100
,
unique
=
True
,
verbose_name
=
'组名称'
)
name
=
models
.
CharField
(
max_length
=
100
,
unique
=
True
,
verbose_name
=
_
(
'Name'
)
)
comment
=
models
.
TextField
(
blank
=
True
,
verbose_name
=
'描述'
)
comment
=
models
.
TextField
(
blank
=
True
,
verbose_name
=
_
(
'Comment'
)
)
date_added
=
models
.
DateTimeField
(
auto_now_add
=
True
)
date_added
=
models
.
DateTimeField
(
auto_now_add
=
True
)
created_by
=
models
.
CharField
(
max_length
=
100
)
created_by
=
models
.
CharField
(
max_length
=
100
)
...
@@ -98,25 +99,26 @@ def date_expired_default():
...
@@ -98,25 +99,26 @@ def date_expired_default():
class
User
(
AbstractUser
):
class
User
(
AbstractUser
):
ROLE_CHOICES
=
(
ROLE_CHOICES
=
(
(
'Admin'
,
'管理员'
),
(
'Admin'
,
_
(
'Administrator'
)
),
(
'User'
,
'用户'
),
(
'User'
,
_
(
'User'
)
),
)
)
username
=
models
.
CharField
(
max_length
=
20
,
unique
=
True
,
verbose_name
=
'用户名'
)
username
=
models
.
CharField
(
max_length
=
20
,
unique
=
True
,
verbose_name
=
_
(
'Username'
)
)
name
=
models
.
CharField
(
max_length
=
20
,
blank
=
True
,
verbose_name
=
'姓名'
)
name
=
models
.
CharField
(
max_length
=
20
,
blank
=
True
,
verbose_name
=
_
(
'Name'
)
)
email
=
models
.
EmailField
(
max_length
=
30
,
unique
=
True
,
verbose_name
=
'邮件'
)
email
=
models
.
EmailField
(
max_length
=
30
,
unique
=
True
,
verbose_name
=
_
(
'Email'
)
)
groups
=
models
.
ManyToManyField
(
UserGroup
,
related_name
=
'users'
,
blank
=
True
,
verbose_name
=
'用户组'
)
groups
=
models
.
ManyToManyField
(
UserGroup
,
related_name
=
'users'
,
blank
=
True
,
verbose_name
=
_
(
'Usergroup'
)
)
role
=
models
.
CharField
(
choices
=
ROLE_CHOICES
,
default
=
'User'
,
max_length
=
10
,
blank
=
True
,
verbose_name
=
'角色'
)
role
=
models
.
CharField
(
choices
=
ROLE_CHOICES
,
default
=
'User'
,
max_length
=
10
,
blank
=
True
,
verbose_name
=
_
(
'Role'
)
)
avatar
=
models
.
ImageField
(
upload_to
=
"avatar"
,
verbose_name
=
'头像'
)
avatar
=
models
.
ImageField
(
upload_to
=
"avatar"
,
verbose_name
=
_
(
'Avatar'
)
)
wechat
=
models
.
CharField
(
max_length
=
30
,
blank
=
True
,
verbose_name
=
'微信'
)
wechat
=
models
.
CharField
(
max_length
=
30
,
blank
=
True
,
verbose_name
=
_
(
'Wechat'
)
)
phone
=
models
.
CharField
(
max_length
=
20
,
blank
=
True
,
verbose_name
=
'手机号'
)
phone
=
models
.
CharField
(
max_length
=
20
,
blank
=
True
,
verbose_name
=
_
(
'Phone'
)
)
enable_otp
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
'启用二次验证'
)
enable_otp
=
models
.
BooleanField
(
default
=
False
,
verbose_name
=
_
(
'Enable OTP'
)
)
secret_key_otp
=
models
.
CharField
(
max_length
=
16
,
blank
=
True
)
secret_key_otp
=
models
.
CharField
(
max_length
=
16
,
blank
=
True
)
private_key
=
models
.
CharField
(
max_length
=
5000
,
blank
=
True
,
verbose_name
=
'ssh私钥'
)
# ssh key max length 4096 bit
private_key
=
models
.
CharField
(
max_length
=
5000
,
blank
=
True
,
verbose_name
=
_
(
'ssh private key'
))
public_key
=
models
.
CharField
(
max_length
=
1000
,
blank
=
True
,
verbose_name
=
'公钥'
)
public_key
=
models
.
CharField
(
max_length
=
1000
,
blank
=
True
,
verbose_name
=
_
(
'ssh public key'
)
)
comment
=
models
.
TextField
(
max_length
=
200
,
blank
=
True
,
verbose_name
=
'描述'
)
comment
=
models
.
TextField
(
max_length
=
200
,
blank
=
True
,
verbose_name
=
_
(
'Comment'
)
)
is_first_login
=
models
.
BooleanField
(
default
=
False
)
is_first_login
=
models
.
BooleanField
(
default
=
False
)
date_expired
=
models
.
DateTimeField
(
default
=
date_expired_default
,
blank
=
True
,
null
=
True
,
verbose_name
=
'有效期'
)
date_expired
=
models
.
DateTimeField
(
default
=
date_expired_default
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Date expired'
))
created_by
=
models
.
CharField
(
max_length
=
30
,
default
=
''
)
created_by
=
models
.
CharField
(
max_length
=
30
,
default
=
''
)
@property
@property
...
@@ -204,7 +206,7 @@ class User(AbstractUser):
...
@@ -204,7 +206,7 @@ class User(AbstractUser):
user_email
=
data
.
get
(
'email'
,
''
)
user_email
=
data
.
get
(
'email'
,
''
)
user
=
cls
.
objects
.
get
(
id
=
user_id
,
email
=
user_email
)
user
=
cls
.
objects
.
get
(
id
=
user_id
,
email
=
user_email
)
except
signing
.
BadSignature
,
cls
.
DoesNotExist
:
except
(
signing
.
BadSignature
,
cls
.
DoesNotExist
)
:
user
=
None
user
=
None
return
user
return
user
...
@@ -220,11 +222,11 @@ class User(AbstractUser):
...
@@ -220,11 +222,11 @@ class User(AbstractUser):
def
initial
(
cls
):
def
initial
(
cls
):
user
=
cls
(
username
=
'admin'
,
user
=
cls
(
username
=
'admin'
,
email
=
'admin@jumpserver.org'
,
email
=
'admin@jumpserver.org'
,
name
=
'Administrator'
,
name
=
_
(
'Administrator'
)
,
password_raw
=
'admin'
,
password_raw
=
'admin'
,
role
=
'Admin'
,
role
=
'Admin'
,
comment
=
'Administrator is the super user of system'
,
comment
=
_
(
'Administrator is the super user of system'
)
,
created_by
=
'System'
)
created_by
=
_
(
'System'
)
)
user
.
save
()
user
.
save
()
user
.
groups
.
add
(
UserGroup
.
initial
())
user
.
groups
.
add
(
UserGroup
.
initial
())
...
...
apps/users/templates/users/_user.html
View file @
f2746844
{% extends 'base.html' %}
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load static %}
{% load bootstrap %}
{% load bootstrap %}
{% block custom_head_css_js %}
{% block custom_head_css_js %}
...
@@ -13,7 +14,7 @@
...
@@ -13,7 +14,7 @@
<div
class=
"col-sm-12"
>
<div
class=
"col-sm-12"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox-title"
>
<div
class=
"ibox-title"
>
<h5>
填写用户信息
</h5>
<h5>
{% trans 'Create user' %}
</h5>
<div
class=
"ibox-tools"
>
<div
class=
"ibox-tools"
>
<a
class=
"collapse-link"
>
<a
class=
"collapse-link"
>
<i
class=
"fa fa-chevron-up"
></i>
<i
class=
"fa fa-chevron-up"
></i>
...
@@ -29,7 +30,7 @@
...
@@ -29,7 +30,7 @@
<div
class=
"ibox-content"
>
<div
class=
"ibox-content"
>
<form
method=
"post"
id=
"userForm"
class=
"form-horizontal"
action=
""
enctype=
"multipart/form-data"
>
<form
method=
"post"
id=
"userForm"
class=
"form-horizontal"
action=
""
enctype=
"multipart/form-data"
>
{% csrf_token %}
{% csrf_token %}
<h3>
账户
</h3>
<h3>
{% trans 'Account' %}
</h3>
{% block username %} {% endblock %}
{% block username %} {% endblock %}
{{ form.email|bootstrap_horizontal }}
{{ form.email|bootstrap_horizontal }}
{{ form.name|bootstrap_horizontal }}
{{ form.name|bootstrap_horizontal }}
...
@@ -39,7 +40,7 @@
...
@@ -39,7 +40,7 @@
{% block password %} {% endblock %}
{% block password %} {% endblock %}
<div
class=
"hr-line-dashed"
></div>
<div
class=
"hr-line-dashed"
></div>
<h3>
角色安全
</h3>
<h3>
{% trans 'Security and Role' %}
</h3>
{{ form.role|bootstrap_horizontal }}
{{ form.role|bootstrap_horizontal }}
<div
class=
"form-group {% if form.date_expired.errors %} has-error {% endif %}"
id=
"date_5"
>
<div
class=
"form-group {% if form.date_expired.errors %} has-error {% endif %}"
id=
"date_5"
>
<label
for=
"{{ form.date_expired.id_for_label }}"
class=
"col-sm-2 control-label"
>
{{ form.date_expired.label }}
</label>
<label
for=
"{{ form.date_expired.id_for_label }}"
class=
"col-sm-2 control-label"
>
{{ form.date_expired.label }}
</label>
...
@@ -52,21 +53,21 @@
...
@@ -52,21 +53,21 @@
</div>
</div>
</div>
</div>
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<label
for=
"{{ form.enable_otp.id_for_label }}"
class=
"col-sm-2 control-label"
>
二次验证
</label>
<label
for=
"{{ form.enable_otp.id_for_label }}"
class=
"col-sm-2 control-label"
>
{% trans 'Enable OTP' %}
</label>
<div
class=
"col-sm-8"
>
<div
class=
"col-sm-8"
>
{{ form.enable_otp }}
{{ form.enable_otp }}
</div>
</div>
</div>
</div>
<div
class=
"hr-line-dashed"
></div>
<div
class=
"hr-line-dashed"
></div>
<h3>
信息
</h3>
<h3>
{% trans 'Profile' %}
</h3>
{{ form.phone|bootstrap_horizontal }}
{{ form.phone|bootstrap_horizontal }}
{{ form.wechat|bootstrap_horizontal }}
{{ form.wechat|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }}
{{ form.comment|bootstrap_horizontal }}
<div
class=
"hr-line-dashed"
></div>
<div
class=
"hr-line-dashed"
></div>
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<div
class=
"col-sm-4 col-sm-offset-2"
>
<div
class=
"col-sm-4 col-sm-offset-2"
>
<button
class=
"btn btn-white"
type=
"reset"
>
取消
</button>
<button
class=
"btn btn-white"
type=
"reset"
>
{% trans 'Reset' %}
</button>
<button
id=
"submit_button"
class=
"btn btn-primary"
type=
"submit"
>
确认保存
</button>
<button
id=
"submit_button"
class=
"btn btn-primary"
type=
"submit"
>
{% trans 'Commit' %}
</button>
</div>
</div>
</div>
</div>
</form>
</form>
...
...
apps/users/templates/users/forget_password.html
View file @
f2746844
{% load static %}
{% load static %}
{% load i18n %}
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<html>
...
@@ -22,14 +23,14 @@
...
@@ -22,14 +23,14 @@
<div
class=
"ibox-content"
>
<div
class=
"ibox-content"
>
<img
src=
"{% static 'img/logo.png' %}"
style=
"margin: auto"
width=
"82"
height=
"82"
>
<img
src=
"{% static 'img/logo.png' %}"
style=
"margin: auto"
width=
"82"
height=
"82"
>
<h2
class=
"font-bold"
style=
"display: inline"
>
忘记密码
?
</h2>
<h2
class=
"font-bold"
style=
"display: inline"
>
{% trans 'Forget password' %}
?
</h2>
<h1></h1>
<h1></h1>
{% if errors %}
{% if errors %}
<p
class=
"red-fonts"
>
{{ errors }}
</p>
<p
class=
"red-fonts"
>
{{ errors }}
</p>
{% endif %}
{% endif %}
<p>
<p>
输入您的邮箱, 将会发一封重置短信邮件到您的邮箱中
{% trans 'Input your email, that will send a mail to your' %}
</p>
</p>
<div
class=
"row"
>
<div
class=
"row"
>
...
@@ -40,7 +41,7 @@
...
@@ -40,7 +41,7 @@
<input
type=
"email"
name=
"email"
class=
"form-control"
placeholder=
"Email address"
required=
""
>
<input
type=
"email"
name=
"email"
class=
"form-control"
placeholder=
"Email address"
required=
""
>
</div>
</div>
<button
type=
"submit"
class=
"btn btn-primary block full-width m-b"
>
重置密码
</button>
<button
type=
"submit"
class=
"btn btn-primary block full-width m-b"
>
{% trans 'Commit' %}
</button>
</form>
</form>
</div>
</div>
...
...
apps/users/templates/users/login.html
View file @
f2746844
{% load static %}
{% load static %}
{% load i18n %}
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<html>
...
@@ -23,23 +24,17 @@
...
@@ -23,23 +24,17 @@
<body
class=
"gray-bg"
>
<body
class=
"gray-bg"
>
<div
class=
"loginColumns animated fadeInDown"
>
<div
class=
"loginColumns animated fadeInDown"
>
<div
class=
"row"
>
<div
class=
"row"
>
<div
class=
"col-md-6"
>
<div
class=
"col-md-6"
>
<h2
class=
"font-bold"
>
欢迎使用Jumpserver开源跳板机
</h2>
<h2
class=
"font-bold"
>
欢迎使用Jumpserver开源跳板机
</h2>
<p>
<p>
Jumpserver是一款使用Python, Django开发的开源跳板机系统, 助力互联网企业高效 用户、资产、权限、审计 管理
Jumpserver是一款使用Python, Django开发的开源跳板机系统, 助力互联网企业高效 用户、资产、权限、审计 管理
</p>
</p>
<p>
<p>
我们自五湖四海,我们对开源精神无比敬仰和崇拜,我们对完美、整洁、优雅 无止境的追求
我们自五湖四海,我们对开源精神无比敬仰和崇拜,我们对完美、整洁、优雅 无止境的追求
</p>
</p>
<p>
<p>
专注自动化运维,努力打造 易用、稳定、安全、自动化 的跳板机, 这是我们的不懈的追求和动力
专注自动化运维,努力打造 易用、稳定、安全、自动化 的跳板机, 这是我们的不懈的追求和动力
</p>
</p>
<p>
<p>
<small>
永远年轻,永远热泪盈眶 stay foolish stay hungry
</small>
<small>
永远年轻,永远热泪盈眶 stay foolish stay hungry
</small>
</p>
</p>
...
@@ -47,27 +42,27 @@
...
@@ -47,27 +42,27 @@
</div>
</div>
<div
class=
"col-md-6"
>
<div
class=
"col-md-6"
>
<div
class=
"ibox-content"
>
<div
class=
"ibox-content"
>
<div><img
src=
"{% static 'img/logo.png' %}"
width=
"82"
height=
"82"
>
<span
class=
"font-bold text-center"
style=
"font-size: 32px; font-family: inherit"
>
登录
</span></div>
<div><img
src=
"{% static 'img/logo.png' %}"
width=
"82"
height=
"82"
>
<span
class=
"font-bold text-center"
style=
"font-size: 32px; font-family: inherit"
>
{% trans 'Login' %}
</span></div>
<form
class=
"m-t"
role=
"form"
method=
"post"
action=
"{% url 'users:login' %}"
>
<form
class=
"m-t"
role=
"form"
method=
"post"
action=
"{% url 'users:login' %}"
>
{% csrf_token %}
{% csrf_token %}
{% if form.errors %}
{% if form.errors %}
{% if 'captcha' in form.errors %}
{% if 'captcha' in form.errors %}
<p
class=
"red-fonts"
>
验证码错误
</p>
<p
class=
"red-fonts"
>
{% trans 'Captcha invalid' %}
</p>
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% if errors %}
{% if errors %}
<p
class=
"red-fonts"
>
{{ errors }}
</p>
<p
class=
"red-fonts"
>
{{ errors }}
</p>
{% endif %}
{% endif %}
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<input
type=
"text"
class=
"form-control"
name=
"{{ form.username.html_name }}"
placeholder=
"
Username
"
required=
""
>
<input
type=
"text"
class=
"form-control"
name=
"{{ form.username.html_name }}"
placeholder=
"
{% trans 'Username' %}
"
required=
""
>
</div>
</div>
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<input
type=
"password"
class=
"form-control"
name=
"{{ form.password.html_name }}"
placeholder=
"
Password
"
required=
""
>
<input
type=
"password"
class=
"form-control"
name=
"{{ form.password.html_name }}"
placeholder=
"
{% trans 'Password' %}
"
required=
""
>
</div>
</div>
<div>
<div>
{{ form.captcha }}
{{ form.captcha }}
</div>
</div>
<button
type=
"submit"
class=
"btn btn-primary block full-width m-b"
>
Login
</button>
<button
type=
"submit"
class=
"btn btn-primary block full-width m-b"
>
{% trans 'Login' %}
</button>
<a
href=
"{% url 'users:forget-password' %}"
>
<a
href=
"{% url 'users:forget-password' %}"
>
<small>
Forgot password?
</small>
<small>
Forgot password?
</small>
...
...
apps/users/templates/users/reset_password.html
View file @
f2746844
{% load static %}
{% load static %}
{% load i18n %}
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<html>
...
@@ -41,31 +42,28 @@
...
@@ -41,31 +42,28 @@
</div>
</div>
<div
class=
"col-md-6"
>
<div
class=
"col-md-6"
>
<div
class=
"ibox-content"
>
<div
class=
"ibox-content"
>
<div><img
src=
"{% static 'img/logo.png' %}"
width=
"82"
height=
"82"
>
<span
class=
"font-bold text-center"
style=
"font-size: 32px; font-family: inherit"
>
重设密码
</span></div>
<div><img
src=
"{% static 'img/logo.png' %}"
width=
"82"
height=
"82"
>
<span
class=
"font-bold text-center"
style=
"font-size: 32px; font-family: inherit"
>
{% trans 'Reset password' %}
</span></div>
<form
class=
"m-t"
role=
"form"
method=
"post"
action=
""
>
<form
class=
"m-t"
role=
"form"
method=
"post"
action=
""
>
{% csrf_token %}
{% csrf_token %}
{% if errors %}
{% if errors %}
<p
class=
"red-fonts"
>
{{ errors }}
</p>
<p
class=
"red-fonts"
>
{{ errors }}
</p>
{% endif %}
{% endif %}
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<input
type=
"password"
class=
"form-control"
name=
"password"
placeholder=
"
Password
"
required=
""
>
<input
type=
"password"
class=
"form-control"
name=
"password"
placeholder=
"
{% trans 'Password' %}
"
required=
""
>
</div>
</div>
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<input
type=
"password"
class=
"form-control"
name=
"password-confirm"
placeholder=
"
Password again
"
required=
""
>
<input
type=
"password"
class=
"form-control"
name=
"password-confirm"
placeholder=
"
{% trans 'Password again' %}
"
required=
""
>
</div>
</div>
<button
type=
"submit"
class=
"btn btn-primary block full-width m-b"
>
Setting
</button>
<button
type=
"submit"
class=
"btn btn-primary block full-width m-b"
>
{% trans "Setting" %}
</button>
<a
href=
"#"
>
<a
href=
"#"
>
<small>
Forgot password?
</small>
<small>
Forgot password?
</small>
</a>
</a>
<p
class=
"text-muted text-center"
>
<p
class=
"text-muted text-center"
>
{#
<small>
Do not have an account?
</small>
#}
</p>
</p>
{#
<a
class=
"btn btn-sm btn-white btn-block"
href=
"register.html"
>
Create an account
</a>
#}
</form>
</form>
<p
class=
"m-t"
>
<p
class=
"m-t"
>
{#
<small>
Inspinia we app framework base on Bootstrap 3
©
2014
</small>
#}
</p>
</p>
</div>
</div>
</div>
</div>
...
...
apps/users/templates/users/user_add.html
View file @
f2746844
{% extends 'users/_user.html' %}
{% extends 'users/_user.html' %}
{% load i18n %}
{% load bootstrap %}
{% load bootstrap %}
{% block username %}
{% block username %}
{{ form.username|bootstrap_horizontal }}
{{ form.username|bootstrap_horizontal }}
{% endblock %}
{% endblock %}
{% block password %}
{% block password %}
<h3>
密码
</h3>
<h3>
{% trans 'Password' %}
</h3>
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<label
class=
"col-sm-2 control-label"
>
密码
</label>
<label
class=
"col-sm-2 control-label"
>
{% trans 'Password' %}
</label>
<div
class=
"col-sm-8 controls"
>
<div
class=
"col-sm-8 controls"
>
生成重置密码连接,通过邮件发送给用户
{% trans 'Reset link will be generated and sent to the user. ' %}
</div>
</div>
</div>
</div>
{% endblock %}
{% endblock %}
\ No newline at end of file
apps/users/templates/users/user_delete_confirm.html
View file @
f2746844
{% load i18n %}
<!DOCTYPE html>
<!DOCTYPE html>
<html
lang=
"en"
>
<html
lang=
"en"
>
<head>
<head>
<meta
charset=
"UTF-8"
>
<meta
charset=
"UTF-8"
>
<title>
确认删除
</title>
<title>
{% trans 'Confirm delete' %}
</title>
</head>
</head>
<body>
<body>
<form
action=
""
method=
"post"
>
<form
action=
""
method=
"post"
>
...
...
apps/users/templates/users/user_detail.html
View file @
f2746844
This diff is collapsed.
Click to expand it.
apps/users/templates/users/user_edit.html
View file @
f2746844
{% extends 'users/_user.html' %}
{% extends 'users/_user.html' %}
{% load i18n %}
{% block username %}
{% block username %}
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<label
for=
"{{ form.username.id_for_label }}"
class=
"col-sm-2 control-label"
>
用户名
</label>
<label
for=
"{{ form.username.id_for_label }}"
class=
"col-sm-2 control-label"
>
{% trans 'Username' %}
</label>
<div
class=
"col-sm-9 controls"
>
<div
class=
"col-sm-9 controls"
>
<input
id=
"{{ form.username.id_for_label }}"
name=
"{{ form.username.html_name }}"
type=
"text"
value=
"{{ user.username }}"
readonly
class=
"form-control"
>
<input
id=
"{{ form.username.id_for_label }}"
name=
"{{ form.username.html_name }}"
type=
"text"
value=
"{{ user.username }}"
readonly
class=
"form-control"
>
</div>
</div>
</div>
</div>
{% endblock %}
{% endblock %}
{% block password %}
{% block password %}
<h3>
密码
</h3>
<h3>
{% trans 'Password' %}
</h3>
<div
class=
"form-group"
>
<div
class=
"form-group"
>
<label
for=
"password"
class=
"col-sm-2 control-label"
>
密码
</label>
<label
for=
"password"
class=
"col-sm-2 control-label"
>
{% trans 'Password' %}
</label>
<div
class=
"col-sm-9 controls"
>
<div
class=
"col-sm-9 controls"
>
<input
id=
"password"
name=
"password"
type=
"password"
class=
"form-control"
>
<input
id=
"password"
name=
"password"
type=
"password"
class=
"form-control"
>
</div>
</div>
...
...
apps/users/templates/users/user_list.bak.html
deleted
100644 → 0
View file @
ba3f46fb
{% extends '_list_base.html' %}
{% load common_tags %}
<div
class=
"col-sm-12"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox-title"
>
<h5>
查看用户
</h5>
<div
class=
"ibox-tools"
>
<a
class=
"collapise-link"
>
<i
class=
"fa fa-chevron-up"
></i>
</a>
<a
class=
"dropdown-toggle"
data-toggle=
"dropdown"
href=
"#"
>
<i
class=
"fa fa-wrench"
></i>
</a>
<a
class=
"close-link"
>
<i
class=
"fa fa-times"
></i>
</a>
</div>
</div>
<div
class=
"ibox-content"
>
<div
class=
""
>
<a
href=
"{% url 'users:user-add' %}"
class=
"btn btn-sm btn-primary "
>
添加用户
</a>
<a
id=
"del_btn"
class=
"btn btn-sm btn-danger "
>
删除所选
</a>
<form
id=
"search_form"
method=
"get"
action=
""
class=
"pull-right mail-search"
>
<div
class=
"input-group"
>
<input
type=
"text"
class=
"form-control input-sm"
name=
"keyword"
placeholder=
"用户名或姓名"
value=
"{{ keyword }}"
>
<div
class=
"input-group-btn"
>
<button
id=
'search_btn'
type=
"submit"
class=
"btn btn-sm btn-primary"
>
搜索
</button>
</div>
</div>
</form>
</div>
<table
class=
"table table-striped table-bordered table-hover "
id=
"editable"
>
<thead>
<tr>
<th
class=
"text-center"
>
<input
type=
"checkbox"
id=
"check_all"
onclick=
"checkAll('check_all', 'checked')"
>
</th>
<th
class=
"text-center"
><a
href=
"{% url 'users:user-list' %}?sort=name"
>
姓名
</a></th>
<th
class=
"text-center"
><a
href=
"{% url 'users:user-list' %}?sort=username"
>
用户名
</a></th>
<th
class=
"text-center"
>
角色
</th>
<th
class=
"text-center"
>
用户组
</th>
<th
class=
"text-center"
>
资产数量
</th>
<th
class=
"text-center"
><a
href=
"{% url 'users:user-list' %}?sort=date_expired"
>
有效
</a></th>
<th
class=
"text-center"
></th>
</tr>
</thead>
<tbody>
{% for user in user_list %}
<tr
class=
"gradeX"
>
<td
class=
"text-center"
>
<input
type=
"checkbox"
name=
"checked"
value=
"{{ user.id }}"
>
</td>
<td
class=
"text-center"
>
<a
href=
"{% url 'users:user-detail' pk=user.id %}"
>
{{ user.name }}
</a>
</td>
<td
class=
"text-center"
>
{{ user.username }}
</td>
<td
class=
"text-center"
>
{{ user.role.name }}
</td>
<td
class=
"text-center"
title=
"{% for user_group in user.group.all %} {{ user_group.name }} {% endfor %}"
>
{{ user.groups.all|join_queryset_attr:"name" }}
</td>
<th
class=
"text-center"
>
{{ user.name }}
</th>
<td
class=
"text-center"
>
{% if user.is_expired %}
<i
class=
"fa fa-times text-danger"
></i>
{% else %}
<i
class=
"fa fa-check text-navy"
></i>
{% endif %}
</td>
<td
class=
"text-center"
>
<a
href=
"{% url 'users:user-edit' pk=user.id %}"
class=
"btn btn-xs btn-info"
>
编辑
</a>
<a
href=
"{% url 'users:user-delete' pk=user.id %}"
class=
"btn btn-xs btn-danger del {% if user.username == 'admin' %} disabled {% endif %}"
>
删除
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div
class=
"row"
>
<div
class=
"col-sm-6"
>
</div>
{% include '_pagination.html' %}
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
apps/users/templates/users/user_list.html
View file @
f2746844
{% extends '_list_base.html' %}
{% extends '_list_base.html' %}
{% load i18n %}
{% load common_tags %}
{% load common_tags %}
{% block content_left_head %}
{% block content_left_head %}
<a
href=
"{% url 'users:user-add' %}"
class=
"btn btn-sm btn-primary "
>
添加用户
</a>
<a
href=
"{% url 'users:user-add' %}"
class=
"btn btn-sm btn-primary "
>
{% trans "Create user" %}
</a>
{#
<a
id=
"del_btn"
class=
"btn btn-sm btn-danger "
>
删除所选
</a>
#}
{% endblock %}
{% endblock %}
{% block table_head %}
{% block table_head %}
<th
class=
"text-center"
>
<th
class=
"text-center"
>
<input
type=
"checkbox"
id=
"check_all"
onclick=
"checkAll('check_all', 'checked')"
>
<input
type=
"checkbox"
id=
"check_all"
onclick=
"checkAll('check_all', 'checked')"
>
</th>
</th>
<th
class=
"text-center"
><a
href=
"{% url 'users:user-list' %}?sort=name"
>
姓名
</a></th>
<th
class=
"text-center"
><a
href=
"{% url 'users:user-list' %}?sort=name"
>
{% trans 'Name' %}
</a></th>
<th
class=
"text-center"
><a
href=
"{% url 'users:user-list' %}?sort=username"
>
用户名
</a></th>
<th
class=
"text-center"
><a
href=
"{% url 'users:user-list' %}?sort=username"
>
{% trans 'Username' %}
</a></th>
<th
class=
"text-center"
>
角色
</th>
<th
class=
"text-center"
>
{% trans 'Role' %}
</th>
<th
class=
"text-center"
>
用户组
</th>
<th
class=
"text-center"
>
{% trans 'Usergroup' %}
</th>
<th
class=
"text-center"
>
资产数量
</th>
<th
class=
"text-center"
>
{% trans 'Asset num' %}
</th>
<th
class=
"text-center"
><a
href=
"{% url 'users:user-list' %}?sort=date_expired"
>
有效
</a></th>
<th
class=
"text-center"
><a
href=
"{% url 'users:user-list' %}?sort=date_expired"
>
{% trans 'Active' %}
</a></th>
<th
class=
"text-center"
></th>
<th
class=
"text-center"
></th>
{% endblock %}
{% endblock %}
...
@@ -41,8 +41,8 @@
...
@@ -41,8 +41,8 @@
{% endif %}
{% endif %}
</td>
</td>
<td
class=
"text-center"
>
<td
class=
"text-center"
>
<a
href=
"{% url 'users:user-edit' pk=user.id %}"
class=
"btn btn-xs btn-info"
>
编辑
</a>
<a
href=
"{% url 'users:user-edit' pk=user.id %}"
class=
"btn btn-xs btn-info"
>
{% trans 'Edit' %}
</a>
<a
href=
"{% url 'users:user-delete' pk=user.id %}"
class=
"btn btn-xs btn-danger del {% if user.id == request.user.id or user.username == 'admin' %} disabled {% endif %}"
>
删除
</a>
<a
href=
"{% url 'users:user-delete' pk=user.id %}"
class=
"btn btn-xs btn-danger del {% if user.id == request.user.id or user.username == 'admin' %} disabled {% endif %}"
>
{% trans 'Delete' %}
</a>
</td>
</td>
</tr>
</tr>
{% endfor %}
{% endfor %}
...
@@ -52,15 +52,15 @@
...
@@ -52,15 +52,15 @@
<form
id=
""
method=
"get"
action=
""
class=
" mail-search"
>
<form
id=
""
method=
"get"
action=
""
class=
" mail-search"
>
<div
class=
"input-group"
>
<div
class=
"input-group"
>
<select
class=
"form-control m-b"
style=
"width: auto"
>
<select
class=
"form-control m-b"
style=
"width: auto"
>
<option>
批量删除
</option>
<option>
{% trans 'Delete selected' %}
</option>
<option>
批量更新
</option>
<option>
{% trans 'Update selected' %}
</option>
<option>
批量禁用
</option>
<option>
{% trans 'Deactive selected' %}
</option>
<option>
批量导出
</option>
<option>
{% trans 'Export selected' %}
</option>
</select>
</select>
<div
class=
"input-group-btn pull-left"
style=
"padding-left: 5px;"
>
<div
class=
"input-group-btn pull-left"
style=
"padding-left: 5px;"
>
<button
id=
'search_btn'
type=
"submit"
style=
"height: 32px;"
class=
"btn btn-sm btn-primary"
>
<button
id=
'search_btn'
type=
"submit"
style=
"height: 32px;"
class=
"btn btn-sm btn-primary"
>
确认
{% trans 'Commit' %}
</button>
</button>
</div>
</div>
...
...
apps/users/utils.py
View file @
f2746844
...
@@ -8,6 +8,7 @@ import logging
...
@@ -8,6 +8,7 @@ import logging
from
paramiko.rsakey
import
RSAKey
from
paramiko.rsakey
import
RSAKey
from
django.contrib.auth.mixins
import
UserPassesTestMixin
from
django.contrib.auth.mixins
import
UserPassesTestMixin
from
django.urls
import
reverse_lazy
from
django.urls
import
reverse_lazy
from
django.utils.translation
import
ugettext
as
_
from
common.tasks
import
send_mail_async
from
common.tasks
import
send_mail_async
from
common.utils
import
reverse
from
common.utils
import
reverse
...
@@ -43,7 +44,7 @@ def ssh_key_gen(length=2048, password=None, username='root', hostname=None):
...
@@ -43,7 +44,7 @@ def ssh_key_gen(length=2048, password=None, username='root', hostname=None):
f
=
StringIO
.
StringIO
()
f
=
StringIO
.
StringIO
()
try
:
try
:
logger
.
debug
(
'Begin to generate ssh private key ...'
)
logger
.
debug
(
_
(
'Begin to generate ssh private key ...'
)
)
private_key_obj
=
RSAKey
.
generate
(
length
)
private_key_obj
=
RSAKey
.
generate
(
length
)
private_key_obj
.
write_private_key
(
f
,
password
=
password
)
private_key_obj
.
write_private_key
(
f
,
password
=
password
)
private_key
=
f
.
getvalue
()
private_key
=
f
.
getvalue
()
...
@@ -55,33 +56,33 @@ def ssh_key_gen(length=2048, password=None, username='root', hostname=None):
...
@@ -55,33 +56,33 @@ def ssh_key_gen(length=2048, password=None, username='root', hostname=None):
'hostname'
:
hostname
,
'hostname'
:
hostname
,
}
}
logger
.
debug
(
'Finish to generate ssh private key ...'
)
logger
.
debug
(
_
(
'Finish to generate ssh private key ...'
)
)
return
private_key
,
public_key
return
private_key
,
public_key
except
IOError
:
except
IOError
:
raise
IOError
(
'These is error when generate ssh key.'
)
raise
IOError
(
_
(
'These is error when generate ssh key.'
)
)
def
user_add_success_next
(
user
):
def
user_add_success_next
(
user
):
subject
=
'您的用户创建成功'
subject
=
_
(
'Create account successfully'
)
recipient_list
=
[
user
.
email
]
recipient_list
=
[
user
.
email
]
message
=
"""
message
=
_
(
"""
您好
%(name)
s:
Hello
%(name)
s:
</br>
</br>
恭喜您,您的账号已经创建成功.
Your account has been created successfully
</br>
</br>
<a href="
%(rest_password_url)
s?token=
%(rest_password_token)
s">
请点击这里设置密码
</a>
<a href="
%(rest_password_url)
s?token=
%(rest_password_token)
s">
click here to set your password
</a>
</br>
</br>
这个链接有效期1小时, 超过时间您可以 <a href="
%(forget_password_url)
s?email=
%(email)
s">重新申请
</a>
This link is valid for 1 hour. After it expires, <a href="
%(forget_password_url)
s?email=
%(email)
s">request new one
</a>
</br>
</br>
---
---
</br>
</br>
<a href="
%(login_url)
s">
直接登录
</a>
<a href="
%(login_url)
s">
Login direct
</a>
</br>
</br>
"""
%
{
"""
)
%
{
'name'
:
user
.
name
,
'name'
:
user
.
name
,
'rest_password_url'
:
reverse
(
'users:reset-password'
,
external
=
True
),
'rest_password_url'
:
reverse
(
'users:reset-password'
,
external
=
True
),
'rest_password_token'
:
user
.
generate_reset_token
(),
'rest_password_token'
:
user
.
generate_reset_token
(),
...
@@ -94,25 +95,25 @@ def user_add_success_next(user):
...
@@ -94,25 +95,25 @@ def user_add_success_next(user):
def
send_reset_password_mail
(
user
):
def
send_reset_password_mail
(
user
):
subject
=
'重设密码'
subject
=
_
(
'Reset password'
)
recipient_list
=
[
user
.
email
]
recipient_list
=
[
user
.
email
]
message
=
"""
message
=
_
(
"""
您好
%(name)
s:
Hello
%(name)
s:
</br>
</br>
您好,请点击下面链接重置密码, 如果不是您申请的, 请关注账号安全
Please click the link below to reset your password, if not your request, concern your account security
</br>
</br>
<a href="
%(rest_password_url)
s?token=
%(rest_password_token)
s">
请点击这里设置密码
</a>
<a href="
%(rest_password_url)
s?token=
%(rest_password_token)
s">
Click here reset password
</a>
</br>
</br>
这个链接有效期1小时, 超过时间您可以 <a href="
%(forget_password_url)
s?email=
%(email)
s">重新申请
</a>
This link is valid for 1 hour. After it expires, <a href="
%(forget_password_url)
s?email=
%(email)
s">request new one<
</a>
</br>
</br>
---
---
</br>
</br>
<a href="
%(login_url)
s">
直接登录
</a>
<a href="
%(login_url)
s">
Login direct
</a>
</br>
</br>
"""
%
{
"""
)
%
{
'name'
:
user
.
name
,
'name'
:
user
.
name
,
'rest_password_url'
:
reverse
(
'users:reset-password'
,
external
=
True
),
'rest_password_url'
:
reverse
(
'users:reset-password'
,
external
=
True
),
'rest_password_token'
:
user
.
generate_reset_token
(),
'rest_password_token'
:
user
.
generate_reset_token
(),
...
...
apps/users/views.py
View file @
f2746844
...
@@ -5,7 +5,6 @@ from __future__ import unicode_literals
...
@@ -5,7 +5,6 @@ from __future__ import unicode_literals
import
logging
import
logging
from
django.shortcuts
import
get_object_or_404
,
reverse
,
render
,
Http404
,
redirect
from
django.shortcuts
import
get_object_or_404
,
reverse
,
render
,
Http404
,
redirect
from
django.http
import
HttpResponseRedirect
from
django.urls
import
reverse_lazy
from
django.urls
import
reverse_lazy
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
django.db.models
import
Q
from
django.db.models
import
Q
...
@@ -68,8 +67,8 @@ class UserLogoutView(TemplateView):
...
@@ -68,8 +67,8 @@ class UserLogoutView(TemplateView):
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
context
=
{
'title'
:
'退出登录成功'
,
'title'
:
_
(
'Logout success'
)
,
'messages'
:
'退出登录成功, 返回登录页面'
,
'messages'
:
_
(
'Logout success, return login page'
)
,
'redirect_url'
:
reverse
(
'users:login'
),
'redirect_url'
:
reverse
(
'users:login'
),
'auto_redirect'
:
True
,
'auto_redirect'
:
True
,
}
}
...
@@ -98,7 +97,7 @@ class UserListView(AdminUserRequiredMixin, ListView):
...
@@ -98,7 +97,7 @@ class UserListView(AdminUserRequiredMixin, ListView):
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
UserListView
,
self
)
.
get_context_data
(
**
kwargs
)
context
=
super
(
UserListView
,
self
)
.
get_context_data
(
**
kwargs
)
context
.
update
({
'app'
:
'用户管理'
,
'action'
:
'用户列表'
,
'keyword'
:
self
.
keyword
})
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'User list'
)
,
'keyword'
:
self
.
keyword
})
return
context
return
context
...
@@ -107,11 +106,11 @@ class UserAddView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
...
@@ -107,11 +106,11 @@ class UserAddView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
form_class
=
UserAddForm
form_class
=
UserAddForm
template_name
=
'users/user_add.html'
template_name
=
'users/user_add.html'
success_url
=
reverse_lazy
(
'users:user-list'
)
success_url
=
reverse_lazy
(
'users:user-list'
)
success_message
=
'添加用户 <a href="
%
s">
%
s</a> 成功 .'
success_message
=
_
(
'Create user<a href="
%
s">
%
s</a> success.'
)
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
UserAddView
,
self
)
.
get_context_data
(
**
kwargs
)
context
=
super
(
UserAddView
,
self
)
.
get_context_data
(
**
kwargs
)
context
.
update
({
'app'
:
'用户管理'
,
'action'
:
'用户添加'
})
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'Create user'
)
})
return
context
return
context
def
form_valid
(
self
,
form
):
def
form_valid
(
self
,
form
):
...
@@ -153,7 +152,7 @@ class UserUpdateView(AdminUserRequiredMixin, UpdateView):
...
@@ -153,7 +152,7 @@ class UserUpdateView(AdminUserRequiredMixin, UpdateView):
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
UserUpdateView
,
self
)
.
get_context_data
(
**
kwargs
)
context
=
super
(
UserUpdateView
,
self
)
.
get_context_data
(
**
kwargs
)
context
.
update
({
'app'
:
'用户管理'
,
'action'
:
'用户编辑'
})
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'Edit user'
)
})
return
context
return
context
...
@@ -171,7 +170,7 @@ class UserDetailView(AdminUserRequiredMixin, DetailView):
...
@@ -171,7 +170,7 @@ class UserDetailView(AdminUserRequiredMixin, DetailView):
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
UserDetailView
,
self
)
.
get_context_data
(
**
kwargs
)
context
=
super
(
UserDetailView
,
self
)
.
get_context_data
(
**
kwargs
)
groups
=
[
group
for
group
in
UserGroup
.
objects
.
iterator
()
if
group
not
in
self
.
object
.
groups
.
iterator
()]
groups
=
[
group
for
group
in
UserGroup
.
objects
.
iterator
()
if
group
not
in
self
.
object
.
groups
.
iterator
()]
context
.
update
({
'app'
:
'用户管理'
,
'action'
:
'用户详情'
,
'groups'
:
groups
})
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'User detail'
)
,
'groups'
:
groups
})
return
context
return
context
...
@@ -195,7 +194,7 @@ class UserGroupListView(AdminUserRequiredMixin, ListView):
...
@@ -195,7 +194,7 @@ class UserGroupListView(AdminUserRequiredMixin, ListView):
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
UserGroupListView
,
self
)
.
get_context_data
(
**
kwargs
)
context
=
super
(
UserGroupListView
,
self
)
.
get_context_data
(
**
kwargs
)
context
.
update
({
'app'
:
'用户管理'
,
'action'
:
'用户组列表'
,
'keyword'
:
self
.
keyword
})
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'Usergroup list'
)
,
'keyword'
:
self
.
keyword
})
return
context
return
context
...
@@ -208,7 +207,7 @@ class UserGroupAddView(AdminUserRequiredMixin, CreateView):
...
@@ -208,7 +207,7 @@ class UserGroupAddView(AdminUserRequiredMixin, CreateView):
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
UserGroupAddView
,
self
)
.
get_context_data
(
**
kwargs
)
context
=
super
(
UserGroupAddView
,
self
)
.
get_context_data
(
**
kwargs
)
users
=
User
.
objects
.
all
()
users
=
User
.
objects
.
all
()
context
.
update
({
'app'
:
'用户管理'
,
'action'
:
'用户组添加'
,
'users'
:
users
})
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'Create usergroup'
)
,
'users'
:
users
})
return
context
return
context
def
form_valid
(
self
,
form
):
def
form_valid
(
self
,
form
):
...
@@ -240,7 +239,7 @@ class UserForgetPasswordView(TemplateView):
...
@@ -240,7 +239,7 @@ class UserForgetPasswordView(TemplateView):
email
=
request
.
POST
.
get
(
'email'
)
email
=
request
.
POST
.
get
(
'email'
)
user
=
get_object_or_none
(
User
,
email
=
email
)
user
=
get_object_or_none
(
User
,
email
=
email
)
if
not
user
:
if
not
user
:
return
self
.
get
(
request
,
errors
=
'邮件地址错误,请重新输入'
)
return
self
.
get
(
request
,
errors
=
_
(
'Email address invalid, input again'
)
)
else
:
else
:
send_reset_password_mail
(
user
)
send_reset_password_mail
(
user
)
return
HttpResponseRedirect
(
reverse
(
'users:forget-password-sendmail-success'
))
return
HttpResponseRedirect
(
reverse
(
'users:forget-password-sendmail-success'
))
...
@@ -251,8 +250,8 @@ class UserForgetPasswordSendmailSuccessView(TemplateView):
...
@@ -251,8 +250,8 @@ class UserForgetPasswordSendmailSuccessView(TemplateView):
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
context
=
{
'title'
:
'发送重置邮件'
,
'title'
:
_
(
'Send reset password message'
)
,
'messages'
:
'发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)'
,
'messages'
:
_
(
'Send reset password mail success, login your mail box and follow it '
)
,
'redirect_url'
:
reverse
(
'users:login'
),
'redirect_url'
:
reverse
(
'users:login'
),
}
}
kwargs
.
update
(
context
)
kwargs
.
update
(
context
)
...
@@ -264,8 +263,8 @@ class UserResetPasswordSuccessView(TemplateView):
...
@@ -264,8 +263,8 @@ class UserResetPasswordSuccessView(TemplateView):
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
context
=
{
'title'
:
'重设密码成功'
,
'title'
:
_
(
'Reset password success'
)
,
'messages'
:
'密码重置成功, 返回登录页面 '
,
'messages'
:
_
(
'Reset password success, return to login page'
)
,
'redirect_url'
:
reverse
(
'users:login'
),
'redirect_url'
:
reverse
(
'users:login'
),
'auto_redirect'
:
True
,
'auto_redirect'
:
True
,
}
}
...
@@ -281,7 +280,7 @@ class UserResetPasswordView(TemplateView):
...
@@ -281,7 +280,7 @@ class UserResetPasswordView(TemplateView):
user
=
User
.
validate_reset_token
(
token
)
user
=
User
.
validate_reset_token
(
token
)
if
not
user
:
if
not
user
:
kwargs
.
update
({
'errors'
:
'Token不正确或已过期'
})
kwargs
.
update
({
'errors'
:
_
(
'Token invalid or expired'
)
})
return
super
(
UserResetPasswordView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
return
super
(
UserResetPasswordView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
...
@@ -290,11 +289,11 @@ class UserResetPasswordView(TemplateView):
...
@@ -290,11 +289,11 @@ class UserResetPasswordView(TemplateView):
token
=
request
.
GET
.
get
(
'token'
)
token
=
request
.
GET
.
get
(
'token'
)
if
password
!=
password_confirm
:
if
password
!=
password_confirm
:
return
self
.
get
(
request
,
errors
=
'两次密码不一致'
)
return
self
.
get
(
request
,
errors
=
_
(
'Password not same'
)
)
user
=
User
.
validate_reset_token
(
token
)
user
=
User
.
validate_reset_token
(
token
)
if
not
user
:
if
not
user
:
return
self
.
get
(
request
,
errors
=
'Token不正确或已过期'
)
return
self
.
get
(
request
,
errors
=
_
(
'Token invalid or expired'
)
)
user
.
reset_password
(
password
)
user
.
reset_password
(
password
)
return
HttpResponseRedirect
(
reverse
(
'users:reset-password-success'
))
return
HttpResponseRedirect
(
reverse
(
'users:reset-password-success'
))
config-example.py
View file @
f2746844
...
@@ -23,6 +23,7 @@ class Config:
...
@@ -23,6 +23,7 @@ class Config:
# It's used to identify your site, When we send a create mail to user, we only know login url is /login/
# It's used to identify your site, When we send a create mail to user, we only know login url is /login/
# But we should know the absolute url like: http://jms.jumpserver.org/login/, so SITE_URL is
# But we should know the absolute url like: http://jms.jumpserver.org/login/, so SITE_URL is
# HTTP_PROTOCOL://HOST[:PORT]
# HTTP_PROTOCOL://HOST[:PORT]
# Todo: May be use :method: get_current_site more grace, bug restful api unknown ok or not
SITE_URL
=
'http://localhost'
SITE_URL
=
'http://localhost'
# Django security setting, if your disable debug model, you should setting that
# Django security setting, if your disable debug model, you should setting that
...
...
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