mirror of https://github.com/jumpserver/jumpserver
[Update] 基本完成登录二次审核
parent
517c682201
commit
d0ba67ed50
|
@ -7,7 +7,7 @@ from django.views.generic.detail import SingleObjectMixin
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.urls import reverse_lazy, reverse
|
from django.urls import reverse_lazy, reverse
|
||||||
|
|
||||||
from common.permissions import PermissionsMixin ,IsOrgAdmin
|
from common.permissions import PermissionsMixin, IsOrgAdmin
|
||||||
from common.const import create_success_msg, update_success_msg
|
from common.const import create_success_msg, update_success_msg
|
||||||
from common.utils import get_object_or_none
|
from common.utils import get_object_or_none
|
||||||
from ..models import Domain, Gateway
|
from ..models import Domain, Gateway
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -8,19 +7,17 @@ from django.core.cache import cache
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from rest_framework.permissions import AllowAny
|
from rest_framework.permissions import AllowAny
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.generics import CreateAPIView
|
from rest_framework.generics import CreateAPIView
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
from common.utils import get_logger, get_request_ip
|
from common.utils import get_logger, get_request_ip, get_object_or_none
|
||||||
from common.permissions import IsOrgAdminOrAppUser, IsValidUser
|
from common.permissions import IsOrgAdminOrAppUser, IsValidUser
|
||||||
from orgs.mixins.api import RootOrgViewMixin
|
from orgs.mixins.api import RootOrgViewMixin
|
||||||
from users.serializers import UserSerializer
|
from users.serializers import UserSerializer
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from assets.models import Asset, SystemUser
|
from assets.models import Asset, SystemUser
|
||||||
from audits.models import UserLoginLog as LoginLog
|
|
||||||
from users.utils import (
|
from users.utils import (
|
||||||
check_otp_code, increase_login_failed_count,
|
check_otp_code, increase_login_failed_count,
|
||||||
is_block_login, clean_failed_count
|
is_block_login, clean_failed_count
|
||||||
|
@ -33,7 +30,7 @@ from ..signals import post_auth_success, post_auth_failed
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'UserAuthApi', 'UserConnectionTokenApi', 'UserOtpAuthApi',
|
'UserAuthApi', 'UserConnectionTokenApi', 'UserOtpAuthApi',
|
||||||
'UserOtpVerifyApi',
|
'UserOtpVerifyApi', 'UserOrderAcceptAuthApi',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -209,3 +206,26 @@ class UserOtpVerifyApi(CreateAPIView):
|
||||||
else:
|
else:
|
||||||
return Response({"error": "Code not valid"}, status=400)
|
return Response({"error": "Code not valid"}, status=400)
|
||||||
|
|
||||||
|
|
||||||
|
class UserOrderAcceptAuthApi(APIView):
|
||||||
|
permission_classes = ()
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
from orders.models import LoginConfirmOrder
|
||||||
|
order_id = self.request.session.get("auth_order_id")
|
||||||
|
logger.debug('Login confirm order id: {}'.format(order_id))
|
||||||
|
if not order_id:
|
||||||
|
order = None
|
||||||
|
else:
|
||||||
|
order = get_object_or_none(LoginConfirmOrder, pk=order_id)
|
||||||
|
if not order:
|
||||||
|
error = _("No order found or order expired")
|
||||||
|
return Response({"error": error, "status": "not found"}, status=404)
|
||||||
|
if order.status == order.STATUS_ACCEPTED:
|
||||||
|
self.request.session["auth_confirm"] = "1"
|
||||||
|
return Response({"msg": "ok"})
|
||||||
|
elif order.status == order.STATUS_REJECTED:
|
||||||
|
error = _("Order was rejected by {}").format(order.assignee_display)
|
||||||
|
else:
|
||||||
|
error = "Order status: {}".format(order.status)
|
||||||
|
return Response({"error": error, "status": order.status}, status=400)
|
||||||
|
|
|
@ -71,7 +71,8 @@ class TokenCreateApi(CreateAPIView):
|
||||||
raise MFARequiredError()
|
raise MFARequiredError()
|
||||||
self.send_auth_signal(success=True, user=user)
|
self.send_auth_signal(success=True, user=user)
|
||||||
clean_failed_count(username, ip)
|
clean_failed_count(username, ip)
|
||||||
return super().create(request, *args, **kwargs)
|
resp = super().create(request, *args, **kwargs)
|
||||||
|
return resp
|
||||||
except AuthFailedError as e:
|
except AuthFailedError as e:
|
||||||
increase_login_failed_count(username, ip)
|
increase_login_failed_count(username, ip)
|
||||||
self.send_auth_signal(success=False, user=user, username=username, reason=str(e))
|
self.send_auth_signal(success=False, user=user, username=username, reason=str(e))
|
||||||
|
@ -80,8 +81,8 @@ class TokenCreateApi(CreateAPIView):
|
||||||
msg = _("MFA required")
|
msg = _("MFA required")
|
||||||
seed = uuid.uuid4().hex
|
seed = uuid.uuid4().hex
|
||||||
cache.set(seed, user.username, 300)
|
cache.set(seed, user.username, 300)
|
||||||
resp = {'msg': msg, "choices": ["otp"], "req": seed}
|
data = {'msg': msg, "choices": ["otp"], "req": seed}
|
||||||
return Response(resp, status=300)
|
return Response(data, status=300)
|
||||||
|
|
||||||
def send_auth_signal(self, success=True, user=None, username='', reason=''):
|
def send_auth_signal(self, success=True, user=None, username='', reason=''):
|
||||||
if success:
|
if success:
|
||||||
|
|
|
@ -49,8 +49,8 @@ class LoginConfirmSetting(CommonModelMixin):
|
||||||
return get_object_or_none(cls, user=user)
|
return get_object_or_none(cls, user=user)
|
||||||
|
|
||||||
def create_confirm_order(self, request=None):
|
def create_confirm_order(self, request=None):
|
||||||
from orders.models import Order
|
from orders.models import LoginConfirmOrder
|
||||||
title = _('User login request confirm: {}'.format(self.user))
|
title = _('User login request: {}'.format(self.user))
|
||||||
if request:
|
if request:
|
||||||
remote_addr = get_request_ip(request)
|
remote_addr = get_request_ip(request)
|
||||||
city = get_ip_city(remote_addr)
|
city = get_ip_city(remote_addr)
|
||||||
|
@ -58,14 +58,17 @@ class LoginConfirmSetting(CommonModelMixin):
|
||||||
self.user, remote_addr, city, timezone.now()
|
self.user, remote_addr, city, timezone.now()
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
city = ''
|
||||||
|
remote_addr = ''
|
||||||
body = ''
|
body = ''
|
||||||
reviewer = self.reviewers.all()
|
reviewer = self.reviewers.all()
|
||||||
reviewer_names = ','.join([u.name for u in reviewer])
|
reviewer_names = ','.join([u.name for u in reviewer])
|
||||||
order = Order.objects.create(
|
order = LoginConfirmOrder.objects.create(
|
||||||
user=self.user, user_display=str(self.user),
|
user=self.user, user_display=str(self.user),
|
||||||
title=title, body=body,
|
title=title, body=body,
|
||||||
|
city=city, ip=remote_addr,
|
||||||
assignees_display=reviewer_names,
|
assignees_display=reviewer_names,
|
||||||
type=Order.TYPE_LOGIN_REQUEST,
|
type=LoginConfirmOrder.TYPE_LOGIN_CONFIRM,
|
||||||
)
|
)
|
||||||
order.assignees.set(reviewer)
|
order.assignees.set(reviewer)
|
||||||
return order
|
return order
|
||||||
|
|
|
@ -6,13 +6,11 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="shortcut icon" href="{{ FAVICON_URL }}" type="image/x-icon">
|
||||||
<title>{{ title }}</title>
|
<title>{{ title }}</title>
|
||||||
|
|
||||||
{% include '_head_css_js.html' %}
|
{% include '_head_css_js.html' %}
|
||||||
<link href="{% static "css/jumpserver.css" %}" rel="stylesheet">
|
<link href="{% static "css/jumpserver.css" %}" rel="stylesheet">
|
||||||
<script type="text/javascript"
|
<script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
|
||||||
src="{% url 'javascript-catalog' %}"></script>
|
|
||||||
<script src="{% static "js/jumpserver.js" %}"></script>
|
<script src="{% static "js/jumpserver.js" %}"></script>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
@ -29,23 +27,29 @@
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p></p>
|
<p></p>
|
||||||
<div class="alert alert-success" id="messages">
|
<div class="alert alert-success info-messages" >
|
||||||
Wait for Guanghongwei confirm, You also can copy link to her/his <br/>
|
{{ msg|safe }}
|
||||||
Don't close ....
|
|
||||||
</div>
|
</div>
|
||||||
<div class="progress progress-bar-default">
|
<div class="alert alert-danger error-messages" style="display: none">
|
||||||
<div style="width: 43%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="43" role="progressbar" class="progress-bar">
|
</div>
|
||||||
|
<div class="progress progress-bar-default progress-striped active">
|
||||||
|
<div aria-valuemax="3600" aria-valuemin="0" aria-valuenow="43" role="progressbar" class="progress-bar">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-3">
|
<div class="col-lg-3">
|
||||||
<a href="{{ redirect_url }}" class="btn btn-primary block full-width m-b">
|
<a class="btn btn-primary btn-sm block btn-refresh">
|
||||||
{% trans 'Refresh' %}
|
<i class="fa fa-refresh"></i> {% trans 'Refresh' %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-3">
|
<div class="col-lg-3">
|
||||||
<a href="{{ redirect_url }}" class="btn btn-primary block full-width m-b">
|
<a class="btn btn-primary btn-sm block btn-copy" data-link="{{ order_detail_url }}">
|
||||||
{% trans 'Copy link' %}
|
<i class="fa fa-clipboard"></i> {% trans 'Copy link' %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-3">
|
||||||
|
<a class="btn btn-default btn-sm block btn-return" href="{% url 'authentication:login' %}">
|
||||||
|
<i class="fa fa-reply"></i> {% trans 'Return' %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -63,26 +67,76 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
{% include '_foot_js.html' %}
|
||||||
|
<script src="{% static "js/plugins/clipboard/clipboard.min.js" %}"></script>
|
||||||
<script>
|
<script>
|
||||||
var time = '{{ interval }}';
|
var errorMsgShow = false;
|
||||||
if (!time) {
|
var errorMsgRef = $(".error-messages");
|
||||||
time = 5;
|
var infoMsgRef = $(".info-messages");
|
||||||
} else {
|
var timestamp = '{{ timestamp }}';
|
||||||
time = parseInt(time);
|
var progressBarRef = $(".progress-bar");
|
||||||
}
|
var interval, checkInterval;
|
||||||
|
var url = "{% url 'api-auth:user-order-auth' %}";
|
||||||
|
var successUrl = "{% url 'authentication:login-guard' %}";
|
||||||
|
|
||||||
function redirect_page() {
|
function doRequestAuth() {
|
||||||
if (time >= 0) {
|
requestApi({
|
||||||
var messages = '{{ messages|safe }}, <b>' + time + '</b> ...';
|
url: url,
|
||||||
$('#messages').html(messages);
|
method: "GET",
|
||||||
time--;
|
success: function () {
|
||||||
setTimeout(redirect_page, 1000);
|
clearInterval(interval);
|
||||||
} else {
|
clearInterval(checkInterval);
|
||||||
window.location.href = "{{ redirect_url }}";
|
window.location = successUrl;
|
||||||
|
},
|
||||||
|
error: function (text, data) {
|
||||||
|
if (data.status !== "pending") {
|
||||||
|
if (!errorMsgShow) {
|
||||||
|
infoMsgRef.hide();
|
||||||
|
errorMsgRef.show();
|
||||||
|
progressBarRef.addClass('progress-bar-danger');
|
||||||
|
errorMsgShow = true;
|
||||||
|
}
|
||||||
|
clearInterval(interval);
|
||||||
|
clearInterval(checkInterval);
|
||||||
|
$(".copy-btn").attr('disabled', 'disabled')
|
||||||
|
}
|
||||||
|
errorMsgRef.html(data.error)
|
||||||
|
},
|
||||||
|
flash_message: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function initClipboard() {
|
||||||
|
var clipboard = new Clipboard('.btn-copy', {
|
||||||
|
text: function (trigger) {
|
||||||
|
var origin = window.location.origin;
|
||||||
|
var link = origin + $(".btn-copy").data('link');
|
||||||
|
return link
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
clipboard.on("success", function (e) {
|
||||||
|
toastr.success("{% trans "Copy success" %}")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleProgressBar() {
|
||||||
|
var now = new Date().getTime() / 1000;
|
||||||
|
var offset = now - timestamp;
|
||||||
|
var percent = offset / 3600 * 100;
|
||||||
|
if (percent > 100) {
|
||||||
|
percent = 100
|
||||||
}
|
}
|
||||||
{% if auto_redirect %}
|
progressBarRef.css("width", percent + '%');
|
||||||
window.onload = redirect_page;
|
progressBarRef.attr('aria-valuenow', offset);
|
||||||
{% endif %}
|
}
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
interval = setInterval(handleProgressBar, 1000);
|
||||||
|
checkInterval = setInterval(doRequestAuth, 5000);
|
||||||
|
doRequestAuth();
|
||||||
|
initClipboard();
|
||||||
|
}).on('click', '.btn-refresh', function () {
|
||||||
|
window.location.reload();
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,20 +1,15 @@
|
||||||
# coding:utf-8
|
# coding:utf-8
|
||||||
#
|
#
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
from .. import api
|
from .. import api
|
||||||
|
|
||||||
|
app_name = 'authentication'
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
router.register('access-keys', api.AccessKeyViewSet, 'access-key')
|
router.register('access-keys', api.AccessKeyViewSet, 'access-key')
|
||||||
|
|
||||||
|
|
||||||
app_name = 'authentication'
|
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# path('token/', api.UserToken.as_view(), name='user-token'),
|
# path('token/', api.UserToken.as_view(), name='user-token'),
|
||||||
path('auth/', api.UserAuthApi.as_view(), name='user-auth'),
|
path('auth/', api.UserAuthApi.as_view(), name='user-auth'),
|
||||||
|
@ -24,6 +19,7 @@ urlpatterns = [
|
||||||
api.UserConnectionTokenApi.as_view(), name='connection-token'),
|
api.UserConnectionTokenApi.as_view(), name='connection-token'),
|
||||||
path('otp/auth/', api.UserOtpAuthApi.as_view(), name='user-otp-auth'),
|
path('otp/auth/', api.UserOtpAuthApi.as_view(), name='user-otp-auth'),
|
||||||
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.UserOrderAcceptAuthApi.as_view(), name='user-order-auth')
|
||||||
]
|
]
|
||||||
|
|
||||||
urlpatterns += router.urls
|
urlpatterns += router.urls
|
||||||
|
|
|
@ -16,7 +16,7 @@ urlpatterns = [
|
||||||
# login
|
# login
|
||||||
path('login/', views.UserLoginView.as_view(), name='login'),
|
path('login/', views.UserLoginView.as_view(), name='login'),
|
||||||
path('login/otp/', views.UserLoginOtpView.as_view(), name='login-otp'),
|
path('login/otp/', views.UserLoginOtpView.as_view(), name='login-otp'),
|
||||||
path('login/continue/', views.UserLoginContinueView.as_view(), name='login-continue'),
|
path('login/wait-confirm/', views.UserLoginWaitConfirmView.as_view(), name='login-wait-confirm'),
|
||||||
path('login/wait/', views.UserLoginWaitConfirmView.as_view(), name='login-wait'),
|
path('login/guard/', views.UserLoginGuardView.as_view(), name='login-guard'),
|
||||||
path('logout/', views.UserLogoutView.as_view(), name='logout'),
|
path('logout/', views.UserLogoutView.as_view(), name='logout'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _, ugettext_lazy as __
|
||||||
from django.contrib.auth import authenticate
|
from django.contrib.auth import authenticate
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
from common.utils import get_ip_city, get_object_or_none, validate_ip
|
from common.utils import (
|
||||||
|
get_ip_city, get_object_or_none, validate_ip, get_request_ip
|
||||||
|
)
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from . import const
|
from . import const
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import os
|
import os
|
||||||
|
import datetime
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.contrib.auth import login as auth_login, logout as auth_logout
|
from django.contrib.auth import login as auth_login, logout as auth_logout
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
|
@ -12,17 +13,18 @@ from django.utils.translation import ugettext as _
|
||||||
from django.views.decorators.cache import never_cache
|
from django.views.decorators.cache import never_cache
|
||||||
from django.views.decorators.csrf import csrf_protect
|
from django.views.decorators.csrf import csrf_protect
|
||||||
from django.views.decorators.debug import sensitive_post_parameters
|
from django.views.decorators.debug import sensitive_post_parameters
|
||||||
from django.views.generic.base import TemplateView, View, RedirectView
|
from django.views.generic.base import TemplateView, RedirectView
|
||||||
from django.views.generic.edit import FormView
|
from django.views.generic.edit import FormView
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from common.utils import get_request_ip
|
from common.utils import get_request_ip, get_object_or_none
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from users.utils import (
|
from users.utils import (
|
||||||
check_otp_code, is_block_login, clean_failed_count, get_user_or_tmp_user,
|
check_otp_code, is_block_login, clean_failed_count, get_user_or_tmp_user,
|
||||||
set_tmp_user_to_cache, increase_login_failed_count,
|
set_tmp_user_to_cache, increase_login_failed_count,
|
||||||
redirect_user_first_login_or_index,
|
redirect_user_first_login_or_index
|
||||||
)
|
)
|
||||||
|
from ..models import LoginConfirmSetting
|
||||||
from ..signals import post_auth_success, post_auth_failed
|
from ..signals import post_auth_success, post_auth_failed
|
||||||
from .. import forms
|
from .. import forms
|
||||||
from .. import const
|
from .. import const
|
||||||
|
@ -30,7 +32,7 @@ from .. import const
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'UserLoginView', 'UserLoginOtpView', 'UserLogoutView',
|
'UserLoginView', 'UserLoginOtpView', 'UserLogoutView',
|
||||||
'UserLoginContinueView', 'UserLoginWaitConfirmView',
|
'UserLoginGuardView', 'UserLoginWaitConfirmView',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,7 +93,7 @@ class UserLoginView(FormView):
|
||||||
# 登陆成功,清除缓存计数
|
# 登陆成功,清除缓存计数
|
||||||
clean_failed_count(username, ip)
|
clean_failed_count(username, ip)
|
||||||
self.request.session['auth_password'] = '1'
|
self.request.session['auth_password'] = '1'
|
||||||
return self.redirect_to_continue_view()
|
return self.redirect_to_guard_view()
|
||||||
|
|
||||||
def form_invalid(self, form):
|
def form_invalid(self, form):
|
||||||
# write login failed log
|
# write login failed log
|
||||||
|
@ -112,8 +114,8 @@ class UserLoginView(FormView):
|
||||||
return super().form_invalid(form)
|
return super().form_invalid(form)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def redirect_to_continue_view():
|
def redirect_to_guard_view():
|
||||||
continue_url = reverse('authentication:login-continue')
|
continue_url = reverse('authentication:login-guard')
|
||||||
return redirect(continue_url)
|
return redirect(continue_url)
|
||||||
|
|
||||||
def get_form_class(self):
|
def get_form_class(self):
|
||||||
|
@ -144,7 +146,7 @@ class UserLoginOtpView(FormView):
|
||||||
|
|
||||||
if check_otp_code(otp_secret_key, otp_code):
|
if check_otp_code(otp_secret_key, otp_code):
|
||||||
self.request.session['auth_otp'] = '1'
|
self.request.session['auth_otp'] = '1'
|
||||||
return UserLoginView.redirect_to_continue_view()
|
return UserLoginView.redirect_to_guard_view()
|
||||||
else:
|
else:
|
||||||
self.send_auth_signal(
|
self.send_auth_signal(
|
||||||
success=False, username=user.username,
|
success=False, username=user.username,
|
||||||
|
@ -165,7 +167,7 @@ class UserLoginOtpView(FormView):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserLoginContinueView(RedirectView):
|
class UserLoginGuardView(RedirectView):
|
||||||
redirect_field_name = 'next'
|
redirect_field_name = 'next'
|
||||||
|
|
||||||
def get_redirect_url(self, *args, **kwargs):
|
def get_redirect_url(self, *args, **kwargs):
|
||||||
|
@ -173,11 +175,18 @@ class UserLoginContinueView(RedirectView):
|
||||||
return reverse('authentication:login')
|
return reverse('authentication:login')
|
||||||
|
|
||||||
user = get_user_or_tmp_user(self.request)
|
user = get_user_or_tmp_user(self.request)
|
||||||
|
# 启用并设置了otp
|
||||||
if user.otp_enabled and user.otp_secret_key and \
|
if user.otp_enabled and user.otp_secret_key and \
|
||||||
not self.request.session.get('auth_otp'):
|
not self.request.session.get('auth_otp'):
|
||||||
return reverse('authentication:login-otp')
|
return reverse('authentication:login-otp')
|
||||||
|
confirm_setting = LoginConfirmSetting.get_user_confirm_setting(user)
|
||||||
|
if confirm_setting and not self.request.session.get('auth_confirm'):
|
||||||
|
order = confirm_setting.create_confirm_order(self.request)
|
||||||
|
self.request.session['auth_order_id'] = str(order.id)
|
||||||
|
url = reverse('authentication:login-wait-confirm')
|
||||||
|
return url
|
||||||
self.login_success(user)
|
self.login_success(user)
|
||||||
|
# 启用但是没有设置otp
|
||||||
if user.otp_enabled and not user.otp_secret_key:
|
if user.otp_enabled and not user.otp_secret_key:
|
||||||
# 1,2,mfa_setting & F
|
# 1,2,mfa_setting & F
|
||||||
return reverse('users:user-otp-enable-authentication')
|
return reverse('users:user-otp-enable-authentication')
|
||||||
|
@ -204,7 +213,28 @@ class UserLoginWaitConfirmView(TemplateView):
|
||||||
template_name = 'authentication/login_wait_confirm.html'
|
template_name = 'authentication/login_wait_confirm.html'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
return super().get_context_data(**kwargs)
|
from orders.models import LoginConfirmOrder
|
||||||
|
order_id = self.request.session.get("auth_order_id")
|
||||||
|
if not order_id:
|
||||||
|
order = None
|
||||||
|
else:
|
||||||
|
order = get_object_or_none(LoginConfirmOrder, pk=order_id)
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
if order:
|
||||||
|
order_detail_url = reverse('orders:login-confirm-order-detail', kwargs={'pk': order_id})
|
||||||
|
timestamp_created = datetime.datetime.timestamp(order.date_created)
|
||||||
|
msg = _("""Wait for <b>{}</b> confirm, You also can copy link to her/him <br/>
|
||||||
|
Don't close this page""").format(order.assignees_display)
|
||||||
|
else:
|
||||||
|
timestamp_created = 0
|
||||||
|
order_detail_url = ''
|
||||||
|
msg = _("No order found")
|
||||||
|
context.update({
|
||||||
|
"msg": msg,
|
||||||
|
"timestamp": timestamp_created,
|
||||||
|
"order_detail_url": order_detail_url
|
||||||
|
})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(never_cache, name='dispatch')
|
@method_decorator(never_cache, name='dispatch')
|
||||||
|
|
|
@ -13,22 +13,23 @@ from .celery_flower import celery_flower_view
|
||||||
from .swagger import get_swagger_view
|
from .swagger import get_swagger_view
|
||||||
|
|
||||||
api_v1 = [
|
api_v1 = [
|
||||||
path('users/', include('users.urls.api_urls', namespace='api-users')),
|
path('users/', include('users.urls.api_urls', namespace='api-users')),
|
||||||
path('assets/', include('assets.urls.api_urls', namespace='api-assets')),
|
path('assets/', include('assets.urls.api_urls', namespace='api-assets')),
|
||||||
path('perms/', include('perms.urls.api_urls', namespace='api-perms')),
|
path('perms/', include('perms.urls.api_urls', namespace='api-perms')),
|
||||||
path('terminal/', include('terminal.urls.api_urls', namespace='api-terminal')),
|
path('terminal/', include('terminal.urls.api_urls', namespace='api-terminal')),
|
||||||
path('ops/', include('ops.urls.api_urls', namespace='api-ops')),
|
path('ops/', include('ops.urls.api_urls', namespace='api-ops')),
|
||||||
path('audits/', include('audits.urls.api_urls', namespace='api-audits')),
|
path('audits/', include('audits.urls.api_urls', namespace='api-audits')),
|
||||||
path('orgs/', include('orgs.urls.api_urls', namespace='api-orgs')),
|
path('orgs/', include('orgs.urls.api_urls', namespace='api-orgs')),
|
||||||
path('settings/', include('settings.urls.api_urls', namespace='api-settings')),
|
path('settings/', include('settings.urls.api_urls', namespace='api-settings')),
|
||||||
path('authentication/', include('authentication.urls.api_urls', namespace='api-auth')),
|
path('authentication/', include('authentication.urls.api_urls', namespace='api-auth')),
|
||||||
path('common/', include('common.urls.api_urls', namespace='api-common')),
|
path('common/', include('common.urls.api_urls', namespace='api-common')),
|
||||||
path('applications/', include('applications.urls.api_urls', namespace='api-applications')),
|
path('applications/', include('applications.urls.api_urls', namespace='api-applications')),
|
||||||
|
path('orders/', include('orders.urls.api_urls', namespace='api-orders')),
|
||||||
]
|
]
|
||||||
|
|
||||||
api_v2 = [
|
api_v2 = [
|
||||||
path('terminal/', include('terminal.urls.api_urls_v2', namespace='api-terminal-v2')),
|
path('terminal/', include('terminal.urls.api_urls_v2', namespace='api-terminal-v2')),
|
||||||
path('users/', include('users.urls.api_urls_v2', namespace='api-users-v2')),
|
path('users/', include('users.urls.api_urls_v2', namespace='api-users-v2')),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,6 +43,7 @@ app_view_patterns = [
|
||||||
path('orgs/', include('orgs.urls.views_urls', namespace='orgs')),
|
path('orgs/', include('orgs.urls.views_urls', namespace='orgs')),
|
||||||
path('auth/', include('authentication.urls.view_urls'), name='auth'),
|
path('auth/', include('authentication.urls.view_urls'), name='auth'),
|
||||||
path('applications/', include('applications.urls.views_urls', namespace='applications')),
|
path('applications/', include('applications.urls.views_urls', namespace='applications')),
|
||||||
|
path('orders/', include('orders.urls.views_urls', namespace='orders')),
|
||||||
re_path(r'flower/(?P<path>.*)', celery_flower_view, name='flower-view'),
|
re_path(r'flower/(?P<path>.*)', celery_flower_view, name='flower-view'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -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-10-25 10:52+0800\n"
|
"POT-Creation-Date: 2019-10-30 11:52+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"
|
||||||
|
@ -144,7 +144,7 @@ msgstr "资产"
|
||||||
#: settings/templates/settings/terminal_setting.html:105 terminal/models.py:23
|
#: settings/templates/settings/terminal_setting.html:105 terminal/models.py:23
|
||||||
#: terminal/models.py:260 terminal/templates/terminal/terminal_detail.html:43
|
#: terminal/models.py:260 terminal/templates/terminal/terminal_detail.html:43
|
||||||
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14
|
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14
|
||||||
#: users/models/user.py:373 users/templates/users/_select_user_modal.html:13
|
#: users/models/user.py:375 users/templates/users/_select_user_modal.html:13
|
||||||
#: users/templates/users/user_detail.html:63
|
#: users/templates/users/user_detail.html:63
|
||||||
#: users/templates/users/user_group_detail.html:55
|
#: users/templates/users/user_group_detail.html:55
|
||||||
#: users/templates/users/user_group_list.html:35
|
#: users/templates/users/user_group_list.html:35
|
||||||
|
@ -197,7 +197,7 @@ msgstr "参数"
|
||||||
#: orgs/models.py:16 perms/models/base.py:54
|
#: orgs/models.py:16 perms/models/base.py:54
|
||||||
#: perms/templates/perms/asset_permission_detail.html:98
|
#: perms/templates/perms/asset_permission_detail.html:98
|
||||||
#: perms/templates/perms/remote_app_permission_detail.html:90
|
#: perms/templates/perms/remote_app_permission_detail.html:90
|
||||||
#: users/models/user.py:414 users/serializers/v1.py:143
|
#: users/models/user.py:416 users/serializers/group.py:32
|
||||||
#: users/templates/users/user_detail.html:111
|
#: users/templates/users/user_detail.html:111
|
||||||
#: xpack/plugins/change_auth_plan/models.py:108
|
#: 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
|
||||||
|
@ -219,7 +219,8 @@ 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
|
||||||
#: orgs/models.py:17 perms/models/base.py:55
|
#: orders/templates/orders/login_confirm_order_detail.html:60 orgs/models.py:17
|
||||||
|
#: 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 users/models/group.py:17
|
||||||
|
@ -253,12 +254,14 @@ 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
|
||||||
#: orgs/models.py:18 perms/models/base.py:56
|
#: orders/serializers.py:23
|
||||||
|
#: 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 users/models/group.py:15
|
||||||
#: users/models/user.py:406 users/templates/users/user_detail.html:129
|
#: users/models/user.py:408 users/templates/users/user_detail.html:129
|
||||||
#: 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
|
||||||
|
@ -516,6 +519,7 @@ 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
|
||||||
|
@ -699,12 +703,12 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC"
|
||||||
#: assets/templates/assets/system_user_list.html:48 audits/models.py:80
|
#: assets/templates/assets/system_user_list.html:48 audits/models.py:80
|
||||||
#: 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:65
|
#: authentication/templates/authentication/login.html:65
|
||||||
#: authentication/templates/authentication/new_login.html:92
|
#: authentication/templates/authentication/xpack_login.html:92
|
||||||
#: 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:13
|
||||||
#: users/models/user.py:371 users/templates/users/_select_user_modal.html:14
|
#: users/models/user.py:373 users/templates/users/_select_user_modal.html:14
|
||||||
#: users/templates/users/user_detail.html:67
|
#: users/templates/users/user_detail.html:67
|
||||||
#: 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
|
||||||
|
@ -729,7 +733,7 @@ msgstr "密码或密钥密码"
|
||||||
#: assets/templates/assets/_asset_user_auth_view_modal.html:27
|
#: assets/templates/assets/_asset_user_auth_view_modal.html:27
|
||||||
#: authentication/forms.py:15
|
#: authentication/forms.py:15
|
||||||
#: authentication/templates/authentication/login.html:68
|
#: authentication/templates/authentication/login.html:68
|
||||||
#: authentication/templates/authentication/new_login.html:95
|
#: authentication/templates/authentication/xpack_login.html:95
|
||||||
#: settings/forms.py:114 users/forms.py:15 users/forms.py:27
|
#: settings/forms.py:114 users/forms.py:15 users/forms.py:27
|
||||||
#: 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
|
||||||
|
@ -744,7 +748,7 @@ msgstr "密码"
|
||||||
|
|
||||||
#: assets/forms/user.py:30 assets/serializers/asset_user.py:71
|
#: assets/forms/user.py:30 assets/serializers/asset_user.py:71
|
||||||
#: assets/templates/assets/_asset_user_auth_update_modal.html:27
|
#: assets/templates/assets/_asset_user_auth_update_modal.html:27
|
||||||
#: users/models/user.py:400
|
#: users/models/user.py:402
|
||||||
msgid "Private key"
|
msgid "Private key"
|
||||||
msgstr "ssh私钥"
|
msgstr "ssh私钥"
|
||||||
|
|
||||||
|
@ -793,6 +797,8 @@ 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:15
|
||||||
#: 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
|
||||||
|
@ -842,6 +848,7 @@ msgstr "系统平台"
|
||||||
#: assets/models/asset.py:146 assets/models/authbook.py:27
|
#: assets/models/asset.py:146 assets/models/authbook.py:27
|
||||||
#: assets/models/cmd_filter.py:22 assets/models/domain.py:54
|
#: assets/models/cmd_filter.py:22 assets/models/domain.py:54
|
||||||
#: assets/models/label.py:22 assets/templates/assets/asset_detail.html:110
|
#: assets/models/label.py:22 assets/templates/assets/asset_detail.html:110
|
||||||
|
#: authentication/models.py:45
|
||||||
msgid "Is active"
|
msgid "Is active"
|
||||||
msgstr "激活"
|
msgstr "激活"
|
||||||
|
|
||||||
|
@ -957,7 +964,7 @@ msgstr "带宽"
|
||||||
msgid "Contact"
|
msgid "Contact"
|
||||||
msgstr "联系人"
|
msgstr "联系人"
|
||||||
|
|
||||||
#: assets/models/cluster.py:22 users/models/user.py:392
|
#: assets/models/cluster.py:22 users/models/user.py:394
|
||||||
#: users/templates/users/user_detail.html:76
|
#: users/templates/users/user_detail.html:76
|
||||||
msgid "Phone"
|
msgid "Phone"
|
||||||
msgstr "手机"
|
msgstr "手机"
|
||||||
|
@ -983,7 +990,7 @@ msgid "Default"
|
||||||
msgstr "默认"
|
msgstr "默认"
|
||||||
|
|
||||||
#: assets/models/cluster.py:36 assets/models/label.py:14
|
#: assets/models/cluster.py:36 assets/models/label.py:14
|
||||||
#: users/models/user.py:512
|
#: users/models/user.py:514
|
||||||
msgid "System"
|
msgid "System"
|
||||||
msgstr "系统"
|
msgstr "系统"
|
||||||
|
|
||||||
|
@ -1011,7 +1018,7 @@ msgstr "BGP全网通"
|
||||||
msgid "Regex"
|
msgid "Regex"
|
||||||
msgstr "正则表达式"
|
msgstr "正则表达式"
|
||||||
|
|
||||||
#: assets/models/cmd_filter.py:40 ops/models/command.py:21
|
#: assets/models/cmd_filter.py:40 ops/models/command.py:22
|
||||||
#: ops/templates/ops/command_execution_list.html:64 terminal/models.py:163
|
#: ops/templates/ops/command_execution_list.html:64 terminal/models.py:163
|
||||||
#: terminal/templates/terminal/command_list.html:28
|
#: terminal/templates/terminal/command_list.html:28
|
||||||
#: terminal/templates/terminal/command_list.html:68
|
#: terminal/templates/terminal/command_list.html:68
|
||||||
|
@ -1034,7 +1041,7 @@ 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
|
#: audits/templates/audits/login_log_list.html:58 orders/models.py:41
|
||||||
#: 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
|
||||||
|
@ -1097,8 +1104,11 @@ msgstr "默认资产组"
|
||||||
#: audits/templates/audits/operate_log_list.html:72
|
#: audits/templates/audits/operate_log_list.html:72
|
||||||
#: 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
|
||||||
#: 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
|
#: ops/templates/ops/command_execution_list.html:63 orders/models.py:11
|
||||||
|
#: orders/models.py:32
|
||||||
|
#: orders/templates/orders/login_confirm_order_detail.html:32
|
||||||
|
#: orders/templates/orders/login_confirm_order_list.html:14
|
||||||
#: 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
|
||||||
|
@ -1111,8 +1121,9 @@ msgstr "默认资产组"
|
||||||
#: 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 users/forms.py:319
|
||||||
#: users/models/user.py:127 users/models/user.py:143 users/models/user.py:500
|
#: users/models/user.py:129 users/models/user.py:145 users/models/user.py:502
|
||||||
#: users/serializers/v1.py:132 users/templates/users/user_group_detail.html:78
|
#: users/serializers/group.py:21
|
||||||
|
#: users/templates/users/user_group_detail.html:78
|
||||||
#: users/templates/users/user_group_list.html:36 users/views/user.py:250
|
#: users/templates/users/user_group_list.html:36 users/views/user.py:250
|
||||||
#: xpack/plugins/orgs/forms.py:28
|
#: xpack/plugins/orgs/forms.py:28
|
||||||
#: xpack/plugins/orgs/templates/orgs/org_detail.html:113
|
#: xpack/plugins/orgs/templates/orgs/org_detail.html:113
|
||||||
|
@ -1235,7 +1246,7 @@ msgid "Reachable"
|
||||||
msgstr "可连接"
|
msgstr "可连接"
|
||||||
|
|
||||||
#: assets/models/utils.py:45 assets/tasks/const.py:86
|
#: assets/models/utils.py:45 assets/tasks/const.py:86
|
||||||
#: authentication/utils.py:13 xpack/plugins/license/models.py:78
|
#: authentication/utils.py:16 xpack/plugins/license/models.py:78
|
||||||
msgid "Unknown"
|
msgid "Unknown"
|
||||||
msgstr "未知"
|
msgstr "未知"
|
||||||
|
|
||||||
|
@ -1266,7 +1277,7 @@ msgid "Backend"
|
||||||
msgstr "后端"
|
msgstr "后端"
|
||||||
|
|
||||||
#: assets/serializers/asset_user.py:67 users/forms.py:262
|
#: assets/serializers/asset_user.py:67 users/forms.py:262
|
||||||
#: users/models/user.py:403 users/templates/users/first_login.html:42
|
#: users/models/user.py:405 users/templates/users/first_login.html:42
|
||||||
#: users/templates/users/user_password_update.html:49
|
#: users/templates/users/user_password_update.html:49
|
||||||
#: users/templates/users/user_profile.html:69
|
#: users/templates/users/user_profile.html:69
|
||||||
#: users/templates/users/user_profile_update.html:46
|
#: users/templates/users/user_profile_update.html:46
|
||||||
|
@ -1470,6 +1481,7 @@ msgid "Asset user auth"
|
||||||
msgstr "资产用户信息"
|
msgstr "资产用户信息"
|
||||||
|
|
||||||
#: assets/templates/assets/_asset_user_auth_view_modal.html:54
|
#: assets/templates/assets/_asset_user_auth_view_modal.html:54
|
||||||
|
#: authentication/templates/authentication/login_wait_confirm.html:117
|
||||||
msgid "Copy success"
|
msgid "Copy success"
|
||||||
msgstr "复制成功"
|
msgstr "复制成功"
|
||||||
|
|
||||||
|
@ -1490,6 +1502,7 @@ 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
|
||||||
msgid "Datetime"
|
msgid "Datetime"
|
||||||
|
@ -1768,7 +1781,7 @@ msgstr "硬盘"
|
||||||
msgid "Date joined"
|
msgid "Date joined"
|
||||||
msgstr "创建日期"
|
msgstr "创建日期"
|
||||||
|
|
||||||
#: assets/templates/assets/asset_detail.html:148 authentication/models.py:15
|
#: assets/templates/assets/asset_detail.html:148 authentication/models.py:19
|
||||||
#: authentication/templates/authentication/_access_key_modal.html:32
|
#: authentication/templates/authentication/_access_key_modal.html:32
|
||||||
#: perms/models/base.py:51
|
#: perms/models/base.py:51
|
||||||
#: perms/templates/perms/asset_permission_create_update.html:55
|
#: perms/templates/perms/asset_permission_create_update.html:55
|
||||||
|
@ -1787,6 +1800,7 @@ msgid "Refresh hardware"
|
||||||
msgstr "更新硬件信息"
|
msgstr "更新硬件信息"
|
||||||
|
|
||||||
#: assets/templates/assets/asset_detail.html:168
|
#: assets/templates/assets/asset_detail.html:168
|
||||||
|
#: authentication/templates/authentication/login_wait_confirm.html:42
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "刷新"
|
msgstr "刷新"
|
||||||
|
|
||||||
|
@ -2264,7 +2278,7 @@ msgstr "Agent"
|
||||||
|
|
||||||
#: audits/models.py:85 audits/templates/audits/login_log_list.html:62
|
#: audits/models.py:85 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:395
|
#: users/forms.py:174 users/models/user.py:397
|
||||||
#: users/templates/users/first_login.html:45
|
#: users/templates/users/first_login.html:45
|
||||||
msgid "MFA"
|
msgid "MFA"
|
||||||
msgstr "MFA"
|
msgstr "MFA"
|
||||||
|
@ -2278,6 +2292,8 @@ msgid "Reason"
|
||||||
msgstr "原因"
|
msgstr "原因"
|
||||||
|
|
||||||
#: audits/models.py:87 audits/templates/audits/login_log_list.html:64
|
#: audits/models.py:87 audits/templates/audits/login_log_list.html:64
|
||||||
|
#: orders/templates/orders/login_confirm_order_detail.html:35
|
||||||
|
#: orders/templates/orders/login_confirm_order_list.html:17
|
||||||
#: 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
|
||||||
|
@ -2338,6 +2354,8 @@ 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
|
||||||
|
#: orders/templates/orders/login_confirm_order_list.html:16
|
||||||
msgid "City"
|
msgid "City"
|
||||||
msgstr "城市"
|
msgstr "城市"
|
||||||
|
|
||||||
|
@ -2348,23 +2366,23 @@ msgid "Date"
|
||||||
msgstr "日期"
|
msgstr "日期"
|
||||||
|
|
||||||
#: audits/views.py:86 audits/views.py:130 audits/views.py:167
|
#: audits/views.py:86 audits/views.py:130 audits/views.py:167
|
||||||
#: audits/views.py:212 audits/views.py:244 templates/_nav.html:129
|
#: audits/views.py:212 audits/views.py:244 templates/_nav.html:139
|
||||||
msgid "Audits"
|
msgid "Audits"
|
||||||
msgstr "日志审计"
|
msgstr "日志审计"
|
||||||
|
|
||||||
#: audits/views.py:87 templates/_nav.html:133
|
#: audits/views.py:87 templates/_nav.html:143
|
||||||
msgid "FTP log"
|
msgid "FTP log"
|
||||||
msgstr "FTP日志"
|
msgstr "FTP日志"
|
||||||
|
|
||||||
#: audits/views.py:131 templates/_nav.html:134
|
#: audits/views.py:131 templates/_nav.html:144
|
||||||
msgid "Operate log"
|
msgid "Operate log"
|
||||||
msgstr "操作日志"
|
msgstr "操作日志"
|
||||||
|
|
||||||
#: audits/views.py:168 templates/_nav.html:135
|
#: audits/views.py:168 templates/_nav.html:145
|
||||||
msgid "Password change log"
|
msgid "Password change log"
|
||||||
msgstr "改密日志"
|
msgstr "改密日志"
|
||||||
|
|
||||||
#: audits/views.py:213 templates/_nav.html:132
|
#: audits/views.py:213 templates/_nav.html:142
|
||||||
msgid "Login log"
|
msgid "Login log"
|
||||||
msgstr "登录日志"
|
msgstr "登录日志"
|
||||||
|
|
||||||
|
@ -2372,25 +2390,33 @@ msgstr "登录日志"
|
||||||
msgid "Command execution log"
|
msgid "Command execution log"
|
||||||
msgstr "命令执行"
|
msgstr "命令执行"
|
||||||
|
|
||||||
#: authentication/api/auth.py:61 authentication/api/token.py:45
|
#: authentication/api/auth.py:58 authentication/api/token.py:45
|
||||||
#: authentication/templates/authentication/login.html:52
|
#: authentication/templates/authentication/login.html:52
|
||||||
#: authentication/templates/authentication/new_login.html:77
|
#: authentication/templates/authentication/xpack_login.html:77
|
||||||
msgid "Log in frequently and try again later"
|
msgid "Log in frequently and try again later"
|
||||||
msgstr "登录频繁, 稍后重试"
|
msgstr "登录频繁, 稍后重试"
|
||||||
|
|
||||||
#: authentication/api/auth.py:86
|
#: authentication/api/auth.py:83
|
||||||
msgid "Please carry seed value and conduct MFA secondary certification"
|
msgid "Please carry seed value and conduct MFA secondary certification"
|
||||||
msgstr "请携带seed值, 进行MFA二次认证"
|
msgstr "请携带seed值, 进行MFA二次认证"
|
||||||
|
|
||||||
#: authentication/api/auth.py:176
|
#: authentication/api/auth.py:173
|
||||||
msgid "Please verify the user name and password first"
|
msgid "Please verify the user name and password first"
|
||||||
msgstr "请先进行用户名和密码验证"
|
msgstr "请先进行用户名和密码验证"
|
||||||
|
|
||||||
#: authentication/api/auth.py:181
|
#: authentication/api/auth.py:178
|
||||||
msgid "MFA certification failed"
|
msgid "MFA certification failed"
|
||||||
msgstr "MFA认证失败"
|
msgstr "MFA认证失败"
|
||||||
|
|
||||||
#: authentication/api/token.py:80
|
#: authentication/api/auth.py:222
|
||||||
|
msgid "No order found or order expired"
|
||||||
|
msgstr "没有找到工单,或者已过期"
|
||||||
|
|
||||||
|
#: authentication/api/auth.py:228
|
||||||
|
msgid "Order was rejected by {}"
|
||||||
|
msgstr "工单被拒绝 {}"
|
||||||
|
|
||||||
|
#: authentication/api/token.py:81
|
||||||
msgid "MFA required"
|
msgid "MFA required"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -2491,10 +2517,38 @@ msgstr "账号已被锁定(请联系管理员解锁 或 {}分钟后重试)"
|
||||||
msgid "MFA code"
|
msgid "MFA code"
|
||||||
msgstr "MFA 验证码"
|
msgstr "MFA 验证码"
|
||||||
|
|
||||||
#: authentication/models.py:35
|
#: authentication/models.py:39
|
||||||
msgid "Private Token"
|
msgid "Private Token"
|
||||||
msgstr "ssh密钥"
|
msgstr "ssh密钥"
|
||||||
|
|
||||||
|
#: authentication/models.py:43
|
||||||
|
msgid "login_confirmation_setting"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: authentication/models.py:44
|
||||||
|
msgid "Reviewers"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: authentication/models.py:44
|
||||||
|
msgid "review_login_confirmation_settings"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: authentication/models.py:53
|
||||||
|
msgid "User login request: {}"
|
||||||
|
msgstr "用户登录请求: {}"
|
||||||
|
|
||||||
|
#: authentication/models.py:57
|
||||||
|
msgid ""
|
||||||
|
"User: {}\n"
|
||||||
|
"IP: {}\n"
|
||||||
|
"City: {}\n"
|
||||||
|
"Date: {}\n"
|
||||||
|
msgstr ""
|
||||||
|
"用户: {}\n"
|
||||||
|
"IP: {}\n"
|
||||||
|
"城市: {}\n"
|
||||||
|
"日期: {}\n"
|
||||||
|
|
||||||
#: authentication/templates/authentication/_access_key_modal.html:6
|
#: authentication/templates/authentication/_access_key_modal.html:6
|
||||||
msgid "API key list"
|
msgid "API key list"
|
||||||
msgstr "API Key列表"
|
msgstr "API Key列表"
|
||||||
|
@ -2517,14 +2571,14 @@ msgid "Show"
|
||||||
msgstr "显示"
|
msgstr "显示"
|
||||||
|
|
||||||
#: authentication/templates/authentication/_access_key_modal.html:66
|
#: authentication/templates/authentication/_access_key_modal.html:66
|
||||||
#: users/models/user.py:330 users/templates/users/user_profile.html:94
|
#: users/models/user.py:332 users/templates/users/user_profile.html:94
|
||||||
#: users/templates/users/user_profile.html:163
|
#: users/templates/users/user_profile.html:163
|
||||||
#: users/templates/users/user_profile.html:166
|
#: users/templates/users/user_profile.html:166
|
||||||
msgid "Disable"
|
msgid "Disable"
|
||||||
msgstr "禁用"
|
msgstr "禁用"
|
||||||
|
|
||||||
#: authentication/templates/authentication/_access_key_modal.html:67
|
#: authentication/templates/authentication/_access_key_modal.html:67
|
||||||
#: users/models/user.py:331 users/templates/users/user_profile.html:92
|
#: users/models/user.py:333 users/templates/users/user_profile.html:92
|
||||||
#: users/templates/users/user_profile.html:170
|
#: users/templates/users/user_profile.html:170
|
||||||
msgid "Enable"
|
msgid "Enable"
|
||||||
msgstr "启用"
|
msgstr "启用"
|
||||||
|
@ -2586,23 +2640,23 @@ msgstr "改变世界,从一点点开始。"
|
||||||
|
|
||||||
#: authentication/templates/authentication/login.html:46
|
#: authentication/templates/authentication/login.html:46
|
||||||
#: authentication/templates/authentication/login.html:73
|
#: authentication/templates/authentication/login.html:73
|
||||||
#: authentication/templates/authentication/new_login.html:101
|
#: authentication/templates/authentication/xpack_login.html:101
|
||||||
#: templates/_header_bar.html:83
|
#: templates/_header_bar.html:83
|
||||||
msgid "Login"
|
msgid "Login"
|
||||||
msgstr "登录"
|
msgstr "登录"
|
||||||
|
|
||||||
#: authentication/templates/authentication/login.html:54
|
#: authentication/templates/authentication/login.html:54
|
||||||
#: authentication/templates/authentication/new_login.html:80
|
#: authentication/templates/authentication/xpack_login.html:80
|
||||||
msgid "The user password has expired"
|
msgid "The user password has expired"
|
||||||
msgstr "用户密码已过期"
|
msgstr "用户密码已过期"
|
||||||
|
|
||||||
#: authentication/templates/authentication/login.html:57
|
#: authentication/templates/authentication/login.html:57
|
||||||
#: authentication/templates/authentication/new_login.html:83
|
#: authentication/templates/authentication/xpack_login.html:83
|
||||||
msgid "Captcha invalid"
|
msgid "Captcha invalid"
|
||||||
msgstr "验证码错误"
|
msgstr "验证码错误"
|
||||||
|
|
||||||
#: authentication/templates/authentication/login.html:84
|
#: authentication/templates/authentication/login.html:84
|
||||||
#: authentication/templates/authentication/new_login.html:105
|
#: authentication/templates/authentication/xpack_login.html:105
|
||||||
#: 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"
|
||||||
|
@ -2653,24 +2707,45 @@ msgstr "下一步"
|
||||||
msgid "Can't provide security? Please contact the administrator!"
|
msgid "Can't provide security? Please contact the administrator!"
|
||||||
msgstr "如果不能提供MFA验证码,请联系管理员!"
|
msgstr "如果不能提供MFA验证码,请联系管理员!"
|
||||||
|
|
||||||
#: authentication/templates/authentication/new_login.html:67
|
#: authentication/templates/authentication/login_wait_confirm.html:47
|
||||||
|
msgid "Copy link"
|
||||||
|
msgstr "复制链接"
|
||||||
|
|
||||||
|
#: authentication/templates/authentication/login_wait_confirm.html:52
|
||||||
|
#: templates/flash_message_standalone.html:47
|
||||||
|
msgid "Return"
|
||||||
|
msgstr "返回"
|
||||||
|
|
||||||
|
#: authentication/templates/authentication/xpack_login.html:67
|
||||||
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:81
|
#: authentication/views/login.py:82
|
||||||
msgid "Please enable cookies and try again."
|
msgid "Please enable cookies and try again."
|
||||||
msgstr "设置你的浏览器支持cookie"
|
msgstr "设置你的浏览器支持cookie"
|
||||||
|
|
||||||
#: authentication/views/login.py:174 users/views/user.py:393
|
#: authentication/views/login.py:156 users/views/user.py:393
|
||||||
#: users/views/user.py:418
|
#: 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/views/login.py:205
|
#: authentication/views/login.py:226
|
||||||
|
msgid ""
|
||||||
|
"Wait for <b>{}</b> confirm, You also can copy link to her/him <br/>\n"
|
||||||
|
" Don't close this page"
|
||||||
|
msgstr ""
|
||||||
|
"等待 <b>{}</b> 确认, 你也可以复制链接发给他/她 <br/>\n"
|
||||||
|
" 不要关闭本页面"
|
||||||
|
|
||||||
|
#: authentication/views/login.py:231
|
||||||
|
msgid "No order found"
|
||||||
|
msgstr "没有发现工单"
|
||||||
|
|
||||||
|
#: authentication/views/login.py:254
|
||||||
msgid "Logout success"
|
msgid "Logout success"
|
||||||
msgstr "退出登录成功"
|
msgstr "退出登录成功"
|
||||||
|
|
||||||
#: authentication/views/login.py:206
|
#: authentication/views/login.py:255
|
||||||
msgid "Logout success, return login page"
|
msgid "Logout success, return login page"
|
||||||
msgstr "退出登录成功,返回到登录页面"
|
msgstr "退出登录成功,返回到登录页面"
|
||||||
|
|
||||||
|
@ -2757,6 +2832,21 @@ msgstr ""
|
||||||
msgid "Websocket server run on port: {}, you should proxy it on nginx"
|
msgid "Websocket server run on port: {}, you should proxy it on nginx"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: jumpserver/views.py:241
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid ""
|
||||||
|
#| "<div>Luna is a separately deployed program, you need to deploy Luna, "
|
||||||
|
#| "koko, configure nginx for url distribution,</div> </div>If you see this "
|
||||||
|
#| "page, prove that you are not accessing the nginx listening port. Good "
|
||||||
|
#| "luck.</div>"
|
||||||
|
msgid ""
|
||||||
|
"<div>Koko is a separately deployed program, you need to deploy Koko, "
|
||||||
|
"configure nginx for url distribution,</div> </div>If you see this page, "
|
||||||
|
"prove that you are not accessing the nginx listening port. Good luck.</div>"
|
||||||
|
msgstr ""
|
||||||
|
"<div>Luna是单独部署的一个程序,你需要部署luna,koko, </div><div>如果你看到了"
|
||||||
|
"这个页面,证明你访问的不是nginx监听的端口,祝你好运</div>"
|
||||||
|
|
||||||
#: ops/api/celery.py:54
|
#: ops/api/celery.py:54
|
||||||
msgid "Waiting task start"
|
msgid "Waiting task start"
|
||||||
msgstr "等待任务开始"
|
msgstr "等待任务开始"
|
||||||
|
@ -2872,21 +2962,21 @@ msgstr "结果"
|
||||||
msgid "Adhoc result summary"
|
msgid "Adhoc result summary"
|
||||||
msgstr "汇总"
|
msgstr "汇总"
|
||||||
|
|
||||||
#: ops/models/command.py:22
|
#: ops/models/command.py:23
|
||||||
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:56
|
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:56
|
||||||
#: xpack/plugins/cloud/models.py:273
|
#: xpack/plugins/cloud/models.py:273
|
||||||
msgid "Result"
|
msgid "Result"
|
||||||
msgstr "结果"
|
msgstr "结果"
|
||||||
|
|
||||||
#: ops/models/command.py:57
|
#: ops/models/command.py:58
|
||||||
msgid "Task start"
|
msgid "Task start"
|
||||||
msgstr "任务开始"
|
msgstr "任务开始"
|
||||||
|
|
||||||
#: ops/models/command.py:71
|
#: ops/models/command.py:75
|
||||||
msgid "Command `{}` is forbidden ........"
|
msgid "Command `{}` is forbidden ........"
|
||||||
msgstr "命令 `{}` 不允许被执行 ......."
|
msgstr "命令 `{}` 不允许被执行 ......."
|
||||||
|
|
||||||
#: ops/models/command.py:77
|
#: ops/models/command.py:81
|
||||||
msgid "Task end"
|
msgid "Task end"
|
||||||
msgstr "任务结束"
|
msgstr "任务结束"
|
||||||
|
|
||||||
|
@ -3028,7 +3118,7 @@ msgstr "没有输入命令"
|
||||||
msgid "No system user was selected"
|
msgid "No system user was selected"
|
||||||
msgstr "没有选择系统用户"
|
msgstr "没有选择系统用户"
|
||||||
|
|
||||||
#: ops/templates/ops/command_execution_create.html:296
|
#: ops/templates/ops/command_execution_create.html:296 orders/models.py:26
|
||||||
msgid "Pending"
|
msgid "Pending"
|
||||||
msgstr "等待"
|
msgstr "等待"
|
||||||
|
|
||||||
|
@ -3112,7 +3202,93 @@ msgstr "命令执行列表"
|
||||||
msgid "Command execution"
|
msgid "Command execution"
|
||||||
msgstr "命令执行"
|
msgstr "命令执行"
|
||||||
|
|
||||||
#: orgs/mixins/models.py:58 orgs/mixins/serializers.py:26 orgs/models.py:31
|
#: orders/models.py:12 orders/models.py:33
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "User is inactive"
|
||||||
|
msgid "User display name"
|
||||||
|
msgstr "用户已禁用"
|
||||||
|
|
||||||
|
#: orders/models.py:13 orders/models.py:36
|
||||||
|
msgid "Body"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: orders/models.py:24
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Accept"
|
||||||
|
msgid "Accepted"
|
||||||
|
msgstr "接受"
|
||||||
|
|
||||||
|
#: orders/models.py:25
|
||||||
|
msgid "Rejected"
|
||||||
|
msgstr "拒绝"
|
||||||
|
|
||||||
|
#: orders/models.py:35 orders/templates/orders/login_confirm_order_list.html:13
|
||||||
|
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:53
|
||||||
|
#: 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:54
|
||||||
|
#: 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/templates/orders/login_confirm_order_list.html:83
|
||||||
|
#: users/templates/users/user_list.html:327
|
||||||
|
msgid "User is expired"
|
||||||
|
msgstr "用户已失效"
|
||||||
|
|
||||||
|
#: orders/templates/orders/login_confirm_order_list.html:86
|
||||||
|
#: users/templates/users/user_list.html:330
|
||||||
|
msgid "User is inactive"
|
||||||
|
msgstr "用户已禁用"
|
||||||
|
|
||||||
|
#: orders/views.py:15 orders/views.py:31 templates/_nav.html:127
|
||||||
|
msgid "Orders"
|
||||||
|
msgstr "工单管理"
|
||||||
|
|
||||||
|
#: orders/views.py:16
|
||||||
|
msgid "Login confirm order list"
|
||||||
|
msgstr "登录复核工单列表"
|
||||||
|
|
||||||
|
#: orders/views.py:32
|
||||||
|
msgid "Login confirm order detail"
|
||||||
|
msgstr "登录复核工单详情"
|
||||||
|
|
||||||
|
#: orgs/mixins/models.py:44 orgs/mixins/serializers.py:26 orgs/models.py:31
|
||||||
msgid "Organization"
|
msgid "Organization"
|
||||||
msgstr "组织"
|
msgstr "组织"
|
||||||
|
|
||||||
|
@ -3136,7 +3312,7 @@ msgstr "提示:RDP 协议不支持单独控制上传或下载文件"
|
||||||
#: perms/templates/perms/asset_permission_list.html:118
|
#: perms/templates/perms/asset_permission_list.html:118
|
||||||
#: perms/templates/perms/remote_app_permission_list.html:16
|
#: perms/templates/perms/remote_app_permission_list.html:16
|
||||||
#: templates/_nav.html:21 users/forms.py:293 users/models/group.py:26
|
#: templates/_nav.html:21 users/forms.py:293 users/models/group.py:26
|
||||||
#: users/models/user.py:379 users/templates/users/_select_user_modal.html:16
|
#: users/models/user.py:381 users/templates/users/_select_user_modal.html:16
|
||||||
#: users/templates/users/user_detail.html:218
|
#: users/templates/users/user_detail.html:218
|
||||||
#: users/templates/users/user_list.html:38
|
#: users/templates/users/user_list.html:38
|
||||||
#: xpack/plugins/orgs/templates/orgs/org_list.html:16
|
#: xpack/plugins/orgs/templates/orgs/org_list.html:16
|
||||||
|
@ -3178,7 +3354,7 @@ msgstr "资产授权"
|
||||||
#: perms/models/base.py:53
|
#: perms/models/base.py:53
|
||||||
#: perms/templates/perms/asset_permission_detail.html:90
|
#: perms/templates/perms/asset_permission_detail.html:90
|
||||||
#: perms/templates/perms/remote_app_permission_detail.html:82
|
#: perms/templates/perms/remote_app_permission_detail.html:82
|
||||||
#: users/models/user.py:411 users/templates/users/user_detail.html:107
|
#: users/models/user.py:413 users/templates/users/user_detail.html:107
|
||||||
#: users/templates/users/user_profile.html:120
|
#: users/templates/users/user_profile.html:120
|
||||||
msgid "Date expired"
|
msgid "Date expired"
|
||||||
msgstr "失效日期"
|
msgstr "失效日期"
|
||||||
|
@ -3742,7 +3918,7 @@ msgid "Please submit the LDAP configuration before import"
|
||||||
msgstr "请先提交LDAP配置再进行导入"
|
msgstr "请先提交LDAP配置再进行导入"
|
||||||
|
|
||||||
#: settings/templates/settings/_ldap_list_users_modal.html:32
|
#: settings/templates/settings/_ldap_list_users_modal.html:32
|
||||||
#: users/models/user.py:375 users/templates/users/user_detail.html:71
|
#: users/models/user.py:377 users/templates/users/user_detail.html:71
|
||||||
#: users/templates/users/user_profile.html:59
|
#: users/templates/users/user_profile.html:59
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "邮件"
|
msgstr "邮件"
|
||||||
|
@ -3946,7 +4122,7 @@ msgstr "用户来源不是LDAP"
|
||||||
|
|
||||||
#: settings/views.py:19 settings/views.py:46 settings/views.py:73
|
#: settings/views.py:19 settings/views.py:46 settings/views.py:73
|
||||||
#: settings/views.py:103 settings/views.py:131 settings/views.py:144
|
#: settings/views.py:103 settings/views.py:131 settings/views.py:144
|
||||||
#: settings/views.py:158 settings/views.py:185 templates/_nav.html:170
|
#: settings/views.py:158 settings/views.py:185 templates/_nav.html:180
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "系统设置"
|
msgstr "系统设置"
|
||||||
|
|
||||||
|
@ -4139,7 +4315,7 @@ msgstr "终端管理"
|
||||||
msgid "Job Center"
|
msgid "Job Center"
|
||||||
msgstr "作业中心"
|
msgstr "作业中心"
|
||||||
|
|
||||||
#: templates/_nav.html:116 templates/_nav.html:136
|
#: templates/_nav.html:116 templates/_nav.html:146
|
||||||
msgid "Batch command"
|
msgid "Batch command"
|
||||||
msgstr "批量命令"
|
msgstr "批量命令"
|
||||||
|
|
||||||
|
@ -4147,15 +4323,19 @@ msgstr "批量命令"
|
||||||
msgid "Task monitor"
|
msgid "Task monitor"
|
||||||
msgstr "任务监控"
|
msgstr "任务监控"
|
||||||
|
|
||||||
#: templates/_nav.html:146
|
#: templates/_nav.html:130
|
||||||
|
msgid "Login confirm"
|
||||||
|
msgstr "登录复核"
|
||||||
|
|
||||||
|
#: templates/_nav.html:156
|
||||||
msgid "XPack"
|
msgid "XPack"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/_nav.html:154 xpack/plugins/cloud/views.py:28
|
#: templates/_nav.html:164 xpack/plugins/cloud/views.py:28
|
||||||
msgid "Account list"
|
msgid "Account list"
|
||||||
msgstr "账户列表"
|
msgstr "账户列表"
|
||||||
|
|
||||||
#: templates/_nav.html:155
|
#: templates/_nav.html:165
|
||||||
msgid "Sync instance"
|
msgid "Sync instance"
|
||||||
msgstr "同步实例"
|
msgstr "同步实例"
|
||||||
|
|
||||||
|
@ -4184,10 +4364,6 @@ msgstr "语言播放验证码"
|
||||||
msgid "Captcha"
|
msgid "Captcha"
|
||||||
msgstr "验证码"
|
msgstr "验证码"
|
||||||
|
|
||||||
#: templates/flash_message_standalone.html:47
|
|
||||||
msgid "Return"
|
|
||||||
msgstr "返回"
|
|
||||||
|
|
||||||
#: templates/index.html:11
|
#: templates/index.html:11
|
||||||
msgid "Total users"
|
msgid "Total users"
|
||||||
msgstr "用户总数"
|
msgstr "用户总数"
|
||||||
|
@ -4496,14 +4672,6 @@ msgstr "地址"
|
||||||
msgid "Alive"
|
msgid "Alive"
|
||||||
msgstr "在线"
|
msgstr "在线"
|
||||||
|
|
||||||
#: terminal/templates/terminal/terminal_list.html:78
|
|
||||||
msgid "Accept"
|
|
||||||
msgstr "接受"
|
|
||||||
|
|
||||||
#: terminal/templates/terminal/terminal_list.html:80
|
|
||||||
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 "接受终端注册"
|
||||||
|
@ -4541,7 +4709,7 @@ msgstr "你可以使用ssh客户端工具连接终端"
|
||||||
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:383
|
#: users/forms.py:32 users/models/user.py:385
|
||||||
#: users/templates/users/_select_user_modal.html:15
|
#: users/templates/users/_select_user_modal.html:15
|
||||||
#: users/templates/users/user_detail.html:87
|
#: users/templates/users/user_detail.html:87
|
||||||
#: users/templates/users/user_list.html:37
|
#: users/templates/users/user_list.html:37
|
||||||
|
@ -4570,7 +4738,7 @@ msgstr "添加到用户组"
|
||||||
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/v1.py:116
|
#: users/forms.py:90 users/forms.py:251 users/serializers/user.py:110
|
||||||
msgid "Not a valid ssh public key"
|
msgid "Not a valid ssh public key"
|
||||||
msgstr "ssh密钥不合法"
|
msgstr "ssh密钥不合法"
|
||||||
|
|
||||||
|
@ -4655,98 +4823,98 @@ msgstr "复制你的公钥到这里"
|
||||||
msgid "Select users"
|
msgid "Select users"
|
||||||
msgstr "选择用户"
|
msgstr "选择用户"
|
||||||
|
|
||||||
#: users/models/user.py:50 users/templates/users/user_update.html:22
|
#: users/models/user.py:52 users/templates/users/user_update.html:22
|
||||||
#: users/views/login.py:46 users/views/login.py:107
|
#: users/views/login.py:46 users/views/login.py:107
|
||||||
msgid "User auth from {}, go there change password"
|
msgid "User auth from {}, go there change password"
|
||||||
msgstr "用户认证源来自 {}, 请去相应系统修改密码"
|
msgstr "用户认证源来自 {}, 请去相应系统修改密码"
|
||||||
|
|
||||||
#: users/models/user.py:126 users/models/user.py:508
|
#: users/models/user.py:128 users/models/user.py:510
|
||||||
msgid "Administrator"
|
msgid "Administrator"
|
||||||
msgstr "管理员"
|
msgstr "管理员"
|
||||||
|
|
||||||
#: users/models/user.py:128
|
#: users/models/user.py:130
|
||||||
msgid "Application"
|
msgid "Application"
|
||||||
msgstr "应用程序"
|
msgstr "应用程序"
|
||||||
|
|
||||||
#: users/models/user.py:129 xpack/plugins/orgs/forms.py:30
|
#: users/models/user.py:131 xpack/plugins/orgs/forms.py:30
|
||||||
#: xpack/plugins/orgs/templates/orgs/org_list.html:14
|
#: xpack/plugins/orgs/templates/orgs/org_list.html:14
|
||||||
msgid "Auditor"
|
msgid "Auditor"
|
||||||
msgstr "审计员"
|
msgstr "审计员"
|
||||||
|
|
||||||
#: users/models/user.py:139
|
#: users/models/user.py:141
|
||||||
msgid "Org admin"
|
msgid "Org admin"
|
||||||
msgstr "组织管理员"
|
msgstr "组织管理员"
|
||||||
|
|
||||||
#: users/models/user.py:141
|
#: users/models/user.py:143
|
||||||
msgid "Org auditor"
|
msgid "Org auditor"
|
||||||
msgstr "组织审计员"
|
msgstr "组织审计员"
|
||||||
|
|
||||||
#: users/models/user.py:332 users/templates/users/user_profile.html:90
|
#: users/models/user.py:334 users/templates/users/user_profile.html:90
|
||||||
msgid "Force enable"
|
msgid "Force enable"
|
||||||
msgstr "强制启用"
|
msgstr "强制启用"
|
||||||
|
|
||||||
#: users/models/user.py:386
|
#: users/models/user.py:388
|
||||||
msgid "Avatar"
|
msgid "Avatar"
|
||||||
msgstr "头像"
|
msgstr "头像"
|
||||||
|
|
||||||
#: users/models/user.py:389 users/templates/users/user_detail.html:82
|
#: users/models/user.py:391 users/templates/users/user_detail.html:82
|
||||||
msgid "Wechat"
|
msgid "Wechat"
|
||||||
msgstr "微信"
|
msgstr "微信"
|
||||||
|
|
||||||
#: users/models/user.py:418 users/templates/users/user_detail.html:103
|
#: users/models/user.py:420 users/templates/users/user_detail.html:103
|
||||||
#: users/templates/users/user_list.html:39
|
#: users/templates/users/user_list.html:39
|
||||||
#: users/templates/users/user_profile.html:102
|
#: users/templates/users/user_profile.html:102
|
||||||
msgid "Source"
|
msgid "Source"
|
||||||
msgstr "用户来源"
|
msgstr "用户来源"
|
||||||
|
|
||||||
#: users/models/user.py:422
|
#: users/models/user.py:424
|
||||||
msgid "Date password last updated"
|
msgid "Date password last updated"
|
||||||
msgstr "最后更新密码日期"
|
msgstr "最后更新密码日期"
|
||||||
|
|
||||||
#: users/models/user.py:511
|
#: users/models/user.py:513
|
||||||
msgid "Administrator is the super user of system"
|
msgid "Administrator is the super user of system"
|
||||||
msgstr "Administrator是初始的超级管理员"
|
msgstr "Administrator是初始的超级管理员"
|
||||||
|
|
||||||
#: users/serializers/v1.py:45
|
#: users/serializers/group.py:46
|
||||||
|
msgid "Auditors cannot be join in the user group"
|
||||||
|
msgstr "审计员不能被加入到用户组"
|
||||||
|
|
||||||
|
#: users/serializers/user.py:39
|
||||||
msgid "Groups name"
|
msgid "Groups name"
|
||||||
msgstr "用户组名"
|
msgstr "用户组名"
|
||||||
|
|
||||||
#: users/serializers/v1.py:46
|
#: users/serializers/user.py:40
|
||||||
msgid "Source name"
|
msgid "Source name"
|
||||||
msgstr "用户来源名"
|
msgstr "用户来源名"
|
||||||
|
|
||||||
#: users/serializers/v1.py:47
|
#: users/serializers/user.py:41
|
||||||
msgid "Is first login"
|
msgid "Is first login"
|
||||||
msgstr "首次登录"
|
msgstr "首次登录"
|
||||||
|
|
||||||
#: users/serializers/v1.py:48
|
#: users/serializers/user.py:42
|
||||||
msgid "Role name"
|
msgid "Role name"
|
||||||
msgstr "角色名"
|
msgstr "角色名"
|
||||||
|
|
||||||
#: users/serializers/v1.py:49
|
#: users/serializers/user.py:43
|
||||||
msgid "Is valid"
|
msgid "Is valid"
|
||||||
msgstr "账户是否有效"
|
msgstr "账户是否有效"
|
||||||
|
|
||||||
#: users/serializers/v1.py:50
|
#: users/serializers/user.py:44
|
||||||
msgid "Is expired"
|
msgid "Is expired"
|
||||||
msgstr " 是否过期"
|
msgstr " 是否过期"
|
||||||
|
|
||||||
#: users/serializers/v1.py:51
|
#: users/serializers/user.py:45
|
||||||
msgid "Avatar url"
|
msgid "Avatar url"
|
||||||
msgstr "头像路径"
|
msgstr "头像路径"
|
||||||
|
|
||||||
#: users/serializers/v1.py:72
|
#: users/serializers/user.py:66
|
||||||
msgid "Role limit to {}"
|
msgid "Role limit to {}"
|
||||||
msgstr "角色只能为 {}"
|
msgstr "角色只能为 {}"
|
||||||
|
|
||||||
#: users/serializers/v1.py:84
|
#: users/serializers/user.py:78
|
||||||
msgid "Password does not match security rules"
|
msgid "Password does not match security rules"
|
||||||
msgstr "密码不满足安全规则"
|
msgstr "密码不满足安全规则"
|
||||||
|
|
||||||
#: users/serializers/v1.py:157
|
|
||||||
msgid "Auditors cannot be join in the user group"
|
|
||||||
msgstr "审计员不能被加入到用户组"
|
|
||||||
|
|
||||||
#: users/serializers_v2/user.py:36
|
#: users/serializers_v2/user.py:36
|
||||||
msgid "name not unique"
|
msgid "name not unique"
|
||||||
msgstr "名称重复"
|
msgstr "名称重复"
|
||||||
|
@ -5092,14 +5260,6 @@ msgstr "删除"
|
||||||
msgid "User Deleting failed."
|
msgid "User Deleting failed."
|
||||||
msgstr "用户删除失败"
|
msgstr "用户删除失败"
|
||||||
|
|
||||||
#: users/templates/users/user_list.html:327
|
|
||||||
msgid "User is expired"
|
|
||||||
msgstr "用户已失效"
|
|
||||||
|
|
||||||
#: users/templates/users/user_list.html:330
|
|
||||||
msgid "User is inactive"
|
|
||||||
msgstr "用户已禁用"
|
|
||||||
|
|
||||||
#: users/templates/users/user_otp_authentication.html:6
|
#: users/templates/users/user_otp_authentication.html:6
|
||||||
#: users/templates/users/user_password_authentication.html:6
|
#: users/templates/users/user_password_authentication.html:6
|
||||||
msgid "Authenticate"
|
msgid "Authenticate"
|
||||||
|
@ -6391,9 +6551,6 @@ msgstr "创建"
|
||||||
#~ msgid "Start"
|
#~ msgid "Start"
|
||||||
#~ msgstr "开始"
|
#~ msgstr "开始"
|
||||||
|
|
||||||
#~ msgid "User login settings"
|
|
||||||
#~ msgstr "用户登录设置"
|
|
||||||
|
|
||||||
#~ msgid "Bit"
|
#~ msgid "Bit"
|
||||||
#~ msgstr " 位"
|
#~ msgstr " 位"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
from rest_framework import viewsets, generics
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
|
||||||
|
from common.permissions import IsValidUser
|
||||||
|
from common.mixins import CommonApiMixin
|
||||||
|
from . import serializers
|
||||||
|
from .models import LoginConfirmOrder
|
||||||
|
|
||||||
|
|
||||||
|
class LoginConfirmOrderViewSet(CommonApiMixin, viewsets.ModelViewSet):
|
||||||
|
serializer_class = serializers.LoginConfirmOrderSerializer
|
||||||
|
permission_classes = (IsValidUser,)
|
||||||
|
search_fields = ['user_display', 'title', 'ip', 'city']
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = LoginConfirmOrder.objects.all()\
|
||||||
|
.filter(assignees=self.request.user)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
class LoginConfirmOrderCreateActionApi(generics.CreateAPIView):
|
||||||
|
permission_classes = (IsValidUser,)
|
||||||
|
serializer_class = serializers.LoginConfirmOrderActionSerializer
|
||||||
|
|
||||||
|
def get_order(self):
|
||||||
|
order_id = self.kwargs.get('pk')
|
||||||
|
queryset = LoginConfirmOrder.objects.all()\
|
||||||
|
.filter(assignees=self.request.user)
|
||||||
|
order = get_object_or_404(queryset, id=order_id)
|
||||||
|
return order
|
||||||
|
|
||||||
|
def get_serializer_context(self):
|
||||||
|
context = super().get_serializer_context()
|
||||||
|
order = self.get_order()
|
||||||
|
context['order'] = order
|
||||||
|
return context
|
|
@ -3,3 +3,7 @@ from django.apps import AppConfig
|
||||||
|
|
||||||
class OrdersConfig(AppConfig):
|
class OrdersConfig(AppConfig):
|
||||||
name = 'orders'
|
name = 'orders'
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
from . import signals_handler
|
||||||
|
return super().ready()
|
||||||
|
|
|
@ -3,31 +3,56 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from common.mixins.models import CommonModelMixin
|
from common.mixins.models import CommonModelMixin
|
||||||
|
|
||||||
|
__all__ = ['LoginConfirmOrder', 'Comment']
|
||||||
|
|
||||||
class Order(CommonModelMixin):
|
|
||||||
|
class Comment(CommonModelMixin):
|
||||||
|
order_id = models.UUIDField()
|
||||||
|
user = models.ForeignKey('users.User', on_delete=models.SET_NULL, null=True, verbose_name=_("User"), related_name='comments')
|
||||||
|
user_display = models.CharField(max_length=128, verbose_name=_("User display name"))
|
||||||
|
body = models.TextField(verbose_name=_("Body"))
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ('date_created', )
|
||||||
|
|
||||||
|
|
||||||
|
class BaseOrder(CommonModelMixin):
|
||||||
|
STATUS_ACCEPTED = 'accepted'
|
||||||
|
STATUS_REJECTED = 'rejected'
|
||||||
|
STATUS_PENDING = 'pending'
|
||||||
STATUS_CHOICES = (
|
STATUS_CHOICES = (
|
||||||
('accepted', _("Accepted")),
|
(STATUS_ACCEPTED, _("Accepted")),
|
||||||
('rejected', _("Rejected")),
|
(STATUS_REJECTED, _("Rejected")),
|
||||||
('pending', _("Pending"))
|
(STATUS_PENDING, _("Pending"))
|
||||||
)
|
)
|
||||||
TYPE_LOGIN_REQUEST = 'login_request'
|
TYPE_LOGIN_CONFIRM = 'login_confirm'
|
||||||
TYPE_CHOICES = (
|
TYPE_CHOICES = (
|
||||||
(TYPE_LOGIN_REQUEST, _("Login request")),
|
(TYPE_LOGIN_CONFIRM, 'Login confirm'),
|
||||||
)
|
)
|
||||||
user = models.ForeignKey('users.User', on_delete=models.SET_NULL, null=True, related_name='orders', verbose_name=_("User"))
|
user = models.ForeignKey('users.User', on_delete=models.SET_NULL, null=True, related_name='%(class)s_requested', verbose_name=_("User"))
|
||||||
user_display = models.CharField(max_length=128, verbose_name=_("User display name"))
|
user_display = models.CharField(max_length=128, verbose_name=_("User display name"))
|
||||||
|
|
||||||
title = models.CharField(max_length=256, verbose_name=_("Title"))
|
title = models.CharField(max_length=256, verbose_name=_("Title"))
|
||||||
body = models.TextField(verbose_name=_("Body"))
|
body = models.TextField(verbose_name=_("Body"))
|
||||||
assignees = models.ManyToManyField('users.User', related_name='assign_orders', verbose_name=_("Assignees"))
|
assignee = models.ForeignKey('users.User', on_delete=models.SET_NULL, null=True, related_name='%(class)s_handled', verbose_name=_("Assignee"))
|
||||||
|
assignee_display = models.CharField(max_length=128, blank=True, null=True, verbose_name=_("Assignee display name"))
|
||||||
|
assignees = models.ManyToManyField('users.User', related_name='%(class)s_assigned', verbose_name=_("Assignees"))
|
||||||
assignees_display = models.CharField(max_length=128, verbose_name=_("Assignees display name"), blank=True)
|
assignees_display = models.CharField(max_length=128, verbose_name=_("Assignees display name"), blank=True)
|
||||||
|
type = models.CharField(choices=TYPE_CHOICES, max_length=16, verbose_name=_('Type'))
|
||||||
type = models.CharField(choices=TYPE_CHOICES, max_length=64)
|
|
||||||
status = models.CharField(choices=STATUS_CHOICES, max_length=16, default='pending')
|
status = models.CharField(choices=STATUS_CHOICES, max_length=16, default='pending')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '{}: {}'.format(self.user_display, self.title)
|
return '{}: {}'.format(self.user_display, self.title)
|
||||||
|
|
||||||
class Meta:
|
@property
|
||||||
ordering = ('date_created',)
|
def comments(self):
|
||||||
|
return Comment.objects.filter(order_id=self.id)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
ordering = ('-date_created',)
|
||||||
|
|
||||||
|
|
||||||
|
class LoginConfirmOrder(BaseOrder):
|
||||||
|
ip = models.GenericIPAddressField(blank=True, null=True)
|
||||||
|
city = models.CharField(max_length=16, blank=True, default='')
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
from rest_framework import serializers
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from .models import LoginConfirmOrder, Comment
|
||||||
|
|
||||||
|
|
||||||
|
class LoginConfirmOrderSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = LoginConfirmOrder
|
||||||
|
fields = [
|
||||||
|
'id', 'user', 'user_display', 'title', 'body',
|
||||||
|
'ip', 'city', 'assignees', 'assignees_display',
|
||||||
|
'type', 'status', 'date_created', 'date_updated',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class LoginConfirmOrderActionSerializer(serializers.Serializer):
|
||||||
|
ACTION_CHOICES = (
|
||||||
|
('accept', _('Accept')),
|
||||||
|
('reject', _('Reject')),
|
||||||
|
('comment', _('Comment'))
|
||||||
|
)
|
||||||
|
action = serializers.ChoiceField(choices=ACTION_CHOICES)
|
||||||
|
comment = serializers.CharField(allow_blank=True)
|
||||||
|
|
||||||
|
def update(self, instance, validated_data):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def create_comments(self, order, user, validated_data):
|
||||||
|
comment_data = validated_data.get('comment')
|
||||||
|
action = validated_data.get('action')
|
||||||
|
comments_data = []
|
||||||
|
if comment_data:
|
||||||
|
comments_data.append(comment_data)
|
||||||
|
Comment.objects.create(
|
||||||
|
order_id=order.id, body=comment_data, user=user,
|
||||||
|
user_display=str(user)
|
||||||
|
)
|
||||||
|
if action != "comment":
|
||||||
|
action_display = dict(self.ACTION_CHOICES).get(action)
|
||||||
|
comment_data = '{} {} {}'.format(user, action_display, _("this order"))
|
||||||
|
comments_data.append(comment_data)
|
||||||
|
comments = [
|
||||||
|
Comment(order_id=order.id, body=data, user=user, user_display=str(user))
|
||||||
|
for data in comments_data
|
||||||
|
]
|
||||||
|
Comment.objects.bulk_create(comments)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def perform_action(order, user, validated_data):
|
||||||
|
action = validated_data.get('action')
|
||||||
|
if action == "accept":
|
||||||
|
status = "accepted"
|
||||||
|
elif action == "reject":
|
||||||
|
status = "rejected"
|
||||||
|
else:
|
||||||
|
status = None
|
||||||
|
|
||||||
|
if status:
|
||||||
|
order.status = status
|
||||||
|
order.assignee = user
|
||||||
|
order.assignee_display = str(user)
|
||||||
|
order.save()
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
order = self.context['order']
|
||||||
|
user = self.context['request'].user
|
||||||
|
self.create_comments(order, user, validated_data)
|
||||||
|
self.perform_action(order, user, validated_data)
|
||||||
|
return validated_data
|
|
@ -0,0 +1,59 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from django.db.models.signals import m2m_changed
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
from common.tasks import send_mail_async
|
||||||
|
from common.utils import get_logger, reverse
|
||||||
|
from .models import LoginConfirmOrder
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def send_mail(order, assignees):
|
||||||
|
recipient_list = [user.email for user in assignees]
|
||||||
|
user = order.user
|
||||||
|
if not recipient_list:
|
||||||
|
logger.error("Order not has assignees: {}".format(order.id))
|
||||||
|
return
|
||||||
|
subject = '{}: {}'.format(_("New order"), order.title)
|
||||||
|
detail_url = reverse('orders:login-confirm-order-detail',
|
||||||
|
kwargs={'pk': order.id}, external=True)
|
||||||
|
message = _("""
|
||||||
|
<div>
|
||||||
|
<p>Your has a new order</p>
|
||||||
|
<div>
|
||||||
|
<b>Title:</b> {order.title}
|
||||||
|
<br/>
|
||||||
|
<b>User:</b> {user}
|
||||||
|
<br/>
|
||||||
|
<b>City:</b> {order.city}
|
||||||
|
<br/>
|
||||||
|
<b>IP:</b> {order.ip}
|
||||||
|
<br/>
|
||||||
|
<a href={url}>click here to review</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
""").format(order=order, user=user, url=detail_url)
|
||||||
|
if settings.DEBUG:
|
||||||
|
try:
|
||||||
|
print(message)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
send_mail_async.delay(subject, message, recipient_list, html_message=message)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(m2m_changed, sender=LoginConfirmOrder.assignees.through)
|
||||||
|
def on_login_confirm_order_assignee_set(sender, instance=None, action=None,
|
||||||
|
model=None, pk_set=None, **kwargs):
|
||||||
|
print(">>>>>>>>>>>>>>>>>>>>>>>.")
|
||||||
|
print(action)
|
||||||
|
if action == 'post_add':
|
||||||
|
print("<<<<<<<<<<<<<<<<<<<<")
|
||||||
|
logger.debug('New order create, send mail: {}'.format(instance.id))
|
||||||
|
assignees = model.objects.filter(pk__in=pk_set)
|
||||||
|
send_mail(instance, assignees)
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
{% 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 '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>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
{% block custom_foot_js %}
|
||||||
|
<script>
|
||||||
|
var orderId = "{{ object.id }}";
|
||||||
|
var status = "{{ object.status }}";
|
||||||
|
var actionCreateUrl = "{% url 'api-orders:login-confirm-order-create-action' pk=object.id %}";
|
||||||
|
$(document).ready(function () {
|
||||||
|
if (status !== "pending") {
|
||||||
|
$('.btn-update').attr('disabled', '1')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on('click', '.btn-action', function () {
|
||||||
|
var action = $(this).data('action');
|
||||||
|
var comment = $("#comment").val();
|
||||||
|
var data = {
|
||||||
|
url: actionCreateUrl,
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({action: action, comment: comment}),
|
||||||
|
success: function () {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
requestApi(data);
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,91 @@
|
||||||
|
{% extends '_base_list.html' %}
|
||||||
|
{% load i18n static %}
|
||||||
|
{% block table_search %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
{% block table_container %}
|
||||||
|
<table class="table table-striped table-bordered table-hover " id="login_confirm_order_list_table" >
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">
|
||||||
|
<input id="" type="checkbox" class="ipt_check_all">
|
||||||
|
</th>
|
||||||
|
<th class="text-center">{% trans 'Title' %}</th>
|
||||||
|
<th class="text-center">{% trans 'User' %}</th>
|
||||||
|
<th class="text-center">{% trans 'IP' %}</th>
|
||||||
|
<th class="text-center">{% trans 'City' %}</th>
|
||||||
|
<th class="text-center">{% trans 'Status' %}</th>
|
||||||
|
<th class="text-center">{% trans 'Datetime' %}</th>
|
||||||
|
<th class="text-center">{% trans 'Action' %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
||||||
|
{% block content_bottom_left %}{% endblock %}
|
||||||
|
{% block custom_foot_js %}
|
||||||
|
<script>
|
||||||
|
var orderTable = 0;
|
||||||
|
function initTable() {
|
||||||
|
var options = {
|
||||||
|
ele: $('#login_confirm_order_list_table'),
|
||||||
|
columnDefs: [
|
||||||
|
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||||
|
cellData = htmlEscape(cellData);
|
||||||
|
var detailBtn = '<a href="{% url "orders:login-confirm-order-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
|
||||||
|
$(td).html(detailBtn.replace("{{ DEFAULT_PK }}", rowData.id));
|
||||||
|
}},
|
||||||
|
{targets: 5, createdCell: function (td, cellData, rowData) {
|
||||||
|
if (cellData === "accepted") {
|
||||||
|
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||||
|
} else if (cellData === "rejected") {
|
||||||
|
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||||
|
} else if (cellData === "pending") {
|
||||||
|
$(td).html('<i class="fa fa-spinner text-info"></i>')
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
{targets: 6, createdCell: function (td, cellData) {
|
||||||
|
var d = toSafeLocalDateStr(cellData);
|
||||||
|
$(td).html(d)
|
||||||
|
}},
|
||||||
|
{targets: 7, createdCell: function (td, cellData, rowData) {
|
||||||
|
var acceptBtn = '<a class="btn btn-xs btn-info" data-uid="{{ DEFAULT_PK }}" >{% trans "Accept" %}</a> ';
|
||||||
|
var rejectBtn = '<a class="btn btn-xs btn-danger " data-uid="{{ DEFAULT_PK }}" >{% trans "Reject" %}</a>';
|
||||||
|
acceptBtn = acceptBtn.replace('{{ DEFAULT_PK }}', cellData);
|
||||||
|
rejectBtn = rejectBtn.replace('{{ DEFAULT_PK }}', cellData);
|
||||||
|
var acceptBtnRef = $(acceptBtn);
|
||||||
|
var rejectBtnRef = $(rejectBtn);
|
||||||
|
if (rowData.status !== "pending") {
|
||||||
|
acceptBtnRef.attr('disabled', 'disabled');
|
||||||
|
rejectBtnRef.attr('disabled', 'disabled');
|
||||||
|
}
|
||||||
|
var btn = acceptBtnRef.prop('outerHTML') + ' ' + rejectBtnRef.prop('outerHTML');
|
||||||
|
$(td).html(btn)
|
||||||
|
}}],
|
||||||
|
ajax_url: '{% url "api-orders:login-confirm-order-list" %}',
|
||||||
|
columns: [
|
||||||
|
{data: "id"}, {data: "title", className: "text-left"}, {data: "user_display"},
|
||||||
|
{data: "ip"}, {data: "city"},
|
||||||
|
{data: "status", orderable: false},
|
||||||
|
{data: "date_created"},
|
||||||
|
{data: "id", orderable: false, width: "100px"}
|
||||||
|
],
|
||||||
|
op_html: $('#actions').html()
|
||||||
|
};
|
||||||
|
orderTable = jumpserver.initServerSideDataTable(options);
|
||||||
|
return orderTable
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
initTable();
|
||||||
|
}).on('click', '.expired', function () {
|
||||||
|
var msg = '{% trans "User is expired" %}';
|
||||||
|
toastr.error(msg)
|
||||||
|
}).on('click', '.inactive', function () {
|
||||||
|
var msg = '{% trans 'User is inactive' %}';
|
||||||
|
toastr.error(msg)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
|
@ -0,0 +1,20 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
from django.urls import path
|
||||||
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
|
from .. import api
|
||||||
|
|
||||||
|
app_name = 'orders'
|
||||||
|
router = DefaultRouter()
|
||||||
|
|
||||||
|
router.register('login-confirm-orders', api.LoginConfirmOrderViewSet, 'login-confirm-order')
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('login-confirm-order/<uuid:pk>/actions/',
|
||||||
|
api.LoginConfirmOrderCreateActionApi.as_view(),
|
||||||
|
name='login-confirm-order-create-action'
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
urlpatterns += router.urls
|
|
@ -0,0 +1,11 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
from django.urls import path
|
||||||
|
from .. import views
|
||||||
|
|
||||||
|
app_name = 'orders'
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('login-confirm-orders/', views.LoginConfirmOrderListView.as_view(), name='login-confirm-order-list'),
|
||||||
|
path('login-confirm-orders/<uuid:pk>/', views.LoginConfirmOrderDetailView.as_view(), name='login-confirm-order-detail')
|
||||||
|
]
|
|
@ -0,0 +1,2 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
|
@ -1,3 +1,34 @@
|
||||||
from django.shortcuts import render
|
from django.views.generic import TemplateView, DetailView
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
# Create your views here.
|
from common.permissions import PermissionsMixin, IsOrgAdmin
|
||||||
|
from .models import LoginConfirmOrder
|
||||||
|
|
||||||
|
|
||||||
|
class LoginConfirmOrderListView(PermissionsMixin, TemplateView):
|
||||||
|
template_name = 'orders/login_confirm_order_list.html'
|
||||||
|
permission_classes = (IsOrgAdmin,)
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context.update({
|
||||||
|
'app': _("Orders"),
|
||||||
|
'action': _("Login confirm order list")
|
||||||
|
})
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class LoginConfirmOrderDetailView(PermissionsMixin, DetailView):
|
||||||
|
template_name = 'orders/login_confirm_order_detail.html'
|
||||||
|
permission_classes = (IsOrgAdmin,)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return LoginConfirmOrder.objects.filter(assignees=self.request.user)
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context.update({
|
||||||
|
'app': _("Orders"),
|
||||||
|
'action': _("Login confirm order detail")
|
||||||
|
})
|
||||||
|
return context
|
||||||
|
|
|
@ -307,7 +307,7 @@ function requestApi(props) {
|
||||||
toastr.error(msg);
|
toastr.error(msg);
|
||||||
}
|
}
|
||||||
if (typeof props.error === 'function') {
|
if (typeof props.error === 'function') {
|
||||||
return props.error(jqXHR.responseText, jqXHR.status);
|
return props.error(jqXHR.responseText, jqXHR.responseJSON, jqXHR.status);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// return true;
|
// return true;
|
||||||
|
|
|
@ -121,6 +121,16 @@
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if request.user.can_admin_current_org %}
|
||||||
|
<li id="orders">
|
||||||
|
<a>
|
||||||
|
<i class="fa fa-check-square-o" style="width: 14px"></i> <span class="nav-label">{% trans 'Orders' %}</span><span class="fa arrow"></span>
|
||||||
|
</a>
|
||||||
|
<ul class="nav nav-second-level">
|
||||||
|
<li id="login-confirm-orders"><a href="{% url 'orders:login-confirm-order-list' %}">{% trans 'Login confirm' %}</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{# Audits #}
|
{# Audits #}
|
||||||
{% if request.user.can_admin_or_audit_current_org %}
|
{% if request.user.can_admin_or_audit_current_org %}
|
||||||
|
@ -175,4 +185,4 @@
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -193,7 +193,6 @@ def send_reset_ssh_key_mail(user):
|
||||||
send_mail_async.delay(subject, message, recipient_list, html_message=message)
|
send_mail_async.delay(subject, message, recipient_list, html_message=message)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_user_or_tmp_user(request):
|
def get_user_or_tmp_user(request):
|
||||||
user = request.user
|
user = request.user
|
||||||
tmp_user = get_tmp_user_from_cache(request)
|
tmp_user = get_tmp_user_from_cache(request)
|
||||||
|
@ -212,8 +211,8 @@ def get_tmp_user_from_cache(request):
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
def set_tmp_user_to_cache(request, user):
|
def set_tmp_user_to_cache(request, user, ttl=3600):
|
||||||
cache.set(request.session.session_key+'user', user, 600)
|
cache.set(request.session.session_key+'user', user, ttl)
|
||||||
|
|
||||||
|
|
||||||
def redirect_user_first_login_or_index(request, redirect_field_name):
|
def redirect_user_first_login_or_index(request, redirect_field_name):
|
||||||
|
|
Loading…
Reference in New Issue