Commit f9e41d71 authored by ibuler's avatar ibuler

[Update] 修改登录工单

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