Unverified Commit a0259309 authored by 老广's avatar 老广 Committed by GitHub

Merge pull request #2642 from jumpserver/dev

Dev
parents cf2455c0 990c78e7
...@@ -201,8 +201,7 @@ Jumpserver 采纳分布式架构,支持多机房跨区域部署,中心节点 ...@@ -201,8 +201,7 @@ Jumpserver 采纳分布式架构,支持多机房跨区域部署,中心节点
### License & Copyright ### License & Copyright
---- Copyright (c) 2014-2019 飞致云 FIT2CLOUD, All rights reserved.
Copyright (c) 2014-2019 Beijing Duizhan Tech, Inc., All rights reserved.
Licensed under The GNU General Public License version 2 (GPLv2) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at Licensed under The GNU General Public License version 2 (GPLv2) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import uuid
import random import random
from rest_framework import generics from rest_framework import generics
from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework_bulk import BulkModelViewSet from rest_framework_bulk import BulkModelViewSet
from rest_framework_bulk import ListBulkCreateUpdateDestroyAPIView from rest_framework_bulk import ListBulkCreateUpdateDestroyAPIView
from rest_framework.pagination import LimitOffsetPagination from rest_framework.pagination import LimitOffsetPagination
from django.utils.translation import ugettext_lazy as _
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.urls import reverse_lazy
from django.core.cache import cache
from django.db.models import Q from django.db.models import Q
from common.mixins import IDInFilterMixin from common.mixins import IDInFilterMixin
from common.utils import get_logger from common.utils import get_logger
from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser
from ..const import CACHE_KEY_ASSET_BULK_UPDATE_ID_PREFIX
from ..models import Asset, AdminUser, Node from ..models import Asset, AdminUser, Node
from .. import serializers from .. import serializers
from ..tasks import update_asset_hardware_info_manual, \ from ..tasks import update_asset_hardware_info_manual, \
...@@ -25,7 +31,7 @@ logger = get_logger(__file__) ...@@ -25,7 +31,7 @@ logger = get_logger(__file__)
__all__ = [ __all__ = [
'AssetViewSet', 'AssetListUpdateApi', 'AssetViewSet', 'AssetListUpdateApi',
'AssetRefreshHardwareApi', 'AssetAdminUserTestApi', 'AssetRefreshHardwareApi', 'AssetAdminUserTestApi',
'AssetGatewayApi' 'AssetGatewayApi', 'AssetBulkUpdateSelectAPI'
] ]
...@@ -92,6 +98,21 @@ class AssetListUpdateApi(IDInFilterMixin, ListBulkCreateUpdateDestroyAPIView): ...@@ -92,6 +98,21 @@ class AssetListUpdateApi(IDInFilterMixin, ListBulkCreateUpdateDestroyAPIView):
permission_classes = (IsOrgAdmin,) permission_classes = (IsOrgAdmin,)
class AssetBulkUpdateSelectAPI(APIView):
permission_classes = (IsOrgAdmin,)
def post(self, request, *args, **kwargs):
assets_id = request.data.get('assets_id', '')
if assets_id:
spm = uuid.uuid4().hex
key = CACHE_KEY_ASSET_BULK_UPDATE_ID_PREFIX.format(spm)
cache.set(key, assets_id, 300)
url = reverse_lazy('assets:asset-bulk-update') + '?spm=%s' % spm
return Response({'url': url})
error = _('Please select assets that need to be updated')
return Response({'error': error}, status=400)
class AssetRefreshHardwareApi(generics.RetrieveAPIView): class AssetRefreshHardwareApi(generics.RetrieveAPIView):
""" """
Refresh asset hardware info Refresh asset hardware info
......
...@@ -48,3 +48,6 @@ TASK_OPTIONS = { ...@@ -48,3 +48,6 @@ TASK_OPTIONS = {
'timeout': 10, 'timeout': 10,
'forks': 10, 'forks': 10,
} }
CACHE_KEY_ASSET_BULK_UPDATE_ID_PREFIX = '_KEY_ASSET_BULK_UPDATE_ID_{}'
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
from django.core.cache import cache from django.core.cache import cache
from rest_framework import serializers from rest_framework import serializers
from common.serializers import AdaptedBulkListSerializer
from ..models import Node, AdminUser from ..models import Node, AdminUser
from ..const import ADMIN_USER_CONN_CACHE_KEY from ..const import ADMIN_USER_CONN_CACHE_KEY
...@@ -18,6 +20,7 @@ class AdminUserSerializer(serializers.ModelSerializer): ...@@ -18,6 +20,7 @@ class AdminUserSerializer(serializers.ModelSerializer):
reachable_amount = serializers.SerializerMethodField() reachable_amount = serializers.SerializerMethodField()
class Meta: class Meta:
list_serializer_class = AdaptedBulkListSerializer
model = AdminUser model = AdminUser
fields = '__all__' fields = '__all__'
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from rest_framework import serializers from rest_framework import serializers
from rest_framework_bulk.serializers import BulkListSerializer
from common.mixins import BulkSerializerMixin from common.mixins import BulkSerializerMixin
from common.serializers import AdaptedBulkListSerializer
from ..models import Asset from ..models import Asset
from .system_user import AssetSystemUserSerializer from .system_user import AssetSystemUserSerializer
...@@ -19,7 +19,7 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer): ...@@ -19,7 +19,7 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
""" """
class Meta: class Meta:
model = Asset model = Asset
list_serializer_class = BulkListSerializer list_serializer_class = AdaptedBulkListSerializer
fields = '__all__' fields = '__all__'
validators = [] validators = []
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
from rest_framework import serializers from rest_framework import serializers
from common.fields import ChoiceDisplayField from common.fields import ChoiceDisplayField
from common.serializers import AdaptedBulkListSerializer
from ..models import CommandFilter, CommandFilterRule, SystemUser from ..models import CommandFilter, CommandFilterRule, SystemUser
...@@ -12,6 +13,7 @@ class CommandFilterSerializer(serializers.ModelSerializer): ...@@ -12,6 +13,7 @@ class CommandFilterSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = CommandFilter model = CommandFilter
list_serializer_class = AdaptedBulkListSerializer
fields = '__all__' fields = '__all__'
...@@ -21,3 +23,4 @@ class CommandFilterRuleSerializer(serializers.ModelSerializer): ...@@ -21,3 +23,4 @@ class CommandFilterRuleSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = CommandFilterRule model = CommandFilterRule
fields = '__all__' fields = '__all__'
list_serializer_class = AdaptedBulkListSerializer
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
# #
from rest_framework import serializers from rest_framework import serializers
from common.serializers import AdaptedBulkListSerializer
from ..models import Domain, Gateway from ..models import Domain, Gateway
...@@ -12,6 +14,7 @@ class DomainSerializer(serializers.ModelSerializer): ...@@ -12,6 +14,7 @@ class DomainSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Domain model = Domain
fields = '__all__' fields = '__all__'
list_serializer_class = AdaptedBulkListSerializer
@staticmethod @staticmethod
def get_asset_count(obj): def get_asset_count(obj):
...@@ -25,6 +28,7 @@ class DomainSerializer(serializers.ModelSerializer): ...@@ -25,6 +28,7 @@ class DomainSerializer(serializers.ModelSerializer):
class GatewaySerializer(serializers.ModelSerializer): class GatewaySerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Gateway model = Gateway
list_serializer_class = AdaptedBulkListSerializer
fields = [ fields = [
'id', 'name', 'ip', 'port', 'protocol', 'username', 'id', 'name', 'ip', 'port', 'protocol', 'username',
'domain', 'is_active', 'date_created', 'date_updated', 'domain', 'is_active', 'date_created', 'date_updated',
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from rest_framework import serializers from rest_framework import serializers
from rest_framework_bulk.serializers import BulkListSerializer
from common.serializers import AdaptedBulkListSerializer
from ..models import Label from ..models import Label
...@@ -12,7 +13,7 @@ class LabelSerializer(serializers.ModelSerializer): ...@@ -12,7 +13,7 @@ class LabelSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Label model = Label
fields = '__all__' fields = '__all__'
list_serializer_class = BulkListSerializer list_serializer_class = AdaptedBulkListSerializer
@staticmethod @staticmethod
def get_asset_count(obj): def get_asset_count(obj):
......
from rest_framework import serializers from rest_framework import serializers
from common.serializers import AdaptedBulkListSerializer
from ..models import SystemUser, Asset from ..models import SystemUser, Asset
from .base import AuthSerializer from .base import AuthSerializer
...@@ -17,6 +19,7 @@ class SystemUserSerializer(serializers.ModelSerializer): ...@@ -17,6 +19,7 @@ class SystemUserSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = SystemUser model = SystemUser
exclude = ('_password', '_private_key', '_public_key') exclude = ('_password', '_private_key', '_public_key')
list_serializer_class = AdaptedBulkListSerializer
def get_field_names(self, declared_fields, info): def get_field_names(self, declared_fields, info):
fields = super(SystemUserSerializer, self).get_field_names(declared_fields, info) fields = super(SystemUserSerializer, self).get_field_names(declared_fields, info)
...@@ -61,13 +64,19 @@ class AssetSystemUserSerializer(serializers.ModelSerializer): ...@@ -61,13 +64,19 @@ class AssetSystemUserSerializer(serializers.ModelSerializer):
""" """
查看授权的资产系统用户的数据结构,这个和AssetSerializer不同,字段少 查看授权的资产系统用户的数据结构,这个和AssetSerializer不同,字段少
""" """
actions = serializers.SerializerMethodField()
class Meta: class Meta:
model = SystemUser model = SystemUser
fields = ( fields = (
'id', 'name', 'username', 'priority', 'id', 'name', 'username', 'priority',
'protocol', 'comment', 'login_mode' 'protocol', 'comment', 'login_mode', 'actions',
) )
@staticmethod
def get_actions(obj):
return [action.name for action in obj.actions]
class SystemUserSimpleSerializer(serializers.ModelSerializer): class SystemUserSimpleSerializer(serializers.ModelSerializer):
""" """
......
...@@ -98,6 +98,7 @@ function initTable() { ...@@ -98,6 +98,7 @@ function initTable() {
order: [], order: [],
columnDefs: [ columnDefs: [
{targets: 0, createdCell: function (td, cellData, rowData) { {targets: 0, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
var detail_btn = '<a href="{% url "assets:asset-detail" pk=DEFAULT_PK %}" data-aid="'+rowData.id+'">' + cellData + '</a>'; var detail_btn = '<a href="{% url "assets:asset-detail" pk=DEFAULT_PK %}" data-aid="'+rowData.id+'">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}}, }},
......
...@@ -44,9 +44,10 @@ $(document).ready(function(){ ...@@ -44,9 +44,10 @@ $(document).ready(function(){
var options = { var options = {
ele: $('#admin_user_list_table'), ele: $('#admin_user_list_table'),
columnDefs: [ columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) { {targets: 1, render: function (cellData, tp, rowData, meta) {
cellData = htmlEscape(cellData);
var detail_btn = '<a href="{% url "assets:admin-user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>'; var detail_btn = '<a href="{% url "assets:admin-user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); return detail_btn.replace('{{ DEFAULT_PK }}', rowData.id);
}}, }},
{targets: 4, createdCell: function (td, cellData) { {targets: 4, createdCell: function (td, cellData) {
var innerHtml = ""; var innerHtml = "";
...@@ -82,7 +83,6 @@ $(document).ready(function(){ ...@@ -82,7 +83,6 @@ $(document).ready(function(){
innerHtml = "<span class='text-danger'>" + num.toFixed(1) + "% </span>"; innerHtml = "<span class='text-danger'>" + num.toFixed(1) + "% </span>";
} }
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>'); $(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');
}}, }},
{targets: 8, createdCell: function (td, cellData, rowData) { {targets: 8, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "assets:admin-user-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData); var update_btn = '<a href="{% url "assets:admin-user-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
...@@ -90,8 +90,8 @@ $(document).ready(function(){ ...@@ -90,8 +90,8 @@ $(document).ready(function(){
$(td).html(update_btn + del_btn) $(td).html(update_btn + del_btn)
}}], }}],
ajax_url: '{% url "api-assets:admin-user-list" %}', ajax_url: '{% url "api-assets:admin-user-list" %}',
columns: [{data: function(){return ""}}, {data: "name" }, {data: "username" }, {data: "assets_amount" }, columns: [{data: function(){return ""}}, {data: "name"}, {data: "username" }, {data: "assets_amount" },
{data: "reachable_amount"}, {data: "unreachable_amount"}, {data: "id"}, {data: "comment" }, {data: "id" }] {data: "reachable_amount"}, {data: "unreachable_amount"}, {data: "id"}, {data: "comment"}, {data: "id"}]
}; };
jumpserver.initServerSideDataTable(options) jumpserver.initServerSideDataTable(options)
}) })
......
...@@ -156,6 +156,7 @@ function initTable() { ...@@ -156,6 +156,7 @@ function initTable() {
ele: $('#asset_list_table'), ele: $('#asset_list_table'),
columnDefs: [ columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) { {targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
{% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %} {% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %}
var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>'; var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
...@@ -657,9 +658,23 @@ $(document).ready(function(){ ...@@ -657,9 +658,23 @@ $(document).ready(function(){
}); });
} }
function doUpdate() { function doUpdate() {
var id_list_string = id_list.join(','); var data = {
var url = "{% url 'assets:asset-bulk-update' %}?assets_id=" + id_list_string; 'assets_id':id_list
location.href = url };
function error(data) {
toastr.error(JSON.parse(data).error)
}
function success(data) {
location.href = data.url;
}
APIUpdateAttr({
'url': "{% url 'api-assets:asset-bulk-update-select' %}",
'method': 'POST',
'body': JSON.stringify(data),
'flash_message': false,
'success': success,
'error': error,
})
} }
function doRemove() { function doRemove() {
......
...@@ -40,6 +40,7 @@ function initTable() { ...@@ -40,6 +40,7 @@ function initTable() {
ele: $('#cmd_filter_list_table'), ele: $('#cmd_filter_list_table'),
columnDefs: [ columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) { {targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
var detail_btn = '<a href="{% url 'assets:cmd-filter-detail' pk=DEFAULT_PK %}">' + cellData + '</a>'; var detail_btn = '<a href="{% url 'assets:cmd-filter-detail' pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}}, }},
......
...@@ -41,6 +41,7 @@ function initTable() { ...@@ -41,6 +41,7 @@ function initTable() {
ele: $('#domain_list_table'), ele: $('#domain_list_table'),
columnDefs: [ columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) { {targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
var detail_btn = '<a href="{% url "assets:domain-detail" pk=DEFAULT_PK %}">' + cellData + '</a>'; var detail_btn = '<a href="{% url "assets:domain-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}}, }},
......
...@@ -30,6 +30,7 @@ function initTable() { ...@@ -30,6 +30,7 @@ function initTable() {
columnDefs: [ columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) { {targets: 1, createdCell: function (td, cellData, rowData) {
{# var detail_btn = '<a href="{% url "assets:label-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';#} {# var detail_btn = '<a href="{% url "assets:label-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';#}
cellData = htmlEscape(cellData);
var detail_btn = '<a>' + cellData + '</a>'; var detail_btn = '<a>' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}}, }},
......
...@@ -144,6 +144,7 @@ function initAssetsTable() { ...@@ -144,6 +144,7 @@ function initAssetsTable() {
order: [], order: [],
columnDefs: [ columnDefs: [
{targets: 0, createdCell: function (td, cellData, rowData) { {targets: 0, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
var detail_btn = '<a href="{% url "assets:asset-detail" pk=DEFAULT_PK %}" data-aid="'+rowData.id+'">' + cellData + '</a>'; var detail_btn = '<a href="{% url "assets:asset-detail" pk=DEFAULT_PK %}" data-aid="'+rowData.id+'">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}}, }},
......
...@@ -49,6 +49,7 @@ function initTable() { ...@@ -49,6 +49,7 @@ function initTable() {
ele: $('#system_user_list_table'), ele: $('#system_user_list_table'),
columnDefs: [ columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) { {targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
var detail_btn = '<a href="{% url "assets:system-user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>'; var detail_btn = '<a href="{% url "assets:system-user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}}, }},
......
...@@ -25,6 +25,8 @@ cmd_filter_router.register(r'rules', api.CommandFilterRuleViewSet, 'cmd-filter-r ...@@ -25,6 +25,8 @@ cmd_filter_router.register(r'rules', api.CommandFilterRuleViewSet, 'cmd-filter-r
urlpatterns = [ urlpatterns = [
path('assets-bulk/', api.AssetListUpdateApi.as_view(), name='asset-bulk-update'), path('assets-bulk/', api.AssetListUpdateApi.as_view(), name='asset-bulk-update'),
path('asset/update/select/',
api.AssetBulkUpdateSelectAPI.as_view(), name='asset-bulk-update-select'),
path('assets/<uuid:pk>/refresh/', path('assets/<uuid:pk>/refresh/',
api.AssetRefreshHardwareApi.as_view(), name='asset-refresh'), api.AssetRefreshHardwareApi.as_view(), name='asset-refresh'),
path('assets/<uuid:pk>/alive/', path('assets/<uuid:pk>/alive/',
......
...@@ -28,6 +28,7 @@ from common.mixins import JSONResponseMixin ...@@ -28,6 +28,7 @@ from common.mixins import JSONResponseMixin
from common.utils import get_object_or_none, get_logger from common.utils import get_object_or_none, get_logger
from common.permissions import AdminUserRequiredMixin from common.permissions import AdminUserRequiredMixin
from common.const import create_success_msg, update_success_msg from common.const import create_success_msg, update_success_msg
from ..const import CACHE_KEY_ASSET_BULK_UPDATE_ID_PREFIX
from orgs.utils import current_org from orgs.utils import current_org
from .. import forms from .. import forms
from ..models import Asset, AdminUser, SystemUser, Label, Node, Domain from ..models import Asset, AdminUser, SystemUser, Label, Node, Domain
...@@ -120,15 +121,12 @@ class AssetBulkUpdateView(AdminUserRequiredMixin, ListView): ...@@ -120,15 +121,12 @@ class AssetBulkUpdateView(AdminUserRequiredMixin, ListView):
form = None form = None
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
assets_id = self.request.GET.get('assets_id', '') spm = request.GET.get('spm', '')
self.id_list = [i for i in assets_id.split(',')] assets_id = cache.get(CACHE_KEY_ASSET_BULK_UPDATE_ID_PREFIX.format(spm))
if kwargs.get('form'): if kwargs.get('form'):
self.form = kwargs['form'] self.form = kwargs['form']
elif assets_id: elif assets_id:
self.form = self.form_class( self.form = self.form_class(initial={'assets': assets_id})
initial={'assets': self.id_list}
)
else: else:
self.form = self.form_class() self.form = self.form_class()
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
......
...@@ -23,15 +23,15 @@ class OpenIDAuthenticationMiddleware(MiddlewareMixin): ...@@ -23,15 +23,15 @@ class OpenIDAuthenticationMiddleware(MiddlewareMixin):
def process_request(self, request): def process_request(self, request):
# Don't need openid auth if AUTH_OPENID is False # Don't need openid auth if AUTH_OPENID is False
if not settings.AUTH_OPENID: if not settings.AUTH_OPENID:
logger.info("Not settings.AUTH_OPENID") logger.debug("Not settings.AUTH_OPENID")
return return
# Don't need check single logout if user not authenticated # Don't need check single logout if user not authenticated
if not request.user.is_authenticated: if not request.user.is_authenticated:
logger.info("User is not authenticated") logger.debug("User is not authenticated")
return return
elif not request.session[BACKEND_SESSION_KEY].endswith( elif not request.session[BACKEND_SESSION_KEY].endswith(
BACKEND_OPENID_AUTH_CODE): BACKEND_OPENID_AUTH_CODE):
logger.info("BACKEND_SESSION_KEY is not BACKEND_OPENID_AUTH_CODE") logger.debug("BACKEND_SESSION_KEY is not BACKEND_OPENID_AUTH_CODE")
return return
# Check openid user single logout or not with access_token # Check openid user single logout or not with access_token
...@@ -40,7 +40,6 @@ class OpenIDAuthenticationMiddleware(MiddlewareMixin): ...@@ -40,7 +40,6 @@ class OpenIDAuthenticationMiddleware(MiddlewareMixin):
client.openid_connect_client.userinfo( client.openid_connect_client.userinfo(
token=request.session.get(OIDT_ACCESS_TOKEN) token=request.session.get(OIDT_ACCESS_TOKEN)
) )
except Exception as e: except Exception as e:
logout(request) logout(request)
logger.error(e) logger.error(e)
...@@ -14,6 +14,14 @@ class UserLoginForm(AuthenticationForm): ...@@ -14,6 +14,14 @@ class UserLoginForm(AuthenticationForm):
max_length=128, strip=False max_length=128, strip=False
) )
error_messages = {
'invalid_login': _(
"Please enter a correct username and password. Note that both "
"fields may be case-sensitive."
),
'inactive': _("This account is inactive."),
}
def confirm_login_allowed(self, user): def confirm_login_allowed(self, user):
if not user.is_staff: if not user.is_staff:
raise forms.ValidationError( raise forms.ValidationError(
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
</style> </style>
</head> </head>
<body style="height: 100%"> <body style="height: 100%;font-size: 13px">
<div> <div>
<div class="box-1"> <div class="box-1">
<div class="box-2"> <div class="box-2">
...@@ -60,19 +60,19 @@ ...@@ -60,19 +60,19 @@
</div> </div>
<div class="box-3"> <div class="box-3">
<div style="background-color: white"> <div style="background-color: white">
<div style="margin-top: 40px;padding-top: 50px;"> <div style="margin-top: 30px;padding-top: 40px;padding-left: 20px;padding-right: 20px;height: 80px">
<span style="font-size: 24px;font-weight:400;color: #151515;letter-spacing: 0;">{{ JMS_TITLE }}</span> <span style="font-size: 21px;font-weight:400;color: #151515;letter-spacing: 0;">{{ JMS_TITLE }}</span>
</div> </div>
<div style="font-size: 12px;color: #999999;letter-spacing: 0;line-height: 18px;margin-top: 10px"> <div style="font-size: 12px;color: #999999;letter-spacing: 0;line-height: 18px;margin-top: 18px">
{% trans 'Welcome back, please enter username and password to login' %} {% trans 'Welcome back, please enter username and password to login' %}
</div> </div>
<div style="margin-bottom: 10px"> <div style="margin-bottom: 10px">
<div> <div>
<div class="col-md-1"></div> <div class="col-md-1"></div>
<div class="contact-form col-md-10" style="margin-top: 20px;height: 35px"> <div class="contact-form col-md-10" style="margin-top: 10px;height: 35px">
<form id="contact-form" action="" method="post" role="form" novalidate="novalidate"> <form id="contact-form" action="" method="post" role="form" novalidate="novalidate">
{% csrf_token %} {% csrf_token %}
<div style="height: 48px;color: red"> <div style="height: 45px;color: red;line-height: 17px;">
{% if block_login %} {% if block_login %}
<p class="red-fonts">{% trans 'Log in frequently and try again later' %}</p> <p class="red-fonts">{% trans 'Log in frequently and try again later' %}</p>
{% elif password_expired %} {% elif password_expired %}
...@@ -92,7 +92,7 @@ ...@@ -92,7 +92,7 @@
<div class="form-group"> <div class="form-group">
<input type="password" class="form-control" name="{{ form.password.html_name }}" placeholder="{% trans 'Password' %}" required=""> <input type="password" class="form-control" name="{{ form.password.html_name }}" placeholder="{% trans 'Password' %}" required="">
</div> </div>
<div class="form-group" style="height: 50px;margin-bottom: 0"> <div class="form-group" style="height: 50px;margin-bottom: 0;font-size: 13px">
{{ form.captcha }} {{ form.captcha }}
</div> </div>
<div class="form-group" style="margin-top: 10px"> <div class="form-group" style="margin-top: 10px">
......
...@@ -59,6 +59,11 @@ class UserLoginView(FormView): ...@@ -59,6 +59,11 @@ class UserLoginView(FormView):
return redirect(redirect_user_first_login_or_index( return redirect(redirect_user_first_login_or_index(
request, self.redirect_field_name) request, self.redirect_field_name)
) )
# show jumpserver login page if request http://{JUMP-SERVER}/?admin=1
if settings.AUTH_OPENID and not self.request.GET.get('admin', 0):
query_string = request.GET.urlencode()
login_url = "{}?{}".format(settings.LOGIN_URL, query_string)
return redirect(login_url)
request.session.set_test_cookie() request.session.set_test_cookie()
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
create_success_msg = _("<b>%(name)s</b> was created successfully") create_success_msg = _("%(name)s was created successfully")
update_success_msg = _("<b>%(name)s</b> was updated successfully") update_success_msg = _("%(name)s was updated successfully")
FILE_END_GUARD = ">>> Content End <<<" FILE_END_GUARD = ">>> Content End <<<"
celery_task_pre_key = "CELERY_" celery_task_pre_key = "CELERY_"
...@@ -4,6 +4,10 @@ from django.db import models ...@@ -4,6 +4,10 @@ from django.db import models
from django.http import JsonResponse from django.http import JsonResponse
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework.utils import html
from rest_framework.settings import api_settings
from rest_framework.exceptions import ValidationError
from rest_framework.fields import SkipField
class NoDeleteQuerySet(models.query.QuerySet): class NoDeleteQuerySet(models.query.QuerySet):
...@@ -89,6 +93,60 @@ class BulkSerializerMixin(object): ...@@ -89,6 +93,60 @@ class BulkSerializerMixin(object):
return ret return ret
class BulkListSerializerMixin(object):
"""
Become rest_framework_bulk doing bulk update raise Exception:
'QuerySet' object has no attribute 'pk' when doing bulk update
so rewrite it .
https://github.com/miki725/django-rest-framework-bulk/issues/68
"""
def to_internal_value(self, data):
"""
List of dicts of native values <- List of dicts of primitive datatypes.
"""
if html.is_html_input(data):
data = html.parse_html_list(data)
if not isinstance(data, list):
message = self.error_messages['not_a_list'].format(
input_type=type(data).__name__
)
raise ValidationError({
api_settings.NON_FIELD_ERRORS_KEY: [message]
}, code='not_a_list')
if not self.allow_empty and len(data) == 0:
if self.parent and self.partial:
raise SkipField()
message = self.error_messages['empty']
raise ValidationError({
api_settings.NON_FIELD_ERRORS_KEY: [message]
}, code='empty')
ret = []
errors = []
for item in data:
try:
# prepare child serializer to only handle one instance
self.child.instance = self.instance.get(id=item['id']) if self.instance else None
self.child.initial_data = item
# raw
validated = self.child.run_validation(item)
except ValidationError as exc:
errors.append(exc.detail)
else:
ret.append(validated)
errors.append({})
if any(errors):
raise ValidationError(errors)
return ret
class DatetimeSearchMixin: class DatetimeSearchMixin:
date_format = '%Y-%m-%d' date_format = '%Y-%m-%d'
date_from = date_to = None date_from = date_to = None
......
...@@ -35,7 +35,7 @@ class IsSuperUser(IsValidUser): ...@@ -35,7 +35,7 @@ class IsSuperUser(IsValidUser):
class IsSuperUserOrAppUser(IsSuperUser): class IsSuperUserOrAppUser(IsSuperUser):
def has_permission(self, request, view): def has_permission(self, request, view):
return super(IsSuperUserOrAppUser, self).has_permission(request, view) \ return super(IsSuperUserOrAppUser, self).has_permission(request, view) \
and (request.user.is_superuser or request.user.is_app) or request.user.is_app
class IsOrgAdmin(IsValidUser): class IsOrgAdmin(IsValidUser):
......
# -*- coding: utf-8 -*-
#
from .mixins import BulkListSerializerMixin
from rest_framework_bulk.serializers import BulkListSerializer
class AdaptedBulkListSerializer(BulkListSerializerMixin, BulkListSerializer):
pass
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
VERSION = '1.4.9' VERSION = '1.4.10'
...@@ -15,7 +15,7 @@ def jumpserver_processor(request): ...@@ -15,7 +15,7 @@ def jumpserver_processor(request):
'FAVICON_URL': static('img/facio.ico'), 'FAVICON_URL': static('img/facio.ico'),
'JMS_TITLE': 'Jumpserver', 'JMS_TITLE': 'Jumpserver',
'VERSION': settings.VERSION, 'VERSION': settings.VERSION,
'COPYRIGHT': _('Beijing Duizhan Tech, Inc.') + ' © 2014-2019' 'COPYRIGHT': 'FIT2CLOUD 飞致云' + ' © 2014-2019'
} }
return context return context
......
...@@ -8,7 +8,7 @@ msgid "" ...@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n" "Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-03-27 17:33+0800\n" "POT-Creation-Date: 2019-04-29 12:22+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"
...@@ -17,6 +17,10 @@ msgstr "" ...@@ -17,6 +17,10 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: assets/api/asset.py:112
msgid "Please select assets that need to be updated"
msgstr "请选择需要更新的资产"
#: assets/api/node.py:58 #: assets/api/node.py:58
msgid "You can't update the root node name" msgid "You can't update the root node name"
msgstr "不能修改根节点名称" msgstr "不能修改根节点名称"
...@@ -32,7 +36,7 @@ msgstr "测试节点下资产是否可连接: {}" ...@@ -32,7 +36,7 @@ msgstr "测试节点下资产是否可连接: {}"
#: assets/forms/asset.py:27 assets/models/asset.py:80 assets/models/user.py:133 #: assets/forms/asset.py:27 assets/models/asset.py:80 assets/models/user.py:133
#: assets/templates/assets/asset_detail.html:194 #: assets/templates/assets/asset_detail.html:194
#: assets/templates/assets/asset_detail.html:202 #: assets/templates/assets/asset_detail.html:202
#: assets/templates/assets/system_user_asset.html:95 perms/models.py:31 #: assets/templates/assets/system_user_asset.html:95 perms/models.py:51
#: xpack/plugins/change_auth_plan/models.py:69 #: xpack/plugins/change_auth_plan/models.py:69
msgid "Nodes" msgid "Nodes"
msgstr "节点管理" msgstr "节点管理"
...@@ -69,7 +73,7 @@ msgstr "网域" ...@@ -69,7 +73,7 @@ msgstr "网域"
#: assets/forms/asset.py:112 assets/models/node.py:31 #: assets/forms/asset.py:112 assets/models/node.py:31
#: assets/templates/assets/asset_create.html:30 #: assets/templates/assets/asset_create.html:30
#: assets/templates/assets/asset_update.html:35 perms/forms.py:45 #: assets/templates/assets/asset_update.html:35 perms/forms.py:45
#: perms/forms.py:52 perms/models.py:84 #: perms/forms.py:55 perms/models.py:105
#: perms/templates/perms/asset_permission_list.html:57 #: perms/templates/perms/asset_permission_list.html:57
#: perms/templates/perms/asset_permission_list.html:78 #: perms/templates/perms/asset_permission_list.html:78
#: perms/templates/perms/asset_permission_list.html:128 #: perms/templates/perms/asset_permission_list.html:128
...@@ -116,7 +120,7 @@ msgstr "选择资产" ...@@ -116,7 +120,7 @@ msgstr "选择资产"
#: assets/templates/assets/system_user_list.html:33 audits/models.py:19 #: assets/templates/assets/system_user_list.html:33 audits/models.py:19
#: audits/templates/audits/ftp_log_list.html:41 #: audits/templates/audits/ftp_log_list.html:41
#: audits/templates/audits/ftp_log_list.html:71 perms/forms.py:42 #: audits/templates/audits/ftp_log_list.html:71 perms/forms.py:42
#: perms/models.py:30 #: perms/models.py:50
#: perms/templates/perms/asset_permission_create_update.html:45 #: perms/templates/perms/asset_permission_create_update.html:45
#: perms/templates/perms/asset_permission_list.html:56 #: perms/templates/perms/asset_permission_list.html:56
#: perms/templates/perms/asset_permission_list.html:125 #: perms/templates/perms/asset_permission_list.html:125
...@@ -126,7 +130,7 @@ msgstr "选择资产" ...@@ -126,7 +130,7 @@ msgstr "选择资产"
#: terminal/templates/terminal/session_list.html:41 #: terminal/templates/terminal/session_list.html:41
#: terminal/templates/terminal/session_list.html:72 #: terminal/templates/terminal/session_list.html:72
#: xpack/plugins/change_auth_plan/forms.py:114 #: xpack/plugins/change_auth_plan/forms.py:114
#: xpack/plugins/change_auth_plan/models.py:408 #: xpack/plugins/change_auth_plan/models.py:409
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:46 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:46
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:54 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:54
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:13 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:13
...@@ -160,7 +164,7 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC" ...@@ -160,7 +164,7 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC"
#: assets/templates/assets/system_user_detail.html:58 #: assets/templates/assets/system_user_detail.html:58
#: assets/templates/assets/system_user_list.html:29 ops/models/adhoc.py:37 #: assets/templates/assets/system_user_list.html:29 ops/models/adhoc.py:37
#: ops/templates/ops/task_detail.html:60 ops/templates/ops/task_list.html:27 #: ops/templates/ops/task_detail.html:60 ops/templates/ops/task_list.html:27
#: orgs/models.py:12 perms/models.py:27 #: orgs/models.py:12 perms/models.py:17 perms/models.py:47
#: perms/templates/perms/asset_permission_detail.html:62 #: perms/templates/perms/asset_permission_detail.html:62
#: perms/templates/perms/asset_permission_list.html:53 #: perms/templates/perms/asset_permission_list.html:53
#: perms/templates/perms/asset_permission_list.html:72 #: perms/templates/perms/asset_permission_list.html:72
...@@ -172,7 +176,7 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC" ...@@ -172,7 +176,7 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC"
#: settings/templates/settings/terminal_setting.html:102 terminal/models.py:22 #: settings/templates/settings/terminal_setting.html:102 terminal/models.py:22
#: terminal/models.py:241 terminal/templates/terminal/terminal_detail.html:43 #: terminal/models.py:241 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:54 users/templates/users/_select_user_modal.html:13 #: users/models/user.py:61 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:12 #: users/templates/users/user_group_list.html:12
...@@ -208,13 +212,13 @@ msgstr "名称" ...@@ -208,13 +212,13 @@ msgstr "名称"
#: ops/models/adhoc.py:164 perms/templates/perms/asset_permission_list.html:74 #: ops/models/adhoc.py:164 perms/templates/perms/asset_permission_list.html:74
#: perms/templates/perms/asset_permission_user.html:55 #: perms/templates/perms/asset_permission_user.html:55
#: settings/templates/settings/_ldap_list_users_modal.html:37 users/forms.py:13 #: settings/templates/settings/_ldap_list_users_modal.html:37 users/forms.py:13
#: users/models/user.py:52 users/templates/users/_select_user_modal.html:14 #: users/models/user.py:59 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:24 #: users/templates/users/user_list.html:24
#: users/templates/users/user_profile.html:47 #: users/templates/users/user_profile.html:47
#: xpack/plugins/change_auth_plan/forms.py:99 #: xpack/plugins/change_auth_plan/forms.py:99
#: xpack/plugins/change_auth_plan/models.py:60 #: xpack/plugins/change_auth_plan/models.py:60
#: xpack/plugins/change_auth_plan/models.py:404 #: xpack/plugins/change_auth_plan/models.py:405
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:65 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:65
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:53 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:53
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:12 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:12
...@@ -241,12 +245,12 @@ msgstr "密码或密钥密码" ...@@ -241,12 +245,12 @@ msgstr "密码或密钥密码"
#: users/templates/users/user_pubkey_update.html:40 #: users/templates/users/user_pubkey_update.html:40
#: users/templates/users/user_update.html:20 #: users/templates/users/user_update.html:20
#: xpack/plugins/change_auth_plan/models.py:90 #: xpack/plugins/change_auth_plan/models.py:90
#: xpack/plugins/change_auth_plan/models.py:259 #: xpack/plugins/change_auth_plan/models.py:260
msgid "Password" msgid "Password"
msgstr "密码" msgstr "密码"
#: assets/forms/user.py:29 assets/serializers/asset_user.py:27 #: assets/forms/user.py:29 assets/serializers/asset_user.py:27
#: users/models/user.py:81 #: users/models/user.py:88
msgid "Private key" msgid "Private key"
msgstr "ssh私钥" msgstr "ssh私钥"
...@@ -380,7 +384,7 @@ msgid "CPU model" ...@@ -380,7 +384,7 @@ msgid "CPU model"
msgstr "CPU型号" msgstr "CPU型号"
#: assets/models/asset.py:96 #: assets/models/asset.py:96
#: xpack/plugins/license/templates/license/license_detail.html:71 #: xpack/plugins/license/templates/license/license_detail.html:80
msgid "CPU count" msgid "CPU count"
msgstr "CPU数量" msgstr "CPU数量"
...@@ -435,9 +439,9 @@ msgstr "标签管理" ...@@ -435,9 +439,9 @@ msgstr "标签管理"
#: assets/templates/assets/cmd_filter_detail.html:77 #: assets/templates/assets/cmd_filter_detail.html:77
#: assets/templates/assets/domain_detail.html:72 #: assets/templates/assets/domain_detail.html:72
#: assets/templates/assets/system_user_detail.html:100 #: assets/templates/assets/system_user_detail.html:100
#: ops/templates/ops/adhoc_detail.html:86 orgs/models.py:15 perms/models.py:36 #: ops/templates/ops/adhoc_detail.html:86 orgs/models.py:15 perms/models.py:57
#: perms/models.py:89 perms/templates/perms/asset_permission_detail.html:98 #: perms/models.py:110 perms/templates/perms/asset_permission_detail.html:98
#: users/models/user.py:95 users/templates/users/user_detail.html:111 #: users/models/user.py:102 users/templates/users/user_detail.html:111
#: xpack/plugins/change_auth_plan/models.py:103 #: xpack/plugins/change_auth_plan/models.py:103
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113
#: xpack/plugins/cloud/models.py:55 xpack/plugins/cloud/models.py:127 #: xpack/plugins/cloud/models.py:55 xpack/plugins/cloud/models.py:127
...@@ -451,7 +455,7 @@ msgstr "创建者" ...@@ -451,7 +455,7 @@ msgstr "创建者"
#: assets/templates/assets/domain_detail.html:68 #: assets/templates/assets/domain_detail.html:68
#: assets/templates/assets/system_user_detail.html:96 #: assets/templates/assets/system_user_detail.html:96
#: 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:16 perms/models.py:37 perms/models.py:90 #: orgs/models.py:16 perms/models.py:58 perms/models.py:111
#: perms/templates/perms/asset_permission_detail.html:94 #: perms/templates/perms/asset_permission_detail.html:94
#: terminal/templates/terminal/terminal_detail.html:59 users/models/group.py:17 #: terminal/templates/terminal/terminal_detail.html:59 users/models/group.py:17
#: users/templates/users/user_group_detail.html:63 #: users/templates/users/user_group_detail.html:63
...@@ -479,10 +483,10 @@ msgstr "创建日期" ...@@ -479,10 +483,10 @@ msgstr "创建日期"
#: assets/templates/assets/system_user_detail.html:104 #: assets/templates/assets/system_user_detail.html:104
#: assets/templates/assets/system_user_list.html:37 #: assets/templates/assets/system_user_list.html:37
#: assets/templates/assets/user_asset_list.html:171 ops/models/adhoc.py:43 #: assets/templates/assets/user_asset_list.html:171 ops/models/adhoc.py:43
#: orgs/models.py:17 perms/models.py:38 perms/models.py:91 #: orgs/models.py:17 perms/models.py:59 perms/models.py:112
#: perms/templates/perms/asset_permission_detail.html:102 settings/models.py:34 #: perms/templates/perms/asset_permission_detail.html:102 settings/models.py:34
#: terminal/models.py:32 terminal/templates/terminal/terminal_detail.html:63 #: terminal/models.py:32 terminal/templates/terminal/terminal_detail.html:63
#: users/models/group.py:15 users/models/user.py:87 #: users/models/group.py:15 users/models/user.py:94
#: users/templates/users/user_detail.html:127 #: users/templates/users/user_detail.html:127
#: users/templates/users/user_group_detail.html:67 #: users/templates/users/user_group_detail.html:67
#: users/templates/users/user_group_list.html:14 #: users/templates/users/user_group_list.html:14
...@@ -537,12 +541,12 @@ msgid "AuthBook" ...@@ -537,12 +541,12 @@ msgid "AuthBook"
msgstr "" msgstr ""
#: assets/models/base.py:29 xpack/plugins/change_auth_plan/models.py:94 #: assets/models/base.py:29 xpack/plugins/change_auth_plan/models.py:94
#: xpack/plugins/change_auth_plan/models.py:266 #: xpack/plugins/change_auth_plan/models.py:267
msgid "SSH private key" msgid "SSH private key"
msgstr "ssh密钥" msgstr "ssh密钥"
#: assets/models/base.py:30 xpack/plugins/change_auth_plan/models.py:97 #: assets/models/base.py:30 xpack/plugins/change_auth_plan/models.py:97
#: xpack/plugins/change_auth_plan/models.py:262 #: xpack/plugins/change_auth_plan/models.py:263
msgid "SSH public key" msgid "SSH public key"
msgstr "ssh公钥" msgstr "ssh公钥"
...@@ -554,7 +558,7 @@ msgstr "带宽" ...@@ -554,7 +558,7 @@ msgstr "带宽"
msgid "Contact" msgid "Contact"
msgstr "联系人" msgstr "联系人"
#: assets/models/cluster.py:22 users/models/user.py:73 #: assets/models/cluster.py:22 users/models/user.py:80
#: users/templates/users/user_detail.html:76 #: users/templates/users/user_detail.html:76
msgid "Phone" msgid "Phone"
msgstr "手机" msgstr "手机"
...@@ -580,7 +584,7 @@ msgid "Default" ...@@ -580,7 +584,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:457 #: users/models/user.py:475
msgid "System" msgid "System"
msgstr "系统" msgstr "系统"
...@@ -675,7 +679,10 @@ msgstr "每行一个命令" ...@@ -675,7 +679,10 @@ msgstr "每行一个命令"
#: audits/templates/audits/operate_log_list.html:67 #: audits/templates/audits/operate_log_list.html:67
#: 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:34 #: ops/templates/ops/task_history.html:65 ops/templates/ops/task_list.html:34
#: perms/forms.py:51 perms/models.py:21 perms/models.py:53
#: perms/templates/perms/asset_permission_create_update.html:50
#: perms/templates/perms/asset_permission_list.html:60 #: perms/templates/perms/asset_permission_list.html:60
#: perms/templates/perms/asset_permission_list.html:134
#: settings/templates/settings/terminal_setting.html:82 #: settings/templates/settings/terminal_setting.html:82
#: settings/templates/settings/terminal_setting.html:104 #: settings/templates/settings/terminal_setting.html:104
#: terminal/templates/terminal/session_list.html:81 #: terminal/templates/terminal/session_list.html:81
...@@ -719,7 +726,7 @@ msgstr "默认资产组" ...@@ -719,7 +726,7 @@ msgstr "默认资产组"
#: audits/templates/audits/password_change_log_list.html:50 #: audits/templates/audits/password_change_log_list.html:50
#: ops/templates/ops/command_execution_list.html:35 #: ops/templates/ops/command_execution_list.html:35
#: ops/templates/ops/command_execution_list.html:60 perms/forms.py:36 #: ops/templates/ops/command_execution_list.html:60 perms/forms.py:36
#: perms/models.py:28 #: perms/models.py:48
#: perms/templates/perms/asset_permission_create_update.html:41 #: perms/templates/perms/asset_permission_create_update.html:41
#: perms/templates/perms/asset_permission_list.html:54 #: perms/templates/perms/asset_permission_list.html:54
#: perms/templates/perms/asset_permission_list.html:119 templates/index.html:87 #: perms/templates/perms/asset_permission_list.html:119 templates/index.html:87
...@@ -728,9 +735,9 @@ msgstr "默认资产组" ...@@ -728,9 +735,9 @@ msgstr "默认资产组"
#: terminal/templates/terminal/command_list.html:72 #: terminal/templates/terminal/command_list.html:72
#: terminal/templates/terminal/session_list.html:33 #: terminal/templates/terminal/session_list.html:33
#: terminal/templates/terminal/session_list.html:71 users/forms.py:283 #: terminal/templates/terminal/session_list.html:71 users/forms.py:283
#: users/models/user.py:32 users/models/user.py:445 #: users/models/user.py:36 users/models/user.py:463
#: users/templates/users/user_group_detail.html:78 #: users/templates/users/user_group_detail.html:78
#: users/templates/users/user_group_list.html:13 users/views/user.py:386 #: users/templates/users/user_group_list.html:13 users/views/user.py:395
#: xpack/plugins/orgs/forms.py:26 #: xpack/plugins/orgs/forms.py:26
#: xpack/plugins/orgs/templates/orgs/org_detail.html:113 #: xpack/plugins/orgs/templates/orgs/org_detail.html:113
#: xpack/plugins/orgs/templates/orgs/org_list.html:14 #: xpack/plugins/orgs/templates/orgs/org_list.html:14
...@@ -768,9 +775,9 @@ msgstr "手动登录" ...@@ -768,9 +775,9 @@ msgstr "手动登录"
#: assets/templates/assets/system_user_detail.html:22 #: assets/templates/assets/system_user_detail.html:22
#: assets/views/admin_user.py:29 assets/views/admin_user.py:47 #: assets/views/admin_user.py:29 assets/views/admin_user.py:47
#: assets/views/admin_user.py:63 assets/views/admin_user.py:78 #: assets/views/admin_user.py:63 assets/views/admin_user.py:78
#: assets/views/admin_user.py:102 assets/views/asset.py:50 #: assets/views/admin_user.py:102 assets/views/asset.py:51
#: assets/views/asset.py:66 assets/views/asset.py:103 assets/views/asset.py:147 #: assets/views/asset.py:67 assets/views/asset.py:104 assets/views/asset.py:145
#: assets/views/asset.py:164 assets/views/asset.py:188 #: assets/views/asset.py:162 assets/views/asset.py:186
#: assets/views/cmd_filter.py:30 assets/views/cmd_filter.py:46 #: assets/views/cmd_filter.py:30 assets/views/cmd_filter.py:46
#: assets/views/cmd_filter.py:62 assets/views/cmd_filter.py:78 #: assets/views/cmd_filter.py:62 assets/views/cmd_filter.py:78
#: assets/views/cmd_filter.py:97 assets/views/cmd_filter.py:130 #: assets/views/cmd_filter.py:97 assets/views/cmd_filter.py:130
...@@ -807,7 +814,7 @@ msgstr "登录模式" ...@@ -807,7 +814,7 @@ msgstr "登录模式"
#: assets/models/user.py:247 assets/templates/assets/user_asset_list.html:168 #: assets/models/user.py:247 assets/templates/assets/user_asset_list.html:168
#: audits/models.py:20 audits/templates/audits/ftp_log_list.html:49 #: audits/models.py:20 audits/templates/audits/ftp_log_list.html:49
#: audits/templates/audits/ftp_log_list.html:72 perms/forms.py:48 #: audits/templates/audits/ftp_log_list.html:72 perms/forms.py:48
#: perms/models.py:32 perms/models.py:86 #: perms/models.py:52 perms/models.py:107
#: perms/templates/perms/asset_permission_detail.html:140 #: perms/templates/perms/asset_permission_detail.html:140
#: perms/templates/perms/asset_permission_list.html:58 #: perms/templates/perms/asset_permission_list.html:58
#: perms/templates/perms/asset_permission_list.html:79 #: perms/templates/perms/asset_permission_list.html:79
...@@ -827,7 +834,7 @@ msgid "%(value)s is not an even number" ...@@ -827,7 +834,7 @@ msgid "%(value)s is not an even number"
msgstr "%(value)s is not an even number" msgstr "%(value)s is not an even number"
#: assets/serializers/asset_user.py:23 users/forms.py:230 #: assets/serializers/asset_user.py:23 users/forms.py:230
#: users/models/user.py:84 users/templates/users/first_login.html:42 #: users/models/user.py:91 users/templates/users/first_login.html:42
#: users/templates/users/user_password_update.html:46 #: users/templates/users/user_password_update.html:46
#: users/templates/users/user_profile.html:68 #: users/templates/users/user_profile.html:68
#: users/templates/users/user_profile_update.html:43 #: users/templates/users/user_profile_update.html:43
...@@ -954,7 +961,7 @@ msgstr "资产csv文件" ...@@ -954,7 +961,7 @@ msgstr "资产csv文件"
msgid "If set id, will use this id update asset existed" msgid "If set id, will use this id update asset existed"
msgstr "如果设置了id,则会使用该行信息更新该id的资产" msgstr "如果设置了id,则会使用该行信息更新该id的资产"
#: assets/templates/assets/_asset_list_modal.html:7 assets/views/asset.py:51 #: assets/templates/assets/_asset_list_modal.html:7 assets/views/asset.py:52
#: templates/_nav.html:22 xpack/plugins/change_auth_plan/views.py:110 #: templates/_nav.html:22 xpack/plugins/change_auth_plan/views.py:110
msgid "Asset list" msgid "Asset list"
msgstr "资产列表" msgstr "资产列表"
...@@ -1005,7 +1012,7 @@ msgstr "自动生成密钥" ...@@ -1005,7 +1012,7 @@ msgstr "自动生成密钥"
#: assets/templates/assets/asset_create.html:60 #: assets/templates/assets/asset_create.html:60
#: assets/templates/assets/asset_update.html:64 #: assets/templates/assets/asset_update.html:64
#: assets/templates/assets/gateway_create_update.html:53 #: assets/templates/assets/gateway_create_update.html:53
#: perms/templates/perms/asset_permission_create_update.html:50 #: perms/templates/perms/asset_permission_create_update.html:53
#: terminal/templates/terminal/terminal_update.html:40 #: terminal/templates/terminal/terminal_update.html:40
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:67 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:67
msgid "Other" msgid "Other"
...@@ -1021,12 +1028,12 @@ msgstr "其它" ...@@ -1021,12 +1028,12 @@ msgstr "其它"
#: assets/templates/assets/domain_create_update.html:16 #: assets/templates/assets/domain_create_update.html:16
#: assets/templates/assets/gateway_create_update.html:58 #: assets/templates/assets/gateway_create_update.html:58
#: assets/templates/assets/label_create_update.html:18 #: assets/templates/assets/label_create_update.html:18
#: perms/templates/perms/asset_permission_create_update.html:80 #: perms/templates/perms/asset_permission_create_update.html:83
#: settings/templates/settings/basic_setting.html:61 #: settings/templates/settings/basic_setting.html:61
#: settings/templates/settings/command_storage_create.html:79 #: settings/templates/settings/command_storage_create.html:79
#: settings/templates/settings/email_setting.html:62 #: settings/templates/settings/email_setting.html:62
#: settings/templates/settings/ldap_setting.html:61 #: settings/templates/settings/ldap_setting.html:61
#: settings/templates/settings/replay_storage_create.html:151 #: settings/templates/settings/replay_storage_create.html:152
#: settings/templates/settings/security_setting.html:70 #: settings/templates/settings/security_setting.html:70
#: settings/templates/settings/terminal_setting.html:68 #: settings/templates/settings/terminal_setting.html:68
#: terminal/templates/terminal/terminal_update.html:45 #: terminal/templates/terminal/terminal_update.html:45
...@@ -1057,12 +1064,12 @@ msgstr "重置" ...@@ -1057,12 +1064,12 @@ msgstr "重置"
#: assets/templates/assets/gateway_create_update.html:59 #: assets/templates/assets/gateway_create_update.html:59
#: assets/templates/assets/label_create_update.html:19 #: assets/templates/assets/label_create_update.html:19
#: audits/templates/audits/login_log_list.html:89 #: audits/templates/audits/login_log_list.html:89
#: perms/templates/perms/asset_permission_create_update.html:81 #: perms/templates/perms/asset_permission_create_update.html:84
#: settings/templates/settings/basic_setting.html:62 #: settings/templates/settings/basic_setting.html:62
#: settings/templates/settings/command_storage_create.html:80 #: settings/templates/settings/command_storage_create.html:80
#: settings/templates/settings/email_setting.html:63 #: settings/templates/settings/email_setting.html:63
#: settings/templates/settings/ldap_setting.html:64 #: settings/templates/settings/ldap_setting.html:64
#: settings/templates/settings/replay_storage_create.html:152 #: settings/templates/settings/replay_storage_create.html:153
#: settings/templates/settings/security_setting.html:71 #: settings/templates/settings/security_setting.html:71
#: settings/templates/settings/terminal_setting.html:70 #: settings/templates/settings/terminal_setting.html:70
#: terminal/templates/terminal/command_list.html:103 #: terminal/templates/terminal/command_list.html:103
...@@ -1076,13 +1083,13 @@ msgstr "重置" ...@@ -1076,13 +1083,13 @@ msgstr "重置"
#: users/templates/users/user_profile_update.html:64 #: users/templates/users/user_profile_update.html:64
#: users/templates/users/user_pubkey_update.html:77 #: users/templates/users/user_pubkey_update.html:77
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:72 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:72
#: xpack/plugins/interface/templates/interface/interface.html:73 #: xpack/plugins/interface/templates/interface/interface.html:74
msgid "Submit" msgid "Submit"
msgstr "提交" msgstr "提交"
#: assets/templates/assets/_user_asset_detail_modal.html:11 #: assets/templates/assets/_user_asset_detail_modal.html:11
#: assets/templates/assets/asset_asset_user_list.html:17 #: assets/templates/assets/asset_asset_user_list.html:17
#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:189 #: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:187
msgid "Asset detail" msgid "Asset detail"
msgstr "资产详情" msgstr "资产详情"
...@@ -1139,60 +1146,61 @@ msgid "Test connective" ...@@ -1139,60 +1146,61 @@ msgid "Test connective"
msgstr "测试可连接性" msgstr "测试可连接性"
#: assets/templates/assets/admin_user_assets.html:73 #: assets/templates/assets/admin_user_assets.html:73
#: assets/templates/assets/admin_user_assets.html:114 #: assets/templates/assets/admin_user_assets.html:115
#: assets/templates/assets/asset_asset_user_list.html:74 #: assets/templates/assets/asset_asset_user_list.html:74
#: assets/templates/assets/asset_asset_user_list.html:122 #: assets/templates/assets/asset_asset_user_list.html:122
#: assets/templates/assets/asset_detail.html:182 #: assets/templates/assets/asset_detail.html:182
#: assets/templates/assets/system_user_asset.html:75 #: assets/templates/assets/system_user_asset.html:75
#: assets/templates/assets/system_user_asset.html:164 #: assets/templates/assets/system_user_asset.html:165
#: assets/templates/assets/system_user_detail.html:151 #: assets/templates/assets/system_user_detail.html:151
msgid "Test" msgid "Test"
msgstr "测试" msgstr "测试"
#: assets/templates/assets/admin_user_assets.html:115 #: assets/templates/assets/admin_user_assets.html:116
#: assets/templates/assets/asset_asset_user_list.html:120 #: assets/templates/assets/asset_asset_user_list.html:120
#: assets/templates/assets/system_user_asset.html:166 #: assets/templates/assets/system_user_asset.html:167
msgid "Update auth" msgid "Update auth"
msgstr "更新认证" msgstr "更新认证"
#: assets/templates/assets/admin_user_assets.html:191 #: assets/templates/assets/admin_user_assets.html:192
#: assets/templates/assets/asset_asset_user_list.html:176 #: assets/templates/assets/asset_asset_user_list.html:176
#: assets/templates/assets/asset_detail.html:311 #: assets/templates/assets/asset_detail.html:311
#: assets/templates/assets/system_user_asset.html:350 #: assets/templates/assets/system_user_asset.html:351
#: users/templates/users/user_detail.html:307 #: users/templates/users/user_detail.html:307
#: users/templates/users/user_detail.html:334 #: users/templates/users/user_detail.html:334
#: xpack/plugins/interface/views.py:31 #: xpack/plugins/interface/views.py:34
msgid "Update successfully!" msgid "Update successfully!"
msgstr "更新成功" msgstr "更新成功"
#: assets/templates/assets/admin_user_assets.html:194 #: assets/templates/assets/admin_user_assets.html:195
#: assets/templates/assets/asset_asset_user_list.html:179 #: assets/templates/assets/asset_asset_user_list.html:179
#: assets/templates/assets/system_user_asset.html:353 #: assets/templates/assets/system_user_asset.html:354
msgid "Update failed!" msgid "Update failed!"
msgstr "更新失败" msgstr "更新失败"
#: assets/templates/assets/admin_user_detail.html:24 #: assets/templates/assets/admin_user_detail.html:24
#: assets/templates/assets/admin_user_list.html:88 #: assets/templates/assets/admin_user_list.html:88
#: assets/templates/assets/asset_detail.html:27 #: assets/templates/assets/asset_detail.html:27
#: assets/templates/assets/asset_list.html:177 #: assets/templates/assets/asset_list.html:178
#: assets/templates/assets/cmd_filter_detail.html:29 #: assets/templates/assets/cmd_filter_detail.html:29
#: assets/templates/assets/cmd_filter_list.html:57 #: assets/templates/assets/cmd_filter_list.html:58
#: assets/templates/assets/cmd_filter_rule_list.html:86 #: assets/templates/assets/cmd_filter_rule_list.html:86
#: assets/templates/assets/domain_detail.html:24 #: assets/templates/assets/domain_detail.html:24
#: assets/templates/assets/domain_detail.html:103 #: assets/templates/assets/domain_detail.html:103
#: assets/templates/assets/domain_gateway_list.html:97 #: assets/templates/assets/domain_gateway_list.html:97
#: assets/templates/assets/domain_list.html:53 #: assets/templates/assets/domain_list.html:54
#: assets/templates/assets/label_list.html:38 #: assets/templates/assets/label_list.html:39
#: assets/templates/assets/system_user_detail.html:26 #: assets/templates/assets/system_user_detail.html:26
#: assets/templates/assets/system_user_list.html:92 audits/models.py:33 #: assets/templates/assets/system_user_list.html:93 audits/models.py:33
#: perms/templates/perms/asset_permission_detail.html:30 #: perms/templates/perms/asset_permission_detail.html:30
#: perms/templates/perms/asset_permission_list.html:177 #: perms/templates/perms/asset_permission_list.html:181
#: terminal/templates/terminal/terminal_detail.html:16 #: terminal/templates/terminal/terminal_detail.html:16
#: terminal/templates/terminal/terminal_list.html:71 #: terminal/templates/terminal/terminal_list.html:72
#: users/templates/users/user_detail.html:25 #: users/templates/users/user_detail.html:25
#: users/templates/users/user_group_detail.html:28 #: users/templates/users/user_group_detail.html:28
#: users/templates/users/user_group_list.html:43 #: users/templates/users/user_group_list.html:45
#: users/templates/users/user_list.html:80 #: users/templates/users/user_list.html:83
#: users/templates/users/user_list.html:86
#: users/templates/users/user_profile.html:177 #: users/templates/users/user_profile.html:177
#: users/templates/users/user_profile.html:187 #: users/templates/users/user_profile.html:187
#: users/templates/users/user_profile.html:196 #: users/templates/users/user_profile.html:196
...@@ -1208,28 +1216,28 @@ msgstr "更新" ...@@ -1208,28 +1216,28 @@ msgstr "更新"
#: assets/templates/assets/admin_user_detail.html:28 #: assets/templates/assets/admin_user_detail.html:28
#: assets/templates/assets/admin_user_list.html:89 #: assets/templates/assets/admin_user_list.html:89
#: assets/templates/assets/asset_detail.html:31 #: assets/templates/assets/asset_detail.html:31
#: assets/templates/assets/asset_list.html:178 #: assets/templates/assets/asset_list.html:179
#: assets/templates/assets/cmd_filter_detail.html:33 #: assets/templates/assets/cmd_filter_detail.html:33
#: assets/templates/assets/cmd_filter_list.html:58 #: assets/templates/assets/cmd_filter_list.html:59
#: assets/templates/assets/cmd_filter_rule_list.html:87 #: assets/templates/assets/cmd_filter_rule_list.html:87
#: assets/templates/assets/domain_detail.html:28 #: assets/templates/assets/domain_detail.html:28
#: assets/templates/assets/domain_detail.html:104 #: assets/templates/assets/domain_detail.html:104
#: assets/templates/assets/domain_gateway_list.html:98 #: assets/templates/assets/domain_gateway_list.html:98
#: assets/templates/assets/domain_list.html:54 #: assets/templates/assets/domain_list.html:55
#: assets/templates/assets/label_list.html:39 #: assets/templates/assets/label_list.html:40
#: assets/templates/assets/system_user_detail.html:30 #: assets/templates/assets/system_user_detail.html:30
#: assets/templates/assets/system_user_list.html:93 audits/models.py:34 #: assets/templates/assets/system_user_list.html:94 audits/models.py:34
#: ops/templates/ops/task_list.html:64 #: ops/templates/ops/task_list.html:64
#: perms/templates/perms/asset_permission_detail.html:34 #: perms/templates/perms/asset_permission_detail.html:34
#: perms/templates/perms/asset_permission_list.html:178 #: perms/templates/perms/asset_permission_list.html:182
#: settings/templates/settings/terminal_setting.html:90 #: settings/templates/settings/terminal_setting.html:90
#: settings/templates/settings/terminal_setting.html:112 #: settings/templates/settings/terminal_setting.html:112
#: terminal/templates/terminal/terminal_list.html:73 #: terminal/templates/terminal/terminal_list.html:74
#: users/templates/users/user_detail.html:30 #: users/templates/users/user_detail.html:30
#: users/templates/users/user_group_detail.html:32 #: users/templates/users/user_group_detail.html:32
#: users/templates/users/user_group_list.html:45 #: users/templates/users/user_group_list.html:47
#: users/templates/users/user_list.html:84 #: users/templates/users/user_list.html:91
#: users/templates/users/user_list.html:88 #: users/templates/users/user_list.html:95
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:33 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:33
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:56 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:56
#: xpack/plugins/cloud/templates/cloud/account_detail.html:29 #: xpack/plugins/cloud/templates/cloud/account_detail.html:29
...@@ -1254,11 +1262,11 @@ msgstr "选择节点" ...@@ -1254,11 +1262,11 @@ msgstr "选择节点"
#: assets/templates/assets/admin_user_detail.html:100 #: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:211 #: assets/templates/assets/asset_detail.html:211
#: assets/templates/assets/asset_list.html:636 #: assets/templates/assets/asset_list.html:637
#: assets/templates/assets/cmd_filter_detail.html:106 #: assets/templates/assets/cmd_filter_detail.html:106
#: assets/templates/assets/system_user_asset.html:112 #: assets/templates/assets/system_user_asset.html:112
#: assets/templates/assets/system_user_detail.html:182 #: assets/templates/assets/system_user_detail.html:182
#: assets/templates/assets/system_user_list.html:143 #: assets/templates/assets/system_user_list.html:144
#: settings/templates/settings/terminal_setting.html:165 #: settings/templates/settings/terminal_setting.html:165
#: templates/_modal.html:23 terminal/templates/terminal/session_detail.html:108 #: templates/_modal.html:23 terminal/templates/terminal/session_detail.html:108
#: users/templates/users/user_detail.html:388 #: users/templates/users/user_detail.html:388
...@@ -1266,11 +1274,12 @@ msgstr "选择节点" ...@@ -1266,11 +1274,12 @@ msgstr "选择节点"
#: users/templates/users/user_detail.html:437 #: users/templates/users/user_detail.html:437
#: users/templates/users/user_detail.html:482 #: users/templates/users/user_detail.html:482
#: users/templates/users/user_group_create_update.html:32 #: users/templates/users/user_group_create_update.html:32
#: users/templates/users/user_group_list.html:88 #: users/templates/users/user_group_list.html:90
#: users/templates/users/user_list.html:208 #: users/templates/users/user_list.html:215
#: users/templates/users/user_profile.html:238 #: users/templates/users/user_profile.html:238
#: xpack/plugins/cloud/templates/cloud/account_create_update.html:34 #: xpack/plugins/cloud/templates/cloud/account_create_update.html:34
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:36 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:36
#: xpack/plugins/interface/templates/interface/interface.html:103
#: xpack/plugins/orgs/templates/orgs/org_create_update.html:33 #: xpack/plugins/orgs/templates/orgs/org_create_update.html:33
msgid "Confirm" msgid "Confirm"
msgstr "确认" msgstr "确认"
...@@ -1305,7 +1314,7 @@ msgid "Ratio" ...@@ -1305,7 +1314,7 @@ msgid "Ratio"
msgstr "比例" msgstr "比例"
#: assets/templates/assets/asset_asset_user_list.html:20 #: assets/templates/assets/asset_asset_user_list.html:20
#: assets/templates/assets/asset_detail.html:23 assets/views/asset.py:67 #: assets/templates/assets/asset_detail.html:23 assets/views/asset.py:68
msgid "Asset user list" msgid "Asset user list"
msgstr "资产用户列表" msgstr "资产用户列表"
...@@ -1329,7 +1338,7 @@ msgstr "更新日期" ...@@ -1329,7 +1338,7 @@ msgstr "更新日期"
#: users/templates/users/user_detail.html:138 #: users/templates/users/user_detail.html:138
#: users/templates/users/user_profile.html:146 #: users/templates/users/user_profile.html:146
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:128 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:128
#: xpack/plugins/license/templates/license/license_detail.html:93 #: xpack/plugins/license/templates/license/license_detail.html:102
msgid "Quick modify" msgid "Quick modify"
msgstr "快速修改" msgstr "快速修改"
...@@ -1358,9 +1367,9 @@ msgid "Date joined" ...@@ -1358,9 +1367,9 @@ msgid "Date joined"
msgstr "创建日期" msgstr "创建日期"
#: assets/templates/assets/asset_detail.html:154 #: assets/templates/assets/asset_detail.html:154
#: assets/templates/assets/user_asset_list.html:46 perms/models.py:33 #: assets/templates/assets/user_asset_list.html:46 perms/models.py:54
#: perms/models.py:87 #: perms/models.py:108
#: perms/templates/perms/asset_permission_create_update.html:52 #: perms/templates/perms/asset_permission_create_update.html:55
#: perms/templates/perms/asset_permission_detail.html:120 #: perms/templates/perms/asset_permission_detail.html:120
#: terminal/templates/terminal/terminal_list.html:34 #: terminal/templates/terminal/terminal_list.html:34
#: users/templates/users/_select_user_modal.html:18 #: users/templates/users/_select_user_modal.html:18
...@@ -1388,14 +1397,14 @@ msgstr "" ...@@ -1388,14 +1397,14 @@ msgstr ""
"左侧是资产树,右击可以新建、删除、更改树节点,授权资产也是以节点方式组织的," "左侧是资产树,右击可以新建、删除、更改树节点,授权资产也是以节点方式组织的,"
"右侧是属于该节点下的资产" "右侧是属于该节点下的资产"
#: assets/templates/assets/asset_list.html:69 assets/views/asset.py:104 #: assets/templates/assets/asset_list.html:69 assets/views/asset.py:105
msgid "Create asset" msgid "Create asset"
msgstr "创建资产" msgstr "创建资产"
#: assets/templates/assets/asset_list.html:73 #: assets/templates/assets/asset_list.html:73
#: settings/templates/settings/_ldap_list_users_modal.html:97 #: settings/templates/settings/_ldap_list_users_modal.html:97
#: users/templates/users/user_list.html:7 #: users/templates/users/user_list.html:7
#: xpack/plugins/license/templates/license/license_detail.html:101 #: xpack/plugins/license/templates/license/license_detail.html:110
msgid "Import" msgid "Import"
msgstr "导入" msgstr "导入"
...@@ -1473,63 +1482,65 @@ msgstr "仅显示当前节点资产" ...@@ -1473,63 +1482,65 @@ msgstr "仅显示当前节点资产"
msgid "Displays all child node assets" msgid "Displays all child node assets"
msgstr "显示所有子节点资产" msgstr "显示所有子节点资产"
#: assets/templates/assets/asset_list.html:216 #: assets/templates/assets/asset_list.html:217
msgid "Create node failed" msgid "Create node failed"
msgstr "创建节点失败" msgstr "创建节点失败"
#: assets/templates/assets/asset_list.html:228 #: assets/templates/assets/asset_list.html:229
msgid "Have child node, cancel" msgid "Have child node, cancel"
msgstr "存在子节点,不能删除" msgstr "存在子节点,不能删除"
#: assets/templates/assets/asset_list.html:230 #: assets/templates/assets/asset_list.html:231
msgid "Have assets, cancel" msgid "Have assets, cancel"
msgstr "存在资产,不能删除" msgstr "存在资产,不能删除"
#: assets/templates/assets/asset_list.html:301 #: assets/templates/assets/asset_list.html:302
msgid "Rename success" msgid "Rename success"
msgstr "重命名成功" msgstr "重命名成功"
#: assets/templates/assets/asset_list.html:302 #: assets/templates/assets/asset_list.html:303
msgid "Rename failed, do not change the root node name" msgid "Rename failed, do not change the root node name"
msgstr "重命名失败,不能更改root节点的名称" msgstr "重命名失败,不能更改root节点的名称"
#: assets/templates/assets/asset_list.html:630 #: assets/templates/assets/asset_list.html:631
#: assets/templates/assets/system_user_list.html:137 #: assets/templates/assets/system_user_list.html:138
#: users/templates/users/user_detail.html:382 #: users/templates/users/user_detail.html:382
#: users/templates/users/user_detail.html:408 #: users/templates/users/user_detail.html:408
#: users/templates/users/user_detail.html:476 #: users/templates/users/user_detail.html:476
#: users/templates/users/user_group_list.html:82 #: users/templates/users/user_group_list.html:84
#: users/templates/users/user_list.html:202 #: users/templates/users/user_list.html:209
#: xpack/plugins/interface/templates/interface/interface.html:97
msgid "Are you sure?" msgid "Are you sure?"
msgstr "你确认吗?" msgstr "你确认吗?"
#: assets/templates/assets/asset_list.html:631 #: assets/templates/assets/asset_list.html:632
msgid "This will delete the selected assets !!!" msgid "This will delete the selected assets !!!"
msgstr "删除选择资产" msgstr "删除选择资产"
#: assets/templates/assets/asset_list.html:634 #: assets/templates/assets/asset_list.html:635
#: assets/templates/assets/system_user_list.html:141 #: assets/templates/assets/system_user_list.html:142
#: settings/templates/settings/terminal_setting.html:163 #: settings/templates/settings/terminal_setting.html:163
#: users/templates/users/user_detail.html:386 #: users/templates/users/user_detail.html:386
#: users/templates/users/user_detail.html:412 #: users/templates/users/user_detail.html:412
#: users/templates/users/user_detail.html:480 #: users/templates/users/user_detail.html:480
#: users/templates/users/user_group_create_update.html:31 #: users/templates/users/user_group_create_update.html:31
#: users/templates/users/user_group_list.html:86 #: users/templates/users/user_group_list.html:88
#: users/templates/users/user_list.html:206 #: users/templates/users/user_list.html:213
#: xpack/plugins/interface/templates/interface/interface.html:101
#: xpack/plugins/orgs/templates/orgs/org_create_update.html:32 #: xpack/plugins/orgs/templates/orgs/org_create_update.html:32
msgid "Cancel" msgid "Cancel"
msgstr "取消" msgstr "取消"
#: assets/templates/assets/asset_list.html:640 #: assets/templates/assets/asset_list.html:641
msgid "Asset Deleted." msgid "Asset Deleted."
msgstr "已被删除" msgstr "已被删除"
#: assets/templates/assets/asset_list.html:641 #: assets/templates/assets/asset_list.html:642
#: assets/templates/assets/asset_list.html:646 #: assets/templates/assets/asset_list.html:647
msgid "Asset Delete" msgid "Asset Delete"
msgstr "删除" msgstr "删除"
#: assets/templates/assets/asset_list.html:645 #: assets/templates/assets/asset_list.html:646
msgid "Asset Deleting failed." msgid "Asset Deleting failed."
msgstr "删除失败" msgstr "删除失败"
...@@ -1661,7 +1672,7 @@ msgid "Push system user now" ...@@ -1661,7 +1672,7 @@ msgid "Push system user now"
msgstr "立刻推送系统" msgstr "立刻推送系统"
#: assets/templates/assets/system_user_asset.html:84 #: assets/templates/assets/system_user_asset.html:84
#: assets/templates/assets/system_user_asset.html:162 #: assets/templates/assets/system_user_asset.html:163
#: assets/templates/assets/system_user_detail.html:142 #: assets/templates/assets/system_user_detail.html:142
msgid "Push" msgid "Push"
msgstr "推送" msgstr "推送"
...@@ -1717,24 +1728,24 @@ msgstr "" ...@@ -1717,24 +1728,24 @@ msgstr ""
msgid "Create system user" msgid "Create system user"
msgstr "创建系统用户" msgstr "创建系统用户"
#: assets/templates/assets/system_user_list.html:138 #: assets/templates/assets/system_user_list.html:139
msgid "This will delete the selected System Users !!!" msgid "This will delete the selected System Users !!!"
msgstr "删除选择系统用户" msgstr "删除选择系统用户"
#: assets/templates/assets/system_user_list.html:147 #: assets/templates/assets/system_user_list.html:148
msgid "System Users Deleted." msgid "System Users Deleted."
msgstr "已被删除" msgstr "已被删除"
#: assets/templates/assets/system_user_list.html:148 #: assets/templates/assets/system_user_list.html:149
#: assets/templates/assets/system_user_list.html:153 #: assets/templates/assets/system_user_list.html:154
msgid "System Users Delete" msgid "System Users Delete"
msgstr "删除系统用户" msgstr "删除系统用户"
#: assets/templates/assets/system_user_list.html:152 #: assets/templates/assets/system_user_list.html:153
msgid "System Users Deleting failed." msgid "System Users Deleting failed."
msgstr "系统用户删除失败" msgstr "系统用户删除失败"
#: assets/templates/assets/user_asset_list.html:100 #: assets/templates/assets/user_asset_list.html:100 perms/const.py:19
msgid "Connect" msgid "Connect"
msgstr "连接" msgstr "连接"
...@@ -1750,23 +1761,23 @@ msgstr "更新管理用户" ...@@ -1750,23 +1761,23 @@ msgstr "更新管理用户"
msgid "Admin user detail" msgid "Admin user detail"
msgstr "管理用户详情" msgstr "管理用户详情"
#: assets/views/asset.py:78 templates/_nav_user.html:4 #: assets/views/asset.py:79 templates/_nav_user.html:4
msgid "My assets" msgid "My assets"
msgstr "我的资产" msgstr "我的资产"
#: assets/views/asset.py:118 #: assets/views/asset.py:119
msgid "Bulk update asset success" msgid "Bulk update asset success"
msgstr "批量更新资产成功" msgstr "批量更新资产成功"
#: assets/views/asset.py:148 #: assets/views/asset.py:146
msgid "Bulk update asset" msgid "Bulk update asset"
msgstr "批量更新资产" msgstr "批量更新资产"
#: assets/views/asset.py:165 #: assets/views/asset.py:163
msgid "Update asset" msgid "Update asset"
msgstr "更新资产" msgstr "更新资产"
#: assets/views/asset.py:306 #: assets/views/asset.py:304
msgid "already exists" msgid "already exists"
msgstr "已经存在" msgstr "已经存在"
...@@ -1938,13 +1949,13 @@ msgid "User agent" ...@@ -1938,13 +1949,13 @@ msgid "User agent"
msgstr "Agent" msgstr "Agent"
#: audits/models.py:99 audits/templates/audits/login_log_list.html:56 #: audits/models.py:99 audits/templates/audits/login_log_list.html:56
#: users/forms.py:142 users/models/user.py:76 #: users/forms.py:142 users/models/user.py:83
#: users/templates/users/first_login.html:45 #: users/templates/users/first_login.html:45
msgid "MFA" msgid "MFA"
msgstr "MFA" msgstr "MFA"
#: audits/models.py:100 audits/templates/audits/login_log_list.html:57 #: audits/models.py:100 audits/templates/audits/login_log_list.html:57
#: xpack/plugins/change_auth_plan/models.py:412 #: xpack/plugins/change_auth_plan/models.py:413
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:15 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:15
#: xpack/plugins/cloud/models.py:172 #: xpack/plugins/cloud/models.py:172
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:69 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:69
...@@ -1966,11 +1977,11 @@ msgstr "登录日期" ...@@ -1966,11 +1977,11 @@ msgstr "登录日期"
#: ops/templates/ops/adhoc_history.html:52 #: ops/templates/ops/adhoc_history.html:52
#: ops/templates/ops/adhoc_history_detail.html:61 #: ops/templates/ops/adhoc_history_detail.html:61
#: ops/templates/ops/command_execution_list.html:66 #: ops/templates/ops/command_execution_list.html:66
#: ops/templates/ops/task_history.html:58 perms/models.py:34 #: ops/templates/ops/task_history.html:58 perms/models.py:55
#: perms/templates/perms/asset_permission_detail.html:86 terminal/models.py:165 #: perms/templates/perms/asset_permission_detail.html:86 terminal/models.py:165
#: terminal/templates/terminal/session_list.html:78 #: terminal/templates/terminal/session_list.html:78
#: xpack/plugins/change_auth_plan/models.py:245 #: xpack/plugins/change_auth_plan/models.py:246
#: xpack/plugins/change_auth_plan/models.py:415 #: xpack/plugins/change_auth_plan/models.py:416
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:59 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:59
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:17 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:17
msgid "Date start" msgid "Date start"
...@@ -1988,7 +1999,7 @@ msgstr "选择用户" ...@@ -1988,7 +1999,7 @@ msgstr "选择用户"
#: ops/templates/ops/command_execution_list.html:43 #: ops/templates/ops/command_execution_list.html:43
#: ops/templates/ops/command_execution_list.html:48 #: ops/templates/ops/command_execution_list.html:48
#: ops/templates/ops/task_list.html:13 ops/templates/ops/task_list.html:18 #: ops/templates/ops/task_list.html:13 ops/templates/ops/task_list.html:18
#: templates/_base_list.html:43 templates/_header_bar.html:8 #: templates/_base_list.html:41 templates/_header_bar.html:8
#: terminal/templates/terminal/command_list.html:60 #: terminal/templates/terminal/command_list.html:60
#: terminal/templates/terminal/session_list.html:61 #: terminal/templates/terminal/session_list.html:61
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:52 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_history.html:52
...@@ -2125,7 +2136,17 @@ msgstr "" ...@@ -2125,7 +2136,17 @@ msgstr ""
msgid "Invalid token or cache refreshed." msgid "Invalid token or cache refreshed."
msgstr "" msgstr ""
#: authentication/forms.py:29 users/forms.py:21 #: authentication/forms.py:19
msgid ""
"Please enter a correct username and password. Note that both fields may be "
"case-sensitive."
msgstr "请输入正确的用户名和密码. 注意它们是区分大小写."
#: authentication/forms.py:22
msgid "This account is inactive."
msgstr "此账户无效"
#: authentication/forms.py:37 users/forms.py:21
msgid "MFA code" msgid "MFA code"
msgstr "MFA 验证码" msgstr "MFA 验证码"
...@@ -2249,32 +2270,32 @@ msgstr "如果不能提供MFA验证码,请联系管理员!" ...@@ -2249,32 +2270,32 @@ msgstr "如果不能提供MFA验证码,请联系管理员!"
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:75 #: authentication/views/login.py:80
msgid "Please enable cookies and try again." msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie" msgstr "设置你的浏览器支持cookie"
#: authentication/views/login.py:167 users/views/user.py:532 #: authentication/views/login.py:172 users/views/user.py:541
#: users/views/user.py:557 #: users/views/user.py:566
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:198 #: authentication/views/login.py:203
msgid "Logout success" msgid "Logout success"
msgstr "退出登录成功" msgstr "退出登录成功"
#: authentication/views/login.py:199 #: authentication/views/login.py:204
msgid "Logout success, return login page" msgid "Logout success, return login page"
msgstr "退出登录成功,返回到登录页面" msgstr "退出登录成功,返回到登录页面"
#: common/const.py:6 #: common/const.py:6
#, python-format #, python-format
msgid "<b>%(name)s</b> was created successfully" msgid "%(name)s was created successfully"
msgstr "<b>%(name)s</b> 创建成功" msgstr "%(name)s 创建成功"
#: common/const.py:7 #: common/const.py:7
#, python-format #, python-format
msgid "<b>%(name)s</b> was updated successfully" msgid "%(name)s was updated successfully"
msgstr "<b>%(name)s</b> 更新成功" msgstr "%(name)s 更新成功"
#: common/fields/form.py:34 #: common/fields/form.py:34
msgid "Not a valid json" msgid "Not a valid json"
...@@ -2312,11 +2333,11 @@ msgstr "" ...@@ -2312,11 +2333,11 @@ msgstr ""
msgid "Encrypt field using Secret Key" msgid "Encrypt field using Secret Key"
msgstr "" msgstr ""
#: common/mixins.py:28 #: common/mixins.py:32
msgid "is discard" msgid "is discard"
msgstr "" msgstr ""
#: common/mixins.py:29 #: common/mixins.py:33
msgid "discard time" msgid "discard time"
msgstr "" msgstr ""
...@@ -2324,10 +2345,6 @@ msgstr "" ...@@ -2324,10 +2345,6 @@ msgstr ""
msgid "Special char not allowed" msgid "Special char not allowed"
msgstr "不能包含特殊字符" msgstr "不能包含特殊字符"
#: jumpserver/context_processor.py:18
msgid "Beijing Duizhan Tech, Inc."
msgstr "北京堆栈科技有限公司"
#: jumpserver/views.py:185 #: jumpserver/views.py:185
msgid "" msgid ""
"<div>Luna is a separately deployed program, you need to deploy Luna, coco, " "<div>Luna is a separately deployed program, you need to deploy Luna, coco, "
...@@ -2421,8 +2438,8 @@ msgstr "完成时间" ...@@ -2421,8 +2438,8 @@ msgstr "完成时间"
#: ops/models/adhoc.py:326 ops/templates/ops/adhoc_history.html:57 #: ops/models/adhoc.py:326 ops/templates/ops/adhoc_history.html:57
#: ops/templates/ops/task_history.html:63 ops/templates/ops/task_list.html:33 #: ops/templates/ops/task_history.html:63 ops/templates/ops/task_list.html:33
#: xpack/plugins/change_auth_plan/models.py:248 #: xpack/plugins/change_auth_plan/models.py:249
#: xpack/plugins/change_auth_plan/models.py:418 #: xpack/plugins/change_auth_plan/models.py:419
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:58 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:58
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:16 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:16
msgid "Time" msgid "Time"
...@@ -2572,33 +2589,33 @@ msgstr "任务列表" ...@@ -2572,33 +2589,33 @@ msgstr "任务列表"
msgid "Go" msgid "Go"
msgstr "" msgstr ""
#: ops/templates/ops/command_execution_create.html:148 #: ops/templates/ops/command_execution_create.html:152
msgid "Selected assets" msgid "Selected assets"
msgstr "已选择资产" msgstr "已选择资产"
#: ops/templates/ops/command_execution_create.html:151 #: ops/templates/ops/command_execution_create.html:155
msgid "In total" msgid "In total"
msgstr "总共" msgstr "总共"
#: ops/templates/ops/command_execution_create.html:186 #: ops/templates/ops/command_execution_create.html:190
msgid "" msgid ""
"Select the left asset, select the running system user, execute command in " "Select the left asset, select the running system user, execute command in "
"batch" "batch"
msgstr "选择左侧资产, 选择运行的系统用户,批量执行命令" msgstr "选择左侧资产, 选择运行的系统用户,批量执行命令"
#: ops/templates/ops/command_execution_create.html:204 #: ops/templates/ops/command_execution_create.html:208
msgid "Unselected assets" msgid "Unselected assets"
msgstr "没有选中资产" msgstr "没有选中资产"
#: ops/templates/ops/command_execution_create.html:208 #: ops/templates/ops/command_execution_create.html:212
msgid "No input command" msgid "No input command"
msgstr "没有输入命令" msgstr "没有输入命令"
#: ops/templates/ops/command_execution_create.html:212 #: ops/templates/ops/command_execution_create.html:216
msgid "No system user was selected" msgid "No system user was selected"
msgstr "没有选择系统用户" msgstr "没有选择系统用户"
#: ops/templates/ops/command_execution_create.html:257 #: ops/templates/ops/command_execution_create.html:261
msgid "Pending" msgid "Pending"
msgstr "等待" msgstr "等待"
...@@ -2683,11 +2700,23 @@ msgstr "命令执行" ...@@ -2683,11 +2700,23 @@ msgstr "命令执行"
msgid "Organization" msgid "Organization"
msgstr "组织管理" msgstr "组织管理"
#: perms/forms.py:39 perms/models.py:29 perms/models.py:85 #: perms/const.py:18 settings/forms.py:136
msgid "All"
msgstr "全部"
#: perms/const.py:20
msgid "Upload file"
msgstr "上传文件"
#: perms/const.py:21
msgid "Download file"
msgstr "下载文件"
#: perms/forms.py:39 perms/models.py:49 perms/models.py:106
#: perms/templates/perms/asset_permission_list.html:55 #: perms/templates/perms/asset_permission_list.html:55
#: perms/templates/perms/asset_permission_list.html:75 #: perms/templates/perms/asset_permission_list.html:75
#: perms/templates/perms/asset_permission_list.html:122 templates/_nav.html:14 #: perms/templates/perms/asset_permission_list.html:122 templates/_nav.html:14
#: users/forms.py:253 users/models/group.py:26 users/models/user.py:60 #: users/forms.py:253 users/models/group.py:26 users/models/user.py:67
#: users/templates/users/_select_user_modal.html:16 #: users/templates/users/_select_user_modal.html:16
#: users/templates/users/user_detail.html:213 #: users/templates/users/user_detail.html:213
#: users/templates/users/user_list.html:26 #: users/templates/users/user_list.html:26
...@@ -2695,22 +2724,28 @@ msgstr "组织管理" ...@@ -2695,22 +2724,28 @@ msgstr "组织管理"
msgid "User group" msgid "User group"
msgstr "用户组" msgstr "用户组"
#: perms/forms.py:61 #: perms/forms.py:58
msgid ""
"Tips: The RDP protocol does not support separate controls for uploading or "
"downloading files"
msgstr "提示:RDP 协议不支持单独控制上传或下载文件"
#: perms/forms.py:68
msgid "User or group at least one required" msgid "User or group at least one required"
msgstr "用户和用户组至少选一个" msgstr "用户和用户组至少选一个"
#: perms/forms.py:70 #: perms/forms.py:77
msgid "Asset or group at least one required" msgid "Asset or group at least one required"
msgstr "资产和节点至少选一个" msgstr "资产和节点至少选一个"
#: perms/models.py:35 perms/models.py:88 #: perms/models.py:56 perms/models.py:109
#: perms/templates/perms/asset_permission_detail.html:90 #: perms/templates/perms/asset_permission_detail.html:90
#: users/models/user.py:92 users/templates/users/user_detail.html:107 #: users/models/user.py:99 users/templates/users/user_detail.html:107
#: users/templates/users/user_profile.html:116 #: users/templates/users/user_profile.html:116
msgid "Date expired" msgid "Date expired"
msgstr "失效日期" msgstr "失效日期"
#: perms/models.py:44 perms/models.py:97 templates/_nav.html:34 #: perms/models.py:65 perms/models.py:118 templates/_nav.html:34
msgid "Asset permission" msgid "Asset permission"
msgstr "资产授权" msgstr "资产授权"
...@@ -2756,12 +2791,12 @@ msgstr "添加节点" ...@@ -2756,12 +2791,12 @@ msgstr "添加节点"
msgid "Join" msgid "Join"
msgstr "加入" msgstr "加入"
#: perms/templates/perms/asset_permission_create_update.html:58 #: perms/templates/perms/asset_permission_create_update.html:61
msgid "Validity period" msgid "Validity period"
msgstr "有效期" msgstr "有效期"
#: perms/templates/perms/asset_permission_detail.html:66 #: perms/templates/perms/asset_permission_detail.html:66
#: xpack/plugins/license/templates/license/license_detail.html:67 #: xpack/plugins/license/templates/license/license_detail.html:76
msgid "User count" msgid "User count"
msgstr "用户数量" msgstr "用户数量"
...@@ -2770,7 +2805,7 @@ msgid "User group count" ...@@ -2770,7 +2805,7 @@ msgid "User group count"
msgstr "用户组列表" msgstr "用户组列表"
#: perms/templates/perms/asset_permission_detail.html:74 #: perms/templates/perms/asset_permission_detail.html:74
#: xpack/plugins/license/templates/license/license_detail.html:63 #: xpack/plugins/license/templates/license/license_detail.html:72
msgid "Asset count" msgid "Asset count"
msgstr "资产数量" msgstr "资产数量"
...@@ -2814,29 +2849,29 @@ msgstr "添加用户组" ...@@ -2814,29 +2849,29 @@ msgstr "添加用户组"
msgid "Select user groups" msgid "Select user groups"
msgstr "选择用户组" msgstr "选择用户组"
#: perms/views.py:23 perms/views.py:53 perms/views.py:68 perms/views.py:83 #: perms/views.py:24 perms/views.py:56 perms/views.py:71 perms/views.py:86
#: perms/views.py:118 perms/views.py:150 templates/_nav.html:31 #: perms/views.py:121 perms/views.py:153 templates/_nav.html:31
#: xpack/plugins/orgs/templates/orgs/org_list.html:21 #: xpack/plugins/orgs/templates/orgs/org_list.html:21
msgid "Perms" msgid "Perms"
msgstr "权限管理" msgstr "权限管理"
#: perms/views.py:24 #: perms/views.py:25
msgid "Asset permission list" msgid "Asset permission list"
msgstr "资产授权列表" msgstr "资产授权列表"
#: perms/views.py:54 #: perms/views.py:57
msgid "Create asset permission" msgid "Create asset permission"
msgstr "创建权限规则" msgstr "创建权限规则"
#: perms/views.py:69 perms/views.py:84 #: perms/views.py:72 perms/views.py:87
msgid "Update asset permission" msgid "Update asset permission"
msgstr "更新资产授权" msgstr "更新资产授权"
#: perms/views.py:119 #: perms/views.py:122
msgid "Asset permission user list" msgid "Asset permission user list"
msgstr "资产授权用户列表" msgstr "资产授权用户列表"
#: perms/views.py:151 #: perms/views.py:154
msgid "Asset permission asset list" msgid "Asset permission asset list"
msgstr "资产授权资产列表" msgstr "资产授权资产列表"
...@@ -2968,10 +3003,6 @@ msgstr "" ...@@ -2968,10 +3003,6 @@ msgstr ""
msgid "Enable LDAP auth" msgid "Enable LDAP auth"
msgstr "启用LDAP认证" msgstr "启用LDAP认证"
#: settings/forms.py:136
msgid "All"
msgstr "全部"
#: settings/forms.py:137 #: settings/forms.py:137
msgid "Auto" msgid "Auto"
msgstr "自动" msgstr "自动"
...@@ -3123,7 +3154,7 @@ msgid "Please submit the LDAP configuration before import" ...@@ -3123,7 +3154,7 @@ msgid "Please submit the LDAP configuration before import"
msgstr "请先提交LDAP配置再进行导入" msgstr "请先提交LDAP配置再进行导入"
#: settings/templates/settings/_ldap_list_users_modal.html:39 #: settings/templates/settings/_ldap_list_users_modal.html:39
#: users/models/user.py:56 users/templates/users/user_detail.html:71 #: users/models/user.py:63 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 "邮件"
...@@ -3349,7 +3380,7 @@ msgstr "商业支持" ...@@ -3349,7 +3380,7 @@ msgstr "商业支持"
#: users/templates/users/user_profile.html:17 #: users/templates/users/user_profile.html:17
#: users/templates/users/user_profile_update.html:37 #: users/templates/users/user_profile_update.html:37
#: users/templates/users/user_profile_update.html:57 #: users/templates/users/user_profile_update.html:57
#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:368 #: users/templates/users/user_pubkey_update.html:37 users/views/user.py:377
msgid "Profile" msgid "Profile"
msgstr "个人信息" msgstr "个人信息"
...@@ -3431,9 +3462,9 @@ msgstr "" ...@@ -3431,9 +3462,9 @@ msgstr ""
#: templates/_nav.html:10 users/views/group.py:27 users/views/group.py:43 #: templates/_nav.html:10 users/views/group.py:27 users/views/group.py:43
#: users/views/group.py:59 users/views/group.py:75 users/views/group.py:91 #: users/views/group.py:59 users/views/group.py:75 users/views/group.py:91
#: users/views/login.py:151 users/views/user.py:68 users/views/user.py:83 #: users/views/login.py:154 users/views/user.py:68 users/views/user.py:83
#: users/views/user.py:113 users/views/user.py:194 users/views/user.py:355 #: users/views/user.py:122 users/views/user.py:203 users/views/user.py:364
#: users/views/user.py:405 users/views/user.py:445 #: users/views/user.py:414 users/views/user.py:454
msgid "Users" msgid "Users"
msgstr "用户管理" msgstr "用户管理"
...@@ -3822,11 +3853,11 @@ msgstr "地址" ...@@ -3822,11 +3853,11 @@ msgstr "地址"
msgid "Alive" msgid "Alive"
msgstr "在线" msgstr "在线"
#: terminal/templates/terminal/terminal_list.html:76 #: terminal/templates/terminal/terminal_list.html:77
msgid "Accept" msgid "Accept"
msgstr "接受" msgstr "接受"
#: terminal/templates/terminal/terminal_list.html:78 #: terminal/templates/terminal/terminal_list.html:79
msgid "Reject" msgid "Reject"
msgstr "拒绝" msgstr "拒绝"
...@@ -3867,11 +3898,15 @@ msgid "" ...@@ -3867,11 +3898,15 @@ msgid ""
"You should use your ssh client tools connect terminal: {} <br /> <br />{}" "You should use your ssh client tools connect terminal: {} <br /> <br />{}"
msgstr "你可以使用ssh客户端工具连接终端" msgstr "你可以使用ssh客户端工具连接终端"
#: users/api/user.py:146 #: users/api/user.py:69 users/api/user.py:80 users/api/user.py:106
msgid "You do not have permission."
msgstr "你没有权限"
#: users/api/user.py:210
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:64 #: users/forms.py:32 users/models/user.py:71
#: 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:25 #: users/templates/users/user_list.html:25
...@@ -3964,53 +3999,53 @@ msgstr "复制你的公钥到这里" ...@@ -3964,53 +3999,53 @@ msgstr "复制你的公钥到这里"
msgid "Select users" msgid "Select users"
msgstr "选择用户" msgstr "选择用户"
#: users/models/user.py:31 users/models/user.py:453 #: users/models/user.py:35 users/models/user.py:471
msgid "Administrator" msgid "Administrator"
msgstr "管理员" msgstr "管理员"
#: users/models/user.py:33 #: users/models/user.py:37
msgid "Application" msgid "Application"
msgstr "应用程序" msgstr "应用程序"
#: users/models/user.py:36 users/templates/users/user_profile.html:92 #: users/models/user.py:40 users/templates/users/user_profile.html:92
#: users/templates/users/user_profile.html:159 #: users/templates/users/user_profile.html:159
#: users/templates/users/user_profile.html:162 #: users/templates/users/user_profile.html:162
msgid "Disable" msgid "Disable"
msgstr "禁用" msgstr "禁用"
#: users/models/user.py:37 users/templates/users/user_profile.html:90 #: users/models/user.py:41 users/templates/users/user_profile.html:90
#: users/templates/users/user_profile.html:166 #: users/templates/users/user_profile.html:166
msgid "Enable" msgid "Enable"
msgstr "启用" msgstr "启用"
#: users/models/user.py:38 users/templates/users/user_profile.html:88 #: users/models/user.py:42 users/templates/users/user_profile.html:88
msgid "Force enable" msgid "Force enable"
msgstr "强制启用" msgstr "强制启用"
#: users/models/user.py:67 #: users/models/user.py:74
msgid "Avatar" msgid "Avatar"
msgstr "头像" msgstr "头像"
#: users/models/user.py:70 users/templates/users/user_detail.html:82 #: users/models/user.py:77 users/templates/users/user_detail.html:82
msgid "Wechat" msgid "Wechat"
msgstr "微信" msgstr "微信"
#: users/models/user.py:99 users/templates/users/user_detail.html:103 #: users/models/user.py:106 users/templates/users/user_detail.html:103
#: users/templates/users/user_list.html:27 #: users/templates/users/user_list.html:27
#: users/templates/users/user_profile.html:100 #: users/templates/users/user_profile.html:100
msgid "Source" msgid "Source"
msgstr "用户来源" msgstr "用户来源"
#: users/models/user.py:103 #: users/models/user.py:110
msgid "Date password last updated" msgid "Date password last updated"
msgstr "最后更新密码日期" msgstr "最后更新密码日期"
#: users/models/user.py:129 users/templates/users/user_update.html:22 #: users/models/user.py:136 users/templates/users/user_update.html:22
#: users/views/login.py:45 users/views/login.py:104 users/views/user.py:418 #: users/views/login.py:47 users/views/login.py:108 users/views/user.py:427
msgid "User auth from {}, go there change password" msgid "User auth from {}, go there change password"
msgstr "用户认证源来自 {}, 请去相应系统修改密码" msgstr "用户认证源来自 {}, 请去相应系统修改密码"
#: users/models/user.py:456 #: users/models/user.py:474
msgid "Administrator is the super user of system" msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员" msgstr "Administrator是初始的超级管理员"
...@@ -4201,7 +4236,7 @@ msgid "Reset link will be generated and sent to the user. " ...@@ -4201,7 +4236,7 @@ msgid "Reset link will be generated and sent to the user. "
msgstr "生成重置密码连接,通过邮件发送给用户" msgstr "生成重置密码连接,通过邮件发送给用户"
#: users/templates/users/user_detail.html:19 #: users/templates/users/user_detail.html:19
#: users/templates/users/user_granted_asset.html:18 users/views/user.py:195 #: users/templates/users/user_granted_asset.html:18 users/views/user.py:204
msgid "User detail" msgid "User detail"
msgstr "用户详情" msgstr "用户详情"
...@@ -4317,45 +4352,45 @@ msgstr "添加用户" ...@@ -4317,45 +4352,45 @@ msgstr "添加用户"
msgid "Create user group" msgid "Create user group"
msgstr "创建用户组" msgstr "创建用户组"
#: users/templates/users/user_group_list.html:83 #: users/templates/users/user_group_list.html:85
msgid "This will delete the selected groups !!!" msgid "This will delete the selected groups !!!"
msgstr "删除选择组" msgstr "删除选择组"
#: users/templates/users/user_group_list.html:92 #: users/templates/users/user_group_list.html:94
msgid "UserGroups Deleted." msgid "UserGroups Deleted."
msgstr "用户组删除" msgstr "用户组删除"
#: users/templates/users/user_group_list.html:93 #: users/templates/users/user_group_list.html:95
#: users/templates/users/user_group_list.html:98 #: users/templates/users/user_group_list.html:100
msgid "UserGroups Delete" msgid "UserGroups Delete"
msgstr "用户组删除" msgstr "用户组删除"
#: users/templates/users/user_group_list.html:97 #: users/templates/users/user_group_list.html:99
msgid "UserGroup Deleting failed." msgid "UserGroup Deleting failed."
msgstr "用户组删除失败" msgstr "用户组删除失败"
#: users/templates/users/user_list.html:203 #: users/templates/users/user_list.html:210
msgid "This will delete the selected users !!!" msgid "This will delete the selected users !!!"
msgstr "删除选中用户 !!!" msgstr "删除选中用户 !!!"
#: users/templates/users/user_list.html:212 #: users/templates/users/user_list.html:219
msgid "User Deleted." msgid "User Deleted."
msgstr "已被删除" msgstr "已被删除"
#: users/templates/users/user_list.html:213 #: users/templates/users/user_list.html:220
#: users/templates/users/user_list.html:218 #: users/templates/users/user_list.html:225
msgid "User Delete" msgid "User Delete"
msgstr "删除" msgstr "删除"
#: users/templates/users/user_list.html:217 #: users/templates/users/user_list.html:224
msgid "User Deleting failed." msgid "User Deleting failed."
msgstr "用户删除失败" msgstr "用户删除失败"
#: users/templates/users/user_list.html:253 #: users/templates/users/user_list.html:260
msgid "User is expired" msgid "User is expired"
msgstr "用户已失效" msgstr "用户已失效"
#: users/templates/users/user_list.html:256 #: users/templates/users/user_list.html:263
msgid "User is inactive" msgid "User is inactive"
msgstr "用户已禁用" msgstr "用户已禁用"
...@@ -4404,8 +4439,8 @@ msgstr "安装完成后点击下一步进入绑定页面(如已安装,直接 ...@@ -4404,8 +4439,8 @@ msgstr "安装完成后点击下一步进入绑定页面(如已安装,直接
msgid "Administrator Settings force MFA login" msgid "Administrator Settings force MFA login"
msgstr "管理员设置强制使用MFA登录" msgstr "管理员设置强制使用MFA登录"
#: users/templates/users/user_profile.html:120 users/views/user.py:231 #: users/templates/users/user_profile.html:120 users/views/user.py:240
#: users/views/user.py:285 #: users/views/user.py:294
msgid "User groups" msgid "User groups"
msgstr "用户组" msgstr "用户组"
...@@ -4455,7 +4490,7 @@ msgid "" ...@@ -4455,7 +4490,7 @@ msgid ""
"corresponding private key." "corresponding private key."
msgstr "新的公钥已设置成功,请下载对应的私钥" msgstr "新的公钥已设置成功,请下载对应的私钥"
#: users/templates/users/user_update.html:4 users/views/user.py:114 #: users/templates/users/user_update.html:4 users/views/user.py:123
msgid "Update user" msgid "Update user"
msgstr "更新用户" msgstr "更新用户"
...@@ -4658,88 +4693,88 @@ msgstr "更新用户组" ...@@ -4658,88 +4693,88 @@ msgstr "更新用户组"
msgid "User group granted asset" msgid "User group granted asset"
msgstr "用户组授权资产" msgstr "用户组授权资产"
#: users/views/login.py:42 #: users/views/login.py:44
msgid "Email address invalid, please input again" msgid "Email address invalid, please input again"
msgstr "邮箱地址错误,重新输入" msgstr "邮箱地址错误,重新输入"
#: users/views/login.py:58 #: users/views/login.py:60
msgid "Send reset password message" msgid "Send reset password message"
msgstr "发送重置密码邮件" msgstr "发送重置密码邮件"
#: users/views/login.py:59 #: users/views/login.py:61
msgid "Send reset password mail success, login your mail box and follow it " msgid "Send reset password mail success, login your mail box and follow it "
msgstr "" msgstr ""
"发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)" "发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)"
#: users/views/login.py:72 #: users/views/login.py:74
msgid "Reset password success" msgid "Reset password success"
msgstr "重置密码成功" msgstr "重置密码成功"
#: users/views/login.py:73 #: users/views/login.py:75
msgid "Reset password success, return to login page" msgid "Reset password success, return to login page"
msgstr "重置密码成功,返回到登录页面" msgstr "重置密码成功,返回到登录页面"
#: users/views/login.py:88 users/views/login.py:107 #: users/views/login.py:90 users/views/login.py:106
msgid "Token invalid or expired" msgid "Token invalid or expired"
msgstr "Token错误或失效" msgstr "Token错误或失效"
#: users/views/login.py:100 #: users/views/login.py:102
msgid "Password not same" msgid "Password not same"
msgstr "密码不一致" msgstr "密码不一致"
#: users/views/login.py:113 users/views/user.py:128 users/views/user.py:428 #: users/views/login.py:115 users/views/user.py:137 users/views/user.py:437
msgid "* Your password does not meet the requirements" msgid "* Your password does not meet the requirements"
msgstr "* 您的密码不符合要求" msgstr "* 您的密码不符合要求"
#: users/views/login.py:151 #: users/views/login.py:154
msgid "First login" msgid "First login"
msgstr "首次登录" msgstr "首次登录"
#: users/views/user.py:145 #: users/views/user.py:154
msgid "Bulk update user success" msgid "Bulk update user success"
msgstr "批量更新用户成功" msgstr "批量更新用户成功"
#: users/views/user.py:175 #: users/views/user.py:184
msgid "Bulk update user" msgid "Bulk update user"
msgstr "批量更新用户" msgstr "批量更新用户"
#: users/views/user.py:260 #: users/views/user.py:269
msgid "Invalid file." msgid "Invalid file."
msgstr "文件不合法" msgstr "文件不合法"
#: users/views/user.py:356 #: users/views/user.py:365
msgid "User granted assets" msgid "User granted assets"
msgstr "用户授权资产" msgstr "用户授权资产"
#: users/views/user.py:387 #: users/views/user.py:396
msgid "Profile setting" msgid "Profile setting"
msgstr "个人信息设置" msgstr "个人信息设置"
#: users/views/user.py:406 #: users/views/user.py:415
msgid "Password update" msgid "Password update"
msgstr "密码更新" msgstr "密码更新"
#: users/views/user.py:446 #: users/views/user.py:455
msgid "Public key update" msgid "Public key update"
msgstr "密钥更新" msgstr "密钥更新"
#: users/views/user.py:487 #: users/views/user.py:496
msgid "Password invalid" msgid "Password invalid"
msgstr "用户名或密码无效" msgstr "用户名或密码无效"
#: users/views/user.py:587 #: users/views/user.py:596
msgid "MFA enable success" msgid "MFA enable success"
msgstr "MFA 绑定成功" msgstr "MFA 绑定成功"
#: users/views/user.py:588 #: users/views/user.py:597
msgid "MFA enable success, return login page" msgid "MFA enable success, return login page"
msgstr "MFA 绑定成功,返回到登录页面" msgstr "MFA 绑定成功,返回到登录页面"
#: users/views/user.py:590 #: users/views/user.py:599
msgid "MFA disable success" msgid "MFA disable success"
msgstr "MFA 解绑成功" msgstr "MFA 解绑成功"
#: users/views/user.py:591 #: users/views/user.py:600
msgid "MFA disable success, return login page" msgid "MFA disable success, return login page"
msgstr "MFA 解绑成功,返回登录页面" msgstr "MFA 解绑成功,返回登录页面"
...@@ -4796,8 +4831,8 @@ msgstr "" ...@@ -4796,8 +4831,8 @@ msgstr ""
"具</a>) <br>注意: 如果同时设置了定期执行和周期执行,优先使用定期执行" "具</a>) <br>注意: 如果同时设置了定期执行和周期执行,优先使用定期执行"
#: xpack/plugins/change_auth_plan/meta.py:9 #: xpack/plugins/change_auth_plan/meta.py:9
#: xpack/plugins/change_auth_plan/models.py:110 #: xpack/plugins/change_auth_plan/models.py:111
#: xpack/plugins/change_auth_plan/models.py:252 #: xpack/plugins/change_auth_plan/models.py:253
#: xpack/plugins/change_auth_plan/views.py:31 #: xpack/plugins/change_auth_plan/views.py:31
#: xpack/plugins/change_auth_plan/views.py:47 #: xpack/plugins/change_auth_plan/views.py:47
#: xpack/plugins/change_auth_plan/views.py:68 #: xpack/plugins/change_auth_plan/views.py:68
...@@ -4821,13 +4856,13 @@ msgid "All assets use different random password" ...@@ -4821,13 +4856,13 @@ msgid "All assets use different random password"
msgstr "所有资产使用不同的随机密码" msgstr "所有资产使用不同的随机密码"
#: xpack/plugins/change_auth_plan/models.py:73 #: xpack/plugins/change_auth_plan/models.py:73
#: xpack/plugins/change_auth_plan/models.py:141 #: xpack/plugins/change_auth_plan/models.py:142
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:100 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:100
msgid "Cycle perform" msgid "Cycle perform"
msgstr "周期执行" msgstr "周期执行"
#: xpack/plugins/change_auth_plan/models.py:78 #: xpack/plugins/change_auth_plan/models.py:78
#: xpack/plugins/change_auth_plan/models.py:139 #: xpack/plugins/change_auth_plan/models.py:140
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:92 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:92
msgid "Regularly perform" msgid "Regularly perform"
msgstr "定期执行" msgstr "定期执行"
...@@ -4845,32 +4880,32 @@ msgstr "密码策略" ...@@ -4845,32 +4880,32 @@ msgstr "密码策略"
msgid "Password rules" msgid "Password rules"
msgstr "密码规则" msgstr "密码规则"
#: xpack/plugins/change_auth_plan/models.py:209 #: xpack/plugins/change_auth_plan/models.py:210
msgid "For security, do not change root user's password" msgid "For security, do not change root user's password"
msgstr "为了安全,禁止更改root用户的密码" msgstr "为了安全,禁止更改root用户的密码"
#: xpack/plugins/change_auth_plan/models.py:212 #: xpack/plugins/change_auth_plan/models.py:213
msgid "Assets is empty, please add the asset" msgid "Assets is empty, please add the asset"
msgstr "资产为空,请添加资产" msgstr "资产为空,请添加资产"
#: xpack/plugins/change_auth_plan/models.py:256 #: xpack/plugins/change_auth_plan/models.py:257
msgid "Change auth plan snapshot" msgid "Change auth plan snapshot"
msgstr "改密计划快照" msgstr "改密计划快照"
#: xpack/plugins/change_auth_plan/models.py:271 #: xpack/plugins/change_auth_plan/models.py:272
#: xpack/plugins/change_auth_plan/models.py:422 #: xpack/plugins/change_auth_plan/models.py:423
msgid "Change auth plan execution" msgid "Change auth plan execution"
msgstr "改密计划执行" msgstr "改密计划执行"
#: xpack/plugins/change_auth_plan/models.py:431 #: xpack/plugins/change_auth_plan/models.py:432
msgid "Change auth plan execution subtask" msgid "Change auth plan execution subtask"
msgstr "改密计划执行子任务" msgstr "改密计划执行子任务"
#: xpack/plugins/change_auth_plan/models.py:449 #: xpack/plugins/change_auth_plan/models.py:450
msgid "Authentication failed" msgid "Authentication failed"
msgstr "认证失败" msgstr "认证失败"
#: xpack/plugins/change_auth_plan/models.py:451 #: xpack/plugins/change_auth_plan/models.py:452
msgid "Connection timeout" msgid "Connection timeout"
msgstr "连接超时" msgstr "连接超时"
...@@ -5217,30 +5252,57 @@ msgid "Interface settings" ...@@ -5217,30 +5252,57 @@ msgid "Interface settings"
msgstr "界面设置" msgstr "界面设置"
#: xpack/plugins/interface/templates/interface/interface.html:15 #: xpack/plugins/interface/templates/interface/interface.html:15
#: xpack/plugins/interface/views.py:21 #: xpack/plugins/interface/views.py:24
msgid "Interface setting" msgid "Interface setting"
msgstr "界面设置" msgstr "界面设置"
#: xpack/plugins/interface/views.py:20 #: xpack/plugins/interface/templates/interface/interface.html:73
#: xpack/plugins/interface/templates/interface/interface.html:108
#: xpack/plugins/interface/templates/interface/interface.html:115
msgid "Restore Default"
msgstr "恢复默认"
#: xpack/plugins/interface/templates/interface/interface.html:98
msgid "This will restore default Settings of the interface !!!"
msgstr "您确定要恢复默认初始化吗?"
#: xpack/plugins/interface/templates/interface/interface.html:107
msgid "Restore default successfully."
msgstr "恢复默认成功!"
#: xpack/plugins/interface/templates/interface/interface.html:114
msgid "Restore default failed."
msgstr "恢复默认失败!"
#: xpack/plugins/interface/views.py:23
msgid "Interface" msgid "Interface"
msgstr "界面" msgstr "界面"
#: xpack/plugins/interface/views.py:49
msgid "It is already in the default setting state!"
msgstr "当前已经是初始化状态!"
#: xpack/plugins/interface/views.py:53
msgid "Restore default successfully!"
msgstr "恢复默认成功!"
#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:94 #: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:94
#: xpack/plugins/license/templates/license/license_detail.html:50 #: xpack/plugins/license/templates/license/license_detail.html:50
#: xpack/plugins/license/templates/license/license_detail.html:55
#: xpack/plugins/license/views.py:31 #: xpack/plugins/license/views.py:31
msgid "License" msgid "License"
msgstr "许可证" msgstr "许可证"
#: xpack/plugins/license/models.py:74 #: xpack/plugins/license/models.py:74
msgid "Standard edition" msgid "Standard edition"
msgstr "" msgstr "标准版"
#: xpack/plugins/license/models.py:76 #: xpack/plugins/license/models.py:76
msgid "Enterprise edition" msgid "Enterprise edition"
msgstr "企业版" msgstr "企业版"
#: xpack/plugins/license/templates/license/_license_import_modal.html:4 #: xpack/plugins/license/templates/license/_license_import_modal.html:4
#: xpack/plugins/license/templates/license/license_detail.html:99 #: xpack/plugins/license/templates/license/license_detail.html:108
msgid "Import license" msgid "Import license"
msgstr "导入许可证" msgstr "导入许可证"
...@@ -5253,6 +5315,7 @@ msgid "Please Import License" ...@@ -5253,6 +5315,7 @@ msgid "Please Import License"
msgstr "请导入许可证" msgstr "请导入许可证"
#: xpack/plugins/license/templates/license/license_detail.html:17 #: xpack/plugins/license/templates/license/license_detail.html:17
#: xpack/plugins/license/templates/license/license_detail.html:56
msgid "License has expired" msgid "License has expired"
msgstr "许可证已经过期" msgstr "许可证已经过期"
...@@ -5273,34 +5336,38 @@ msgstr "许可证详情" ...@@ -5273,34 +5336,38 @@ msgstr "许可证详情"
msgid "No license" msgid "No license"
msgstr "暂无许可证" msgstr "暂无许可证"
#: xpack/plugins/license/templates/license/license_detail.html:55 #: xpack/plugins/license/templates/license/license_detail.html:60
msgid "Subscription ID"
msgstr "订阅授权ID"
#: xpack/plugins/license/templates/license/license_detail.html:64
msgid "Corporation" msgid "Corporation"
msgstr "公司" msgstr "公司"
#: xpack/plugins/license/templates/license/license_detail.html:59 #: xpack/plugins/license/templates/license/license_detail.html:68
msgid "Expired" msgid "Expired"
msgstr "过期时间" msgstr "过期时间"
#: xpack/plugins/license/templates/license/license_detail.html:64 #: xpack/plugins/license/templates/license/license_detail.html:73
#: xpack/plugins/license/templates/license/license_detail.html:68 #: xpack/plugins/license/templates/license/license_detail.html:77
#: xpack/plugins/license/templates/license/license_detail.html:72 #: xpack/plugins/license/templates/license/license_detail.html:81
#: xpack/plugins/license/templates/license/license_detail.html:76 #: xpack/plugins/license/templates/license/license_detail.html:85
msgid "Unlimited" msgid "Unlimited"
msgstr "无限制" msgstr "无限制"
#: xpack/plugins/license/templates/license/license_detail.html:75 #: xpack/plugins/license/templates/license/license_detail.html:84
msgid "Concurrent connections" msgid "Concurrent connections"
msgstr "并发连接" msgstr "并发连接"
#: xpack/plugins/license/templates/license/license_detail.html:80 #: xpack/plugins/license/templates/license/license_detail.html:89
msgid "Edition" msgid "Edition"
msgstr "版本" msgstr "版本"
#: xpack/plugins/license/templates/license/license_detail.html:106 #: xpack/plugins/license/templates/license/license_detail.html:115
msgid "Technology consulting" msgid "Technology consulting"
msgstr "技术咨询" msgstr "技术咨询"
#: xpack/plugins/license/templates/license/license_detail.html:109 #: xpack/plugins/license/templates/license/license_detail.html:118
msgid "Consult" msgid "Consult"
msgstr "咨询" msgstr "咨询"
...@@ -5356,6 +5423,9 @@ msgstr "创建组织" ...@@ -5356,6 +5423,9 @@ msgstr "创建组织"
msgid "Update org" msgid "Update org"
msgstr "更新组织" msgstr "更新组织"
#~ msgid "Beijing Duizhan Tech, Inc."
#~ msgstr "北京堆栈科技有限公司"
#~ msgid "Sync User" #~ msgid "Sync User"
#~ msgstr "同步用户" #~ msgstr "同步用户"
......
...@@ -82,6 +82,7 @@ ...@@ -82,6 +82,7 @@
<script> <script>
var zTree, show = 0; var zTree, show = 0;
var systemUserId = null; var systemUserId = null;
var url = null;
var treeUrl = "{% url 'api-perms:my-nodes-assets-as-tree' %}?cache_policy=1"; var treeUrl = "{% url 'api-perms:my-nodes-assets-as-tree' %}?cache_policy=1";
function initTree() { function initTree() {
...@@ -114,6 +115,9 @@ function initTree() { ...@@ -114,6 +115,9 @@ function initTree() {
if (systemUserId) { if (systemUserId) {
url = treeUrl + '&system_user=' + systemUserId url = treeUrl + '&system_user=' + systemUserId
} }
else{
url = treeUrl
}
$.get(url, function(data, status){ $.get(url, function(data, status){
$.fn.zTree.init($("#assetTree"), setting, data); $.fn.zTree.init($("#assetTree"), setting, data);
......
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from rest_framework import serializers from rest_framework import serializers
from rest_framework_bulk import BulkListSerializer
from users.models import User, UserGroup from users.models import User, UserGroup
from assets.models import Asset, Domain, AdminUser, SystemUser, Label from assets.models import Asset, Domain, AdminUser, SystemUser, Label
from perms.models import AssetPermission from perms.models import AssetPermission
from common.serializers import AdaptedBulkListSerializer
from .utils import set_current_org, get_current_org from .utils import set_current_org, get_current_org
from .models import Organization from .models import Organization
from .mixins import OrgMembershipSerializerMixin from .mixins import OrgMembershipSerializerMixin
...@@ -14,7 +14,7 @@ from .mixins import OrgMembershipSerializerMixin ...@@ -14,7 +14,7 @@ from .mixins import OrgMembershipSerializerMixin
class OrgSerializer(ModelSerializer): class OrgSerializer(ModelSerializer):
class Meta: class Meta:
model = Organization model = Organization
list_serializer_class = BulkListSerializer list_serializer_class = AdaptedBulkListSerializer
fields = '__all__' fields = '__all__'
read_only_fields = ['created_by', 'date_created'] read_only_fields = ['created_by', 'date_created']
...@@ -70,12 +70,12 @@ class OrgReadSerializer(ModelSerializer): ...@@ -70,12 +70,12 @@ class OrgReadSerializer(ModelSerializer):
class OrgMembershipAdminSerializer(OrgMembershipSerializerMixin, ModelSerializer): class OrgMembershipAdminSerializer(OrgMembershipSerializerMixin, ModelSerializer):
class Meta: class Meta:
model = Organization.admins.through model = Organization.admins.through
list_serializer_class = BulkListSerializer list_serializer_class = AdaptedBulkListSerializer
fields = '__all__' fields = '__all__'
class OrgMembershipUserSerializer(OrgMembershipSerializerMixin, ModelSerializer): class OrgMembershipUserSerializer(OrgMembershipSerializerMixin, ModelSerializer):
class Meta: class Meta:
model = Organization.users.through model = Organization.users.through
list_serializer_class = BulkListSerializer list_serializer_class = AdaptedBulkListSerializer
fields = '__all__' fields = '__all__'
...@@ -10,7 +10,7 @@ from rest_framework.pagination import LimitOffsetPagination ...@@ -10,7 +10,7 @@ from rest_framework.pagination import LimitOffsetPagination
from common.permissions import IsOrgAdmin from common.permissions import IsOrgAdmin
from common.utils import get_object_or_none from common.utils import get_object_or_none
from ..models import AssetPermission from ..models import AssetPermission, Action
from ..hands import ( from ..hands import (
User, UserGroup, Asset, Node, SystemUser, User, UserGroup, Asset, Node, SystemUser,
) )
...@@ -20,10 +20,16 @@ from .. import serializers ...@@ -20,10 +20,16 @@ from .. import serializers
__all__ = [ __all__ = [
'AssetPermissionViewSet', 'AssetPermissionRemoveUserApi', 'AssetPermissionViewSet', 'AssetPermissionRemoveUserApi',
'AssetPermissionAddUserApi', 'AssetPermissionRemoveAssetApi', 'AssetPermissionAddUserApi', 'AssetPermissionRemoveAssetApi',
'AssetPermissionAddAssetApi', 'AssetPermissionAddAssetApi', 'ActionViewSet',
] ]
class ActionViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Action.objects.all()
serializer_class = serializers.ActionSerializer
permission_classes = (IsOrgAdmin,)
class AssetPermissionViewSet(viewsets.ModelViewSet): class AssetPermissionViewSet(viewsets.ModelViewSet):
""" """
资产授权列表的增删改查api 资产授权列表的增删改查api
......
...@@ -16,7 +16,8 @@ from common.tree import TreeNodeSerializer ...@@ -16,7 +16,8 @@ from common.tree import TreeNodeSerializer
from common.utils import get_logger from common.utils import get_logger
from orgs.utils import set_to_root_org from orgs.utils import set_to_root_org
from ..utils import ( from ..utils import (
AssetPermissionUtil, parse_asset_to_tree_node, parse_node_to_tree_node AssetPermissionUtil, parse_asset_to_tree_node, parse_node_to_tree_node,
check_system_user_action
) )
from ..hands import ( from ..hands import (
AssetGrantedSerializer, User, Asset, Node, AssetGrantedSerializer, User, Asset, Node,
...@@ -24,6 +25,7 @@ from ..hands import ( ...@@ -24,6 +25,7 @@ from ..hands import (
) )
from .. import serializers from .. import serializers
from ..mixins import AssetsFilterMixin from ..mixins import AssetsFilterMixin
from ..models import Action
logger = get_logger(__name__) logger = get_logger(__name__)
...@@ -31,7 +33,7 @@ __all__ = [ ...@@ -31,7 +33,7 @@ __all__ = [
'UserGrantedAssetsApi', 'UserGrantedNodesApi', 'UserGrantedAssetsApi', 'UserGrantedNodesApi',
'UserGrantedNodesWithAssetsApi', 'UserGrantedNodeAssetsApi', 'UserGrantedNodesWithAssetsApi', 'UserGrantedNodeAssetsApi',
'ValidateUserAssetPermissionApi', 'UserGrantedNodeChildrenApi', 'ValidateUserAssetPermissionApi', 'UserGrantedNodeChildrenApi',
'UserGrantedNodesWithAssetsAsTreeApi', 'UserGrantedNodesWithAssetsAsTreeApi', 'GetUserAssetPermissionActionsApi',
] ]
...@@ -403,16 +405,45 @@ class ValidateUserAssetPermissionApi(UserPermissionCacheMixin, APIView): ...@@ -403,16 +405,45 @@ class ValidateUserAssetPermissionApi(UserPermissionCacheMixin, APIView):
user_id = request.query_params.get('user_id', '') user_id = request.query_params.get('user_id', '')
asset_id = request.query_params.get('asset_id', '') asset_id = request.query_params.get('asset_id', '')
system_id = request.query_params.get('system_user_id', '') system_id = request.query_params.get('system_user_id', '')
action_name = request.query_params.get('action_name', '')
user = get_object_or_404(User, id=user_id) user = get_object_or_404(User, id=user_id)
asset = get_object_or_404(Asset, id=asset_id) asset = get_object_or_404(Asset, id=asset_id)
system_user = get_object_or_404(SystemUser, id=system_id) su = get_object_or_404(SystemUser, id=system_id)
action = get_object_or_404(Action, name=action_name)
util = AssetPermissionUtil(user, cache_policy=self.cache_policy) util = AssetPermissionUtil(user, cache_policy=self.cache_policy)
assets_granted = util.get_assets() granted_assets = util.get_assets()
if system_user in assets_granted.get(asset, []): granted_system_users = granted_assets.get(asset, [])
return Response({'msg': True}, status=200)
else: if su not in granted_system_users:
return Response({'msg': False}, status=403)
_su = next((s for s in granted_system_users if s.id == su.id), None)
if not check_system_user_action(_su, action):
return Response({'msg': False}, status=403) return Response({'msg': False}, status=403)
return Response({'msg': True}, status=200)
class GetUserAssetPermissionActionsApi(UserPermissionCacheMixin, APIView):
permission_classes = (IsOrgAdminOrAppUser,)
def get(self, request, *args, **kwargs):
user_id = request.query_params.get('user_id', '')
asset_id = request.query_params.get('asset_id', '')
system_id = request.query_params.get('system_user_id', '')
user = get_object_or_404(User, id=user_id)
asset = get_object_or_404(Asset, id=asset_id)
su = get_object_or_404(SystemUser, id=system_id)
util = AssetPermissionUtil(user, cache_policy=self.cache_policy)
granted_assets = util.get_assets()
granted_system_users = granted_assets.get(asset, [])
_su = next((s for s in granted_system_users if s.id == su.id), None)
if not _su:
return Response({'actions': []}, status=403)
actions = [action.name for action in getattr(_su, 'actions', [])]
return Response({'actions': actions}, status=200)
# -*- coding: utf-8 -*-
#
from django.utils.translation import ugettext_lazy as _
__all__ = [
'PERMS_ACTION_NAME_ALL', 'PERMS_ACTION_NAME_CONNECT',
'PERMS_ACTION_NAME_DOWNLOAD_FILE', 'PERMS_ACTION_NAME_UPLOAD_FILE',
'PERMS_ACTION_NAME_CHOICES'
]
PERMS_ACTION_NAME_ALL = 'all'
PERMS_ACTION_NAME_CONNECT = 'connect'
PERMS_ACTION_NAME_UPLOAD_FILE = 'upload_file'
PERMS_ACTION_NAME_DOWNLOAD_FILE = 'download_file'
PERMS_ACTION_NAME_CHOICES = (
(PERMS_ACTION_NAME_ALL, _('All')),
(PERMS_ACTION_NAME_CONNECT, _('Connect')),
(PERMS_ACTION_NAME_UPLOAD_FILE, _('Upload file')),
(PERMS_ACTION_NAME_DOWNLOAD_FILE, _('Download file')),
)
...@@ -47,10 +47,17 @@ class AssetPermissionForm(OrgModelForm): ...@@ -47,10 +47,17 @@ class AssetPermissionForm(OrgModelForm):
'system_users': forms.SelectMultiple( 'system_users': forms.SelectMultiple(
attrs={'class': 'select2', 'data-placeholder': _('System user')} attrs={'class': 'select2', 'data-placeholder': _('System user')}
), ),
'actions': forms.SelectMultiple(
attrs={'class': 'select2', 'data-placeholder': _('Action')}
)
} }
labels = { labels = {
'nodes': _("Node"), 'nodes': _("Node"),
} }
help_texts = {
'actions': _('Tips: The RDP protocol does not support separate '
'controls for uploading or downloading files')
}
def clean_user_groups(self): def clean_user_groups(self):
users = self.cleaned_data.get('users') users = self.cleaned_data.get('users')
......
# Generated by Django 2.1.7 on 2019-04-12 07:00
from django.db import migrations, models
import uuid
def add_default_actions(apps, schema_editor):
from ..const import PERMS_ACTION_NAME_CHOICES
action_model = apps.get_model('perms', 'Action')
db_alias = schema_editor.connection.alias
for action, _ in PERMS_ACTION_NAME_CHOICES:
action_model.objects.using(db_alias).update_or_create(name=action)
class Migration(migrations.Migration):
dependencies = [
('perms', '0002_auto_20171228_0025_squashed_0009_auto_20180903_1132'),
]
operations = [
migrations.CreateModel(
name='Action',
fields=[
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(choices=[('all', 'All'), ('connect', 'Connect'), ('upload_file', 'Upload file'), ('download_file', 'Download file')], max_length=128, unique=True, verbose_name='Name')),
],
options={
'verbose_name': 'Action',
},
),
migrations.RunPython(add_default_actions)
]
# Generated by Django 2.1.7 on 2019-04-12 09:17
from django.db import migrations, models
def set_default_action_to_existing_perms(apps, schema_editor):
from orgs.utils import set_to_root_org
from ..models import Action
set_to_root_org()
perm_model = apps.get_model('perms', 'AssetPermission')
db_alias = schema_editor.connection.alias
perms = perm_model.objects.using(db_alias).all()
default_action = Action.get_action_all()
for perm in perms:
perm.actions.add(default_action.id)
class Migration(migrations.Migration):
dependencies = [
('perms', '0003_action'),
]
operations = [
migrations.AddField(
model_name='assetpermission',
name='actions',
field=models.ManyToManyField(blank=True, related_name='permissions', to='perms.Action', verbose_name='Action'),
),
migrations.RunPython(set_default_action_to_existing_perms)
]
...@@ -7,6 +7,26 @@ from django.utils import timezone ...@@ -7,6 +7,26 @@ from django.utils import timezone
from common.utils import date_expired_default, set_or_append_attr_bulk from common.utils import date_expired_default, set_or_append_attr_bulk
from orgs.mixins import OrgModelMixin, OrgManager from orgs.mixins import OrgModelMixin, OrgManager
from .const import PERMS_ACTION_NAME_CHOICES, PERMS_ACTION_NAME_ALL
class Action(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(
max_length=128, unique=True, choices=PERMS_ACTION_NAME_CHOICES,
verbose_name=_('Name')
)
class Meta:
verbose_name = _('Action')
def __str__(self):
return self.get_name_display()
@classmethod
def get_action_all(cls):
return cls.objects.get(name=PERMS_ACTION_NAME_ALL)
class AssetPermissionQuerySet(models.QuerySet): class AssetPermissionQuerySet(models.QuerySet):
def active(self): def active(self):
...@@ -30,6 +50,7 @@ class AssetPermission(OrgModelMixin): ...@@ -30,6 +50,7 @@ class AssetPermission(OrgModelMixin):
assets = models.ManyToManyField('assets.Asset', related_name='granted_by_permissions', blank=True, verbose_name=_("Asset")) assets = models.ManyToManyField('assets.Asset', related_name='granted_by_permissions', blank=True, verbose_name=_("Asset"))
nodes = models.ManyToManyField('assets.Node', related_name='granted_by_permissions', blank=True, verbose_name=_("Nodes")) nodes = models.ManyToManyField('assets.Node', related_name='granted_by_permissions', blank=True, verbose_name=_("Nodes"))
system_users = models.ManyToManyField('assets.SystemUser', related_name='granted_by_permissions', verbose_name=_("System user")) system_users = models.ManyToManyField('assets.SystemUser', related_name='granted_by_permissions', verbose_name=_("System user"))
actions = models.ManyToManyField('Action', related_name='permissions', blank=True, verbose_name=_('Action'))
is_active = models.BooleanField(default=True, verbose_name=_('Active')) is_active = models.BooleanField(default=True, verbose_name=_('Active'))
date_start = models.DateTimeField(default=timezone.now, db_index=True, verbose_name=_("Date start")) date_start = models.DateTimeField(default=timezone.now, db_index=True, verbose_name=_("Date start"))
date_expired = models.DateTimeField(default=date_expired_default, db_index=True, verbose_name=_('Date expired')) date_expired = models.DateTimeField(default=date_expired_default, db_index=True, verbose_name=_('Date expired'))
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
from rest_framework import serializers from rest_framework import serializers
from common.fields import StringManyToManyField from common.fields import StringManyToManyField
from .models import AssetPermission from .models import AssetPermission, Action
from assets.models import Node, Asset, SystemUser from assets.models import Node, Asset, SystemUser
from assets.serializers import AssetGrantedSerializer from assets.serializers import AssetGrantedSerializer
...@@ -13,9 +13,16 @@ __all__ = [ ...@@ -13,9 +13,16 @@ __all__ = [
'AssetPermissionUpdateUserSerializer', 'AssetPermissionUpdateAssetSerializer', 'AssetPermissionUpdateUserSerializer', 'AssetPermissionUpdateAssetSerializer',
'AssetPermissionNodeSerializer', 'GrantedNodeSerializer', 'AssetPermissionNodeSerializer', 'GrantedNodeSerializer',
'GrantedAssetSerializer', 'GrantedSystemUserSerializer', 'GrantedAssetSerializer', 'GrantedSystemUserSerializer',
'ActionSerializer',
] ]
class ActionSerializer(serializers.ModelSerializer):
class Meta:
model = Action
fields = '__all__'
class AssetPermissionCreateUpdateSerializer(serializers.ModelSerializer): class AssetPermissionCreateUpdateSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = AssetPermission model = AssetPermission
...@@ -28,6 +35,7 @@ class AssetPermissionListSerializer(serializers.ModelSerializer): ...@@ -28,6 +35,7 @@ class AssetPermissionListSerializer(serializers.ModelSerializer):
assets = StringManyToManyField(many=True, read_only=True) assets = StringManyToManyField(many=True, read_only=True)
nodes = StringManyToManyField(many=True, read_only=True) nodes = StringManyToManyField(many=True, read_only=True)
system_users = StringManyToManyField(many=True, read_only=True) system_users = StringManyToManyField(many=True, read_only=True)
actions = StringManyToManyField(many=True, read_only=True)
is_valid = serializers.BooleanField() is_valid = serializers.BooleanField()
is_expired = serializers.BooleanField() is_expired = serializers.BooleanField()
......
...@@ -2,15 +2,37 @@ ...@@ -2,15 +2,37 @@
# #
from django.db.models.signals import m2m_changed, post_save, post_delete from django.db.models.signals import m2m_changed, post_save, post_delete
from django.dispatch import receiver from django.dispatch import receiver
from django.db import transaction
from common.utils import get_logger from common.utils import get_logger
from .utils import AssetPermissionUtil from .utils import AssetPermissionUtil
from .models import AssetPermission from .models import AssetPermission, Action
logger = get_logger(__file__) logger = get_logger(__file__)
def on_transaction_commit(func):
"""
如果不调用on_commit, 对象创建时添加多对多字段值失败
"""
def inner(*args, **kwargs):
transaction.on_commit(lambda: func(*args, **kwargs))
return inner
@receiver(post_save, sender=AssetPermission, dispatch_uid="my_unique_identifier")
@on_transaction_commit
def on_permission_created(sender, instance=None, created=False, **kwargs):
actions = instance.actions.all()
if created and not actions:
default_action = Action.get_action_all()
instance.actions.add(default_action)
logger.debug(
"Set default action to perms: {}".format(default_action, instance)
)
@receiver(post_save, sender=AssetPermission) @receiver(post_save, sender=AssetPermission)
def on_permission_update(sender, **kwargs): def on_permission_update(sender, **kwargs):
AssetPermissionUtil.expire_all_cache() AssetPermissionUtil.expire_all_cache()
......
...@@ -47,6 +47,9 @@ ...@@ -47,6 +47,9 @@
{% bootstrap_field form.nodes layout="horizontal" %} {% bootstrap_field form.nodes layout="horizontal" %}
{% bootstrap_field form.system_users layout="horizontal" %} {% bootstrap_field form.system_users layout="horizontal" %}
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<h3>{% trans 'Action' %}</h3>
{% bootstrap_field form.actions layout="horizontal" %}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Other' %}</h3> <h3>{% trans 'Other' %}</h3>
<div class="form-group"> <div class="form-group">
<label for="{{ form.is_active.id_for_label }}" class="col-sm-2 control-label">{% trans 'Active' %}</label> <label for="{{ form.is_active.id_for_label }}" class="col-sm-2 control-label">{% trans 'Active' %}</label>
......
...@@ -130,6 +130,9 @@ function format(d) { ...@@ -130,6 +130,9 @@ function format(d) {
if (d.system_users.length > 0) { if (d.system_users.length > 0) {
data += makeLabel(["{% trans 'System user' %}", d.system_users.join(", ")]) data += makeLabel(["{% trans 'System user' %}", d.system_users.join(", ")])
} }
if (d.actions.length > 0) {
data += makeLabel(["{% trans 'Action' %}", d.actions.join(", ")])
}
return data return data
} }
...@@ -143,6 +146,7 @@ function initTable() { ...@@ -143,6 +146,7 @@ function initTable() {
$(td).html("<i class='fa fa-angle-right'></i>"); $(td).html("<i class='fa fa-angle-right'></i>");
}}, }},
{targets: 1, createdCell: function (td, cellData, rowData) { {targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
var detail_btn = '<a href="{% url "perms:asset-permission-detail" pk=DEFAULT_PK %}">' + cellData + '</a>'; var detail_btn = '<a href="{% url "perms:asset-permission-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}}, }},
......
...@@ -7,6 +7,7 @@ from .. import api ...@@ -7,6 +7,7 @@ from .. import api
app_name = 'perms' app_name = 'perms'
router = routers.DefaultRouter() router = routers.DefaultRouter()
router.register('actions', api.ActionViewSet, 'action')
router.register('asset-permissions', api.AssetPermissionViewSet, 'asset-permission') router.register('asset-permissions', api.AssetPermissionViewSet, 'asset-permission')
urlpatterns = [ urlpatterns = [
...@@ -67,6 +68,8 @@ urlpatterns = [ ...@@ -67,6 +68,8 @@ urlpatterns = [
# 验证用户是否有某个资产和系统用户的权限 # 验证用户是否有某个资产和系统用户的权限
path('asset-permission/user/validate/', api.ValidateUserAssetPermissionApi.as_view(), path('asset-permission/user/validate/', api.ValidateUserAssetPermissionApi.as_view(),
name='validate-user-asset-permission'), name='validate-user-asset-permission'),
path('asset-permission/user/actions/', api.GetUserAssetPermissionActionsApi.as_view(),
name='get-user-asset-permission-actions'),
] ]
urlpatterns += router.urls urlpatterns += router.urls
......
# coding: utf-8 # coding: utf-8
from __future__ import absolute_import, unicode_literals
import uuid import uuid
from collections import defaultdict from collections import defaultdict
import json import json
...@@ -13,7 +12,7 @@ from django.conf import settings ...@@ -13,7 +12,7 @@ from django.conf import settings
from common.utils import get_logger from common.utils import get_logger
from common.tree import TreeNode from common.tree import TreeNode
from .models import AssetPermission from .models import AssetPermission, Action
from .hands import Node from .hands import Node
logger = get_logger(__file__) logger = get_logger(__file__)
...@@ -101,7 +100,7 @@ class AssetPermissionUtil: ...@@ -101,7 +100,7 @@ class AssetPermissionUtil:
"UserGroup": get_user_group_permissions, "UserGroup": get_user_group_permissions,
"Asset": get_asset_permissions, "Asset": get_asset_permissions,
"Node": get_node_permissions, "Node": get_node_permissions,
"SystemUser": get_node_permissions, "SystemUser": get_system_user_permissions,
} }
CACHE_KEY_PREFIX = '_ASSET_PERM_CACHE_' CACHE_KEY_PREFIX = '_ASSET_PERM_CACHE_'
...@@ -180,6 +179,24 @@ class AssetPermissionUtil: ...@@ -180,6 +179,24 @@ class AssetPermissionUtil:
) )
return assets return assets
def _setattr_actions_to_system_user(self):
"""
动态给system_use设置属性actions
"""
for asset, system_users in self._assets.items():
# 获取资产和资产的祖先节点的所有授权规则
perms = get_asset_permissions(asset, include_node=True)
# 过滤当前self.permission的授权规则
perms = perms.filter(id__in=[perm.id for perm in self.permissions])
for system_user in system_users:
actions = set()
_perms = perms.filter(system_users=system_user).\
prefetch_related('actions')
for _perm in _perms:
actions.update(_perm.actions.all())
setattr(system_user, 'actions', actions)
def get_assets_without_cache(self): def get_assets_without_cache(self):
if self._assets: if self._assets:
return self._assets return self._assets
...@@ -192,6 +209,7 @@ class AssetPermissionUtil: ...@@ -192,6 +209,7 @@ class AssetPermissionUtil:
[s for s in system_users if s.protocol == asset.protocol] [s for s in system_users if s.protocol == asset.protocol]
) )
self._assets = assets self._assets = assets
self._setattr_actions_to_system_user()
return self._assets return self._assets
def get_cache_key(self, resource): def get_cache_key(self, resource):
...@@ -395,6 +413,7 @@ def parse_asset_to_tree_node(node, asset, system_users): ...@@ -395,6 +413,7 @@ def parse_asset_to_tree_node(node, asset, system_users):
'protocol': system_user.protocol, 'protocol': system_user.protocol,
'priority': system_user.priority, 'priority': system_user.priority,
'login_mode': system_user.login_mode, 'login_mode': system_user.login_mode,
'actions': [action.name for action in system_user.actions],
'comment': system_user.comment, 'comment': system_user.comment,
}) })
data = { data = {
...@@ -423,3 +442,21 @@ def parse_asset_to_tree_node(node, asset, system_users): ...@@ -423,3 +442,21 @@ def parse_asset_to_tree_node(node, asset, system_users):
} }
tree_node = TreeNode(**data) tree_node = TreeNode(**data)
return tree_node return tree_node
#
# actions
#
def check_system_user_action(system_user, action):
"""
:param system_user: SystemUser object (包含动态属性: actions)
:param action: Action object
:return: bool
"""
check_actions = [Action.get_action_all(), action]
granted_actions = getattr(system_user, 'actions', [])
actions = list(set(granted_actions).intersection(set(check_actions)))
return bool(actions)
...@@ -11,8 +11,9 @@ from django.conf import settings ...@@ -11,8 +11,9 @@ from django.conf import settings
from common.permissions import AdminUserRequiredMixin from common.permissions import AdminUserRequiredMixin
from orgs.utils import current_org from orgs.utils import current_org
from .hands import Node, Asset, SystemUser, User, UserGroup from .hands import Node, Asset, SystemUser, User, UserGroup
from .models import AssetPermission from .models import AssetPermission, Action
from .forms import AssetPermissionForm from .forms import AssetPermissionForm
from .const import PERMS_ACTION_NAME_ALL
class AssetPermissionListView(AdminUserRequiredMixin, TemplateView): class AssetPermissionListView(AdminUserRequiredMixin, TemplateView):
...@@ -46,6 +47,8 @@ class AssetPermissionCreateView(AdminUserRequiredMixin, CreateView): ...@@ -46,6 +47,8 @@ class AssetPermissionCreateView(AdminUserRequiredMixin, CreateView):
assets_id = assets_id.split(",") assets_id = assets_id.split(",")
assets = Asset.objects.filter(id__in=assets_id) assets = Asset.objects.filter(id__in=assets_id)
form['assets'].initial = assets form['assets'].initial = assets
form['actions'].initial = Action.objects.get(name=PERMS_ACTION_NAME_ALL)
return form return form
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
......
...@@ -538,7 +538,11 @@ jumpserver.initServerSideDataTable = function (options) { ...@@ -538,7 +538,11 @@ jumpserver.initServerSideDataTable = function (options) {
$(td).html('<input type="checkbox" class="text-center ipt_check" id=99991937>'.replace('99991937', cellData)); $(td).html('<input type="checkbox" class="text-center ipt_check" id=99991937>'.replace('99991937', cellData));
} }
}, },
{className: 'text-center', targets: '_all'} {
targets: '_all',
className: 'text-center',
render: $.fn.dataTable.render.text()
}
]; ];
columnDefs = options.columnDefs ? options.columnDefs.concat(columnDefs) : columnDefs; columnDefs = options.columnDefs ? options.columnDefs.concat(columnDefs) : columnDefs;
var select = { var select = {
...@@ -945,4 +949,11 @@ function rootNodeAddDom(ztree, callback) { ...@@ -945,4 +949,11 @@ function rootNodeAddDom(ztree, callback) {
ztree.destroy(); ztree.destroy();
callback() callback()
}) })
}
function htmlEscape ( d ) {
return typeof d === 'string' ?
d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
d;
} }
\ No newline at end of file
...@@ -2,10 +2,8 @@ ...@@ -2,10 +2,8 @@
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
{% block custom_head_css_js %} {% block custom_head_css_js %}
<link href="{% static "css/plugins/datatables/datatables.min.css" %}" rel="stylesheet">
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet"> <link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script> <script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
<script src="{% static "js/plugins/datatables/datatables.min.js" %}"></script>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
......
...@@ -47,7 +47,8 @@ ...@@ -47,7 +47,8 @@
{% if messages %} {% if messages %}
{% for message in messages %} {% for message in messages %}
<div class="alert alert-{{ message.tags }} help-message" > <div class="alert alert-{{ message.tags }} help-message" >
{{ message|safe }} {# {{ message|safe }}#}
{{ message }}
<button aria-hidden="true" data-dismiss="alert" class="close" type="button" style="outline: none;">×</button> <button aria-hidden="true" data-dismiss="alert" class="close" type="button" style="outline: none;">×</button>
</div> </div>
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from rest_framework import serializers from rest_framework import serializers
from rest_framework_bulk.serializers import BulkListSerializer
from common.mixins import BulkSerializerMixin from common.mixins import BulkSerializerMixin
from common.serializers import AdaptedBulkListSerializer
from ..models import Terminal, Status, Session, Task from ..models import Terminal, Status, Session, Task
...@@ -29,7 +29,7 @@ class SessionSerializer(BulkSerializerMixin, serializers.ModelSerializer): ...@@ -29,7 +29,7 @@ class SessionSerializer(BulkSerializerMixin, serializers.ModelSerializer):
class Meta: class Meta:
model = Session model = Session
list_serializer_class = BulkListSerializer list_serializer_class = AdaptedBulkListSerializer
fields = '__all__' fields = '__all__'
...@@ -44,7 +44,7 @@ class TaskSerializer(BulkSerializerMixin, serializers.ModelSerializer): ...@@ -44,7 +44,7 @@ class TaskSerializer(BulkSerializerMixin, serializers.ModelSerializer):
class Meta: class Meta:
fields = '__all__' fields = '__all__'
model = Task model = Task
list_serializer_class = BulkListSerializer list_serializer_class = AdaptedBulkListSerializer
class ReplaySerializer(serializers.Serializer): class ReplaySerializer(serializers.Serializer):
......
...@@ -50,6 +50,7 @@ function initTable() { ...@@ -50,6 +50,7 @@ function initTable() {
buttons: [], buttons: [],
columnDefs: [ columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) { {targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
var detail_btn = '<a href="{% url "terminal:terminal-detail" pk=DEFAULT_PK %}">' + cellData + '</a>'; var detail_btn = '<a href="{% url "terminal:terminal-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}}, }},
......
...@@ -5,6 +5,7 @@ from django.core.cache import cache ...@@ -5,6 +5,7 @@ from django.core.cache import cache
from django.contrib.auth import logout from django.contrib.auth import logout
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from rest_framework import status
from rest_framework import generics from rest_framework import generics
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
...@@ -52,9 +53,72 @@ class UserViewSet(IDInFilterMixin, BulkModelViewSet): ...@@ -52,9 +53,72 @@ class UserViewSet(IDInFilterMixin, BulkModelViewSet):
self.permission_classes = (IsOrgAdminOrAppUser,) self.permission_classes = (IsOrgAdminOrAppUser,)
return super().get_permissions() return super().get_permissions()
def _deny_permission(self, instance):
"""
check current user has permission to handle instance
(update, destroy, bulk_update, bulk destroy)
"""
return not self.request.user.is_superuser and instance.is_superuser
def destroy(self, request, *args, **kwargs):
"""
rewrite because limit org_admin destroy superuser
"""
instance = self.get_object()
if self._deny_permission(instance):
data = {'msg': _("You do not have permission.")}
return Response(data=data, status=status.HTTP_403_FORBIDDEN)
return super().destroy(request, *args, **kwargs)
def update(self, request, *args, **kwargs):
"""
rewrite because limit org_admin update superuser
"""
instance = self.get_object()
if self._deny_permission(instance):
data = {'msg': _("You do not have permission.")}
return Response(data=data, status=status.HTTP_403_FORBIDDEN)
return super().update(request, *args, **kwargs)
def _bulk_deny_permission(self, instances):
deny_instances = [i for i in instances if self._deny_permission(i)]
if len(deny_instances) > 0:
return True
else:
return False
def allow_bulk_destroy(self, qs, filtered): def allow_bulk_destroy(self, qs, filtered):
if self._bulk_deny_permission(filtered):
return False
return qs.count() != filtered.count() return qs.count() != filtered.count()
def bulk_update(self, request, *args, **kwargs):
"""
rewrite because limit org_admin update superuser
"""
partial = kwargs.pop('partial', False)
# restrict the update to the filtered queryset
queryset = self.filter_queryset(self.get_queryset())
if self._bulk_deny_permission(queryset):
data = {'msg': _("You do not have permission.")}
return Response(data=data, status=status.HTTP_403_FORBIDDEN)
serializer = self.get_serializer(
queryset, data=request.data, many=True, partial=partial,
)
try:
serializer.is_valid(raise_exception=True)
except Exception as e:
data = {'error': str(e)}
return Response(data=data, status=status.HTTP_400_BAD_REQUEST)
self.perform_bulk_update(serializer)
return Response(serializer.data, status=status.HTTP_200_OK)
class UserChangePasswordApi(generics.RetrieveUpdateAPIView): class UserChangePasswordApi(generics.RetrieveUpdateAPIView):
permission_classes = (IsOrgAdmin,) permission_classes = (IsOrgAdmin,)
......
...@@ -3,24 +3,28 @@ ...@@ -3,24 +3,28 @@
# #
import uuid import uuid
import base64 import base64
import string
import random
from collections import OrderedDict from collections import OrderedDict
from django.conf import settings from django.conf import settings
from django.contrib.auth.hashers import make_password from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.core import signing
from django.core.cache import cache from django.core.cache import cache
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils import timezone from django.utils import timezone
from django.shortcuts import reverse from django.shortcuts import reverse
from common.utils import get_signer, date_expired_default from common.utils import get_signer, date_expired_default, get_logger
__all__ = ['User'] __all__ = ['User']
signer = get_signer() signer = get_signer()
logger = get_logger(__file__)
class User(AbstractUser): class User(AbstractUser):
ROLE_ADMIN = 'Admin' ROLE_ADMIN = 'Admin'
...@@ -47,6 +51,9 @@ class User(AbstractUser): ...@@ -47,6 +51,9 @@ class User(AbstractUser):
(SOURCE_OPENID, 'OpenID'), (SOURCE_OPENID, 'OpenID'),
(SOURCE_RADIUS, 'Radius'), (SOURCE_RADIUS, 'Radius'),
) )
CACHE_KEY_USER_RESET_PASSWORD_PREFIX = "_KEY_USER_RESET_PASSWORD_{}"
id = models.UUIDField(default=uuid.uuid4, primary_key=True) id = models.UUIDField(default=uuid.uuid4, primary_key=True)
username = models.CharField( username = models.CharField(
max_length=128, unique=True, verbose_name=_('Username') max_length=128, unique=True, verbose_name=_('Username')
...@@ -346,9 +353,32 @@ class User(AbstractUser): ...@@ -346,9 +353,32 @@ class User(AbstractUser):
return user_default return user_default
def generate_reset_token(self): def generate_reset_token(self):
return signer.sign_t( letter = string.ascii_letters + string.digits
{'reset': str(self.id), 'email': self.email}, expires_in=3600 token =''.join([random.choice(letter) for _ in range(50)])
) self.set_cache(token)
return token
def set_cache(self, token):
key = self.CACHE_KEY_USER_RESET_PASSWORD_PREFIX.format(token)
cache.set(key, {'id': self.id, 'email': self.email}, 3600)
@classmethod
def validate_reset_password_token(cls, token):
try:
key = cls.CACHE_KEY_USER_RESET_PASSWORD_PREFIX.format(token)
value = cache.get(key)
user_id = value.get('id', '')
email = value.get('email', '')
user = cls.objects.get(id=user_id, email=email)
except (AttributeError, cls.DoesNotExist) as e:
logger.error(e, exc_info=True)
user = None
return user
@classmethod
def expired_reset_password_token(cls, token):
key = cls.CACHE_KEY_USER_RESET_PASSWORD_PREFIX.format(token)
cache.delete(key)
@property @property
def otp_enabled(self): def otp_enabled(self):
...@@ -400,18 +430,6 @@ class User(AbstractUser): ...@@ -400,18 +430,6 @@ class User(AbstractUser):
access_key = app.create_access_key() access_key = app.create_access_key()
return app, access_key return app, access_key
@classmethod
def validate_reset_token(cls, token):
try:
data = signer.unsign_t(token)
user_id = data.get('reset', None)
user_email = data.get('email', '')
user = cls.objects.get(id=user_id, email=user_email)
except (signing.BadSignature, cls.DoesNotExist):
user = None
return user
def reset_password(self, new_password): def reset_password(self, new_password):
self.set_password(new_password) self.set_password(new_password)
self.date_password_last_updated = timezone.now() self.date_password_last_updated = timezone.now()
......
...@@ -3,10 +3,10 @@ ...@@ -3,10 +3,10 @@
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from rest_framework_bulk import BulkListSerializer
from common.utils import get_signer, validate_ssh_public_key from common.utils import get_signer, validate_ssh_public_key
from common.mixins import BulkSerializerMixin from common.mixins import BulkSerializerMixin
from common.serializers import AdaptedBulkListSerializer
from ..models import User, UserGroup from ..models import User, UserGroup
signer = get_signer() signer = get_signer()
...@@ -16,7 +16,7 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer): ...@@ -16,7 +16,7 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
class Meta: class Meta:
model = User model = User
list_serializer_class = BulkListSerializer list_serializer_class = AdaptedBulkListSerializer
fields = [ fields = [
'id', 'name', 'username', 'email', 'groups', 'groups_display', 'id', 'name', 'username', 'email', 'groups', 'groups_display',
'role', 'role_display', 'avatar_url', 'wechat', 'phone', 'role', 'role_display', 'avatar_url', 'wechat', 'phone',
...@@ -52,7 +52,7 @@ class UserGroupSerializer(BulkSerializerMixin, serializers.ModelSerializer): ...@@ -52,7 +52,7 @@ class UserGroupSerializer(BulkSerializerMixin, serializers.ModelSerializer):
class Meta: class Meta:
model = UserGroup model = UserGroup
list_serializer_class = BulkListSerializer list_serializer_class = AdaptedBulkListSerializer
fields = '__all__' fields = '__all__'
read_only_fields = ['created_by'] read_only_fields = ['created_by']
......
...@@ -22,11 +22,11 @@ ...@@ -22,11 +22,11 @@
<a href="{% url 'users:user-granted-asset' pk=user_object.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a> <a href="{% url 'users:user-granted-asset' pk=user_object.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a>
</li> </li>
<li class="pull-right"> <li class="pull-right">
<a class="btn btn-outline btn-default" href="{% url 'users:user-update' pk=user_object.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a> <a class="btn btn-outline {% if user_object.is_superuser and not request.user.is_superuser %} disabled {% else %} btn-default {% endif %}" href="{% url 'users:user-update' pk=user_object.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
</li> </li>
<li class="pull-right"> <li class="pull-right">
<a class="btn btn-outline {% if request.user != user_object and user_object.username != "admin" %} btn-danger btn-delete-user {% else %} disabled {% endif %}"> <a class="btn btn-outline {% if request.user == user_object or user_object.username == "admin" or user_object.is_superuser and not request.user.is_superuser %} disabled {% else %} btn-danger btn-delete-user {% endif %}">
<i class="fa fa-trash-o"></i>{% trans 'Delete' %} <i class="fa fa-trash-o"></i>{% trans 'Delete' %}
</a> </a>
</li> </li>
......
...@@ -77,6 +77,7 @@ function initTable() { ...@@ -77,6 +77,7 @@ function initTable() {
ele: $('#user_assets_table'), ele: $('#user_assets_table'),
columnDefs: [ columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) { {targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
{% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %} {% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %}
var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>'; var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
...@@ -91,7 +92,8 @@ function initTable() { ...@@ -91,7 +92,8 @@ function initTable() {
{targets: 4, createdCell: function (td, cellData) { {targets: 4, createdCell: function (td, cellData) {
var users = []; var users = [];
$.each(cellData, function (id, data) { $.each(cellData, function (id, data) {
users.push(data.name); var name = htmlEscape(data.name);
users.push(name);
}); });
$(td).html(users.join(', ')) $(td).html(users.join(', '))
}} }}
......
...@@ -77,6 +77,7 @@ function initTable() { ...@@ -77,6 +77,7 @@ function initTable() {
ele: $('#user_assets_table'), ele: $('#user_assets_table'),
columnDefs: [ columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) { {targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
{% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %} {% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %}
var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>'; var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
...@@ -91,7 +92,8 @@ function initTable() { ...@@ -91,7 +92,8 @@ function initTable() {
{targets: 4, createdCell: function (td, cellData) { {targets: 4, createdCell: function (td, cellData) {
var users = []; var users = [];
$.each(cellData, function (id, data) { $.each(cellData, function (id, data) {
users.push(data.name); var name = htmlEscape(data.name);
users.push(name);
}); });
$(td).html(users.join(', ')) $(td).html(users.join(', '))
}} }}
......
...@@ -28,6 +28,7 @@ $(document).ready(function() { ...@@ -28,6 +28,7 @@ $(document).ready(function() {
buttons: [], buttons: [],
columnDefs: [ columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) { {targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
var detail_btn = '<a href="{% url "users:user-group-detail" pk=DEFAULT_PK %}">' + cellData + '</a>'; var detail_btn = '<a href="{% url "users:user-group-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}}, }},
...@@ -36,6 +37,7 @@ $(document).ready(function() { ...@@ -36,6 +37,7 @@ $(document).ready(function() {
$(td).html(html); $(td).html(html);
}}, }},
{targets: 3, createdCell: function (td, cellData) { {targets: 3, createdCell: function (td, cellData) {
cellData = htmlEscape(cellData);
var innerHtml = cellData.length > 30 ? cellData.substring(0, 30) + '...': cellData; var innerHtml = cellData.length > 30 ? cellData.substring(0, 30) + '...': cellData;
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>'); $(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');
}}, }},
......
...@@ -59,6 +59,7 @@ function initTable() { ...@@ -59,6 +59,7 @@ function initTable() {
ele: $('#user_list_table'), ele: $('#user_list_table'),
columnDefs: [ columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) { {targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
var detail_btn = '<a href="{% url "users:user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>'; var detail_btn = '<a href="{% url "users:user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace("{{ DEFAULT_PK }}", rowData.id)); $(td).html(detail_btn.replace("{{ DEFAULT_PK }}", rowData.id));
}}, }},
...@@ -77,10 +78,16 @@ function initTable() { ...@@ -77,10 +78,16 @@ function initTable() {
} }
}}, }},
{targets: 7, createdCell: function (td, cellData, rowData) { {targets: 7, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "users:user-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('00000000-0000-0000-0000-000000000000', cellData); var update_btn = "";
if (rowData.role === 'Admin' && ('{{ request.user.role }}' !== 'Admin')) {
update_btn = '<a class="btn btn-xs disabled btn-info">{% trans "Update" %}</a>';
}
else{
update_btn = '<a href="{% url "users:user-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('00000000-0000-0000-0000-000000000000', cellData);
}
var del_btn = ""; var del_btn = "";
if (rowData.id === 1 || rowData.username === "admin" || rowData.username === "{{ request.user.username }}") { if (rowData.id === 1 || rowData.username === "admin" || rowData.username === "{{ request.user.username }}" || (rowData.role === 'Admin' && ('{{ request.user.role }}' !== 'Admin'))) {
del_btn = '<a class="btn btn-xs btn-danger m-l-xs" disabled>{% trans "Delete" %}</a>' del_btn = '<a class="btn btn-xs btn-danger m-l-xs" disabled>{% trans "Delete" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData) .replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', rowData.name); .replace('99991938', rowData.name);
......
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals from __future__ import unicode_literals
from django.core.cache import cache
from django.shortcuts import render from django.shortcuts import render
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import RedirectView from django.views.generic import RedirectView
...@@ -84,7 +85,7 @@ class UserResetPasswordView(TemplateView): ...@@ -84,7 +85,7 @@ class UserResetPasswordView(TemplateView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
token = request.GET.get('token', '') token = request.GET.get('token', '')
user = User.validate_reset_token(token) user = User.validate_reset_password_token(token)
if not user: if not user:
kwargs.update({'errors': _('Token invalid or expired')}) kwargs.update({'errors': _('Token invalid or expired')})
else: else:
...@@ -100,12 +101,12 @@ class UserResetPasswordView(TemplateView): ...@@ -100,12 +101,12 @@ class UserResetPasswordView(TemplateView):
if password != password_confirm: if password != password_confirm:
return self.get(request, errors=_('Password not same')) return self.get(request, errors=_('Password not same'))
user = User.validate_reset_token(token) user = User.validate_reset_password_token(token)
if not user:
return self.get(request, errors=_('Token invalid or expired'))
if not user.can_update_password(): if not user.can_update_password():
error = _('User auth from {}, go there change password'.format(user.source)) error = _('User auth from {}, go there change password'.format(user.source))
return self.get(request, errors=error) return self.get(request, errors=error)
if not user:
return self.get(request, errors=_('Token invalid or expired'))
is_ok = check_password_rules(password) is_ok = check_password_rules(password)
if not is_ok: if not is_ok:
...@@ -115,6 +116,7 @@ class UserResetPasswordView(TemplateView): ...@@ -115,6 +116,7 @@ class UserResetPasswordView(TemplateView):
) )
user.reset_password(password) user.reset_password(password)
User.expired_reset_password_token(token)
return HttpResponseRedirect(reverse('users:reset-password-success')) return HttpResponseRedirect(reverse('users:reset-password-success'))
......
...@@ -107,6 +107,15 @@ class UserUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView): ...@@ -107,6 +107,15 @@ class UserUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
success_url = reverse_lazy('users:user-list') success_url = reverse_lazy('users:user-list')
success_message = update_success_msg success_message = update_success_msg
def _deny_permission(self):
obj = self.get_object()
return not self.request.user.is_superuser and obj.is_superuser
def get(self, request, *args, **kwargs):
if self._deny_permission():
return redirect(self.success_url)
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
check_rules = get_password_check_rules() check_rules = get_password_check_rules()
context = { context = {
......
...@@ -7,4 +7,4 @@ if [ ! -d $backup_dir ];then ...@@ -7,4 +7,4 @@ if [ ! -d $backup_dir ];then
mkdir $backup_dir mkdir $backup_dir
fi fi
mysqldump -uroot -h127.0.0.1 -p jumpserver > ${backup_dir}/jumpserver_$(date +'%Y-%m-%d_%H:%M:%S').sql mysqldump -uroot -h127.0.0.1 -p jumpserver -P3307 > ${backup_dir}/jumpserver_$(date +'%Y-%m-%d_%H:%M:%S').sql
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment