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
9e487483
Commit
9e487483
authored
Nov 08, 2019
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Update] 修改tickets
parent
bd323d60
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
168 additions
and
119 deletions
+168
-119
login_confirm.py
apps/authentication/api/login_confirm.py
+4
-19
token.py
apps/authentication/api/token.py
+1
-1
mixins.py
apps/authentication/mixins.py
+49
-14
login_wait_confirm.html
...tication/templates/authentication/login_wait_confirm.html
+5
-1
login.py
apps/authentication/views/login.py
+18
-34
django.mo
apps/locale/zh/LC_MESSAGES/django.mo
+0
-0
django.po
apps/locale/zh/LC_MESSAGES/django.po
+33
-24
jumpserver.js
apps/static/js/jumpserver.js
+1
-1
login_confirm.py
apps/tickets/api/login_confirm.py
+2
-16
login_confirm.py
apps/tickets/serializers/login_confirm.py
+8
-2
login_confirm_ticket_list.html
.../tickets/templates/tickets/login_confirm_ticket_list.html
+45
-4
api_urls.py
apps/tickets/urls/api_urls.py
+2
-3
No files found.
apps/authentication/api/login_confirm.py
View file @
9e487483
...
@@ -10,7 +10,7 @@ from common.utils import get_logger, get_object_or_none
...
@@ -10,7 +10,7 @@ from common.utils import get_logger, get_object_or_none
from
common.permissions
import
IsOrgAdmin
from
common.permissions
import
IsOrgAdmin
from
..models
import
LoginConfirmSetting
from
..models
import
LoginConfirmSetting
from
..serializers
import
LoginConfirmSettingSerializer
from
..serializers
import
LoginConfirmSettingSerializer
from
..
import
errors
from
..
import
errors
,
mixins
__all__
=
[
'LoginConfirmSettingUpdateApi'
,
'LoginConfirmTicketStatusApi'
]
__all__
=
[
'LoginConfirmSettingUpdateApi'
,
'LoginConfirmTicketStatusApi'
]
logger
=
get_logger
(
__name__
)
logger
=
get_logger
(
__name__
)
...
@@ -31,7 +31,7 @@ class LoginConfirmSettingUpdateApi(UpdateAPIView):
...
@@ -31,7 +31,7 @@ class LoginConfirmSettingUpdateApi(UpdateAPIView):
return
s
return
s
class
LoginConfirmTicketStatusApi
(
APIView
):
class
LoginConfirmTicketStatusApi
(
mixins
.
AuthMixin
,
APIView
):
permission_classes
=
()
permission_classes
=
()
def
get_ticket
(
self
):
def
get_ticket
(
self
):
...
@@ -45,24 +45,9 @@ class LoginConfirmTicketStatusApi(APIView):
...
@@ -45,24 +45,9 @@ class LoginConfirmTicketStatusApi(APIView):
return
ticket
return
ticket
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
ticket_id
=
self
.
request
.
session
.
get
(
"auth_ticket_id"
)
ticket
=
self
.
get_ticket
()
try
:
try
:
if
not
ticket
:
self
.
check_user_login_confirm
()
raise
errors
.
LoginConfirmOtherError
(
ticket_id
,
_
(
"not found"
))
return
Response
({
"msg"
:
"ok"
})
if
ticket
.
status
==
'open'
:
raise
errors
.
LoginConfirmWaitError
(
ticket_id
)
elif
ticket
.
action
==
ticket
.
ACTION_APPROVE
:
self
.
request
.
session
[
"auth_confirm"
]
=
"1"
return
Response
({
"msg"
:
"ok"
})
elif
ticket
.
action
==
ticket
.
ACTION_REJECT
:
raise
errors
.
LoginConfirmOtherError
(
ticket_id
,
ticket
.
get_action_display
()
)
else
:
raise
errors
.
LoginConfirmOtherError
(
ticket_id
,
ticket
.
get_status_display
()
)
except
errors
.
NeedMoreInfoError
as
e
:
except
errors
.
NeedMoreInfoError
as
e
:
return
Response
(
e
.
as_data
(),
status
=
200
)
return
Response
(
e
.
as_data
(),
status
=
200
)
...
...
apps/authentication/api/token.py
View file @
9e487483
...
@@ -28,7 +28,7 @@ class TokenCreateApi(AuthMixin, CreateAPIView):
...
@@ -28,7 +28,7 @@ class TokenCreateApi(AuthMixin, CreateAPIView):
self
.
create_session_if_need
()
self
.
create_session_if_need
()
# 如果认证没有过,检查账号密码
# 如果认证没有过,检查账号密码
try
:
try
:
user
=
self
.
check_user_auth
()
user
=
self
.
check_user_auth
_if_need
()
self
.
check_user_mfa_if_need
(
user
)
self
.
check_user_mfa_if_need
(
user
)
self
.
check_user_login_confirm_if_need
(
user
)
self
.
check_user_login_confirm_if_need
(
user
)
self
.
send_auth_signal
(
success
=
True
,
user
=
user
)
self
.
send_auth_signal
(
success
=
True
,
user
=
user
)
...
...
apps/authentication/mixins.py
View file @
9e487483
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#
#
import
time
import
time
from
django.conf
import
settings
from
common.utils
import
get_object_or_none
,
get_request_ip
,
get_logger
from
common.utils
import
get_object_or_none
,
get_request_ip
,
get_logger
from
users.models
import
User
from
users.models
import
User
...
@@ -49,8 +50,8 @@ class AuthMixin:
...
@@ -49,8 +50,8 @@ class AuthMixin:
raise
errors
.
BlockLoginError
(
username
=
username
,
ip
=
ip
)
raise
errors
.
BlockLoginError
(
username
=
username
,
ip
=
ip
)
def
check_user_auth
(
self
):
def
check_user_auth
(
self
):
request
=
self
.
request
self
.
check_is_block
()
self
.
check_is_block
()
request
=
self
.
request
if
hasattr
(
request
,
'data'
):
if
hasattr
(
request
,
'data'
):
username
=
request
.
data
.
get
(
'username'
,
''
)
username
=
request
.
data
.
get
(
'username'
,
''
)
password
=
request
.
data
.
get
(
'password'
,
''
)
password
=
request
.
data
.
get
(
'password'
,
''
)
...
@@ -73,11 +74,20 @@ class AuthMixin:
...
@@ -73,11 +74,20 @@ class AuthMixin:
request
.
session
[
'user_id'
]
=
str
(
user
.
id
)
request
.
session
[
'user_id'
]
=
str
(
user
.
id
)
return
user
return
user
def
check_user_auth_if_need
(
self
):
request
=
self
.
request
if
request
.
session
.
get
(
'auth_password'
)
and
\
request
.
session
.
get
(
'user_id'
):
user
=
self
.
get_user_from_session
()
if
user
:
return
user
return
self
.
check_user_auth
()
def
check_user_mfa_if_need
(
self
,
user
):
def
check_user_mfa_if_need
(
self
,
user
):
if
self
.
request
.
session
.
get
(
'auth_mfa'
):
if
self
.
request
.
session
.
get
(
'auth_mfa'
):
return
True
return
if
not
user
.
otp_enabled
or
not
user
.
otp_secret_key
:
if
not
user
.
otp_enabled
or
not
user
.
otp_secret_key
:
return
True
return
raise
errors
.
MFARequiredError
()
raise
errors
.
MFARequiredError
()
def
check_user_mfa
(
self
,
code
):
def
check_user_mfa
(
self
,
code
):
...
@@ -90,28 +100,53 @@ class AuthMixin:
...
@@ -90,28 +100,53 @@ class AuthMixin:
return
return
raise
errors
.
MFAFailedError
(
username
=
user
.
username
,
request
=
self
.
request
)
raise
errors
.
MFAFailedError
(
username
=
user
.
username
,
request
=
self
.
request
)
def
check_user_login_confirm_if_need
(
self
,
user
):
def
get_ticket
(
self
):
from
tickets.models
import
LoginConfirmTicket
from
tickets.models
import
LoginConfirmTicket
confirm_setting
=
user
.
get_login_confirm_setting
()
ticket_id
=
self
.
request
.
session
.
get
(
"auth_ticket_id"
)
if
self
.
request
.
session
.
get
(
'auth_confirm'
)
or
not
confirm_setting
:
logger
.
debug
(
'Login confirm ticket id: {}'
.
format
(
ticket_id
))
return
if
not
ticket_id
:
ticket
=
None
ticket
=
None
if
self
.
request
.
session
.
get
(
'auth_ticket_id'
):
else
:
ticket_id
=
self
.
request
.
session
[
'auth_ticket_id'
]
ticket
=
get_object_or_none
(
LoginConfirmTicket
,
pk
=
ticket_id
)
ticket
=
get_object_or_none
(
LoginConfirmTicket
,
pk
=
ticket_id
)
return
ticket
def
get_ticket_or_create
(
self
,
confirm_setting
):
ticket
=
self
.
get_ticket
()
if
not
ticket
:
if
not
ticket
:
ticket
=
confirm_setting
.
create_confirm_ticket
(
self
.
request
)
ticket
=
confirm_setting
.
create_confirm_ticket
(
self
.
request
)
self
.
request
.
session
[
'auth_ticket_id'
]
=
str
(
ticket
.
id
)
self
.
request
.
session
[
'auth_ticket_id'
]
=
str
(
ticket
.
id
)
return
ticket
if
ticket
.
status
==
"accepted"
:
def
check_user_login_confirm
(
self
):
ticket
=
self
.
get_ticket
()
if
not
ticket
:
raise
errors
.
LoginConfirmOtherError
(
''
,
"Not found"
)
if
ticket
.
status
==
ticket
.
STATUS_OPEN
:
raise
errors
.
LoginConfirmWaitError
(
ticket
.
id
)
elif
ticket
.
action
==
ticket
.
ACTION_APPROVE
:
self
.
request
.
session
[
"auth_confirm"
]
=
"1"
return
return
elif
ticket
.
status
==
"rejected"
:
elif
ticket
.
action
==
ticket
.
ACTION_REJECT
:
raise
errors
.
LoginConfirmOtherError
(
ticket
.
id
)
raise
errors
.
LoginConfirmOtherError
(
ticket
.
id
,
ticket
.
get_action_display
()
)
else
:
else
:
raise
errors
.
LoginConfirmWaitError
(
ticket
.
id
)
raise
errors
.
LoginConfirmOtherError
(
ticket
.
id
,
ticket
.
get_status_display
()
)
def
check_user_login_confirm_if_need
(
self
,
user
):
if
not
settings
.
CONFIG
.
LOGIN_CONFIRM_ENABLE
:
return
confirm_setting
=
user
.
get_login_confirm_setting
()
if
self
.
request
.
session
.
get
(
'auth_confirm'
)
or
not
confirm_setting
:
return
self
.
get_ticket_or_create
(
confirm_setting
)
self
.
check_user_login_confirm
()
def
clear_auth_mark
(
self
):
def
clear_auth_mark
(
self
):
self
.
request
.
session
[
'auth_password'
]
=
''
self
.
request
.
session
[
'auth_password'
]
=
''
self
.
request
.
session
[
'auth_user_id'
]
=
''
self
.
request
.
session
[
'auth_mfa'
]
=
''
self
.
request
.
session
[
'auth_mfa'
]
=
''
self
.
request
.
session
[
'auth_confirm'
]
=
''
self
.
request
.
session
[
'auth_confirm'
]
=
''
self
.
request
.
session
[
'auth_ticket_id'
]
=
''
self
.
request
.
session
[
'auth_ticket_id'
]
=
''
...
...
apps/authentication/templates/authentication/login_wait_confirm.html
View file @
9e487483
...
@@ -43,7 +43,7 @@
...
@@ -43,7 +43,7 @@
</a>
</a>
</div>
</div>
<div
class=
"col-lg-3"
>
<div
class=
"col-lg-3"
>
<a
class=
"btn btn-primary btn-sm block btn-copy"
data-link=
"{{
order
_detail_url }}"
>
<a
class=
"btn btn-primary btn-sm block btn-copy"
data-link=
"{{
ticket
_detail_url }}"
>
<i
class=
"fa fa-clipboard"
></i>
{% trans 'Copy link' %}
<i
class=
"fa fa-clipboard"
></i>
{% trans 'Copy link' %}
</a>
</a>
</div>
</div>
...
@@ -132,7 +132,11 @@ $(document).ready(function () {
...
@@ -132,7 +132,11 @@ $(document).ready(function () {
checkInterval
=
setInterval
(
doRequestAuth
,
5000
);
checkInterval
=
setInterval
(
doRequestAuth
,
5000
);
doRequestAuth
();
doRequestAuth
();
initClipboard
();
initClipboard
();
window
.
onbeforeunload
=
function
(
e
)
{
return
"{% trans "
Confirm
" %}"
;
};
}).
on
(
'click'
,
'.btn-refresh'
,
function
()
{
}).
on
(
'click'
,
'.btn-refresh'
,
function
()
{
window
.
onbeforeunload
=
function
()
{};
window
.
location
.
reload
();
window
.
location
.
reload
();
})
})
...
...
apps/authentication/views/login.py
View file @
9e487483
...
@@ -19,9 +19,7 @@ from django.conf import settings
...
@@ -19,9 +19,7 @@ from django.conf import settings
from
django.urls
import
reverse_lazy
from
django.urls
import
reverse_lazy
from
common.utils
import
get_request_ip
,
get_object_or_none
from
common.utils
import
get_request_ip
,
get_object_or_none
from
users.models
import
User
from
users.utils
import
(
from
users.utils
import
(
get_user_or_tmp_user
,
increase_login_failed_count
,
redirect_user_first_login_or_index
redirect_user_first_login_or_index
)
)
from
..signals
import
post_auth_success
,
post_auth_failed
from
..signals
import
post_auth_success
,
post_auth_failed
...
@@ -117,42 +115,28 @@ class UserLoginGuardView(mixins.AuthMixin, RedirectView):
...
@@ -117,42 +115,28 @@ class UserLoginGuardView(mixins.AuthMixin, RedirectView):
return
url
return
url
def
get_redirect_url
(
self
,
*
args
,
**
kwargs
):
def
get_redirect_url
(
self
,
*
args
,
**
kwargs
):
if
not
self
.
request
.
session
.
get
(
'auth_password'
):
try
:
user
=
self
.
check_user_auth_if_need
()
self
.
check_user_mfa_if_need
(
user
)
self
.
check_user_login_confirm_if_need
(
user
)
except
errors
.
CredentialError
:
return
self
.
format_redirect_url
(
self
.
login_url
)
return
self
.
format_redirect_url
(
self
.
login_url
)
user
=
self
.
get_user_from_session
()
except
errors
.
MFARequiredError
:
# 启用并设置了otp
if
user
.
otp_enabled
and
user
.
otp_secret_key
and
\
not
self
.
request
.
session
.
get
(
'auth_mfa'
):
return
self
.
format_redirect_url
(
self
.
login_otp_url
)
return
self
.
format_redirect_url
(
self
.
login_otp_url
)
confirm_setting
=
user
.
get_login_confirm_setting
()
except
errors
.
LoginConfirmBaseError
:
if
confirm_setting
and
not
self
.
request
.
session
.
get
(
'auth_confirm'
):
return
self
.
format_redirect_url
(
self
.
login_confirm_url
)
ticket
=
confirm_setting
.
create_confirm_ticket
(
self
.
request
)
self
.
request
.
session
[
'auth_ticket_id'
]
=
str
(
ticket
.
id
)
url
=
self
.
format_redirect_url
(
self
.
login_confirm_url
)
return
url
self
.
login_success
(
user
)
self
.
clear_auth_mark
()
# 启用但是没有设置otp
if
user
.
otp_enabled
and
not
user
.
otp_secret_key
:
# 1,2,mfa_setting & F
return
reverse
(
'users:user-otp-enable-authentication'
)
url
=
redirect_user_first_login_or_index
(
self
.
request
,
self
.
redirect_field_name
)
return
url
def
login_success
(
self
,
user
):
auth_login
(
self
.
request
,
user
)
self
.
send_auth_signal
(
success
=
True
,
user
=
user
)
def
send_auth_signal
(
self
,
success
=
True
,
user
=
None
,
username
=
''
,
reason
=
''
):
if
success
:
post_auth_success
.
send
(
sender
=
self
.
__class__
,
user
=
user
,
request
=
self
.
request
)
else
:
else
:
post_auth_failed
.
send
(
auth_login
(
self
.
request
,
user
)
sender
=
self
.
__class__
,
username
=
username
,
self
.
send_auth_signal
(
success
=
True
,
user
=
user
)
request
=
self
.
request
,
reason
=
reason
self
.
clear_auth_mark
()
# 启用但是没有设置otp
if
user
.
otp_enabled
and
not
user
.
otp_secret_key
:
# 1,2,mfa_setting & F
return
reverse
(
'users:user-otp-enable-authentication'
)
url
=
redirect_user_first_login_or_index
(
self
.
request
,
self
.
redirect_field_name
)
)
return
url
class
UserLoginWaitConfirmView
(
TemplateView
):
class
UserLoginWaitConfirmView
(
TemplateView
):
...
...
apps/locale/zh/LC_MESSAGES/django.mo
View file @
9e487483
No preview for this file type
apps/locale/zh/LC_MESSAGES/django.po
View file @
9e487483
...
@@ -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 1
5:42
+0800\n"
"POT-Creation-Date: 2019-11-08 1
7:27
+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"
...
@@ -354,6 +354,7 @@ msgstr "重置"
...
@@ -354,6 +354,7 @@ msgstr "重置"
#: terminal/templates/terminal/command_list.html:47
#: terminal/templates/terminal/command_list.html:47
#: terminal/templates/terminal/session_list.html:52
#: terminal/templates/terminal/session_list.html:52
#: terminal/templates/terminal/terminal_update.html:46
#: terminal/templates/terminal/terminal_update.html:46
#: tickets/templates/tickets/login_confirm_ticket_list.html:32
#: users/templates/users/_user.html:52
#: users/templates/users/_user.html:52
#: users/templates/users/forgot_password.html:42
#: users/templates/users/forgot_password.html:42
#: users/templates/users/user_bulk_update.html:24
#: users/templates/users/user_bulk_update.html:24
...
@@ -528,7 +529,7 @@ msgstr "创建远程应用"
...
@@ -528,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:
92
#: tickets/templates/tickets/login_confirm_ticket_list.html:
105
#: 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
...
@@ -1480,7 +1481,7 @@ msgid "Asset user auth"
...
@@ -1480,7 +1481,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
4
#: authentication/templates/authentication/login_wait_confirm.html:11
5
msgid "Copy success"
msgid "Copy success"
msgstr "复制成功"
msgstr "复制成功"
...
@@ -1666,6 +1667,7 @@ msgstr "选择节点"
...
@@ -1666,6 +1667,7 @@ 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
...
@@ -2294,7 +2296,7 @@ msgstr "原因"
...
@@ -2294,7 +2296,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:
88
#: tickets/templates/tickets/login_confirm_ticket_list.html:
101
#: 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
...
@@ -2390,10 +2392,6 @@ msgstr "登录日志"
...
@@ -2390,10 +2392,6 @@ msgstr "登录日志"
msgid "Command execution log"
msgid "Command execution log"
msgstr "命令执行"
msgstr "命令执行"
#: authentication/api/login_confirm.py:52
msgid "not found"
msgstr "没有发现"
#: authentication/backends/api.py:53
#: authentication/backends/api.py:53
msgid "Invalid signature header. No credentials provided."
msgid "Invalid signature header. No credentials provided."
msgstr ""
msgstr ""
...
@@ -2703,11 +2701,11 @@ msgstr "返回"
...
@@ -2703,11 +2701,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
3
#: authentication/views/login.py:7
1
msgid "Please enable cookies and try again."
msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie"
msgstr "设置你的浏览器支持cookie"
#: authentication/views/login.py:17
2
#: authentication/views/login.py:17
0
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"
...
@@ -2715,15 +2713,15 @@ msgstr ""
...
@@ -2715,15 +2713,15 @@ msgstr ""
"等待 <b>{}</b> 确认, 你也可以复制链接发给他/她 <br/>\n"
"等待 <b>{}</b> 确认, 你也可以复制链接发给他/她 <br/>\n"
" 不要关闭本页面"
" 不要关闭本页面"
#: authentication/views/login.py:17
7
#: authentication/views/login.py:17
5
msgid "No ticket found"
msgid "No ticket found"
msgstr "没有发现工单"
msgstr "没有发现工单"
#: authentication/views/login.py:
200
#: authentication/views/login.py:
198
msgid "Logout success"
msgid "Logout success"
msgstr "退出登录成功"
msgstr "退出登录成功"
#: authentication/views/login.py:
201
#: authentication/views/login.py:
199
msgid "Logout success, return login page"
msgid "Logout success, return login page"
msgstr "退出登录成功,返回到登录页面"
msgstr "退出登录成功,返回到登录页面"
...
@@ -4571,8 +4569,8 @@ msgstr "接受"
...
@@ -4571,8 +4569,8 @@ msgstr "接受"
#: terminal/templates/terminal/terminal_list.html:80
#: terminal/templates/terminal/terminal_list.html:80
#: 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:
57
#: tickets/templates/tickets/login_confirm_ticket_list.html:
70
#: tickets/templates/tickets/login_confirm_ticket_list.html:
94
#: tickets/templates/tickets/login_confirm_ticket_list.html:
107
msgid "Reject"
msgid "Reject"
msgstr "拒绝"
msgstr "拒绝"
...
@@ -4610,12 +4608,12 @@ msgid ""
...
@@ -4610,12 +4608,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:
89
#: tickets/templates/tickets/login_confirm_ticket_list.html:
102
msgid "Open"
msgid "Open"
msgstr ""
msgstr "
开启
"
#: tickets/models/base.py:17
#: tickets/models/base.py:17
#: tickets/templates/tickets/login_confirm_ticket_list.html:
90
#: tickets/templates/tickets/login_confirm_ticket_list.html:
103
msgid "Closed"
msgid "Closed"
msgstr "关闭"
msgstr "关闭"
...
@@ -4629,7 +4627,7 @@ msgstr "用户显示名称"
...
@@ -4629,7 +4627,7 @@ msgstr "用户显示名称"
#: tickets/models/base.py:28
#: tickets/models/base.py:28
#: tickets/templates/tickets/login_confirm_ticket_list.html:14
#: tickets/templates/tickets/login_confirm_ticket_list.html:14
#: tickets/templates/tickets/login_confirm_ticket_list.html:
87
#: tickets/templates/tickets/login_confirm_ticket_list.html:
100
msgid "Title"
msgid "Title"
msgstr "标题"
msgstr "标题"
...
@@ -4659,8 +4657,8 @@ msgstr "{} {} 这个工单"
...
@@ -4659,8 +4657,8 @@ 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:
56
#: tickets/templates/tickets/login_confirm_ticket_list.html:
69
#: tickets/templates/tickets/login_confirm_ticket_list.html:
93
#: tickets/templates/tickets/login_confirm_ticket_list.html:
106
msgid "Approve"
msgid "Approve"
msgstr "同意"
msgstr "同意"
...
@@ -4668,6 +4666,14 @@ msgstr "同意"
...
@@ -4668,6 +4666,14 @@ msgstr "同意"
msgid "this order"
msgid "this order"
msgstr "这个工单"
msgstr "这个工单"
#: tickets/templates/tickets/login_confirm_ticket_list.html:27
msgid "Approve selected"
msgstr "同意所选"
#: tickets/templates/tickets/login_confirm_ticket_list.html:28
msgid "Reject selected"
msgstr "拒绝所选"
#: tickets/templates/tickets/ticket_detail.html:66
#: tickets/templates/tickets/ticket_detail.html:66
#: tickets/templates/tickets/ticket_detail.html:81
#: tickets/templates/tickets/ticket_detail.html:81
msgid "ago"
msgid "ago"
...
@@ -6431,6 +6437,12 @@ msgstr "密码匣子"
...
@@ -6431,6 +6437,12 @@ msgstr "密码匣子"
msgid "vault create"
msgid "vault create"
msgstr "创建"
msgstr "创建"
#~ msgid "selected"
#~ msgstr "所选"
#~ msgid "not found"
#~ msgstr "没有发现"
#~ msgid "Log in frequently and try again later"
#~ msgid "Log in frequently and try again later"
#~ msgstr "登录频繁, 稍后重试"
#~ msgstr "登录频繁, 稍后重试"
...
@@ -6446,9 +6458,6 @@ msgstr "创建"
...
@@ -6446,9 +6458,6 @@ msgstr "创建"
#~ msgid "Accepted"
#~ msgid "Accepted"
#~ msgstr "已接受"
#~ msgstr "已接受"
#~ msgid "Rejected"
#~ msgstr "已拒绝"
#~ msgid "New order"
#~ msgid "New order"
#~ msgstr "新工单"
#~ msgstr "新工单"
...
...
apps/static/js/jumpserver.js
View file @
9e487483
...
@@ -1319,5 +1319,5 @@ function initDateRangePicker(selector, options) {
...
@@ -1319,5 +1319,5 @@ function initDateRangePicker(selector, options) {
}
}
function
reloadPage
()
{
function
reloadPage
()
{
window
.
location
.
reload
(
);
setTimeout
(
function
()
{
window
.
location
.
reload
();},
300
);
}
}
apps/tickets/api/login_confirm.py
View file @
9e487483
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#
#
from
rest_framework
import
viewsets
,
generics
from
rest_framework_bulk
import
BulkModelViewSet
from
rest_framework.serializers
import
ValidationError
from
django.shortcuts
import
get_object_or_404
from
common.permissions
import
IsValidUser
from
common.permissions
import
IsValidUser
from
common.mixins
import
CommonApiMixin
from
common.mixins
import
CommonApiMixin
...
@@ -10,21 +8,9 @@ from .. import serializers, mixins
...
@@ -10,21 +8,9 @@ from .. import serializers, mixins
from
..models
import
LoginConfirmTicket
from
..models
import
LoginConfirmTicket
class
LoginConfirmTicketViewSet
(
CommonApiMixin
,
mixins
.
TicketMixin
,
viewsets
.
ModelViewSet
):
class
LoginConfirmTicketViewSet
(
CommonApiMixin
,
mixins
.
TicketMixin
,
Bulk
ModelViewSet
):
serializer_class
=
serializers
.
LoginConfirmTicketSerializer
serializer_class
=
serializers
.
LoginConfirmTicketSerializer
permission_classes
=
(
IsValidUser
,)
permission_classes
=
(
IsValidUser
,)
queryset
=
LoginConfirmTicket
.
objects
.
all
()
queryset
=
LoginConfirmTicket
.
objects
.
all
()
filter_fields
=
[
'status'
,
'title'
,
'action'
,
'ip'
]
filter_fields
=
[
'status'
,
'title'
,
'action'
,
'ip'
]
search_fields
=
[
'user_display'
,
'title'
,
'ip'
,
'city'
]
search_fields
=
[
'user_display'
,
'title'
,
'ip'
,
'city'
]
# def check_update_permission(self, serializer):
# data = serializer.validated_data
# action = data.get("action")
# user = self.request.user
# instance = serializer.instance
# if action and user not in instance.assignees.all():
# error = {"action": "Only assignees can update"}
# raise ValidationError(error)
#
# def perform_update(self, serializer):
# self.check_update_permission(serializer)
apps/tickets/serializers/login_confirm.py
View file @
9e487483
...
@@ -2,6 +2,8 @@
...
@@ -2,6 +2,8 @@
#
#
from
rest_framework
import
serializers
from
rest_framework
import
serializers
from
common.serializers
import
AdaptedBulkListSerializer
from
common.mixins.serializers
import
BulkSerializerMixin
from
.base
import
TicketSerializer
from
.base
import
TicketSerializer
from
..models
import
LoginConfirmTicket
from
..models
import
LoginConfirmTicket
...
@@ -9,8 +11,9 @@ from ..models import LoginConfirmTicket
...
@@ -9,8 +11,9 @@ from ..models import LoginConfirmTicket
__all__
=
[
'LoginConfirmTicketSerializer'
,
'LoginConfirmTicketActionSerializer'
]
__all__
=
[
'LoginConfirmTicketSerializer'
,
'LoginConfirmTicketActionSerializer'
]
class
LoginConfirmTicketSerializer
(
serializers
.
ModelSerializer
):
class
LoginConfirmTicketSerializer
(
BulkSerializerMixin
,
serializers
.
ModelSerializer
):
class
Meta
:
class
Meta
:
list_serializer_class
=
AdaptedBulkListSerializer
model
=
LoginConfirmTicket
model
=
LoginConfirmTicket
fields
=
TicketSerializer
.
Meta
.
fields
+
[
fields
=
TicketSerializer
.
Meta
.
fields
+
[
'ip'
,
'city'
,
'action'
'ip'
,
'city'
,
'action'
...
@@ -24,11 +27,14 @@ class LoginConfirmTicketSerializer(serializers.ModelSerializer):
...
@@ -24,11 +27,14 @@ class LoginConfirmTicketSerializer(serializers.ModelSerializer):
def
update
(
self
,
instance
,
validated_data
):
def
update
(
self
,
instance
,
validated_data
):
action
=
validated_data
.
get
(
"action"
)
action
=
validated_data
.
get
(
"action"
)
user
=
self
.
context
[
"request"
]
.
user
user
=
self
.
context
[
"request"
]
.
user
if
action
and
user
not
in
instance
.
assignees
.
all
():
if
action
and
user
not
in
instance
.
assignees
.
all
():
error
=
{
"action"
:
"Only assignees can update"
}
error
=
{
"action"
:
"Only assignees can update"
}
raise
serializers
.
ValidationError
(
error
)
raise
serializers
.
ValidationError
(
error
)
if
instance
.
status
==
instance
.
STATUS_CLOSED
:
validated_data
.
pop
(
'action'
)
instance
=
super
()
.
update
(
instance
,
validated_data
)
instance
=
super
()
.
update
(
instance
,
validated_data
)
if
action
:
if
not
instance
.
status
==
instance
.
STATUS_CLOSED
:
instance
.
perform_action
(
action
,
user
)
instance
.
perform_action
(
action
,
user
)
return
instance
return
instance
...
...
apps/tickets/templates/tickets/login_confirm_ticket_list.html
View file @
9e487483
...
@@ -21,6 +21,19 @@
...
@@ -21,6 +21,19 @@
<tbody>
<tbody>
</tbody>
</tbody>
</table>
</table>
<div
id=
"actions"
class=
"hide"
>
<div
class=
"input-group"
>
<select
class=
"form-control m-b"
style=
"width: auto"
id=
"slct_bulk_update"
>
<option
value=
"approve"
>
{% trans 'Approve selected' %}
</option>
<option
value=
"reject"
>
{% trans 'Reject selected' %}
</option>
</select>
<div
class=
"input-group-btn pull-left"
style=
"padding-left: 5px;"
>
<button
id=
'btn_bulk_update'
style=
"height: 32px;"
class=
"btn btn-sm btn-primary"
>
{% trans 'Submit' %}
</button>
</div>
</div>
</div>
{% include '_filter_dropdown.html' %}
{% include '_filter_dropdown.html' %}
{% endblock %}
{% endblock %}
{% block content_bottom_left %}{% endblock %}
{% block content_bottom_left %}{% endblock %}
...
@@ -38,9 +51,9 @@ function initTable() {
...
@@ -38,9 +51,9 @@ function initTable() {
$
(
td
).
html
(
detailBtn
.
replace
(
"{{ DEFAULT_PK }}"
,
rowData
.
id
));
$
(
td
).
html
(
detailBtn
.
replace
(
"{{ DEFAULT_PK }}"
,
rowData
.
id
));
}},
}},
{
targets
:
3
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
{
targets
:
3
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
if
(
cellData
===
"approv
al
"
)
{
if
(
cellData
===
"approv
e
"
)
{
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
}
else
if
(
cellData
===
"reject
ed
"
)
{
}
else
if
(
cellData
===
"reject"
)
{
$
(
td
).
html
(
'<i class="fa fa-times text-danger"></i>'
)
$
(
td
).
html
(
'<i class="fa fa-times text-danger"></i>'
)
}
else
if
(
cellData
===
"open"
)
{
}
else
if
(
cellData
===
"open"
)
{
$
(
td
).
html
(
'<i class="fa fa-spinner text-info"></i>'
)
$
(
td
).
html
(
'<i class="fa fa-spinner text-info"></i>'
)
...
@@ -70,9 +83,9 @@ function initTable() {
...
@@ -70,9 +83,9 @@ function initTable() {
columns
:
[
columns
:
[
{
data
:
"id"
},
{
data
:
"title"
},
{
data
:
"id"
},
{
data
:
"title"
},
{
data
:
"user_display"
},
{
data
:
"user_display"
},
{
data
:
"
status"
,
ticketable
:
false
},
{
data
:
"
action"
,
width
:
"40px"
},
{
data
:
"date_created"
,
width
:
"120px"
},
{
data
:
"date_created"
,
width
:
"120px"
},
{
data
:
"id"
,
ticket
able
:
false
}
{
data
:
"id"
,
order
able
:
false
}
],
],
op_html
:
$
(
'#actions'
).
html
()
op_html
:
$
(
'#actions'
).
html
()
};
};
...
@@ -85,6 +98,7 @@ $(document).ready(function(){
...
@@ -85,6 +98,7 @@ $(document).ready(function(){
var
menu
=
[
var
menu
=
[
{
title
:
"IP"
,
value
:
"ip"
},
{
title
:
"IP"
,
value
:
"ip"
},
{
title
:
"{% trans 'Title' %}"
,
value
:
"title"
},
{
title
:
"{% trans 'Title' %}"
,
value
:
"title"
},
{
title
:
"{% trans 'User' %}"
,
value
:
"user_display"
},
{
title
:
"{% trans 'Status' %}"
,
value
:
"status"
,
submenu
:
[
{
title
:
"{% trans 'Status' %}"
,
value
:
"status"
,
submenu
:
[
{
title
:
"{% trans 'Open' %}"
,
value
:
"open"
},
{
title
:
"{% trans 'Open' %}"
,
value
:
"open"
},
{
title
:
"{% trans 'Closed' %}"
,
value
:
"closed"
},
{
title
:
"{% trans 'Closed' %}"
,
value
:
"closed"
},
...
@@ -107,6 +121,33 @@ $(document).ready(function(){
...
@@ -107,6 +121,33 @@ $(document).ready(function(){
success
:
reloadPage
success
:
reloadPage
};
};
requestApi
(
data
);
requestApi
(
data
);
}).
on
(
'click'
,
'#btn_bulk_update'
,
function
()
{
var
action
=
$
(
'#slct_bulk_update'
).
val
();
var
idList
=
ticketTable
.
selected
;
if
(
idList
.
length
===
0
)
{
return
false
;
}
var
theUrl
=
"{% url 'api-tickets:login-confirm-ticket-list' %}"
;
function
doAction
(
action
)
{
var
data
=
[];
$
.
each
(
idList
,
function
(
index
,
object_id
)
{
var
obj
=
{
"pk"
:
object_id
,
"action"
:
action
};
data
.
push
(
obj
);
});
requestApi
({
url
:
theUrl
,
method
:
'PATCH'
,
body
:
JSON
.
stringify
(
data
),
success
:
function
(){
$
(
".ipt_check_all"
).
prop
(
"checked"
,
false
)
ticketTable
.
ajax
.
reload
();
}
});
}
doAction
(
action
)
})
})
</script>
</script>
{% endblock %}
{% endblock %}
...
...
apps/tickets/urls/api_urls.py
View file @
9e487483
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#
#
from
django.urls
import
path
from
rest_framework_bulk.routes
import
BulkRouter
from
rest_framework.routers
import
DefaultRouter
from
..
import
api
from
..
import
api
app_name
=
'tickets'
app_name
=
'tickets'
router
=
Default
Router
()
router
=
Bulk
Router
()
router
.
register
(
'tickets'
,
api
.
TicketViewSet
,
'ticket'
)
router
.
register
(
'tickets'
,
api
.
TicketViewSet
,
'ticket'
)
router
.
register
(
'tickets/(?P<ticket_id>[0-9a-zA-Z
\
-]{36})/comments'
,
api
.
TicketCommentViewSet
,
'ticket-comment'
)
router
.
register
(
'tickets/(?P<ticket_id>[0-9a-zA-Z
\
-]{36})/comments'
,
api
.
TicketCommentViewSet
,
'ticket-comment'
)
...
...
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