Commit 9cd75390 authored by BaiJiangJie's avatar BaiJiangJie Committed by 老广

[Update] Auth Info (#2806)

* [Update] 修改支持auth info导出

* [Update] 统一认证查看

* [Update] 修改auth book manager

* [Update] 修改auth info

* [Update] 完成修改auth info

* [Update] 优化api
parent 8adaf629
...@@ -6,11 +6,10 @@ from django.views.generic import TemplateView ...@@ -6,11 +6,10 @@ from django.views.generic import TemplateView
from django.views.generic.edit import CreateView, UpdateView from django.views.generic.edit import CreateView, UpdateView
from django.views.generic.detail import DetailView from django.views.generic.detail import DetailView
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy from django.urls import reverse_lazy
from common.permissions import PermissionsMixin, IsOrgAdmin from common.permissions import PermissionsMixin, IsOrgAdmin, IsValidUser
from common.const import create_success_msg, update_success_msg from common.const import create_success_msg, update_success_msg
from ..models import RemoteApp from ..models import RemoteApp
...@@ -92,8 +91,9 @@ class RemoteAppDetailView(PermissionsMixin, DetailView): ...@@ -92,8 +91,9 @@ class RemoteAppDetailView(PermissionsMixin, DetailView):
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
class UserRemoteAppListView(LoginRequiredMixin, TemplateView): class UserRemoteAppListView(PermissionsMixin, TemplateView):
template_name = 'applications/user_remote_app_list.html' template_name = 'applications/user_remote_app_list.html'
permission_classes = [IsValidUser]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = { context = {
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import time
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework import viewsets, status, generics from rest_framework import viewsets, status, generics
from rest_framework.pagination import LimitOffsetPagination from rest_framework.pagination import LimitOffsetPagination
from rest_framework import filters
from rest_framework_bulk import BulkModelViewSet
from django.shortcuts import get_object_or_404
from common.permissions import IsOrgAdminOrAppUser from common.permissions import IsOrgAdminOrAppUser
from common.utils import get_object_or_none, get_logger from common.utils import get_object_or_none, get_logger
from common.mixins import IDInCacheFilterMixin
from ..backends.multi import AssetUserManager from ..backends import AssetUserManager
from ..models import Asset from ..models import Asset, Node, SystemUser, AdminUser
from .. import serializers from .. import serializers
from ..tasks import test_asset_users_connectivity_manual from ..tasks import test_asset_users_connectivity_manual
__all__ = [ __all__ = [
'AssetUserViewSet', 'AssetUserAuthInfoApi', 'AssetUserTestConnectiveApi', 'AssetUserViewSet', 'AssetUserAuthInfoApi', 'AssetUserTestConnectiveApi',
'AssetUserExportViewSet',
] ]
logger = get_logger(__name__) logger = get_logger(__name__)
class AssetUserViewSet(viewsets.GenericViewSet): class AssetUserFilterBackend(filters.BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
kwargs = {}
for field in view.filter_fields:
value = request.GET.get(field)
if not value:
continue
if field in ("node_id", "system_user_id", "admin_user_id"):
continue
kwargs[field] = value
return queryset.filter(**kwargs)
class AssetUserSearchBackend(filters.BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
value = request.GET.get('search')
if not value:
return queryset
_queryset = AssetUserManager.none()
for field in view.search_fields:
if field in ("node_id", "system_user_id", "admin_user_id"):
continue
_queryset |= queryset.filter(**{field: value})
return _queryset
class AssetUserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
pagination_class = LimitOffsetPagination pagination_class = LimitOffsetPagination
serializer_class = serializers.AssetUserSerializer serializer_class = serializers.AssetUserSerializer
permission_classes = (IsOrgAdminOrAppUser, ) permission_classes = (IsOrgAdminOrAppUser, )
http_method_names = ['get', 'post'] http_method_names = ['get', 'post']
filter_fields = [
def create(self, request, *args, **kwargs): "id", "ip", "hostname", "username", "asset_id", "node_id",
serializer = self.get_serializer(data=request.data) "system_user_id", "admin_user_id"
serializer.is_valid(raise_exception=True) ]
serializer.save() search_fields = filter_fields
return Response(serializer.data, status=status.HTTP_201_CREATED) filter_backends = (
filters.OrderingFilter,
def list(self, request, *args, **kwargs): AssetUserFilterBackend, AssetUserSearchBackend,
queryset = self.filter_queryset(self.get_queryset()) )
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
def get_queryset(self): def get_queryset(self):
# 尽可能先返回更少的数据
username = self.request.GET.get('username') username = self.request.GET.get('username')
asset_id = self.request.GET.get('asset_id') asset_id = self.request.GET.get('asset_id')
node_id = self.request.GET.get('node_id')
admin_user_id = self.request.GET.get("admin_user_id")
system_user_id = self.request.GET.get("system_user_id")
kwargs = {}
assets = []
manager = AssetUserManager()
if system_user_id:
system_user = get_object_or_404(SystemUser, id=system_user_id)
assets = system_user.assets.all()
username = system_user.username
elif admin_user_id:
admin_user = get_object_or_404(AdminUser, id=admin_user_id)
assets = admin_user.assets.all()
username = admin_user.username
manager.prefer('admin_user')
if asset_id:
asset = get_object_or_none(Asset, pk=asset_id) asset = get_object_or_none(Asset, pk=asset_id)
queryset = AssetUserManager.filter(username=username, asset=asset) assets = [asset]
return queryset elif node_id:
node = get_object_or_404(Node, id=node_id)
assets = node.assets.all()
def filter_queryset(self, queryset): if username:
queryset = sorted( kwargs['username'] = username
queryset, if assets:
key=lambda q: (q.asset.hostname, q.connectivity, q.username) kwargs['assets'] = assets
)
queryset = manager.filter(**kwargs)
return queryset return queryset
class AssetUserExportViewSet(AssetUserViewSet):
serializer_class = serializers.AssetUserExportSerializer
http_method_names = ['get']
def list(self, request, *args, **kwargs):
otp_last_verify = request.session.get("OTP_LAST_VERIFY_TIME")
if not otp_last_verify or time.time() - int(otp_last_verify) > 600:
return Response({"error": "Need MFA confirm mfa auth"}, status=403)
return super().list(request, *args, **kwargs)
class AssetUserAuthInfoApi(generics.RetrieveAPIView): class AssetUserAuthInfoApi(generics.RetrieveAPIView):
serializer_class = serializers.AssetUserAuthInfoSerializer serializer_class = serializers.AssetUserAuthInfoSerializer
permission_classes = (IsOrgAdminOrAppUser,) permission_classes = (IsOrgAdminOrAppUser,)
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
otp_last_verify = request.session.get("OTP_LAST_VERIFY_TIME")
if not otp_last_verify or time.time() - int(otp_last_verify) > 600:
return Response({"error": "Need MFA confirm mfa auth"}, status=403)
instance = self.get_object() instance = self.get_object()
serializer = self.get_serializer(instance) serializer = self.get_serializer(instance)
status_code = status.HTTP_200_OK status_code = status.HTTP_200_OK
...@@ -70,9 +137,13 @@ class AssetUserAuthInfoApi(generics.RetrieveAPIView): ...@@ -70,9 +137,13 @@ class AssetUserAuthInfoApi(generics.RetrieveAPIView):
def get_object(self): def get_object(self):
username = self.request.GET.get('username') username = self.request.GET.get('username')
asset_id = self.request.GET.get('asset_id') asset_id = self.request.GET.get('asset_id')
prefer = self.request.GET.get("prefer")
asset = get_object_or_none(Asset, pk=asset_id) asset = get_object_or_none(Asset, pk=asset_id)
try: try:
instance = AssetUserManager.get(username, asset) manger = AssetUserManager()
if prefer:
manger.prefer(prefer)
instance = manger.get(username, asset)
except Exception as e: except Exception as e:
logger.error(e, exc_info=True) logger.error(e, exc_info=True)
return None return None
...@@ -84,18 +155,36 @@ class AssetUserTestConnectiveApi(generics.RetrieveAPIView): ...@@ -84,18 +155,36 @@ class AssetUserTestConnectiveApi(generics.RetrieveAPIView):
""" """
Test asset users connective Test asset users connective
""" """
permission_classes = (IsOrgAdminOrAppUser,)
def get_asset_users(self): def get_asset_users(self):
username = self.request.GET.get('username') username = self.request.GET.get('username')
asset_id = self.request.GET.get('asset_id') asset_id = self.request.GET.get('asset_id')
asset = get_object_or_none(Asset, pk=asset_id) asset = get_object_or_none(Asset, pk=asset_id)
asset_users = AssetUserManager.filter(username=username, asset=asset) manager = AssetUserManager()
asset_users = manager.filter(username=username, assets=[asset])
return asset_users return asset_users
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
asset_users = self.get_asset_users() asset_users = self.get_asset_users()
task = test_asset_users_connectivity_manual.delay(asset_users) prefer = self.request.GET.get("prefer")
kwargs = {}
if prefer == "admin_user":
kwargs["run_as_admin"] = True
task = test_asset_users_connectivity_manual.delay(asset_users, **kwargs)
return Response({"task": task.id}) return Response({"task": task.id})
class AssetUserPushApi(generics.CreateAPIView):
"""
Test asset users connective
"""
serializer_class = serializers.AssetUserPushSerializer
permission_classes = (IsOrgAdminOrAppUser,)
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
asset = serializer.validated_data["asset"]
username = serializer.validated_data["username"]
pass
from .manager import AssetUserManager
# -*- coding: utf-8 -*-
#
from ..models import AdminUser
from .asset_user import AssetUserBackend
class AdminUserBackend(AssetUserBackend):
model = AdminUser
backend = 'AdminUser'
# -*- coding: utf-8 -*-
#
from .base import BaseBackend
class AssetUserBackend(BaseBackend):
model = None
backend = "AssetUser"
@classmethod
def filter_queryset_more(cls, queryset):
return queryset
@classmethod
def filter(cls, username=None, assets=None, **kwargs):
queryset = cls.model.objects.all()
if username:
queryset = queryset.filter(username=username)
if assets:
queryset = queryset.filter(assets__in=assets).distinct()
queryset = cls.filter_queryset_more(queryset)
instances = cls.construct_authbook_objects(queryset, assets)
return instances
@classmethod
def construct_authbook_objects(cls, asset_users, assets):
instances = []
for asset_user in asset_users:
if not assets:
assets = asset_user.assets.all()
for asset in assets:
instance = asset_user.construct_to_authbook(asset)
instance.backend = cls.backend
instances.append(instance)
return instances
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import uuid
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from abc import abstractmethod from abc import abstractmethod
class NotSupportError(Exception):
pass
class BaseBackend: class BaseBackend:
ObjectDoesNotExist = ObjectDoesNotExist
MultipleObjectsReturned = MultipleObjectsReturned
NotSupportError = NotSupportError
MSG_NOT_EXIST = '{} Object matching query does not exist'
MSG_MULTIPLE = '{} get() returned more than one object ' \
'-- it returned {}!'
@classmethod
def get(cls, username, asset):
instances = cls.filter(username, asset)
if len(instances) == 1:
return instances[0]
elif len(instances) == 0:
cls.raise_does_not_exist(cls.__name__)
else:
cls.raise_multiple_return(cls.__name__, len(instances))
@classmethod @classmethod
@abstractmethod @abstractmethod
def filter(cls, username=None, asset=None, latest=True): def filter(cls, username=None, assets=None, latest=True):
""" """
:param username: 用户名 :param username: 用户名
:param asset: <Asset>对象 :param assets: <Asset>对象
:param latest: 是否是最新记录 :param latest: 是否是最新记录
:return: 元素为<AuthBook>的可迭代对象(<list> or <QuerySet>) :return: 元素为<AuthBook>的可迭代对象(<list> or <QuerySet>)
""" """
pass pass
@classmethod
@abstractmethod
def create(cls, **kwargs):
"""
:param kwargs:
{
name, username, asset, comment, password, public_key, private_key,
(org_id)
}
:return: <AuthBook>对象
"""
pass
@classmethod class AssetUserQuerySet(list):
def raise_does_not_exist(cls, name): def order_by(self, *ordering):
raise cls.ObjectDoesNotExist(cls.MSG_NOT_EXIST.format(name)) _ordering = []
reverse = False
for i in ordering:
if i[0] == '-':
reverse = True
i = i[1:]
_ordering.append(i)
self.sort(key=lambda obj: [getattr(obj, j) for j in _ordering], reverse=reverse)
return self
@classmethod def filter_in(self, kwargs):
def raise_multiple_return(cls, name, length): in_kwargs = {}
raise cls.MultipleObjectsReturned(cls.MSG_MULTIPLE.format(name, length)) queryset = []
for k, v in kwargs.items():
if len(v) == 0:
return self
if k.find("__in") >= 0:
in_kwargs[k] = v
for k in in_kwargs:
kwargs.pop(k)
if len(in_kwargs) == 0:
return self
for i in self:
matched = True
for k, v in in_kwargs.items():
key = k.split('__')[0]
attr = getattr(i, key, None)
# 如果属性或者value中是uuid,则转换成string
if isinstance(v[0], uuid.UUID):
v = [str(i) for i in v]
if isinstance(attr, uuid.UUID):
attr = str(attr)
if attr not in v:
matched = False
if matched:
queryset.append(i)
return AssetUserQuerySet(queryset)
def filter_equal(self, kwargs):
def filter_it(obj):
wanted = []
real = []
for k, v in kwargs.items():
wanted.append(v)
value = getattr(obj, k)
if isinstance(value, uuid.UUID):
value = str(value)
real.append(value)
return wanted == real
if len(kwargs) > 0:
queryset = AssetUserQuerySet([i for i in self if filter_it(i)])
else:
queryset = self
return queryset
def filter(self, **kwargs):
queryset = self.filter_in(kwargs).filter_equal(kwargs)
return queryset
def __or__(self, other):
self.extend(other)
return self
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from assets.models import AuthBook from ..models import AuthBook
from .base import BaseBackend
from ..base import BaseBackend
class AuthBookBackend(BaseBackend): class AuthBookBackend(BaseBackend):
@classmethod @classmethod
def filter(cls, username=None, asset=None, latest=True): def filter(cls, username=None, assets=None, latest=True):
queryset = AuthBook.objects.all() queryset = AuthBook.objects.all()
if username is not None: if username is not None:
queryset = queryset.filter(username=username) queryset = queryset.filter(username=username)
if asset: if assets:
queryset = queryset.filter(asset=asset) queryset = queryset.filter(asset__in=assets)
if latest: if latest:
queryset = queryset.latest_version() queryset = queryset.latest_version()
return queryset return queryset
......
# -*- coding: utf-8 -*-
#
from assets.models import Asset
from ..base import BaseBackend
from .utils import construct_authbook_object
class AdminUserBackend(BaseBackend):
@classmethod
def filter(cls, username=None, asset=None, **kwargs):
instances = cls.construct_authbook_objects(username, asset)
return instances
@classmethod
def _get_assets(cls, asset):
if not asset:
assets = Asset.objects.all().prefetch_related('admin_user')
else:
assets = [asset]
return assets
@classmethod
def construct_authbook_objects(cls, username, asset):
instances = []
assets = cls._get_assets(asset)
for asset in assets:
if username is not None and asset.admin_user.username != username:
continue
instance = construct_authbook_object(asset.admin_user, asset)
instances.append(instance)
return instances
@classmethod
def create(cls, **kwargs):
raise cls.NotSupportError("Not support create")
# -*- coding: utf-8 -*-
#
from ..base import BaseBackend
from .admin_user import AdminUserBackend
from .system_user import SystemUserBackend
class AssetUserBackend(BaseBackend):
@classmethod
def filter(cls, username=None, asset=None, **kwargs):
admin_user_instances = AdminUserBackend.filter(username, asset)
system_user_instances = SystemUserBackend.filter(username, asset)
instances = cls._merge_instances(admin_user_instances, system_user_instances)
return instances
@classmethod
def _merge_instances(cls, admin_user_instances, system_user_instances):
admin_user_instances_keyword_list = [
{'username': instance.username, 'asset': instance.asset}
for instance in admin_user_instances
]
instances = [
instance for instance in system_user_instances
if instance.keyword not in admin_user_instances_keyword_list
]
admin_user_instances.extend(instances)
return admin_user_instances
@classmethod
def create(cls, **kwargs):
raise cls.NotSupportError("Not support create")
# -*- coding: utf-8 -*-
#
import itertools
from assets.models import Asset
from ..base import BaseBackend
from .utils import construct_authbook_object
class SystemUserBackend(BaseBackend):
@classmethod
def filter(cls, username=None, asset=None, **kwargs):
instances = cls.construct_authbook_objects(username, asset)
return instances
@classmethod
def _distinct_system_users_by_username(cls, system_users):
system_users = sorted(
system_users,
key=lambda su: (su.username, su.priority, su.date_updated),
reverse=True,
)
results = itertools.groupby(system_users, key=lambda su: su.username)
system_users = [next(result[1]) for result in results]
return system_users
@classmethod
def _filter_system_users_by_username(cls, system_users, username):
_system_users = cls._distinct_system_users_by_username(system_users)
if username is not None:
_system_users = [su for su in _system_users if username == su.username]
return _system_users
@classmethod
def _construct_authbook_objects(cls, system_users, asset):
instances = []
for system_user in system_users:
instance = construct_authbook_object(system_user, asset)
instances.append(instance)
return instances
@classmethod
def _get_assets_with_system_users(cls, asset=None):
"""
{ 'asset': set(<SystemUser>, <SystemUser>, ...) }
"""
if not asset:
_assets = Asset.objects.all().prefetch_related('systemuser_set')
else:
_assets = [asset]
assets = {asset: set(asset.systemuser_set.all()) for asset in _assets}
return assets
@classmethod
def construct_authbook_objects(cls, username, asset):
"""
:return: [<AuthBook>, <AuthBook>, ...]
"""
instances = []
assets = cls._get_assets_with_system_users(asset)
for _asset, _system_users in assets.items():
_system_users = cls._filter_system_users_by_username(_system_users, username)
_instances = cls._construct_authbook_objects(_system_users, _asset)
instances.extend(_instances)
return instances
@classmethod
def create(cls, **kwargs):
raise Exception("Not support create")
# -*- coding: utf-8 -*-
#
from assets.models import AuthBook
def construct_authbook_object(asset_user, asset):
"""
作用: 将<AssetUser>对象构造成为<AuthBook>对象并返回
:param asset_user: <AdminUser>或<SystemUser>对象
:param asset: <Asset>对象
:return: <AuthBook>对象
"""
fields = [
'id', 'name', 'username', 'comment', 'org_id',
'_password', '_private_key', '_public_key',
'date_created', 'date_updated', 'created_by'
]
obj = AuthBook(asset=asset, version=0, is_latest=True)
for field in fields:
value = getattr(asset_user, field)
setattr(obj, field, value)
return obj
# -*- coding: utf-8 -*-
#
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from .base import AssetUserQuerySet
from .db import AuthBookBackend
from .system_user import SystemUserBackend
from .admin_user import AdminUserBackend
class NotSupportError(Exception):
pass
class AssetUserManager:
"""
资产用户管理器
"""
ObjectDoesNotExist = ObjectDoesNotExist
MultipleObjectsReturned = MultipleObjectsReturned
NotSupportError = NotSupportError
MSG_NOT_EXIST = '{} Object matching query does not exist'
MSG_MULTIPLE = '{} get() returned more than one object ' \
'-- it returned {}!'
backends = (
('db', AuthBookBackend),
('system_user', SystemUserBackend),
('admin_user', AdminUserBackend),
)
_prefer = "system_user"
_using = None
def filter(self, username=None, assets=None, latest=True):
if self._using:
backend = dict(self.backends).get(self._using)
if not backend:
return self.none()
instances = backend.filter(username=username, assets=assets, latest=latest)
return AssetUserQuerySet(instances)
instances_map = {}
instances = []
for name, backend in self.backends:
_instances = backend.filter(
username=username, assets=assets, latest=latest
)
instances_map[name] = _instances
# 如果不是获取最新版本,就不再merge
if not latest:
for _instances in instances_map.values():
instances.extend(_instances)
return AssetUserQuerySet(instances)
# merge的顺序
ordering = ["db"]
if self._prefer == "system_user":
ordering.extend(["system_user", "admin_user"])
else:
ordering.extend(["admin_user", "system_user"])
# 根据prefer决定优先使用系统用户或管理用户谁的
ordering_instances = [instances_map.get(i) for i in ordering]
instances = self._merge_instances(*ordering_instances)
return AssetUserQuerySet(instances)
def get(self, username, asset):
instances = self.filter(username, assets=[asset])
if len(instances) == 1:
return instances[0]
elif len(instances) == 0:
self.raise_does_not_exist(self.__name__)
else:
self.raise_multiple_return(self.__name__, len(instances))
def raise_does_not_exist(self, name):
raise self.ObjectDoesNotExist(self.MSG_NOT_EXIST.format(name))
def raise_multiple_return(self, name, length):
raise self.MultipleObjectsReturned(self.MSG_MULTIPLE.format(name, length))
@staticmethod
def create(**kwargs):
instance = AuthBookBackend.create(**kwargs)
return instance
def all(self):
return self.filter()
def prefer(self, s):
self._prefer = s
return self
def using(self, s):
self._using = s
return self
@staticmethod
def none():
return AssetUserQuerySet()
@staticmethod
def _merge_instances(*args):
instances = list(args[0])
keywords = [obj.keyword for obj in instances]
for _instances in args[1:]:
need_merge_instances = [obj for obj in _instances if obj.keyword not in keywords]
need_merge_keywords = [obj.keyword for obj in need_merge_instances]
instances.extend(need_merge_instances)
keywords.extend(need_merge_keywords)
return instances
# -*- coding: utf-8 -*-
#
from .base import BaseBackend
from .external.utils import get_backend
from .internal.asset_user import AssetUserBackend
class AssetUserManager(BaseBackend):
"""
资产用户管理器
"""
external_backend = get_backend()
internal_backend = AssetUserBackend
@classmethod
def filter(cls, username=None, asset=None, **kwargs):
external_instance = list(cls.external_backend.filter(username, asset))
internal_instance = list(cls.internal_backend.filter(username, asset))
instances = cls._merge_instances(external_instance, internal_instance)
return instances
@classmethod
def create(cls, **kwargs):
instance = cls.external_backend.create(**kwargs)
return instance
@classmethod
def _merge_instances(cls, external_instances, internal_instances):
external_instances_keyword_list = [
{'username': instance.username, 'asset': instance.asset}
for instance in external_instances
]
instances = [
instance for instance in internal_instances
if instance.keyword not in external_instances_keyword_list
]
external_instances.extend(instances)
return external_instances
# -*- coding: utf-8 -*-
#
import itertools
from assets.models import SystemUser
from .asset_user import AssetUserBackend
class SystemUserBackend(AssetUserBackend):
model = SystemUser
backend = 'SystemUser'
@classmethod
def filter_queryset_more(cls, queryset):
queryset = cls._distinct_system_users_by_username(queryset)
return queryset
@classmethod
def _distinct_system_users_by_username(cls, system_users):
system_users = sorted(
system_users,
key=lambda su: (su.username, su.priority, su.date_updated),
reverse=True,
)
results = itertools.groupby(system_users, key=lambda su: su.username)
system_users = [next(result[1]) for result in results]
return system_users
...@@ -49,7 +49,7 @@ TEST_WINDOWS_SYSTEM_USER_CONN_TASKS = [ ...@@ -49,7 +49,7 @@ TEST_WINDOWS_SYSTEM_USER_CONN_TASKS = [
} }
] ]
ASSET_USER_CONN_CACHE_KEY = 'ASSET_USER_CONN_{}_{}' ASSET_USER_CONN_CACHE_KEY = 'ASSET_USER_CONN_{}'
TEST_ASSET_USER_CONN_TASKS = [ TEST_ASSET_USER_CONN_TASKS = [
{ {
"name": "ping", "name": "ping",
......
...@@ -104,7 +104,7 @@ class Asset(OrgModelMixin): ...@@ -104,7 +104,7 @@ class Asset(OrgModelMixin):
is_active = models.BooleanField(default=True, verbose_name=_('Is active')) is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
# Auth # Auth
admin_user = models.ForeignKey('assets.AdminUser', on_delete=models.PROTECT, null=True, verbose_name=_("Admin user")) admin_user = models.ForeignKey('assets.AdminUser', on_delete=models.PROTECT, null=True, verbose_name=_("Admin user"), related_name='assets')
# Some information # Some information
public_ip = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('Public IP')) public_ip = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('Public IP'))
...@@ -250,16 +250,11 @@ class Asset(OrgModelMixin): ...@@ -250,16 +250,11 @@ class Asset(OrgModelMixin):
@property @property
def connectivity(self): def connectivity(self):
if not self.is_unixlike(): return self.admin_user.get_connectivity_of(self)
return self.REACHABLE
key = self.CONNECTIVITY_CACHE_KEY.format(str(self.id))
cached = cache.get(key, None)
return cached if cached is not None else self.UNKNOWN
@connectivity.setter @connectivity.setter
def connectivity(self, value): def connectivity(self, value):
key = self.CONNECTIVITY_CACHE_KEY.format(str(self.id)) self.admin_user.set_connectivity_of(self, value)
cache.set(key, value, 3600*2)
def get_auth_info(self): def get_auth_info(self):
if not self.admin_user: if not self.admin_user:
......
...@@ -29,6 +29,9 @@ class AuthBook(AssetUser): ...@@ -29,6 +29,9 @@ class AuthBook(AssetUser):
version = models.IntegerField(default=1, verbose_name=_('Version')) version = models.IntegerField(default=1, verbose_name=_('Version'))
objects = AuthBookManager.from_queryset(AuthBookQuerySet)() objects = AuthBookManager.from_queryset(AuthBookQuerySet)()
backend = "db"
# 用于system user和admin_user的动态设置
_connectivity = None
class Meta: class Meta:
verbose_name = _('AuthBook') verbose_name = _('AuthBook')
...@@ -40,7 +43,8 @@ class AuthBook(AssetUser): ...@@ -40,7 +43,8 @@ class AuthBook(AssetUser):
def _get_pre_obj(self): def _get_pre_obj(self):
pre_obj = self.__class__.objects.filter( pre_obj = self.__class__.objects.filter(
username=self.username, asset=self.asset).latest_version().first() username=self.username, asset=self.asset
).latest_version().first()
return pre_obj return pre_obj
def _remove_pre_obj_latest(self): def _remove_pre_obj_latest(self):
...@@ -63,30 +67,30 @@ class AuthBook(AssetUser): ...@@ -63,30 +67,30 @@ class AuthBook(AssetUser):
@property @property
def _conn_cache_key(self): def _conn_cache_key(self):
return ASSET_USER_CONN_CACHE_KEY.format(self.id, self.asset.id) return ASSET_USER_CONN_CACHE_KEY.format(self.id)
@property @property
def connectivity(self): def connectivity(self):
if self._connectivity:
return self._connectivity
value = cache.get(self._conn_cache_key, self.UNKNOWN) value = cache.get(self._conn_cache_key, self.UNKNOWN)
return value return value
@connectivity.setter @connectivity.setter
def connectivity(self, value): def connectivity(self, value):
_connectivity = self.UNKNOWN cache.set(self._conn_cache_key, value, 3600)
for host in value.get('dark', {}).keys(): @property
if host == self.asset.hostname: def keyword(self):
_connectivity = self.UNREACHABLE return '{}_#_{}'.format(self.username, str(self.asset.id))
for host in value.get('contacted', []):
if host == self.asset.hostname:
_connectivity = self.REACHABLE
cache.set(self._conn_cache_key, _connectivity, 3600) @property
def hostname(self):
return self.asset.hostname
@property @property
def keyword(self): def ip(self):
return {'username': self.username, 'asset': self.asset} return self.asset.ip
def __str__(self): def __str__(self):
return '{}@{}'.format(self.username, self.asset) return '{}@{}'.format(self.username, self.asset)
......
...@@ -6,6 +6,7 @@ from hashlib import md5 ...@@ -6,6 +6,7 @@ from hashlib import md5
import sshpubkeys import sshpubkeys
from django.db import models from django.db import models
from django.core.cache import cache
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.conf import settings from django.conf import settings
...@@ -39,6 +40,8 @@ class AssetUser(OrgModelMixin): ...@@ -39,6 +40,8 @@ class AssetUser(OrgModelMixin):
(REACHABLE, _('Reachable')), (REACHABLE, _('Reachable')),
(UNKNOWN, _("Unknown")), (UNKNOWN, _("Unknown")),
) )
CONNECTIVITY_CACHE_KEY = "CONNECTIVITY_{}"
_prefer = "system_user"
@property @property
def password(self): def password(self):
...@@ -124,10 +127,21 @@ class AssetUser(OrgModelMixin): ...@@ -124,10 +127,21 @@ class AssetUser(OrgModelMixin):
def get_auth(self, asset=None): def get_auth(self, asset=None):
pass pass
def get_connectivity_of(self, asset):
i = self.generate_id_with_asset(asset)
key = self.CONNECTIVITY_CACHE_KEY.format(i)
return cache.get(key)
def set_connectivity_of(self, asset, c):
i = self.generate_id_with_asset(asset)
key = self.CONNECTIVITY_CACHE_KEY.format(i)
cache.set(key, c, 3600)
def load_specific_asset_auth(self, asset): def load_specific_asset_auth(self, asset):
from ..backends.multi import AssetUserManager from ..backends import AssetUserManager
try: try:
other = AssetUserManager.get(username=self.username, asset=asset) manager = AssetUserManager().prefer(self._prefer)
other = manager.get(username=self.username, asset=asset)
except Exception as e: except Exception as e:
logger.error(e, exc_info=True) logger.error(e, exc_info=True)
else: else:
...@@ -172,5 +186,25 @@ class AssetUser(OrgModelMixin): ...@@ -172,5 +186,25 @@ class AssetUser(OrgModelMixin):
'private_key': self.private_key_file, 'private_key': self.private_key_file,
} }
def generate_id_with_asset(self, asset):
id_ = '{}_{}'.format(asset.id, self.id)
id_ = uuid.UUID(md5(id_.encode()).hexdigest())
return id_
def construct_to_authbook(self, asset):
from . import AuthBook
fields = [
'name', 'username', 'comment', 'org_id',
'_password', '_private_key', '_public_key',
'date_created', 'date_updated', 'created_by'
]
id_ = self.generate_id_with_asset(asset)
obj = AuthBook(id=id_, asset=asset, version=0, is_latest=True)
obj._connectivity = self.get_connectivity_of(asset)
for field in fields:
value = getattr(self, field)
setattr(obj, field, value)
return obj
class Meta: class Meta:
abstract = True abstract = True
...@@ -32,6 +32,7 @@ class AdminUser(AssetUser): ...@@ -32,6 +32,7 @@ class AdminUser(AssetUser):
become_user = models.CharField(default='root', max_length=64) become_user = models.CharField(default='root', max_length=64)
_become_pass = models.CharField(default='', max_length=128) _become_pass = models.CharField(default='', max_length=128)
CONNECTIVE_CACHE_KEY = '_JMS_ADMIN_USER_CONNECTIVE_{}' CONNECTIVE_CACHE_KEY = '_JMS_ADMIN_USER_CONNECTIVE_{}'
_prefer = "admin_user"
def __str__(self): def __str__(self):
return self.name return self.name
...@@ -61,7 +62,7 @@ class AdminUser(AssetUser): ...@@ -61,7 +62,7 @@ class AdminUser(AssetUser):
return info return info
def get_related_assets(self): def get_related_assets(self):
assets = self.asset_set.all() assets = self.assets.all()
return assets return assets
@property @property
...@@ -174,17 +175,20 @@ class SystemUser(AssetUser): ...@@ -174,17 +175,20 @@ class SystemUser(AssetUser):
data = self.connectivity data = self.connectivity
unreachable = data['unreachable'] unreachable = data['unreachable']
reachable = data['reachable'] reachable = data['reachable']
assets = {asset.hostname: asset for asset in self.assets.all()}
for host in value.get('dark', {}).keys(): for host in value.get('dark', {}).keys():
if host not in unreachable: if host not in unreachable:
unreachable.append(host) unreachable.append(host)
if host in reachable: if host in reachable:
reachable.remove(host) reachable.remove(host)
self.set_connectivity_of(assets.get(host), self.UNREACHABLE)
for host in value.get('contacted'): for host in value.get('contacted'):
if host not in reachable: if host not in reachable:
reachable.append(host) reachable.append(host)
if host in unreachable: if host in unreachable:
unreachable.remove(host) unreachable.remove(host)
self.set_connectivity_of(assets.get(host), self.REACHABLE)
cache_key = self.CONNECTIVE_CACHE_KEY.format(str(self.id)) cache_key = self.CONNECTIVE_CACHE_KEY.format(str(self.id))
cache.set(cache_key, data, 3600) cache.set(cache_key, data, 3600)
......
...@@ -4,49 +4,70 @@ ...@@ -4,49 +4,70 @@
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from rest_framework import serializers from rest_framework import serializers
from ..models import AuthBook from ..models import AuthBook, Asset
from ..backends.multi import AssetUserManager from ..backends import AssetUserManager
from common.utils import validate_ssh_private_key
from common.mixins import BulkSerializerMixin
from common.serializers import AdaptedBulkListSerializer
__all__ = [ __all__ = [
'AssetUserSerializer', 'AssetUserAuthInfoSerializer', 'AssetUserSerializer', 'AssetUserAuthInfoSerializer',
'AssetUserExportSerializer', 'AssetUserPushSerializer',
] ]
class AssetUserSerializer(serializers.ModelSerializer): class BasicAssetSerializer(serializers.ModelSerializer):
class Meta:
model = Asset
fields = ['hostname', 'ip']
class AssetUserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
hostname = serializers.CharField(read_only=True, label=_("Hostname"))
ip = serializers.CharField(read_only=True, label=_("IP"))
connectivity = serializers.CharField(read_only=True, label=_("Connectivity"))
password = serializers.CharField( password = serializers.CharField(
max_length=256, allow_blank=True, allow_null=True, write_only=True, max_length=256, allow_blank=True, allow_null=True, write_only=True,
required=False, help_text=_('Password') required=False, label=_('Password')
) )
public_key = serializers.CharField( public_key = serializers.CharField(
max_length=4096, allow_blank=True, allow_null=True, write_only=True, max_length=4096, allow_blank=True, allow_null=True, write_only=True,
required=False, help_text=_('Public key') required=False, label=_('Public key')
) )
private_key = serializers.CharField( private_key = serializers.CharField(
max_length=4096, allow_blank=True, allow_null=True, write_only=True, max_length=4096, allow_blank=True, allow_null=True, write_only=True,
required=False, help_text=_('Private key') required=False, label=_('Private key')
) )
backend = serializers.CharField(read_only=True, label=_("Backend"))
class Meta: class Meta:
model = AuthBook model = AuthBook
list_serializer_class = AdaptedBulkListSerializer
read_only_fields = ( read_only_fields = (
'date_created', 'date_updated', 'created_by', 'date_created', 'date_updated', 'created_by',
'is_latest', 'version', 'connectivity', 'is_latest', 'version', 'connectivity',
) )
fields = '__all__' fields = [
"id", "hostname", "ip", "username", "password", "asset", "version",
"is_latest", "connectivity", "backend", "org_id",
"date_created", "date_updated", "private_key", "public_key",
]
extra_kwargs = { extra_kwargs = {
'username': {'required': True} 'username': {'required': True},
} }
def get_field_names(self, declared_fields, info): def validate_private_key(self, key):
fields = super().get_field_names(declared_fields, info) password = self.initial_data.get("password")
fields = [f for f in fields if not f.startswith('_') and f != 'id'] valid = validate_ssh_private_key(key, password)
fields.extend(['connectivity']) if not valid:
return fields raise serializers.ValidationError(_("private key invalid"))
return key
def create(self, validated_data): def create(self, validated_data):
kwargs = { kwargs = {
'name': validated_data.get('name'), 'name': validated_data.get('username'),
'username': validated_data.get('username'), 'username': validated_data.get('username'),
'asset': validated_data.get('asset'), 'asset': validated_data.get('asset'),
'comment': validated_data.get('comment', ''), 'comment': validated_data.get('comment', ''),
...@@ -59,7 +80,33 @@ class AssetUserSerializer(serializers.ModelSerializer): ...@@ -59,7 +80,33 @@ class AssetUserSerializer(serializers.ModelSerializer):
return instance return instance
class AssetUserExportSerializer(AssetUserSerializer):
password = serializers.CharField(
max_length=256, allow_blank=True, allow_null=True,
required=False, label=_('Password')
)
public_key = serializers.CharField(
max_length=4096, allow_blank=True, allow_null=True,
required=False, label=_('Public key')
)
private_key = serializers.CharField(
max_length=4096, allow_blank=True, allow_null=True,
required=False, label=_('Private key')
)
class AssetUserAuthInfoSerializer(serializers.ModelSerializer): class AssetUserAuthInfoSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = AuthBook model = AuthBook
fields = ['password', 'private_key', 'public_key'] fields = ['password', 'private_key', 'public_key']
class AssetUserPushSerializer(serializers.Serializer):
asset = serializers.PrimaryKeyRelatedField(queryset=Asset.objects.all(), label=_("Asset"))
username = serializers.CharField(max_length=1024)
def create(self, validated_data):
pass
def update(self, instance, validated_data):
pass
...@@ -563,11 +563,17 @@ def get_test_asset_user_connectivity_tasks(asset): ...@@ -563,11 +563,17 @@ def get_test_asset_user_connectivity_tasks(asset):
@shared_task @shared_task
def set_asset_user_connectivity_info(asset_user, result): def set_asset_user_connectivity_info(asset_user, result):
summary = result[1] summary = result[1]
asset_user.connectivity = summary if summary.get('contacted'):
connectivity = 1
elif summary.get("dark"):
connectivity = 0
else:
connectivity = 3
asset_user.connectivity = connectivity
@shared_task @shared_task
def test_asset_user_connectivity_util(asset_user, task_name): def test_asset_user_connectivity_util(asset_user, task_name, run_as_admin=False):
""" """
:param asset_user: <AuthBook>对象 :param asset_user: <AuthBook>对象
:param task_name: :param task_name:
...@@ -582,23 +588,29 @@ def test_asset_user_connectivity_util(asset_user, task_name): ...@@ -582,23 +588,29 @@ def test_asset_user_connectivity_util(asset_user, task_name):
if not tasks: if not tasks:
return return
task, created = update_or_create_ansible_task( args = (task_name,)
task_name, hosts=[asset_user.asset], tasks=tasks, pattern='all', kwargs = {
options=const.TASK_OPTIONS, 'hosts': [asset_user.asset], 'tasks': tasks,
run_as=asset_user.username, created_by=asset_user.org_id 'pattern': 'all', 'options': const.TASK_OPTIONS,
) 'created_by': asset_user.org_id,
}
if run_as_admin:
kwargs["run_as_admin"] = True
else:
kwargs["run_as"] = asset_user.username
task, created = update_or_create_ansible_task(*args, **kwargs)
result = task.run() result = task.run()
set_asset_user_connectivity_info(asset_user, result) set_asset_user_connectivity_info(asset_user, result)
@shared_task @shared_task
def test_asset_users_connectivity_manual(asset_users): def test_asset_users_connectivity_manual(asset_users, run_as_admin=False):
""" """
:param asset_users: <AuthBook>对象 :param asset_users: <AuthBook>对象
""" """
for asset_user in asset_users: for asset_user in asset_users:
task_name = _("Test asset user connectivity: {}").format(asset_user) task_name = _("Test asset user connectivity: {}").format(asset_user)
test_asset_user_connectivity_util(asset_user, task_name) test_asset_user_connectivity_util(asset_user, task_name, run_as_admin=run_as_admin)
# @shared_task # @shared_task
......
{% extends '_modal.html' %}
{% load i18n %}
{% block modal_id %}asset_user_auth_modal{% endblock %}
{% block modal_title%}{% trans "Update asset user auth" %}{% endblock %}
{% block modal_body %}
<form class="form-horizontal" role="form" onkeydown="if(event.keyCode==13){ $('#btn_asset_user_auth_modal_confirm').trigger('click'); return false;}">
{% csrf_token %}
<div class="form-group">
<label class="col-sm-2 control-label">{% trans "Hostname" %}</label>
<div class="col-sm-10">
<p class="form-control-static" id="id_hostname_p"></p>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">{% trans "Username" %}</label>
<div class="col-sm-10">
<p class="form-control-static" id="id_username_p"></p>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">{% trans "Password" %}</label>
<div class="col-sm-10">
<input class="form-control" id="id_password" type="password" name="password" placeholder="{% trans 'Please input password' %}"/>
</div>
</div>
</form>
{% endblock %}
{% block modal_confirm_id %}btn_asset_user_auth_modal_confirm{% endblock %}
{% extends '_modal.html' %}
{% load i18n %}
{% block modal_id %}asset_user_auth_update_modal{% endblock %}
{% block modal_title%}{% trans "Update asset user auth" %}{% endblock %}
{% block modal_body %}
<form class="form-horizontal" role="form" onkeydown="if(event.keyCode==13){ $('#btn_asset_user_auth_update_modal_confirm').trigger('click'); return false;}">
{% csrf_token %}
<div class="form-group">
<label class="col-sm-2 control-label">{% trans "Hostname" %}</label>
<div class="col-sm-10">
<p class="form-control-static" id="id_hostname_p"></p>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">{% trans "Username" %}</label>
<div class="col-sm-10">
<p class="form-control-static" id="id_username_p"></p>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">{% trans "Password" %}</label>
<div class="col-sm-10">
<input class="form-control" id="id_password_auth" type="password" name="password" placeholder="{% trans 'Please input password' %}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">{% trans "Private key" %}</label>
<div class="col-sm-10">
<div class="row bootstrap3-multi-input">
<div class="col-xs-12">
<input id="id_private_key" type="file" name="private_key"/>
</div>
</div>
</div>
</div>
</form>
<script>
var authHostname, authUsername, authAssetId = null;
$(document).ready(function () {
}).on("show.bs.modal", "#asset_user_auth_update_modal", function () {
$('#id_hostname_p').html(authHostname);
$('#id_username_p').html(authUsername);
$('#id_password_auth').parent().removeClass('has-error');
$('#id_password_auth').val('');
}).on('click', '#btn_asset_user_auth_update_modal_confirm', function(){
var password = $('#id_password_auth').val();
var privateKey = $('#id_private_key').prop('files');
var hasPrivateKey = privateKey.length > 0;
if (!password && !hasPrivateKey) {
$('#id_password_auth').parent().addClass('has-error');
return
}
var data = {
'asset': authAssetId,
'username': authUsername
};
if (password) {
data["password"] = password
}
var props = {
data: data,
url: "{% url 'api-assets:asset-user-list' %}",
form: $("form"),
method: 'POST',
success: function () {
toastr.success("{% trans 'Update successfully!' %}");
$("#asset_user_auth_update_modal").modal('hide');
}
};
if (hasPrivateKey) {
var reader = new FileReader();//新建一个FileReader
reader.readAsText(privateKey[0], "UTF-8");//读取文件
reader.onload = function(evt){ //读取完文件之后会回来这里
data["private_key"] = evt.target.result;
formSubmit(props);
}
}
if (!hasPrivateKey) {
formSubmit(props);
}
})
</script>
{% endblock %}
{% block modal_confirm_id %}btn_asset_user_auth_update_modal_confirm{% endblock %}
...@@ -10,17 +10,7 @@ ...@@ -10,17 +10,7 @@
} }
</style> </style>
<form class="form-horizontal" action="" style="padding-top: 20px"> <form class="form-horizontal" action="" style="padding-top: 20px">
<div class="form-group mfa-field"> <div class="auth-field">
<label for="mfa" class="col-sm-2 control-label">{% trans 'MFA' %}</label>
<div class="col-sm-8">
<input type="text" id="mfa" class="form-control input-sm" name="mfa">
<span id="mfa_error" class="help-block">{% trans "Need otp auth for view auth" %}</span>
</div>
<div class="col-sm-2">
<a class="btn btn-primary btn-sm btn-mfa">{% trans "Confirm" %}</a>
</div>
</div>
<div hidden class="auth-field">
<div class="form-group"> <div class="form-group">
<label for="" class="col-sm-2 control-label">{% trans 'Hostname' %}</label> <label for="" class="col-sm-2 control-label">{% trans 'Hostname' %}</label>
<div class="col-sm-8"> <div class="col-sm-8">
...@@ -45,13 +35,15 @@ ...@@ -45,13 +35,15 @@
</div> </div>
</div> </div>
</form> </form>
{% include 'authentication/_mfa_confirm_modal.html' %}
<script src="{% static "js/plugins/clipboard/clipboard.min.js" %}"></script> <script src="{% static "js/plugins/clipboard/clipboard.min.js" %}"></script>
<script> <script>
var showPassword = false; var showPassword = false;
var lastMFATime = "{{ request.session.OTP_LAST_VERIFY_TIME }}"; var lastMFATime = "{{ request.session.OTP_LAST_VERIFY_TIME }}";
var asset_id = ""; var authAssetId = "";
var host = ""; var authHostname = "";
var username = ""; var authUsername = "";
var mfaFor = "";
function initClipboard() { function initClipboard() {
var clipboard = new Clipboard('.btn-copy-password', { var clipboard = new Clipboard('.btn-copy-password', {
...@@ -65,12 +57,12 @@ function initClipboard() { ...@@ -65,12 +57,12 @@ function initClipboard() {
} }
function showAuth() { function showAuth() {
$(".mfa-field").hide(); var url = "{% url "api-assets:asset-user-auth-info" %}?asset_id=" + authAssetId + "&username=" + authUsername;
$(".auth-field").show(); if (prefer) {
url = setUrlParam(url, 'prefer', prefer)
var url = "{% url "api-assets:asset-user-auth-info" %}?asset_id=" + asset_id + "&username=" + username; }
$("#id_username_view").html(username); $("#id_username_view").html(authUsername);
$("#id_hostname_view").html(host); $("#id_hostname_view").html(authHostname);
var success = function (data) { var success = function (data) {
var password = data.password; var password = data.password;
$("#id_password_view").val(password); $("#id_password_view").val(password);
...@@ -88,11 +80,6 @@ function showAuth() { ...@@ -88,11 +80,6 @@ function showAuth() {
}) })
} }
function showMFA() {
$(".mfa-field").show();
$(".auth-field").hide();
}
$(document).ready(function () { $(document).ready(function () {
initClipboard(); initClipboard();
}).on("click", ".btn-show-password", function () { }).on("click", ".btn-show-password", function () {
...@@ -108,30 +95,21 @@ $(document).ready(function () { ...@@ -108,30 +95,21 @@ $(document).ready(function () {
lastMFATime = 0 lastMFATime = 0
} }
var nowTime = now.getTime() / 1000; var nowTime = now.getTime() / 1000;
if (nowTime - lastMFATime < 60*10 ) { if (nowTime - lastMFATime > 60*10 ) {
setTimeout(function () {
$("#asset_user_auth_view").modal("hide");
}, 100);
mfaFor = "viewAuth";
$("#mfa_auth_confirm").modal("show");
} else {
showAuth(); showAuth();
} }
}).on("click", ".btn-mfa", function () { }).on("success", '#mfa_auth_confirm', function () {
var url = "{% url 'api-auth:user-otp-verify' %}"; if (mfaFor !== "viewAuth") {
var data = { return
code: $("#mfa").val() }
}; $("#asset_user_auth_view").modal("show");
var success = function () { showAuth();
var now = new Date();
lastMFATime = now.getTime() / 1000;
showAuth()
};
var error = function () {
$("#mfa_error").addClass("text-danger").html("Code error");
};
APIUpdateAttr({
url: url,
method: "POST",
body: JSON.stringify(data),
success: success,
flash_message: false,
error: error
})
}) })
</script> </script>
{% endblock %} {% endblock %}
......
{% load i18n %}
<style>
.btn-group>.btn+.dropdown-toggle {
padding-right: 4px;
padding-left: 4px;
}
</style>
<table class="table table-striped table-bordered table-hover" id="asset_user_list_table" style="width: 100%">
<thead>
<tr>
<th class="text-center">
<input type="checkbox" id="check_all" class="ipt_check_all" >
</th>
<th class="text-center">{% trans 'Hostname' %}</th>
<th class="text-center">{% trans 'IP' %}</th>
<th class="text-center">{% trans 'Username' %}</th>
<th class="text-center">{% trans 'Version' %}</th>
<th class="text-center">{% trans 'Connectivity'%}</th>
<th class="text-center">{% trans 'Datetime' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
{% include 'assets/_asset_user_auth_update_modal.html' %}
{% include 'assets/_asset_user_auth_view_modal.html' %}
<script>
var assetUserListUrl = "{% url "api-assets:asset-user-list" %}";
var assetUserTable;
var needPush = false;
var prefer = null;
function initAssetUserTable() {
var options = {
ele: $('#asset_user_list_table'),
toggle: true,
columnDefs: [
{
targets: 5, createdCell: function (td, cellData) {
if (cellData == 1) {
$(td).html('<i class="fa fa-circle text-navy"></i>')
} else if (cellData == 0) {
$(td).html('<i class="fa fa-circle text-danger"></i>')
} else {
$(td).html('<i class="fa fa-circle text-warning"></i>')
}
}
},
{
targets: 6, createdCell: function (td, cellData) {
var date = new Date(cellData);
$(td).html(date.toLocaleString());
},
},
{
targets: 7, createdCell: function (td, cellData, rowData) {
var view_btn = '<button class="btn btn-xs btn-primary m-l-xs btn-view-auth" data-user="username123" data-hostname="hostname123" data-asset="asset123">{% trans "View" %}</button>'
var update_btn = '<li><a class="btn-update-auth" data-user="username123" data-hostname="hostname123" data-asset="asset123">{% trans 'Update' %}</a></li>';
var test_btn = '<li><a class="btn-test-auth" data-user="username123" data-hostname="hostname123" data-asset="asset123">{% trans 'Test' %}</a></li>';
var push_btn = '<li><a class="btn-push-auth" data-user="username123" data-hostname="hostname123" data-asset="asset123">{% trans 'Push' %}</a></li>';
if (needPush) {
test_btn += push_btn;
}
var actions = '<div class="btn-group">' + view_btn +
' <button data-toggle="dropdown" class="btn btn-primary btn-xs dropdown-toggle">' +
' <span class="caret"></span>' +
' </button>' +
' <ul class="dropdown-menu">' +
update_btn + test_btn +
' </ul>' +
' </div>';
actions = actions.replaceAll("username123", rowData.username)
.replaceAll("hostname123", rowData.hostname)
.replaceAll("asset123", rowData.asset);
$(td).html(actions);
},
width: '70px'
}
],
ajax_url: assetUserListUrl,
columns: [
{data: "id"}, {data: "hostname"}, {data: "ip"},
{data: "username", orderable: false}, {data: "version", orderable: false},
{data: "connectivity", orderable: false},
{data: "date_created", orderable: false},
{data: "asset", orderable: false}
],
op_html: $('#actions').html()
};
table = jumpserver.initServerSideDataTable(options);
return table
}
$(document).ready(function(){
})
.on('click', '.btn-view-auth', function () {
authAssetId = $(this).data("asset") ;
authHostname = $(this).data("hostname");
authUsername = $(this).data('user');
$("#asset_user_auth_view").modal('show');
})
.on('click', '.btn-update-auth', function() {
authUsername = $(this).data("user") ;
authHostname = $(this).data("hostname");
authAssetId = $(this).data("asset");
$("#asset_user_auth_update_modal").modal('show');
})
.on("click", '.btn-test-auth', function () {
authUsername = $(this).data("user") ;
authAssetId = $(this).data("asset");
var the_url = "{% url 'api-assets:asset-user-connective' %}" + "?asset_id=" + authAssetId + "&username=" + authUsername;
if (prefer) {
the_url = setUrlParam(the_url, "prefer", prefer)
}
var success = function (data) {
var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
APIUpdateAttr({
url: the_url,
method: 'GET',
success: success,
flash_message: false
});
})
</script>
\ No newline at end of file
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
</ul> </ul>
</div> </div>
<div class="tab-content"> <div class="tab-content">
<div class="col-sm-8" style="padding-left: 0;"> <div class="col-sm-9" style="padding-left: 0;">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span style="float: left">{% trans 'Asset list of ' %} <b>{{ admin_user.name }}</b></span> <span style="float: left">{% trans 'Asset list of ' %} <b>{{ admin_user.name }}</b></span>
...@@ -42,23 +42,11 @@ ...@@ -42,23 +42,11 @@
</div> </div>
</div> </div>
<div class="ibox-content"> <div class="ibox-content">
<table class="table table-striped table-bordered table-hover" id="asset_list_table"> {% include 'assets/_asset_user_list.html' %}
<thead>
<tr>
<th>{% trans 'Hostname' %}</th>
<th>{% trans 'IP' %}</th>
<th>{% trans 'Port' %}</th>
<th>{% trans 'Reachable' %}</th>
<th>{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div> </div>
</div> </div>
</div> </div>
<div class="col-sm-4" style="padding-left: 0;padding-right: 0"> <div class="col-sm-3" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary"> <div class="panel panel-primary">
<div class="panel-heading"> <div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Quick update' %} <i class="fa fa-info-circle"></i> {% trans 'Quick update' %}
...@@ -84,64 +72,14 @@ ...@@ -84,64 +72,14 @@
</div> </div>
</div> </div>
</div> </div>
{% include 'assets/_asset_user_auth_modal.html' %}
{% include 'assets/_asset_user_view_auth_modal.html' %}
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
function initTable() {
var reachable = {{ admin_user.REACHABLE }};
var unreachable = {{ admin_user.UNREACHABLE }};
var options = {
ele: $('#asset_list_table'),
buttons: [],
order: [],
columnDefs: [
{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>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}},
{targets: 3, createdCell: function (td, cellData) {
if (cellData === unreachable) {
$(td).html('<i class="fa fa-times text-danger"></i>')
} else if (cellData === reachable) {
$(td).html('<i class="fa fa-check text-navy"></i>')
} else {
$(td).html('')
}
}},
{targets: 4, createdCell: function (td, cellData, rowData) {
var btn = ' <a class="btn btn-xs btn-primary btn-update-asset-user-auth" data-aid="{{ DEFAULT_PK }}" data-hostname="hostname777">{% trans "Update auth" %}</a>'.replace("{{ DEFAULT_PK }}", cellData).replace("hostname777", rowData.hostname);
var view_btn = ' <a class="btn btn-xs btn-primary btn-view-auth" data-aid="{{ DEFAULT_PK }}" data-hostname="hostname777">{% trans "View auth" %}</a>'.replace("{{ DEFAULT_PK }}", cellData).replace("hostname777", rowData.hostname);
var test_btn = ' <a class="btn btn-xs btn-info btn-test-asset" data-uid="{{ DEFAULT_PK }}" >{% trans "Test" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
btn += view_btn;
btn += test_btn;
$(td).html(btn);
}}
],
ajax_url: '{% url "api-assets:admin-user-assets" pk=admin_user.id %}',
columns: [
{data: "hostname" }, {data: "ip" },
{data: "port" }, {data: "connectivity" }, {data: "id"}],
op_html: $('#actions').html()
};
jumpserver.initServerSideDataTable(options);
}
function initAssetUserAuthModalForm(hostname, username){
$('#id_hostname_p').html(hostname);
$('#id_username_p').html(username);
$('#id_password').parent().removeClass('has-error');
$('#id_password').val('');
}
var assetId ;
$(document).ready(function () { $(document).ready(function () {
initTable(); assetUserListUrl = setUrlParam(assetUserListUrl, "admin_user_id", "{{ admin_user.id }}");
prefer = "admin_user";
initAssetUserTable();
}) })
.on('click', '.btn-test-asset', function () { .on('click', '.btn-test-asset', function () {
var asset_id = $(this).data('uid'); var asset_id = $(this).data('uid');
...@@ -173,37 +111,10 @@ $(document).ready(function () { ...@@ -173,37 +111,10 @@ $(document).ready(function () {
}); });
}) })
.on('click', '.btn-update-asset-user-auth', function() { .on('click', '.btn-update-asset-user-auth', function() {
assetId = $(this).data('aid'); asset_id = $(this).data('aid');
var hostname = $(this).data('hostname'); hostname = $(this).data('hostname');
var username = '{{ admin_user.username }}'; username = '{{ admin_user.username }}';
initAssetUserAuthModalForm(hostname, username); $("#asset_user_auth_update_modal").modal();
$("#asset_user_auth_modal").modal();
})
.on('click', '#btn_asset_user_auth_modal_confirm', function(){
var password = $('#id_password').val();
if (password){
var data = {
'name': "{{ admin_user.username }}",
'asset': assetId,
'username': "{{ admin_user.username }}",
'password': password
};
formSubmit({
data: data,
url: "{% url 'api-assets:asset-user-list' %}",
method: 'POST',
success: function () {
toastr.success("{% trans 'Update successfully!' %}");
},
error: function () {
toastr.error("{% trans 'Update failed!' %}");
}
});
$("#asset_user_auth_modal").modal('hide');
}
else{
$('#id_password').parent().addClass('has-error');
}
}) })
.on("click", ".btn-view-auth", function (evt) { .on("click", ".btn-view-auth", function (evt) {
asset_id = $(this).data("aid") ; asset_id = $(this).data("aid") ;
......
...@@ -37,20 +37,7 @@ ...@@ -37,20 +37,7 @@
</div> </div>
</div> </div>
<div class="ibox-content"> <div class="ibox-content">
<table class="table table-hover" id="asset_user_list"> {% include 'assets/_asset_user_list.html' %}
<thead>
<tr>
<th class="text-center"><input type="checkbox" class="ipt_check_all"></th>
<th class="text-center">{% trans 'Username' %}</th>
<th class="text-center">{% trans 'Password version' %}</th>
<th class="text-center">{% trans 'Reachable' %}</th>
<th class="text-center">{% trans 'Date updated' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div> </div>
</div> </div>
</div> </div>
...@@ -82,110 +69,14 @@ ...@@ -82,110 +69,14 @@
</div> </div>
</div> </div>
</div> </div>
{% include 'assets/_asset_user_auth_modal.html' %}
{% include 'assets/_asset_user_view_auth_modal.html' %}
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
function initAssetUserAuthModalForm(hostname){
$('#id_hostname_p').html(hostname);
$('#id_username_p').html(username);
$('#id_password').parent().removeClass('has-error');
$('#id_password').val('');
}
function initAssetUserTable() {
var reachable = {{ asset.admin_user.REACHABLE }};
var unreachable = {{ asset.admin_user.UNREACHABLE }};
var options = {
ele: $('#asset_user_list'),
buttons: [],
order: [],
columnDefs: [
{targets: 3, createdCell: function (td, cellData) {
if (cellData === unreachable) {
$(td).html('<i class="fa fa-times text-danger"></i>')
} else if (cellData === reachable) {
$(td).html('<i class="fa fa-check text-navy"></i>')
} else {
$(td).html('')
}
}},
{targets: 4, createdCell: function (td, cellData) {
$(td).html(cellData.slice(0, -6));
}},
{targets: 5, createdCell: function (td, cellData) {
var btn = '<a class="btn btn-xs btn-primary btn-update-asset-user-auth" data-username="DEFAULT_USERNAME">{% trans "Update auth" %}</a>'.replace("DEFAULT_USERNAME", cellData);
var view_btn = ' <a class="btn btn-xs btn-primary btn-view-auth" data-username="DEFAULT_USERNAME">{% trans "View auth" %}</a>'.replace("DEFAULT_USERNAME", cellData);
var test_btn = ' <a class="btn btn-xs btn-info btn-test-connective" data-username="DEFAULT_USERNAME">{% trans "Test" %}</a>'.replace("DEFAULT_USERNAME", cellData);
btn += view_btn;
{% if asset.is_support_ansible %}
btn += test_btn;
{% endif %}
$(td).html(btn);
}}
],
ajax_url: '{% url "api-assets:asset-user-list" %}' + '?asset_id={{ asset.id }}',
columns: [
{data: function (){return ''}}, {data: "username" },
{data: "version"}, {data: "connectivity"}, {data: "date_updated"},
{data: "username", orderable: false}
],
op_html: $('#actions').html()
};
jumpserver.initDataTable(options);
}
var username;
$(document).ready(function () { $(document).ready(function () {
initAssetUserTable(); assetUserListUrl = setUrlParam(assetUserListUrl, "asset_id", "{{ asset.id }}");
}) initAssetUserTable()
.on('click', '.btn-update-asset-user-auth', function() {
username = $(this).data('username');
var hostname = "{{ asset.hostname }}";
initAssetUserAuthModalForm(hostname, username);
$("#asset_user_auth_modal").modal();
})
.on('click', '#btn_asset_user_auth_modal_confirm', function(){
var password = $('#id_password').val();
if (password){
var data = {
'name': username,
'asset': "{{ asset.id }}",
'username': username,
'password': password
};
formSubmit({
data: data,
url: "{% url 'api-assets:asset-user-list' %}",
method: 'POST',
success: function () {
toastr.success("{% trans 'Update successfully!' %}");
},
error: function () {
toastr.error("{% trans 'Update failed!' %}");
}
});
$("#asset_user_auth_modal").modal('hide');
}
else{
$('#id_password').parent().addClass('has-error');
}
})
.on('click', '.btn-test-connective', function () {
var username = $(this).data('username');
var the_url = "{% url 'api-assets:asset-user-connective' %}" + "?asset_id={{ asset.id }}" + "&username=" + username;
var success = function (data) {
var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
APIUpdateAttr({
url: the_url,
method: 'GET',
success: success,
flash_message: false
});
}) })
.on('click', '#btn-bulk-test-connective', function () { .on('click', '#btn-bulk-test-connective', function () {
var the_url = "{% url 'api-assets:asset-user-connective' %}" + "?asset_id={{ asset.id }}"; var the_url = "{% url 'api-assets:asset-user-connective' %}" + "?asset_id={{ asset.id }}";
var success = function (data) { var success = function (data) {
...@@ -200,11 +91,5 @@ $(document).ready(function () { ...@@ -200,11 +91,5 @@ $(document).ready(function () {
flash_message: false flash_message: false
}); });
}) })
.on("click", ".btn-view-auth", function (evt) {
asset_id = "{{ asset.id }}" ;
host = "{{ asset.hostname }}";
username = $(this).data("username");
$("#asset_user_auth_view").modal();
})
</script> </script>
{% endblock %} {% endblock %}
\ No newline at end of file
...@@ -202,7 +202,7 @@ $(document).ready(function () { ...@@ -202,7 +202,7 @@ $(document).ready(function () {
$(this).parent().parent().find(".protocol-port").val(port); $(this).parent().parent().find(".protocol-port").val(port);
}) })
</script> </script>
{% block form_submit %} {% block form_submit %}
<script> <script>
$(document).ready(function () { $(document).ready(function () {
}) })
...@@ -245,5 +245,5 @@ $(document).ready(function () { ...@@ -245,5 +245,5 @@ $(document).ready(function () {
formSubmit(props); formSubmit(props);
}) })
</script> </script>
{% endblock %} {% endblock %}
{% endblock %} {% endblock %}
\ No newline at end of file
...@@ -10,9 +10,9 @@ ...@@ -10,9 +10,9 @@
{% block form_submit %} {% block form_submit %}
<script> <script>
$(document).ready(function () { $(document).ready(function () {
}) })
.on("submit", "form", function (evt) { .on("submit", "form", function (evt) {
evt.preventDefault(); evt.preventDefault();
var the_url = '{% url 'api-assets:asset-detail' pk=object.id %}'; var the_url = '{% url 'api-assets:asset-detail' pk=object.id %}';
var redirect_to = '{% url "assets:asset-list" %}'; var redirect_to = '{% url "assets:asset-list" %}';
...@@ -35,6 +35,9 @@ ...@@ -35,6 +35,9 @@
return v return v
}); });
data["protocols"] = protocols; data["protocols"] = protocols;
if (typeof data.labels === "string") {
data["labels"] = [data["labels"]];
}
if (typeof data["nodes"] == "string") { if (typeof data["nodes"] == "string") {
data["nodes"] = [data["nodes"]] data["nodes"] = [data["nodes"]]
} }
...@@ -46,6 +49,6 @@ ...@@ -46,6 +49,6 @@
redirect_to: redirect_to redirect_to: redirect_to
}; };
formSubmit(props); formSubmit(props);
}); });
</script> </script>
{% endblock %} {% endblock %}
\ No newline at end of file
...@@ -44,19 +44,7 @@ ...@@ -44,19 +44,7 @@
</div> </div>
</div> </div>
<div class="ibox-content"> <div class="ibox-content">
<table class="table table-hover" id="system_user_list"> {% include 'assets/_asset_user_list.html' %}
<thead>
<tr>
<th>{% trans 'Hostname' %}</th>
<th>{% trans 'IP' %}</th>
<th>{% trans 'Port' %}</th>
<th>{% trans 'Reachable' %}</th>
<th>{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div> </div>
</div> </div>
</div> </div>
...@@ -132,50 +120,9 @@ ...@@ -132,50 +120,9 @@
</div> </div>
</div> </div>
</div> </div>
{% include 'assets/_asset_user_auth_modal.html' %}
{% include 'assets/_asset_user_view_auth_modal.html' %}
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
function initAssetsTable() {
var connectivity = {{ system_user.connectivity | safe }};
var options = {
ele: $('#system_user_list'),
buttons: [],
order: [],
columnDefs: [
{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>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}},
{targets: 3, createdCell: function (td, cellData) {
if (connectivity.unreachable.indexOf(cellData) >= 0) {
$(td).html('<i class="fa fa-times text-danger"></i>')
} else if (connectivity.reachable.indexOf(cellData) >= 0 ) {
$(td).html('<i class="fa fa-check text-navy"></i>')
} else {
$(td).html('')
}
}},
{targets: 4, createdCell: function (td, cellData, rowData) {
var push_btn = '';
{% if system_user.auto_push %}
push_btn = ' <a class="btn btn-xs btn-primary btn-push-asset" data-uid="{{ DEFAULT_PK }}" >{% trans "Push" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
{% endif %}
var test_btn = ' <a class="btn btn-xs btn-info btn-test-asset" data-uid="{{ DEFAULT_PK }}" >{% trans "Test" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
var view_btn = ' <a class="btn btn-xs btn-primary btn-view-auth" data-aid="{{ DEFAULT_PK }}" data-hostname="hostname777">{% trans "View auth" %}</a>'.replace("{{ DEFAULT_PK }}", cellData).replace("hostname777", rowData.hostname);
{#var unbound_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-asset-unbound" data-uid="{{ DEFAULT_PK }}">{% trans "Unbound" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);#}
var update_auth_btn = ' <a class="btn btn-xs btn-primary btn-update-asset-user-auth" data-aid="{{ DEFAULT_PK }}" data-hostname="hostname777">{% trans "Update auth" %}</a>'.replace("{{ DEFAULT_PK }}", cellData).replace("hostname777", rowData.hostname);
$(td).html(update_auth_btn + view_btn + push_btn + test_btn);
}}
],
ajax_url: '{% url "api-assets:system-user-assets" pk=system_user.id %}',
columns: [{data: "hostname" }, {data: "ip" }, {data: "port" }, {data: "hostname" }, {data: "id"}],
op_html: $('#actions').html()
};
jumpserver.initServerSideDataTable(options);
}
function updateSystemUserNode(nodes) { function updateSystemUserNode(nodes) {
var the_url = "{% url 'api-assets:system-user-detail' pk=system_user.id %}"; var the_url = "{% url 'api-assets:system-user-detail' pk=system_user.id %}";
...@@ -207,15 +154,6 @@ function updateSystemUserNode(nodes) { ...@@ -207,15 +154,6 @@ function updateSystemUserNode(nodes) {
} }
jumpserver.nodes_selected = {}; jumpserver.nodes_selected = {};
function initAssetUserAuthModalForm(hostname, username){
$('#id_hostname_p').html(hostname);
$('#id_username_p').html(username);
$('#id_password').parent().removeClass('has-error');
$('#id_password').val('');
}
var assetId;
$(document).ready(function () { $(document).ready(function () {
$('.select2').select2() $('.select2').select2()
.on('select2:select', function(evt) { .on('select2:select', function(evt) {
...@@ -226,7 +164,10 @@ $(document).ready(function () { ...@@ -226,7 +164,10 @@ $(document).ready(function () {
var data = evt.params.data; var data = evt.params.data;
delete jumpserver.nodes_selected[data.id]; delete jumpserver.nodes_selected[data.id];
}); });
initAssetsTable(); assetUserListUrl = setUrlParam(assetUserListUrl, "system_user_id", "{{ system_user.id }}");
needPush = true;
initAssetUserTable();
}) })
.on('click', '.btn-push', function () { .on('click', '.btn-push', function () {
var the_url = "{% url 'api-assets:system-user-push' pk=system_user.id %}"; var the_url = "{% url 'api-assets:system-user-push' pk=system_user.id %}";
...@@ -289,9 +230,9 @@ $(document).ready(function () { ...@@ -289,9 +230,9 @@ $(document).ready(function () {
}); });
updateSystemUserNode(nodes); updateSystemUserNode(nodes);
}) })
.on('click', '.btn-push-asset', function () { .on('click', '.btn-push-auth', function () {
var $this = $(this); var $this = $(this);
var asset_id = $this.data('uid'); var asset_id = $this.data('asset');
var the_url = "{% url 'api-assets:system-user-push-to-asset' pk=object.id aid=DEFAULT_PK %}"; var the_url = "{% url 'api-assets:system-user-push-to-asset' pk=object.id aid=DEFAULT_PK %}";
the_url = the_url.replace("{{ DEFAULT_PK }}", asset_id); the_url = the_url.replace("{{ DEFAULT_PK }}", asset_id);
var success = function (data) { var success = function (data) {
...@@ -309,64 +250,7 @@ $(document).ready(function () { ...@@ -309,64 +250,7 @@ $(document).ready(function () {
error: error error: error
}) })
}) })
.on('click', '.btn-test-asset', function () {
var $this = $(this);
var asset_id = $this.data('uid');
var the_url = "{% url 'api-assets:system-user-test-to-asset' pk=object.id aid=DEFAULT_PK %}";
the_url = the_url.replace("{{ DEFAULT_PK }}", asset_id);
var success = function (data) {
var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
var error = function (data) {
alert(data)
};
APIUpdateAttr({
url: the_url,
method: 'GET',
success: success,
error: error
})
})
.on('click', '.btn-update-asset-user-auth', function() {
assetId = $(this).data('aid');
var hostname = $(this).data('hostname');
var username = '{{ system_user.username }}';
initAssetUserAuthModalForm(hostname, username);
$("#asset_user_auth_modal").modal();
})
.on('click', '#btn_asset_user_auth_modal_confirm', function(){
var password = $('#id_password').val();
if (password){
var data = {
'name': "{{ system_user.username }}",
'asset': assetId,
'username': "{{ system_user.username }}",
'password': password
};
formSubmit({
data: data,
url: "{% url 'api-assets:asset-user-list' %}",
method: 'POST',
success: function () {
toastr.success("{% trans 'Update successfully!' %}");
},
error: function () {
toastr.error("{% trans 'Update failed!' %}");
}
});
$("#asset_user_auth_modal").modal('hide');
}
else{
$('#id_password').parent().addClass('has-error');
}
})
.on("click", ".btn-view-auth", function (evt) {
asset_id = $(this).data("aid") ;
host = $(this).data("hostname");
username = "{{ system_user.username }}";
$("#asset_user_auth_view").modal();
})
</script> </script>
{% endblock %} {% endblock %}
...@@ -18,6 +18,7 @@ router.register(r'domain', api.DomainViewSet, 'domain') ...@@ -18,6 +18,7 @@ router.register(r'domain', api.DomainViewSet, 'domain')
router.register(r'gateway', api.GatewayViewSet, 'gateway') router.register(r'gateway', api.GatewayViewSet, 'gateway')
router.register(r'cmd-filter', api.CommandFilterViewSet, 'cmd-filter') router.register(r'cmd-filter', api.CommandFilterViewSet, 'cmd-filter')
router.register(r'asset-user', api.AssetUserViewSet, 'asset-user') router.register(r'asset-user', api.AssetUserViewSet, 'asset-user')
router.register(r'asset-user-info', api.AssetUserExportViewSet, 'asset-user-info')
cmd_filter_router = routers.NestedDefaultRouter(router, r'cmd-filter', lookup='filter') cmd_filter_router = routers.NestedDefaultRouter(router, r'cmd-filter', lookup='filter')
cmd_filter_router.register(r'rules', api.CommandFilterRuleViewSet, 'cmd-filter-rule') cmd_filter_router.register(r'rules', api.CommandFilterRuleViewSet, 'cmd-filter-rule')
......
...@@ -99,7 +99,7 @@ class AdminUserAssetsView(PermissionsMixin, SingleObjectMixin, ListView): ...@@ -99,7 +99,7 @@ class AdminUserAssetsView(PermissionsMixin, SingleObjectMixin, ListView):
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
def get_queryset(self): def get_queryset(self):
self.queryset = self.object.asset_set.all() self.queryset = self.object.assets.all()
return self.queryset return self.queryset
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
......
...@@ -27,7 +27,7 @@ from django.forms.formsets import formset_factory ...@@ -27,7 +27,7 @@ from django.forms.formsets import formset_factory
from common.mixins import JSONResponseMixin 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 PermissionsMixin ,IsOrgAdmin from common.permissions import PermissionsMixin, IsOrgAdmin, IsValidUser
from common.const import ( from common.const import (
create_success_msg, update_success_msg, KEY_CACHE_RESOURCES_ID create_success_msg, update_success_msg, KEY_CACHE_RESOURCES_ID
) )
...@@ -74,8 +74,9 @@ class AssetUserListView(PermissionsMixin, DetailView): ...@@ -74,8 +74,9 @@ class AssetUserListView(PermissionsMixin, DetailView):
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
class UserAssetListView(LoginRequiredMixin, TemplateView): class UserAssetListView(PermissionsMixin, TemplateView):
template_name = 'assets/user_asset_list.html' template_name = 'assets/user_asset_list.html'
permission_classes = [IsValidUser]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = { context = {
...@@ -214,10 +215,11 @@ class AssetDeleteView(PermissionsMixin, DeleteView): ...@@ -214,10 +215,11 @@ class AssetDeleteView(PermissionsMixin, DeleteView):
permission_classes = [IsOrgAdmin] permission_classes = [IsOrgAdmin]
class AssetDetailView(LoginRequiredMixin, DetailView): class AssetDetailView(PermissionsMixin, DetailView):
model = Asset model = Asset
context_object_name = 'asset' context_object_name = 'asset'
template_name = 'assets/asset_detail.html' template_name = 'assets/asset_detail.html'
permission_classes = [IsValidUser]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
nodes_remain = Node.objects.exclude(assets=self.object) nodes_remain = Node.objects.exclude(assets=self.object)
...@@ -231,7 +233,9 @@ class AssetDetailView(LoginRequiredMixin, DetailView): ...@@ -231,7 +233,9 @@ class AssetDetailView(LoginRequiredMixin, DetailView):
@method_decorator(csrf_exempt, name='dispatch') @method_decorator(csrf_exempt, name='dispatch')
class AssetExportView(LoginRequiredMixin, View): class AssetExportView(PermissionsMixin, View):
permission_classes = [IsValidUser]
def get(self, request): def get(self, request):
spm = request.GET.get('spm', '') spm = request.GET.get('spm', '')
assets_id_default = [Asset.objects.first().id] if Asset.objects.first() else [] assets_id_default = [Asset.objects.first().id] if Asset.objects.first() else []
......
...@@ -14,12 +14,11 @@ from django.views import View ...@@ -14,12 +14,11 @@ from django.views import View
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.views.generic import ListView from django.views.generic import ListView
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Q from django.db.models import Q
from audits.utils import get_excel_response, write_content_to_excel from audits.utils import get_excel_response, write_content_to_excel
from common.mixins import DatetimeSearchMixin from common.mixins import DatetimeSearchMixin
from common.permissions import PermissionsMixin, IsOrgAdmin, IsAuditor from common.permissions import PermissionsMixin, IsOrgAdmin, IsAuditor, IsValidUser
from orgs.utils import current_org from orgs.utils import current_org
from ops.views import CommandExecutionListView as UserCommandExecutionListView from ops.views import CommandExecutionListView as UserCommandExecutionListView
...@@ -253,7 +252,8 @@ class CommandExecutionListView(UserCommandExecutionListView): ...@@ -253,7 +252,8 @@ class CommandExecutionListView(UserCommandExecutionListView):
@method_decorator(csrf_exempt, name='dispatch') @method_decorator(csrf_exempt, name='dispatch')
class LoginLogExportView(LoginRequiredMixin, View): class LoginLogExportView(PermissionsMixin, View):
permission_classes = [IsValidUser]
def get(self, request): def get(self, request):
fields = [ fields = [
......
{% extends '_modal.html' %}
{% load i18n %}
{% load static %}
{% block modal_id %}mfa_auth_confirm{% endblock %}
{% block modal_title%}{% trans "MFA confirm" %}{% endblock %}
{% block modal_body %}
<style>
.inmodal .modal-body {
background: #fff;
}
</style>
<form class="form-horizontal" action="" style="padding-top: 20px">
<div class="form-group mfa-field">
<label for="mfa" class="col-sm-2 control-label">{% trans 'MFA' %}</label>
<div class="col-sm-8">
<input type="text" id="mfa" class="form-control input-sm" name="mfa">
<span id="mfa_error" class="help-block">{% trans "Need otp auth for view auth" %}</span>
</div>
<div class="col-sm-2">
<a class="btn btn-primary btn-sm btn-mfa">{% trans "Confirm" %}</a>
</div>
</div>
</form>
<script>
var lastMFATime = "{{ request.session.OTP_LAST_VERIFY_TIME }}";
function showAuth() {
$(".mfa-field").hide();
$(".auth-field").show();
var url = "{% url "api-assets:asset-user-auth-info" %}?asset_id=" + asset_id + "&username=" + username;
$("#id_username_view").html(username);
$("#id_hostname_view").html(host);
var success = function (data) {
var password = data.password;
$("#id_password_view").val(password);
};
var error = function() {
var msg = "{% trans 'Get auth info error' %}";
toastr.error(msg)
};
APIUpdateAttr({
url: url,
method: "GET",
success: success,
flash_message: false,
error: error
})
}
var codeError = "{% trans 'Code error' %}";
$(document).ready(function () {
}).on("click", ".btn-mfa", function () {
var url = "{% url 'api-auth:user-otp-verify' %}";
var data = {
code: $("#mfa").val()
};
var success = function () {
var now = new Date();
lastMFATime = now.getTime() / 1000;
$("#mfa_auth_confirm").modal("hide").trigger("success");
};
var error = function () {
$("#mfa_error").addClass("text-danger").html(codeError);
};
APIUpdateAttr({
url: url,
method: "POST",
body: JSON.stringify(data),
success: success,
flash_message: false,
error: error
})
})
</script>
{% endblock %}
{% block modal_button %}
<button data-dismiss="modal" class="btn btn-white close_btn2" type="button">{% trans "Close" %}</button>
{% endblock %}
...@@ -48,7 +48,7 @@ class LogTailApi(generics.RetrieveAPIView): ...@@ -48,7 +48,7 @@ class LogTailApi(generics.RetrieveAPIView):
return line return line
def read_from_file(self): def read_from_file(self):
with open(self.log_path, 'r') as f: with open(self.log_path, 'rt', encoding='utf8') as f:
offset = cache.get(self.mark, 0) offset = cache.get(self.mark, 0)
f.seek(offset) f.seek(offset)
data = f.read(self.buff_size).replace('\n', '\r\n') data = f.read(self.buff_size).replace('\n', '\r\n')
...@@ -79,7 +79,6 @@ class LogTailApi(generics.RetrieveAPIView): ...@@ -79,7 +79,6 @@ class LogTailApi(generics.RetrieveAPIView):
class ResourcesIDCacheApi(APIView): class ResourcesIDCacheApi(APIView):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
spm = str(uuid.uuid4()) spm = str(uuid.uuid4())
resources_id = request.data.get('resources') resources_id = request.data.get('resources')
......
...@@ -358,7 +358,7 @@ EMAIL_USE_SSL = False ...@@ -358,7 +358,7 @@ EMAIL_USE_SSL = False
EMAIL_USE_TLS = False EMAIL_USE_TLS = False
EMAIL_SUBJECT_PREFIX = '[JMS] ' EMAIL_SUBJECT_PREFIX = '[JMS] '
#Email custom content # Email custom content
EMAIL_CUSTOM_USER_CREATED_SUBJECT = '' EMAIL_CUSTOM_USER_CREATED_SUBJECT = ''
EMAIL_CUSTOM_USER_CREATED_HONORIFIC = '' EMAIL_CUSTOM_USER_CREATED_HONORIFIC = ''
EMAIL_CUSTOM_USER_CREATED_BODY = '' EMAIL_CUSTOM_USER_CREATED_BODY = ''
......
...@@ -8,7 +8,6 @@ from django.utils import timezone ...@@ -8,7 +8,6 @@ from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.db.models import Count from django.db.models import Count
from django.shortcuts import redirect from django.shortcuts import redirect
from django.contrib.auth.mixins import LoginRequiredMixin
from rest_framework.response import Response from rest_framework.response import Response
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse from django.http import HttpResponse
...@@ -18,10 +17,12 @@ from users.models import User ...@@ -18,10 +17,12 @@ from users.models import User
from assets.models import Asset from assets.models import Asset
from terminal.models import Session from terminal.models import Session
from orgs.utils import current_org from orgs.utils import current_org
from common.permissions import PermissionsMixin, IsValidUser
class IndexView(LoginRequiredMixin, TemplateView): class IndexView(PermissionsMixin, TemplateView):
template_name = 'index.html' template_name = 'index.html'
permission_classes = [IsValidUser]
session_week = None session_week = None
session_month = None session_month = None
......
...@@ -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-06-14 17:01+0800\n" "POT-Creation-Date: 2019-06-19 10:59+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"
...@@ -76,8 +76,9 @@ msgstr "运行参数" ...@@ -76,8 +76,9 @@ msgstr "运行参数"
#: applications/templates/applications/remote_app_list.html:22 #: applications/templates/applications/remote_app_list.html:22
#: applications/templates/applications/user_remote_app_list.html:18 #: applications/templates/applications/user_remote_app_list.html:18
#: assets/forms/domain.py:15 assets/forms/label.py:13 #: assets/forms/domain.py:15 assets/forms/label.py:13
#: assets/models/asset.py:320 assets/models/authbook.py:27 #: assets/models/asset.py:315 assets/models/authbook.py:27
#: assets/serializers/admin_user.py:23 assets/serializers/system_user.py:28 #: assets/serializers/admin_user.py:23 assets/serializers/asset_user.py:105
#: assets/serializers/system_user.py:28
#: assets/templates/assets/admin_user_list.html:49 #: assets/templates/assets/admin_user_list.html:49
#: assets/templates/assets/domain_detail.html:60 #: assets/templates/assets/domain_detail.html:60
#: assets/templates/assets/domain_list.html:26 #: assets/templates/assets/domain_list.html:26
...@@ -95,7 +96,7 @@ msgstr "运行参数" ...@@ -95,7 +96,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:409 #: xpack/plugins/change_auth_plan/models.py:413
#: 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
...@@ -103,6 +104,7 @@ msgstr "运行参数" ...@@ -103,6 +104,7 @@ msgstr "运行参数"
#: xpack/plugins/cloud/models.py:187 #: xpack/plugins/cloud/models.py:187
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:63 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:63
#: xpack/plugins/orgs/templates/orgs/org_list.html:16 #: xpack/plugins/orgs/templates/orgs/org_list.html:16
#: xpack/plugins/vault/forms.py:13 xpack/plugins/vault/forms.py:15
msgid "Asset" msgid "Asset"
msgstr "资产" msgstr "资产"
...@@ -110,7 +112,7 @@ msgstr "资产" ...@@ -110,7 +112,7 @@ msgstr "资产"
#: applications/templates/applications/remote_app_detail.html:61 #: applications/templates/applications/remote_app_detail.html:61
#: applications/templates/applications/remote_app_list.html:23 #: applications/templates/applications/remote_app_list.html:23
#: applications/templates/applications/user_remote_app_list.html:19 #: applications/templates/applications/user_remote_app_list.html:19
#: assets/models/user.py:247 assets/templates/assets/user_asset_list.html:172 #: assets/models/user.py:251 assets/templates/assets/user_asset_list.html:172
#: 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 #: audits/templates/audits/ftp_log_list.html:72
#: perms/forms/asset_permission.py:52 perms/models/asset_permission.py:39 #: perms/forms/asset_permission.py:52 perms/models/asset_permission.py:39
...@@ -133,7 +135,7 @@ msgstr "系统用户" ...@@ -133,7 +135,7 @@ msgstr "系统用户"
#: applications/templates/applications/remote_app_list.html:20 #: applications/templates/applications/remote_app_list.html:20
#: applications/templates/applications/user_remote_app_list.html:16 #: applications/templates/applications/user_remote_app_list.html:16
#: assets/forms/domain.py:73 assets/forms/user.py:84 assets/forms/user.py:148 #: assets/forms/domain.py:73 assets/forms/user.py:84 assets/forms/user.py:148
#: assets/models/asset.py:72 assets/models/base.py:26 #: assets/models/asset.py:72 assets/models/base.py:27
#: assets/models/cluster.py:18 assets/models/cmd_filter.py:20 #: assets/models/cluster.py:18 assets/models/cmd_filter.py:20
#: assets/models/domain.py:20 assets/models/group.py:20 #: assets/models/domain.py:20 assets/models/group.py:20
#: assets/models/label.py:18 assets/templates/assets/admin_user_detail.html:56 #: assets/models/label.py:18 assets/templates/assets/admin_user_detail.html:56
...@@ -173,7 +175,7 @@ msgstr "系统用户" ...@@ -173,7 +175,7 @@ msgstr "系统用户"
#: users/templates/users/user_profile.html:51 #: users/templates/users/user_profile.html:51
#: users/templates/users/user_pubkey_update.html:53 #: users/templates/users/user_pubkey_update.html:53
#: xpack/plugins/change_auth_plan/forms.py:97 #: xpack/plugins/change_auth_plan/forms.py:97
#: xpack/plugins/change_auth_plan/models.py:58 #: xpack/plugins/change_auth_plan/models.py:61
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:61 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:61
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:12 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:12
#: xpack/plugins/cloud/models.py:49 xpack/plugins/cloud/models.py:119 #: xpack/plugins/cloud/models.py:49 xpack/plugins/cloud/models.py:119
...@@ -204,7 +206,7 @@ msgstr "参数" ...@@ -204,7 +206,7 @@ msgstr "参数"
#: applications/models/remote_app.py:43 #: applications/models/remote_app.py:43
#: applications/templates/applications/remote_app_detail.html:77 #: applications/templates/applications/remote_app_detail.html:77
#: assets/models/asset.py:132 assets/models/base.py:34 #: assets/models/asset.py:132 assets/models/base.py:35
#: assets/models/cluster.py:28 assets/models/cmd_filter.py:25 #: assets/models/cluster.py:28 assets/models/cmd_filter.py:25
#: assets/models/cmd_filter.py:58 assets/models/group.py:21 #: assets/models/cmd_filter.py:58 assets/models/group.py:21
#: assets/templates/assets/admin_user_detail.html:68 #: assets/templates/assets/admin_user_detail.html:68
...@@ -218,7 +220,7 @@ msgstr "参数" ...@@ -218,7 +220,7 @@ msgstr "参数"
#: perms/templates/perms/remote_app_permission_detail.html:90 #: perms/templates/perms/remote_app_permission_detail.html:90
#: users/models/user.py:104 users/serializers/v1.py:72 #: users/models/user.py:104 users/serializers/v1.py:72
#: users/templates/users/user_detail.html:111 #: users/templates/users/user_detail.html:111
#: xpack/plugins/change_auth_plan/models.py:103 #: xpack/plugins/change_auth_plan/models.py:106
#: 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
msgid "Created by" msgid "Created by"
...@@ -256,7 +258,7 @@ msgstr "创建日期" ...@@ -256,7 +258,7 @@ msgstr "创建日期"
#: applications/templates/applications/remote_app_detail.html:81 #: applications/templates/applications/remote_app_detail.html:81
#: applications/templates/applications/remote_app_list.html:24 #: applications/templates/applications/remote_app_list.html:24
#: applications/templates/applications/user_remote_app_list.html:20 #: applications/templates/applications/user_remote_app_list.html:20
#: assets/models/asset.py:134 assets/models/base.py:31 #: assets/models/asset.py:134 assets/models/base.py:32
#: assets/models/cluster.py:29 assets/models/cmd_filter.py:22 #: assets/models/cluster.py:29 assets/models/cmd_filter.py:22
#: assets/models/cmd_filter.py:55 assets/models/domain.py:21 #: assets/models/cmd_filter.py:55 assets/models/domain.py:21
#: assets/models/domain.py:53 assets/models/group.py:23 #: assets/models/domain.py:53 assets/models/group.py:23
...@@ -282,7 +284,7 @@ msgstr "创建日期" ...@@ -282,7 +284,7 @@ msgstr "创建日期"
#: users/templates/users/user_group_detail.html:67 #: users/templates/users/user_group_detail.html:67
#: users/templates/users/user_group_list.html:37 #: users/templates/users/user_group_list.html:37
#: users/templates/users/user_profile.html:134 #: users/templates/users/user_profile.html:134
#: xpack/plugins/change_auth_plan/models.py:99 #: xpack/plugins/change_auth_plan/models.py:102
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:117 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:117
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:19 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:19
#: xpack/plugins/cloud/models.py:54 xpack/plugins/cloud/models.py:125 #: xpack/plugins/cloud/models.py:54 xpack/plugins/cloud/models.py:125
...@@ -339,6 +341,7 @@ msgstr "远程应用" ...@@ -339,6 +341,7 @@ msgstr "远程应用"
#: xpack/plugins/cloud/templates/cloud/account_create_update.html:33 #: xpack/plugins/cloud/templates/cloud/account_create_update.html:33
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:35 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:35
#: xpack/plugins/interface/templates/interface/interface.html:72 #: xpack/plugins/interface/templates/interface/interface.html:72
#: xpack/plugins/vault/templates/vault/vault_create.html:45
msgid "Reset" msgid "Reset"
msgstr "重置" msgstr "重置"
...@@ -365,7 +368,7 @@ msgstr "重置" ...@@ -365,7 +368,7 @@ msgstr "重置"
#: settings/templates/settings/security_setting.html:74 #: settings/templates/settings/security_setting.html:74
#: settings/templates/settings/terminal_setting.html:73 #: settings/templates/settings/terminal_setting.html:73
#: terminal/templates/terminal/command_list.html:103 #: terminal/templates/terminal/command_list.html:103
#: terminal/templates/terminal/session_list.html:126 #: terminal/templates/terminal/session_list.html:127
#: terminal/templates/terminal/terminal_update.html:46 #: terminal/templates/terminal/terminal_update.html:46
#: users/templates/users/_user.html:51 #: users/templates/users/_user.html:51
#: users/templates/users/forgot_password.html:42 #: users/templates/users/forgot_password.html:42
...@@ -376,6 +379,7 @@ msgstr "重置" ...@@ -376,6 +379,7 @@ msgstr "重置"
#: 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:74 #: xpack/plugins/interface/templates/interface/interface.html:74
#: xpack/plugins/vault/templates/vault/vault_create.html:46
msgid "Submit" msgid "Submit"
msgstr "提交" msgstr "提交"
...@@ -407,6 +411,7 @@ msgstr "详情" ...@@ -407,6 +411,7 @@ msgstr "详情"
#: applications/templates/applications/remote_app_detail.html:21 #: applications/templates/applications/remote_app_detail.html:21
#: applications/templates/applications/remote_app_list.html:56 #: applications/templates/applications/remote_app_list.html:56
#: assets/templates/assets/_asset_user_list.html:60
#: assets/templates/assets/admin_user_detail.html:24 #: assets/templates/assets/admin_user_detail.html:24
#: assets/templates/assets/admin_user_list.html:29 #: assets/templates/assets/admin_user_list.html:29
#: assets/templates/assets/admin_user_list.html:112 #: assets/templates/assets/admin_user_list.html:112
...@@ -503,23 +508,21 @@ msgid "Download application loader" ...@@ -503,23 +508,21 @@ msgid "Download application loader"
msgstr "下载应用加载器" msgstr "下载应用加载器"
#: applications/templates/applications/remote_app_list.html:12 #: applications/templates/applications/remote_app_list.html:12
#: applications/views/remote_app.py:47 #: applications/views/remote_app.py:49
msgid "Create RemoteApp" msgid "Create RemoteApp"
msgstr "创建远程应用" msgstr "创建远程应用"
#: applications/templates/applications/remote_app_list.html:25 #: applications/templates/applications/remote_app_list.html:25
#: applications/templates/applications/user_remote_app_list.html:21 #: applications/templates/applications/user_remote_app_list.html:21
#: assets/models/cmd_filter.py:54 #: assets/models/cmd_filter.py:54
#: assets/templates/assets/admin_user_assets.html:52 #: assets/templates/assets/_asset_user_list.html:20
#: assets/templates/assets/admin_user_list.html:54 #: assets/templates/assets/admin_user_list.html:54
#: assets/templates/assets/asset_asset_user_list.html:48
#: assets/templates/assets/asset_list.html:108 #: assets/templates/assets/asset_list.html:108
#: assets/templates/assets/cmd_filter_list.html:28 #: assets/templates/assets/cmd_filter_list.html:28
#: assets/templates/assets/cmd_filter_rule_list.html:63 #: assets/templates/assets/cmd_filter_rule_list.html:63
#: assets/templates/assets/domain_gateway_list.html:73 #: assets/templates/assets/domain_gateway_list.html:73
#: assets/templates/assets/domain_list.html:29 #: assets/templates/assets/domain_list.html:29
#: assets/templates/assets/label_list.html:17 #: assets/templates/assets/label_list.html:17
#: assets/templates/assets/system_user_asset.html:54
#: assets/templates/assets/system_user_list.html:60 #: assets/templates/assets/system_user_list.html:60
#: assets/templates/assets/user_asset_list.html:48 audits/models.py:38 #: assets/templates/assets/user_asset_list.html:48 audits/models.py:38
#: audits/templates/audits/operate_log_list.html:41 #: audits/templates/audits/operate_log_list.html:41
...@@ -552,44 +555,44 @@ msgstr "动作" ...@@ -552,44 +555,44 @@ msgstr "动作"
msgid "Connect" msgid "Connect"
msgstr "连接" msgstr "连接"
#: applications/views/remote_app.py:31 applications/views/remote_app.py:46 #: applications/views/remote_app.py:32 applications/views/remote_app.py:48
#: applications/views/remote_app.py:67 applications/views/remote_app.py:84 #: applications/views/remote_app.py:70 applications/views/remote_app.py:88
#: assets/models/user.py:134 #: assets/models/user.py:135
#: assets/templates/assets/_asset_group_bulk_update_modal.html:11 #: assets/templates/assets/_asset_group_bulk_update_modal.html:11
#: assets/templates/assets/system_user_asset.html:22 #: assets/templates/assets/system_user_asset.html:22
#: 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:30 assets/views/admin_user.py:49
#: assets/views/admin_user.py:63 assets/views/admin_user.py:78 #: assets/views/admin_user.py:66 assets/views/admin_user.py:82
#: assets/views/admin_user.py:102 assets/views/asset.py:52 #: assets/views/admin_user.py:107 assets/views/asset.py:53
#: assets/views/asset.py:68 assets/views/asset.py:125 assets/views/asset.py:167 #: assets/views/asset.py:70 assets/views/asset.py:128 assets/views/asset.py:171
#: assets/views/asset.py:194 assets/views/asset.py:219 #: assets/views/asset.py:199 assets/views/asset.py:225
#: assets/views/cmd_filter.py:30 assets/views/cmd_filter.py:46 #: assets/views/cmd_filter.py:31 assets/views/cmd_filter.py:48
#: assets/views/cmd_filter.py:62 assets/views/cmd_filter.py:78 #: assets/views/cmd_filter.py:65 assets/views/cmd_filter.py:82
#: assets/views/cmd_filter.py:97 assets/views/cmd_filter.py:130 #: assets/views/cmd_filter.py:102 assets/views/cmd_filter.py:136
#: assets/views/cmd_filter.py:163 assets/views/domain.py:29 #: assets/views/cmd_filter.py:170 assets/views/domain.py:30
#: assets/views/domain.py:45 assets/views/domain.py:61 #: assets/views/domain.py:47 assets/views/domain.py:64
#: assets/views/domain.py:74 assets/views/domain.py:98 #: assets/views/domain.py:78 assets/views/domain.py:104
#: assets/views/domain.py:126 assets/views/domain.py:145 #: assets/views/domain.py:133 assets/views/domain.py:153
#: assets/views/label.py:26 assets/views/label.py:43 assets/views/label.py:69 #: assets/views/label.py:27 assets/views/label.py:45 assets/views/label.py:72
#: assets/views/system_user.py:28 assets/views/system_user.py:44 #: assets/views/system_user.py:29 assets/views/system_user.py:46
#: assets/views/system_user.py:60 assets/views/system_user.py:74 #: assets/views/system_user.py:63 assets/views/system_user.py:78
#: templates/_nav.html:19 xpack/plugins/change_auth_plan/models.py:65 #: templates/_nav.html:19 xpack/plugins/change_auth_plan/models.py:68
msgid "Assets" msgid "Assets"
msgstr "资产管理" msgstr "资产管理"
#: applications/views/remote_app.py:32 #: applications/views/remote_app.py:33
msgid "RemoteApp list" msgid "RemoteApp list"
msgstr "远程应用列表" msgstr "远程应用列表"
#: applications/views/remote_app.py:68 #: applications/views/remote_app.py:71
msgid "Update RemoteApp" msgid "Update RemoteApp"
msgstr "更新远程应用" msgstr "更新远程应用"
#: applications/views/remote_app.py:85 #: applications/views/remote_app.py:89
msgid "RemoteApp detail" msgid "RemoteApp detail"
msgstr "远程应用详情" msgstr "远程应用详情"
#: applications/views/remote_app.py:96 #: applications/views/remote_app.py:100
msgid "My RemoteApp" msgid "My RemoteApp"
msgstr "我的远程应用" msgstr "我的远程应用"
...@@ -615,16 +618,16 @@ msgid "Test if the assets under the node are connectable: {}" ...@@ -615,16 +618,16 @@ msgid "Test if the assets under the node are connectable: {}"
msgstr "测试节点下资产是否可连接: {}" msgstr "测试节点下资产是否可连接: {}"
#: assets/forms/asset.py:45 assets/models/asset.py:103 #: assets/forms/asset.py:45 assets/models/asset.py:103
#: assets/models/user.py:133 assets/templates/assets/asset_detail.html:195 #: assets/models/user.py:134 assets/templates/assets/asset_detail.html:195
#: assets/templates/assets/asset_detail.html:203 #: assets/templates/assets/asset_detail.html:203
#: assets/templates/assets/system_user_asset.html:95 #: assets/templates/assets/system_user_asset.html:83
#: perms/models/asset_permission.py:38 #: perms/models/asset_permission.py:38
#: xpack/plugins/change_auth_plan/models.py:69 #: xpack/plugins/change_auth_plan/models.py:72
msgid "Nodes" msgid "Nodes"
msgstr "节点管理" msgstr "节点管理"
#: assets/forms/asset.py:48 assets/forms/asset.py:83 assets/models/asset.py:107 #: assets/forms/asset.py:48 assets/forms/asset.py:83 assets/models/asset.py:107
#: assets/models/cluster.py:19 assets/models/user.py:91 #: assets/models/cluster.py:19 assets/models/user.py:92
#: assets/templates/assets/asset_detail.html:81 templates/_nav.html:24 #: assets/templates/assets/asset_detail.html:81 templates/_nav.html:24
#: xpack/plugins/cloud/models.py:124 #: xpack/plugins/cloud/models.py:124
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:65 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:65
...@@ -700,12 +703,12 @@ msgid "SSH gateway support proxy SSH,RDP,VNC" ...@@ -700,12 +703,12 @@ msgid "SSH gateway support proxy SSH,RDP,VNC"
msgstr "SSH网关,支持代理SSH,RDP和VNC" msgstr "SSH网关,支持代理SSH,RDP和VNC"
#: assets/forms/domain.py:74 assets/forms/user.py:85 assets/forms/user.py:149 #: assets/forms/domain.py:74 assets/forms/user.py:85 assets/forms/user.py:149
#: assets/models/base.py:27 #: assets/models/base.py:28
#: assets/templates/assets/_asset_user_auth_modal.html:15 #: assets/templates/assets/_asset_user_auth_update_modal.html:15
#: assets/templates/assets/_asset_user_view_auth_modal.html:31 #: assets/templates/assets/_asset_user_auth_view_modal.html:21
#: assets/templates/assets/_asset_user_list.html:16
#: assets/templates/assets/admin_user_detail.html:60 #: assets/templates/assets/admin_user_detail.html:60
#: assets/templates/assets/admin_user_list.html:48 #: assets/templates/assets/admin_user_list.html:48
#: assets/templates/assets/asset_asset_user_list.html:44
#: assets/templates/assets/domain_gateway_list.html:71 #: assets/templates/assets/domain_gateway_list.html:71
#: assets/templates/assets/system_user_detail.html:62 #: assets/templates/assets/system_user_detail.html:62
#: assets/templates/assets/system_user_list.html:52 audits/models.py:94 #: assets/templates/assets/system_user_list.html:52 audits/models.py:94
...@@ -721,8 +724,8 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC" ...@@ -721,8 +724,8 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC"
#: users/templates/users/user_list.html:36 #: users/templates/users/user_list.html:36
#: users/templates/users/user_profile.html:47 #: users/templates/users/user_profile.html:47
#: xpack/plugins/change_auth_plan/forms.py:99 #: xpack/plugins/change_auth_plan/forms.py:99
#: xpack/plugins/change_auth_plan/models.py:60 #: xpack/plugins/change_auth_plan/models.py:63
#: xpack/plugins/change_auth_plan/models.py:405 #: xpack/plugins/change_auth_plan/models.py:409
#: 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
...@@ -734,11 +737,11 @@ msgstr "用户名" ...@@ -734,11 +737,11 @@ msgstr "用户名"
msgid "Password or private key passphrase" msgid "Password or private key passphrase"
msgstr "密码或密钥密码" msgstr "密码或密钥密码"
#: assets/forms/user.py:26 assets/models/base.py:28 #: assets/forms/user.py:26 assets/models/base.py:29
#: assets/serializers/admin_user.py:20 assets/serializers/asset_user.py:19 #: assets/serializers/admin_user.py:20 assets/serializers/asset_user.py:33
#: assets/serializers/system_user.py:16 #: assets/serializers/asset_user.py:86 assets/serializers/system_user.py:16
#: assets/templates/assets/_asset_user_auth_modal.html:21 #: assets/templates/assets/_asset_user_auth_update_modal.html:21
#: assets/templates/assets/_asset_user_view_auth_modal.html:37 #: assets/templates/assets/_asset_user_auth_view_modal.html:27
#: authentication/forms.py:13 #: authentication/forms.py:13
#: authentication/templates/authentication/login.html:67 #: authentication/templates/authentication/login.html:67
#: authentication/templates/authentication/new_login.html:93 #: authentication/templates/authentication/new_login.html:93
...@@ -749,12 +752,14 @@ msgstr "密码或密钥密码" ...@@ -749,12 +752,14 @@ msgstr "密码或密钥密码"
#: users/templates/users/user_profile_update.html:40 #: users/templates/users/user_profile_update.html:40
#: 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:93
#: xpack/plugins/change_auth_plan/models.py:260 #: xpack/plugins/change_auth_plan/models.py:264
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:41
#: assets/serializers/asset_user.py:94
#: assets/templates/assets/_asset_user_auth_update_modal.html:27
#: users/models/user.py:90 #: users/models/user.py:90
msgid "Private key" msgid "Private key"
msgstr "ssh私钥" msgstr "ssh私钥"
...@@ -772,7 +777,7 @@ msgid "* Automatic login mode must fill in the username." ...@@ -772,7 +777,7 @@ msgid "* Automatic login mode must fill in the username."
msgstr "自动登录模式,必须填写用户名" msgstr "自动登录模式,必须填写用户名"
#: assets/forms/user.py:151 assets/models/cmd_filter.py:31 #: assets/forms/user.py:151 assets/models/cmd_filter.py:31
#: assets/models/user.py:141 assets/templates/assets/_system_user.html:66 #: assets/models/user.py:142 assets/templates/assets/_system_user.html:66
#: assets/templates/assets/system_user_detail.html:165 #: assets/templates/assets/system_user_detail.html:165
msgid "Command filter" msgid "Command filter"
msgstr "命令过滤器" msgstr "命令过滤器"
...@@ -800,21 +805,20 @@ msgid "Use comma split multi command, ex: /bin/whoami,/bin/ifconfig" ...@@ -800,21 +805,20 @@ msgid "Use comma split multi command, ex: /bin/whoami,/bin/ifconfig"
msgstr "使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig" msgstr "使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig"
#: assets/models/asset.py:73 assets/models/asset.py:98 #: assets/models/asset.py:73 assets/models/asset.py:98
#: assets/models/domain.py:50 assets/templates/assets/admin_user_assets.html:50 #: assets/models/domain.py:50
#: assets/templates/assets/domain_gateway_list.html:69 #: assets/templates/assets/domain_gateway_list.html:69
#: assets/templates/assets/system_user_asset.html:52
#: assets/templates/assets/user_asset_list.html:168 #: assets/templates/assets/user_asset_list.html:168
#: settings/templates/settings/replay_storage_create.html:59 #: settings/templates/settings/replay_storage_create.html:59
msgid "Port" msgid "Port"
msgstr "端口" msgstr "端口"
#: assets/models/asset.py:93 assets/models/domain.py:49 #: assets/models/asset.py:93 assets/models/domain.py:49
#: assets/serializers/asset_user.py:28
#: assets/templates/assets/_asset_list_modal.html:46 #: assets/templates/assets/_asset_list_modal.html:46
#: assets/templates/assets/admin_user_assets.html:49 #: assets/templates/assets/_asset_user_list.html:15
#: assets/templates/assets/asset_detail.html:64 #: assets/templates/assets/asset_detail.html:64
#: assets/templates/assets/asset_list.html:105 #: assets/templates/assets/asset_list.html:105
#: assets/templates/assets/domain_gateway_list.html:68 #: assets/templates/assets/domain_gateway_list.html:68
#: assets/templates/assets/system_user_asset.html:51
#: assets/templates/assets/user_asset_list.html:45 #: assets/templates/assets/user_asset_list.html:45
#: assets/templates/assets/user_asset_list.html:167 #: assets/templates/assets/user_asset_list.html:167
#: audits/templates/audits/login_log_list.html:54 #: audits/templates/audits/login_log_list.html:54
...@@ -825,13 +829,13 @@ msgstr "端口" ...@@ -825,13 +829,13 @@ msgstr "端口"
msgid "IP" msgid "IP"
msgstr "IP" msgstr "IP"
#: assets/models/asset.py:94 assets/templates/assets/_asset_list_modal.html:45 #: assets/models/asset.py:94 assets/serializers/asset_user.py:27
#: assets/templates/assets/_asset_user_auth_modal.html:9 #: assets/templates/assets/_asset_list_modal.html:45
#: assets/templates/assets/_asset_user_view_auth_modal.html:25 #: assets/templates/assets/_asset_user_auth_update_modal.html:9
#: assets/templates/assets/admin_user_assets.html:48 #: assets/templates/assets/_asset_user_auth_view_modal.html:15
#: assets/templates/assets/_asset_user_list.html:14
#: assets/templates/assets/asset_detail.html:60 #: assets/templates/assets/asset_detail.html:60
#: assets/templates/assets/asset_list.html:104 #: assets/templates/assets/asset_list.html:104
#: assets/templates/assets/system_user_asset.html:50
#: assets/templates/assets/user_asset_list.html:44 #: assets/templates/assets/user_asset_list.html:44
#: assets/templates/assets/user_asset_list.html:166 #: assets/templates/assets/user_asset_list.html:166
#: perms/templates/perms/asset_permission_asset.html:54 #: perms/templates/perms/asset_permission_asset.html:54
...@@ -843,7 +847,7 @@ msgid "Hostname" ...@@ -843,7 +847,7 @@ msgid "Hostname"
msgstr "主机名" msgstr "主机名"
#: assets/models/asset.py:97 assets/models/asset.py:100 #: assets/models/asset.py:97 assets/models/asset.py:100
#: assets/models/domain.py:51 assets/models/user.py:136 #: assets/models/domain.py:51 assets/models/user.py:137
#: assets/templates/assets/asset_detail.html:72 #: assets/templates/assets/asset_detail.html:72
#: assets/templates/assets/domain_gateway_list.html:70 #: assets/templates/assets/domain_gateway_list.html:70
#: assets/templates/assets/system_user_detail.html:70 #: assets/templates/assets/system_user_detail.html:70
...@@ -936,26 +940,23 @@ msgstr "主机名原始" ...@@ -936,26 +940,23 @@ msgstr "主机名原始"
msgid "Labels" msgid "Labels"
msgstr "标签管理" msgstr "标签管理"
#: assets/models/asset.py:140 assets/models/base.py:38 #: assets/models/asset.py:140 assets/models/base.py:39
#: assets/serializers/admin_user.py:22 assets/serializers/system_user.py:19 #: assets/serializers/admin_user.py:22 assets/serializers/system_user.py:19
#: assets/templates/assets/admin_user_list.html:51 #: assets/templates/assets/admin_user_list.html:51
#: assets/templates/assets/system_user_list.html:57 #: assets/templates/assets/system_user_list.html:57
msgid "Unreachable" msgid "Unreachable"
msgstr "不可达" msgstr "不可达"
#: assets/models/asset.py:141 assets/models/base.py:39 #: assets/models/asset.py:141 assets/models/base.py:40
#: assets/serializers/admin_user.py:24 assets/serializers/system_user.py:27 #: assets/serializers/admin_user.py:24 assets/serializers/system_user.py:27
#: assets/templates/assets/admin_user_assets.html:51
#: assets/templates/assets/admin_user_list.html:50 #: assets/templates/assets/admin_user_list.html:50
#: assets/templates/assets/asset_asset_user_list.html:46
#: assets/templates/assets/asset_list.html:107 #: assets/templates/assets/asset_list.html:107
#: assets/templates/assets/system_user_asset.html:53
#: assets/templates/assets/system_user_list.html:56 #: assets/templates/assets/system_user_list.html:56
#: users/templates/users/user_group_granted_asset.html:47 #: users/templates/users/user_group_granted_asset.html:47
msgid "Reachable" msgid "Reachable"
msgstr "可连接" msgstr "可连接"
#: assets/models/asset.py:142 assets/models/base.py:40 #: assets/models/asset.py:142 assets/models/base.py:41
#: authentication/utils.py:9 xpack/plugins/license/models.py:78 #: authentication/utils.py:9 xpack/plugins/license/models.py:78
msgid "Unknown" msgid "Unknown"
msgstr "未知" msgstr "未知"
...@@ -964,23 +965,25 @@ msgstr "未知" ...@@ -964,23 +965,25 @@ msgstr "未知"
msgid "Latest version" msgid "Latest version"
msgstr "最新版本" msgstr "最新版本"
#: assets/models/authbook.py:29 ops/templates/ops/adhoc_history.html:58 #: assets/models/authbook.py:29
#: assets/templates/assets/_asset_user_list.html:17
#: ops/templates/ops/adhoc_history.html:58
#: ops/templates/ops/adhoc_history_detail.html:57 #: ops/templates/ops/adhoc_history_detail.html:57
#: ops/templates/ops/task_adhoc.html:58 ops/templates/ops/task_history.html:64 #: ops/templates/ops/task_adhoc.html:58 ops/templates/ops/task_history.html:64
msgid "Version" msgid "Version"
msgstr "版本" msgstr "版本"
#: assets/models/authbook.py:34 #: assets/models/authbook.py:37
msgid "AuthBook" msgid "AuthBook"
msgstr "" msgstr ""
#: assets/models/base.py:29 xpack/plugins/change_auth_plan/models.py:94 #: assets/models/base.py:30 xpack/plugins/change_auth_plan/models.py:97
#: xpack/plugins/change_auth_plan/models.py:267 #: xpack/plugins/change_auth_plan/models.py:271
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:31 xpack/plugins/change_auth_plan/models.py:100
#: xpack/plugins/change_auth_plan/models.py:263 #: xpack/plugins/change_auth_plan/models.py:267
msgid "SSH public key" msgid "SSH public key"
msgstr "ssh公钥" msgstr "ssh公钥"
...@@ -1079,7 +1082,7 @@ msgstr "过滤器" ...@@ -1079,7 +1082,7 @@ msgstr "过滤器"
msgid "Type" msgid "Type"
msgstr "类型" msgstr "类型"
#: assets/models/cmd_filter.py:51 assets/models/user.py:135 #: assets/models/cmd_filter.py:51 assets/models/user.py:136
#: assets/templates/assets/cmd_filter_rule_list.html:60 #: assets/templates/assets/cmd_filter_rule_list.html:60
msgid "Priority" msgid "Priority"
msgstr "优先级" msgstr "优先级"
...@@ -1140,7 +1143,7 @@ msgstr "默认资产组" ...@@ -1140,7 +1143,7 @@ msgstr "默认资产组"
#: terminal/templates/terminal/session_list.html:71 users/forms.py:301 #: terminal/templates/terminal/session_list.html:71 users/forms.py:301
#: users/models/user.py:37 users/models/user.py:473 users/serializers/v1.py:61 #: users/models/user.py:37 users/models/user.py:473 users/serializers/v1.py:61
#: users/templates/users/user_group_detail.html:78 #: users/templates/users/user_group_detail.html:78
#: users/templates/users/user_group_list.html:36 users/views/user.py:399 #: users/templates/users/user_group_list.html:36 users/views/user.py:406
#: 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
...@@ -1164,29 +1167,29 @@ msgstr "键" ...@@ -1164,29 +1167,29 @@ msgstr "键"
msgid "New node" msgid "New node"
msgstr "新节点" msgstr "新节点"
#: assets/models/user.py:129 #: assets/models/user.py:130
msgid "Automatic login" msgid "Automatic login"
msgstr "自动登录" msgstr "自动登录"
#: assets/models/user.py:130 #: assets/models/user.py:131
msgid "Manually login" msgid "Manually login"
msgstr "手动登录" msgstr "手动登录"
#: assets/models/user.py:137 assets/templates/assets/_system_user.html:59 #: assets/models/user.py:138 assets/templates/assets/_system_user.html:59
#: assets/templates/assets/system_user_detail.html:122 #: assets/templates/assets/system_user_detail.html:122
#: assets/templates/assets/system_user_update.html:10 #: assets/templates/assets/system_user_update.html:10
msgid "Auto push" msgid "Auto push"
msgstr "自动推送" msgstr "自动推送"
#: assets/models/user.py:138 assets/templates/assets/system_user_detail.html:74 #: assets/models/user.py:139 assets/templates/assets/system_user_detail.html:74
msgid "Sudo" msgid "Sudo"
msgstr "Sudo" msgstr "Sudo"
#: assets/models/user.py:139 assets/templates/assets/system_user_detail.html:79 #: assets/models/user.py:140 assets/templates/assets/system_user_detail.html:79
msgid "Shell" msgid "Shell"
msgstr "Shell" msgstr "Shell"
#: assets/models/user.py:140 assets/templates/assets/system_user_detail.html:66 #: assets/models/user.py:141 assets/templates/assets/system_user_detail.html:66
#: assets/templates/assets/system_user_list.html:54 #: assets/templates/assets/system_user_list.html:54
msgid "Login mode" msgid "Login mode"
msgstr "登录模式" msgstr "登录模式"
...@@ -1197,7 +1200,6 @@ msgid "%(value)s is not an even number" ...@@ -1197,7 +1200,6 @@ 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/admin_user.py:38 #: assets/serializers/admin_user.py:38
#: assets/templates/assets/asset_asset_user_list.html:47
#: assets/templates/assets/cmd_filter_detail.html:73 #: assets/templates/assets/cmd_filter_detail.html:73
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:109 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:109
msgid "Date updated" msgid "Date updated"
...@@ -1207,7 +1209,8 @@ msgstr "更新日期" ...@@ -1207,7 +1209,8 @@ msgstr "更新日期"
msgid "Hardware info" msgid "Hardware info"
msgstr "硬件信息" msgstr "硬件信息"
#: assets/serializers/asset.py:53 #: assets/serializers/asset.py:53 assets/serializers/asset_user.py:29
#: assets/templates/assets/_asset_user_list.html:18
msgid "Connectivity" msgid "Connectivity"
msgstr "连接" msgstr "连接"
...@@ -1219,8 +1222,9 @@ msgstr "组织名" ...@@ -1219,8 +1222,9 @@ msgstr "组织名"
msgid "Protocol duplicate: {}" msgid "Protocol duplicate: {}"
msgstr "协议重复: {}" msgstr "协议重复: {}"
#: assets/serializers/asset_user.py:23 users/forms.py:248 #: assets/serializers/asset_user.py:37 assets/serializers/asset_user.py:90
#: users/models/user.py:93 users/templates/users/first_login.html:42 #: users/forms.py:248 users/models/user.py:93
#: 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
...@@ -1228,6 +1232,14 @@ msgstr "协议重复: {}" ...@@ -1228,6 +1232,14 @@ msgstr "协议重复: {}"
msgid "Public key" msgid "Public key"
msgstr "ssh公钥" msgstr "ssh公钥"
#: assets/serializers/asset_user.py:43
msgid "Backend"
msgstr ""
#: assets/serializers/asset_user.py:65
msgid "private key invalid"
msgstr "密钥不合法"
#: assets/serializers/system_user.py:22 #: assets/serializers/system_user.py:22
msgid "Unreachable assets" msgid "Unreachable assets"
msgstr "不可达资产" msgstr "不可达资产"
...@@ -1297,6 +1309,7 @@ msgid "Test system user connectivity period: {}" ...@@ -1297,6 +1309,7 @@ msgid "Test system user connectivity period: {}"
msgstr "定期测试系统用户可连接性: {}" msgstr "定期测试系统用户可连接性: {}"
#: assets/tasks.py:469 assets/tasks.py:555 #: assets/tasks.py:469 assets/tasks.py:555
#: xpack/plugins/change_auth_plan/models.py:522
msgid "The asset {} system platform {} does not support run Ansible tasks" msgid "The asset {} system platform {} does not support run Ansible tasks"
msgstr "资产 {} 系统平台 {} 不支持运行 Ansible 任务" msgstr "资产 {} 系统平台 {} 不支持运行 Ansible 任务"
...@@ -1318,7 +1331,7 @@ msgstr "推送系统用户到入资产: {}" ...@@ -1318,7 +1331,7 @@ msgstr "推送系统用户到入资产: {}"
msgid "Push system users to asset: {} => {}" msgid "Push system users to asset: {} => {}"
msgstr "推送系统用户到入资产: {} => {}" msgstr "推送系统用户到入资产: {} => {}"
#: assets/tasks.py:600 #: assets/tasks.py:612
msgid "Test asset user connectivity: {}" msgid "Test asset user connectivity: {}"
msgstr "测试资产用户可连接性: {}" msgstr "测试资产用户可连接性: {}"
...@@ -1327,7 +1340,7 @@ msgid "Import admin user" ...@@ -1327,7 +1340,7 @@ msgid "Import admin user"
msgstr "导入管理用户" msgstr "导入管理用户"
#: assets/templates/assets/_admin_user_update_modal.html:4 #: assets/templates/assets/_admin_user_update_modal.html:4
#: assets/views/admin_user.py:64 #: assets/views/admin_user.py:67
msgid "Update admin user" msgid "Update admin user"
msgstr "更新管理用户" msgstr "更新管理用户"
...@@ -1363,7 +1376,7 @@ msgstr "启用MFA" ...@@ -1363,7 +1376,7 @@ msgstr "启用MFA"
msgid "Import assets" msgid "Import assets"
msgstr "导入资产" msgstr "导入资产"
#: assets/templates/assets/_asset_list_modal.html:7 assets/views/asset.py:53 #: assets/templates/assets/_asset_list_modal.html:7 assets/views/asset.py:54
#: 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 "资产列表"
...@@ -1372,70 +1385,74 @@ msgstr "资产列表" ...@@ -1372,70 +1385,74 @@ msgstr "资产列表"
msgid "Update assets" msgid "Update assets"
msgstr "更新资产" msgstr "更新资产"
#: assets/templates/assets/_asset_user_auth_modal.html:4 #: assets/templates/assets/_asset_user_auth_update_modal.html:4
msgid "Update asset user auth" msgid "Update asset user auth"
msgstr "更新资产用户认证信息" msgstr "更新资产用户认证信息"
#: assets/templates/assets/_asset_user_auth_modal.html:23 #: assets/templates/assets/_asset_user_auth_update_modal.html:23
#: xpack/plugins/change_auth_plan/forms.py:101 #: xpack/plugins/change_auth_plan/forms.py:101
msgid "Please input password" msgid "Please input password"
msgstr "请输入密码" msgstr "请输入密码"
#: assets/templates/assets/_asset_user_view_auth_modal.html:5 #: assets/templates/assets/_asset_user_auth_update_modal.html:68
#: assets/templates/assets/asset_detail.html:312
#: users/templates/users/user_detail.html:307
#: users/templates/users/user_detail.html:334
#: xpack/plugins/interface/views.py:34
msgid "Update successfully!"
msgstr "更新成功"
#: assets/templates/assets/_asset_user_auth_view_modal.html:5
msgid "Asset user auth" msgid "Asset user auth"
msgstr "资产用户信息" msgstr "资产用户信息"
#: assets/templates/assets/_asset_user_view_auth_modal.html:14 #: assets/templates/assets/_asset_user_auth_view_modal.html:55
#: audits/models.py:99 audits/templates/audits/login_log_list.html:56
#: users/forms.py:160 users/models/user.py:85
#: users/templates/users/first_login.html:45
msgid "MFA"
msgstr "MFA"
#: assets/templates/assets/_asset_user_view_auth_modal.html:17
msgid "Need otp auth for view auth"
msgstr "需要二次认证来查看账号信息"
#: assets/templates/assets/_asset_user_view_auth_modal.html:20
#: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:212
#: assets/templates/assets/asset_list.html:682
#: assets/templates/assets/cmd_filter_detail.html:106
#: assets/templates/assets/system_user_asset.html:112
#: assets/templates/assets/system_user_detail.html:182
#: assets/templates/assets/system_user_list.html:170
#: settings/templates/settings/terminal_setting.html:168
#: templates/_modal.html:23 terminal/templates/terminal/session_detail.html:108
#: users/templates/users/user_detail.html:388
#: users/templates/users/user_detail.html:414
#: users/templates/users/user_detail.html:437
#: users/templates/users/user_detail.html:482
#: users/templates/users/user_group_create_update.html:32
#: users/templates/users/user_group_list.html:119
#: users/templates/users/user_list.html:257
#: users/templates/users/user_profile.html:238
#: xpack/plugins/cloud/templates/cloud/account_create_update.html:34
#: 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
msgid "Confirm"
msgstr "确认"
#: assets/templates/assets/_asset_user_view_auth_modal.html:63
msgid "Copy success" msgid "Copy success"
msgstr "复制成功" msgstr "复制成功"
#: assets/templates/assets/_asset_user_view_auth_modal.html:79 #: assets/templates/assets/_asset_user_auth_view_modal.html:71
#: authentication/templates/authentication/_mfa_confirm_modal.html:39
msgid "Get auth info error" msgid "Get auth info error"
msgstr "获取认证信息错误" msgstr "获取认证信息错误"
#: assets/templates/assets/_asset_user_view_auth_modal.html:139 #: assets/templates/assets/_asset_user_auth_view_modal.html:117
#: assets/templates/assets/_user_asset_detail_modal.html:23 #: assets/templates/assets/_user_asset_detail_modal.html:23
#: authentication/templates/authentication/_mfa_confirm_modal.html:79
#: settings/templates/settings/_ldap_list_users_modal.html:99 #: settings/templates/settings/_ldap_list_users_modal.html:99
#: templates/_modal.html:22 #: templates/_modal.html:22
msgid "Close" msgid "Close"
msgstr "关闭" msgstr "关闭"
#: assets/templates/assets/_asset_user_list.html:19
#: audits/templates/audits/operate_log_list.html:71
#: audits/templates/audits/password_change_log_list.html:53
#: ops/templates/ops/task_adhoc.html:63
#: terminal/templates/terminal/command_list.html:76
#: terminal/templates/terminal/session_detail.html:50
msgid "Datetime"
msgstr "日期"
#: assets/templates/assets/_asset_user_list.html:59
#, fuzzy
#| msgid "View auth"
msgid "View"
msgstr "查看认证"
#: assets/templates/assets/_asset_user_list.html:61
#: assets/templates/assets/admin_user_assets.html:61
#: assets/templates/assets/asset_asset_user_list.html:57
#: assets/templates/assets/asset_detail.html:183
#: assets/templates/assets/system_user_asset.html:63
#: assets/templates/assets/system_user_detail.html:151
msgid "Test"
msgstr "测试"
#: assets/templates/assets/_asset_user_list.html:62
#: assets/templates/assets/system_user_asset.html:72
#: assets/templates/assets/system_user_detail.html:142
msgid "Push"
msgstr "推送"
#: assets/templates/assets/_gateway_test_modal.html:4 #: assets/templates/assets/_gateway_test_modal.html:4
msgid "Test gateway test connection" msgid "Test gateway test connection"
msgstr "测试连接网关" msgstr "测试连接网关"
...@@ -1483,13 +1500,13 @@ msgid "Import system user" ...@@ -1483,13 +1500,13 @@ msgid "Import system user"
msgstr "导入系统用户" msgstr "导入系统用户"
#: assets/templates/assets/_system_user_update_modal.html:4 #: assets/templates/assets/_system_user_update_modal.html:4
#: assets/views/system_user.py:61 #: assets/views/system_user.py:64
msgid "Update system user" msgid "Update system user"
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:13 #: assets/templates/assets/asset_asset_user_list.html:13
#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:220 #: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:226
msgid "Asset detail" msgid "Asset detail"
msgstr "资产详情" msgstr "资产详情"
...@@ -1504,59 +1521,20 @@ msgstr "资产列表" ...@@ -1504,59 +1521,20 @@ msgstr "资产列表"
msgid "Asset list of " msgid "Asset list of "
msgstr "资产列表" msgstr "资产列表"
#: assets/templates/assets/admin_user_assets.html:64 #: assets/templates/assets/admin_user_assets.html:52
#: assets/templates/assets/system_user_asset.html:66 #: assets/templates/assets/system_user_asset.html:54
#: assets/templates/assets/system_user_detail.html:116 #: assets/templates/assets/system_user_detail.html:116
#: perms/templates/perms/asset_permission_detail.html:114 #: perms/templates/perms/asset_permission_detail.html:114
#: perms/templates/perms/remote_app_permission_detail.html:106 #: perms/templates/perms/remote_app_permission_detail.html:106
msgid "Quick update" msgid "Quick update"
msgstr "快速更新" msgstr "快速更新"
#: assets/templates/assets/admin_user_assets.html:70 #: assets/templates/assets/admin_user_assets.html:58
#: assets/templates/assets/asset_asset_user_list.html:67 #: assets/templates/assets/asset_asset_user_list.html:54
#: assets/templates/assets/asset_detail.html:180 #: assets/templates/assets/asset_detail.html:180
msgid "Test connective" msgid "Test connective"
msgstr "测试可连接性" msgstr "测试可连接性"
#: assets/templates/assets/admin_user_assets.html:73
#: assets/templates/assets/admin_user_assets.html:118
#: assets/templates/assets/asset_asset_user_list.html:70
#: assets/templates/assets/asset_asset_user_list.html:119
#: assets/templates/assets/asset_detail.html:183
#: assets/templates/assets/system_user_asset.html:75
#: assets/templates/assets/system_user_asset.html:166
#: assets/templates/assets/system_user_detail.html:151
msgid "Test"
msgstr "测试"
#: assets/templates/assets/admin_user_assets.html:116
#: assets/templates/assets/asset_asset_user_list.html:117
#: assets/templates/assets/system_user_asset.html:169
msgid "Update auth"
msgstr "更新认证"
#: assets/templates/assets/admin_user_assets.html:117
#: assets/templates/assets/asset_asset_user_list.html:118
#: assets/templates/assets/system_user_asset.html:167
msgid "View auth"
msgstr "查看认证"
#: assets/templates/assets/admin_user_assets.html:196
#: assets/templates/assets/asset_asset_user_list.html:162
#: assets/templates/assets/asset_detail.html:312
#: assets/templates/assets/system_user_asset.html:353
#: users/templates/users/user_detail.html:307
#: users/templates/users/user_detail.html:334
#: xpack/plugins/interface/views.py:34
msgid "Update successfully!"
msgstr "更新成功"
#: assets/templates/assets/admin_user_assets.html:199
#: assets/templates/assets/asset_asset_user_list.html:165
#: assets/templates/assets/system_user_asset.html:356
msgid "Update failed!"
msgstr "更新失败"
#: assets/templates/assets/admin_user_detail.html:83 #: assets/templates/assets/admin_user_detail.html:83
msgid "Replace node assets admin user with this" msgid "Replace node assets admin user with this"
msgstr "替换资产的管理员" msgstr "替换资产的管理员"
...@@ -1568,6 +1546,31 @@ msgstr "替换资产的管理员" ...@@ -1568,6 +1546,31 @@ msgstr "替换资产的管理员"
msgid "Select nodes" msgid "Select nodes"
msgstr "选择节点" msgstr "选择节点"
#: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:212
#: assets/templates/assets/asset_list.html:682
#: assets/templates/assets/cmd_filter_detail.html:106
#: assets/templates/assets/system_user_asset.html:100
#: assets/templates/assets/system_user_detail.html:182
#: assets/templates/assets/system_user_list.html:170
#: authentication/templates/authentication/_mfa_confirm_modal.html:20
#: settings/templates/settings/terminal_setting.html:168
#: templates/_modal.html:23 terminal/templates/terminal/session_detail.html:108
#: users/templates/users/user_detail.html:388
#: users/templates/users/user_detail.html:414
#: users/templates/users/user_detail.html:437
#: users/templates/users/user_detail.html:482
#: users/templates/users/user_group_create_update.html:32
#: users/templates/users/user_group_list.html:119
#: users/templates/users/user_list.html:257
#: users/templates/users/user_profile.html:238
#: xpack/plugins/cloud/templates/cloud/account_create_update.html:34
#: 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
msgid "Confirm"
msgstr "确认"
#: assets/templates/assets/admin_user_list.html:7 #: assets/templates/assets/admin_user_list.html:7
msgid "" msgid ""
"Admin users are asset (charged server) on the root, or have NOPASSWD: ALL " "Admin users are asset (charged server) on the root, or have NOPASSWD: ALL "
...@@ -1591,6 +1594,7 @@ msgstr "Windows或其它硬件可以随意设置一个" ...@@ -1591,6 +1594,7 @@ msgstr "Windows或其它硬件可以随意设置一个"
#: audits/templates/audits/login_log_list.html:85 #: audits/templates/audits/login_log_list.html:85
#: users/templates/users/user_group_list.html:10 #: users/templates/users/user_group_list.html:10
#: users/templates/users/user_list.html:10 #: users/templates/users/user_list.html:10
#: xpack/plugins/vault/templates/vault/vault.html:55
msgid "Export" msgid "Export"
msgstr "导出" msgstr "导出"
...@@ -1601,11 +1605,12 @@ msgstr "导出" ...@@ -1601,11 +1605,12 @@ msgstr "导出"
#: users/templates/users/user_group_list.html:15 #: users/templates/users/user_group_list.html:15
#: users/templates/users/user_list.html:15 #: users/templates/users/user_list.html:15
#: xpack/plugins/license/templates/license/license_detail.html:110 #: xpack/plugins/license/templates/license/license_detail.html:110
#: xpack/plugins/vault/templates/vault/vault.html:60
msgid "Import" msgid "Import"
msgstr "导入" msgstr "导入"
#: assets/templates/assets/admin_user_list.html:39 #: assets/templates/assets/admin_user_list.html:39
#: assets/views/admin_user.py:48 #: assets/views/admin_user.py:50
msgid "Create admin user" msgid "Create admin user"
msgstr "创建管理用户" msgstr "创建管理用户"
...@@ -1626,11 +1631,12 @@ msgstr "比例" ...@@ -1626,11 +1631,12 @@ msgstr "比例"
#: users/templates/users/user_group_list.html:194 #: users/templates/users/user_group_list.html:194
#: users/templates/users/user_list.html:158 #: users/templates/users/user_list.html:158
#: users/templates/users/user_list.html:190 #: users/templates/users/user_list.html:190
#: xpack/plugins/vault/templates/vault/vault.html:223
msgid "Please select file" msgid "Please select file"
msgstr "选择文件" msgstr "选择文件"
#: assets/templates/assets/asset_asset_user_list.html:16 #: assets/templates/assets/asset_asset_user_list.html:16
#: assets/templates/assets/asset_detail.html:23 assets/views/asset.py:69 #: assets/templates/assets/asset_detail.html:23 assets/views/asset.py:71
msgid "Asset user list" msgid "Asset user list"
msgstr "资产用户列表" msgstr "资产用户列表"
...@@ -1638,11 +1644,7 @@ msgstr "资产用户列表" ...@@ -1638,11 +1644,7 @@ msgstr "资产用户列表"
msgid "Asset users of" msgid "Asset users of"
msgstr "资产用户" msgstr "资产用户"
#: assets/templates/assets/asset_asset_user_list.html:45 #: assets/templates/assets/asset_asset_user_list.html:47
msgid "Password version"
msgstr "密码版本"
#: assets/templates/assets/asset_asset_user_list.html:60
#: assets/templates/assets/asset_detail.html:149 #: assets/templates/assets/asset_detail.html:149
#: terminal/templates/terminal/session_detail.html:81 #: terminal/templates/terminal/session_detail.html:81
#: users/templates/users/user_detail.html:138 #: users/templates/users/user_detail.html:138
...@@ -1713,7 +1715,7 @@ msgstr "" ...@@ -1713,7 +1715,7 @@ msgstr ""
"左侧是资产树,右击可以新建、删除、更改树节点,授权资产也是以节点方式组织的," "左侧是资产树,右击可以新建、删除、更改树节点,授权资产也是以节点方式组织的,"
"右侧是属于该节点下的资产" "右侧是属于该节点下的资产"
#: assets/templates/assets/asset_list.html:69 assets/views/asset.py:126 #: assets/templates/assets/asset_list.html:69 assets/views/asset.py:129
msgid "Create asset" msgid "Create asset"
msgstr "创建资产" msgstr "创建资产"
...@@ -1888,12 +1890,12 @@ msgid "else match next rule, if none matched, allowed" ...@@ -1888,12 +1890,12 @@ msgid "else match next rule, if none matched, allowed"
msgstr "否则就匹配下一个规则,如果最后没有匹配到规则,则允许执行" msgstr "否则就匹配下一个规则,如果最后没有匹配到规则,则允许执行"
#: assets/templates/assets/cmd_filter_list.html:16 #: assets/templates/assets/cmd_filter_list.html:16
#: assets/views/cmd_filter.py:47 #: assets/views/cmd_filter.py:49
msgid "Create command filter" msgid "Create command filter"
msgstr "创建命令过滤器" msgstr "创建命令过滤器"
#: assets/templates/assets/cmd_filter_rule_list.html:33 #: assets/templates/assets/cmd_filter_rule_list.html:33
#: assets/views/cmd_filter.py:98 #: assets/views/cmd_filter.py:103
msgid "Command filter rule list" msgid "Command filter rule list"
msgstr "命令过滤器规则列表" msgstr "命令过滤器规则列表"
...@@ -1920,7 +1922,7 @@ msgid "Gateway list" ...@@ -1920,7 +1922,7 @@ msgid "Gateway list"
msgstr "网关列表" msgstr "网关列表"
#: assets/templates/assets/domain_gateway_list.html:56 #: assets/templates/assets/domain_gateway_list.html:56
#: assets/views/domain.py:127 #: assets/views/domain.py:134
msgid "Create gateway" msgid "Create gateway"
msgstr "创建网关" msgstr "创建网关"
...@@ -1952,11 +1954,11 @@ msgstr "" ...@@ -1952,11 +1954,11 @@ msgstr ""
msgid "JMS => Domain gateway => Target assets" msgid "JMS => Domain gateway => Target assets"
msgstr "JMS => 网域网关 => 目标资产" msgstr "JMS => 网域网关 => 目标资产"
#: assets/templates/assets/domain_list.html:17 assets/views/domain.py:46 #: assets/templates/assets/domain_list.html:17 assets/views/domain.py:48
msgid "Create domain" msgid "Create domain"
msgstr "创建网域" msgstr "创建网域"
#: assets/templates/assets/label_list.html:6 assets/views/label.py:44 #: assets/templates/assets/label_list.html:6 assets/views/label.py:46
msgid "Create label" msgid "Create label"
msgstr "创建标签" msgstr "创建标签"
...@@ -1964,23 +1966,17 @@ msgstr "创建标签" ...@@ -1964,23 +1966,17 @@ msgstr "创建标签"
msgid "Assets of " msgid "Assets of "
msgstr "资产" msgstr "资产"
#: assets/templates/assets/system_user_asset.html:72 #: assets/templates/assets/system_user_asset.html:60
#: assets/templates/assets/system_user_detail.html:148 #: assets/templates/assets/system_user_detail.html:148
msgid "Test assets connective" msgid "Test assets connective"
msgstr "测试资产可连接性" msgstr "测试资产可连接性"
#: assets/templates/assets/system_user_asset.html:81 #: assets/templates/assets/system_user_asset.html:69
#: assets/templates/assets/system_user_detail.html:139 #: assets/templates/assets/system_user_detail.html:139
msgid "Push system user now" msgid "Push system user now"
msgstr "立刻推送系统" msgstr "立刻推送系统"
#: assets/templates/assets/system_user_asset.html:84 #: assets/templates/assets/system_user_asset.html:91
#: assets/templates/assets/system_user_asset.html:164
#: assets/templates/assets/system_user_detail.html:142
msgid "Push"
msgstr "推送"
#: assets/templates/assets/system_user_asset.html:103
msgid "Add to node" msgid "Add to node"
msgstr "添加到节点" msgstr "添加到节点"
...@@ -2025,7 +2021,7 @@ msgstr "" ...@@ -2025,7 +2021,7 @@ msgstr ""
"资产中,如果资产(交换机)不支持ansible, 请手动填写账号密码。" "资产中,如果资产(交换机)不支持ansible, 请手动填写账号密码。"
#: assets/templates/assets/system_user_list.html:43 #: assets/templates/assets/system_user_list.html:43
#: assets/views/system_user.py:45 #: assets/views/system_user.py:47
msgid "Create system user" msgid "Create system user"
msgstr "创建系统用户" msgstr "创建系统用户"
...@@ -2046,99 +2042,99 @@ msgstr "删除系统用户" ...@@ -2046,99 +2042,99 @@ msgstr "删除系统用户"
msgid "System Users Deleting failed." msgid "System Users Deleting failed."
msgstr "系统用户删除失败" msgstr "系统用户删除失败"
#: assets/views/admin_user.py:30 #: assets/views/admin_user.py:31
msgid "Admin user list" msgid "Admin user list"
msgstr "管理用户列表" msgstr "管理用户列表"
#: assets/views/admin_user.py:79 assets/views/admin_user.py:103 #: assets/views/admin_user.py:83 assets/views/admin_user.py:108
msgid "Admin user detail" msgid "Admin user detail"
msgstr "管理用户详情" msgstr "管理用户详情"
#: assets/views/asset.py:80 templates/_nav_user.html:4 #: assets/views/asset.py:82 templates/_nav_user.html:4
msgid "My assets" msgid "My assets"
msgstr "我的资产" msgstr "我的资产"
#: assets/views/asset.py:141 #: assets/views/asset.py:144
msgid "Bulk update asset success" msgid "Bulk update asset success"
msgstr "批量更新资产成功" msgstr "批量更新资产成功"
#: assets/views/asset.py:168 #: assets/views/asset.py:172
msgid "Bulk update asset" msgid "Bulk update asset"
msgstr "批量更新资产" msgstr "批量更新资产"
#: assets/views/asset.py:195 #: assets/views/asset.py:200
msgid "Update asset" msgid "Update asset"
msgstr "更新资产" msgstr "更新资产"
#: assets/views/asset.py:337 #: assets/views/asset.py:344
msgid "already exists" msgid "already exists"
msgstr "已经存在" msgstr "已经存在"
#: assets/views/cmd_filter.py:31 #: assets/views/cmd_filter.py:32
msgid "Command filter list" msgid "Command filter list"
msgstr "命令过滤器列表" msgstr "命令过滤器列表"
#: assets/views/cmd_filter.py:63 #: assets/views/cmd_filter.py:66
msgid "Update command filter" msgid "Update command filter"
msgstr "更新命令过滤器" msgstr "更新命令过滤器"
#: assets/views/cmd_filter.py:79 #: assets/views/cmd_filter.py:83
msgid "Command filter detail" msgid "Command filter detail"
msgstr "命令过滤器详情" msgstr "命令过滤器详情"
#: assets/views/cmd_filter.py:131 #: assets/views/cmd_filter.py:137
msgid "Create command filter rule" msgid "Create command filter rule"
msgstr "创建命令过滤器规则" msgstr "创建命令过滤器规则"
#: assets/views/cmd_filter.py:164 #: assets/views/cmd_filter.py:171
msgid "Update command filter rule" msgid "Update command filter rule"
msgstr "更新命令过滤器规则" msgstr "更新命令过滤器规则"
#: assets/views/domain.py:30 templates/_nav.html:23 #: assets/views/domain.py:31 templates/_nav.html:23
msgid "Domain list" msgid "Domain list"
msgstr "网域列表" msgstr "网域列表"
#: assets/views/domain.py:62 #: assets/views/domain.py:65
msgid "Update domain" msgid "Update domain"
msgstr "更新网域" msgstr "更新网域"
#: assets/views/domain.py:75 #: assets/views/domain.py:79
msgid "Domain detail" msgid "Domain detail"
msgstr "网域详情" msgstr "网域详情"
#: assets/views/domain.py:99 #: assets/views/domain.py:105
msgid "Domain gateway list" msgid "Domain gateway list"
msgstr "域网关列表" msgstr "域网关列表"
#: assets/views/domain.py:146 #: assets/views/domain.py:154
msgid "Update gateway" msgid "Update gateway"
msgstr "创建网关" msgstr "创建网关"
#: assets/views/label.py:27 #: assets/views/label.py:28
msgid "Label list" msgid "Label list"
msgstr "标签列表" msgstr "标签列表"
#: assets/views/label.py:53 #: assets/views/label.py:55
msgid "Tips: Avoid using label names reserved internally: {}" msgid "Tips: Avoid using label names reserved internally: {}"
msgstr "提示: 请避免使用内部预留标签名: {}" msgstr "提示: 请避免使用内部预留标签名: {}"
#: assets/views/label.py:70 #: assets/views/label.py:73
msgid "Update label" msgid "Update label"
msgstr "更新标签" msgstr "更新标签"
#: assets/views/system_user.py:29 #: assets/views/system_user.py:30
msgid "System user list" msgid "System user list"
msgstr "系统用户列表" msgstr "系统用户列表"
#: assets/views/system_user.py:75 #: assets/views/system_user.py:79
msgid "System user detail" msgid "System user detail"
msgstr "系统用户详情" msgstr "系统用户详情"
#: assets/views/system_user.py:96 #: assets/views/system_user.py:102
msgid "assets" msgid "assets"
msgstr "资产管理" msgstr "资产管理"
#: assets/views/system_user.py:97 #: assets/views/system_user.py:103
msgid "System user asset" msgid "System user asset"
msgstr "系统用户资产" msgstr "系统用户资产"
...@@ -2170,7 +2166,7 @@ msgstr "文件名" ...@@ -2170,7 +2166,7 @@ msgstr "文件名"
msgid "Success" msgid "Success"
msgstr "成功" msgstr "成功"
#: audits/models.py:32 #: audits/models.py:32 xpack/plugins/vault/templates/vault/vault.html:46
msgid "Create" msgid "Create"
msgstr "创建" msgstr "创建"
...@@ -2237,8 +2233,15 @@ msgstr "登录城市" ...@@ -2237,8 +2233,15 @@ msgstr "登录城市"
msgid "User agent" msgid "User agent"
msgstr "Agent" msgstr "Agent"
#: audits/models.py:99 audits/templates/audits/login_log_list.html:56
#: authentication/templates/authentication/_mfa_confirm_modal.html:14
#: users/forms.py:160 users/models/user.py:85
#: users/templates/users/first_login.html:45
msgid "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:413 #: xpack/plugins/change_auth_plan/models.py:417
#: 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
...@@ -2264,8 +2267,8 @@ msgstr "登录日期" ...@@ -2264,8 +2267,8 @@ msgstr "登录日期"
#: perms/templates/perms/asset_permission_detail.html:86 #: perms/templates/perms/asset_permission_detail.html:86
#: perms/templates/perms/remote_app_permission_detail.html:78 #: perms/templates/perms/remote_app_permission_detail.html:78
#: terminal/models.py:165 terminal/templates/terminal/session_list.html:78 #: terminal/models.py:165 terminal/templates/terminal/session_list.html:78
#: xpack/plugins/change_auth_plan/models.py:246 #: xpack/plugins/change_auth_plan/models.py:250
#: xpack/plugins/change_auth_plan/models.py:416 #: xpack/plugins/change_auth_plan/models.py:420
#: 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"
...@@ -2315,14 +2318,6 @@ msgstr "城市" ...@@ -2315,14 +2318,6 @@ msgstr "城市"
msgid "Date" msgid "Date"
msgstr "日期" msgstr "日期"
#: audits/templates/audits/operate_log_list.html:71
#: audits/templates/audits/password_change_log_list.html:53
#: ops/templates/ops/task_adhoc.html:63
#: terminal/templates/terminal/command_list.html:76
#: terminal/templates/terminal/session_detail.html:50
msgid "Datetime"
msgstr "日期"
#: audits/views.py:86 audits/views.py:130 audits/views.py:167 #: audits/views.py:86 audits/views.py:130 audits/views.py:167
#: audits/views.py:212 audits/views.py:244 templates/_nav.html:87 #: audits/views.py:212 audits/views.py:244 templates/_nav.html:87
#: templates/_nav_audits.html:22 #: templates/_nav_audits.html:22
...@@ -2440,6 +2435,18 @@ msgstr "MFA 验证码" ...@@ -2440,6 +2435,18 @@ msgstr "MFA 验证码"
msgid "Private Token" msgid "Private Token"
msgstr "ssh密钥" msgstr "ssh密钥"
#: authentication/templates/authentication/_mfa_confirm_modal.html:5
msgid "MFA confirm"
msgstr "MFA确认"
#: authentication/templates/authentication/_mfa_confirm_modal.html:17
msgid "Need otp auth for view auth"
msgstr "需要二次认证来查看账号信息"
#: authentication/templates/authentication/_mfa_confirm_modal.html:51
msgid "Code error"
msgstr "代码错误"
#: authentication/templates/authentication/login.html:27 #: authentication/templates/authentication/login.html:27
#: authentication/templates/authentication/login_otp.html:27 #: authentication/templates/authentication/login_otp.html:27
#: users/templates/users/reset_password.html:25 #: users/templates/users/reset_password.html:25
...@@ -2560,8 +2567,8 @@ msgstr "欢迎回来,请输入用户名和密码登录" ...@@ -2560,8 +2567,8 @@ msgstr "欢迎回来,请输入用户名和密码登录"
msgid "Please enable cookies and try again." msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie" msgstr "设置你的浏览器支持cookie"
#: authentication/views/login.py:172 users/views/user.py:545 #: authentication/views/login.py:172 users/views/user.py:552
#: users/views/user.py:570 #: users/views/user.py:577
msgid "MFA code invalid, or ntp sync server time" msgid "MFA code invalid, or ntp sync server time"
msgstr "MFA验证码不正确,或者服务器端时间不对" msgstr "MFA验证码不正确,或者服务器端时间不对"
...@@ -2648,7 +2655,7 @@ msgstr "不能包含特殊字符" ...@@ -2648,7 +2655,7 @@ msgstr "不能包含特殊字符"
msgid "This field must be unique." msgid "This field must be unique."
msgstr "字段必须唯一" msgstr "字段必须唯一"
#: jumpserver/views.py:185 #: jumpserver/views.py:187
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, "
"configure nginx for url distribution,</div> </div>If you see this page, " "configure nginx for url distribution,</div> </div>If you see this page, "
...@@ -2741,8 +2748,8 @@ msgstr "完成时间" ...@@ -2741,8 +2748,8 @@ msgstr "完成时间"
#: ops/models/adhoc.py:327 ops/templates/ops/adhoc_history.html:57 #: ops/models/adhoc.py:327 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:249 #: xpack/plugins/change_auth_plan/models.py:253
#: xpack/plugins/change_auth_plan/models.py:419 #: xpack/plugins/change_auth_plan/models.py:423
#: 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"
...@@ -2792,7 +2799,7 @@ msgid "Version detail" ...@@ -2792,7 +2799,7 @@ msgid "Version detail"
msgstr "版本详情" msgstr "版本详情"
#: ops/templates/ops/adhoc_detail.html:22 #: ops/templates/ops/adhoc_detail.html:22
#: ops/templates/ops/adhoc_history.html:22 ops/views/adhoc.py:122 #: ops/templates/ops/adhoc_history.html:22 ops/views/adhoc.py:128
msgid "Version run history" msgid "Version run history"
msgstr "执行历史" msgstr "执行历史"
...@@ -2851,7 +2858,7 @@ msgstr "执行历史" ...@@ -2851,7 +2858,7 @@ msgstr "执行历史"
msgid "F/S/T" msgid "F/S/T"
msgstr "失败/成功/总" msgstr "失败/成功/总"
#: ops/templates/ops/adhoc_history_detail.html:19 ops/views/adhoc.py:135 #: ops/templates/ops/adhoc_history_detail.html:19 ops/views/adhoc.py:142
msgid "Run history detail" msgid "Run history detail"
msgstr "执行历史详情" msgstr "执行历史详情"
...@@ -2927,12 +2934,12 @@ msgid "Finished" ...@@ -2927,12 +2934,12 @@ msgid "Finished"
msgstr "结束" msgstr "结束"
#: ops/templates/ops/task_adhoc.html:19 ops/templates/ops/task_detail.html:20 #: ops/templates/ops/task_adhoc.html:19 ops/templates/ops/task_detail.html:20
#: ops/templates/ops/task_history.html:19 ops/views/adhoc.py:70 #: ops/templates/ops/task_history.html:19 ops/views/adhoc.py:72
msgid "Task detail" msgid "Task detail"
msgstr "任务详情" msgstr "任务详情"
#: ops/templates/ops/task_adhoc.html:22 ops/templates/ops/task_detail.html:23 #: ops/templates/ops/task_adhoc.html:22 ops/templates/ops/task_detail.html:23
#: ops/templates/ops/task_history.html:22 ops/views/adhoc.py:83 #: ops/templates/ops/task_history.html:22 ops/views/adhoc.py:86
msgid "Task versions" msgid "Task versions"
msgstr "任务各版本" msgstr "任务各版本"
...@@ -2977,17 +2984,17 @@ msgstr "任务开始: " ...@@ -2977,17 +2984,17 @@ msgstr "任务开始: "
msgid "Update task content: {}" msgid "Update task content: {}"
msgstr "更新任务内容: {}" msgstr "更新任务内容: {}"
#: ops/views/adhoc.py:44 ops/views/adhoc.py:69 ops/views/adhoc.py:82 #: ops/views/adhoc.py:45 ops/views/adhoc.py:71 ops/views/adhoc.py:85
#: ops/views/adhoc.py:95 ops/views/adhoc.py:108 ops/views/adhoc.py:121 #: ops/views/adhoc.py:99 ops/views/adhoc.py:113 ops/views/adhoc.py:127
#: ops/views/adhoc.py:134 ops/views/command.py:47 ops/views/command.py:71 #: ops/views/adhoc.py:141 ops/views/command.py:47 ops/views/command.py:71
msgid "Ops" msgid "Ops"
msgstr "作业中心" msgstr "作业中心"
#: ops/views/adhoc.py:45 templates/_nav.html:81 #: ops/views/adhoc.py:46 templates/_nav.html:81
msgid "Task list" msgid "Task list"
msgstr "任务列表" msgstr "任务列表"
#: ops/views/adhoc.py:96 #: ops/views/adhoc.py:100
msgid "Task run history" msgid "Task run history"
msgstr "执行历史" msgstr "执行历史"
...@@ -3197,64 +3204,64 @@ msgstr "添加用户" ...@@ -3197,64 +3204,64 @@ msgstr "添加用户"
msgid "Add user group to this permission" msgid "Add user group to this permission"
msgstr "添加用户组" msgstr "添加用户组"
#: perms/views/asset_permission.py:33 perms/views/asset_permission.py:65 #: perms/views/asset_permission.py:34 perms/views/asset_permission.py:67
#: perms/views/asset_permission.py:80 perms/views/asset_permission.py:95 #: perms/views/asset_permission.py:83 perms/views/asset_permission.py:99
#: perms/views/asset_permission.py:130 perms/views/asset_permission.py:162 #: perms/views/asset_permission.py:136 perms/views/asset_permission.py:169
#: perms/views/remote_app_permission.py:32 #: perms/views/remote_app_permission.py:33
#: perms/views/remote_app_permission.py:47 #: perms/views/remote_app_permission.py:49
#: perms/views/remote_app_permission.py:62 #: perms/views/remote_app_permission.py:65
#: perms/views/remote_app_permission.py:75 #: perms/views/remote_app_permission.py:79
#: perms/views/remote_app_permission.py:101 #: perms/views/remote_app_permission.py:106
#: perms/views/remote_app_permission.py:137 templates/_nav.html:41 #: perms/views/remote_app_permission.py:143 templates/_nav.html:41
#: 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/asset_permission.py:34 #: perms/views/asset_permission.py:35
msgid "Asset permission list" msgid "Asset permission list"
msgstr "资产授权列表" msgstr "资产授权列表"
#: perms/views/asset_permission.py:66 #: perms/views/asset_permission.py:68
msgid "Create asset permission" msgid "Create asset permission"
msgstr "创建权限规则" msgstr "创建权限规则"
#: perms/views/asset_permission.py:81 #: perms/views/asset_permission.py:84
msgid "Update asset permission" msgid "Update asset permission"
msgstr "更新资产授权" msgstr "更新资产授权"
#: perms/views/asset_permission.py:96 #: perms/views/asset_permission.py:100
msgid "Asset permission detail" msgid "Asset permission detail"
msgstr "资产授权详情" msgstr "资产授权详情"
#: perms/views/asset_permission.py:131 #: perms/views/asset_permission.py:137
msgid "Asset permission user list" msgid "Asset permission user list"
msgstr "资产授权用户列表" msgstr "资产授权用户列表"
#: perms/views/asset_permission.py:163 #: perms/views/asset_permission.py:170
msgid "Asset permission asset list" msgid "Asset permission asset list"
msgstr "资产授权资产列表" msgstr "资产授权资产列表"
#: perms/views/remote_app_permission.py:33 #: perms/views/remote_app_permission.py:34
msgid "RemoteApp permission list" msgid "RemoteApp permission list"
msgstr "远程应用授权列表" msgstr "远程应用授权列表"
#: perms/views/remote_app_permission.py:48 #: perms/views/remote_app_permission.py:50
msgid "Create RemoteApp permission" msgid "Create RemoteApp permission"
msgstr "创建远程应用授权规则" msgstr "创建远程应用授权规则"
#: perms/views/remote_app_permission.py:63 #: perms/views/remote_app_permission.py:66
msgid "Update RemoteApp permission" msgid "Update RemoteApp permission"
msgstr "更新远程应用授权规则" msgstr "更新远程应用授权规则"
#: perms/views/remote_app_permission.py:76 #: perms/views/remote_app_permission.py:80
msgid "RemoteApp permission detail" msgid "RemoteApp permission detail"
msgstr "远程应用授权详情" msgstr "远程应用授权详情"
#: perms/views/remote_app_permission.py:102 #: perms/views/remote_app_permission.py:107
msgid "RemoteApp permission user list" msgid "RemoteApp permission user list"
msgstr "远程应用授权用户列表" msgstr "远程应用授权用户列表"
#: perms/views/remote_app_permission.py:138 #: perms/views/remote_app_permission.py:144
msgid "RemoteApp permission RemoteApp list" msgid "RemoteApp permission RemoteApp list"
msgstr "远程应用授权远程应用列表" msgstr "远程应用授权远程应用列表"
...@@ -3602,7 +3609,7 @@ msgstr "已存在" ...@@ -3602,7 +3609,7 @@ msgstr "已存在"
#: settings/templates/settings/ldap_setting.html:15 #: settings/templates/settings/ldap_setting.html:15
#: settings/templates/settings/security_setting.html:15 #: settings/templates/settings/security_setting.html:15
#: settings/templates/settings/terminal_setting.html:16 #: settings/templates/settings/terminal_setting.html:16
#: settings/templates/settings/terminal_setting.html:49 settings/views.py:19 #: settings/templates/settings/terminal_setting.html:49 settings/views.py:20
msgid "Basic setting" msgid "Basic setting"
msgstr "基本设置" msgstr "基本设置"
...@@ -3611,7 +3618,7 @@ msgstr "基本设置" ...@@ -3611,7 +3618,7 @@ msgstr "基本设置"
#: settings/templates/settings/email_setting.html:18 #: settings/templates/settings/email_setting.html:18
#: settings/templates/settings/ldap_setting.html:18 #: settings/templates/settings/ldap_setting.html:18
#: settings/templates/settings/security_setting.html:18 #: settings/templates/settings/security_setting.html:18
#: settings/templates/settings/terminal_setting.html:20 settings/views.py:45 #: settings/templates/settings/terminal_setting.html:20 settings/views.py:47
msgid "Email setting" msgid "Email setting"
msgstr "邮件设置" msgstr "邮件设置"
...@@ -3620,7 +3627,7 @@ msgstr "邮件设置" ...@@ -3620,7 +3627,7 @@ msgstr "邮件设置"
#: settings/templates/settings/email_setting.html:21 #: settings/templates/settings/email_setting.html:21
#: settings/templates/settings/ldap_setting.html:21 #: settings/templates/settings/ldap_setting.html:21
#: settings/templates/settings/security_setting.html:21 #: settings/templates/settings/security_setting.html:21
#: settings/templates/settings/terminal_setting.html:23 settings/views.py:178 #: settings/templates/settings/terminal_setting.html:23 settings/views.py:186
msgid "Email content setting" msgid "Email content setting"
msgstr "邮件内容设置" msgstr "邮件内容设置"
...@@ -3629,7 +3636,7 @@ msgstr "邮件内容设置" ...@@ -3629,7 +3636,7 @@ msgstr "邮件内容设置"
#: settings/templates/settings/email_setting.html:24 #: settings/templates/settings/email_setting.html:24
#: settings/templates/settings/ldap_setting.html:24 #: settings/templates/settings/ldap_setting.html:24
#: settings/templates/settings/security_setting.html:24 #: settings/templates/settings/security_setting.html:24
#: settings/templates/settings/terminal_setting.html:27 settings/views.py:71 #: settings/templates/settings/terminal_setting.html:27 settings/views.py:74
msgid "LDAP setting" msgid "LDAP setting"
msgstr "LDAP设置" msgstr "LDAP设置"
...@@ -3638,7 +3645,7 @@ msgstr "LDAP设置" ...@@ -3638,7 +3645,7 @@ msgstr "LDAP设置"
#: settings/templates/settings/email_setting.html:27 #: settings/templates/settings/email_setting.html:27
#: settings/templates/settings/ldap_setting.html:27 #: settings/templates/settings/ldap_setting.html:27
#: settings/templates/settings/security_setting.html:27 #: settings/templates/settings/security_setting.html:27
#: settings/templates/settings/terminal_setting.html:31 settings/views.py:100 #: settings/templates/settings/terminal_setting.html:31 settings/views.py:104
msgid "Terminal setting" msgid "Terminal setting"
msgstr "终端设置" msgstr "终端设置"
...@@ -3648,7 +3655,7 @@ msgstr "终端设置" ...@@ -3648,7 +3655,7 @@ msgstr "终端设置"
#: settings/templates/settings/ldap_setting.html:30 #: settings/templates/settings/ldap_setting.html:30
#: settings/templates/settings/security_setting.html:30 #: settings/templates/settings/security_setting.html:30
#: settings/templates/settings/security_setting.html:45 #: settings/templates/settings/security_setting.html:45
#: settings/templates/settings/terminal_setting.html:34 settings/views.py:152 #: settings/templates/settings/terminal_setting.html:34 settings/views.py:159
msgid "Security setting" msgid "Security setting"
msgstr "安全设置" msgstr "安全设置"
...@@ -3789,22 +3796,22 @@ msgstr "在ou:{}中没有匹配条目" ...@@ -3789,22 +3796,22 @@ msgstr "在ou:{}中没有匹配条目"
msgid "The user source is not LDAP" msgid "The user source is not LDAP"
msgstr "用户来源不是LDAP" msgstr "用户来源不是LDAP"
#: settings/views.py:18 settings/views.py:44 settings/views.py:70 #: settings/views.py:19 settings/views.py:46 settings/views.py:73
#: settings/views.py:99 settings/views.py:126 settings/views.py:138 #: settings/views.py:103 settings/views.py:131 settings/views.py:144
#: settings/views.py:151 settings/views.py:177 templates/_nav.html:122 #: settings/views.py:158 settings/views.py:185 templates/_nav.html:122
msgid "Settings" msgid "Settings"
msgstr "系统设置" msgstr "系统设置"
#: settings/views.py:29 settings/views.py:55 settings/views.py:81 #: settings/views.py:30 settings/views.py:57 settings/views.py:84
#: settings/views.py:112 settings/views.py:162 settings/views.py:188 #: settings/views.py:116 settings/views.py:169 settings/views.py:196
msgid "Update setting successfully" msgid "Update setting successfully"
msgstr "更新设置成功" msgstr "更新设置成功"
#: settings/views.py:127 #: settings/views.py:132
msgid "Create replay storage" msgid "Create replay storage"
msgstr "创建录像存储" msgstr "创建录像存储"
#: settings/views.py:139 #: settings/views.py:145
msgid "Create command storage" msgid "Create command storage"
msgstr "创建命令存储" msgstr "创建命令存储"
...@@ -3827,7 +3834,7 @@ msgstr "商业支持" ...@@ -3827,7 +3834,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:381 #: users/templates/users/user_pubkey_update.html:37 users/views/user.py:388
msgid "Profile" msgid "Profile"
msgstr "个人信息" msgstr "个人信息"
...@@ -3920,15 +3927,15 @@ msgstr "" ...@@ -3920,15 +3927,15 @@ msgstr ""
"\"%(user_pubkey_update)s\"> 链接 </a> 更新\n" "\"%(user_pubkey_update)s\"> 链接 </a> 更新\n"
" " " "
#: templates/_nav.html:10 users/views/group.py:27 users/views/group.py:43 #: templates/_nav.html:10 users/views/group.py:28 users/views/group.py:45
#: users/views/group.py:59 users/views/group.py:75 users/views/group.py:91 #: users/views/group.py:62 users/views/group.py:79 users/views/group.py:96
#: users/views/login.py:154 users/views/user.py:70 users/views/user.py:86 #: users/views/login.py:154 users/views/user.py:71 users/views/user.py:88
#: users/views/user.py:129 users/views/user.py:207 users/views/user.py:368 #: users/views/user.py:132 users/views/user.py:212 users/views/user.py:375
#: users/views/user.py:418 users/views/user.py:458 #: users/views/user.py:425 users/views/user.py:465
msgid "Users" msgid "Users"
msgstr "用户管理" msgstr "用户管理"
#: templates/_nav.html:13 users/views/user.py:71 #: templates/_nav.html:13 users/views/user.py:72
msgid "User list" msgid "User list"
msgstr "用户列表" msgstr "用户列表"
...@@ -3966,8 +3973,8 @@ msgstr "文件管理" ...@@ -3966,8 +3973,8 @@ msgstr "文件管理"
#: templates/_nav.html:72 terminal/views/command.py:51 #: templates/_nav.html:72 terminal/views/command.py:51
#: terminal/views/session.py:74 terminal/views/session.py:92 #: terminal/views/session.py:74 terminal/views/session.py:92
#: terminal/views/session.py:116 terminal/views/terminal.py:31 #: terminal/views/session.py:116 terminal/views/terminal.py:32
#: terminal/views/terminal.py:46 terminal/views/terminal.py:58 #: terminal/views/terminal.py:48 terminal/views/terminal.py:61
msgid "Terminal" msgid "Terminal"
msgstr "终端管理" msgstr "终端管理"
...@@ -4292,24 +4299,24 @@ msgstr "时长" ...@@ -4292,24 +4299,24 @@ msgstr "时长"
msgid "Terminate" msgid "Terminate"
msgstr "终断" msgstr "终断"
#: terminal/templates/terminal/session_list.html:121 #: terminal/templates/terminal/session_list.html:122
msgid "Terminate selected" msgid "Terminate selected"
msgstr "终断所选" msgstr "终断所选"
#: terminal/templates/terminal/session_list.html:122 #: terminal/templates/terminal/session_list.html:123
msgid "Confirm finished" msgid "Confirm finished"
msgstr "确认已完成" msgstr "确认已完成"
#: terminal/templates/terminal/session_list.html:142 #: terminal/templates/terminal/session_list.html:144
msgid "Terminate task send, waiting ..." msgid "Terminate task send, waiting ..."
msgstr "终断任务已发送,请等待" msgstr "终断任务已发送,请等待"
#: terminal/templates/terminal/session_list.html:155 #: terminal/templates/terminal/session_list.html:157
msgid "Finish session success" msgid "Finish session success"
msgstr "标记会话完成成功" msgstr "标记会话完成成功"
#: terminal/templates/terminal/terminal_detail.html:13 #: terminal/templates/terminal/terminal_detail.html:13
#: terminal/views/terminal.py:59 #: terminal/views/terminal.py:62
msgid "Terminal detail" msgid "Terminal detail"
msgstr "终端详情" msgstr "终端详情"
...@@ -4353,23 +4360,23 @@ msgstr "在线会话" ...@@ -4353,23 +4360,23 @@ msgstr "在线会话"
msgid "Session offline list" msgid "Session offline list"
msgstr "离线会话" msgstr "离线会话"
#: terminal/views/terminal.py:32 #: terminal/views/terminal.py:33
msgid "Terminal list" msgid "Terminal list"
msgstr "终端列表" msgstr "终端列表"
#: terminal/views/terminal.py:46 #: terminal/views/terminal.py:48
msgid "Update terminal" msgid "Update terminal"
msgstr "更新终端" msgstr "更新终端"
#: terminal/views/terminal.py:105 terminal/views/terminal.py:106 #: terminal/views/terminal.py:111 terminal/views/terminal.py:112
msgid "Redirect to web terminal" msgid "Redirect to web terminal"
msgstr "重定向到web terminal" msgstr "重定向到web terminal"
#: terminal/views/terminal.py:113 #: terminal/views/terminal.py:119
msgid "Connect ssh terminal" msgid "Connect ssh terminal"
msgstr "连接ssh终端" msgstr "连接ssh终端"
#: terminal/views/terminal.py:114 #: terminal/views/terminal.py:120
msgid "" 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客户端工具连接终端"
...@@ -4422,7 +4429,7 @@ msgstr "生成重置密码链接,通过邮件发送给用户" ...@@ -4422,7 +4429,7 @@ msgstr "生成重置密码链接,通过邮件发送给用户"
msgid "Set password" msgid "Set password"
msgstr "设置密码" msgstr "设置密码"
#: users/forms.py:118 xpack/plugins/change_auth_plan/models.py:83 #: users/forms.py:118 xpack/plugins/change_auth_plan/models.py:86
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:51 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:51
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:69 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:69
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:57 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:57
...@@ -4537,7 +4544,7 @@ msgid "Date password last updated" ...@@ -4537,7 +4544,7 @@ msgid "Date password last updated"
msgstr "最后更新密码日期" msgstr "最后更新密码日期"
#: users/models/user.py:138 users/templates/users/user_update.html:22 #: users/models/user.py:138 users/templates/users/user_update.html:22
#: users/views/login.py:47 users/views/login.py:108 users/views/user.py:431 #: users/views/login.py:47 users/views/login.py:108 users/views/user.py:438
msgid "User auth from {}, go there change password" msgid "User auth from {}, go there change password"
msgstr "用户认证源来自 {}, 请去相应系统修改密码" msgstr "用户认证源来自 {}, 请去相应系统修改密码"
...@@ -4614,7 +4621,7 @@ msgid "Import user groups" ...@@ -4614,7 +4621,7 @@ msgid "Import user groups"
msgstr "导入用户组" msgstr "导入用户组"
#: users/templates/users/_user_groups_update_modal.html:4 #: users/templates/users/_user_groups_update_modal.html:4
#: users/views/group.py:60 #: users/views/group.py:63
msgid "Update user group" msgid "Update user group"
msgstr "更新用户组" msgstr "更新用户组"
...@@ -4623,7 +4630,7 @@ msgid "Import users" ...@@ -4623,7 +4630,7 @@ msgid "Import users"
msgstr "导入用户" msgstr "导入用户"
#: users/templates/users/_user_update_modal.html:4 #: users/templates/users/_user_update_modal.html:4
#: users/templates/users/user_update.html:4 users/views/user.py:130 #: users/templates/users/user_update.html:4 users/views/user.py:133
msgid "Update user" msgid "Update user"
msgstr "更新用户" msgstr "更新用户"
...@@ -4696,7 +4703,7 @@ msgid "Always young, always with tears in my eyes. Stay foolish Stay hungry" ...@@ -4696,7 +4703,7 @@ msgid "Always young, always with tears in my eyes. Stay foolish Stay hungry"
msgstr "永远年轻,永远热泪盈眶 stay foolish stay hungry" msgstr "永远年轻,永远热泪盈眶 stay foolish stay hungry"
#: users/templates/users/reset_password.html:46 #: users/templates/users/reset_password.html:46
#: users/templates/users/user_detail.html:373 users/utils.py:98 #: users/templates/users/user_detail.html:373 users/utils.py:88
msgid "Reset password" msgid "Reset password"
msgstr "重置密码" msgstr "重置密码"
...@@ -4761,12 +4768,12 @@ msgid "Very strong" ...@@ -4761,12 +4768,12 @@ msgid "Very strong"
msgstr "很强" msgstr "很强"
#: users/templates/users/user_create.html:4 #: users/templates/users/user_create.html:4
#: users/templates/users/user_list.html:28 users/views/user.py:87 #: users/templates/users/user_list.html:28 users/views/user.py:89
msgid "Create user" msgid "Create 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:208 #: users/templates/users/user_granted_asset.html:18 users/views/user.py:213
msgid "User detail" msgid "User detail"
msgstr "用户详情" msgstr "用户详情"
...@@ -4869,7 +4876,7 @@ msgstr "重置用户MFA成功" ...@@ -4869,7 +4876,7 @@ msgstr "重置用户MFA成功"
#: users/templates/users/user_group_detail.html:22 #: users/templates/users/user_group_detail.html:22
#: users/templates/users/user_group_granted_asset.html:18 #: users/templates/users/user_group_granted_asset.html:18
#: users/views/group.py:76 #: users/views/group.py:80
msgid "User group detail" msgid "User group detail"
msgstr "用户组详情" msgstr "用户组详情"
...@@ -4878,7 +4885,7 @@ msgstr "用户组详情" ...@@ -4878,7 +4885,7 @@ msgstr "用户组详情"
msgid "Add user" msgid "Add user"
msgstr "添加用户" msgstr "添加用户"
#: users/templates/users/user_group_list.html:28 users/views/group.py:44 #: users/templates/users/user_group_list.html:28 users/views/group.py:46
msgid "Create user group" msgid "Create user group"
msgstr "创建用户组" msgstr "创建用户组"
...@@ -4969,8 +4976,8 @@ msgstr "安装完成后点击下一步进入绑定页面(如已安装,直接 ...@@ -4969,8 +4976,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:244 #: users/templates/users/user_profile.html:120 users/views/user.py:249
#: users/views/user.py:298 #: users/views/user.py:304
msgid "User groups" msgid "User groups"
msgstr "用户组" msgstr "用户组"
...@@ -5020,7 +5027,7 @@ msgid "" ...@@ -5020,7 +5027,7 @@ msgid ""
"corresponding private key." "corresponding private key."
msgstr "新的公钥已设置成功,请下载对应的私钥" msgstr "新的公钥已设置成功,请下载对应的私钥"
#: users/utils.py:38 #: users/utils.py:28
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
...@@ -5065,16 +5072,16 @@ msgstr "" ...@@ -5065,16 +5072,16 @@ msgstr ""
" </p>\n" " </p>\n"
" " " "
#: users/utils.py:73 #: users/utils.py:63
msgid "Create account successfully" msgid "Create account successfully"
msgstr "创建账户成功" msgstr "创建账户成功"
#: users/utils.py:77 #: users/utils.py:67
#, python-format #, python-format
msgid "Hello %(name)s" msgid "Hello %(name)s"
msgstr "您好 %(name)s" msgstr "您好 %(name)s"
#: users/utils.py:100 #: users/utils.py:90
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
...@@ -5118,11 +5125,11 @@ msgstr "" ...@@ -5118,11 +5125,11 @@ msgstr ""
" </br>\n" " </br>\n"
" " " "
#: users/utils.py:131 #: users/utils.py:121
msgid "Security notice" msgid "Security notice"
msgstr "安全通知" msgstr "安全通知"
#: users/utils.py:133 #: users/utils.py:123
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
...@@ -5171,11 +5178,11 @@ msgstr "" ...@@ -5171,11 +5178,11 @@ msgstr ""
" </br>\n" " </br>\n"
" " " "
#: users/utils.py:169 #: users/utils.py:159
msgid "SSH Key Reset" msgid "SSH Key Reset"
msgstr "重置ssh密钥" msgstr "重置ssh密钥"
#: users/utils.py:171 #: users/utils.py:161
#, python-format #, python-format
msgid "" msgid ""
"\n" "\n"
...@@ -5200,23 +5207,23 @@ msgstr "" ...@@ -5200,23 +5207,23 @@ msgstr ""
" </br>\n" " </br>\n"
" " " "
#: users/utils.py:204 #: users/utils.py:194
msgid "User not exist" msgid "User not exist"
msgstr "用户不存在" msgstr "用户不存在"
#: users/utils.py:206 #: users/utils.py:196
msgid "Disabled or expired" msgid "Disabled or expired"
msgstr "禁用或失效" msgstr "禁用或失效"
#: users/utils.py:219 #: users/utils.py:209
msgid "Password or SSH public key invalid" msgid "Password or SSH public key invalid"
msgstr "密码或密钥不合法" msgstr "密码或密钥不合法"
#: users/views/group.py:28 #: users/views/group.py:29
msgid "User group list" msgid "User group list"
msgstr "用户组列表" msgstr "用户组列表"
#: users/views/group.py:92 #: users/views/group.py:97
msgid "User group granted asset" msgid "User group granted asset"
msgstr "用户组授权资产" msgstr "用户组授权资产"
...@@ -5249,7 +5256,7 @@ msgstr "Token错误或失效" ...@@ -5249,7 +5256,7 @@ msgstr "Token错误或失效"
msgid "Password not same" msgid "Password not same"
msgstr "密码不一致" msgstr "密码不一致"
#: users/views/login.py:115 users/views/user.py:144 users/views/user.py:441 #: users/views/login.py:115 users/views/user.py:147 users/views/user.py:448
msgid "* Your password does not meet the requirements" msgid "* Your password does not meet the requirements"
msgstr "* 您的密码不符合要求" msgstr "* 您的密码不符合要求"
...@@ -5257,51 +5264,51 @@ msgstr "* 您的密码不符合要求" ...@@ -5257,51 +5264,51 @@ msgstr "* 您的密码不符合要求"
msgid "First login" msgid "First login"
msgstr "首次登录" msgstr "首次登录"
#: users/views/user.py:161 #: users/views/user.py:164
msgid "Bulk update user success" msgid "Bulk update user success"
msgstr "批量更新用户成功" msgstr "批量更新用户成功"
#: users/views/user.py:188 #: users/views/user.py:192
msgid "Bulk update user" msgid "Bulk update user"
msgstr "批量更新用户" msgstr "批量更新用户"
#: users/views/user.py:273 #: users/views/user.py:279
msgid "Invalid file." msgid "Invalid file."
msgstr "文件不合法" msgstr "文件不合法"
#: users/views/user.py:369 #: users/views/user.py:376
msgid "User granted assets" msgid "User granted assets"
msgstr "用户授权资产" msgstr "用户授权资产"
#: users/views/user.py:400 #: users/views/user.py:407
msgid "Profile setting" msgid "Profile setting"
msgstr "个人信息设置" msgstr "个人信息设置"
#: users/views/user.py:419 #: users/views/user.py:426
msgid "Password update" msgid "Password update"
msgstr "密码更新" msgstr "密码更新"
#: users/views/user.py:459 #: users/views/user.py:466
msgid "Public key update" msgid "Public key update"
msgstr "密钥更新" msgstr "密钥更新"
#: users/views/user.py:500 #: users/views/user.py:507
msgid "Password invalid" msgid "Password invalid"
msgstr "用户名或密码无效" msgstr "用户名或密码无效"
#: users/views/user.py:600 #: users/views/user.py:607
msgid "MFA enable success" msgid "MFA enable success"
msgstr "MFA 绑定成功" msgstr "MFA 绑定成功"
#: users/views/user.py:601 #: users/views/user.py:608
msgid "MFA enable success, return login page" msgid "MFA enable success, return login page"
msgstr "MFA 绑定成功,返回到登录页面" msgstr "MFA 绑定成功,返回到登录页面"
#: users/views/user.py:603 #: users/views/user.py:610
msgid "MFA disable success" msgid "MFA disable success"
msgstr "MFA 解绑成功" msgstr "MFA 解绑成功"
#: users/views/user.py:604 #: users/views/user.py:611
msgid "MFA disable success, return login page" msgid "MFA disable success, return login page"
msgstr "MFA 解绑成功,返回登录页面" msgstr "MFA 解绑成功,返回登录页面"
...@@ -5330,23 +5337,17 @@ msgstr "定时执行" ...@@ -5330,23 +5337,17 @@ msgstr "定时执行"
#: xpack/plugins/change_auth_plan/forms.py:120 #: xpack/plugins/change_auth_plan/forms.py:120
msgid "" msgid ""
"Tips: Currently only unix-like assets are supported, while Windows assets "
"are not"
msgstr ""
#: xpack/plugins/change_auth_plan/forms.py:122
msgid ""
"Tips: The username of the user on the asset to be modified. if the user " "Tips: The username of the user on the asset to be modified. if the user "
"exists, change the password; If the user does not exist, create the user." "exists, change the password; If the user does not exist, create the user."
msgstr "" msgstr ""
"提示:用户名为将要修改的资产上的用户的用户名。如果用户存在,则修改密码;如果" "提示:用户名为将要修改的资产上的用户的用户名。如果用户存在,则修改密码;如果"
"用户不存在,则创建用户。" "用户不存在,则创建用户。"
#: xpack/plugins/change_auth_plan/forms.py:126 #: xpack/plugins/change_auth_plan/forms.py:124
msgid "Tips: (Units: hour)" msgid "Tips: (Units: hour)"
msgstr "提示:(单位: 时)" msgstr "提示:(单位: 时)"
#: xpack/plugins/change_auth_plan/forms.py:127 #: xpack/plugins/change_auth_plan/forms.py:125
msgid "" msgid ""
"eg: Every Sunday 03:05 run <5 3 * * 0> <br> Tips: Using 5 digits linux " "eg: Every Sunday 03:05 run <5 3 * * 0> <br> Tips: Using 5 digits linux "
"crontab expressions <min hour day month week> (<a href='https://tool.lu/" "crontab expressions <min hour day month week> (<a href='https://tool.lu/"
...@@ -5358,8 +5359,8 @@ msgstr "" ...@@ -5358,8 +5359,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:111 #: xpack/plugins/change_auth_plan/models.py:114
#: xpack/plugins/change_auth_plan/models.py:253 #: xpack/plugins/change_auth_plan/models.py:257
#: 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
...@@ -5370,61 +5371,63 @@ msgstr "" ...@@ -5370,61 +5371,63 @@ msgstr ""
msgid "Change auth plan" msgid "Change auth plan"
msgstr "改密计划" msgstr "改密计划"
#: xpack/plugins/change_auth_plan/models.py:52 #: xpack/plugins/change_auth_plan/models.py:55
msgid "Custom password" msgid "Custom password"
msgstr "自定义密码" msgstr "自定义密码"
#: xpack/plugins/change_auth_plan/models.py:53 #: xpack/plugins/change_auth_plan/models.py:56
msgid "All assets use the same random password" msgid "All assets use the same random password"
msgstr "所有资产使用相同的随机密码" msgstr "所有资产使用相同的随机密码"
#: xpack/plugins/change_auth_plan/models.py:54 #: xpack/plugins/change_auth_plan/models.py:57
msgid "All assets use different random password" msgid "All assets use different random password"
msgstr "所有资产使用不同的随机密码" msgstr "所有资产使用不同的随机密码"
#: xpack/plugins/change_auth_plan/models.py:73 #: xpack/plugins/change_auth_plan/models.py:76
#: xpack/plugins/change_auth_plan/models.py:142 #: xpack/plugins/change_auth_plan/models.py:145
#: 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:81
#: xpack/plugins/change_auth_plan/models.py:140 #: xpack/plugins/change_auth_plan/models.py:143
#: 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 "定期执行"
#: xpack/plugins/change_auth_plan/models.py:87 #: xpack/plugins/change_auth_plan/models.py:90
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:74 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:74
msgid "Password rules" msgid "Password rules"
msgstr "密码规则" msgstr "密码规则"
#: xpack/plugins/change_auth_plan/models.py:210 #: xpack/plugins/change_auth_plan/models.py:213
msgid "For security, do not change root user's password" #, fuzzy
#| msgid "For security, do not change root user's password"
msgid "For security, do not change {} user's password"
msgstr "为了安全,禁止更改 {} 用户的密码" msgstr "为了安全,禁止更改 {} 用户的密码"
#: xpack/plugins/change_auth_plan/models.py:213 #: xpack/plugins/change_auth_plan/models.py:217
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:257 #: xpack/plugins/change_auth_plan/models.py:261
msgid "Change auth plan snapshot" msgid "Change auth plan snapshot"
msgstr "改密计划快照" msgstr "改密计划快照"
#: xpack/plugins/change_auth_plan/models.py:272 #: xpack/plugins/change_auth_plan/models.py:276
#: xpack/plugins/change_auth_plan/models.py:423 #: xpack/plugins/change_auth_plan/models.py:427
msgid "Change auth plan execution" msgid "Change auth plan execution"
msgstr "改密计划执行" msgstr "改密计划执行"
#: xpack/plugins/change_auth_plan/models.py:432 #: xpack/plugins/change_auth_plan/models.py:436
msgid "Change auth plan execution subtask" msgid "Change auth plan execution subtask"
msgstr "改密计划执行子任务" msgstr "改密计划执行子任务"
#: xpack/plugins/change_auth_plan/models.py:450 #: xpack/plugins/change_auth_plan/models.py:454
msgid "Authentication failed" msgid "Authentication failed"
msgstr "认证失败" msgstr "认证失败"
#: xpack/plugins/change_auth_plan/models.py:452 #: xpack/plugins/change_auth_plan/models.py:456
msgid "Connection timeout" msgid "Connection timeout"
msgstr "连接超时" msgstr "连接超时"
...@@ -5939,11 +5942,31 @@ msgstr "创建组织" ...@@ -5939,11 +5942,31 @@ msgstr "创建组织"
msgid "Update org" msgid "Update org"
msgstr "更新组织" msgstr "更新组织"
#~ msgid "Vault" #: xpack/plugins/vault/meta.py:11 xpack/plugins/vault/views.py:21
#~ msgstr "密码匣子" #: xpack/plugins/vault/views.py:35
msgid "Vault"
msgstr "密码匣子"
#: xpack/plugins/vault/templates/vault/_xpack_import_modal.html:4
msgid "Import vault"
msgstr "导入密码"
#: xpack/plugins/vault/views.py:22
msgid "vault list"
msgstr "密码匣子"
#~ msgid "vault list" #: xpack/plugins/vault/views.py:36
#~ msgstr "密码匣子" msgid "vault create"
msgstr "创建"
#~ msgid "Update failed!"
#~ msgstr "更新失败"
#~ msgid "Update auth"
#~ msgstr "更新认证"
#~ msgid "Password version"
#~ msgstr "密码版本"
#~ msgid "User does not exist" #~ msgid "User does not exist"
#~ msgstr "用户不存在" #~ msgstr "用户不存在"
...@@ -6049,9 +6072,6 @@ msgstr "更新组织" ...@@ -6049,9 +6072,6 @@ msgstr "更新组织"
#~ msgid "If set id, will use this id update user existed" #~ msgid "If set id, will use this id update user existed"
#~ msgstr "如果设置了id,则会使用该行信息更新该id的用户" #~ msgstr "如果设置了id,则会使用该行信息更新该id的用户"
#~ msgid "MFA Confirm"
#~ msgstr "确认"
#~ msgid "Monitor" #~ msgid "Monitor"
#~ msgstr "监控" #~ msgstr "监控"
......
...@@ -104,14 +104,15 @@ class JMSInventory(JMSBaseInventory): ...@@ -104,14 +104,15 @@ class JMSInventory(JMSBaseInventory):
super().__init__(host_list=host_list) super().__init__(host_list=host_list)
def get_run_user_info(self, host): def get_run_user_info(self, host):
from assets.backends.multi import AssetUserManager from assets.backends import AssetUserManager
if not self.run_as: if not self.run_as:
return {} return {}
try: try:
asset = self.assets.get(id=host.get('id')) asset = self.assets.get(id=host.get('id'))
run_user = AssetUserManager.get(self.run_as, asset) manager = AssetUserManager()
run_user = manager.get(self.run_as, asset)
except Exception as e: except Exception as e:
logger.error(e, exc_info=True) logger.error(e, exc_info=True)
return {} return {}
......
...@@ -104,6 +104,13 @@ def hello(name, callback=None): ...@@ -104,6 +104,13 @@ def hello(name, callback=None):
print("Hello {}".format(name)) print("Hello {}".format(name))
@shared_task
@after_app_shutdown_clean_periodic
@register_as_period_task(interval=30)
def hello123():
print("Hello world")
@shared_task @shared_task
def hello_callback(result): def hello_callback(result):
print(result) print(result)
......
...@@ -6,7 +6,7 @@ from django.conf import settings ...@@ -6,7 +6,7 @@ from django.conf import settings
from django.views.generic import ListView, TemplateView from django.views.generic import ListView, TemplateView
from common.permissions import ( from common.permissions import (
LoginRequiredMixin, PermissionsMixin, IsOrgAdmin, IsAuditor PermissionsMixin, IsOrgAdmin, IsAuditor, IsValidUser
) )
from common.mixins import DatetimeSearchMixin from common.mixins import DatetimeSearchMixin
from ..models import CommandExecution from ..models import CommandExecution
...@@ -54,9 +54,10 @@ class CommandExecutionListView(PermissionsMixin, DatetimeSearchMixin, ListView): ...@@ -54,9 +54,10 @@ class CommandExecutionListView(PermissionsMixin, DatetimeSearchMixin, ListView):
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
class CommandExecutionStartView(LoginRequiredMixin, TemplateView): class CommandExecutionStartView(PermissionsMixin, TemplateView):
template_name = 'ops/command_execution_create.html' template_name = 'ops/command_execution_create.html'
form_class = CommandExecutionForm form_class = CommandExecutionForm
permission_classes = [IsValidUser]
def get_user_system_users(self): def get_user_system_users(self):
from perms.utils import AssetPermissionUtil from perms.utils import AssetPermissionUtil
......
...@@ -646,6 +646,8 @@ jumpserver.initServerSideDataTable = function (options) { ...@@ -646,6 +646,8 @@ jumpserver.initServerSideDataTable = function (options) {
$.each(rows, function (id, row) { $.each(rows, function (id, row) {
table.selected_rows.push(row); table.selected_rows.push(row);
if (row.id && $.inArray(row.id, table.selected) === -1){ if (row.id && $.inArray(row.id, table.selected) === -1){
console.log(table)
console.log(table.selected);
table.selected.push(row.id) table.selected.push(row.id)
} }
}) })
...@@ -927,8 +929,11 @@ function initPopover($container, $progress, $idPassword, $el, password_check_rul ...@@ -927,8 +929,11 @@ function initPopover($container, $progress, $idPassword, $el, password_check_rul
} }
// 解决input框中的资产和弹出表格中资产的显示不一致 // 解决input框中的资产和弹出表格中资产的显示不一致
function initSelectedAssets2Table(){ function initSelectedAssets2Table(id){
var inputAssets = $('#id_assets').val(); if (!id) {
id = "#id_assets"
}
var inputAssets = $(id).val();
var selectedAssets = asset_table2.selected.concat(); var selectedAssets = asset_table2.selected.concat();
// input assets无,table assets选中,则取消勾选(再次click) // input assets无,table assets选中,则取消勾选(再次click)
......
...@@ -49,7 +49,7 @@ class TerminalUpdateView(PermissionsMixin, UpdateView): ...@@ -49,7 +49,7 @@ class TerminalUpdateView(PermissionsMixin, UpdateView):
return context return context
class TerminalDetailView(LoginRequiredMixin, PermissionsMixin, DetailView): class TerminalDetailView(PermissionsMixin, DetailView):
model = Terminal model = Terminal
template_name = 'terminal/terminal_detail.html' template_name = 'terminal/terminal_detail.html'
context_object_name = 'terminal' context_object_name = 'terminal'
...@@ -97,7 +97,7 @@ class TerminalAcceptView(PermissionsMixin, JSONResponseMixin, UpdateView): ...@@ -97,7 +97,7 @@ class TerminalAcceptView(PermissionsMixin, JSONResponseMixin, UpdateView):
return self.render_json_response(data) return self.render_json_response(data)
class TerminalConnectView(LoginRequiredMixin, PermissionsMixin, DetailView): class TerminalConnectView(PermissionsMixin, DetailView):
""" """
Abandon Abandon
""" """
...@@ -127,11 +127,11 @@ class TerminalConnectView(LoginRequiredMixin, PermissionsMixin, DetailView): ...@@ -127,11 +127,11 @@ class TerminalConnectView(LoginRequiredMixin, PermissionsMixin, DetailView):
return super(TerminalConnectView, self).get_context_data(**kwargs) return super(TerminalConnectView, self).get_context_data(**kwargs)
class WebTerminalView(LoginRequiredMixin, View): class WebTerminalView(View):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
return redirect('/luna/?' + request.GET.urlencode()) return redirect('/luna/?' + request.GET.urlencode())
class WebSFTPView(LoginRequiredMixin, View): class WebSFTPView(View):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
return redirect('/coco/elfinder/sftp/?' + request.GET.urlencode()) return redirect('/coco/elfinder/sftp/?' + request.GET.urlencode())
# ~*~ 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.views.generic import RedirectView from django.views.generic import RedirectView
from django.core.files.storage import default_storage from django.core.files.storage import default_storage
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
...@@ -15,6 +13,7 @@ from django.urls import reverse_lazy ...@@ -15,6 +13,7 @@ from django.urls import reverse_lazy
from formtools.wizard.views import SessionWizardView from formtools.wizard.views import SessionWizardView
from common.utils import get_object_or_none from common.utils import get_object_or_none
from common.permissions import PermissionsMixin, IsValidUser
from ..models import User from ..models import User
from ..utils import ( from ..utils import (
send_reset_password_mail, get_password_check_rules, check_password_rules send_reset_password_mail, get_password_check_rules, check_password_rules
...@@ -120,8 +119,9 @@ class UserResetPasswordView(TemplateView): ...@@ -120,8 +119,9 @@ class UserResetPasswordView(TemplateView):
return HttpResponseRedirect(reverse('users:reset-password-success')) return HttpResponseRedirect(reverse('users:reset-password-success'))
class UserFirstLoginView(LoginRequiredMixin, SessionWizardView): class UserFirstLoginView(PermissionsMixin, SessionWizardView):
template_name = 'users/first_login.html' template_name = 'users/first_login.html'
permission_classes = [IsValidUser]
form_list = [ form_list = [
forms.UserProfileForm, forms.UserProfileForm,
forms.UserPublicKeyForm, forms.UserPublicKeyForm,
......
...@@ -10,7 +10,6 @@ import chardet ...@@ -10,7 +10,6 @@ import chardet
from io import StringIO from io import StringIO
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth import authenticate, login as auth_login from django.contrib.auth import authenticate, login as auth_login
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.core.cache import cache from django.core.cache import cache
...@@ -36,7 +35,7 @@ from common.const import ( ...@@ -36,7 +35,7 @@ from common.const import (
) )
from common.mixins import JSONResponseMixin from common.mixins import JSONResponseMixin
from common.utils import get_logger, get_object_or_none, is_uuid, ssh_key_gen from common.utils import get_logger, get_object_or_none, is_uuid, ssh_key_gen
from common.permissions import PermissionsMixin, IsOrgAdmin from common.permissions import PermissionsMixin, IsOrgAdmin, IsValidUser
from orgs.utils import current_org from orgs.utils import current_org
from .. import forms from .. import forms
from ..models import User, UserGroup from ..models import User, UserGroup
...@@ -379,8 +378,9 @@ class UserGrantedAssetView(PermissionsMixin, DetailView): ...@@ -379,8 +378,9 @@ class UserGrantedAssetView(PermissionsMixin, DetailView):
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
class UserProfileView(LoginRequiredMixin, TemplateView): class UserProfileView(PermissionsMixin, TemplateView):
template_name = 'users/user_profile.html' template_name = 'users/user_profile.html'
permission_classes = [IsValidUser]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
mfa_setting = settings.SECURITY_MFA_AUTH mfa_setting = settings.SECURITY_MFA_AUTH
...@@ -392,9 +392,10 @@ class UserProfileView(LoginRequiredMixin, TemplateView): ...@@ -392,9 +392,10 @@ class UserProfileView(LoginRequiredMixin, TemplateView):
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
class UserProfileUpdateView(LoginRequiredMixin, UpdateView): class UserProfileUpdateView(PermissionsMixin, UpdateView):
template_name = 'users/user_profile_update.html' template_name = 'users/user_profile_update.html'
model = User model = User
permission_classes = [IsValidUser]
form_class = forms.UserProfileForm form_class = forms.UserProfileForm
success_url = reverse_lazy('users:user-profile') success_url = reverse_lazy('users:user-profile')
...@@ -410,7 +411,7 @@ class UserProfileUpdateView(LoginRequiredMixin, UpdateView): ...@@ -410,7 +411,7 @@ class UserProfileUpdateView(LoginRequiredMixin, UpdateView):
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
class UserPasswordUpdateView(LoginRequiredMixin, UpdateView): class UserPasswordUpdateView(PermissionsMixin, UpdateView):
template_name = 'users/user_password_update.html' template_name = 'users/user_password_update.html'
model = User model = User
form_class = forms.UserPasswordForm form_class = forms.UserPasswordForm
...@@ -451,10 +452,11 @@ class UserPasswordUpdateView(LoginRequiredMixin, UpdateView): ...@@ -451,10 +452,11 @@ class UserPasswordUpdateView(LoginRequiredMixin, UpdateView):
return super().form_valid(form) return super().form_valid(form)
class UserPublicKeyUpdateView(LoginRequiredMixin, UpdateView): class UserPublicKeyUpdateView(PermissionsMixin, UpdateView):
template_name = 'users/user_pubkey_update.html' template_name = 'users/user_pubkey_update.html'
model = User model = User
form_class = forms.UserPublicKeyForm form_class = forms.UserPublicKeyForm
permission_classes = [IsValidUser]
success_url = reverse_lazy('users:user-profile') success_url = reverse_lazy('users:user-profile')
def get_object(self, queryset=None): def get_object(self, queryset=None):
...@@ -469,7 +471,8 @@ class UserPublicKeyUpdateView(LoginRequiredMixin, UpdateView): ...@@ -469,7 +471,8 @@ class UserPublicKeyUpdateView(LoginRequiredMixin, UpdateView):
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
class UserPublicKeyGenerateView(LoginRequiredMixin, View): class UserPublicKeyGenerateView(PermissionsMixin, View):
permission_classes = [IsValidUser]
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
private, public = ssh_key_gen(username=request.user.username, hostname='jumpserver') private, public = ssh_key_gen(username=request.user.username, hostname='jumpserver')
......
...@@ -28,7 +28,6 @@ djangorestframework==3.9.4 ...@@ -28,7 +28,6 @@ djangorestframework==3.9.4
djangorestframework-bulk==0.2.1 djangorestframework-bulk==0.2.1
docutils==0.14 docutils==0.14
ecdsa==0.13 ecdsa==0.13
elasticsearch==6.1.1
enum-compat==0.0.2 enum-compat==0.0.2
ephem==3.7.6.0 ephem==3.7.6.0
eventlet==0.24.1 eventlet==0.24.1
......
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