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
5434b657
Commit
5434b657
authored
Nov 12, 2019
by
BaiJiangJie
Browse files
Options
Browse Files
Download
Plain Diff
[Update] Merge branch dev to 1.5.5
parents
a01126c6
200ca65d
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
830 additions
and
504 deletions
+830
-504
node.py
apps/assets/models/node.py
+53
-12
asset_list.html
apps/assets/templates/assets/asset_list.html
+13
-10
signals_handlers.py
apps/authentication/signals_handlers.py
+1
-1
django.mo
apps/locale/zh/LC_MESSAGES/django.mo
+0
-0
django.po
apps/locale/zh/LC_MESSAGES/django.po
+148
-152
signals_handler.py
apps/perms/signals_handler.py
+0
-7
api.py
apps/settings/api.py
+128
-54
serializers.py
apps/settings/serializers.py
+1
-0
__init__.py
apps/settings/tasks/__init__.py
+4
-0
ldap.py
apps/settings/tasks/ldap.py
+17
-0
_ldap_list_users_modal.html
apps/settings/templates/settings/_ldap_list_users_modal.html
+85
-6
ldap_setting.html
apps/settings/templates/settings/ldap_setting.html
+1
-29
api_urls.py
apps/settings/urls/api_urls.py
+2
-1
utils.py
apps/settings/utils.py
+0
-219
__init__.py
apps/settings/utils/__init__.py
+4
-0
ldap.py
apps/settings/utils/ldap.py
+338
-0
views.py
apps/settings/views.py
+2
-0
signals_handler.py
apps/users/signals_handler.py
+13
-2
tasks.py
apps/users/tasks.py
+20
-11
No files found.
apps/assets/models/node.py
View file @
5434b657
...
@@ -6,6 +6,7 @@ import time
...
@@ -6,6 +6,7 @@ import time
from
django.db
import
models
,
transaction
from
django.db
import
models
,
transaction
from
django.db.models
import
Q
from
django.db.models
import
Q
from
django.db.utils
import
IntegrityError
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext
from
django.utils.translation
import
ugettext
from
django.core.cache
import
cache
from
django.core.cache
import
cache
...
@@ -67,7 +68,7 @@ class TreeMixin:
...
@@ -67,7 +68,7 @@ class TreeMixin:
@classmethod
@classmethod
def
refresh_node_assets
(
cls
,
t
=
None
):
def
refresh_node_assets
(
cls
,
t
=
None
):
logger
.
debug
(
"Refresh node
tree
assets"
)
logger
.
debug
(
"Refresh node assets"
)
key
=
cls
.
tree_assets_cache_key
key
=
cls
.
tree_assets_cache_key
ttl
=
cls
.
tree_cache_time
ttl
=
cls
.
tree_cache_time
if
not
t
:
if
not
t
:
...
@@ -336,6 +337,17 @@ class SomeNodesMixin:
...
@@ -336,6 +337,17 @@ class SomeNodesMixin:
else
:
else
:
return
False
return
False
@classmethod
def
get_next_org_root_node_key
(
cls
):
with
tmp_to_org
(
Organization
.
root
()):
org_nodes_roots
=
cls
.
objects
.
filter
(
key__regex
=
r'^[0-9]+$'
)
org_nodes_roots_keys
=
org_nodes_roots
.
values_list
(
'key'
,
flat
=
True
)
if
not
org_nodes_roots_keys
:
org_nodes_roots_keys
=
[
'1'
]
max_key
=
max
([
int
(
k
)
for
k
in
org_nodes_roots_keys
])
key
=
str
(
max_key
+
1
)
if
max_key
!=
0
else
'2'
return
key
@classmethod
@classmethod
def
create_org_root_node
(
cls
):
def
create_org_root_node
(
cls
):
# 如果使用current_org 在set_current_org时会死循环
# 如果使用current_org 在set_current_org时会死循环
...
@@ -343,14 +355,7 @@ class SomeNodesMixin:
...
@@ -343,14 +355,7 @@ class SomeNodesMixin:
with
transaction
.
atomic
():
with
transaction
.
atomic
():
if
not
ori_org
.
is_real
():
if
not
ori_org
.
is_real
():
return
cls
.
default_node
()
return
cls
.
default_node
()
set_current_org
(
Organization
.
root
())
key
=
cls
.
get_next_org_root_node_key
()
org_nodes_roots
=
cls
.
objects
.
filter
(
key__regex
=
r'^[0-9]+$'
)
org_nodes_roots_keys
=
org_nodes_roots
.
values_list
(
'key'
,
flat
=
True
)
if
not
org_nodes_roots_keys
:
org_nodes_roots_keys
=
[
'1'
]
key
=
max
([
int
(
k
)
for
k
in
org_nodes_roots_keys
])
key
=
str
(
key
+
1
)
if
key
!=
0
else
'2'
set_current_org
(
ori_org
)
root
=
cls
.
objects
.
create
(
key
=
key
,
value
=
ori_org
.
name
)
root
=
cls
.
objects
.
create
(
key
=
key
,
value
=
ori_org
.
name
)
return
root
return
root
...
@@ -384,9 +389,16 @@ class SomeNodesMixin:
...
@@ -384,9 +389,16 @@ class SomeNodesMixin:
def
default_node
(
cls
):
def
default_node
(
cls
):
with
tmp_to_org
(
Organization
.
default
()):
with
tmp_to_org
(
Organization
.
default
()):
defaults
=
{
'value'
:
cls
.
default_value
}
defaults
=
{
'value'
:
cls
.
default_value
}
obj
,
created
=
cls
.
objects
.
get_or_create
(
try
:
defaults
=
defaults
,
key
=
cls
.
default_key
,
obj
,
created
=
cls
.
objects
.
get_or_create
(
)
defaults
=
defaults
,
key
=
cls
.
default_key
,
)
except
IntegrityError
as
e
:
logger
.
error
(
"Create default node failed: {}"
.
format
(
e
))
cls
.
modify_other_org_root_node_key
()
obj
,
created
=
cls
.
objects
.
get_or_create
(
defaults
=
defaults
,
key
=
cls
.
default_key
,
)
return
obj
return
obj
@classmethod
@classmethod
...
@@ -405,6 +417,35 @@ class SomeNodesMixin:
...
@@ -405,6 +417,35 @@ class SomeNodesMixin:
cls
.
ungrouped_node
()
cls
.
ungrouped_node
()
cls
.
favorite_node
()
cls
.
favorite_node
()
@classmethod
def
modify_other_org_root_node_key
(
cls
):
"""
解决创建 default 节点失败的问题,
因为在其他组织下存在 default 节点,故在 DEFAULT 组织下 get 不到 create 失败
"""
logger
.
info
(
"Modify other org root node key"
)
with
tmp_to_org
(
Organization
.
root
()):
node_key1
=
cls
.
objects
.
filter
(
key
=
'1'
)
.
first
()
if
not
node_key1
:
logger
.
info
(
"Not found node that `key` = 1"
)
return
if
not
node_key1
.
org
.
is_real
():
logger
.
info
(
"Org is not real for node that `key` = 1"
)
return
with
transaction
.
atomic
():
with
tmp_to_org
(
node_key1
.
org
):
org_root_node_new_key
=
cls
.
get_next_org_root_node_key
()
for
n
in
cls
.
objects
.
all
():
old_key
=
n
.
key
key_list
=
n
.
key
.
split
(
':'
)
key_list
[
0
]
=
org_root_node_new_key
new_key
=
':'
.
join
(
key_list
)
n
.
key
=
new_key
n
.
save
()
logger
.
info
(
'Modify key ( {} > {} )'
.
format
(
old_key
,
new_key
))
class
Node
(
OrgModelMixin
,
SomeNodesMixin
,
TreeMixin
,
FamilyMixin
,
FullValueMixin
,
NodeAssetsMixin
):
class
Node
(
OrgModelMixin
,
SomeNodesMixin
,
TreeMixin
,
FamilyMixin
,
FullValueMixin
,
NodeAssetsMixin
):
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
...
...
apps/assets/templates/assets/asset_list.html
View file @
5434b657
...
@@ -426,13 +426,15 @@ $(document).ready(function(){
...
@@ -426,13 +426,15 @@ $(document).ready(function(){
function
success
(
data
)
{
function
success
(
data
)
{
url
=
setUrlParam
(
the_url
,
'spm'
,
data
.
spm
);
url
=
setUrlParam
(
the_url
,
'spm'
,
data
.
spm
);
requestApi
({
requestApi
({
url
:
url
,
url
:
url
,
method
:
'DELETE'
,
method
:
'DELETE'
,
success
:
refreshPage
,
success
:
function
()
{
flash_message
:
false
,
var
msg
=
"{% trans 'Asset Deleted.' %}"
;
swal
(
"{% trans 'Asset Delete' %}"
,
msg
,
"success"
);
refreshPage
();
},
flash_message
:
false
,
});
});
var
msg
=
"{% trans 'Asset Deleted.' %}"
;
swal
(
"{% trans 'Asset Delete' %}"
,
msg
,
"success"
);
}
}
function
fail
()
{
function
fail
()
{
var
msg
=
"{% trans 'Asset Deleting failed.' %}"
;
var
msg
=
"{% trans 'Asset Deleting failed.' %}"
;
...
@@ -440,10 +442,11 @@ $(document).ready(function(){
...
@@ -440,10 +442,11 @@ $(document).ready(function(){
}
}
requestApi
({
requestApi
({
url
:
"{% url 'api-common:resources-cache' %}"
,
url
:
"{% url 'api-common:resources-cache' %}"
,
method
:
'POST'
,
method
:
'POST'
,
body
:
JSON
.
stringify
(
data
),
body
:
JSON
.
stringify
(
data
),
success
:
success
,
success
:
success
,
error
:
fail
error
:
fail
,
flash_message
:
false
})
})
})
})
}
}
...
...
apps/authentication/signals_handlers.py
View file @
5434b657
...
@@ -43,7 +43,7 @@ def on_openid_login_success(sender, user=None, request=None, **kwargs):
...
@@ -43,7 +43,7 @@ def on_openid_login_success(sender, user=None, request=None, **kwargs):
@receiver
(
populate_user
)
@receiver
(
populate_user
)
def
on_ldap_create_user
(
sender
,
user
,
ldap_user
,
**
kwargs
):
def
on_ldap_create_user
(
sender
,
user
,
ldap_user
,
**
kwargs
):
if
user
and
user
.
username
!=
'admin'
:
if
user
and
user
.
username
not
in
[
'admin'
]
:
user
.
source
=
user
.
SOURCE_LDAP
user
.
source
=
user
.
SOURCE_LDAP
user
.
save
()
user
.
save
()
...
...
apps/locale/zh/LC_MESSAGES/django.mo
View file @
5434b657
No preview for this file type
apps/locale/zh/LC_MESSAGES/django.po
View file @
5434b657
...
@@ -8,7 +8,7 @@ msgid ""
...
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n"
"Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-11-
08 17:27
+0800\n"
"POT-Creation-Date: 2019-11-
12 14:10
+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
...
@@ -96,7 +96,7 @@ msgstr "运行参数"
...
@@ -96,7 +96,7 @@ msgstr "运行参数"
#: terminal/templates/terminal/session_list.html:28
#: terminal/templates/terminal/session_list.html:28
#: terminal/templates/terminal/session_list.html:72
#: terminal/templates/terminal/session_list.html:72
#: xpack/plugins/change_auth_plan/forms.py:73
#: xpack/plugins/change_auth_plan/forms.py:73
#: xpack/plugins/change_auth_plan/models.py:41
2
#: xpack/plugins/change_auth_plan/models.py:41
9
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:46
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:46
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:54
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:54
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:13
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:13
...
@@ -137,14 +137,14 @@ msgstr "资产"
...
@@ -137,14 +137,14 @@ msgstr "资产"
#: perms/templates/perms/remote_app_permission_remote_app.html:53
#: perms/templates/perms/remote_app_permission_remote_app.html:53
#: perms/templates/perms/remote_app_permission_user.html:53
#: perms/templates/perms/remote_app_permission_user.html:53
#: settings/models.py:29
#: settings/models.py:29
#: settings/templates/settings/_ldap_list_users_modal.html:3
1
#: settings/templates/settings/_ldap_list_users_modal.html:3
2
#: settings/templates/settings/command_storage_create.html:41
#: settings/templates/settings/command_storage_create.html:41
#: settings/templates/settings/replay_storage_create.html:44
#: settings/templates/settings/replay_storage_create.html:44
#: settings/templates/settings/terminal_setting.html:83
#: settings/templates/settings/terminal_setting.html:83
#: settings/templates/settings/terminal_setting.html:105 terminal/models.py:23
#: settings/templates/settings/terminal_setting.html:105 terminal/models.py:23
#: terminal/models.py:260 terminal/templates/terminal/terminal_detail.html:43
#: terminal/models.py:260 terminal/templates/terminal/terminal_detail.html:43
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14
#: users/models/user.py:
382
users/templates/users/_select_user_modal.html:13
#: users/models/user.py:
410
users/templates/users/_select_user_modal.html:13
#: users/templates/users/user_detail.html:64
#: users/templates/users/user_detail.html:64
#: users/templates/users/user_group_detail.html:55
#: users/templates/users/user_group_detail.html:55
#: users/templates/users/user_group_list.html:35
#: users/templates/users/user_group_list.html:35
...
@@ -152,7 +152,7 @@ msgstr "资产"
...
@@ -152,7 +152,7 @@ msgstr "资产"
#: users/templates/users/user_profile.html:51
#: users/templates/users/user_profile.html:51
#: users/templates/users/user_pubkey_update.html:57
#: users/templates/users/user_pubkey_update.html:57
#: xpack/plugins/change_auth_plan/forms.py:56
#: xpack/plugins/change_auth_plan/forms.py:56
#: xpack/plugins/change_auth_plan/models.py:6
3
#: xpack/plugins/change_auth_plan/models.py:6
4
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:61
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:61
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:12
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:12
#: xpack/plugins/cloud/models.py:59 xpack/plugins/cloud/models.py:144
#: xpack/plugins/cloud/models.py:59 xpack/plugins/cloud/models.py:144
...
@@ -197,9 +197,9 @@ msgstr "参数"
...
@@ -197,9 +197,9 @@ msgstr "参数"
#: orgs/models.py:16 perms/models/base.py:54
#: orgs/models.py:16 perms/models/base.py:54
#: perms/templates/perms/asset_permission_detail.html:98
#: perms/templates/perms/asset_permission_detail.html:98
#: perms/templates/perms/remote_app_permission_detail.html:90
#: perms/templates/perms/remote_app_permission_detail.html:90
#: users/models/user.py:4
23
users/serializers/group.py:32
#: users/models/user.py:4
51
users/serializers/group.py:32
#: users/templates/users/user_detail.html:112
#: users/templates/users/user_detail.html:112
#: xpack/plugins/change_auth_plan/models.py:10
8
#: xpack/plugins/change_auth_plan/models.py:10
9
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113
#: xpack/plugins/cloud/models.py:80 xpack/plugins/cloud/models.py:179
#: xpack/plugins/cloud/models.py:80 xpack/plugins/cloud/models.py:179
#: xpack/plugins/gathered_user/models.py:46
#: xpack/plugins/gathered_user/models.py:46
...
@@ -260,11 +260,11 @@ msgstr "创建日期"
...
@@ -260,11 +260,11 @@ msgstr "创建日期"
#: settings/models.py:34 terminal/models.py:33
#: settings/models.py:34 terminal/models.py:33
#: terminal/templates/terminal/terminal_detail.html:63
#: terminal/templates/terminal/terminal_detail.html:63
#: tickets/templates/tickets/ticket_detail.html:106 users/models/group.py:15
#: tickets/templates/tickets/ticket_detail.html:106 users/models/group.py:15
#: users/models/user.py:4
15
users/templates/users/user_detail.html:130
#: users/models/user.py:4
43
users/templates/users/user_detail.html:130
#: users/templates/users/user_group_detail.html:67
#: users/templates/users/user_group_detail.html:67
#: users/templates/users/user_group_list.html:37
#: users/templates/users/user_group_list.html:37
#: users/templates/users/user_profile.html:138
#: users/templates/users/user_profile.html:138
#: xpack/plugins/change_auth_plan/models.py:10
4
#: xpack/plugins/change_auth_plan/models.py:10
5
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:117
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:117
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:19
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:19
#: xpack/plugins/cloud/models.py:77 xpack/plugins/cloud/models.py:173
#: xpack/plugins/cloud/models.py:77 xpack/plugins/cloud/models.py:173
...
@@ -529,7 +529,7 @@ msgstr "创建远程应用"
...
@@ -529,7 +529,7 @@ msgstr "创建远程应用"
#: terminal/templates/terminal/session_list.html:36
#: terminal/templates/terminal/session_list.html:36
#: terminal/templates/terminal/terminal_list.html:36
#: terminal/templates/terminal/terminal_list.html:36
#: tickets/templates/tickets/login_confirm_ticket_list.html:18
#: tickets/templates/tickets/login_confirm_ticket_list.html:18
#: tickets/templates/tickets/login_confirm_ticket_list.html:10
5
#: tickets/templates/tickets/login_confirm_ticket_list.html:10
6
#: users/templates/users/_granted_assets.html:34
#: users/templates/users/_granted_assets.html:34
#: users/templates/users/user_group_list.html:38
#: users/templates/users/user_group_list.html:38
#: users/templates/users/user_list.html:41
#: users/templates/users/user_list.html:41
...
@@ -607,7 +607,7 @@ msgstr "端口"
...
@@ -607,7 +607,7 @@ msgstr "端口"
#: assets/templates/assets/asset_detail.html:196
#: assets/templates/assets/asset_detail.html:196
#: assets/templates/assets/system_user_assets.html:83
#: assets/templates/assets/system_user_assets.html:83
#: perms/models/asset_permission.py:81
#: perms/models/asset_permission.py:81
#: xpack/plugins/change_auth_plan/models.py:7
4
#: xpack/plugins/change_auth_plan/models.py:7
5
#: xpack/plugins/gathered_user/models.py:31
#: xpack/plugins/gathered_user/models.py:31
#: xpack/plugins/gathered_user/templates/gathered_user/task_list.html:17
#: xpack/plugins/gathered_user/templates/gathered_user/task_list.html:17
msgid "Nodes"
msgid "Nodes"
...
@@ -639,7 +639,7 @@ msgid "Domain"
...
@@ -639,7 +639,7 @@ msgid "Domain"
msgstr "网域"
msgstr "网域"
#: assets/forms/asset.py:69 assets/forms/asset.py:103 assets/forms/asset.py:116
#: assets/forms/asset.py:69 assets/forms/asset.py:103 assets/forms/asset.py:116
#: assets/forms/asset.py:152 assets/models/node.py:4
21
#: assets/forms/asset.py:152 assets/models/node.py:4
62
#: assets/serializers/system_user.py:36
#: assets/serializers/system_user.py:36
#: assets/templates/assets/asset_create.html:42
#: assets/templates/assets/asset_create.html:42
#: perms/forms/asset_permission.py:87 perms/forms/asset_permission.py:94
#: perms/forms/asset_permission.py:87 perms/forms/asset_permission.py:94
...
@@ -704,18 +704,18 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC"
...
@@ -704,18 +704,18 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC"
#: assets/templates/assets/system_user_list.html:48 audits/models.py:81
#: assets/templates/assets/system_user_list.html:48 audits/models.py:81
#: audits/templates/audits/login_log_list.html:57 authentication/forms.py:13
#: audits/templates/audits/login_log_list.html:57 authentication/forms.py:13
#: authentication/templates/authentication/login.html:58
#: authentication/templates/authentication/login.html:58
#: authentication/templates/authentication/xpack_login.html:9
1
#: authentication/templates/authentication/xpack_login.html:9
3
#: ops/models/adhoc.py:189 perms/templates/perms/asset_permission_list.html:70
#: ops/models/adhoc.py:189 perms/templates/perms/asset_permission_list.html:70
#: perms/templates/perms/asset_permission_user.html:55
#: perms/templates/perms/asset_permission_user.html:55
#: perms/templates/perms/remote_app_permission_user.html:54
#: perms/templates/perms/remote_app_permission_user.html:54
#: settings/templates/settings/_ldap_list_users_modal.html:3
0
users/forms.py:14
#: settings/templates/settings/_ldap_list_users_modal.html:3
1
users/forms.py:14
#: users/models/user.py:
380
users/templates/users/_select_user_modal.html:14
#: users/models/user.py:
408
users/templates/users/_select_user_modal.html:14
#: users/templates/users/user_detail.html:68
#: users/templates/users/user_detail.html:68
#: users/templates/users/user_list.html:36
#: users/templates/users/user_list.html:36
#: users/templates/users/user_profile.html:47
#: users/templates/users/user_profile.html:47
#: xpack/plugins/change_auth_plan/forms.py:58
#: xpack/plugins/change_auth_plan/forms.py:58
#: xpack/plugins/change_auth_plan/models.py:6
5
#: xpack/plugins/change_auth_plan/models.py:6
6
#: xpack/plugins/change_auth_plan/models.py:4
08
#: xpack/plugins/change_auth_plan/models.py:4
15
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:65
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:65
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:53
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:53
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:12
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:12
...
@@ -734,7 +734,7 @@ msgstr "密码或密钥密码"
...
@@ -734,7 +734,7 @@ msgstr "密码或密钥密码"
#: assets/templates/assets/_asset_user_auth_view_modal.html:27
#: assets/templates/assets/_asset_user_auth_view_modal.html:27
#: authentication/forms.py:15
#: authentication/forms.py:15
#: authentication/templates/authentication/login.html:66
#: authentication/templates/authentication/login.html:66
#: authentication/templates/authentication/xpack_login.html:
99
#: authentication/templates/authentication/xpack_login.html:
101
#: settings/forms.py:114 users/forms.py:16 users/forms.py:42
#: settings/forms.py:114 users/forms.py:16 users/forms.py:42
#: users/templates/users/reset_password.html:53
#: users/templates/users/reset_password.html:53
#: users/templates/users/user_password_authentication.html:18
#: users/templates/users/user_password_authentication.html:18
...
@@ -742,14 +742,14 @@ msgstr "密码或密钥密码"
...
@@ -742,14 +742,14 @@ msgstr "密码或密钥密码"
#: users/templates/users/user_profile_update.html:41
#: users/templates/users/user_profile_update.html:41
#: users/templates/users/user_pubkey_update.html:41
#: users/templates/users/user_pubkey_update.html:41
#: users/templates/users/user_update.html:20
#: users/templates/users/user_update.html:20
#: xpack/plugins/change_auth_plan/models.py:9
5
#: xpack/plugins/change_auth_plan/models.py:9
6
#: xpack/plugins/change_auth_plan/models.py:26
3
#: xpack/plugins/change_auth_plan/models.py:26
4
msgid "Password"
msgid "Password"
msgstr "密码"
msgstr "密码"
#: assets/forms/user.py:30 assets/serializers/asset_user.py:71
#: assets/forms/user.py:30 assets/serializers/asset_user.py:71
#: assets/templates/assets/_asset_user_auth_update_modal.html:27
#: assets/templates/assets/_asset_user_auth_update_modal.html:27
#: users/models/user.py:4
09
#: users/models/user.py:4
37
msgid "Private key"
msgid "Private key"
msgstr "ssh私钥"
msgstr "ssh私钥"
...
@@ -937,13 +937,13 @@ msgstr "版本"
...
@@ -937,13 +937,13 @@ msgstr "版本"
msgid "AuthBook"
msgid "AuthBook"
msgstr ""
msgstr ""
#: assets/models/base.py:31 xpack/plugins/change_auth_plan/models.py:
99
#: assets/models/base.py:31 xpack/plugins/change_auth_plan/models.py:
100
#: xpack/plugins/change_auth_plan/models.py:27
0
#: xpack/plugins/change_auth_plan/models.py:27
1
msgid "SSH private key"
msgid "SSH private key"
msgstr "ssh密钥"
msgstr "ssh密钥"
#: assets/models/base.py:32 xpack/plugins/change_auth_plan/models.py:10
2
#: assets/models/base.py:32 xpack/plugins/change_auth_plan/models.py:10
3
#: xpack/plugins/change_auth_plan/models.py:26
6
#: xpack/plugins/change_auth_plan/models.py:26
7
msgid "SSH public key"
msgid "SSH public key"
msgstr "ssh公钥"
msgstr "ssh公钥"
...
@@ -963,7 +963,7 @@ msgstr "带宽"
...
@@ -963,7 +963,7 @@ msgstr "带宽"
msgid "Contact"
msgid "Contact"
msgstr "联系人"
msgstr "联系人"
#: assets/models/cluster.py:22 users/models/user.py:4
01
#: assets/models/cluster.py:22 users/models/user.py:4
29
#: users/templates/users/user_detail.html:77
#: users/templates/users/user_detail.html:77
msgid "Phone"
msgid "Phone"
msgstr "手机"
msgstr "手机"
...
@@ -989,7 +989,7 @@ msgid "Default"
...
@@ -989,7 +989,7 @@ msgid "Default"
msgstr "默认"
msgstr "默认"
#: assets/models/cluster.py:36 assets/models/label.py:14
#: assets/models/cluster.py:36 assets/models/label.py:14
#: users/models/user.py:5
21
#: users/models/user.py:5
49
msgid "System"
msgid "System"
msgstr "系统"
msgstr "系统"
...
@@ -1120,8 +1120,9 @@ msgstr "默认资产组"
...
@@ -1120,8 +1120,9 @@ msgstr "默认资产组"
#: terminal/templates/terminal/session_list.html:71 tickets/models/base.py:25
#: terminal/templates/terminal/session_list.html:71 tickets/models/base.py:25
#: tickets/models/base.py:68
#: tickets/models/base.py:68
#: tickets/templates/tickets/login_confirm_ticket_list.html:15
#: tickets/templates/tickets/login_confirm_ticket_list.html:15
#: tickets/templates/tickets/login_confirm_ticket_list.html:101
#: tickets/templates/tickets/ticket_detail.html:32 users/forms.py:339
#: tickets/templates/tickets/ticket_detail.html:32 users/forms.py:339
#: users/models/user.py:1
32 users/models/user.py:148 users/models/user.py:509
#: users/models/user.py:1
49 users/models/user.py:165 users/models/user.py:537
#: users/serializers/group.py:21
#: users/serializers/group.py:21
#: users/templates/users/user_group_detail.html:78
#: users/templates/users/user_group_detail.html:78
#: users/templates/users/user_group_list.html:36 users/views/user.py:250
#: users/templates/users/user_group_list.html:36 users/views/user.py:250
...
@@ -1131,7 +1132,7 @@ msgstr "默认资产组"
...
@@ -1131,7 +1132,7 @@ msgstr "默认资产组"
msgid "User"
msgid "User"
msgstr "用户"
msgstr "用户"
#: assets/models/label.py:19 assets/models/node.py:4
12
#: assets/models/label.py:19 assets/models/node.py:4
53
#: assets/templates/assets/label_list.html:15 settings/models.py:30
#: assets/templates/assets/label_list.html:15 settings/models.py:30
msgid "Value"
msgid "Value"
msgstr "值"
msgstr "值"
...
@@ -1140,23 +1141,23 @@ msgstr "值"
...
@@ -1140,23 +1141,23 @@ msgstr "值"
msgid "Category"
msgid "Category"
msgstr "分类"
msgstr "分类"
#: assets/models/node.py:16
3
#: assets/models/node.py:16
4
msgid "New node"
msgid "New node"
msgstr "新节点"
msgstr "新节点"
#: assets/models/node.py:32
4
#: assets/models/node.py:32
5
msgid "ungrouped"
msgid "ungrouped"
msgstr "未分组"
msgstr "未分组"
#: assets/models/node.py:32
6
#: assets/models/node.py:32
7
msgid "empty"
msgid "empty"
msgstr "空"
msgstr "空"
#: assets/models/node.py:32
8
#: assets/models/node.py:32
9
msgid "favorite"
msgid "favorite"
msgstr "收藏夹"
msgstr "收藏夹"
#: assets/models/node.py:4
11
#: assets/models/node.py:4
52
msgid "Key"
msgid "Key"
msgstr "键"
msgstr "键"
...
@@ -1187,7 +1188,7 @@ msgstr "手动登录"
...
@@ -1187,7 +1188,7 @@ msgstr "手动登录"
#: assets/views/label.py:27 assets/views/label.py:45 assets/views/label.py:73
#: assets/views/label.py:27 assets/views/label.py:45 assets/views/label.py:73
#: assets/views/system_user.py:29 assets/views/system_user.py:46
#: assets/views/system_user.py:29 assets/views/system_user.py:46
#: assets/views/system_user.py:63 assets/views/system_user.py:79
#: assets/views/system_user.py:63 assets/views/system_user.py:79
#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models.py:7
0
#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models.py:7
1
msgid "Assets"
msgid "Assets"
msgstr "资产管理"
msgstr "资产管理"
...
@@ -1277,7 +1278,7 @@ msgid "Backend"
...
@@ -1277,7 +1278,7 @@ msgid "Backend"
msgstr "后端"
msgstr "后端"
#: assets/serializers/asset_user.py:67 users/forms.py:282
#: assets/serializers/asset_user.py:67 users/forms.py:282
#: users/models/user.py:4
12
users/templates/users/first_login.html:42
#: users/models/user.py:4
40
users/templates/users/first_login.html:42
#: users/templates/users/user_password_update.html:49
#: users/templates/users/user_password_update.html:49
#: users/templates/users/user_profile.html:69
#: users/templates/users/user_profile.html:69
#: users/templates/users/user_profile_update.html:46
#: users/templates/users/user_profile_update.html:46
...
@@ -1332,7 +1333,7 @@ msgstr "测试资产可连接性: {}"
...
@@ -1332,7 +1333,7 @@ msgstr "测试资产可连接性: {}"
#: assets/tasks/asset_user_connectivity.py:27
#: assets/tasks/asset_user_connectivity.py:27
#: assets/tasks/push_system_user.py:130
#: assets/tasks/push_system_user.py:130
#: xpack/plugins/change_auth_plan/models.py:52
1
#: xpack/plugins/change_auth_plan/models.py:52
8
msgid "The asset {} system platform {} does not support run Ansible tasks"
msgid "The asset {} system platform {} does not support run Ansible tasks"
msgstr "资产 {} 系统平台 {} 不支持运行 Ansible 任务"
msgstr "资产 {} 系统平台 {} 不支持运行 Ansible 任务"
...
@@ -1450,6 +1451,7 @@ msgstr "资产列表"
...
@@ -1450,6 +1451,7 @@ msgstr "资产列表"
#: assets/templates/assets/_node_tree.html:39
#: assets/templates/assets/_node_tree.html:39
#: ops/templates/ops/command_execution_create.html:70
#: ops/templates/ops/command_execution_create.html:70
#: ops/templates/ops/command_execution_create.html:127
#: ops/templates/ops/command_execution_create.html:127
#: settings/templates/settings/_ldap_list_users_modal.html:41
#: users/templates/users/_granted_assets.html:7
#: users/templates/users/_granted_assets.html:7
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_create_update.html:66
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_create_update.html:66
msgid "Loading"
msgid "Loading"
...
@@ -1481,7 +1483,7 @@ msgid "Asset user auth"
...
@@ -1481,7 +1483,7 @@ msgid "Asset user auth"
msgstr "资产用户信息"
msgstr "资产用户信息"
#: assets/templates/assets/_asset_user_auth_view_modal.html:54
#: assets/templates/assets/_asset_user_auth_view_modal.html:54
#: authentication/templates/authentication/login_wait_confirm.html:11
5
#: authentication/templates/authentication/login_wait_confirm.html:11
4
msgid "Copy success"
msgid "Copy success"
msgstr "复制成功"
msgstr "复制成功"
...
@@ -1493,7 +1495,7 @@ msgstr "获取认证信息错误"
...
@@ -1493,7 +1495,7 @@ msgstr "获取认证信息错误"
#: assets/templates/assets/_user_asset_detail_modal.html:23
#: assets/templates/assets/_user_asset_detail_modal.html:23
#: authentication/templates/authentication/_access_key_modal.html:142
#: authentication/templates/authentication/_access_key_modal.html:142
#: authentication/templates/authentication/_mfa_confirm_modal.html:53
#: authentication/templates/authentication/_mfa_confirm_modal.html:53
#: settings/templates/settings/_ldap_list_users_modal.html:
92
#: settings/templates/settings/_ldap_list_users_modal.html:
171
#: templates/_modal.html:22 tickets/models/base.py:50
#: templates/_modal.html:22 tickets/models/base.py:50
#: tickets/templates/tickets/ticket_detail.html:103
#: tickets/templates/tickets/ticket_detail.html:103
msgid "Close"
msgid "Close"
...
@@ -1667,7 +1669,6 @@ msgstr "选择节点"
...
@@ -1667,7 +1669,6 @@ msgstr "选择节点"
#: assets/templates/assets/system_user_detail.html:182
#: assets/templates/assets/system_user_detail.html:182
#: assets/templates/assets/system_user_list.html:135
#: assets/templates/assets/system_user_list.html:135
#: authentication/templates/authentication/_mfa_confirm_modal.html:20
#: authentication/templates/authentication/_mfa_confirm_modal.html:20
#: authentication/templates/authentication/login_wait_confirm.html:136
#: settings/templates/settings/terminal_setting.html:168
#: settings/templates/settings/terminal_setting.html:168
#: templates/_modal.html:23 terminal/templates/terminal/session_detail.html:112
#: templates/_modal.html:23 terminal/templates/terminal/session_detail.html:112
#: users/templates/users/user_detail.html:271
#: users/templates/users/user_detail.html:271
...
@@ -1713,7 +1714,7 @@ msgstr "导出"
...
@@ -1713,7 +1714,7 @@ msgstr "导出"
#: assets/templates/assets/admin_user_list.html:21
#: assets/templates/assets/admin_user_list.html:21
#: assets/templates/assets/asset_list.html:73
#: assets/templates/assets/asset_list.html:73
#: assets/templates/assets/system_user_list.html:24
#: assets/templates/assets/system_user_list.html:24
#: settings/templates/settings/_ldap_list_users_modal.html:
93
#: settings/templates/settings/_ldap_list_users_modal.html:
172
#: users/templates/users/user_group_list.html:15
#: users/templates/users/user_group_list.html:15
#: users/templates/users/user_list.html:15
#: users/templates/users/user_list.html:15
#: xpack/plugins/license/templates/license/license_detail.html:110
#: xpack/plugins/license/templates/license/license_detail.html:110
...
@@ -1899,16 +1900,16 @@ msgstr "删除选择资产"
...
@@ -1899,16 +1900,16 @@ msgstr "删除选择资产"
msgid "Cancel"
msgid "Cancel"
msgstr "取消"
msgstr "取消"
#: assets/templates/assets/asset_list.html:43
4
#: assets/templates/assets/asset_list.html:43
2
msgid "Asset Deleted."
msgid "Asset Deleted."
msgstr "已被删除"
msgstr "已被删除"
#: assets/templates/assets/asset_list.html:43
5
#: assets/templates/assets/asset_list.html:43
3
#: assets/templates/assets/asset_list.html:4
39
#: assets/templates/assets/asset_list.html:4
41
msgid "Asset Delete"
msgid "Asset Delete"
msgstr "删除"
msgstr "删除"
#: assets/templates/assets/asset_list.html:4
38
#: assets/templates/assets/asset_list.html:4
40
msgid "Asset Deleting failed."
msgid "Asset Deleting failed."
msgstr "删除失败"
msgstr "删除失败"
...
@@ -2281,13 +2282,13 @@ msgstr "Agent"
...
@@ -2281,13 +2282,13 @@ msgstr "Agent"
#: audits/models.py:86 audits/templates/audits/login_log_list.html:62
#: audits/models.py:86 audits/templates/audits/login_log_list.html:62
#: authentication/templates/authentication/_mfa_confirm_modal.html:14
#: authentication/templates/authentication/_mfa_confirm_modal.html:14
#: users/forms.py:194 users/models/user.py:4
04
#: users/forms.py:194 users/models/user.py:4
32
#: users/templates/users/first_login.html:45
#: users/templates/users/first_login.html:45
msgid "MFA"
msgid "MFA"
msgstr "MFA"
msgstr "MFA"
#: audits/models.py:87 audits/templates/audits/login_log_list.html:63
#: audits/models.py:87 audits/templates/audits/login_log_list.html:63
#: xpack/plugins/change_auth_plan/models.py:4
16
#: xpack/plugins/change_auth_plan/models.py:4
23
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:15
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:15
#: xpack/plugins/cloud/models.py:278
#: xpack/plugins/cloud/models.py:278
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:69
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:69
...
@@ -2296,7 +2297,7 @@ msgstr "原因"
...
@@ -2296,7 +2297,7 @@ msgstr "原因"
#: audits/models.py:88 audits/templates/audits/login_log_list.html:64
#: audits/models.py:88 audits/templates/audits/login_log_list.html:64
#: tickets/templates/tickets/login_confirm_ticket_list.html:16
#: tickets/templates/tickets/login_confirm_ticket_list.html:16
#: tickets/templates/tickets/login_confirm_ticket_list.html:10
1
#: tickets/templates/tickets/login_confirm_ticket_list.html:10
2
#: tickets/templates/tickets/ticket_detail.html:34
#: tickets/templates/tickets/ticket_detail.html:34
#: xpack/plugins/cloud/models.py:275 xpack/plugins/cloud/models.py:310
#: xpack/plugins/cloud/models.py:275 xpack/plugins/cloud/models.py:310
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:70
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:70
...
@@ -2316,8 +2317,8 @@ msgstr "登录日期"
...
@@ -2316,8 +2317,8 @@ msgstr "登录日期"
#: perms/templates/perms/asset_permission_detail.html:86
#: perms/templates/perms/asset_permission_detail.html:86
#: perms/templates/perms/remote_app_permission_detail.html:78
#: perms/templates/perms/remote_app_permission_detail.html:78
#: terminal/models.py:167 terminal/templates/terminal/session_list.html:34
#: terminal/models.py:167 terminal/templates/terminal/session_list.html:34
#: xpack/plugins/change_auth_plan/models.py:2
49
#: xpack/plugins/change_auth_plan/models.py:2
50
#: xpack/plugins/change_auth_plan/models.py:4
19
#: xpack/plugins/change_auth_plan/models.py:4
26
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:59
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:59
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:17
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:17
#: xpack/plugins/gathered_user/models.py:143
#: xpack/plugins/gathered_user/models.py:143
...
@@ -2557,14 +2558,14 @@ msgid "Show"
...
@@ -2557,14 +2558,14 @@ msgid "Show"
msgstr "显示"
msgstr "显示"
#: authentication/templates/authentication/_access_key_modal.html:66
#: authentication/templates/authentication/_access_key_modal.html:66
#: users/models/user.py:3
35
users/templates/users/user_profile.html:94
#: users/models/user.py:3
52
users/templates/users/user_profile.html:94
#: users/templates/users/user_profile.html:163
#: users/templates/users/user_profile.html:163
#: users/templates/users/user_profile.html:166
#: users/templates/users/user_profile.html:166
msgid "Disable"
msgid "Disable"
msgstr "禁用"
msgstr "禁用"
#: authentication/templates/authentication/_access_key_modal.html:67
#: authentication/templates/authentication/_access_key_modal.html:67
#: users/models/user.py:3
36
users/templates/users/user_profile.html:92
#: users/models/user.py:3
53
users/templates/users/user_profile.html:92
#: users/templates/users/user_profile.html:170
#: users/templates/users/user_profile.html:170
msgid "Enable"
msgid "Enable"
msgstr "启用"
msgstr "启用"
...
@@ -2626,7 +2627,7 @@ msgstr "改变世界,从一点点开始。"
...
@@ -2626,7 +2627,7 @@ msgstr "改变世界,从一点点开始。"
#: authentication/templates/authentication/login.html:45
#: authentication/templates/authentication/login.html:45
#: authentication/templates/authentication/login.html:76
#: authentication/templates/authentication/login.html:76
#: authentication/templates/authentication/xpack_login.html:11
0
#: authentication/templates/authentication/xpack_login.html:11
2
#: templates/_header_bar.html:83
#: templates/_header_bar.html:83
msgid "Login"
msgid "Login"
msgstr "登录"
msgstr "登录"
...
@@ -2637,7 +2638,7 @@ msgid "Captcha invalid"
...
@@ -2637,7 +2638,7 @@ msgid "Captcha invalid"
msgstr "验证码错误"
msgstr "验证码错误"
#: authentication/templates/authentication/login.html:87
#: authentication/templates/authentication/login.html:87
#: authentication/templates/authentication/xpack_login.html:11
4
#: authentication/templates/authentication/xpack_login.html:11
6
#: users/templates/users/forgot_password.html:10
#: users/templates/users/forgot_password.html:10
#: users/templates/users/forgot_password.html:25
#: users/templates/users/forgot_password.html:25
msgid "Forgot password"
msgid "Forgot password"
...
@@ -2701,11 +2702,11 @@ msgstr "返回"
...
@@ -2701,11 +2702,11 @@ msgstr "返回"
msgid "Welcome back, please enter username and password to login"
msgid "Welcome back, please enter username and password to login"
msgstr "欢迎回来,请输入用户名和密码登录"
msgstr "欢迎回来,请输入用户名和密码登录"
#: authentication/views/login.py:7
1
#: authentication/views/login.py:7
0
msgid "Please enable cookies and try again."
msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie"
msgstr "设置你的浏览器支持cookie"
#: authentication/views/login.py:1
70
#: authentication/views/login.py:1
57
msgid ""
msgid ""
"Wait for <b>{}</b> confirm, You also can copy link to her/him <br/>\n"
"Wait for <b>{}</b> confirm, You also can copy link to her/him <br/>\n"
" Don't close this page"
" Don't close this page"
...
@@ -2713,15 +2714,15 @@ msgstr ""
...
@@ -2713,15 +2714,15 @@ msgstr ""
"等待 <b>{}</b> 确认, 你也可以复制链接发给他/她 <br/>\n"
"等待 <b>{}</b> 确认, 你也可以复制链接发给他/她 <br/>\n"
" 不要关闭本页面"
" 不要关闭本页面"
#: authentication/views/login.py:1
75
#: authentication/views/login.py:1
62
msgid "No ticket found"
msgid "No ticket found"
msgstr "没有发现工单"
msgstr "没有发现工单"
#: authentication/views/login.py:1
98
#: authentication/views/login.py:1
85
msgid "Logout success"
msgid "Logout success"
msgstr "退出登录成功"
msgstr "退出登录成功"
#: authentication/views/login.py:1
99
#: authentication/views/login.py:1
86
msgid "Logout success, return login page"
msgid "Logout success, return login page"
msgstr "退出登录成功,返回到登录页面"
msgstr "退出登录成功,返回到登录页面"
...
@@ -2905,8 +2906,8 @@ msgstr "完成时间"
...
@@ -2905,8 +2906,8 @@ msgstr "完成时间"
#: ops/models/adhoc.py:358 ops/templates/ops/adhoc_history.html:57
#: ops/models/adhoc.py:358 ops/templates/ops/adhoc_history.html:57
#: ops/templates/ops/task_history.html:63 ops/templates/ops/task_list.html:17
#: ops/templates/ops/task_history.html:63 ops/templates/ops/task_list.html:17
#: xpack/plugins/change_auth_plan/models.py:25
2
#: xpack/plugins/change_auth_plan/models.py:25
3
#: xpack/plugins/change_auth_plan/models.py:42
2
#: xpack/plugins/change_auth_plan/models.py:42
9
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:58
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:58
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:16
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:16
#: xpack/plugins/gathered_user/models.py:146
#: xpack/plugins/gathered_user/models.py:146
...
@@ -3197,7 +3198,7 @@ msgstr "提示:RDP 协议不支持单独控制上传或下载文件"
...
@@ -3197,7 +3198,7 @@ msgstr "提示:RDP 协议不支持单独控制上传或下载文件"
#: perms/templates/perms/asset_permission_list.html:118
#: perms/templates/perms/asset_permission_list.html:118
#: perms/templates/perms/remote_app_permission_list.html:16
#: perms/templates/perms/remote_app_permission_list.html:16
#: templates/_nav.html:21 users/forms.py:313 users/models/group.py:26
#: templates/_nav.html:21 users/forms.py:313 users/models/group.py:26
#: users/models/user.py:
388
users/templates/users/_select_user_modal.html:16
#: users/models/user.py:
416
users/templates/users/_select_user_modal.html:16
#: users/templates/users/user_detail.html:218
#: users/templates/users/user_detail.html:218
#: users/templates/users/user_list.html:38
#: users/templates/users/user_list.html:38
#: xpack/plugins/orgs/templates/orgs/org_list.html:16
#: xpack/plugins/orgs/templates/orgs/org_list.html:16
...
@@ -3239,7 +3240,7 @@ msgstr "资产授权"
...
@@ -3239,7 +3240,7 @@ msgstr "资产授权"
#: perms/models/base.py:53
#: perms/models/base.py:53
#: perms/templates/perms/asset_permission_detail.html:90
#: perms/templates/perms/asset_permission_detail.html:90
#: perms/templates/perms/remote_app_permission_detail.html:82
#: perms/templates/perms/remote_app_permission_detail.html:82
#: users/models/user.py:4
20
users/templates/users/user_detail.html:108
#: users/models/user.py:4
48
users/templates/users/user_detail.html:108
#: users/templates/users/user_profile.html:120
#: users/templates/users/user_profile.html:120
msgid "Date expired"
msgid "Date expired"
msgstr "失效日期"
msgstr "失效日期"
...
@@ -3456,33 +3457,41 @@ msgstr "远程应用授权用户列表"
...
@@ -3456,33 +3457,41 @@ msgstr "远程应用授权用户列表"
msgid "RemoteApp permission RemoteApp list"
msgid "RemoteApp permission RemoteApp list"
msgstr "远程应用授权远程应用列表"
msgstr "远程应用授权远程应用列表"
#: settings/api.py:3
1
#: settings/api.py:3
7
msgid "Test mail sent to {}, please check"
msgid "Test mail sent to {}, please check"
msgstr "邮件已经发送{}, 请检查"
msgstr "邮件已经发送{}, 请检查"
#: settings/api.py:7
0
#: settings/api.py:7
6
msgid "Test ldap success"
msgid "Test ldap success"
msgstr "连接LDAP成功"
msgstr "连接LDAP成功"
#: settings/api.py:107
#: settings/api.py:107
msgid "LDAP attr map not valid"
msgstr ""
#: settings/api.py:116
msgid "Match {} s users"
msgid "Match {} s users"
msgstr "匹配 {} 个用户"
msgstr "匹配 {} 个用户"
#: settings/api.py:166
#: settings/api.py:224
msgid "succeed: {} failed: {} total: {}"
msgid "Get ldap users is None"
msgstr "成功:{} 失败:{} 总数:{}"
msgstr "获取 LDAP 用户为 None"
#: settings/api.py:231
msgid "Imported {} users successfully"
msgstr "导入 {} 个用户成功"
#: settings/api.py:
188 settings/api.py:224
#: settings/api.py:
262 settings/api.py:298
msgid ""
msgid ""
"Error: Account invalid (Please make sure the information such as Access key "
"Error: Account invalid (Please make sure the information such as Access key "
"or Secret key is correct)"
"or Secret key is correct)"
msgstr "错误:账户无效 (请确保 Access key 或 Secret key 等信息正确)"
msgstr "错误:账户无效 (请确保 Access key 或 Secret key 等信息正确)"
#: settings/api.py:
194 settings/api.py:230
#: settings/api.py:
268 settings/api.py:304
msgid "Create succeed"
msgid "Create succeed"
msgstr "创建成功"
msgstr "创建成功"
#: settings/api.py:2
12 settings/api.py:250
#: settings/api.py:2
86 settings/api.py:324
#: settings/templates/settings/terminal_setting.html:154
#: settings/templates/settings/terminal_setting.html:154
msgid "Delete succeed"
msgid "Delete succeed"
msgstr "删除成功"
msgstr "删除成功"
...
@@ -3802,23 +3811,32 @@ msgstr "LDAP 用户列表"
...
@@ -3802,23 +3811,32 @@ msgstr "LDAP 用户列表"
msgid "Please submit the LDAP configuration before import"
msgid "Please submit the LDAP configuration before import"
msgstr "请先提交LDAP配置再进行导入"
msgstr "请先提交LDAP配置再进行导入"
#: settings/templates/settings/_ldap_list_users_modal.html:32
#: settings/templates/settings/_ldap_list_users_modal.html:26
#: users/models/user.py:384 users/templates/users/user_detail.html:72
msgid "Refresh cache"
msgstr "刷新缓存"
#: settings/templates/settings/_ldap_list_users_modal.html:33
#: users/models/user.py:412 users/templates/users/user_detail.html:72
#: users/templates/users/user_profile.html:59
#: users/templates/users/user_profile.html:59
msgid "Email"
msgid "Email"
msgstr "邮件"
msgstr "邮件"
#: settings/templates/settings/_ldap_list_users_modal.html:3
3
#: settings/templates/settings/_ldap_list_users_modal.html:3
4
msgid "Existing"
msgid "Existing"
msgstr "已存在"
msgstr "已存在"
#: settings/templates/settings/_ldap_list_users_modal.html:144
msgid ""
"User is not currently selected, please check the user you want to import"
msgstr "当前无勾选用户,请勾选你想要导入的用户"
#: settings/templates/settings/basic_setting.html:15
#: settings/templates/settings/basic_setting.html:15
#: settings/templates/settings/email_content_setting.html:15
#: settings/templates/settings/email_content_setting.html:15
#: settings/templates/settings/email_setting.html:15
#: settings/templates/settings/email_setting.html:15
#: settings/templates/settings/ldap_setting.html:15
#: settings/templates/settings/ldap_setting.html:15
#: settings/templates/settings/security_setting.html:15
#: settings/templates/settings/security_setting.html:15
#: settings/templates/settings/terminal_setting.html:16
#: settings/templates/settings/terminal_setting.html:16
#: settings/templates/settings/terminal_setting.html:49 settings/views.py:2
0
#: settings/templates/settings/terminal_setting.html:49 settings/views.py:2
1
msgid "Basic setting"
msgid "Basic setting"
msgstr "基本设置"
msgstr "基本设置"
...
@@ -3827,7 +3845,7 @@ msgstr "基本设置"
...
@@ -3827,7 +3845,7 @@ msgstr "基本设置"
#: settings/templates/settings/email_setting.html:18
#: settings/templates/settings/email_setting.html:18
#: settings/templates/settings/ldap_setting.html:18
#: settings/templates/settings/ldap_setting.html:18
#: settings/templates/settings/security_setting.html:18
#: settings/templates/settings/security_setting.html:18
#: settings/templates/settings/terminal_setting.html:20 settings/views.py:4
7
#: settings/templates/settings/terminal_setting.html:20 settings/views.py:4
8
msgid "Email setting"
msgid "Email setting"
msgstr "邮件设置"
msgstr "邮件设置"
...
@@ -3836,7 +3854,7 @@ msgstr "邮件设置"
...
@@ -3836,7 +3854,7 @@ msgstr "邮件设置"
#: settings/templates/settings/email_setting.html:21
#: settings/templates/settings/email_setting.html:21
#: settings/templates/settings/ldap_setting.html:21
#: settings/templates/settings/ldap_setting.html:21
#: settings/templates/settings/security_setting.html:21
#: settings/templates/settings/security_setting.html:21
#: settings/templates/settings/terminal_setting.html:23 settings/views.py:18
6
#: settings/templates/settings/terminal_setting.html:23 settings/views.py:18
8
msgid "Email content setting"
msgid "Email content setting"
msgstr "邮件内容设置"
msgstr "邮件内容设置"
...
@@ -3845,7 +3863,7 @@ msgstr "邮件内容设置"
...
@@ -3845,7 +3863,7 @@ msgstr "邮件内容设置"
#: settings/templates/settings/email_setting.html:24
#: settings/templates/settings/email_setting.html:24
#: settings/templates/settings/ldap_setting.html:24
#: settings/templates/settings/ldap_setting.html:24
#: settings/templates/settings/security_setting.html:24
#: settings/templates/settings/security_setting.html:24
#: settings/templates/settings/terminal_setting.html:27 settings/views.py:7
4
#: settings/templates/settings/terminal_setting.html:27 settings/views.py:7
5
msgid "LDAP setting"
msgid "LDAP setting"
msgstr "LDAP设置"
msgstr "LDAP设置"
...
@@ -3854,7 +3872,7 @@ msgstr "LDAP设置"
...
@@ -3854,7 +3872,7 @@ msgstr "LDAP设置"
#: settings/templates/settings/email_setting.html:27
#: settings/templates/settings/email_setting.html:27
#: settings/templates/settings/ldap_setting.html:27
#: settings/templates/settings/ldap_setting.html:27
#: settings/templates/settings/security_setting.html:27
#: settings/templates/settings/security_setting.html:27
#: settings/templates/settings/terminal_setting.html:31 settings/views.py:10
4
#: settings/templates/settings/terminal_setting.html:31 settings/views.py:10
6
msgid "Terminal setting"
msgid "Terminal setting"
msgstr "终端设置"
msgstr "终端设置"
...
@@ -3864,7 +3882,7 @@ msgstr "终端设置"
...
@@ -3864,7 +3882,7 @@ msgstr "终端设置"
#: settings/templates/settings/ldap_setting.html:30
#: settings/templates/settings/ldap_setting.html:30
#: settings/templates/settings/security_setting.html:30
#: settings/templates/settings/security_setting.html:30
#: settings/templates/settings/security_setting.html:45
#: settings/templates/settings/security_setting.html:45
#: settings/templates/settings/terminal_setting.html:34 settings/views.py:1
59
#: settings/templates/settings/terminal_setting.html:34 settings/views.py:1
61
msgid "Security setting"
msgid "Security setting"
msgstr "安全设置"
msgstr "安全设置"
...
@@ -3884,15 +3902,10 @@ msgstr "文档类型"
...
@@ -3884,15 +3902,10 @@ msgstr "文档类型"
msgid "Create User setting"
msgid "Create User setting"
msgstr "创建用户设置"
msgstr "创建用户设置"
#: settings/templates/settings/ldap_setting.html:6
8
#: settings/templates/settings/ldap_setting.html:6
6
msgid "Bulk import"
msgid "Bulk import"
msgstr "一键导入"
msgstr "一键导入"
#: settings/templates/settings/ldap_setting.html:116
msgid ""
"User is not currently selected, please check the user you want to import"
msgstr "当前无勾选用户,请勾选你想要导入的用户"
#: settings/templates/settings/replay_storage_create.html:66
#: settings/templates/settings/replay_storage_create.html:66
msgid "Bucket"
msgid "Bucket"
msgstr "桶名称"
msgstr "桶名称"
...
@@ -3997,30 +4010,26 @@ msgstr "删除失败"
...
@@ -3997,30 +4010,26 @@ msgstr "删除失败"
msgid "Are you sure about deleting it?"
msgid "Are you sure about deleting it?"
msgstr "您确定删除吗?"
msgstr "您确定删除吗?"
#: settings/utils
.py:9
8
#: settings/utils
/ldap.py:12
8
msgid "Search no entry matched in ou {}"
msgid "Search no entry matched in ou {}"
msgstr "在ou:{}中没有匹配条目"
msgstr "在ou:{}中没有匹配条目"
#: settings/utils.py:172
#: settings/views.py:20 settings/views.py:47 settings/views.py:74
msgid "The user source is not LDAP"
#: settings/views.py:105 settings/views.py:133 settings/views.py:146
msgstr "用户来源不是LDAP"
#: settings/views.py:160 settings/views.py:187 templates/_nav.html:180
#: settings/views.py:19 settings/views.py:46 settings/views.py:73
#: settings/views.py:103 settings/views.py:131 settings/views.py:144
#: settings/views.py:158 settings/views.py:185 templates/_nav.html:180
msgid "Settings"
msgid "Settings"
msgstr "系统设置"
msgstr "系统设置"
#: settings/views.py:3
0 settings/views.py:57 settings/views.py:84
#: settings/views.py:3
1 settings/views.py:58 settings/views.py:85
#: settings/views.py:11
6 settings/views.py:169 settings/views.py:196
#: settings/views.py:11
8 settings/views.py:171 settings/views.py:198
msgid "Update setting successfully"
msgid "Update setting successfully"
msgstr "更新设置成功"
msgstr "更新设置成功"
#: settings/views.py:13
2
#: settings/views.py:13
4
msgid "Create replay storage"
msgid "Create replay storage"
msgstr "创建录像存储"
msgstr "创建录像存储"
#: settings/views.py:14
5
#: settings/views.py:14
7
msgid "Create command storage"
msgid "Create command storage"
msgstr "创建命令存储"
msgstr "创建命令存储"
...
@@ -4570,7 +4579,7 @@ msgstr "接受"
...
@@ -4570,7 +4579,7 @@ msgstr "接受"
#: tickets/models/login_confirm.py:16
#: tickets/models/login_confirm.py:16
#: tickets/templates/tickets/login_confirm_ticket_detail.html:10
#: tickets/templates/tickets/login_confirm_ticket_detail.html:10
#: tickets/templates/tickets/login_confirm_ticket_list.html:70
#: tickets/templates/tickets/login_confirm_ticket_list.html:70
#: tickets/templates/tickets/login_confirm_ticket_list.html:10
7
#: tickets/templates/tickets/login_confirm_ticket_list.html:10
8
msgid "Reject"
msgid "Reject"
msgstr "拒绝"
msgstr "拒绝"
...
@@ -4608,12 +4617,12 @@ msgid ""
...
@@ -4608,12 +4617,12 @@ msgid ""
msgstr "你可以使用ssh客户端工具连接终端"
msgstr "你可以使用ssh客户端工具连接终端"
#: tickets/models/base.py:16 tickets/models/base.py:52
#: tickets/models/base.py:16 tickets/models/base.py:52
#: tickets/templates/tickets/login_confirm_ticket_list.html:10
2
#: tickets/templates/tickets/login_confirm_ticket_list.html:10
3
msgid "Open"
msgid "Open"
msgstr "开启"
msgstr "开启"
#: tickets/models/base.py:17
#: tickets/models/base.py:17
#: tickets/templates/tickets/login_confirm_ticket_list.html:10
3
#: tickets/templates/tickets/login_confirm_ticket_list.html:10
4
msgid "Closed"
msgid "Closed"
msgstr "关闭"
msgstr "关闭"
...
@@ -4658,7 +4667,7 @@ msgstr "{} {} 这个工单"
...
@@ -4658,7 +4667,7 @@ msgstr "{} {} 这个工单"
#: tickets/models/login_confirm.py:15
#: tickets/models/login_confirm.py:15
#: tickets/templates/tickets/login_confirm_ticket_detail.html:9
#: tickets/templates/tickets/login_confirm_ticket_detail.html:9
#: tickets/templates/tickets/login_confirm_ticket_list.html:69
#: tickets/templates/tickets/login_confirm_ticket_list.html:69
#: tickets/templates/tickets/login_confirm_ticket_list.html:10
6
#: tickets/templates/tickets/login_confirm_ticket_list.html:10
7
msgid "Approve"
msgid "Approve"
msgstr "同意"
msgstr "同意"
...
@@ -4771,7 +4780,7 @@ msgstr "登录复核工单详情"
...
@@ -4771,7 +4780,7 @@ msgstr "登录复核工单详情"
msgid "Could not reset self otp, use profile reset instead"
msgid "Could not reset self otp, use profile reset instead"
msgstr "不能再该页面重置MFA, 请去个人信息页面重置"
msgstr "不能再该页面重置MFA, 请去个人信息页面重置"
#: users/forms.py:47 users/models/user.py:
392
#: users/forms.py:47 users/models/user.py:
420
#: users/templates/users/_select_user_modal.html:15
#: users/templates/users/_select_user_modal.html:15
#: users/templates/users/user_detail.html:88
#: users/templates/users/user_detail.html:88
#: users/templates/users/user_list.html:37
#: users/templates/users/user_list.html:37
...
@@ -4779,7 +4788,7 @@ msgstr "不能再该页面重置MFA, 请去个人信息页面重置"
...
@@ -4779,7 +4788,7 @@ msgstr "不能再该页面重置MFA, 请去个人信息页面重置"
msgid "Role"
msgid "Role"
msgstr "角色"
msgstr "角色"
#: users/forms.py:51 users/models/user.py:4
27
#: users/forms.py:51 users/models/user.py:4
55
#: users/templates/users/user_detail.html:104
#: users/templates/users/user_detail.html:104
#: users/templates/users/user_list.html:39
#: users/templates/users/user_list.html:39
#: users/templates/users/user_profile.html:102
#: users/templates/users/user_profile.html:102
...
@@ -4823,7 +4832,7 @@ msgstr "生成重置密码链接,通过邮件发送给用户"
...
@@ -4823,7 +4832,7 @@ msgstr "生成重置密码链接,通过邮件发送给用户"
msgid "Set password"
msgid "Set password"
msgstr "设置密码"
msgstr "设置密码"
#: users/forms.py:152 xpack/plugins/change_auth_plan/models.py:8
8
#: users/forms.py:152 xpack/plugins/change_auth_plan/models.py:8
9
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:51
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:51
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:69
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:69
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:57
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:57
...
@@ -4897,44 +4906,44 @@ msgstr "选择用户"
...
@@ -4897,44 +4906,44 @@ msgstr "选择用户"
msgid "User auth from {}, go there change password"
msgid "User auth from {}, go there change password"
msgstr "用户认证源来自 {}, 请去相应系统修改密码"
msgstr "用户认证源来自 {}, 请去相应系统修改密码"
#: users/models/user.py:1
31 users/models/user.py:517
#: users/models/user.py:1
48 users/models/user.py:545
msgid "Administrator"
msgid "Administrator"
msgstr "管理员"
msgstr "管理员"
#: users/models/user.py:1
33
#: users/models/user.py:1
50
msgid "Application"
msgid "Application"
msgstr "应用程序"
msgstr "应用程序"
#: users/models/user.py:1
34
xpack/plugins/orgs/forms.py:30
#: users/models/user.py:1
51
xpack/plugins/orgs/forms.py:30
#: xpack/plugins/orgs/templates/orgs/org_list.html:14
#: xpack/plugins/orgs/templates/orgs/org_list.html:14
msgid "Auditor"
msgid "Auditor"
msgstr "审计员"
msgstr "审计员"
#: users/models/user.py:1
44
#: users/models/user.py:1
61
msgid "Org admin"
msgid "Org admin"
msgstr "组织管理员"
msgstr "组织管理员"
#: users/models/user.py:1
46
#: users/models/user.py:1
63
msgid "Org auditor"
msgid "Org auditor"
msgstr "组织审计员"
msgstr "组织审计员"
#: users/models/user.py:3
37
users/templates/users/user_profile.html:90
#: users/models/user.py:3
54
users/templates/users/user_profile.html:90
msgid "Force enable"
msgid "Force enable"
msgstr "强制启用"
msgstr "强制启用"
#: users/models/user.py:
395
#: users/models/user.py:
423
msgid "Avatar"
msgid "Avatar"
msgstr "头像"
msgstr "头像"
#: users/models/user.py:
398
users/templates/users/user_detail.html:83
#: users/models/user.py:
426
users/templates/users/user_detail.html:83
msgid "Wechat"
msgid "Wechat"
msgstr "微信"
msgstr "微信"
#: users/models/user.py:4
31
#: users/models/user.py:4
59
msgid "Date password last updated"
msgid "Date password last updated"
msgstr "最后更新密码日期"
msgstr "最后更新密码日期"
#: users/models/user.py:5
20
#: users/models/user.py:5
48
msgid "Administrator is the super user of system"
msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员"
msgstr "Administrator是初始的超级管理员"
...
@@ -5753,8 +5762,8 @@ msgstr ""
...
@@ -5753,8 +5762,8 @@ msgstr ""
"具</a>) <br>注意: 如果同时设置了定期执行和周期执行,优先使用定期执行"
"具</a>) <br>注意: 如果同时设置了定期执行和周期执行,优先使用定期执行"
#: xpack/plugins/change_auth_plan/meta.py:9
#: xpack/plugins/change_auth_plan/meta.py:9
#: xpack/plugins/change_auth_plan/models.py:11
6
#: xpack/plugins/change_auth_plan/models.py:11
7
#: xpack/plugins/change_auth_plan/models.py:25
6
#: xpack/plugins/change_auth_plan/models.py:25
7
#: xpack/plugins/change_auth_plan/views.py:33
#: xpack/plugins/change_auth_plan/views.py:33
#: xpack/plugins/change_auth_plan/views.py:50
#: xpack/plugins/change_auth_plan/views.py:50
#: xpack/plugins/change_auth_plan/views.py:74
#: xpack/plugins/change_auth_plan/views.py:74
...
@@ -5765,20 +5774,20 @@ msgstr ""
...
@@ -5765,20 +5774,20 @@ msgstr ""
msgid "Change auth plan"
msgid "Change auth plan"
msgstr "改密计划"
msgstr "改密计划"
#: xpack/plugins/change_auth_plan/models.py:5
7
#: xpack/plugins/change_auth_plan/models.py:5
8
msgid "Custom password"
msgid "Custom password"
msgstr "自定义密码"
msgstr "自定义密码"
#: xpack/plugins/change_auth_plan/models.py:5
8
#: xpack/plugins/change_auth_plan/models.py:5
9
msgid "All assets use the same random password"
msgid "All assets use the same random password"
msgstr "所有资产使用相同的随机密码"
msgstr "所有资产使用相同的随机密码"
#: xpack/plugins/change_auth_plan/models.py:
59
#: xpack/plugins/change_auth_plan/models.py:
60
msgid "All assets use different random password"
msgid "All assets use different random password"
msgstr "所有资产使用不同的随机密码"
msgstr "所有资产使用不同的随机密码"
#: xpack/plugins/change_auth_plan/models.py:7
8
#: xpack/plugins/change_auth_plan/models.py:7
9
#: xpack/plugins/change_auth_plan/models.py:14
7
#: xpack/plugins/change_auth_plan/models.py:14
8
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:100
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:100
#: xpack/plugins/cloud/models.py:165 xpack/plugins/cloud/models.py:219
#: xpack/plugins/cloud/models.py:165 xpack/plugins/cloud/models.py:219
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:91
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:91
...
@@ -5787,8 +5796,8 @@ msgstr "所有资产使用不同的随机密码"
...
@@ -5787,8 +5796,8 @@ msgstr "所有资产使用不同的随机密码"
msgid "Cycle perform"
msgid "Cycle perform"
msgstr "周期执行"
msgstr "周期执行"
#: xpack/plugins/change_auth_plan/models.py:8
3
#: xpack/plugins/change_auth_plan/models.py:8
4
#: xpack/plugins/change_auth_plan/models.py:14
5
#: xpack/plugins/change_auth_plan/models.py:14
6
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:92
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:92
#: xpack/plugins/cloud/models.py:170 xpack/plugins/cloud/models.py:217
#: xpack/plugins/cloud/models.py:170 xpack/plugins/cloud/models.py:217
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:83
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:83
...
@@ -5797,37 +5806,37 @@ msgstr "周期执行"
...
@@ -5797,37 +5806,37 @@ msgstr "周期执行"
msgid "Regularly perform"
msgid "Regularly perform"
msgstr "定期执行"
msgstr "定期执行"
#: xpack/plugins/change_auth_plan/models.py:9
2
#: xpack/plugins/change_auth_plan/models.py:9
3
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:74
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:74
msgid "Password rules"
msgid "Password rules"
msgstr "密码规则"
msgstr "密码规则"
#: xpack/plugins/change_auth_plan/models.py:21
2
#: xpack/plugins/change_auth_plan/models.py:21
3
msgid "* For security, do not change {} user's password"
msgid "* For security, do not change {} user's password"
msgstr "* 为了安全,禁止更改 {} 用户的密码"
msgstr "* 为了安全,禁止更改 {} 用户的密码"
#: xpack/plugins/change_auth_plan/models.py:21
6
#: xpack/plugins/change_auth_plan/models.py:21
7
msgid "Assets is empty, please add the asset"
msgid "Assets is empty, please add the asset"
msgstr "资产为空,请添加资产"
msgstr "资产为空,请添加资产"
#: xpack/plugins/change_auth_plan/models.py:26
0
#: xpack/plugins/change_auth_plan/models.py:26
1
msgid "Change auth plan snapshot"
msgid "Change auth plan snapshot"
msgstr "改密计划快照"
msgstr "改密计划快照"
#: xpack/plugins/change_auth_plan/models.py:27
5
#: xpack/plugins/change_auth_plan/models.py:27
6
#: xpack/plugins/change_auth_plan/models.py:4
26
#: xpack/plugins/change_auth_plan/models.py:4
33
msgid "Change auth plan execution"
msgid "Change auth plan execution"
msgstr "改密计划执行"
msgstr "改密计划执行"
#: xpack/plugins/change_auth_plan/models.py:4
35
#: xpack/plugins/change_auth_plan/models.py:4
42
msgid "Change auth plan execution subtask"
msgid "Change auth plan execution subtask"
msgstr "改密计划执行子任务"
msgstr "改密计划执行子任务"
#: xpack/plugins/change_auth_plan/models.py:4
53
#: xpack/plugins/change_auth_plan/models.py:4
60
msgid "Authentication failed"
msgid "Authentication failed"
msgstr "认证失败"
msgstr "认证失败"
#: xpack/plugins/change_auth_plan/models.py:4
55
#: xpack/plugins/change_auth_plan/models.py:4
62
msgid "Connection timeout"
msgid "Connection timeout"
msgstr "连接超时"
msgstr "连接超时"
...
@@ -6437,6 +6446,12 @@ msgstr "密码匣子"
...
@@ -6437,6 +6446,12 @@ msgstr "密码匣子"
msgid "vault create"
msgid "vault create"
msgstr "创建"
msgstr "创建"
#~ msgid "succeed: {} failed: {} total: {}"
#~ msgstr "成功:{} 失败:{} 总数:{}"
#~ msgid "The user source is not LDAP"
#~ msgstr "用户来源不是LDAP"
#~ msgid "selected"
#~ msgid "selected"
#~ msgstr "所选"
#~ msgstr "所选"
...
@@ -6610,25 +6625,6 @@ msgstr "创建"
...
@@ -6610,25 +6625,6 @@ msgstr "创建"
#~ msgid "Sync User"
#~ msgid "Sync User"
#~ msgstr "同步用户"
#~ msgstr "同步用户"
#~ msgid "Have user but attr mapping error"
#~ msgstr "有用户但attr映射错误"
#~ msgid ""
#~ "Import {} users successfully; import {} users failed, the database "
#~ "already exists with the same name"
#~ msgstr "导入 {} 个用户成功; 导入 {} 这些用户失败,数据库已经存在同名的用户"
#~ msgid ""
#~ "Import {} users successfully; import {} users failed, the database "
#~ "already exists with the same name; import {}users failed, "
#~ "Because’TypeError' object has no attribute 'keys'"
#~ msgstr ""
#~ "导入 {} 个用户成功; 导入 {} 这些用户失败,数据库已经存在同名的用户; 导入 "
#~ "{} 这些用户失败,因为对象没有属性'keys'"
#~ msgid "Import {} users successfully"
#~ msgstr "导入 {} 个用户成功"
#~ msgid ""
#~ msgid ""
#~ "Import {} users successfully;import {} users failed, Because’TypeError' "
#~ "Import {} users successfully;import {} users failed, Because’TypeError' "
#~ "object has no attribute 'keys'"
#~ "object has no attribute 'keys'"
...
...
apps/perms/signals_handler.py
View file @
5434b657
...
@@ -11,13 +11,6 @@ from .utils.asset_permission import AssetPermissionUtilV2
...
@@ -11,13 +11,6 @@ from .utils.asset_permission import AssetPermissionUtilV2
logger
=
get_logger
(
__file__
)
logger
=
get_logger
(
__file__
)
permission_m2m_senders
=
(
AssetPermission
.
nodes
.
through
,
AssetPermission
.
assets
.
through
,
AssetPermission
.
users
.
through
,
AssetPermission
.
user_groups
.
through
,
)
@receiver
([
post_save
,
post_delete
],
sender
=
AssetPermission
)
@receiver
([
post_save
,
post_delete
],
sender
=
AssetPermission
)
@on_transaction_commit
@on_transaction_commit
...
...
apps/settings/api.py
View file @
5434b657
...
@@ -12,21 +12,27 @@ from django.conf import settings
...
@@ -12,21 +12,27 @@ from django.conf import settings
from
django.core.mail
import
send_mail
from
django.core.mail
import
send_mail
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
.models
import
Setting
from
.utils
import
(
LDAPServerUtil
,
LDAPCacheUtil
,
LDAPImportUtil
,
LDAPSyncUtil
,
LDAP_USE_CACHE_FLAGS
)
from
.tasks
import
sync_ldap_user_task
from
common.permissions
import
IsOrgAdmin
,
IsSuperUser
from
common.permissions
import
IsOrgAdmin
,
IsSuperUser
from
common.utils
import
get_logger
from
common.utils
import
get_logger
from
.models
import
Setting
from
.utils
import
LDAPUtil
from
.serializers
import
(
from
.serializers
import
(
MailTestSerializer
,
LDAPTestSerializer
,
LDAPUserSerializer
,
MailTestSerializer
,
LDAPTestSerializer
,
LDAPUserSerializer
,
PublicSettingSerializer
,
PublicSettingSerializer
,
)
)
from
users.models
import
User
logger
=
get_logger
(
__file__
)
logger
=
get_logger
(
__file__
)
class
MailTestingAPI
(
APIView
):
class
MailTestingAPI
(
APIView
):
permission_classes
=
(
Is
OrgAdmin
,)
permission_classes
=
(
Is
SuperUser
,)
serializer_class
=
MailTestSerializer
serializer_class
=
MailTestSerializer
success_message
=
_
(
"Test mail sent to {}, please check"
)
success_message
=
_
(
"Test mail sent to {}, please check"
)
...
@@ -65,70 +71,83 @@ class MailTestingAPI(APIView):
...
@@ -65,70 +71,83 @@ class MailTestingAPI(APIView):
class
LDAPTestingAPI
(
APIView
):
class
LDAPTestingAPI
(
APIView
):
permission_classes
=
(
Is
OrgAdmin
,)
permission_classes
=
(
Is
SuperUser
,)
serializer_class
=
LDAPTestSerializer
serializer_class
=
LDAPTestSerializer
success_message
=
_
(
"Test ldap success"
)
success_message
=
_
(
"Test ldap success"
)
@staticmethod
@staticmethod
def
get_ldap_
util
(
serializer
):
def
get_ldap_
config
(
serializer
):
host
=
serializer
.
validated_data
[
"AUTH_LDAP_SERVER_URI"
]
server_uri
=
serializer
.
validated_data
[
"AUTH_LDAP_SERVER_URI"
]
bind_dn
=
serializer
.
validated_data
[
"AUTH_LDAP_BIND_DN"
]
bind_dn
=
serializer
.
validated_data
[
"AUTH_LDAP_BIND_DN"
]
password
=
serializer
.
validated_data
[
"AUTH_LDAP_BIND_PASSWORD"
]
password
=
serializer
.
validated_data
[
"AUTH_LDAP_BIND_PASSWORD"
]
use_ssl
=
serializer
.
validated_data
.
get
(
"AUTH_LDAP_START_TLS"
,
False
)
use_ssl
=
serializer
.
validated_data
.
get
(
"AUTH_LDAP_START_TLS"
,
False
)
search_ougroup
=
serializer
.
validated_data
[
"AUTH_LDAP_SEARCH_OU"
]
search_ougroup
=
serializer
.
validated_data
[
"AUTH_LDAP_SEARCH_OU"
]
search_filter
=
serializer
.
validated_data
[
"AUTH_LDAP_SEARCH_FILTER"
]
search_filter
=
serializer
.
validated_data
[
"AUTH_LDAP_SEARCH_FILTER"
]
attr_map
=
serializer
.
validated_data
[
"AUTH_LDAP_USER_ATTR_MAP"
]
attr_map
=
serializer
.
validated_data
[
"AUTH_LDAP_USER_ATTR_MAP"
]
try
:
config
=
{
attr_map
=
json
.
loads
(
attr_map
)
'server_uri'
:
server_uri
,
except
json
.
JSONDecodeError
:
'bind_dn'
:
bind_dn
,
return
Response
({
"error"
:
"AUTH_LDAP_USER_ATTR_MAP not valid"
},
status
=
401
)
'password'
:
password
,
'use_ssl'
:
use_ssl
,
util
=
LDAPUtil
(
'search_ougroup'
:
search_ougroup
,
use_settings_config
=
False
,
server_uri
=
host
,
bind_dn
=
bind_dn
,
'search_filter'
:
search_filter
,
password
=
password
,
use_ssl
=
use_ssl
,
'attr_map'
:
json
.
loads
(
attr_map
),
search_ougroup
=
search_ougroup
,
search_filter
=
search_filter
,
}
attr_map
=
attr_map
return
config
)
return
util
def
post
(
self
,
request
):
def
post
(
self
,
request
):
serializer
=
self
.
serializer_class
(
data
=
request
.
data
)
serializer
=
self
.
serializer_class
(
data
=
request
.
data
)
if
not
serializer
.
is_valid
():
if
not
serializer
.
is_valid
():
return
Response
({
"error"
:
str
(
serializer
.
errors
)},
status
=
401
)
return
Response
({
"error"
:
str
(
serializer
.
errors
)},
status
=
401
)
util
=
self
.
get_ldap_util
(
serializer
)
attr_map
=
serializer
.
validated_data
[
"AUTH_LDAP_USER_ATTR_MAP"
]
try
:
json
.
loads
(
attr_map
)
except
json
.
JSONDecodeError
:
return
Response
({
"error"
:
_
(
"LDAP attr map not valid"
)},
status
=
401
)
config
=
self
.
get_ldap_config
(
serializer
)
util
=
LDAPServerUtil
(
config
=
config
)
try
:
try
:
users
=
util
.
search
_user_items
()
users
=
util
.
search
()
except
Exception
as
e
:
except
Exception
as
e
:
return
Response
({
"error"
:
str
(
e
)},
status
=
401
)
return
Response
({
"error"
:
str
(
e
)},
status
=
401
)
if
len
(
users
)
>
0
:
return
Response
({
"msg"
:
_
(
"Match {} s users"
)
.
format
(
len
(
users
))})
return
Response
({
"msg"
:
_
(
"Match {} s users"
)
.
format
(
len
(
users
))})
else
:
return
Response
({
"error"
:
"Have user but attr mapping error"
},
status
=
401
)
class
LDAPUserListApi
(
generics
.
ListAPIView
):
class
LDAPUserListApi
(
generics
.
ListAPIView
):
permission_classes
=
(
Is
OrgAdmin
,)
permission_classes
=
(
Is
SuperUser
,)
serializer_class
=
LDAPUserSerializer
serializer_class
=
LDAPUserSerializer
def
get_queryset_from_cache
(
self
):
search_value
=
self
.
request
.
query_params
.
get
(
'search'
)
users
=
LDAPCacheUtil
()
.
search
(
search_value
=
search_value
)
return
users
def
get_queryset_from_server
(
self
):
search_value
=
self
.
request
.
query_params
.
get
(
'search'
)
users
=
LDAPServerUtil
()
.
search
(
search_value
=
search_value
)
return
users
def
get_queryset
(
self
):
def
get_queryset
(
self
):
if
hasattr
(
self
,
'swagger_fake_view'
):
if
hasattr
(
self
,
'swagger_fake_view'
):
return
[]
return
[]
q
=
self
.
request
.
query_params
.
get
(
'search'
)
cache_police
=
self
.
request
.
query_params
.
get
(
'cache_police'
,
True
)
try
:
if
cache_police
in
LDAP_USE_CACHE_FLAGS
:
util
=
LDAPUtil
()
users
=
self
.
get_queryset_from_cache
()
extra_filter
=
util
.
construct_extra_filter
(
util
.
SEARCH_FIELD_ALL
,
q
)
else
:
users
=
util
.
search_user_items
(
extra_filter
)
users
=
self
.
get_queryset_from_server
()
except
Exception
as
e
:
users
=
[]
logger
.
error
(
e
)
# 前端data_table会根据row.id对table.selected值进行操作
for
user
in
users
:
user
[
'id'
]
=
user
[
'username'
]
return
users
return
users
@staticmethod
def
processing_queryset
(
queryset
):
db_username_list
=
User
.
objects
.
all
()
.
values_list
(
'username'
,
flat
=
True
)
for
q
in
queryset
:
q
[
'id'
]
=
q
[
'username'
]
q
[
'existing'
]
=
q
[
'username'
]
in
db_username_list
return
queryset
def
sort_queryset
(
self
,
queryset
):
def
sort_queryset
(
self
,
queryset
):
order_by
=
self
.
request
.
query_params
.
get
(
'order'
)
order_by
=
self
.
request
.
query_params
.
get
(
'order'
)
if
not
order_by
:
if
not
order_by
:
...
@@ -141,32 +160,87 @@ class LDAPUserListApi(generics.ListAPIView):
...
@@ -141,32 +160,87 @@ class LDAPUserListApi(generics.ListAPIView):
queryset
=
sorted
(
queryset
,
key
=
lambda
x
:
x
[
order_by
],
reverse
=
reverse
)
queryset
=
sorted
(
queryset
,
key
=
lambda
x
:
x
[
order_by
],
reverse
=
reverse
)
return
queryset
return
queryset
def
list
(
self
,
request
,
*
args
,
**
kwargs
):
def
filter_queryset
(
self
,
queryset
):
queryset
=
self
.
get_queryset
()
if
queryset
is
None
:
return
queryset
queryset
=
self
.
processing_queryset
(
queryset
)
queryset
=
self
.
sort_queryset
(
queryset
)
queryset
=
self
.
sort_queryset
(
queryset
)
page
=
self
.
paginate_queryset
(
queryset
)
return
queryset
if
page
is
not
None
:
return
self
.
get_paginated_response
(
page
)
def
list
(
self
,
request
,
*
args
,
**
kwargs
):
return
Response
(
queryset
)
cache_police
=
self
.
request
.
query_params
.
get
(
'cache_police'
,
True
)
# 不是用缓存
if
cache_police
not
in
LDAP_USE_CACHE_FLAGS
:
return
super
()
.
list
(
request
,
*
args
,
**
kwargs
)
try
:
queryset
=
self
.
get_queryset
()
except
Exception
as
e
:
data
=
{
'error'
:
str
(
e
)}
return
Response
(
data
=
data
,
status
=
400
)
# 缓存有数据
if
queryset
is
not
None
:
return
super
()
.
list
(
request
,
*
args
,
**
kwargs
)
sync_util
=
LDAPSyncUtil
()
# 还没有同步任务
if
sync_util
.
task_no_start
:
task
=
sync_ldap_user_task
.
delay
()
data
=
{
'msg'
:
'Cache no data, sync task {} started.'
.
format
(
task
.
id
)}
return
Response
(
data
=
data
,
status
=
409
)
# 同步任务正在执行
if
sync_util
.
task_is_running
:
data
=
{
'msg'
:
'synchronization is running.'
}
return
Response
(
data
=
data
,
status
=
409
)
# 同步任务执行结束
if
sync_util
.
task_is_over
:
msg
=
sync_util
.
get_task_error_msg
()
data
=
{
'error'
:
'Synchronization task report error: {}'
.
format
(
msg
)}
return
Response
(
data
=
data
,
status
=
400
)
return
super
()
.
list
(
request
,
*
args
,
**
kwargs
)
class
LDAPUserImportAPI
(
APIView
):
permission_classes
=
(
IsSuperUser
,)
class
LDAPUserSyncAPI
(
APIView
):
def
get_ldap_users
(
self
):
permission_classes
=
(
IsOrgAdmin
,)
username_list
=
self
.
request
.
data
.
get
(
'username_list'
,
[])
cache_police
=
self
.
request
.
query_params
.
get
(
'cache_police'
,
True
)
if
cache_police
in
LDAP_USE_CACHE_FLAGS
:
users
=
LDAPCacheUtil
()
.
search
(
search_users
=
username_list
)
else
:
users
=
LDAPServerUtil
()
.
search
(
search_users
=
username_list
)
return
users
def
post
(
self
,
request
):
def
post
(
self
,
request
):
username_list
=
request
.
data
.
get
(
'username_list'
,
[])
util
=
LDAPUtil
()
try
:
try
:
result
=
util
.
sync_users
(
username_list
)
users
=
self
.
get_ldap_users
(
)
except
Exception
as
e
:
except
Exception
as
e
:
logger
.
error
(
e
,
exc_info
=
True
)
return
Response
({
'error'
:
str
(
e
)},
status
=
401
)
return
Response
({
'error'
:
str
(
e
)},
status
=
401
)
else
:
msg
=
_
(
"succeed: {} failed: {} total: {}"
)
.
format
(
if
users
is
None
:
result
[
'succeed'
],
result
[
'failed'
],
result
[
'total'
]
return
Response
({
'msg'
:
_
(
'Get ldap users is None'
)},
status
=
401
)
)
return
Response
({
'msg'
:
msg
})
errors
=
LDAPImportUtil
()
.
perform_import
(
users
)
if
errors
:
return
Response
({
'errors'
:
errors
},
status
=
401
)
count
=
users
if
users
is
None
else
len
(
users
)
return
Response
({
'msg'
:
_
(
'Imported {} users successfully'
)
.
format
(
count
)})
class
LDAPCacheRefreshAPI
(
generics
.
RetrieveAPIView
):
permission_classes
=
(
IsSuperUser
,)
def
retrieve
(
self
,
request
,
*
args
,
**
kwargs
):
try
:
LDAPSyncUtil
()
.
clear_cache
()
except
Exception
as
e
:
logger
.
error
(
str
(
e
))
return
Response
(
data
=
{
'msg'
:
str
(
e
)},
status
=
400
)
return
Response
(
data
=
{
'msg'
:
'success'
})
class
ReplayStorageCreateAPI
(
APIView
):
class
ReplayStorageCreateAPI
(
APIView
):
...
...
apps/settings/serializers.py
View file @
5434b657
...
@@ -25,6 +25,7 @@ class LDAPTestSerializer(serializers.Serializer):
...
@@ -25,6 +25,7 @@ class LDAPTestSerializer(serializers.Serializer):
class
LDAPUserSerializer
(
serializers
.
Serializer
):
class
LDAPUserSerializer
(
serializers
.
Serializer
):
id
=
serializers
.
CharField
()
id
=
serializers
.
CharField
()
username
=
serializers
.
CharField
()
username
=
serializers
.
CharField
()
name
=
serializers
.
CharField
()
email
=
serializers
.
CharField
()
email
=
serializers
.
CharField
()
existing
=
serializers
.
BooleanField
(
read_only
=
True
)
existing
=
serializers
.
BooleanField
(
read_only
=
True
)
...
...
apps/settings/tasks/__init__.py
0 → 100644
View file @
5434b657
# coding: utf-8
#
from
.ldap
import
*
apps/settings/tasks/ldap.py
0 → 100644
View file @
5434b657
# coding: utf-8
#
from
celery
import
shared_task
from
common.utils
import
get_logger
from
..utils
import
LDAPSyncUtil
__all__
=
[
'sync_ldap_user_task'
]
logger
=
get_logger
(
__file__
)
@shared_task
def
sync_ldap_user_task
():
LDAPSyncUtil
()
.
perform_sync
()
apps/settings/templates/settings/_ldap_list_users_modal.html
View file @
5434b657
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
<div
class=
"row"
>
<div
class=
"row"
>
<div
class=
"col-lg-12 animated fadeInRight"
id=
"split-right"
>
<div
class=
"col-lg-12 animated fadeInRight"
id=
"split-right"
>
<div
class=
"mail-box-header"
>
<div
class=
"mail-box-header"
>
<div
class=
"uc pull-left m-r-5"
><a
id=
"id_refresh_cache"
class=
"btn btn-sm btn-primary"
>
{% trans "Refresh cache" %}
</a></div>
<table
class=
"table table-striped table-bordered table-hover "
id=
"ldap_list_users_table"
style=
"width: 100%"
>
<table
class=
"table table-striped table-bordered table-hover "
id=
"ldap_list_users_table"
style=
"width: 100%"
>
<thead>
<thead>
<tr>
<tr>
...
@@ -36,6 +37,9 @@
...
@@ -36,6 +37,9 @@
<tbody>
<tbody>
</tbody>
</tbody>
</table>
</table>
<div
id=
"fake_datatable_wrapper_loading"
class=
"dataTables_wrapper"
style=
"display: block;"
>
<div
id=
"ldap_list_users_table_processing"
class=
"dataTables_processing panel panel-default"
>
{% trans 'Loading' %}...
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
...
@@ -43,8 +47,11 @@
...
@@ -43,8 +47,11 @@
<script>
<script>
var
ldap_users_table
=
0
;
var
ldap_users_table
=
0
;
var
interval
;
function
initLdapUsersTable
()
{
function
initLdapUsersTable
()
{
if
(
ldap_users_table
){
if
(
ldap_users_table
){
ldap_users_table
.
ajax
.
reload
(
null
,
false
);
return
ldap_users_table
return
ldap_users_table
}
}
var
options
=
{
var
options
=
{
...
@@ -68,21 +75,93 @@ function initLdapUsersTable() {
...
@@ -68,21 +75,93 @@ function initLdapUsersTable() {
],
],
pageLength
:
15
pageLength
:
15
};
};
ldap_users_table
=
jumpserver
.
initServerSideDataTable
(
options
);
ldap_users_table
=
jumpserver
.
initServerSideDataTable
(
options
);
return
ldap_users_table
return
ldap_users_table
}
}
function
testRequestLdapUser
(){
$
(
"#fake_datatable_wrapper_loading"
).
css
(
'display'
,
'block'
);
var
the_url
=
"{% url 'api-settings:ldap-user-list' %}"
;
var
error
=
function
(
data
,
status
)
{
if
(
status
===
409
){
console
.
log
(
data
);
return
}
if
(
status
===
400
){
toastr
.
error
(
data
);
$
(
"#fake_datatable_wrapper_loading"
).
css
(
'display'
,
'none'
);
clearInterval
(
interval
);
interval
=
undefined
;
return
}
console
.
log
(
data
,
status
)
};
var
success
=
function
()
{
$
(
"#fake_datatable_wrapper_loading"
).
css
(
'display'
,
'none'
);
initLdapUsersTable
();
clearInterval
(
interval
);
interval
=
undefined
};
requestApi
({
url
:
the_url
,
method
:
'GET'
,
flash_message
:
false
,
error
:
error
,
success
:
success
});
}
function
timingTestRequestLdapUser
(){
if
(
interval
!==
undefined
){
return
}
interval
=
setInterval
(
testRequestLdapUser
,
2000
);
}
$
(
document
).
ready
(
function
(){
$
(
document
).
ready
(
function
(){
}).
on
(
'show.bs.modal'
,
function
()
{
}).
on
(
'show.bs.modal'
,
function
()
{
initLdapUsersTable
();
timingTestRequestLdapUser
()
})
})
.
on
(
'click'
,
'.close_btn1'
,
function
()
{
.
on
(
'click'
,
'#id_refresh_cache'
,
function
()
{
window
.
location
.
reload
()
var
the_url
=
"{% url "
api
-
settings
:
ldap
-
cache
-
refresh
" %}"
;
function
error
(
data
)
{
toastr
.
error
(
data
)
}
function
success
(){
timingTestRequestLdapUser
();
}
requestApi
({
url
:
the_url
,
method
:
'GET'
,
error
:
error
,
success
:
success
})
})
})
.
on
(
'click'
,
'.close_btn2'
,
function
()
{
.
on
(
"click"
,
"#btn_ldap_modal_confirm"
,
function
()
{
window
.
location
.
reload
()
var
username_list
=
ldap_users_table
.
selected
;
if
(
username_list
.
length
===
0
){
var
msg
=
"{% trans 'User is not currently selected, please check the user you want to import'%}"
;
toastr
.
error
(
msg
);
return
}
var
the_url
=
"{% url "
api
-
settings
:
ldap
-
user
-
import
" %}"
;
function
error
(
message
)
{
toastr
.
error
(
message
)
}
function
success
(
message
)
{
toastr
.
success
(
message
.
msg
);
ldap_users_table
.
selected
=
[];
timingTestRequestLdapUser
();
}
requestApi
({
url
:
the_url
,
body
:
JSON
.
stringify
({
'username_list'
:
username_list
}),
method
:
"POST"
,
flash_message
:
false
,
success
:
success
,
error
:
error
});
})
})
</script>
</script>
...
...
apps/settings/templates/settings/ldap_setting.html
View file @
5434b657
...
@@ -63,9 +63,8 @@
...
@@ -63,9 +63,8 @@
<div
class=
"col-sm-4 col-sm-offset-2"
>
<div
class=
"col-sm-4 col-sm-offset-2"
>
<button
class=
"btn btn-default"
type=
"reset"
>
{% trans 'Reset' %}
</button>
<button
class=
"btn btn-default"
type=
"reset"
>
{% trans 'Reset' %}
</button>
<button
class=
"btn btn-default btn-test"
type=
"button"
>
{% trans 'Test connection' %}
</button>
<button
class=
"btn btn-default btn-test"
type=
"button"
>
{% trans 'Test connection' %}
</button>
{#
<button
class=
"btn btn-primary sync_button "
data-toggle=
"modal"
data-target=
"#sync_users_modal"
type=
"button"
>
{% trans 'Synchronization' %}
</button>
#}
<button
id=
"submit_button"
class=
"btn btn-primary"
type=
"submit"
>
{% trans 'Submit' %}
</button>
<button
class=
"btn btn-default sync_button "
data-toggle=
"modal"
data-target=
"#ldap_list_users_modal"
type=
"button"
>
{% trans 'Bulk import' %}
</button>
<button
class=
"btn btn-default sync_button "
data-toggle=
"modal"
data-target=
"#ldap_list_users_modal"
type=
"button"
>
{% trans 'Bulk import' %}
</button>
<button
id=
"submit_button"
class=
"btn btn-primary"
type=
"submit"
>
{% trans 'Submit' %}
</button>
</div>
</div>
</div>
</div>
</form>
</form>
...
@@ -109,33 +108,6 @@ $(document).ready(function () {
...
@@ -109,33 +108,6 @@ $(document).ready(function () {
error
:
error
error
:
error
});
});
})
})
.
on
(
"click"
,
"#btn_ldap_modal_confirm"
,
function
()
{
var
username_list
=
ldap_users_table
.
selected
;
if
(
username_list
.
length
===
0
){
var
msg
=
"{% trans 'User is not currently selected, please check the user you want to import'%}"
;
toastr
.
error
(
msg
);
return
}
var
the_url
=
"{% url "
api
-
settings
:
ldap
-
user
-
sync
" %}"
;
function
error
(
message
)
{
toastr
.
error
(
message
)
}
function
success
(
message
)
{
toastr
.
success
(
message
.
msg
)
}
requestApi
({
url
:
the_url
,
body
:
JSON
.
stringify
({
'username_list'
:
username_list
}),
method
:
"POST"
,
flash_message
:
false
,
success
:
success
,
error
:
error
});
})
</script>
</script>
{% endblock %}
{% endblock %}
apps/settings/urls/api_urls.py
View file @
5434b657
...
@@ -10,7 +10,8 @@ urlpatterns = [
...
@@ -10,7 +10,8 @@ urlpatterns = [
path
(
'mail/testing/'
,
api
.
MailTestingAPI
.
as_view
(),
name
=
'mail-testing'
),
path
(
'mail/testing/'
,
api
.
MailTestingAPI
.
as_view
(),
name
=
'mail-testing'
),
path
(
'ldap/testing/'
,
api
.
LDAPTestingAPI
.
as_view
(),
name
=
'ldap-testing'
),
path
(
'ldap/testing/'
,
api
.
LDAPTestingAPI
.
as_view
(),
name
=
'ldap-testing'
),
path
(
'ldap/users/'
,
api
.
LDAPUserListApi
.
as_view
(),
name
=
'ldap-user-list'
),
path
(
'ldap/users/'
,
api
.
LDAPUserListApi
.
as_view
(),
name
=
'ldap-user-list'
),
path
(
'ldap/users/sync/'
,
api
.
LDAPUserSyncAPI
.
as_view
(),
name
=
'ldap-user-sync'
),
path
(
'ldap/users/import/'
,
api
.
LDAPUserImportAPI
.
as_view
(),
name
=
'ldap-user-import'
),
path
(
'ldap/cache/refresh/'
,
api
.
LDAPCacheRefreshAPI
.
as_view
(),
name
=
'ldap-cache-refresh'
),
path
(
'terminal/replay-storage/create/'
,
api
.
ReplayStorageCreateAPI
.
as_view
(),
name
=
'replay-storage-create'
),
path
(
'terminal/replay-storage/create/'
,
api
.
ReplayStorageCreateAPI
.
as_view
(),
name
=
'replay-storage-create'
),
path
(
'terminal/replay-storage/delete/'
,
api
.
ReplayStorageDeleteAPI
.
as_view
(),
name
=
'replay-storage-delete'
),
path
(
'terminal/replay-storage/delete/'
,
api
.
ReplayStorageDeleteAPI
.
as_view
(),
name
=
'replay-storage-delete'
),
path
(
'terminal/command-storage/create/'
,
api
.
CommandStorageCreateAPI
.
as_view
(),
name
=
'command-storage-create'
),
path
(
'terminal/command-storage/create/'
,
api
.
CommandStorageCreateAPI
.
as_view
(),
name
=
'command-storage-create'
),
...
...
apps/settings/utils.py
deleted
100644 → 0
View file @
a01126c6
# -*- coding: utf-8 -*-
#
from
ldap3
import
Server
,
Connection
from
django.utils.translation
import
ugettext_lazy
as
_
from
users.models
import
User
from
users.utils
import
construct_user_email
from
common.utils
import
get_logger
from
common.const
import
LDAP_AD_ACCOUNT_DISABLE
from
.models
import
settings
logger
=
get_logger
(
__file__
)
class
LDAPOUGroupException
(
Exception
):
pass
class
LDAPUtil
:
_conn
=
None
SEARCH_FIELD_ALL
=
'all'
SEARCH_FIELD_USERNAME
=
'username'
def
__init__
(
self
,
use_settings_config
=
True
,
server_uri
=
None
,
bind_dn
=
None
,
password
=
None
,
use_ssl
=
None
,
search_ougroup
=
None
,
search_filter
=
None
,
attr_map
=
None
,
auth_ldap
=
None
):
# config
self
.
paged_size
=
settings
.
AUTH_LDAP_SEARCH_PAGED_SIZE
if
use_settings_config
:
self
.
_load_config_from_settings
()
else
:
self
.
server_uri
=
server_uri
self
.
bind_dn
=
bind_dn
self
.
password
=
password
self
.
use_ssl
=
use_ssl
self
.
search_ougroup
=
search_ougroup
self
.
search_filter
=
search_filter
self
.
attr_map
=
attr_map
self
.
auth_ldap
=
auth_ldap
def
_load_config_from_settings
(
self
):
self
.
server_uri
=
settings
.
AUTH_LDAP_SERVER_URI
self
.
bind_dn
=
settings
.
AUTH_LDAP_BIND_DN
self
.
password
=
settings
.
AUTH_LDAP_BIND_PASSWORD
self
.
use_ssl
=
settings
.
AUTH_LDAP_START_TLS
self
.
search_ougroup
=
settings
.
AUTH_LDAP_SEARCH_OU
self
.
search_filter
=
settings
.
AUTH_LDAP_SEARCH_FILTER
self
.
attr_map
=
settings
.
AUTH_LDAP_USER_ATTR_MAP
self
.
auth_ldap
=
settings
.
AUTH_LDAP
@property
def
connection
(
self
):
if
self
.
_conn
is
None
:
server
=
Server
(
self
.
server_uri
,
use_ssl
=
self
.
use_ssl
)
conn
=
Connection
(
server
,
self
.
bind_dn
,
self
.
password
)
conn
.
bind
()
self
.
_conn
=
conn
return
self
.
_conn
@staticmethod
def
get_user_by_username
(
username
):
try
:
user
=
User
.
objects
.
get
(
username
=
username
)
except
Exception
as
e
:
return
None
else
:
return
user
def
_ldap_entry_to_user_item
(
self
,
entry
):
user_item
=
{}
for
attr
,
mapping
in
self
.
attr_map
.
items
():
if
not
hasattr
(
entry
,
mapping
):
continue
value
=
getattr
(
entry
,
mapping
)
.
value
or
''
if
mapping
.
lower
()
==
'useraccountcontrol'
and
attr
==
'is_active'
\
and
value
:
value
=
int
(
value
)
&
LDAP_AD_ACCOUNT_DISABLE
\
!=
LDAP_AD_ACCOUNT_DISABLE
user_item
[
attr
]
=
value
return
user_item
def
_search_user_items_ou
(
self
,
search_ou
,
extra_filter
=
None
,
cookie
=
None
):
search_filter
=
self
.
search_filter
%
{
"user"
:
"*"
}
if
extra_filter
:
search_filter
=
'(&{}{})'
.
format
(
search_filter
,
extra_filter
)
ok
=
self
.
connection
.
search
(
search_ou
,
search_filter
,
attributes
=
list
(
self
.
attr_map
.
values
()),
paged_size
=
self
.
paged_size
,
paged_cookie
=
cookie
)
if
not
ok
:
error
=
_
(
"Search no entry matched in ou {}"
.
format
(
search_ou
))
raise
LDAPOUGroupException
(
error
)
user_items
=
[]
for
entry
in
self
.
connection
.
entries
:
user_item
=
self
.
_ldap_entry_to_user_item
(
entry
)
user
=
self
.
get_user_by_username
(
user_item
[
'username'
])
user_item
[
'existing'
]
=
bool
(
user
)
if
user_item
in
user_items
:
continue
user_items
.
append
(
user_item
)
return
user_items
def
_cookie
(
self
):
if
self
.
paged_size
is
None
:
cookie
=
None
else
:
cookie
=
self
.
connection
.
result
[
'controls'
][
'1.2.840.113556.1.4.319'
][
'value'
][
'cookie'
]
return
cookie
def
search_user_items
(
self
,
extra_filter
=
None
):
user_items
=
[]
logger
.
info
(
"Search user items"
)
for
search_ou
in
str
(
self
.
search_ougroup
)
.
split
(
"|"
):
logger
.
info
(
"Search user search ou: {}"
.
format
(
search_ou
))
_user_items
=
self
.
_search_user_items_ou
(
search_ou
,
extra_filter
=
extra_filter
)
user_items
.
extend
(
_user_items
)
while
self
.
_cookie
():
logger
.
info
(
"Page Search user search ou: {}"
.
format
(
search_ou
))
_user_items
=
self
.
_search_user_items_ou
(
search_ou
,
extra_filter
,
self
.
_cookie
())
user_items
.
extend
(
_user_items
)
logger
.
info
(
"Search user items end"
)
return
user_items
def
construct_extra_filter
(
self
,
field
,
q
):
if
not
q
:
return
None
extra_filter
=
''
if
field
==
self
.
SEARCH_FIELD_ALL
:
for
attr
in
self
.
attr_map
.
values
():
extra_filter
+=
'({}={})'
.
format
(
attr
,
q
)
extra_filter
=
'(|{})'
.
format
(
extra_filter
)
return
extra_filter
if
field
==
self
.
SEARCH_FIELD_USERNAME
and
isinstance
(
q
,
list
):
attr
=
self
.
attr_map
.
get
(
'username'
)
for
username
in
q
:
extra_filter
+=
'({}={})'
.
format
(
attr
,
username
)
extra_filter
=
'(|{})'
.
format
(
extra_filter
)
return
extra_filter
def
search_filter_user_items
(
self
,
username_list
):
extra_filter
=
self
.
construct_extra_filter
(
self
.
SEARCH_FIELD_USERNAME
,
username_list
)
user_items
=
self
.
search_user_items
(
extra_filter
)
return
user_items
@staticmethod
def
save_user
(
user
,
user_item
):
for
field
,
value
in
user_item
.
items
():
if
not
hasattr
(
user
,
field
):
continue
if
isinstance
(
getattr
(
user
,
field
),
bool
):
if
isinstance
(
value
,
str
):
value
=
value
.
lower
()
value
=
value
in
[
'true'
,
1
,
True
]
setattr
(
user
,
field
,
value
)
user
.
save
()
def
update_user
(
self
,
user_item
):
user
=
self
.
get_user_by_username
(
user_item
[
'username'
])
if
user
.
source
!=
User
.
SOURCE_LDAP
:
msg
=
_
(
'The user source is not LDAP'
)
return
False
,
msg
try
:
self
.
save_user
(
user
,
user_item
)
except
Exception
as
e
:
logger
.
error
(
e
,
exc_info
=
True
)
return
False
,
str
(
e
)
else
:
return
True
,
None
def
create_user
(
self
,
user_item
):
user
=
User
(
source
=
User
.
SOURCE_LDAP
)
try
:
self
.
save_user
(
user
,
user_item
)
except
Exception
as
e
:
logger
.
error
(
e
,
exc_info
=
True
)
return
False
,
str
(
e
)
else
:
return
True
,
None
@staticmethod
def
construct_user_email
(
user_item
):
username
=
user_item
[
'username'
]
email
=
user_item
.
get
(
'email'
,
''
)
email
=
construct_user_email
(
username
,
email
)
return
email
def
create_or_update_users
(
self
,
user_items
):
succeed
=
failed
=
0
for
user_item
in
user_items
:
exist
=
user_item
.
pop
(
'existing'
,
False
)
user_item
[
'email'
]
=
self
.
construct_user_email
(
user_item
)
if
not
exist
:
ok
,
error
=
self
.
create_user
(
user_item
)
else
:
ok
,
error
=
self
.
update_user
(
user_item
)
if
not
ok
:
logger
.
info
(
"Failed User: {}"
.
format
(
user_item
))
failed
+=
1
else
:
succeed
+=
1
result
=
{
'total'
:
len
(
user_items
),
'succeed'
:
succeed
,
'failed'
:
failed
}
return
result
def
sync_users
(
self
,
username_list
=
None
):
user_items
=
self
.
search_filter_user_items
(
username_list
)
result
=
self
.
create_or_update_users
(
user_items
)
return
result
apps/settings/utils/__init__.py
0 → 100644
View file @
5434b657
# coding: utf-8
#
from
.ldap
import
*
apps/settings/utils/ldap.py
0 → 100644
View file @
5434b657
# coding: utf-8
#
from
ldap3
import
Server
,
Connection
from
django.conf
import
settings
from
django.core.cache
import
cache
from
django.utils.translation
import
ugettext_lazy
as
_
from
common.const
import
LDAP_AD_ACCOUNT_DISABLE
from
common.utils
import
timeit
,
get_logger
from
users.utils
import
construct_user_email
from
users.models
import
User
logger
=
get_logger
(
__file__
)
__all__
=
[
'LDAPConfig'
,
'LDAPServerUtil'
,
'LDAPCacheUtil'
,
'LDAPImportUtil'
,
'LDAPSyncUtil'
,
'LDAP_USE_CACHE_FLAGS'
]
LDAP_USE_CACHE_FLAGS
=
[
1
,
'1'
,
'true'
,
'True'
,
True
]
class
LDAPOUGroupException
(
Exception
):
pass
class
LDAPConfig
(
object
):
def
__init__
(
self
,
config
=
None
):
self
.
server_uri
=
None
self
.
bind_dn
=
None
self
.
password
=
None
self
.
use_ssl
=
None
self
.
search_ougroup
=
None
self
.
search_filter
=
None
self
.
attr_map
=
None
if
isinstance
(
config
,
dict
):
self
.
load_from_config
(
config
)
else
:
self
.
load_from_settings
()
def
load_from_config
(
self
,
config
):
self
.
server_uri
=
config
.
get
(
'server_uri'
)
self
.
bind_dn
=
config
.
get
(
'bind_dn'
)
self
.
password
=
config
.
get
(
'password'
)
self
.
use_ssl
=
config
.
get
(
'use_ssl'
)
self
.
search_ougroup
=
config
.
get
(
'search_ougroup'
)
self
.
search_filter
=
config
.
get
(
'search_filter'
)
self
.
attr_map
=
config
.
get
(
'attr_map'
)
def
load_from_settings
(
self
):
self
.
server_uri
=
settings
.
AUTH_LDAP_SERVER_URI
self
.
bind_dn
=
settings
.
AUTH_LDAP_BIND_DN
self
.
password
=
settings
.
AUTH_LDAP_BIND_PASSWORD
self
.
use_ssl
=
settings
.
AUTH_LDAP_START_TLS
self
.
search_ougroup
=
settings
.
AUTH_LDAP_SEARCH_OU
self
.
search_filter
=
settings
.
AUTH_LDAP_SEARCH_FILTER
self
.
attr_map
=
settings
.
AUTH_LDAP_USER_ATTR_MAP
class
LDAPServerUtil
(
object
):
def
__init__
(
self
,
config
=
None
):
if
isinstance
(
config
,
dict
):
self
.
config
=
LDAPConfig
(
config
=
config
)
elif
isinstance
(
config
,
LDAPConfig
):
self
.
config
=
config
else
:
self
.
config
=
LDAPConfig
()
self
.
_conn
=
None
self
.
_paged_size
=
self
.
get_paged_size
()
self
.
search_users
=
None
self
.
search_value
=
None
@property
def
connection
(
self
):
if
self
.
_conn
:
return
self
.
_conn
server
=
Server
(
self
.
config
.
server_uri
,
use_ssl
=
self
.
config
.
use_ssl
)
conn
=
Connection
(
server
,
self
.
config
.
bind_dn
,
self
.
config
.
password
)
conn
.
bind
()
self
.
_conn
=
conn
return
self
.
_conn
@staticmethod
def
get_paged_size
():
paged_size
=
settings
.
AUTH_LDAP_SEARCH_PAGED_SIZE
if
isinstance
(
paged_size
,
int
):
return
paged_size
return
None
def
paged_cookie
(
self
):
if
self
.
_paged_size
is
None
:
return
None
cookie
=
self
.
connection
.
result
[
'controls'
][
'1.2.840.113556.1.4.319'
][
'value'
][
'cookie'
]
return
cookie
def
get_search_filter_extra
(
self
):
extra
=
''
if
self
.
search_users
:
mapping_username
=
self
.
config
.
attr_map
.
get
(
'username'
)
for
user
in
self
.
search_users
:
extra
+=
'({}={})'
.
format
(
mapping_username
,
user
)
return
'(|{})'
.
format
(
extra
)
if
self
.
search_value
:
for
attr
in
self
.
config
.
attr_map
.
values
():
extra
+=
'({}={})'
.
format
(
attr
,
self
.
search_value
)
return
'(|{})'
.
format
(
extra
)
return
extra
def
get_search_filter
(
self
):
search_filter
=
self
.
config
.
search_filter
%
{
'user'
:
'*'
}
search_filter_extra
=
self
.
get_search_filter_extra
()
if
search_filter_extra
:
search_filter
=
'(&{}{})'
.
format
(
search_filter
,
search_filter_extra
)
return
search_filter
def
search_user_entries_ou
(
self
,
search_ou
,
paged_cookie
=
None
):
search_filter
=
self
.
get_search_filter
()
attributes
=
list
(
self
.
config
.
attr_map
.
values
())
ok
=
self
.
connection
.
search
(
search_base
=
search_ou
,
search_filter
=
search_filter
,
attributes
=
attributes
,
paged_size
=
self
.
_paged_size
,
paged_cookie
=
paged_cookie
)
if
not
ok
:
error
=
_
(
"Search no entry matched in ou {}"
.
format
(
search_ou
))
raise
LDAPOUGroupException
(
error
)
@timeit
def
search_user_entries
(
self
):
logger
.
info
(
"Search user entries"
)
user_entries
=
list
()
search_ous
=
str
(
self
.
config
.
search_ougroup
)
.
split
(
'|'
)
for
search_ou
in
search_ous
:
logger
.
info
(
"Search user entries ou: {}"
.
format
(
search_ou
))
self
.
search_user_entries_ou
(
search_ou
)
user_entries
.
extend
(
self
.
connection
.
entries
)
while
self
.
paged_cookie
():
self
.
search_user_entries_ou
(
search_ou
,
self
.
paged_cookie
())
user_entries
.
extend
(
self
.
connection
.
entries
)
return
user_entries
def
user_entry_to_dict
(
self
,
entry
):
user
=
{}
attr_map
=
self
.
config
.
attr_map
.
items
()
for
attr
,
mapping
in
attr_map
:
if
not
hasattr
(
entry
,
mapping
):
continue
value
=
getattr
(
entry
,
mapping
)
.
value
or
''
if
attr
==
'is_active'
and
mapping
.
lower
()
==
'useraccountcontrol'
\
and
value
:
value
=
int
(
value
)
&
LDAP_AD_ACCOUNT_DISABLE
!=
LDAP_AD_ACCOUNT_DISABLE
user
[
attr
]
=
value
return
user
@timeit
def
user_entries_to_dict
(
self
,
user_entries
):
users
=
[]
for
user_entry
in
user_entries
:
user
=
self
.
user_entry_to_dict
(
user_entry
)
users
.
append
(
user
)
return
users
@timeit
def
search
(
self
,
search_users
=
None
,
search_value
=
None
):
logger
.
info
(
"Search ldap users"
)
self
.
search_users
=
search_users
self
.
search_value
=
search_value
user_entries
=
self
.
search_user_entries
()
users
=
self
.
user_entries_to_dict
(
user_entries
)
return
users
class
LDAPCacheUtil
(
object
):
CACHE_KEY_USERS
=
'CACHE_KEY_LDAP_USERS'
def
__init__
(
self
):
self
.
search_users
=
None
self
.
search_value
=
None
def
set_users
(
self
,
users
):
logger
.
info
(
'Set ldap users to cache, count: {}'
.
format
(
len
(
users
)))
cache
.
set
(
self
.
CACHE_KEY_USERS
,
users
,
None
)
def
get_users
(
self
):
users
=
cache
.
get
(
self
.
CACHE_KEY_USERS
)
count
=
users
if
users
is
None
else
len
(
users
)
logger
.
info
(
'Get ldap users from cache, count: {}'
.
format
(
count
))
return
users
def
delete_users
(
self
):
logger
.
info
(
'Delete ldap users from cache'
)
cache
.
delete
(
self
.
CACHE_KEY_USERS
)
def
filter_users
(
self
,
users
):
if
users
is
None
:
return
users
if
self
.
search_users
:
filter_users
=
[
user
for
user
in
users
if
user
[
'username'
]
in
self
.
search_users
]
elif
self
.
search_value
:
filter_users
=
[
user
for
user
in
users
if
self
.
search_value
in
','
.
join
(
user
.
values
())
]
else
:
filter_users
=
users
return
filter_users
def
search
(
self
,
search_users
=
None
,
search_value
=
None
):
self
.
search_users
=
search_users
self
.
search_value
=
search_value
users
=
self
.
get_users
()
users
=
self
.
filter_users
(
users
)
return
users
class
LDAPSyncUtil
(
object
):
CACHE_KEY_LDAP_USERS_SYNC_TASK_ERROR_MSG
=
'CACHE_KEY_LDAP_USERS_SYNC_TASK_ERROR_MSG'
CACHE_KEY_LDAP_USERS_SYNC_TASK_STATUS
=
'CACHE_KEY_LDAP_USERS_SYNC_TASK_STATUS'
TASK_STATUS_IS_RUNNING
=
'RUNNING'
TASK_STATUS_IS_OVER
=
'OVER'
def
__init__
(
self
):
self
.
server_util
=
LDAPServerUtil
()
self
.
cache_util
=
LDAPCacheUtil
()
self
.
task_error_msg
=
None
def
clear_cache
(
self
):
logger
.
info
(
'Clear ldap sync cache'
)
self
.
delete_task_status
()
self
.
delete_task_error_msg
()
self
.
cache_util
.
delete_users
()
@property
def
task_no_start
(
self
):
status
=
self
.
get_task_status
()
return
status
is
None
@property
def
task_is_running
(
self
):
status
=
self
.
get_task_status
()
return
status
==
self
.
TASK_STATUS_IS_RUNNING
@property
def
task_is_over
(
self
):
status
=
self
.
get_task_status
()
return
status
==
self
.
TASK_STATUS_IS_OVER
def
set_task_status
(
self
,
status
):
logger
.
info
(
'Set task status: {}'
.
format
(
status
))
cache
.
set
(
self
.
CACHE_KEY_LDAP_USERS_SYNC_TASK_STATUS
,
status
,
None
)
def
get_task_status
(
self
):
status
=
cache
.
get
(
self
.
CACHE_KEY_LDAP_USERS_SYNC_TASK_STATUS
)
logger
.
info
(
'Get task status: {}'
.
format
(
status
))
return
status
def
delete_task_status
(
self
):
logger
.
info
(
'Delete task status'
)
cache
.
delete
(
self
.
CACHE_KEY_LDAP_USERS_SYNC_TASK_STATUS
)
def
set_task_error_msg
(
self
,
error_msg
):
logger
.
info
(
'Set task error msg'
)
cache
.
set
(
self
.
CACHE_KEY_LDAP_USERS_SYNC_TASK_ERROR_MSG
,
error_msg
,
None
)
def
get_task_error_msg
(
self
):
logger
.
info
(
'Get task error msg'
)
error_msg
=
cache
.
get
(
self
.
CACHE_KEY_LDAP_USERS_SYNC_TASK_ERROR_MSG
)
return
error_msg
def
delete_task_error_msg
(
self
):
logger
.
info
(
'Delete task error msg'
)
cache
.
delete
(
self
.
CACHE_KEY_LDAP_USERS_SYNC_TASK_ERROR_MSG
)
def
pre_sync
(
self
):
self
.
set_task_status
(
self
.
TASK_STATUS_IS_RUNNING
)
def
sync
(
self
):
users
=
self
.
server_util
.
search
()
self
.
cache_util
.
set_users
(
users
)
def
post_sync
(
self
):
self
.
set_task_status
(
self
.
TASK_STATUS_IS_OVER
)
def
perform_sync
(
self
):
logger
.
info
(
'Start perform sync ldap users from server to cache'
)
self
.
pre_sync
()
try
:
self
.
sync
()
except
Exception
as
e
:
error_msg
=
str
(
e
)
logger
.
error
(
error_msg
)
self
.
set_task_error_msg
(
error_msg
)
self
.
post_sync
()
logger
.
info
(
'End perform sync ldap users from server to cache'
)
class
LDAPImportUtil
(
object
):
def
__init__
(
self
):
pass
@staticmethod
def
get_user_email
(
user
):
username
=
user
[
'username'
]
email
=
user
[
'email'
]
email
=
construct_user_email
(
username
,
email
)
return
email
def
update_or_create
(
self
,
user
):
user
[
'email'
]
=
self
.
get_user_email
(
user
)
if
user
[
'username'
]
not
in
[
'admin'
]:
user
[
'source'
]
=
User
.
SOURCE_LDAP
obj
,
created
=
User
.
objects
.
update_or_create
(
username
=
user
[
'username'
],
defaults
=
user
)
return
obj
,
created
def
perform_import
(
self
,
users
):
logger
.
info
(
'Start perform import ldap users, count: {}'
.
format
(
len
(
users
)))
errors
=
[]
for
user
in
users
:
try
:
self
.
update_or_create
(
user
)
except
Exception
as
e
:
errors
.
append
({
user
[
'username'
]:
str
(
e
)})
logger
.
error
(
e
)
logger
.
info
(
'End perform import ldap users'
)
return
errors
apps/settings/views.py
View file @
5434b657
...
@@ -5,6 +5,7 @@ from django.utils.translation import ugettext as _
...
@@ -5,6 +5,7 @@ from django.utils.translation import ugettext as _
from
common.permissions
import
PermissionsMixin
,
IsSuperUser
from
common.permissions
import
PermissionsMixin
,
IsSuperUser
from
common
import
utils
from
common
import
utils
from
.utils
import
LDAPSyncUtil
from
.forms
import
EmailSettingForm
,
LDAPSettingForm
,
BasicSettingForm
,
\
from
.forms
import
EmailSettingForm
,
LDAPSettingForm
,
BasicSettingForm
,
\
TerminalSettingForm
,
SecuritySettingForm
,
EmailContentSettingForm
TerminalSettingForm
,
SecuritySettingForm
,
EmailContentSettingForm
...
@@ -83,6 +84,7 @@ class LDAPSettingView(PermissionsMixin, TemplateView):
...
@@ -83,6 +84,7 @@ class LDAPSettingView(PermissionsMixin, TemplateView):
form
.
save
()
form
.
save
()
msg
=
_
(
"Update setting successfully"
)
msg
=
_
(
"Update setting successfully"
)
messages
.
success
(
request
,
msg
)
messages
.
success
(
request
,
msg
)
LDAPSyncUtil
()
.
clear_cache
()
return
redirect
(
'settings:ldap-setting'
)
return
redirect
(
'settings:ldap-setting'
)
else
:
else
:
context
=
self
.
get_context_data
()
context
=
self
.
get_context_data
()
...
...
apps/users/signals_handler.py
View file @
5434b657
...
@@ -2,11 +2,11 @@
...
@@ -2,11 +2,11 @@
#
#
from
django.dispatch
import
receiver
from
django.dispatch
import
receiver
# from django.db.models.signals import post_save
from
django.db.models.signals
import
post_save
,
m2m_changed
from
common.utils
import
get_logger
from
common.utils
import
get_logger
from
.signals
import
post_user_create
from
.signals
import
post_user_create
#
from .models import User
from
.models
import
User
logger
=
get_logger
(
__file__
)
logger
=
get_logger
(
__file__
)
...
@@ -28,3 +28,14 @@ def on_user_create(sender, user=None, **kwargs):
...
@@ -28,3 +28,14 @@ def on_user_create(sender, user=None, **kwargs):
logger
.
info
(
" - Sending welcome mail ..."
.
format
(
user
.
name
))
logger
.
info
(
" - Sending welcome mail ..."
.
format
(
user
.
name
))
if
user
.
email
:
if
user
.
email
:
send_user_created_mail
(
user
)
send_user_created_mail
(
user
)
@receiver
(
m2m_changed
,
sender
=
User
.
groups
.
through
)
def
on_user_groups_change
(
sender
,
instance
=
None
,
action
=
''
,
**
kwargs
):
"""
资产节点发生变化时,刷新节点
"""
if
action
.
startswith
(
'post'
):
logger
.
debug
(
"User group member change signal recv: {}"
.
format
(
instance
))
from
perms.utils
import
AssetPermissionUtilV2
AssetPermissionUtilV2
.
expire_all_user_tree_cache
()
apps/users/tasks.py
View file @
5434b657
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#
#
import
sys
from
celery
import
shared_task
from
celery
import
shared_task
from
django.conf
import
settings
from
django.conf
import
settings
from
ops.celery.utils
import
create_or_update_celery_periodic_tasks
from
ops.celery.utils
import
(
create_or_update_celery_periodic_tasks
,
disable_celery_periodic_task
)
from
ops.celery.decorator
import
after_app_ready_start
from
ops.celery.decorator
import
after_app_ready_start
from
common.utils
import
get_logger
from
common.utils
import
get_logger
from
.models
import
User
from
.models
import
User
from
.utils
import
(
from
.utils
import
(
send_password_expiration_reminder_mail
,
send_user_expiration_reminder_mail
send_password_expiration_reminder_mail
,
send_user_expiration_reminder_mail
)
)
from
settings.utils
import
LDAPUtil
from
settings.utils
import
LDAP
ServerUtil
,
LDAPImport
Util
logger
=
get_logger
(
__file__
)
logger
=
get_logger
(
__file__
)
...
@@ -70,19 +73,26 @@ def check_user_expired_periodic():
...
@@ -70,19 +73,26 @@ def check_user_expired_periodic():
@shared_task
@shared_task
def
sync_ldap_user
():
def
import_ldap_user
():
logger
.
info
(
"Start sync ldap user periodic task"
)
logger
.
info
(
"Start import ldap user task"
)
util
=
LDAPUtil
()
util_server
=
LDAPServerUtil
()
result
=
util
.
sync_users
()
util_import
=
LDAPImportUtil
()
logger
.
info
(
"Result: {}"
.
format
(
result
))
users
=
util_server
.
search
()
errors
=
util_import
.
perform_import
(
users
)
if
errors
:
logger
.
error
(
"Imported LDAP users errors: {}"
.
format
(
errors
))
else
:
logger
.
info
(
'Imported {} users successfully'
.
format
(
len
(
users
)))
@shared_task
@shared_task
@after_app_ready_start
@after_app_ready_start
def
sync
_ldap_user_periodic
():
def
import
_ldap_user_periodic
():
if
not
settings
.
AUTH_LDAP
:
if
not
settings
.
AUTH_LDAP
:
return
return
if
not
settings
.
AUTH_LDAP_SYNC_IS_PERIODIC
:
if
not
settings
.
AUTH_LDAP_SYNC_IS_PERIODIC
:
task_name
=
sys
.
_getframe
()
.
f_code
.
co_name
disable_celery_periodic_task
(
task_name
)
return
return
interval
=
settings
.
AUTH_LDAP_SYNC_INTERVAL
interval
=
settings
.
AUTH_LDAP_SYNC_INTERVAL
...
@@ -91,10 +101,9 @@ def sync_ldap_user_periodic():
...
@@ -91,10 +101,9 @@ def sync_ldap_user_periodic():
else
:
else
:
interval
=
None
interval
=
None
crontab
=
settings
.
AUTH_LDAP_SYNC_CRONTAB
crontab
=
settings
.
AUTH_LDAP_SYNC_CRONTAB
tasks
=
{
tasks
=
{
'
sync
_ldap_user_periodic'
:
{
'
import
_ldap_user_periodic'
:
{
'task'
:
sync
_ldap_user
.
name
,
'task'
:
import
_ldap_user
.
name
,
'interval'
:
interval
,
'interval'
:
interval
,
'crontab'
:
crontab
,
'crontab'
:
crontab
,
'enabled'
:
True
,
'enabled'
:
True
,
...
...
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