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
f9e41d71
Commit
f9e41d71
authored
Nov 08, 2019
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Update] 修改登录工单
parent
08775551
Hide whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
783 additions
and
598 deletions
+783
-598
login_confirm.py
apps/authentication/api/login_confirm.py
+26
-24
errors.py
apps/authentication/errors.py
+6
-9
mixins.py
apps/authentication/mixins.py
+1
-1
models.py
apps/authentication/models.py
+1
-4
serializers.py
apps/authentication/serializers.py
+6
-5
login_wait_confirm.html
...tication/templates/authentication/login_wait_confirm.html
+1
-1
api_urls.py
apps/authentication/urls/api_urls.py
+1
-1
django.mo
apps/locale/zh/LC_MESSAGES/django.mo
+0
-0
django.po
apps/locale/zh/LC_MESSAGES/django.po
+368
-345
jumpserver.js
apps/static/js/jumpserver.js
+4
-0
_nav.html
apps/templates/_nav.html
+1
-1
base.py
apps/tickets/api/base.py
+26
-9
login_confirm.py
apps/tickets/api/login_confirm.py
+16
-25
apps.py
apps/tickets/apps.py
+4
-0
mixins.py
apps/tickets/mixins.py
+18
-0
base.py
apps/tickets/models/base.py
+16
-8
login_confirm.py
apps/tickets/models/login_confirm.py
+13
-0
permissions.py
apps/tickets/permissions.py
+6
-0
base.py
apps/tickets/serializers/base.py
+17
-0
login_confirm.py
apps/tickets/serializers/login_confirm.py
+16
-1
signals_handler.py
apps/tickets/signals_handler.py
+22
-4
login_confirm_ticket_detail.html
...ickets/templates/tickets/login_confirm_ticket_detail.html
+25
-128
login_confirm_ticket_list.html
.../tickets/templates/tickets/login_confirm_ticket_list.html
+11
-19
ticket_detail.html
apps/tickets/templates/tickets/ticket_detail.html
+162
-0
api_urls.py
apps/tickets/urls/api_urls.py
+1
-5
views.py
apps/tickets/views.py
+6
-7
user.py
apps/users/serializers/user.py
+9
-1
No files found.
apps/authentication/api/login_confirm.py
View file @
f9e41d71
...
...
@@ -4,6 +4,7 @@ from rest_framework.generics import UpdateAPIView
from
rest_framework.response
import
Response
from
rest_framework.views
import
APIView
from
django.shortcuts
import
get_object_or_404
from
django.utils.translation
import
ugettext
as
_
from
common.utils
import
get_logger
,
get_object_or_none
from
common.permissions
import
IsOrgAdmin
...
...
@@ -11,7 +12,7 @@ from ..models import LoginConfirmSetting
from
..serializers
import
LoginConfirmSettingSerializer
from
..
import
errors
__all__
=
[
'LoginConfirmSettingUpdateApi'
,
'
UserTicketAcceptAuth
Api'
]
__all__
=
[
'LoginConfirmSettingUpdateApi'
,
'
LoginConfirmTicketStatus
Api'
]
logger
=
get_logger
(
__name__
)
...
...
@@ -30,10 +31,10 @@ class LoginConfirmSettingUpdateApi(UpdateAPIView):
return
s
class
UserTicketAcceptAuth
Api
(
APIView
):
class
LoginConfirmTicketStatus
Api
(
APIView
):
permission_classes
=
()
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
def
get
_ticket
(
self
):
from
tickets.models
import
LoginConfirmTicket
ticket_id
=
self
.
request
.
session
.
get
(
"auth_ticket_id"
)
logger
.
debug
(
'Login confirm ticket id: {}'
.
format
(
ticket_id
))
...
...
@@ -41,31 +42,32 @@ class UserTicketAcceptAuthApi(APIView):
ticket
=
None
else
:
ticket
=
get_object_or_none
(
LoginConfirmTicket
,
pk
=
ticket_id
)
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
.
LoginConfirmTicketNotFound
(
ticket_id
)
if
ticket
.
action
==
LoginConfirmTicket
.
ACTION_APPROVE
:
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
==
LoginConfirmTicket
.
ACTION_REJECT
:
raise
errors
.
LoginConfirmRejectedError
(
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
()
)
except
errors
.
AuthFailedError
as
e
:
data
=
e
.
as_data
()
return
Response
(
data
,
status
=
400
)
class
UserTicketCancelAuthApi
(
APIView
):
permission_classes
=
()
return
Response
(
e
.
as_data
(),
status
=
400
)
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
from
tickets.models
import
LoginConfirmTicket
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
)
if
not
ticket
:
ticket
.
status
=
"close"
def
delete
(
self
,
request
,
*
args
,
**
kwargs
):
ticket
=
self
.
get_ticket
()
if
ticket
:
ticket
.
perform_status
(
'closed'
,
request
.
user
)
return
Response
(
''
,
status
=
200
)
apps/authentication/errors.py
View file @
f9e41d71
...
...
@@ -48,8 +48,7 @@ mfa_failed_msg = _("MFA code invalid, or ntp sync server time")
mfa_required_msg
=
_
(
"MFA required"
)
login_confirm_required_msg
=
_
(
"Login confirm required"
)
login_confirm_wait_msg
=
_
(
"Wait login confirm ticket for accept"
)
login_confirm_rejected_msg
=
_
(
"Login confirm ticket was rejected"
)
login_confirm_ticket_not_found_msg
=
_
(
"Ticket not found"
)
login_confirm_error_msg
=
_
(
"Login confirm ticket was {}"
)
class
AuthFailedNeedLogMixin
:
...
...
@@ -174,11 +173,9 @@ class LoginConfirmWaitError(LoginConfirmError):
error
=
'login_confirm_wait'
class
LoginConfirmRejectedError
(
LoginConfirmError
):
msg
=
login_confirm_rejected_msg
error
=
'login_confirm_rejected'
class
LoginConfirmOtherError
(
LoginConfirmError
):
error
=
'login_confirm_error'
class
LoginConfirmTicketNotFound
(
LoginConfirmError
):
msg
=
login_confirm_ticket_not_found_msg
error
=
'login_confirm_ticket_not_found'
def
__init__
(
self
,
ticket_id
,
status
):
msg
=
login_confirm_error_msg
.
format
(
status
)
super
()
.
__init__
(
ticket_id
=
ticket_id
,
msg
=
msg
)
apps/authentication/mixins.py
View file @
f9e41d71
...
...
@@ -106,7 +106,7 @@ class AuthMixin:
if
ticket
.
status
==
"accepted"
:
return
elif
ticket
.
status
==
"rejected"
:
raise
errors
.
LoginConfirm
Rejected
Error
(
ticket
.
id
)
raise
errors
.
LoginConfirm
Other
Error
(
ticket
.
id
)
else
:
raise
errors
.
LoginConfirmWaitError
(
ticket
.
id
)
...
...
apps/authentication/models.py
View file @
f9e41d71
...
...
@@ -62,12 +62,9 @@ class LoginConfirmSetting(CommonModelMixin):
remote_addr
=
'127.0.0.1'
body
=
''
reviewer
=
self
.
reviewers
.
all
()
reviewer_names
=
','
.
join
([
u
.
name
for
u
in
reviewer
])
ticket
=
LoginConfirmTicket
.
objects
.
create
(
user
=
self
.
user
,
user_display
=
str
(
self
.
user
),
title
=
title
,
body
=
body
,
user
=
self
.
user
,
title
=
title
,
body
=
body
,
city
=
city
,
ip
=
remote_addr
,
assignees_display
=
reviewer_names
,
type
=
LoginConfirmTicket
.
TYPE_LOGIN_CONFIRM
,
)
ticket
.
assignees
.
set
(
reviewer
)
...
...
apps/authentication/serializers.py
View file @
f9e41d71
# -*- coding: utf-8 -*-
#
from
django.core.cache
import
cache
from
rest_framework
import
serializers
from
common.utils
import
get_object_or_none
from
users.models
import
User
from
users.serializers
import
UserProfileSerializer
from
.models
import
AccessKey
,
LoginConfirmSetting
...
...
@@ -26,14 +26,15 @@ class OtpVerifySerializer(serializers.Serializer):
class
BearerTokenSerializer
(
serializers
.
Serializer
):
username
=
serializers
.
CharField
(
allow_null
=
True
,
required
=
False
)
username
=
serializers
.
CharField
(
allow_null
=
True
,
required
=
False
,
write_only
=
True
)
password
=
serializers
.
CharField
(
write_only
=
True
,
allow_null
=
True
,
required
=
False
)
required
=
False
,
allow_blank
=
True
)
public_key
=
serializers
.
CharField
(
write_only
=
True
,
allow_null
=
True
,
required
=
False
)
allow_blank
=
True
,
required
=
False
)
token
=
serializers
.
CharField
(
read_only
=
True
)
keyword
=
serializers
.
SerializerMethodField
()
date_expired
=
serializers
.
DateTimeField
(
read_only
=
True
)
user
=
UserProfileSerializer
(
read_only
=
True
)
@staticmethod
def
get_keyword
(
obj
):
...
...
@@ -52,9 +53,9 @@ class BearerTokenSerializer(serializers.Serializer):
)
token
,
date_expired
=
user
.
create_bearer_token
(
request
)
instance
=
{
"username"
:
user
.
username
,
"token"
:
token
,
"date_expired"
:
date_expired
,
"user"
:
user
}
return
instance
...
...
apps/authentication/templates/authentication/login_wait_confirm.html
View file @
f9e41d71
...
...
@@ -73,7 +73,7 @@ var infoMsgRef = $(".info-messages");
var
timestamp
=
'{{ timestamp }}'
;
var
progressBarRef
=
$
(
".progress-bar"
);
var
interval
,
checkInterval
;
var
url
=
"{% url 'api-auth:
user-order-auth
' %}"
;
var
url
=
"{% url 'api-auth:
login-confirm-ticket-status
' %}"
;
var
successUrl
=
"{% url 'authentication:login-guard' %}"
;
function
doRequestAuth
()
{
...
...
apps/authentication/urls/api_urls.py
View file @
f9e41d71
...
...
@@ -18,7 +18,7 @@ urlpatterns = [
path
(
'connection-token/'
,
api
.
UserConnectionTokenApi
.
as_view
(),
name
=
'connection-token'
),
path
(
'otp/verify/'
,
api
.
UserOtpVerifyApi
.
as_view
(),
name
=
'user-otp-verify'
),
path
(
'
order/auth/'
,
api
.
UserTicketAcceptAuthApi
.
as_view
(),
name
=
'user-order-auth
'
),
path
(
'
login-confirm-ticket/status/'
,
api
.
LoginConfirmTicketStatusApi
.
as_view
(),
name
=
'login-confirm-ticket-status
'
),
path
(
'login-confirm-settings/<uuid:user_id>/'
,
api
.
LoginConfirmSettingUpdateApi
.
as_view
(),
name
=
'login-confirm-setting-update'
)
]
...
...
apps/locale/zh/LC_MESSAGES/django.mo
View file @
f9e41d71
No preview for this file type
apps/locale/zh/LC_MESSAGES/django.po
View file @
f9e41d71
...
...
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-11-0
5 15:00
+0800\n"
"POT-Creation-Date: 2019-11-0
8 15:42
+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"
...
...
@@ -96,7 +96,7 @@ msgstr "运行参数"
#: terminal/templates/terminal/session_list.html:28
#: terminal/templates/terminal/session_list.html:72
#: xpack/plugins/change_auth_plan/forms.py:73
#: xpack/plugins/change_auth_plan/models.py:41
9
#: xpack/plugins/change_auth_plan/models.py:41
2
#: 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_subtask_list.html:13
...
...
@@ -152,7 +152,7 @@ msgstr "资产"
#: users/templates/users/user_profile.html:51
#: users/templates/users/user_pubkey_update.html:57
#: xpack/plugins/change_auth_plan/forms.py:56
#: xpack/plugins/change_auth_plan/models.py:6
4
#: xpack/plugins/change_auth_plan/models.py:6
3
#: 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/cloud/models.py:59 xpack/plugins/cloud/models.py:144
...
...
@@ -199,7 +199,7 @@ msgstr "参数"
#: perms/templates/perms/remote_app_permission_detail.html:90
#: users/models/user.py:423 users/serializers/group.py:32
#: users/templates/users/user_detail.html:112
#: xpack/plugins/change_auth_plan/models.py:10
9
#: xpack/plugins/change_auth_plan/models.py:10
8
#: 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/gathered_user/models.py:46
...
...
@@ -219,11 +219,11 @@ msgstr "创建者"
#: assets/templates/assets/system_user_detail.html:96
#: common/mixins/models.py:51 ops/models/adhoc.py:45
#: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:64
#: orders/templates/orders/login_confirm_order_detail.html:60 orgs/models.py:17
#: perms/models/base.py:55
#: orgs/models.py:17 perms/models/base.py:55
#: perms/templates/perms/asset_permission_detail.html:94
#: perms/templates/perms/remote_app_permission_detail.html:86
#: terminal/templates/terminal/terminal_detail.html:59 users/models/group.py:17
#: terminal/templates/terminal/terminal_detail.html:59
#: tickets/templates/tickets/ticket_detail.html:52 users/models/group.py:17
#: users/templates/users/user_group_detail.html:63
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:105
#: xpack/plugins/cloud/models.py:83 xpack/plugins/cloud/models.py:182
...
...
@@ -254,18 +254,17 @@ msgstr "创建日期"
#: assets/templates/assets/domain_list.html:28
#: assets/templates/assets/system_user_detail.html:104
#: assets/templates/assets/system_user_list.html:55 ops/models/adhoc.py:43
#: orders/serializers.py:23
#: orders/templates/orders/login_confirm_order_detail.html:96 orgs/models.py:18
#: perms/models/base.py:56
#: orgs/models.py:18 perms/models/base.py:56
#: perms/templates/perms/asset_permission_detail.html:102
#: perms/templates/perms/remote_app_permission_detail.html:94
#: settings/models.py:34 terminal/models.py:33
#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15
#: terminal/templates/terminal/terminal_detail.html:63
#: tickets/templates/tickets/ticket_detail.html:106 users/models/group.py:15
#: users/models/user.py:415 users/templates/users/user_detail.html:130
#: users/templates/users/user_group_detail.html:67
#: users/templates/users/user_group_list.html:37
#: users/templates/users/user_profile.html:138
#: xpack/plugins/change_auth_plan/models.py:10
5
#: xpack/plugins/change_auth_plan/models.py:10
4
#: 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/cloud/models.py:77 xpack/plugins/cloud/models.py:173
...
...
@@ -311,7 +310,7 @@ msgstr "远程应用"
#: settings/templates/settings/security_setting.html:73
#: settings/templates/settings/terminal_setting.html:71
#: terminal/templates/terminal/terminal_update.html:45
#: users/templates/users/_user.html:5
0
#: users/templates/users/_user.html:5
1
#: users/templates/users/user_bulk_update.html:23
#: users/templates/users/user_detail.html:179
#: users/templates/users/user_group_create_update.html:31
...
...
@@ -355,7 +354,7 @@ msgstr "重置"
#: terminal/templates/terminal/command_list.html:47
#: terminal/templates/terminal/session_list.html:52
#: terminal/templates/terminal/terminal_update.html:46
#: users/templates/users/_user.html:5
1
#: users/templates/users/_user.html:5
2
#: users/templates/users/forgot_password.html:42
#: users/templates/users/user_bulk_update.html:24
#: users/templates/users/user_list.html:57
...
...
@@ -519,7 +518,6 @@ msgstr "创建远程应用"
#: authentication/templates/authentication/_access_key_modal.html:34
#: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:64
#: ops/templates/ops/task_history.html:65 ops/templates/ops/task_list.html:18
#: orders/templates/orders/login_confirm_order_list.html:19
#: perms/forms/asset_permission.py:21
#: perms/templates/perms/asset_permission_create_update.html:50
#: perms/templates/perms/asset_permission_list.html:56
...
...
@@ -529,6 +527,8 @@ msgstr "创建远程应用"
#: settings/templates/settings/terminal_setting.html:107
#: 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
#: users/templates/users/_granted_assets.html:34
#: users/templates/users/user_group_list.html:38
#: users/templates/users/user_list.html:41
...
...
@@ -606,7 +606,7 @@ msgstr "端口"
#: assets/templates/assets/asset_detail.html:196
#: assets/templates/assets/system_user_assets.html:83
#: perms/models/asset_permission.py:81
#: xpack/plugins/change_auth_plan/models.py:7
5
#: xpack/plugins/change_auth_plan/models.py:7
4
#: xpack/plugins/gathered_user/models.py:31
#: xpack/plugins/gathered_user/templates/gathered_user/task_list.html:17
msgid "Nodes"
...
...
@@ -700,21 +700,21 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC"
#: assets/templates/assets/admin_user_list.html:45
#: assets/templates/assets/domain_gateway_list.html:71
#: assets/templates/assets/system_user_detail.html:62
#: assets/templates/assets/system_user_list.html:48 audits/models.py:8
2
#: assets/templates/assets/system_user_list.html:48 audits/models.py:8
1
#: audits/templates/audits/login_log_list.html:57 authentication/forms.py:13
#: authentication/templates/authentication/login.html:
60
#: authentication/templates/authentication/xpack_login.html:
87
#: authentication/templates/authentication/login.html:
58
#: authentication/templates/authentication/xpack_login.html:
91
#: ops/models/adhoc.py:189 perms/templates/perms/asset_permission_list.html:70
#: perms/templates/perms/asset_permission_user.html:55
#: perms/templates/perms/remote_app_permission_user.html:54
#: settings/templates/settings/_ldap_list_users_modal.html:30 users/forms.py:1
3
#: settings/templates/settings/_ldap_list_users_modal.html:30 users/forms.py:1
4
#: users/models/user.py:380 users/templates/users/_select_user_modal.html:14
#: users/templates/users/user_detail.html:68
#: users/templates/users/user_list.html:36
#: users/templates/users/user_profile.html:47
#: xpack/plugins/change_auth_plan/forms.py:58
#: xpack/plugins/change_auth_plan/models.py:6
6
#: xpack/plugins/change_auth_plan/models.py:4
15
#: xpack/plugins/change_auth_plan/models.py:6
5
#: xpack/plugins/change_auth_plan/models.py:4
08
#: 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_subtask_list.html:12
...
...
@@ -732,17 +732,17 @@ msgstr "密码或密钥密码"
#: assets/templates/assets/_asset_user_auth_update_modal.html:21
#: assets/templates/assets/_asset_user_auth_view_modal.html:27
#: authentication/forms.py:15
#: authentication/templates/authentication/login.html:6
3
#: authentication/templates/authentication/xpack_login.html:9
0
#: settings/forms.py:114 users/forms.py:1
5 users/forms.py:27
#: authentication/templates/authentication/login.html:6
6
#: authentication/templates/authentication/xpack_login.html:9
9
#: settings/forms.py:114 users/forms.py:1
6 users/forms.py:42
#: users/templates/users/reset_password.html:53
#: users/templates/users/user_password_authentication.html:18
#: users/templates/users/user_password_update.html:44
#: users/templates/users/user_profile_update.html:41
#: users/templates/users/user_pubkey_update.html:41
#: users/templates/users/user_update.html:20
#: xpack/plugins/change_auth_plan/models.py:9
6
#: xpack/plugins/change_auth_plan/models.py:26
4
#: xpack/plugins/change_auth_plan/models.py:9
5
#: xpack/plugins/change_auth_plan/models.py:26
3
msgid "Password"
msgstr "密码"
...
...
@@ -797,8 +797,6 @@ msgstr "使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig"
#: assets/templates/assets/domain_gateway_list.html:68
#: assets/templates/assets/user_asset_list.html:76
#: audits/templates/audits/login_log_list.html:60
#: orders/templates/orders/login_confirm_order_detail.html:33
#: orders/templates/orders/login_confirm_order_list.html:16
#: perms/templates/perms/asset_permission_asset.html:58 settings/forms.py:144
#: users/templates/users/_granted_assets.html:31
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:54
...
...
@@ -938,13 +936,13 @@ msgstr "版本"
msgid "AuthBook"
msgstr ""
#: assets/models/base.py:31 xpack/plugins/change_auth_plan/models.py:
100
#: xpack/plugins/change_auth_plan/models.py:27
1
#: assets/models/base.py:31 xpack/plugins/change_auth_plan/models.py:
99
#: xpack/plugins/change_auth_plan/models.py:27
0
msgid "SSH private key"
msgstr "ssh密钥"
#: assets/models/base.py:32 xpack/plugins/change_auth_plan/models.py:10
3
#: xpack/plugins/change_auth_plan/models.py:26
7
#: assets/models/base.py:32 xpack/plugins/change_auth_plan/models.py:10
2
#: xpack/plugins/change_auth_plan/models.py:26
6
msgid "SSH public key"
msgstr "ssh公钥"
...
...
@@ -1041,12 +1039,13 @@ msgstr "过滤器"
#: assets/models/cmd_filter.py:51
#: assets/templates/assets/cmd_filter_rule_list.html:58
#: audits/templates/audits/login_log_list.html:58
orders/models.py:41
#: audits/templates/audits/login_log_list.html:58
#: perms/templates/perms/remote_app_permission_remote_app.html:54
#: settings/templates/settings/command_storage_create.html:31
#: settings/templates/settings/replay_storage_create.html:31
#: settings/templates/settings/terminal_setting.html:84
#: settings/templates/settings/terminal_setting.html:106
#: tickets/models/base.py:34 tickets/templates/tickets/ticket_detail.html:33
msgid "Type"
msgstr "类型"
...
...
@@ -1105,10 +1104,7 @@ msgstr "默认资产组"
#: audits/templates/audits/password_change_log_list.html:39
#: audits/templates/audits/password_change_log_list.html:56
#: authentication/models.py:43 ops/templates/ops/command_execution_list.html:38
#: ops/templates/ops/command_execution_list.html:63 orders/models.py:11
#: orders/models.py:32
#: orders/templates/orders/login_confirm_order_detail.html:32
#: orders/templates/orders/login_confirm_order_list.html:15
#: ops/templates/ops/command_execution_list.html:63
#: perms/forms/asset_permission.py:78 perms/forms/remote_app_permission.py:34
#: perms/models/base.py:49
#: perms/templates/perms/asset_permission_create_update.html:41
...
...
@@ -1120,7 +1116,10 @@ msgstr "默认资产组"
#: terminal/models.py:156 terminal/templates/terminal/command_list.html:29
#: terminal/templates/terminal/command_list.html:65
#: terminal/templates/terminal/session_list.html:27
#: terminal/templates/terminal/session_list.html:71 users/forms.py:319
#: terminal/templates/terminal/session_list.html:71 tickets/models/base.py:25
#: tickets/models/base.py:68
#: tickets/templates/tickets/login_confirm_ticket_list.html:15
#: tickets/templates/tickets/ticket_detail.html:32 users/forms.py:339
#: users/models/user.py:132 users/models/user.py:148 users/models/user.py:509
#: users/serializers/group.py:21
#: users/templates/users/user_group_detail.html:78
...
...
@@ -1187,7 +1186,7 @@ msgstr "手动登录"
#: 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:63 assets/views/system_user.py:79
#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models.py:7
1
#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models.py:7
0
msgid "Assets"
msgstr "资产管理"
...
...
@@ -1245,7 +1244,7 @@ msgstr "不可达"
msgid "Reachable"
msgstr "可连接"
#: assets/models/utils.py:45 assets/tasks/const.py:89 audits/utils.py:
29
#: assets/models/utils.py:45 assets/tasks/const.py:89 audits/utils.py:
30
#: xpack/plugins/license/models.py:78
msgid "Unknown"
msgstr "未知"
...
...
@@ -1276,7 +1275,7 @@ msgstr "组织名称"
msgid "Backend"
msgstr "后端"
#: assets/serializers/asset_user.py:67 users/forms.py:2
6
2
#: assets/serializers/asset_user.py:67 users/forms.py:2
8
2
#: users/models/user.py:412 users/templates/users/first_login.html:42
#: users/templates/users/user_password_update.html:49
#: users/templates/users/user_profile.html:69
...
...
@@ -1332,7 +1331,7 @@ msgstr "测试资产可连接性: {}"
#: assets/tasks/asset_user_connectivity.py:27
#: assets/tasks/push_system_user.py:130
#: xpack/plugins/change_auth_plan/models.py:52
8
#: xpack/plugins/change_auth_plan/models.py:52
1
msgid "The asset {} system platform {} does not support run Ansible tasks"
msgstr "资产 {} 系统平台 {} 不支持运行 Ansible 任务"
...
...
@@ -1447,7 +1446,7 @@ msgid "Asset list"
msgstr "资产列表"
#: assets/templates/assets/_asset_list_modal.html:33
#: assets/templates/assets/_node_tree.html:
40
#: assets/templates/assets/_node_tree.html:
39
#: ops/templates/ops/command_execution_create.html:70
#: ops/templates/ops/command_execution_create.html:127
#: users/templates/users/_granted_assets.html:7
...
...
@@ -1494,7 +1493,8 @@ msgstr "获取认证信息错误"
#: authentication/templates/authentication/_access_key_modal.html:142
#: authentication/templates/authentication/_mfa_confirm_modal.html:53
#: settings/templates/settings/_ldap_list_users_modal.html:92
#: templates/_modal.html:22
#: templates/_modal.html:22 tickets/models/base.py:50
#: tickets/templates/tickets/ticket_detail.html:103
msgid "Close"
msgstr "关闭"
...
...
@@ -1502,9 +1502,9 @@ msgstr "关闭"
#: audits/templates/audits/operate_log_list.html:77
#: audits/templates/audits/password_change_log_list.html:59
#: ops/templates/ops/task_adhoc.html:63
#: orders/templates/orders/login_confirm_order_list.html:18
#: terminal/templates/terminal/command_list.html:33
#: terminal/templates/terminal/session_detail.html:50
#: tickets/templates/tickets/login_confirm_ticket_list.html:17
msgid "Datetime"
msgstr "日期"
...
...
@@ -1544,31 +1544,31 @@ msgstr "SSH端口"
msgid "If use nat, set the ssh real port"
msgstr "如果使用了nat端口映射,请设置为ssh真实监听的端口"
#: assets/templates/assets/_node_tree.html:
50
#: assets/templates/assets/_node_tree.html:
49
msgid "Add node"
msgstr "新建节点"
#: assets/templates/assets/_node_tree.html:5
1
#: assets/templates/assets/_node_tree.html:5
0
msgid "Rename node"
msgstr "重命名节点"
#: assets/templates/assets/_node_tree.html:5
2
#: assets/templates/assets/_node_tree.html:5
1
msgid "Delete node"
msgstr "删除节点"
#: assets/templates/assets/_node_tree.html:16
6
#: assets/templates/assets/_node_tree.html:16
5
msgid "Create node failed"
msgstr "创建节点失败"
#: assets/templates/assets/_node_tree.html:17
8
#: assets/templates/assets/_node_tree.html:17
7
msgid "Have child node, cancel"
msgstr "存在子节点,不能删除"
#: assets/templates/assets/_node_tree.html:1
80
#: assets/templates/assets/_node_tree.html:1
79
msgid "Have assets, cancel"
msgstr "存在资产,不能删除"
#: assets/templates/assets/_node_tree.html:25
5
#: assets/templates/assets/_node_tree.html:25
4
msgid "Rename success"
msgstr "重命名成功"
...
...
@@ -2214,7 +2214,7 @@ msgstr "操作"
msgid "Filename"
msgstr "文件名"
#: audits/models.py:24 audits/models.py:7
8
#: audits/models.py:24 audits/models.py:7
7
#: audits/templates/audits/ftp_log_list.html:79
#: ops/templates/ops/command_execution_list.html:68
#: ops/templates/ops/task_list.html:15
...
...
@@ -2256,53 +2256,53 @@ msgstr "启用"
msgid "-"
msgstr ""
#: audits/models.py:7
9
xpack/plugins/cloud/models.py:264
#: audits/models.py:7
8
xpack/plugins/cloud/models.py:264
#: xpack/plugins/cloud/models.py:287
msgid "Failed"
msgstr "失败"
#: audits/models.py:8
3
#: audits/models.py:8
2
msgid "Login type"
msgstr "登录方式"
#: audits/models.py:8
4
#: audits/models.py:8
3
msgid "Login ip"
msgstr "登录IP"
#: audits/models.py:8
5
#: audits/models.py:8
4
msgid "Login city"
msgstr "登录城市"
#: audits/models.py:8
6
#: audits/models.py:8
5
msgid "User agent"
msgstr "Agent"
#: audits/models.py:8
7
audits/templates/audits/login_log_list.html:62
#: audits/models.py:8
6
audits/templates/audits/login_log_list.html:62
#: authentication/templates/authentication/_mfa_confirm_modal.html:14
#: users/forms.py:1
7
4 users/models/user.py:404
#: users/forms.py:1
9
4 users/models/user.py:404
#: users/templates/users/first_login.html:45
msgid "MFA"
msgstr "MFA"
#: audits/models.py:8
8
audits/templates/audits/login_log_list.html:63
#: xpack/plugins/change_auth_plan/models.py:4
23
#: audits/models.py:8
7
audits/templates/audits/login_log_list.html:63
#: xpack/plugins/change_auth_plan/models.py:4
16
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:15
#: xpack/plugins/cloud/models.py:278
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:69
msgid "Reason"
msgstr "原因"
#: audits/models.py:8
9
audits/templates/audits/login_log_list.html:64
#:
orders/templates/orders/login_confirm_order_detail.html:35
#:
orders/templates/orders/login_confirm_order_list.html:17
#:
orders/templates/orders/login_confirm_order_list.html:91
#: audits/models.py:8
8
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/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
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:65
msgid "Status"
msgstr "状态"
#: audits/models.py:
90
#: audits/models.py:
89
msgid "Date login"
msgstr "登录日期"
...
...
@@ -2314,8 +2314,8 @@ msgstr "登录日期"
#: perms/templates/perms/asset_permission_detail.html:86
#: perms/templates/perms/remote_app_permission_detail.html:78
#: terminal/models.py:167 terminal/templates/terminal/session_list.html:34
#: xpack/plugins/change_auth_plan/models.py:2
50
#: xpack/plugins/change_auth_plan/models.py:4
26
#: xpack/plugins/change_auth_plan/models.py:2
49
#: xpack/plugins/change_auth_plan/models.py:4
19
#: 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/gathered_user/models.py:143
...
...
@@ -2356,7 +2356,6 @@ msgid "UA"
msgstr "Agent"
#: audits/templates/audits/login_log_list.html:61
#: orders/templates/orders/login_confirm_order_detail.html:58
msgid "City"
msgstr "城市"
...
...
@@ -2391,21 +2390,9 @@ msgstr "登录日志"
msgid "Command execution log"
msgstr "命令执行"
#: authentication/api/auth.py:58
msgid "Log in frequently and try again later"
msgstr "登录频繁, 稍后重试"
#: authentication/api/auth.py:83
msgid "Please carry seed value and conduct MFA secondary certification"
msgstr "请携带seed值, 进行MFA二次认证"
#: authentication/api/auth.py:173
msgid "Please verify the user name and password first"
msgstr "请先进行用户名和密码验证"
#: authentication/api/auth.py:178
msgid "MFA certification failed"
msgstr "MFA认证失败"
#: authentication/api/login_confirm.py:52
msgid "not found"
msgstr "没有发现"
#: authentication/backends/api.py:53
msgid "Invalid signature header. No credentials provided."
...
...
@@ -2482,11 +2469,11 @@ msgstr "禁用或失效"
msgid "This account is inactive."
msgstr "此账户已禁用"
#: authentication/errors.py:
28
#: authentication/errors.py:
35
msgid "No session found, check your cookie"
msgstr "会话已变更,刷新页面"
#: authentication/errors.py:3
0
#: authentication/errors.py:3
7
#, python-brace-format
msgid ""
"The username or password you entered is incorrect, please enter it again. "
...
...
@@ -2496,37 +2483,33 @@ msgstr ""
"您输入的用户名或密码不正确,请重新输入。 您还可以尝试 {times_try} 次(账号将"
"被临时 锁定 {block_time} 分钟)"
#: authentication/errors.py:
36
#: authentication/errors.py:
43
msgid ""
"The account has been locked (please contact admin to unlock it or try again "
"after {} minutes)"
msgstr "账号已被锁定(请联系管理员解锁 或 {}分钟后重试)"
#: authentication/errors.py:
39
users/views/user.py:393 users/views/user.py:418
#: authentication/errors.py:
46
users/views/user.py:393 users/views/user.py:418
msgid "MFA code invalid, or ntp sync server time"
msgstr "MFA验证码不正确,或者服务器端时间不对"
#: authentication/errors.py:4
1
#: authentication/errors.py:4
8
msgid "MFA required"
msgstr ""
#: authentication/errors.py:4
2
#: authentication/errors.py:4
9
msgid "Login confirm required"
msgstr "需要登录复核"
#: authentication/errors.py:
43
msgid "Wait login confirm
order
for accept"
#: authentication/errors.py:
50
msgid "Wait login confirm
ticket
for accept"
msgstr "等待登录复核处理"
#: authentication/errors.py:
44
msgid "Login confirm
order was rejected
"
msgstr "登录
已被拒绝
"
#: authentication/errors.py:
51
msgid "Login confirm
ticket was {}
"
msgstr "登录
复核 {}
"
#: authentication/errors.py:45
msgid "Order not found"
msgstr "没有发现工单"
#: authentication/forms.py:32 users/forms.py:21
#: authentication/forms.py:32 users/forms.py:22
msgid "MFA code"
msgstr "MFA 验证码"
...
...
@@ -2643,30 +2626,30 @@ msgstr ""
msgid "Changes the world, starting with a little bit."
msgstr "改变世界,从一点点开始。"
#: authentication/templates/authentication/login.html:4
6
#: authentication/templates/authentication/login.html:
68
#: authentication/templates/authentication/xpack_login.html:
96
#: authentication/templates/authentication/login.html:4
5
#: authentication/templates/authentication/login.html:
76
#: authentication/templates/authentication/xpack_login.html:
110
#: templates/_header_bar.html:83
msgid "Login"
msgstr "登录"
#: authentication/templates/authentication/login.html:5
2
#: authentication/templates/authentication/xpack_login.html:
78
#: authentication/templates/authentication/login.html:5
4
#: authentication/templates/authentication/xpack_login.html:
87
msgid "Captcha invalid"
msgstr "验证码错误"
#: authentication/templates/authentication/login.html:
79
#: authentication/templates/authentication/xpack_login.html:1
00
#: authentication/templates/authentication/login.html:
87
#: authentication/templates/authentication/xpack_login.html:1
14
#: users/templates/users/forgot_password.html:10
#: users/templates/users/forgot_password.html:25
msgid "Forgot password"
msgstr "忘记密码"
#: authentication/templates/authentication/login.html:
86
#: authentication/templates/authentication/login.html:
94
msgid "More login options"
msgstr "更多登录方式"
#: authentication/templates/authentication/login.html:9
0
#: authentication/templates/authentication/login.html:9
8
msgid "Keycloak"
msgstr ""
...
...
@@ -2716,15 +2699,15 @@ msgstr "复制链接"
msgid "Return"
msgstr "返回"
#: authentication/templates/authentication/xpack_login.html:
67
#: authentication/templates/authentication/xpack_login.html:
74
msgid "Welcome back, please enter username and password to login"
msgstr "欢迎回来,请输入用户名和密码登录"
#: authentication/views/login.py:
80
#: authentication/views/login.py:
73
msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie"
#: authentication/views/login.py:1
9
2
#: authentication/views/login.py:1
7
2
msgid ""
"Wait for <b>{}</b> confirm, You also can copy link to her/him <br/>\n"
" Don't close this page"
...
...
@@ -2732,15 +2715,15 @@ msgstr ""
"等待 <b>{}</b> 确认, 你也可以复制链接发给他/她 <br/>\n"
" 不要关闭本页面"
#: authentication/views/login.py:1
9
7
msgid "No
order
found"
#: authentication/views/login.py:1
7
7
msgid "No
ticket
found"
msgstr "没有发现工单"
#: authentication/views/login.py:2
2
0
#: authentication/views/login.py:2
0
0
msgid "Logout success"
msgstr "退出登录成功"
#: authentication/views/login.py:2
2
1
#: authentication/views/login.py:2
0
1
msgid "Logout success, return login page"
msgstr "退出登录成功,返回到登录页面"
...
...
@@ -2906,49 +2889,49 @@ msgstr "Become"
msgid "Create by"
msgstr "创建者"
#: ops/models/adhoc.py:25
1
#: ops/models/adhoc.py:25
2
msgid "{} Start task: {}"
msgstr "{} 任务开始: {}"
#: ops/models/adhoc.py:26
3
#: ops/models/adhoc.py:26
4
msgid "{} Task finish"
msgstr "{} 任务结束"
#: ops/models/adhoc.py:35
5
#: ops/models/adhoc.py:35
6
msgid "Start time"
msgstr "开始时间"
#: ops/models/adhoc.py:35
6
#: ops/models/adhoc.py:35
7
msgid "End time"
msgstr "完成时间"
#: ops/models/adhoc.py:35
7
ops/templates/ops/adhoc_history.html:57
#: ops/models/adhoc.py:35
8
ops/templates/ops/adhoc_history.html:57
#: ops/templates/ops/task_history.html:63 ops/templates/ops/task_list.html:17
#: xpack/plugins/change_auth_plan/models.py:25
3
#: xpack/plugins/change_auth_plan/models.py:42
9
#: xpack/plugins/change_auth_plan/models.py:25
2
#: xpack/plugins/change_auth_plan/models.py:42
2
#: 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/gathered_user/models.py:146
msgid "Time"
msgstr "时间"
#: ops/models/adhoc.py:35
8
ops/templates/ops/adhoc_detail.html:106
#: ops/models/adhoc.py:35
9
ops/templates/ops/adhoc_detail.html:106
#: ops/templates/ops/adhoc_history.html:55
#: ops/templates/ops/adhoc_history_detail.html:69
#: ops/templates/ops/task_detail.html:84 ops/templates/ops/task_history.html:61
msgid "Is finished"
msgstr "是否完成"
#: ops/models/adhoc.py:3
59
ops/templates/ops/adhoc_history.html:56
#: ops/models/adhoc.py:3
60
ops/templates/ops/adhoc_history.html:56
#: ops/templates/ops/task_history.html:62
msgid "Is success"
msgstr "是否成功"
#: ops/models/adhoc.py:36
0
#: ops/models/adhoc.py:36
1
msgid "Adhoc raw result"
msgstr "结果"
#: ops/models/adhoc.py:36
1
#: ops/models/adhoc.py:36
2
msgid "Adhoc result summary"
msgstr "汇总"
...
...
@@ -3108,8 +3091,7 @@ msgstr "没有输入命令"
msgid "No system user was selected"
msgstr "没有选择系统用户"
#: ops/templates/ops/command_execution_create.html:296 orders/models.py:26
#: orders/templates/orders/login_confirm_order_list.html:92
#: ops/templates/ops/command_execution_create.html:296
msgid "Pending"
msgstr "等待"
...
...
@@ -3193,159 +3175,6 @@ msgstr "命令执行列表"
msgid "Command execution"
msgstr "命令执行"
#: orders/models.py:12 orders/models.py:33
msgid "User display name"
msgstr "用户显示名称"
#: orders/models.py:13 orders/models.py:36
msgid "Body"
msgstr "内容"
#: orders/models.py:24 orders/templates/orders/login_confirm_order_list.html:93
msgid "Accepted"
msgstr "已接受"
#: orders/models.py:25 orders/templates/orders/login_confirm_order_list.html:94
msgid "Rejected"
msgstr "已拒绝"
#: orders/models.py:35 orders/templates/orders/login_confirm_order_list.html:14
#: orders/templates/orders/login_confirm_order_list.html:90
msgid "Title"
msgstr "标题"
#: orders/models.py:37
#: orders/templates/orders/login_confirm_order_detail.html:59
msgid "Assignee"
msgstr "处理人"
#: orders/models.py:38
msgid "Assignee display name"
msgstr "处理人名称"
#: orders/models.py:39
#: orders/templates/orders/login_confirm_order_detail.html:34
msgid "Assignees"
msgstr "待处理人"
#: orders/models.py:40
msgid "Assignees display name"
msgstr "待处理人名称"
#: orders/serializers.py:21
#: orders/templates/orders/login_confirm_order_detail.html:94
#: orders/templates/orders/login_confirm_order_list.html:59
#: terminal/templates/terminal/terminal_list.html:78
msgid "Accept"
msgstr "接受"
#: orders/serializers.py:22
#: orders/templates/orders/login_confirm_order_detail.html:95
#: orders/templates/orders/login_confirm_order_list.html:60
#: terminal/templates/terminal/terminal_list.html:80
msgid "Reject"
msgstr "拒绝"
#: orders/serializers.py:43
msgid "this order"
msgstr "这个工单"
#: orders/templates/orders/login_confirm_order_detail.html:75
msgid "ago"
msgstr "前"
#: orders/utils.py:18
msgid "New order"
msgstr "新工单"
#: orders/utils.py:21
#, python-brace-format
msgid ""
"\n"
" <div>\n"
" <p>Your has a new order</p>\n"
" <div>\n"
" <b>Title:</b> {order.title}\n"
" <br/>\n"
" <b>User:</b> {user}\n"
" <br/>\n"
" <b>Assignees:</b> {order.assignees_display}\n"
" <br/>\n"
" <b>City:</b> {order.city}\n"
" <br/>\n"
" <b>IP:</b> {order.ip}\n"
" <br/>\n"
" <a href={url}>click here to review</a> \n"
" </div>\n"
" </div>\n"
" "
msgstr ""
"\n"
" <div>\n"
" <p>您有一个新工单</p>\n"
" <div>\n"
" <b>标题:</b> {order.title}\n"
" <br/>\n"
" <b>用户:</b> {user}\n"
" <br/>\n"
" <b>待处理人:</b> {order.assignees_display}\n"
" <br/>\n"
" <b>城市:</b> {order.city}\n"
" <br/>\n"
" <b>IP:</b> {order.ip}\n"
" <br/>\n"
" <a href={url}>点我查看</a> \n"
" </div>\n"
" </div>\n"
" "
#: orders/utils.py:48
msgid "Order has been reply"
msgstr "工单已被回复"
#: orders/utils.py:49
#, python-brace-format
msgid ""
"\n"
" <div>\n"
" <p>Your order has been replay</p>\n"
" <div>\n"
" <b>Title:</b> {order.title}\n"
" <br/>\n"
" <b>Assignee:</b> {order.assignee_display}\n"
" <br/>\n"
" <b>Status:</b> {order.status_display}\n"
" <br/>\n"
" </div>\n"
" </div>\n"
" "
msgstr ""
"\n"
" <div>\n"
" <p>您的工单已被回复</p>\n"
" <div>\n"
" <b>标题:</b> {order.title}\n"
" <br/>\n"
" <b>处理人:</b> {order.assignee_display}\n"
" <br/>\n"
" <b>状态:</b> {order.status_display}\n"
" <br/>\n"
" </div>\n"
" </div>\n"
" "
#: orders/views.py:15 orders/views.py:31 templates/_nav.html:127
msgid "Orders"
msgstr "工单管理"
#: orders/views.py:16
msgid "Login confirm order list"
msgstr "登录复核工单列表"
#: orders/views.py:32
msgid "Login confirm order detail"
msgstr "登录复核工单详情"
#: orgs/mixins/models.py:44 orgs/mixins/serializers.py:26 orgs/models.py:31
msgid "Organization"
msgstr "组织"
...
...
@@ -3369,7 +3198,7 @@ msgstr "提示:RDP 协议不支持单独控制上传或下载文件"
#: perms/templates/perms/asset_permission_list.html:71
#: perms/templates/perms/asset_permission_list.html:118
#: perms/templates/perms/remote_app_permission_list.html:16
#: templates/_nav.html:21 users/forms.py:
29
3 users/models/group.py:26
#: templates/_nav.html:21 users/forms.py:
31
3 users/models/group.py:26
#: users/models/user.py:388 users/templates/users/_select_user_modal.html:16
#: users/templates/users/user_detail.html:218
#: users/templates/users/user_list.html:38
...
...
@@ -3629,33 +3458,33 @@ msgstr "远程应用授权用户列表"
msgid "RemoteApp permission RemoteApp list"
msgstr "远程应用授权远程应用列表"
#: settings/api.py:
28
#: settings/api.py:
31
msgid "Test mail sent to {}, please check"
msgstr "邮件已经发送{}, 请检查"
#: settings/api.py:
67
#: settings/api.py:
70
msgid "Test ldap success"
msgstr "连接LDAP成功"
#: settings/api.py:10
4
#: settings/api.py:10
7
msgid "Match {} s users"
msgstr "匹配 {} 个用户"
#: settings/api.py:16
3
#: settings/api.py:16
6
msgid "succeed: {} failed: {} total: {}"
msgstr "成功:{} 失败:{} 总数:{}"
#: settings/api.py:18
5 settings/api.py:221
#: settings/api.py:18
8 settings/api.py:224
msgid ""
"Error: Account invalid (Please make sure the information such as Access key "
"or Secret key is correct)"
msgstr "错误:账户无效 (请确保 Access key 或 Secret key 等信息正确)"
#: settings/api.py:19
1 settings/api.py:227
#: settings/api.py:19
4 settings/api.py:230
msgid "Create succeed"
msgstr "创建成功"
#: settings/api.py:2
09 settings/api.py:247
#: settings/api.py:2
12 settings/api.py:250
#: settings/templates/settings/terminal_setting.html:154
msgid "Delete succeed"
msgstr "删除成功"
...
...
@@ -4210,8 +4039,8 @@ msgid "Commercial support"
msgstr "商业支持"
#: templates/_header_bar.html:70 templates/_nav.html:30
#: templates/_nav_user.html:32 users/forms.py:1
5
3
#: users/templates/users/_user.html:4
3
#: templates/_nav_user.html:32 users/forms.py:1
7
3
#: users/templates/users/_user.html:4
4
#: users/templates/users/first_login.html:39
#: users/templates/users/user_password_update.html:40
#: users/templates/users/user_profile.html:17
...
...
@@ -4381,7 +4210,12 @@ msgstr "批量命令"
msgid "Task monitor"
msgstr "任务监控"
#: templates/_nav.html:130 users/templates/users/user_detail.html:257
#: templates/_nav.html:127 tickets/views.py:16 tickets/views.py:30
msgid "Tickets"
msgstr "工单管理"
#: templates/_nav.html:130 tickets/models/base.py:23
#: users/templates/users/user_detail.html:257
msgid "Login confirm"
msgstr "登录复核"
...
...
@@ -4730,6 +4564,18 @@ msgstr "地址"
msgid "Alive"
msgstr "在线"
#: terminal/templates/terminal/terminal_list.html:78
msgid "Accept"
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
msgid "Reject"
msgstr "拒绝"
#: terminal/templates/terminal/terminal_modal_accept.html:5
msgid "Accept terminal registration"
msgstr "接受终端注册"
...
...
@@ -4763,11 +4609,163 @@ msgid ""
"You should use your ssh client tools connect terminal: {} <br /> <br />{}"
msgstr "你可以使用ssh客户端工具连接终端"
#: tickets/models/base.py:16 tickets/models/base.py:52
#: tickets/templates/tickets/login_confirm_ticket_list.html:89
msgid "Open"
msgstr ""
#: tickets/models/base.py:17
#: tickets/templates/tickets/login_confirm_ticket_list.html:90
msgid "Closed"
msgstr "关闭"
#: tickets/models/base.py:22
msgid "General"
msgstr "一般"
#: tickets/models/base.py:26 tickets/models/base.py:69
msgid "User display name"
msgstr "用户显示名称"
#: tickets/models/base.py:28
#: tickets/templates/tickets/login_confirm_ticket_list.html:14
#: tickets/templates/tickets/login_confirm_ticket_list.html:87
msgid "Title"
msgstr "标题"
#: tickets/models/base.py:29 tickets/models/base.py:70
msgid "Body"
msgstr "内容"
#: tickets/models/base.py:30 tickets/templates/tickets/ticket_detail.html:51
msgid "Assignee"
msgstr "处理人"
#: tickets/models/base.py:31
msgid "Assignee display name"
msgstr "处理人名称"
#: tickets/models/base.py:32 tickets/templates/tickets/ticket_detail.html:50
msgid "Assignees"
msgstr "待处理人"
#: tickets/models/base.py:33
msgid "Assignees display name"
msgstr "待处理人名称"
#: tickets/models/base.py:53
msgid "{} {} this ticket"
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
msgid "Approve"
msgstr "同意"
#: tickets/models/login_confirm.py:24
msgid "this order"
msgstr "这个工单"
#: tickets/templates/tickets/ticket_detail.html:66
#: tickets/templates/tickets/ticket_detail.html:81
msgid "ago"
msgstr "前"
#: tickets/utils.py:18
msgid "New ticket"
msgstr "新工单"
#: tickets/utils.py:21
#, python-brace-format
msgid ""
"\n"
" <div>\n"
" <p>Your has a new ticket</p>\n"
" <div>\n"
" <b>Title:</b> {ticket.title}\n"
" <br/>\n"
" <b>User:</b> {user}\n"
" <br/>\n"
" <b>Assignees:</b> {ticket.assignees_display}\n"
" <br/>\n"
" <b>City:</b> {ticket.city}\n"
" <br/>\n"
" <b>IP:</b> {ticket.ip}\n"
" <br/>\n"
" <a href={url}>click here to review</a> \n"
" </div>\n"
" </div>\n"
" "
msgstr ""
"\n"
" <div>\n"
" <p>您有一个新工单</p>\n"
" <div>\n"
" <b>标题:</b> {ticket.title}\n"
" <br/>\n"
" <b>用户:</b> {user}\n"
" <br/>\n"
" <b>待处理人:</b> {ticket.assignees_display}\n"
" <br/>\n"
" <b>城市:</b> {ticket.city}\n"
" <br/>\n"
" <b>IP:</b> {ticket.ip}\n"
" <br/>\n"
" <a href={url}>点我查看</a> \n"
" </div>\n"
" </div>\n"
" "
#: tickets/utils.py:48
msgid "Ticket has been reply"
msgstr "工单已被回复"
#: tickets/utils.py:49
#, python-brace-format
msgid ""
"\n"
" <div>\n"
" <p>Your ticket has been replay</p>\n"
" <div>\n"
" <b>Title:</b> {ticket.title}\n"
" <br/>\n"
" <b>Assignee:</b> {ticket.assignee_display}\n"
" <br/>\n"
" <b>Status:</b> {ticket.status_display}\n"
" <br/>\n"
" </div>\n"
" </div>\n"
" "
msgstr ""
"\n"
" <div>\n"
" <p>您的工单已被回复</p>\n"
" <div>\n"
" <b>标题:</b> {ticket.title}\n"
" <br/>\n"
" <b>处理人:</b> {ticket.assignee_display}\n"
" <br/>\n"
" <b>状态:</b> {ticket.status_display}\n"
" <br/>\n"
" </div>\n"
" </div>\n"
" "
#: tickets/views.py:17
msgid "Login confirm ticket list"
msgstr "登录复核工单列表"
#: tickets/views.py:31
msgid "Login confirm ticket detail"
msgstr "登录复核工单详情"
#: users/api/user.py:173
msgid "Could not reset self otp, use profile reset instead"
msgstr "不能再该页面重置MFA, 请去个人信息页面重置"
#: users/forms.py:
32
users/models/user.py:392
#: users/forms.py:
47
users/models/user.py:392
#: users/templates/users/_select_user_modal.html:15
#: users/templates/users/user_detail.html:88
#: users/templates/users/user_list.html:37
...
...
@@ -4775,44 +4773,51 @@ msgstr "不能再该页面重置MFA, 请去个人信息页面重置"
msgid "Role"
msgstr "角色"
#: users/forms.py:35 users/forms.py:232
#: users/forms.py:51 users/models/user.py:427
#: users/templates/users/user_detail.html:104
#: users/templates/users/user_list.html:39
#: users/templates/users/user_profile.html:102
msgid "Source"
msgstr "用户来源"
#: users/forms.py:54 users/forms.py:252
#: users/templates/users/user_update.html:30
msgid "ssh public key"
msgstr "ssh公钥"
#: users/forms.py:
36 users/forms.py:23
3
#: users/forms.py:
55 users/forms.py:25
3
msgid "ssh-rsa AAAA..."
msgstr ""
#: users/forms.py:
37
#: users/forms.py:
56
msgid "Paste user id_rsa.pub here."
msgstr "复制用户公钥到这里"
#: users/forms.py:
5
1 users/templates/users/user_detail.html:226
#: users/forms.py:
7
1 users/templates/users/user_detail.html:226
msgid "Join user groups"
msgstr "添加到用户组"
#: users/forms.py:
86 users/forms.py:24
7
#: users/forms.py:
106 users/forms.py:26
7
msgid "Public key should not be the same as your old one."
msgstr "不能和原来的密钥相同"
#: users/forms.py:
90 users/forms.py:251 users/serializers/user.py:110
#: users/forms.py:
110 users/forms.py:271 users/serializers/user.py:109
msgid "Not a valid ssh public key"
msgstr "ssh密钥不合法"
#: users/forms.py:1
0
3 users/views/login.py:114 users/views/user.py:287
#: users/forms.py:1
2
3 users/views/login.py:114 users/views/user.py:287
msgid "* Your password does not meet the requirements"
msgstr "* 您的密码不符合要求"
#: users/forms.py:1
2
4
#: users/forms.py:1
4
4
msgid "Reset link will be generated and sent to the user"
msgstr "生成重置密码链接,通过邮件发送给用户"
#: users/forms.py:1
2
5
#: users/forms.py:1
4
5
msgid "Set password"
msgstr "设置密码"
#: users/forms.py:1
32 xpack/plugins/change_auth_plan/models.py:89
#: users/forms.py:1
52 xpack/plugins/change_auth_plan/models.py:88
#: 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_execution_list.html:57
...
...
@@ -4820,7 +4825,7 @@ msgstr "设置密码"
msgid "Password strategy"
msgstr "密码策略"
#: users/forms.py:1
5
9
#: users/forms.py:1
7
9
msgid ""
"When enabled, you will enter the MFA binding process the next time you log "
"in. you can also directly bind in \"personal information -> quick "
...
...
@@ -4829,11 +4834,11 @@ msgstr ""
"启用之后您将会在下次登录时进入MFA绑定流程;您也可以在(个人信息->快速修改->更"
"改MFA设置)中直接绑定!"
#: users/forms.py:1
6
9
#: users/forms.py:1
8
9
msgid "* Enable MFA authentication to make the account more secure."
msgstr "* 启用MFA认证,使账号更加安全。"
#: users/forms.py:1
7
9
#: users/forms.py:1
9
9
msgid ""
"In order to protect you and your company, please keep your account, password "
"and key sensitive information properly. (for example: setting complex "
...
...
@@ -4842,41 +4847,41 @@ msgstr ""
"为了保护您和公司的安全,请妥善保管您的账户、密码和密钥等重要敏感信息;(如:"
"设置复杂密码,启用MFA认证)"
#: users/forms.py:
18
6 users/templates/users/first_login.html:48
#: users/forms.py:
20
6 users/templates/users/first_login.html:48
#: users/templates/users/first_login.html:110
#: users/templates/users/first_login.html:139
msgid "Finish"
msgstr "完成"
#: users/forms.py:
19
2
#: users/forms.py:
21
2
msgid "Old password"
msgstr "原来密码"
#: users/forms.py:
19
7
#: users/forms.py:
21
7
msgid "New password"
msgstr "新密码"
#: users/forms.py:2
0
2
#: users/forms.py:2
2
2
msgid "Confirm password"
msgstr "确认密码"
#: users/forms.py:2
1
2
#: users/forms.py:2
3
2
msgid "Old password error"
msgstr "原来密码错误"
#: users/forms.py:2
2
0
#: users/forms.py:2
4
0
msgid "Password does not match"
msgstr "密码不一致"
#: users/forms.py:2
3
0
#: users/forms.py:2
5
0
msgid "Automatically configure and download the SSH key"
msgstr "自动配置并下载SSH密钥"
#: users/forms.py:2
3
4
#: users/forms.py:2
5
4
msgid "Paste your id_rsa.pub here."
msgstr "复制你的公钥到这里"
#: users/forms.py:2
68 users/forms.py:273 users/forms.py:32
3
#: users/forms.py:2
88 users/forms.py:293 users/forms.py:34
3
#: xpack/plugins/orgs/forms.py:18
msgid "Select users"
msgstr "选择用户"
...
...
@@ -4919,12 +4924,6 @@ msgstr "头像"
msgid "Wechat"
msgstr "微信"
#: users/models/user.py:427 users/templates/users/user_detail.html:104
#: users/templates/users/user_list.html:39
#: users/templates/users/user_profile.html:102
msgid "Source"
msgstr "用户来源"
#: users/models/user.py:431
msgid "Date password last updated"
msgstr "最后更新密码日期"
...
...
@@ -4965,11 +4964,11 @@ msgstr " 是否过期"
msgid "Avatar url"
msgstr "头像路径"
#: users/serializers/user.py:6
6
#: users/serializers/user.py:6
5
msgid "Role limit to {}"
msgstr "角色只能为 {}"
#: users/serializers/user.py:7
8
#: users/serializers/user.py:7
7
msgid "Password does not match security rules"
msgstr "密码不满足安全规则"
...
...
@@ -5005,7 +5004,7 @@ msgstr "选择用户"
msgid "Asset num"
msgstr "资产数量"
#: users/templates/users/_user.html:2
6
#: users/templates/users/_user.html:2
7
msgid "Security and Role"
msgstr "角色安全"
...
...
@@ -5748,8 +5747,8 @@ msgstr ""
"具</a>) <br>注意: 如果同时设置了定期执行和周期执行,优先使用定期执行"
#: xpack/plugins/change_auth_plan/meta.py:9
#: xpack/plugins/change_auth_plan/models.py:11
7
#: xpack/plugins/change_auth_plan/models.py:25
7
#: xpack/plugins/change_auth_plan/models.py:11
6
#: xpack/plugins/change_auth_plan/models.py:25
6
#: xpack/plugins/change_auth_plan/views.py:33
#: xpack/plugins/change_auth_plan/views.py:50
#: xpack/plugins/change_auth_plan/views.py:74
...
...
@@ -5760,20 +5759,20 @@ msgstr ""
msgid "Change auth plan"
msgstr "改密计划"
#: xpack/plugins/change_auth_plan/models.py:5
8
#: xpack/plugins/change_auth_plan/models.py:5
7
msgid "Custom password"
msgstr "自定义密码"
#: xpack/plugins/change_auth_plan/models.py:5
9
#: xpack/plugins/change_auth_plan/models.py:5
8
msgid "All assets use the same random password"
msgstr "所有资产使用相同的随机密码"
#: xpack/plugins/change_auth_plan/models.py:
60
#: xpack/plugins/change_auth_plan/models.py:
59
msgid "All assets use different random password"
msgstr "所有资产使用不同的随机密码"
#: xpack/plugins/change_auth_plan/models.py:7
9
#: xpack/plugins/change_auth_plan/models.py:14
8
#: xpack/plugins/change_auth_plan/models.py:7
8
#: xpack/plugins/change_auth_plan/models.py:14
7
#: 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/templates/cloud/sync_instance_task_detail.html:91
...
...
@@ -5782,8 +5781,8 @@ msgstr "所有资产使用不同的随机密码"
msgid "Cycle perform"
msgstr "周期执行"
#: xpack/plugins/change_auth_plan/models.py:8
4
#: xpack/plugins/change_auth_plan/models.py:14
6
#: xpack/plugins/change_auth_plan/models.py:8
3
#: xpack/plugins/change_auth_plan/models.py:14
5
#: 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/templates/cloud/sync_instance_task_detail.html:83
...
...
@@ -5792,37 +5791,37 @@ msgstr "周期执行"
msgid "Regularly perform"
msgstr "定期执行"
#: xpack/plugins/change_auth_plan/models.py:9
3
#: xpack/plugins/change_auth_plan/models.py:9
2
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:74
msgid "Password rules"
msgstr "密码规则"
#: xpack/plugins/change_auth_plan/models.py:21
3
#: xpack/plugins/change_auth_plan/models.py:21
2
msgid "* For security, do not change {} user's password"
msgstr "* 为了安全,禁止更改 {} 用户的密码"
#: xpack/plugins/change_auth_plan/models.py:21
7
#: xpack/plugins/change_auth_plan/models.py:21
6
msgid "Assets is empty, please add the asset"
msgstr "资产为空,请添加资产"
#: xpack/plugins/change_auth_plan/models.py:26
1
#: xpack/plugins/change_auth_plan/models.py:26
0
msgid "Change auth plan snapshot"
msgstr "改密计划快照"
#: xpack/plugins/change_auth_plan/models.py:27
6
#: xpack/plugins/change_auth_plan/models.py:4
33
#: xpack/plugins/change_auth_plan/models.py:27
5
#: xpack/plugins/change_auth_plan/models.py:4
26
msgid "Change auth plan execution"
msgstr "改密计划执行"
#: xpack/plugins/change_auth_plan/models.py:4
42
#: xpack/plugins/change_auth_plan/models.py:4
35
msgid "Change auth plan execution subtask"
msgstr "改密计划执行子任务"
#: xpack/plugins/change_auth_plan/models.py:4
60
#: xpack/plugins/change_auth_plan/models.py:4
53
msgid "Authentication failed"
msgstr "认证失败"
#: xpack/plugins/change_auth_plan/models.py:4
62
#: xpack/plugins/change_auth_plan/models.py:4
55
msgid "Connection timeout"
msgstr "连接超时"
...
...
@@ -6432,6 +6431,30 @@ msgstr "密码匣子"
msgid "vault create"
msgstr "创建"
#~ msgid "Log in frequently and try again later"
#~ msgstr "登录频繁, 稍后重试"
#~ msgid "Please carry seed value and conduct MFA secondary certification"
#~ msgstr "请携带seed值, 进行MFA二次认证"
#~ msgid "Please verify the user name and password first"
#~ msgstr "请先进行用户名和密码验证"
#~ msgid "MFA certification failed"
#~ msgstr "MFA认证失败"
#~ msgid "Accepted"
#~ msgstr "已接受"
#~ msgid "Rejected"
#~ msgstr "已拒绝"
#~ msgid "New order"
#~ msgstr "新工单"
#~ msgid "Orders"
#~ msgstr "工单管理"
#~ msgid ""
#~ "The username or password you entered is incorrect, please enter it again."
#~ msgstr "您输入的用户名或密码不正确,请重新输入。"
...
...
apps/static/js/jumpserver.js
View file @
f9e41d71
...
...
@@ -1317,3 +1317,7 @@ function initDateRangePicker(selector, options) {
options
=
Object
.
assign
(
defaultOption
,
options
);
return
$
(
selector
).
daterangepicker
(
options
);
}
function
reloadPage
()
{
window
.
location
.
reload
();
}
apps/templates/_nav.html
View file @
f9e41d71
...
...
@@ -127,7 +127,7 @@
<i
class=
"fa fa-check-square-o"
style=
"width: 14px"
></i>
<span
class=
"nav-label"
>
{% trans 'Tickets' %}
</span><span
class=
"fa arrow"
></span>
</a>
<ul
class=
"nav nav-second-level"
>
<li
id=
"login-confirm-
order
s"
><a
href=
"{% url 'tickets:login-confirm-ticket-list' %}"
>
{% trans 'Login confirm' %}
</a></li>
<li
id=
"login-confirm-
ticket
s"
><a
href=
"{% url 'tickets:login-confirm-ticket-list' %}"
>
{% trans 'Login confirm' %}
</a></li>
</ul>
</li>
{% endif %}
...
...
apps/tickets/api/base.py
View file @
f9e41d71
# -*- coding: utf-8 -*-
#
from
rest_framework
import
viewsets
,
generics
from
..
import
serializers
,
models
from
rest_framework
import
viewsets
from
django.shortcuts
import
get_object_or_404
from
common.utils
import
lazyproperty
from
..
import
serializers
,
models
,
mixins
class
TicketViewSet
(
viewsets
.
ModelViewSet
):
serializer_class
=
serializers
.
TicketSerializer
def
get_queryset
(
self
):
queryset
=
models
.
Ticket
.
objects
.
all
()
.
none
()
return
queryset
class
TicketViewSet
(
mixins
.
TicketMixin
,
viewsets
.
ModelViewSet
):
serializer_class
=
serializers
.
TicketSerializer
queryset
=
models
.
Ticket
.
objects
.
all
()
class
CommentViewSet
(
viewsets
.
ModelViewSet
):
class
Ticket
CommentViewSet
(
viewsets
.
ModelViewSet
):
serializer_class
=
serializers
.
CommentSerializer
def
check_permissions
(
self
,
request
):
ticket
=
self
.
ticket
if
request
.
user
==
ticket
.
user
or
request
.
user
in
ticket
.
assignees
.
all
():
return
True
return
False
def
get_serializer_context
(
self
):
context
=
super
()
.
get_serializer_context
()
context
[
'ticket'
]
=
self
.
ticket
return
context
@lazyproperty
def
ticket
(
self
):
ticket_id
=
self
.
kwargs
.
get
(
'ticket_id'
)
ticket
=
get_object_or_404
(
models
.
Ticket
,
pk
=
ticket_id
)
return
ticket
def
get_queryset
(
self
):
queryset
=
models
.
Comment
.
objects
.
none
()
queryset
=
self
.
ticket
.
comments
.
all
()
return
queryset
apps/tickets/api/login_confirm.py
View file @
f9e41d71
# -*- coding: utf-8 -*-
#
from
rest_framework
import
viewsets
,
generics
from
rest_framework.serializers
import
ValidationError
from
django.shortcuts
import
get_object_or_404
from
common.permissions
import
IsValidUser
from
common.mixins
import
CommonApiMixin
from
..
import
serializers
from
..
import
serializers
,
mixins
from
..models
import
LoginConfirmTicket
class
LoginConfirmTicketViewSet
(
CommonApiMixin
,
viewsets
.
ModelViewSet
):
class
LoginConfirmTicketViewSet
(
CommonApiMixin
,
mixins
.
TicketMixin
,
viewsets
.
ModelViewSet
):
serializer_class
=
serializers
.
LoginConfirmTicketSerializer
permission_classes
=
(
IsValidUser
,)
filter_fields
=
[
'status'
,
'title'
]
queryset
=
LoginConfirmTicket
.
objects
.
all
()
filter_fields
=
[
'status'
,
'title'
,
'action'
,
'ip'
]
search_fields
=
[
'user_display'
,
'title'
,
'ip'
,
'city'
]
def
get_queryset
(
self
):
queryset
=
LoginConfirmTicket
.
objects
.
all
()
\
.
filter
(
assignees
=
self
.
request
.
user
)
return
queryset
class
LoginConfirmTicketsCreateActionApi
(
generics
.
CreateAPIView
):
permission_classes
=
(
IsValidUser
,)
serializer_class
=
serializers
.
LoginConfirmTicketActionSerializer
def
get_ticket
(
self
):
ticket_id
=
self
.
kwargs
.
get
(
'pk'
)
queryset
=
LoginConfirmTicket
.
objects
.
all
()
\
.
filter
(
assignees
=
self
.
request
.
user
)
ticket
=
get_object_or_404
(
queryset
,
id
=
ticket_id
)
return
ticket
def
get_serializer_context
(
self
):
context
=
super
()
.
get_serializer_context
()
ticket
=
self
.
get_ticket
()
context
[
'ticket'
]
=
ticket
return
context
# 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/apps.py
View file @
f9e41d71
...
...
@@ -3,3 +3,7 @@ from django.apps import AppConfig
class
TicketsConfig
(
AppConfig
):
name
=
'tickets'
def
ready
(
self
):
from
.
import
signals_handler
return
super
()
.
ready
()
apps/tickets/mixins.py
0 → 100644
View file @
f9e41d71
# -*- coding: utf-8 -*-
#
from
django.db.models
import
Q
class
TicketMixin
:
def
get_queryset
(
self
):
queryset
=
super
()
.
get_queryset
()
assign
=
self
.
request
.
GET
.
get
(
'assign'
,
None
)
if
assign
is
None
:
queryset
=
queryset
.
filter
(
Q
(
assignees
=
self
.
request
.
user
)
|
Q
(
user
=
self
.
request
.
user
)
)
.
distinct
()
elif
assign
in
[
'1'
]:
queryset
=
queryset
.
filter
(
assignees
=
self
.
request
.
user
)
else
:
queryset
=
queryset
.
filter
(
user
=
self
.
request
.
user
)
return
queryset
apps/tickets/models/base.py
View file @
f9e41d71
...
...
@@ -31,16 +31,12 @@ class Ticket(CommonModelMixin):
assignee_display
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
"Assignee display name"
))
assignees
=
models
.
ManyToManyField
(
'users.User'
,
related_name
=
'
%(class)
s_assigned'
,
verbose_name
=
_
(
"Assignees"
))
assignees_display
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
"Assignees display name"
),
blank
=
True
)
type
=
models
.
CharField
(
max_length
=
16
,
default
=
'general'
,
verbose_name
=
_
(
"Type"
))
type
=
models
.
CharField
(
max_length
=
16
,
choices
=
TYPE_CHOICES
,
default
=
TYPE_GENERAL
,
verbose_name
=
_
(
"Type"
))
status
=
models
.
CharField
(
choices
=
STATUS_CHOICES
,
max_length
=
16
,
default
=
'open'
)
def
__str__
(
self
):
return
'{}: {}'
.
format
(
self
.
user_display
,
self
.
title
)
@property
def
comments
(
self
):
return
Comment
.
objects
.
filter
(
order_id
=
self
.
id
)
@property
def
body_as_html
(
self
):
return
self
.
body
.
replace
(
'
\n
'
,
'<br/>'
)
...
...
@@ -49,17 +45,29 @@ class Ticket(CommonModelMixin):
def
status_display
(
self
):
return
self
.
get_status_display
()
def
create_status_comment
(
self
,
status
,
user
):
if
status
==
self
.
STATUS_CLOSED
:
action
=
_
(
"Close"
)
else
:
action
=
_
(
"Open"
)
body
=
_
(
'{} {} this ticket'
)
.
format
(
self
.
user
,
action
)
self
.
comments
.
create
(
user
=
user
,
body
=
body
)
def
perform_status
(
self
,
status
,
user
):
if
self
.
status
==
status
:
return
self
.
status
=
status
self
.
save
()
class
Meta
:
ordering
=
(
'-date_created'
,)
class
Comment
(
CommonModelMixin
):
ticket
=
models
.
ForeignKey
(
Ticket
,
on_delete
=
models
.
CASCADE
)
ticket
=
models
.
ForeignKey
(
Ticket
,
on_delete
=
models
.
CASCADE
,
related_name
=
'comments'
)
user
=
models
.
ForeignKey
(
'users.User'
,
on_delete
=
models
.
SET_NULL
,
null
=
True
,
verbose_name
=
_
(
"User"
),
related_name
=
'comments'
)
user_display
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
"User display name"
))
body
=
models
.
TextField
(
verbose_name
=
_
(
"Body"
))
class
Meta
:
ordering
=
(
'date_created'
,
)
apps/tickets/models/login_confirm.py
View file @
f9e41d71
...
...
@@ -18,3 +18,16 @@ class LoginConfirmTicket(Ticket):
ip
=
models
.
GenericIPAddressField
(
blank
=
True
,
null
=
True
)
city
=
models
.
CharField
(
max_length
=
16
,
blank
=
True
,
default
=
''
)
action
=
models
.
CharField
(
choices
=
ACTION_CHOICES
,
max_length
=
16
,
default
=
''
,
blank
=
True
)
def
create_action_comment
(
self
,
action
,
user
):
action_display
=
dict
(
self
.
ACTION_CHOICES
)
.
get
(
action
)
body
=
'{} {} {}'
.
format
(
user
,
action_display
,
_
(
"this order"
))
self
.
comments
.
create
(
body
=
body
,
user
=
user
,
user_display
=
str
(
user
))
def
perform_action
(
self
,
action
,
user
):
self
.
create_action_comment
(
action
,
user
)
self
.
action
=
action
self
.
status
=
self
.
STATUS_CLOSED
self
.
assignee
=
user
self
.
assignees_display
=
str
(
user
)
self
.
save
()
apps/tickets/permissions.py
0 → 100644
View file @
f9e41d71
# -*- coding: utf-8 -*-
#
from
rest_framework.permissions
import
BasePermission
apps/tickets/serializers/base.py
View file @
f9e41d71
...
...
@@ -21,7 +21,24 @@ class TicketSerializer(serializers.ModelSerializer):
]
class
CurrentTicket
(
object
):
ticket
=
None
def
set_context
(
self
,
serializer_field
):
self
.
ticket
=
serializer_field
.
context
[
'ticket'
]
def
__call__
(
self
):
return
self
.
ticket
class
CommentSerializer
(
serializers
.
ModelSerializer
):
user
=
serializers
.
HiddenField
(
default
=
serializers
.
CurrentUserDefault
(),
)
ticket
=
serializers
.
HiddenField
(
default
=
CurrentTicket
()
)
class
Meta
:
model
=
models
.
Comment
fields
=
[
...
...
apps/tickets/serializers/login_confirm.py
View file @
f9e41d71
...
...
@@ -17,13 +17,28 @@ class LoginConfirmTicketSerializer(serializers.ModelSerializer):
]
read_only_fields
=
TicketSerializer
.
Meta
.
read_only_fields
def
create
(
self
,
validated_data
):
validated_data
.
pop
(
'action'
)
return
super
()
.
create
(
validated_data
)
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
)
instance
=
super
()
.
update
(
instance
,
validated_data
)
if
action
:
instance
.
perform_action
(
action
,
user
)
return
instance
class
LoginConfirmTicketActionSerializer
(
serializers
.
ModelSerializer
):
comment
=
serializers
.
CharField
(
allow_blank
=
True
)
class
Meta
:
model
=
LoginConfirmTicket
fields
=
[
'action'
,
'comment'
]
fields
=
[
'action'
]
def
update
(
self
,
instance
,
validated_data
):
pass
...
...
apps/tickets/signals_handler.py
View file @
f9e41d71
# -*- coding: utf-8 -*-
#
from
django.dispatch
import
receiver
from
django.db.models.signals
import
m2m_changed
,
post_save
from
django.db.models.signals
import
m2m_changed
,
post_save
,
pre_save
from
common.utils
import
get_logger
from
.models
import
LoginConfirmTicket
from
.models
import
LoginConfirmTicket
,
Ticket
,
Comment
from
.utils
import
(
send_login_confirm_ticket_mail_to_assignees
,
send_login_confirm_action_mail_to_user
...
...
@@ -16,16 +16,34 @@ logger = get_logger(__name__)
@receiver
(
m2m_changed
,
sender
=
LoginConfirmTicket
.
assignees
.
through
)
def
on_login_confirm_ticket_assignees_set
(
sender
,
instance
=
None
,
action
=
None
,
model
=
None
,
pk_set
=
None
,
**
kwargs
):
reverse
=
False
,
model
=
None
,
pk_set
=
None
,
**
kwargs
):
if
action
==
'post_add'
:
logger
.
debug
(
'New ticket create, send mail: {}'
.
format
(
instance
.
id
))
assignees
=
model
.
objects
.
filter
(
pk__in
=
pk_set
)
send_login_confirm_ticket_mail_to_assignees
(
instance
,
assignees
)
if
action
.
startswith
(
'post'
)
and
not
reverse
:
instance
.
assignees_display
=
', '
.
join
([
str
(
u
)
for
u
in
instance
.
assignees
.
all
()
])
instance
.
save
()
@receiver
(
post_save
,
sender
=
LoginConfirmTicket
)
def
on_login_confirm_ticket_status_change
(
sender
,
instance
=
None
,
created
=
False
,
**
kwargs
):
if
created
or
instance
.
status
==
"
pending
"
:
if
created
or
instance
.
status
==
"
open
"
:
return
logger
.
debug
(
'Ticket changed, send mail: {}'
.
format
(
instance
.
id
))
send_login_confirm_action_mail_to_user
(
instance
)
@receiver
(
pre_save
,
sender
=
LoginConfirmTicket
)
def
on_ticket_create
(
sender
,
instance
=
None
,
**
kwargs
):
instance
.
user_display
=
str
(
instance
.
user
)
if
instance
.
assignee
:
instance
.
assignee_display
=
str
(
instance
.
assignee
)
@receiver
(
pre_save
,
sender
=
Comment
)
def
on_comment_create
(
sender
,
instance
=
None
,
**
kwargs
):
instance
.
user_display
=
str
(
instance
.
user
)
apps/tickets/templates/tickets/login_confirm_ticket_detail.html
View file @
f9e41d71
{% extends '
base
.html' %}
{% extends '
tickets/ticket_detail
.html' %}
{% load static %}
{% load i18n %}
{% block content %}
<div
class=
"wrapper wrapper-content animated fadeInRight"
>
<div
class=
"row"
>
<div
class=
"col-sm-12"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox-title"
>
<h5>
{{ object.title }}
</h5>
<div
class=
"ibox-tools"
>
<a
class=
"collapse-link"
>
<i
class=
"fa fa-chevron-up"
></i>
</a>
<a
class=
"dropdown-toggle"
data-toggle=
"dropdown"
href=
"#"
>
<i
class=
"fa fa-wrench"
></i>
</a>
<a
class=
"close-link"
>
<i
class=
"fa fa-times"
></i>
</a>
</div>
</div>
<div
class=
"ibox-content"
>
<div
class=
"row"
>
<div
class=
"col-lg-11"
>
<div
class=
"row"
>
<div
class=
"col-lg-6"
>
<dl
class=
"dl-horizontal"
>
<dt>
{% trans 'User' %}:
</dt>
<dd>
{{ object.user_display }}
</dd>
<dt>
{% trans 'IP' %}:
</dt>
<dd>
{{ object.ip }}
</dd>
<dt>
{% trans 'Assignees' %}:
</dt>
<dd>
{{ object.assignees_display }}
</dd>
<dt>
{% trans 'Status' %}:
</dt>
<dd>
{% if object.status == "accpeted" %}
<span
class=
"label label-primary"
>
{{ object.get_status_display }}
</span>
{% endif %}
{% if object.status == "rejected" %}
<span
class=
"label label-danger"
>
{{ object.get_status_display }}
</span>
{% endif %}
{% if object.status == "pending" %}
<span
class=
"label label-info"
>
{{ object.get_status_display }}
</span>
{% endif %}
</dd>
</dl>
</div>
<div
class=
"col-lg-6"
>
<dl
class=
"dl-horizontal"
>
<dt><br></dt><dd></dd>
<dt>
{% trans 'City' %}:
</dt>
<dd>
{{ object.city }}
</dd>
<dt>
{% trans 'Assignee' %}:
</dt>
<dd>
{{ object.assignee_display | default_if_none:"" }}
</dd>
<dt>
{% trans 'Date created' %}:
</dt>
<dd>
{{ object.date_created }}
</dd>
</dl>
</div>
</div>
<div
class=
"row m-t-sm"
>
<div
class=
"col-lg-12"
>
<div
class=
"panel blank-panel"
>
<div
class=
"panel-body"
>
<div
class=
"feed-activity-list"
>
{% for comment in object.comments %}
<div
class=
"feed-element"
>
<a
href=
"#"
class=
"pull-left"
>
<img
alt=
"image"
class=
"img-circle"
src=
"{% static 'img/avatar/user.png'%}"
>
</a>
<div
class=
"media-body "
>
<strong>
{{ comment.user_display }}
</strong>
<small
class=
"text-muted"
>
{{ comment.date_created|timesince}} {% trans 'ago' %}
</small>
<br/>
<small
class=
"text-muted"
>
{{ comment.date_created }}
</small>
<div
style=
"padding-top: 10px"
>
{{ comment.body }}
</div>
</div>
</div>
{% endfor %}
</div>
<div
class=
"feed-element"
>
<a
href=
""
class=
"pull-left"
>
<img
alt=
"image"
class=
"img-circle"
src=
"{% static 'img/avatar/user.png'%}"
>
</a>
<div
class=
"media-body"
>
<textarea
class=
"form-control"
placeholder=
""
id=
"comment"
></textarea>
</div>
</div>
<div
class=
"text-right"
>
<a
class=
"btn btn-sm btn-primary btn-action btn-update"
data-action=
"accept"
><i
class=
"fa fa-check"
></i>
{% trans 'Accept' %}
</a>
<a
class=
"btn btn-sm btn-danger btn-action btn-update"
data-action=
"reject"
><i
class=
"fa fa-times"
></i>
{% trans 'Reject' %}
</a>
<a
class=
"btn btn-sm btn-info btn-action"
data-action=
"comment"
><i
class=
"fa fa-pencil"
></i>
{% trans 'Comment' %}
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"col-lg-1"
>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% block status %}
{% endblock %}
{% block action %}
<a
class=
"btn btn-sm btn-primary btn-update btn-action"
data-action=
"approve"
><i
class=
"fa fa-check"
></i>
{% trans 'Approve' %}
</a>
<a
class=
"btn btn-sm btn-danger btn-update btn-action"
data-action=
"reject"
><i
class=
"fa fa-times"
></i>
{% trans 'Reject' %}
</a>
{% endblock %}
{% block custom_foot_js %}
{{ block.super }}
<script>
var
ticketId
=
"{{ object.id }}"
;
var
status
=
"{{ object.status }}"
;
var
actionCreateUrl
=
"{% url 'api-tickets:login-confirm-ticket-create-action' pk=object.id %}"
;
$
(
document
).
ready
(
function
()
{
if
(
status
!==
"pending"
)
{
$
(
'.btn-update'
).
attr
(
'disabled'
,
'1'
)
}
})
.
on
(
'click'
,
'.btn-action'
,
function
()
{
var
action
=
$
(
this
).
data
(
'action'
);
var
comment
=
$
(
"#comment"
).
val
();
var
data
=
{
url
:
actionCreateUrl
,
method
:
'POST'
,
body
:
JSON
.
stringify
({
action
:
action
,
comment
:
comment
}),
success
:
function
()
{
window
.
location
.
reload
();
}
};
requestApi
(
data
);
})
var
ticketDetailUrl
=
"{% url 'api-tickets:login-confirm-ticket-detail' pk=object.id %}"
;
$
(
document
).
ready
(
function
()
{
}).
on
(
'click'
,
'.btn-action'
,
function
()
{
createComment
(
function
()
{
});
var
action
=
$
(
this
).
data
(
'action'
);
var
data
=
{
url
:
ticketDetailUrl
,
body
:
JSON
.
stringify
({
action
:
action
}),
method
:
"PATCH"
,
success
:
reloadPage
};
requestApi
(
data
);
})
</script>
{% endblock %}
apps/tickets/templates/tickets/login_confirm_ticket_list.html
View file @
f9e41d71
...
...
@@ -13,7 +13,6 @@
</th>
<th
class=
"text-center"
>
{% trans 'Title' %}
</th>
<th
class=
"text-center"
>
{% trans 'User' %}
</th>
<th
class=
"text-center"
>
{% trans 'IP' %}
</th>
<th
class=
"text-center"
>
{% trans 'Status' %}
</th>
<th
class=
"text-center"
>
{% trans 'Datetime' %}
</th>
<th
class=
"text-center"
>
{% trans 'Action' %}
</th>
...
...
@@ -39,10 +38,6 @@ function initTable() {
$
(
td
).
html
(
detailBtn
.
replace
(
"{{ DEFAULT_PK }}"
,
rowData
.
id
));
}},
{
targets
:
3
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
d
=
cellData
+
"("
+
rowData
.
city
+
")"
;
$
(
td
).
html
(
d
)
}},
{
targets
:
4
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
if
(
cellData
===
"approval"
)
{
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
}
else
if
(
cellData
===
"rejected"
)
{
...
...
@@ -53,12 +48,12 @@ function initTable() {
$
(
td
).
html
(
'<i class="fa fa-circle text-info"></i>'
)
}
}},
{
targets
:
5
,
createdCell
:
function
(
td
,
cellData
)
{
{
targets
:
4
,
createdCell
:
function
(
td
,
cellData
)
{
var
d
=
toSafeLocalDateStr
(
cellData
);
$
(
td
).
html
(
d
)
}},
{
targets
:
6
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
acceptBtn
=
'<a class="btn btn-xs btn-info btn-action" data-action="a
ccept" data-uid="{{ DEFAULT_PK }}" >{% trans "Accept
" %}</a> '
;
{
targets
:
5
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
acceptBtn
=
'<a class="btn btn-xs btn-info btn-action" data-action="a
pprove" data-uid="{{ DEFAULT_PK }}" >{% trans "Approve
" %}</a> '
;
var
rejectBtn
=
'<a class="btn btn-xs btn-danger btn-action" data-action="reject" data-uid="{{ DEFAULT_PK }}" >{% trans "Reject" %}</a>'
;
acceptBtn
=
acceptBtn
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
rejectBtn
=
rejectBtn
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
...
...
@@ -74,7 +69,7 @@ function initTable() {
ajax_url
:
'{% url "api-tickets:login-confirm-ticket-list" %}'
,
columns
:
[
{
data
:
"id"
},
{
data
:
"title"
},
{
data
:
"user_display"
},
{
data
:
"ip"
},
{
data
:
"user_display"
},
{
data
:
"status"
,
ticketable
:
false
},
{
data
:
"date_created"
,
width
:
"120px"
},
{
data
:
"id"
,
ticketable
:
false
}
...
...
@@ -101,18 +96,15 @@ $(document).ready(function(){
];
initTableFilterDropdown
(
'#login_confirm_ticket_list_table_filter input'
,
menu
)
}).
on
(
'click'
,
'.btn-action'
,
function
()
{
var
actionCreateUrl
=
"{% url 'api-tickets:login-confirm-ticket-create-action' pk=DEFAULT_PK %}"
;
var
ticketId
=
$
(
this
).
data
(
'uid'
);
actionCreateUrl
=
actionCreateUrl
.
replace
(
"{{ DEFAULT_PK }}"
,
ticketId
);
var
ticketId
=
$
(
this
).
data
(
"uid"
);
var
action
=
$
(
this
).
data
(
'action'
);
var
comment
=
''
;
var
ticketDetailUrl
=
"{% url 'api-tickets:login-confirm-ticket-detail' pk=DEFAULT_PK %}"
;
ticketDetailUrl
=
ticketDetailUrl
.
replace
(
"{{ DEFAULT_PK }}"
,
ticketId
);
var
data
=
{
url
:
actionCreateUrl
,
method
:
'POST'
,
body
:
JSON
.
stringify
({
action
:
action
,
comment
:
comment
}),
success
:
function
()
{
window
.
location
.
reload
();
}
url
:
ticketDetailUrl
,
body
:
JSON
.
stringify
({
action
:
action
}),
method
:
"PATCH"
,
success
:
reloadPage
};
requestApi
(
data
);
})
...
...
apps/tickets/templates/tickets/ticket_detail.html
0 → 100644
View file @
f9e41d71
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% block content %}
<div
class=
"wrapper wrapper-content animated fadeInRight"
>
<div
class=
"row"
>
<div
class=
"col-sm-12"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox-title"
>
<h5>
{{ object.title }}
</h5>
<div
class=
"ibox-tools"
>
<a
class=
"collapse-link"
>
<i
class=
"fa fa-chevron-up"
></i>
</a>
<a
class=
"dropdown-toggle"
data-toggle=
"dropdown"
href=
"#"
>
<i
class=
"fa fa-wrench"
></i>
</a>
<a
class=
"close-link"
>
<i
class=
"fa fa-times"
></i>
</a>
</div>
</div>
<div
class=
"ibox-content"
>
<div
class=
"row"
>
<div
class=
"col-lg-11"
>
<div
class=
"row"
>
<div
class=
"col-lg-6"
>
<dl
class=
"dl-horizontal"
>
<dt>
{% trans 'User' %}:
</dt>
<dd>
{{ object.user_display }}
</dd>
<dt>
{% trans 'Type' %}:
</dt>
<dd>
{{ object.get_type_display | default_if_none:"" }}
</dd>
<dt>
{% trans 'Status' %}:
</dt>
<dd>
{% if object.status == "open" %}
<span
class=
"label label-primary"
>
{{ object.get_status_display }}
</span>
{% elif object.status == "closed" %}
<span
class=
"label label-danger"
>
{{ object.get_status_display }}
</span>
{% endif %}
</dd>
</dl>
</div>
<div
class=
"col-lg-6"
>
<dl
class=
"dl-horizontal"
>
<dt>
{% trans 'Assignees' %}:
</dt>
<dd>
{{ object.assignees_display }}
</dd>
<dt>
{% trans 'Assignee' %}:
</dt>
<dd>
{{ object.assignee_display | default_if_none:"" }}
</dd>
<dt>
{% trans 'Date created' %}:
</dt>
<dd>
{{ object.date_created }}
</dd>
</dl>
</div>
</div>
<div
class=
"row m-t-sm"
>
<div
class=
"col-lg-12"
>
<div
class=
"panel blank-panel"
>
<div
class=
"panel-body"
>
<div
class=
"feed-activity-list"
>
<div
class=
"feed-element"
>
<a
href=
"#"
class=
"pull-left"
>
<img
alt=
"image"
class=
"img-circle"
src=
"{% static 'img/avatar/user.png'%}"
>
</a>
<div
class=
"media-body "
>
<strong>
{{ object.user_display }}
</strong>
<small
class=
"text-muted"
>
{{ object.date_created|timesince}} {% trans 'ago' %}
</small>
<br/>
<small
class=
"text-muted"
>
{{ object.date_created }}
</small>
<div
style=
"padding-top: 10px"
>
{{ object.body_as_html | safe }}
</div>
</div>
</div>
{% for comment in object.comments.all %}
<div
class=
"feed-element"
>
<a
href=
"#"
class=
"pull-left"
>
<img
alt=
"image"
class=
"img-circle"
src=
"{% static 'img/avatar/user.png'%}"
>
</a>
<div
class=
"media-body "
>
<strong>
{{ comment.user_display }}
</strong>
<small
class=
"text-muted"
>
{{ comment.date_created|timesince}} {% trans 'ago' %}
</small>
<br/>
<small
class=
"text-muted"
>
{{ comment.date_created }}
</small>
<div
style=
"padding-top: 10px"
>
{{ comment.body }}
</div>
</div>
</div>
{% endfor %}
</div>
<div
class=
"feed-element"
>
<a
href=
""
class=
"pull-left"
>
<img
alt=
"image"
class=
"img-circle"
src=
"{% static 'img/avatar/user.png'%}"
>
</a>
<div
class=
"media-body"
>
<textarea
class=
"form-control"
placeholder=
""
id=
"comment"
></textarea>
</div>
</div>
<div
class=
"text-right"
>
{% block action %}
{% endblock %}
{% block status %}
<a
class=
"btn btn-sm btn-danger btn-update btn-status"
data-uid=
"close"
><i
class=
"fa fa-times"
></i>
{% trans 'Close' %}
</a>
{% endblock %}
{% block comment %}
<a
class=
"btn btn-sm btn-info btn-update btn-comment"
data-uid=
"comment"
><i
class=
"fa fa-pencil"
></i>
{% trans 'Comment' %}
</a>
{% endblock %}
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"col-lg-1"
>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
var
ticketId
=
"{{ object.id }}"
;
var
status
=
"{{ object.status }}"
;
var
commentUrl
=
"{% url 'api-tickets:ticket-comment-list' ticket_id=object.id %}"
;
function
createComment
(
successCallback
)
{
var
commentText
=
$
(
"#comment"
).
val
();
if
(
!
commentText
)
{
return
}
var
body
=
{
body
:
commentText
,
ticket
:
ticketId
,
};
var
success
=
function
()
{
window
.
location
.
reload
();
};
if
(
successCallback
){
success
=
successCallback
;
}
requestApi
({
url
:
commentUrl
,
data
:
JSON
.
stringify
(
body
),
method
:
"POST"
,
success
:
success
})
}
$
(
document
).
ready
(
function
()
{
if
(
status
!==
"open"
)
{
$
(
'.btn-update'
).
attr
(
'disabled'
,
'1'
)
}
})
.
on
(
'click'
,
'.btn-comment'
,
function
()
{
createComment
();
})
</script>
{% endblock %}
apps/tickets/urls/api_urls.py
View file @
f9e41d71
...
...
@@ -9,15 +9,11 @@ app_name = 'tickets'
router
=
DefaultRouter
()
router
.
register
(
'tickets'
,
api
.
TicketViewSet
,
'ticket'
)
router
.
register
(
'tickets/(?P<ticket_id>[0-9a-zA-Z
\
-]{36})/comments'
,
api
.
TicketCommentViewSet
,
'ticket-comment'
)
router
.
register
(
'login-confirm-tickets'
,
api
.
LoginConfirmTicketViewSet
,
'login-confirm-ticket'
)
router
.
register
(
'tickets/<uuid:ticket_id>/comments/'
,
api
.
CommentViewSet
,
'ticket-comment'
)
urlpatterns
=
[
path
(
'login-confirm-tickets/<uuid:pk>/actions/'
,
api
.
LoginConfirmTicketsCreateActionApi
.
as_view
(),
name
=
'login-confirm-ticket-create-action'
),
]
urlpatterns
+=
router
.
urls
apps/tickets/views.py
View file @
f9e41d71
from
django.views.generic
import
TemplateView
,
DetailView
from
django.utils.translation
import
ugettext
as
_
from
common.permissions
import
PermissionsMixin
,
Is
OrgAdmin
from
common.permissions
import
PermissionsMixin
,
Is
ValidUser
from
.models
import
LoginConfirmTicket
from
.
import
mixins
class
LoginConfirmTicketListView
(
PermissionsMixin
,
TemplateView
):
template_name
=
'tickets/login_confirm_ticket_list.html'
permission_classes
=
(
Is
OrgAdmin
,)
permission_classes
=
(
Is
ValidUser
,)
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
()
.
get_context_data
(
**
kwargs
)
...
...
@@ -18,12 +19,10 @@ class LoginConfirmTicketListView(PermissionsMixin, TemplateView):
return
context
class
LoginConfirmTicketDetailView
(
PermissionsMixin
,
DetailView
):
class
LoginConfirmTicketDetailView
(
PermissionsMixin
,
mixins
.
TicketMixin
,
DetailView
):
template_name
=
'tickets/login_confirm_ticket_detail.html'
permission_classes
=
(
IsOrgAdmin
,)
def
get_queryset
(
self
):
return
LoginConfirmTicket
.
objects
.
filter
(
assignees
=
self
.
request
.
user
)
queryset
=
LoginConfirmTicket
.
objects
.
all
()
permission_classes
=
(
IsValidUser
,)
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
()
.
get_context_data
(
**
kwargs
)
...
...
apps/users/serializers/user.py
View file @
f9e41d71
...
...
@@ -13,11 +13,11 @@ from ..models import User, UserGroup
__all__
=
[
'UserSerializer'
,
'UserPKUpdateSerializer'
,
'UserUpdateGroupSerializer'
,
'ChangeUserPasswordSerializer'
,
'ResetOTPSerializer'
,
'UserProfileSerializer'
,
]
class
UserSerializer
(
BulkSerializerMixin
,
serializers
.
ModelSerializer
):
can_update
=
serializers
.
SerializerMethodField
()
can_delete
=
serializers
.
SerializerMethodField
()
...
...
@@ -135,3 +135,11 @@ class ResetOTPSerializer(serializers.Serializer):
def
update
(
self
,
instance
,
validated_data
):
pass
class
UserProfileSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
User
fields
=
[
'id'
,
'username'
,
'name'
,
'role'
,
'email'
]
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