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
from
common.permissions
import
IsOrgAdmin
from
..models
import
LoginConfirmSetting
from
..serializers
import
LoginConfirmSettingSerializer
from
..
import
errors
from
..
import
errors
,
mixins
__all__
=
[
'LoginConfirmSettingUpdateApi'
,
'LoginConfirmTicketStatusApi'
]
logger
=
get_logger
(
__name__
)
...
...
@@ -31,7 +31,7 @@ class LoginConfirmSettingUpdateApi(UpdateAPIView):
return
s
class
LoginConfirmTicketStatusApi
(
APIView
):
class
LoginConfirmTicketStatusApi
(
mixins
.
AuthMixin
,
APIView
):
permission_classes
=
()
def
get_ticket
(
self
):
...
...
@@ -45,24 +45,9 @@ class LoginConfirmTicketStatusApi(APIView):
return
ticket
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
ticket_id
=
self
.
request
.
session
.
get
(
"auth_ticket_id"
)
ticket
=
self
.
get_ticket
()
try
:
if
not
ticket
:
raise
errors
.
LoginConfirmOtherError
(
ticket_id
,
_
(
"not found"
))
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
()
)
self
.
check_user_login_confirm
()
return
Response
({
"msg"
:
"ok"
})
except
errors
.
NeedMoreInfoError
as
e
:
return
Response
(
e
.
as_data
(),
status
=
200
)
...
...
apps/authentication/api/token.py
View file @
9e487483
...
...
@@ -28,7 +28,7 @@ class TokenCreateApi(AuthMixin, CreateAPIView):
self
.
create_session_if_need
()
# 如果认证没有过,检查账号密码
try
:
user
=
self
.
check_user_auth
()
user
=
self
.
check_user_auth
_if_need
()
self
.
check_user_mfa_if_need
(
user
)
self
.
check_user_login_confirm_if_need
(
user
)
self
.
send_auth_signal
(
success
=
True
,
user
=
user
)
...
...
apps/authentication/mixins.py
View file @
9e487483
# -*- coding: utf-8 -*-
#
import
time
from
django.conf
import
settings
from
common.utils
import
get_object_or_none
,
get_request_ip
,
get_logger
from
users.models
import
User
...
...
@@ -49,8 +50,8 @@ class AuthMixin:
raise
errors
.
BlockLoginError
(
username
=
username
,
ip
=
ip
)
def
check_user_auth
(
self
):
request
=
self
.
request
self
.
check_is_block
()
request
=
self
.
request
if
hasattr
(
request
,
'data'
):
username
=
request
.
data
.
get
(
'username'
,
''
)
password
=
request
.
data
.
get
(
'password'
,
''
)
...
...
@@ -73,11 +74,20 @@ class AuthMixin:
request
.
session
[
'user_id'
]
=
str
(
user
.
id
)
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
):
if
self
.
request
.
session
.
get
(
'auth_mfa'
):
return
True
return
if
not
user
.
otp_enabled
or
not
user
.
otp_secret_key
:
return
True
return
raise
errors
.
MFARequiredError
()
def
check_user_mfa
(
self
,
code
):
...
...
@@ -90,28 +100,53 @@ class AuthMixin:
return
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
confirm_setting
=
user
.
get_login_confirm_setting
()
if
self
.
request
.
session
.
get
(
'auth_confirm'
)
or
not
confirm_setting
:
return
ticket
=
None
if
self
.
request
.
session
.
get
(
'auth_ticket_id'
):
ticket_id
=
self
.
request
.
session
[
'auth_ticket_id'
]
ticket_id
=
self
.
request
.
session
.
get
(
"auth_ticket_id"
)
logger
.
debug
(
'Login confirm ticket id: {}'
.
format
(
ticket_id
))
if
not
ticket_id
:
ticket
=
None
else
:
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
:
ticket
=
confirm_setting
.
create_confirm_ticket
(
self
.
request
)
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
elif
ticket
.
status
==
"rejected"
:
raise
errors
.
LoginConfirmOtherError
(
ticket
.
id
)
elif
ticket
.
action
==
ticket
.
ACTION_REJECT
:
raise
errors
.
LoginConfirmOtherError
(
ticket
.
id
,
ticket
.
get_action_display
()
)
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
):
self
.
request
.
session
[
'auth_password'
]
=
''
self
.
request
.
session
[
'auth_user_id'
]
=
''
self
.
request
.
session
[
'auth_mfa'
]
=
''
self
.
request
.
session
[
'auth_confirm'
]
=
''
self
.
request
.
session
[
'auth_ticket_id'
]
=
''
...
...
apps/authentication/templates/authentication/login_wait_confirm.html
View file @
9e487483
...
...
@@ -43,7 +43,7 @@
</a>
</div>
<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' %}
</a>
</div>
...
...
@@ -132,7 +132,11 @@ $(document).ready(function () {
checkInterval
=
setInterval
(
doRequestAuth
,
5000
);
doRequestAuth
();
initClipboard
();
window
.
onbeforeunload
=
function
(
e
)
{
return
"{% trans "
Confirm
" %}"
;
};
}).
on
(
'click'
,
'.btn-refresh'
,
function
()
{
window
.
onbeforeunload
=
function
()
{};
window
.
location
.
reload
();
})
...
...
apps/authentication/views/login.py
View file @
9e487483
...
...
@@ -19,9 +19,7 @@ from django.conf import settings
from
django.urls
import
reverse_lazy
from
common.utils
import
get_request_ip
,
get_object_or_none
from
users.models
import
User
from
users.utils
import
(
get_user_or_tmp_user
,
increase_login_failed_count
,
redirect_user_first_login_or_index
)
from
..signals
import
post_auth_success
,
post_auth_failed
...
...
@@ -117,42 +115,28 @@ class UserLoginGuardView(mixins.AuthMixin, RedirectView):
return
url
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
)
user
=
self
.
get_user_from_session
()
# 启用并设置了otp
if
user
.
otp_enabled
and
user
.
otp_secret_key
and
\
not
self
.
request
.
session
.
get
(
'auth_mfa'
):
except
errors
.
MFARequiredError
:
return
self
.
format_redirect_url
(
self
.
login_otp_url
)
confirm_setting
=
user
.
get_login_confirm_setting
()
if
confirm_setting
and
not
self
.
request
.
session
.
get
(
'auth_confirm'
):
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
)
except
errors
.
LoginConfirmBaseError
:
return
self
.
format_redirect_url
(
self
.
login_confirm_url
)
else
:
post_auth_failed
.
send
(
sender
=
self
.
__class__
,
username
=
username
,
request
=
self
.
request
,
reason
=
reason
auth_login
(
self
.
request
,
user
)
self
.
send_auth_signal
(
success
=
True
,
user
=
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
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 ""
msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\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"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
...
...
@@ -354,6 +354,7 @@ msgstr "重置"
#: terminal/templates/terminal/command_list.html:47
#: terminal/templates/terminal/session_list.html:52
#: 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/forgot_password.html:42
#: users/templates/users/user_bulk_update.html:24
...
...
@@ -528,7 +529,7 @@ msgstr "创建远程应用"
#: terminal/templates/terminal/session_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:
92
#: tickets/templates/tickets/login_confirm_ticket_list.html:
105
#: users/templates/users/_granted_assets.html:34
#: users/templates/users/user_group_list.html:38
#: users/templates/users/user_list.html:41
...
...
@@ -1480,7 +1481,7 @@ msgid "Asset user auth"
msgstr "资产用户信息"
#: 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"
msgstr "复制成功"
...
...
@@ -1666,6 +1667,7 @@ msgstr "选择节点"
#: assets/templates/assets/system_user_detail.html:182
#: assets/templates/assets/system_user_list.html:135
#: authentication/templates/authentication/_mfa_confirm_modal.html:20
#: authentication/templates/authentication/login_wait_confirm.html:136
#: settings/templates/settings/terminal_setting.html:168
#: templates/_modal.html:23 terminal/templates/terminal/session_detail.html:112
#: users/templates/users/user_detail.html:271
...
...
@@ -2294,7 +2296,7 @@ msgstr "原因"
#: 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:
88
#: tickets/templates/tickets/login_confirm_ticket_list.html:
101
#: tickets/templates/tickets/ticket_detail.html:34
#: xpack/plugins/cloud/models.py:275 xpack/plugins/cloud/models.py:310
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:70
...
...
@@ -2390,10 +2392,6 @@ msgstr "登录日志"
msgid "Command execution log"
msgstr "命令执行"
#: authentication/api/login_confirm.py:52
msgid "not found"
msgstr "没有发现"
#: authentication/backends/api.py:53
msgid "Invalid signature header. No credentials provided."
msgstr ""
...
...
@@ -2703,11 +2701,11 @@ msgstr "返回"
msgid "Welcome back, please enter username and password to login"
msgstr "欢迎回来,请输入用户名和密码登录"
#: authentication/views/login.py:7
3
#: authentication/views/login.py:7
1
msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie"
#: authentication/views/login.py:17
2
#: authentication/views/login.py:17
0
msgid ""
"Wait for <b>{}</b> confirm, You also can copy link to her/him <br/>\n"
" Don't close this page"
...
...
@@ -2715,15 +2713,15 @@ msgstr ""
"等待 <b>{}</b> 确认, 你也可以复制链接发给他/她 <br/>\n"
" 不要关闭本页面"
#: authentication/views/login.py:17
7
#: authentication/views/login.py:17
5
msgid "No ticket found"
msgstr "没有发现工单"
#: authentication/views/login.py:
200
#: authentication/views/login.py:
198
msgid "Logout success"
msgstr "退出登录成功"
#: authentication/views/login.py:
201
#: authentication/views/login.py:
199
msgid "Logout success, return login page"
msgstr "退出登录成功,返回到登录页面"
...
...
@@ -4571,8 +4569,8 @@ msgstr "接受"
#: terminal/templates/terminal/terminal_list.html:80
#: tickets/models/login_confirm.py:16
#: 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:
94
#: tickets/templates/tickets/login_confirm_ticket_list.html:
70
#: tickets/templates/tickets/login_confirm_ticket_list.html:
107
msgid "Reject"
msgstr "拒绝"
...
...
@@ -4610,12 +4608,12 @@ msgid ""
msgstr "你可以使用ssh客户端工具连接终端"
#: 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"
msgstr ""
msgstr "
开启
"
#: 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"
msgstr "关闭"
...
...
@@ -4629,7 +4627,7 @@ msgstr "用户显示名称"
#: tickets/models/base.py:28
#: 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"
msgstr "标题"
...
...
@@ -4659,8 +4657,8 @@ msgstr "{} {} 这个工单"
#: tickets/models/login_confirm.py:15
#: 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:
93
#: tickets/templates/tickets/login_confirm_ticket_list.html:
69
#: tickets/templates/tickets/login_confirm_ticket_list.html:
106
msgid "Approve"
msgstr "同意"
...
...
@@ -4668,6 +4666,14 @@ msgstr "同意"
msgid "this order"
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:81
msgid "ago"
...
...
@@ -6431,6 +6437,12 @@ msgstr "密码匣子"
msgid "vault create"
msgstr "创建"
#~ msgid "selected"
#~ msgstr "所选"
#~ msgid "not found"
#~ msgstr "没有发现"
#~ msgid "Log in frequently and try again later"
#~ msgstr "登录频繁, 稍后重试"
...
...
@@ -6446,9 +6458,6 @@ msgstr "创建"
#~ msgid "Accepted"
#~ msgstr "已接受"
#~ msgid "Rejected"
#~ msgstr "已拒绝"
#~ msgid "New order"
#~ msgstr "新工单"
...
...
apps/static/js/jumpserver.js
View file @
9e487483
...
...
@@ -1319,5 +1319,5 @@ function initDateRangePicker(selector, options) {
}
function
reloadPage
()
{
window
.
location
.
reload
(
);
setTimeout
(
function
()
{
window
.
location
.
reload
();},
300
);
}
apps/tickets/api/login_confirm.py
View file @
9e487483
# -*- coding: utf-8 -*-
#
from
rest_framework
import
viewsets
,
generics
from
rest_framework.serializers
import
ValidationError
from
django.shortcuts
import
get_object_or_404
from
rest_framework_bulk
import
BulkModelViewSet
from
common.permissions
import
IsValidUser
from
common.mixins
import
CommonApiMixin
...
...
@@ -10,21 +8,9 @@ from .. import serializers, mixins
from
..models
import
LoginConfirmTicket
class
LoginConfirmTicketViewSet
(
CommonApiMixin
,
mixins
.
TicketMixin
,
viewsets
.
ModelViewSet
):
class
LoginConfirmTicketViewSet
(
CommonApiMixin
,
mixins
.
TicketMixin
,
Bulk
ModelViewSet
):
serializer_class
=
serializers
.
LoginConfirmTicketSerializer
permission_classes
=
(
IsValidUser
,)
queryset
=
LoginConfirmTicket
.
objects
.
all
()
filter_fields
=
[
'status'
,
'title'
,
'action'
,
'ip'
]
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 @@
#
from
rest_framework
import
serializers
from
common.serializers
import
AdaptedBulkListSerializer
from
common.mixins.serializers
import
BulkSerializerMixin
from
.base
import
TicketSerializer
from
..models
import
LoginConfirmTicket
...
...
@@ -9,8 +11,9 @@ from ..models import LoginConfirmTicket
__all__
=
[
'LoginConfirmTicketSerializer'
,
'LoginConfirmTicketActionSerializer'
]
class
LoginConfirmTicketSerializer
(
serializers
.
ModelSerializer
):
class
LoginConfirmTicketSerializer
(
BulkSerializerMixin
,
serializers
.
ModelSerializer
):
class
Meta
:
list_serializer_class
=
AdaptedBulkListSerializer
model
=
LoginConfirmTicket
fields
=
TicketSerializer
.
Meta
.
fields
+
[
'ip'
,
'city'
,
'action'
...
...
@@ -24,11 +27,14 @@ class LoginConfirmTicketSerializer(serializers.ModelSerializer):
def
update
(
self
,
instance
,
validated_data
):
action
=
validated_data
.
get
(
"action"
)
user
=
self
.
context
[
"request"
]
.
user
if
action
and
user
not
in
instance
.
assignees
.
all
():
error
=
{
"action"
:
"Only assignees can update"
}
raise
serializers
.
ValidationError
(
error
)
if
instance
.
status
==
instance
.
STATUS_CLOSED
:
validated_data
.
pop
(
'action'
)
instance
=
super
()
.
update
(
instance
,
validated_data
)
if
action
:
if
not
instance
.
status
==
instance
.
STATUS_CLOSED
:
instance
.
perform_action
(
action
,
user
)
return
instance
...
...
apps/tickets/templates/tickets/login_confirm_ticket_list.html
View file @
9e487483
...
...
@@ -21,6 +21,19 @@
<tbody>
</tbody>
</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' %}
{% endblock %}
{% block content_bottom_left %}{% endblock %}
...
...
@@ -38,9 +51,9 @@ function initTable() {
$
(
td
).
html
(
detailBtn
.
replace
(
"{{ DEFAULT_PK }}"
,
rowData
.
id
));
}},
{
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>'
)
}
else
if
(
cellData
===
"reject
ed
"
)
{
}
else
if
(
cellData
===
"reject"
)
{
$
(
td
).
html
(
'<i class="fa fa-times text-danger"></i>'
)
}
else
if
(
cellData
===
"open"
)
{
$
(
td
).
html
(
'<i class="fa fa-spinner text-info"></i>'
)
...
...
@@ -70,9 +83,9 @@ function initTable() {
columns
:
[
{
data
:
"id"
},
{
data
:
"title"
},
{
data
:
"user_display"
},
{
data
:
"
status"
,
ticketable
:
false
},
{
data
:
"
action"
,
width
:
"40px"
},
{
data
:
"date_created"
,
width
:
"120px"
},
{
data
:
"id"
,
ticket
able
:
false
}
{
data
:
"id"
,
order
able
:
false
}
],
op_html
:
$
(
'#actions'
).
html
()
};
...
...
@@ -85,6 +98,7 @@ $(document).ready(function(){
var
menu
=
[
{
title
:
"IP"
,
value
:
"ip"
},
{
title
:
"{% trans 'Title' %}"
,
value
:
"title"
},
{
title
:
"{% trans 'User' %}"
,
value
:
"user_display"
},
{
title
:
"{% trans 'Status' %}"
,
value
:
"status"
,
submenu
:
[
{
title
:
"{% trans 'Open' %}"
,
value
:
"open"
},
{
title
:
"{% trans 'Closed' %}"
,
value
:
"closed"
},
...
...
@@ -107,6 +121,33 @@ $(document).ready(function(){
success
:
reloadPage
};
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>
{% endblock %}
...
...
apps/tickets/urls/api_urls.py
View file @
9e487483
# -*- coding: utf-8 -*-
#
from
django.urls
import
path
from
rest_framework.routers
import
DefaultRouter
from
rest_framework_bulk.routes
import
BulkRouter
from
..
import
api
app_name
=
'tickets'
router
=
Default
Router
()
router
=
Bulk
Router
()
router
.
register
(
'tickets'
,
api
.
TicketViewSet
,
'ticket'
)
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