mirror of https://github.com/jumpserver/jumpserver
feat: 改密计划支持数据库改密 (#6709)
* feat: 改密计划支持数据库改密 * fix: 将数据库账户信息不保存在资产信息里,保存到自己的存储中 * perf: 早餐村 * perf: 修改account * perf: 修改app和系统用户 * perf: 优化系统用户和应用关系 * fix: 修复oracle不可连接问题 Co-authored-by: ibuler <ibuler@qq.com> Co-authored-by: feng626 <1304903146@qq.com> Co-authored-by: Michael Bai <baijiangjie@gmail.com>pull/6787/head
parent
3e51f4d616
commit
905014d441
|
@ -40,6 +40,12 @@ COPY --from=stage-build /opt/jumpserver/release/jumpserver /opt/jumpserver
|
||||||
RUN mkdir -p /root/.ssh/ \
|
RUN mkdir -p /root/.ssh/ \
|
||||||
&& echo "Host *\n\tStrictHostKeyChecking no\n\tUserKnownHostsFile /dev/null" > /root/.ssh/config
|
&& echo "Host *\n\tStrictHostKeyChecking no\n\tUserKnownHostsFile /dev/null" > /root/.ssh/config
|
||||||
|
|
||||||
|
RUN mkdir -p /opt/jumpserver/oracle/
|
||||||
|
ADD https://f2c-north-rel.oss-cn-qingdao.aliyuncs.com/2.0/north/jumpserver/instantclient-basiclite-linux.x64-21.1.0.0.0.tar /opt/jumpserver/oracle/
|
||||||
|
RUN tar xvf /opt/jumpserver/oracle/instantclient-basiclite-linux.x64-21.1.0.0.0.tar -C /opt/jumpserver/oracle/
|
||||||
|
RUN sh -c "echo /opt/jumpserver/oracle/instantclient_21_1 > /etc/ld.so.conf.d/oracle-instantclient.conf"
|
||||||
|
RUN ldconfig
|
||||||
|
|
||||||
RUN echo > config.yml
|
RUN echo > config.yml
|
||||||
VOLUME /opt/jumpserver/data
|
VOLUME /opt/jumpserver/data
|
||||||
VOLUME /opt/jumpserver/logs
|
VOLUME /opt/jumpserver/logs
|
||||||
|
|
|
@ -2,74 +2,57 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
from django_filters import rest_framework as filters
|
from django_filters import rest_framework as filters
|
||||||
from django.db.models import F, Value, CharField
|
from django.db.models import F, Q
|
||||||
from django.db.models.functions import Concat
|
|
||||||
from django.http import Http404
|
|
||||||
|
|
||||||
from common.drf.filters import BaseFilterSet
|
from common.drf.filters import BaseFilterSet
|
||||||
from common.drf.api import JMSModelViewSet
|
from common.drf.api import JMSBulkModelViewSet
|
||||||
from common.utils import unique
|
from ..models import Account
|
||||||
from perms.models import ApplicationPermission
|
|
||||||
from ..hands import IsOrgAdminOrAppUser, IsOrgAdmin, NeedMFAVerify
|
from ..hands import IsOrgAdminOrAppUser, IsOrgAdmin, NeedMFAVerify
|
||||||
from .. import serializers
|
from .. import serializers
|
||||||
|
|
||||||
|
|
||||||
class AccountFilterSet(BaseFilterSet):
|
class AccountFilterSet(BaseFilterSet):
|
||||||
username = filters.CharFilter(field_name='username')
|
username = filters.CharFilter(field_name='username')
|
||||||
app = filters.CharFilter(field_name='applications', lookup_expr='exact')
|
type = filters.CharFilter(field_name='type', lookup_expr='exact')
|
||||||
app_name = filters.CharFilter(field_name='app_name', lookup_expr='exact')
|
category = filters.CharFilter(field_name='category', lookup_expr='exact')
|
||||||
|
app_display = filters.CharFilter(field_name='app_display', lookup_expr='exact')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ApplicationPermission
|
model = Account
|
||||||
fields = ['type', 'category']
|
fields = ['app', 'systemuser']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def qs(self):
|
||||||
|
qs = super().qs
|
||||||
|
qs = self.filter_username(qs)
|
||||||
|
return qs
|
||||||
|
|
||||||
|
def filter_username(self, qs):
|
||||||
|
username = self.get_query_param('username')
|
||||||
|
if not username:
|
||||||
|
return qs
|
||||||
|
qs = qs.filter(Q(username=username) | Q(systemuser__username=username)).distinct()
|
||||||
|
return qs
|
||||||
|
|
||||||
|
|
||||||
class ApplicationAccountViewSet(JMSModelViewSet):
|
class ApplicationAccountViewSet(JMSBulkModelViewSet):
|
||||||
permission_classes = (IsOrgAdmin, )
|
model = Account
|
||||||
search_fields = ['username', 'app_name']
|
search_fields = ['username', 'app_display']
|
||||||
filterset_class = AccountFilterSet
|
filterset_class = AccountFilterSet
|
||||||
filterset_fields = ['username', 'app_name', 'type', 'category']
|
filterset_fields = ['username', 'app_display', 'type', 'category', 'app']
|
||||||
serializer_class = serializers.ApplicationAccountSerializer
|
serializer_class = serializers.AppAccountSerializer
|
||||||
http_method_names = ['get', 'put', 'patch', 'options']
|
permission_classes = (IsOrgAdmin,)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = ApplicationPermission.objects\
|
queryset = Account.objects.all() \
|
||||||
.exclude(system_users__isnull=True) \
|
.annotate(type=F('app__type')) \
|
||||||
.exclude(applications__isnull=True) \
|
.annotate(app_display=F('app__name')) \
|
||||||
.annotate(uid=Concat(
|
.annotate(systemuser_display=F('systemuser__name')) \
|
||||||
'applications', Value('_'), 'system_users', output_field=CharField()
|
.annotate(category=F('app__category'))
|
||||||
)) \
|
|
||||||
.annotate(systemuser=F('system_users')) \
|
|
||||||
.annotate(systemuser_display=F('system_users__name')) \
|
|
||||||
.annotate(username=F('system_users__username')) \
|
|
||||||
.annotate(password=F('system_users__password')) \
|
|
||||||
.annotate(app=F('applications')) \
|
|
||||||
.annotate(app_name=F("applications__name")) \
|
|
||||||
.values('username', 'password', 'systemuser', 'systemuser_display',
|
|
||||||
'app', 'app_name', 'category', 'type', 'uid', 'org_id')
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
def get_object(self):
|
|
||||||
obj = self.get_queryset().filter(
|
|
||||||
uid=self.kwargs['pk']
|
|
||||||
).first()
|
|
||||||
if not obj:
|
|
||||||
raise Http404()
|
|
||||||
return obj
|
|
||||||
|
|
||||||
def filter_queryset(self, queryset):
|
|
||||||
queryset = super().filter_queryset(queryset)
|
|
||||||
queryset_list = unique(queryset, key=lambda x: (x['app'], x['systemuser']))
|
|
||||||
return queryset_list
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def filter_spm_queryset(resource_ids, queryset):
|
|
||||||
queryset = queryset.filter(uid__in=resource_ids)
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
class ApplicationAccountSecretViewSet(ApplicationAccountViewSet):
|
class ApplicationAccountSecretViewSet(ApplicationAccountViewSet):
|
||||||
serializer_class = serializers.ApplicationAccountSecretSerializer
|
serializer_class = serializers.AppAccountSecretSerializer
|
||||||
permission_classes = [IsOrgAdminOrAppUser, NeedMFAVerify]
|
permission_classes = [IsOrgAdminOrAppUser, NeedMFAVerify]
|
||||||
http_method_names = ['get', 'options']
|
http_method_names = ['get', 'options']
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,8 @@ class ApplicationViewSet(OrgBulkModelViewSet):
|
||||||
search_fields = ('name', 'type', 'category')
|
search_fields = ('name', 'type', 'category')
|
||||||
permission_classes = (IsOrgAdminOrAppUser,)
|
permission_classes = (IsOrgAdminOrAppUser,)
|
||||||
serializer_classes = {
|
serializer_classes = {
|
||||||
'default': serializers.ApplicationSerializer,
|
'default': serializers.AppSerializer,
|
||||||
'get_tree': TreeNodeSerializer,
|
'get_tree': TreeNodeSerializer
|
||||||
'suggestion': serializers.MiniApplicationSerializer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@action(methods=['GET'], detail=False, url_path='tree')
|
@action(methods=['GET'], detail=False, url_path='tree')
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
# Generated by Django 3.1.12 on 2021-08-26 09:07
|
||||||
|
|
||||||
|
import assets.models.base
|
||||||
|
import common.fields.model
|
||||||
|
from django.conf import settings
|
||||||
|
import django.core.validators
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import simple_history.models
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('assets', '0076_delete_assetuser'),
|
||||||
|
('applications', '0009_applicationuser'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='HistoricalAccount',
|
||||||
|
fields=[
|
||||||
|
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
|
||||||
|
('id', models.UUIDField(db_index=True, default=uuid.uuid4)),
|
||||||
|
('name', models.CharField(max_length=128, verbose_name='Name')),
|
||||||
|
('username', models.CharField(blank=True, db_index=True, max_length=128, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_@\\-\\.]*$', 'Special char not allowed')], verbose_name='Username')),
|
||||||
|
('password', common.fields.model.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')),
|
||||||
|
('private_key', common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')),
|
||||||
|
('public_key', common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH public key')),
|
||||||
|
('comment', models.TextField(blank=True, verbose_name='Comment')),
|
||||||
|
('date_created', models.DateTimeField(blank=True, editable=False, verbose_name='Date created')),
|
||||||
|
('date_updated', models.DateTimeField(blank=True, editable=False, verbose_name='Date updated')),
|
||||||
|
('created_by', models.CharField(max_length=128, null=True, verbose_name='Created by')),
|
||||||
|
('version', models.IntegerField(default=1, verbose_name='Version')),
|
||||||
|
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||||
|
('history_date', models.DateTimeField()),
|
||||||
|
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||||
|
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||||
|
('app', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='applications.application', verbose_name='Database')),
|
||||||
|
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||||
|
('systemuser', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='assets.systemuser', verbose_name='System user')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'historical Account',
|
||||||
|
'ordering': ('-history_date', '-history_id'),
|
||||||
|
'get_latest_by': 'history_date',
|
||||||
|
},
|
||||||
|
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Account',
|
||||||
|
fields=[
|
||||||
|
('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')),
|
||||||
|
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||||
|
('name', models.CharField(max_length=128, verbose_name='Name')),
|
||||||
|
('username', models.CharField(blank=True, db_index=True, max_length=128, validators=[django.core.validators.RegexValidator('^[0-9a-zA-Z_@\\-\\.]*$', 'Special char not allowed')], verbose_name='Username')),
|
||||||
|
('password', common.fields.model.EncryptCharField(blank=True, max_length=256, null=True, verbose_name='Password')),
|
||||||
|
('private_key', common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key')),
|
||||||
|
('public_key', common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH public key')),
|
||||||
|
('comment', models.TextField(blank=True, verbose_name='Comment')),
|
||||||
|
('date_created', models.DateTimeField(auto_now_add=True, verbose_name='Date created')),
|
||||||
|
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
|
||||||
|
('created_by', models.CharField(max_length=128, null=True, verbose_name='Created by')),
|
||||||
|
('version', models.IntegerField(default=1, verbose_name='Version')),
|
||||||
|
('app', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='applications.application', verbose_name='Database')),
|
||||||
|
('systemuser', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='assets.systemuser', verbose_name='System user')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Account',
|
||||||
|
'unique_together': {('username', 'app', 'systemuser')},
|
||||||
|
},
|
||||||
|
bases=(models.Model, assets.models.base.AuthMixin),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,40 @@
|
||||||
|
# Generated by Django 3.1.12 on 2021-08-26 09:59
|
||||||
|
|
||||||
|
from django.db import migrations, transaction
|
||||||
|
from django.db.models import F
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_app_account(apps, schema_editor):
|
||||||
|
db_alias = schema_editor.connection.alias
|
||||||
|
app_perm_model = apps.get_model("perms", "ApplicationPermission")
|
||||||
|
app_account_model = apps.get_model("applications", 'Account')
|
||||||
|
|
||||||
|
queryset = app_perm_model.objects \
|
||||||
|
.exclude(system_users__isnull=True) \
|
||||||
|
.exclude(applications__isnull=True) \
|
||||||
|
.annotate(systemuser=F('system_users')) \
|
||||||
|
.annotate(app=F('applications')) \
|
||||||
|
.values('app', 'systemuser', 'org_id')
|
||||||
|
|
||||||
|
accounts = []
|
||||||
|
for p in queryset:
|
||||||
|
if not p['app']:
|
||||||
|
continue
|
||||||
|
account = app_account_model(
|
||||||
|
app_id=p['app'], systemuser_id=p['systemuser'],
|
||||||
|
version=1, org_id=p['org_id']
|
||||||
|
)
|
||||||
|
accounts.append(account)
|
||||||
|
|
||||||
|
app_account_model.objects.using(db_alias).bulk_create(accounts, ignore_conflicts=True)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('applications', '0010_appaccount_historicalappaccount'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(migrate_app_account)
|
||||||
|
]
|
|
@ -1 +1,2 @@
|
||||||
from .application import *
|
from .application import *
|
||||||
|
from .account import *
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
from django.db import models
|
||||||
|
from simple_history.models import HistoricalRecords
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from common.utils import lazyproperty
|
||||||
|
from assets.models.base import BaseUser
|
||||||
|
|
||||||
|
|
||||||
|
class Account(BaseUser):
|
||||||
|
app = models.ForeignKey('applications.Application', on_delete=models.CASCADE, null=True, verbose_name=_('Database'))
|
||||||
|
systemuser = models.ForeignKey('assets.SystemUser', on_delete=models.CASCADE, null=True, verbose_name=_("System user"))
|
||||||
|
version = models.IntegerField(default=1, verbose_name=_('Version'))
|
||||||
|
history = HistoricalRecords()
|
||||||
|
|
||||||
|
auth_attrs = ['username', 'password', 'private_key', 'public_key']
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _('Account')
|
||||||
|
unique_together = [('username', 'app', 'systemuser')]
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.auth_snapshot = {}
|
||||||
|
|
||||||
|
def get_or_systemuser_attr(self, attr):
|
||||||
|
val = getattr(self, attr, None)
|
||||||
|
if val:
|
||||||
|
return val
|
||||||
|
if self.systemuser:
|
||||||
|
return getattr(self.systemuser, attr, '')
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def load_auth(self):
|
||||||
|
for attr in self.auth_attrs:
|
||||||
|
value = self.get_or_systemuser_attr(attr)
|
||||||
|
self.auth_snapshot[attr] = [getattr(self, attr), value]
|
||||||
|
setattr(self, attr, value)
|
||||||
|
|
||||||
|
def unload_auth(self):
|
||||||
|
if not self.systemuser:
|
||||||
|
return
|
||||||
|
|
||||||
|
for attr, values in self.auth_snapshot.items():
|
||||||
|
origin_value, loaded_value = values
|
||||||
|
current_value = getattr(self, attr, '')
|
||||||
|
if current_value == loaded_value:
|
||||||
|
setattr(self, attr, origin_value)
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
self.unload_auth()
|
||||||
|
instance = super().save(*args, **kwargs)
|
||||||
|
self.load_auth()
|
||||||
|
return instance
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def category(self):
|
||||||
|
return self.app.category
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def type(self):
|
||||||
|
return self.app.type
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def app_display(self):
|
||||||
|
return self.systemuser.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def username_display(self):
|
||||||
|
return self.get_or_systemuser_attr('username') or ''
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def systemuser_display(self):
|
||||||
|
if not self.systemuser:
|
||||||
|
return ''
|
||||||
|
return str(self.systemuser)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def smart_name(self):
|
||||||
|
username = self.username_display
|
||||||
|
|
||||||
|
if self.app:
|
||||||
|
app = str(self.app)
|
||||||
|
else:
|
||||||
|
app = '*'
|
||||||
|
return '{}@{}'.format(username, app)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.smart_name
|
|
@ -4,20 +4,23 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orgs.models import Organization
|
|
||||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||||
|
from assets.serializers.base import AuthSerializerMixin
|
||||||
from common.drf.serializers import MethodSerializer
|
from common.drf.serializers import MethodSerializer
|
||||||
from .attrs import category_serializer_classes_mapping, type_serializer_classes_mapping
|
from .attrs import (
|
||||||
|
category_serializer_classes_mapping,
|
||||||
|
type_serializer_classes_mapping
|
||||||
|
)
|
||||||
from .. import models
|
from .. import models
|
||||||
from .. import const
|
from .. import const
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'ApplicationSerializer', 'ApplicationSerializerMixin', 'MiniApplicationSerializer',
|
'AppSerializer', 'AppSerializerMixin',
|
||||||
'ApplicationAccountSerializer', 'ApplicationAccountSecretSerializer'
|
'AppAccountSerializer', 'AppAccountSecretSerializer'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class ApplicationSerializerMixin(serializers.Serializer):
|
class AppSerializerMixin(serializers.Serializer):
|
||||||
attrs = MethodSerializer()
|
attrs = MethodSerializer()
|
||||||
|
|
||||||
def get_attrs_serializer(self):
|
def get_attrs_serializer(self):
|
||||||
|
@ -45,8 +48,14 @@ class ApplicationSerializerMixin(serializers.Serializer):
|
||||||
serializer = serializer_class
|
serializer = serializer_class
|
||||||
return serializer
|
return serializer
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
return super().create(validated_data)
|
||||||
|
|
||||||
class ApplicationSerializer(ApplicationSerializerMixin, BulkOrgResourceModelSerializer):
|
def update(self, instance, validated_data):
|
||||||
|
return super().update(instance, validated_data)
|
||||||
|
|
||||||
|
|
||||||
|
class AppSerializer(AppSerializerMixin, BulkOrgResourceModelSerializer):
|
||||||
category_display = serializers.ReadOnlyField(source='get_category_display', label=_('Category display'))
|
category_display = serializers.ReadOnlyField(source='get_category_display', label=_('Category display'))
|
||||||
type_display = serializers.ReadOnlyField(source='get_type_display', label=_('Type display'))
|
type_display = serializers.ReadOnlyField(source='get_type_display', label=_('Type display'))
|
||||||
|
|
||||||
|
@ -69,48 +78,54 @@ class ApplicationSerializer(ApplicationSerializerMixin, BulkOrgResourceModelSeri
|
||||||
return _attrs
|
return _attrs
|
||||||
|
|
||||||
|
|
||||||
class ApplicationAccountSerializer(serializers.Serializer):
|
class AppAccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
||||||
id = serializers.ReadOnlyField(label=_("Id"), source='uid')
|
|
||||||
username = serializers.ReadOnlyField(label=_("Username"))
|
|
||||||
password = serializers.CharField(write_only=True, label=_("Password"))
|
|
||||||
systemuser = serializers.ReadOnlyField(label=_('System user'))
|
|
||||||
systemuser_display = serializers.ReadOnlyField(label=_("System user display"))
|
|
||||||
app = serializers.ReadOnlyField(label=_('App'))
|
|
||||||
app_name = serializers.ReadOnlyField(label=_("Application name"), read_only=True)
|
|
||||||
category = serializers.ChoiceField(label=_('Category'), choices=const.AppCategory.choices, read_only=True)
|
category = serializers.ChoiceField(label=_('Category'), choices=const.AppCategory.choices, read_only=True)
|
||||||
category_display = serializers.SerializerMethodField(label=_('Category display'))
|
category_display = serializers.SerializerMethodField(label=_('Category display'))
|
||||||
type = serializers.ChoiceField(label=_('Type'), choices=const.AppType.choices, read_only=True)
|
type = serializers.ChoiceField(label=_('Type'), choices=const.AppType.choices, read_only=True)
|
||||||
type_display = serializers.SerializerMethodField(label=_('Type display'))
|
type_display = serializers.SerializerMethodField(label=_('Type display'))
|
||||||
uid = serializers.ReadOnlyField(label=_("Union id"))
|
|
||||||
org_id = serializers.ReadOnlyField(label=_("Organization"))
|
|
||||||
org_name = serializers.SerializerMethodField(label=_("Org name"))
|
|
||||||
|
|
||||||
category_mapper = dict(const.AppCategory.choices)
|
category_mapper = dict(const.AppCategory.choices)
|
||||||
type_mapper = dict(const.AppType.choices)
|
type_mapper = dict(const.AppType.choices)
|
||||||
|
|
||||||
def create(self, validated_data):
|
class Meta:
|
||||||
pass
|
model = models.Account
|
||||||
|
fields_mini = ['id', 'username', 'version']
|
||||||
def update(self, instance, validated_data):
|
fields_write_only = ['password', 'private_key']
|
||||||
pass
|
fields_fk = ['systemuser', 'systemuser_display', 'app', 'app_display']
|
||||||
|
fields = fields_mini + fields_fk + fields_write_only + [
|
||||||
|
'type', 'type_display', 'category', 'category_display',
|
||||||
|
]
|
||||||
|
extra_kwargs = {
|
||||||
|
'username': {'default': '', 'required': False},
|
||||||
|
'password': {'write_only': True},
|
||||||
|
'app_display': {'label': _('Application display')}
|
||||||
|
}
|
||||||
|
use_model_bulk_create = True
|
||||||
|
model_bulk_create_kwargs = {
|
||||||
|
'ignore_conflicts': True
|
||||||
|
}
|
||||||
|
|
||||||
def get_category_display(self, obj):
|
def get_category_display(self, obj):
|
||||||
return self.category_mapper.get(obj['category'])
|
return self.category_mapper.get(obj.category)
|
||||||
|
|
||||||
def get_type_display(self, obj):
|
def get_type_display(self, obj):
|
||||||
return self.type_mapper.get(obj['type'])
|
return self.type_mapper.get(obj.type)
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def get_org_name(obj):
|
def setup_eager_loading(cls, queryset):
|
||||||
org = Organization.get_instance(obj['org_id'])
|
""" Perform necessary eager loading of data. """
|
||||||
return org.name
|
queryset = queryset.prefetch_related('systemuser', 'app')
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def to_representation(self, instance):
|
||||||
|
instance.load_auth()
|
||||||
|
return super().to_representation(instance)
|
||||||
|
|
||||||
|
|
||||||
class ApplicationAccountSecretSerializer(ApplicationAccountSerializer):
|
class AppAccountSecretSerializer(AppAccountSerializer):
|
||||||
password = serializers.CharField(write_only=False, label=_("Password"))
|
class Meta(AppAccountSerializer.Meta):
|
||||||
|
extra_kwargs = {
|
||||||
|
'password': {'write_only': False},
|
||||||
class MiniApplicationSerializer(serializers.ModelSerializer):
|
'private_key': {'write_only': False},
|
||||||
class Meta:
|
'public_key': {'write_only': False},
|
||||||
model = models.Application
|
}
|
||||||
fields = ApplicationSerializer.Meta.fields_mini
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from django.db.models import F, Value
|
from django.db.models import F, Value, Model
|
||||||
from django.db.models.signals import m2m_changed
|
from django.db.models.signals import m2m_changed
|
||||||
from django.db.models.functions import Concat
|
from django.db.models.functions import Concat
|
||||||
|
|
||||||
|
@ -13,13 +13,15 @@ from .. import models, serializers
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'SystemUserAssetRelationViewSet', 'SystemUserNodeRelationViewSet',
|
'SystemUserAssetRelationViewSet', 'SystemUserNodeRelationViewSet',
|
||||||
'SystemUserUserRelationViewSet',
|
'SystemUserUserRelationViewSet', 'BaseRelationViewSet',
|
||||||
]
|
]
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class RelationMixin:
|
class RelationMixin:
|
||||||
|
model: Model
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = self.model.objects.all()
|
queryset = self.model.objects.all()
|
||||||
if not current_org.is_root():
|
if not current_org.is_root():
|
||||||
|
|
|
@ -16,7 +16,6 @@ class AuthBook(BaseUser, AbsConnectivity):
|
||||||
systemuser = models.ForeignKey('assets.SystemUser', on_delete=models.CASCADE, null=True, verbose_name=_("System user"))
|
systemuser = models.ForeignKey('assets.SystemUser', on_delete=models.CASCADE, null=True, verbose_name=_("System user"))
|
||||||
version = models.IntegerField(default=1, verbose_name=_('Version'))
|
version = models.IntegerField(default=1, verbose_name=_('Version'))
|
||||||
history = HistoricalRecords()
|
history = HistoricalRecords()
|
||||||
_systemuser_display = ''
|
|
||||||
|
|
||||||
auth_attrs = ['username', 'password', 'private_key', 'public_key']
|
auth_attrs = ['username', 'password', 'private_key', 'public_key']
|
||||||
|
|
||||||
|
@ -64,8 +63,6 @@ class AuthBook(BaseUser, AbsConnectivity):
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def systemuser_display(self):
|
def systemuser_display(self):
|
||||||
if self._systemuser_display:
|
|
||||||
return self._systemuser_display
|
|
||||||
if not self.systemuser:
|
if not self.systemuser:
|
||||||
return ''
|
return ''
|
||||||
return str(self.systemuser)
|
return str(self.systemuser)
|
||||||
|
|
|
@ -73,6 +73,10 @@ class ProtocolMixin:
|
||||||
def can_perm_to_asset(self):
|
def can_perm_to_asset(self):
|
||||||
return self.protocol in self.ASSET_CATEGORY_PROTOCOLS
|
return self.protocol in self.ASSET_CATEGORY_PROTOCOLS
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_asset_protocol(self):
|
||||||
|
return self.protocol in self.ASSET_CATEGORY_PROTOCOLS
|
||||||
|
|
||||||
|
|
||||||
class AuthMixin:
|
class AuthMixin:
|
||||||
username_same_with_user: bool
|
username_same_with_user: bool
|
||||||
|
|
|
@ -14,7 +14,7 @@ __all__ = [
|
||||||
'SystemUserSimpleSerializer', 'SystemUserAssetRelationSerializer',
|
'SystemUserSimpleSerializer', 'SystemUserAssetRelationSerializer',
|
||||||
'SystemUserNodeRelationSerializer', 'SystemUserTaskSerializer',
|
'SystemUserNodeRelationSerializer', 'SystemUserTaskSerializer',
|
||||||
'SystemUserUserRelationSerializer', 'SystemUserWithAuthInfoSerializer',
|
'SystemUserUserRelationSerializer', 'SystemUserWithAuthInfoSerializer',
|
||||||
'SystemUserTempAuthSerializer',
|
'SystemUserTempAuthSerializer', 'RelationMixin',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,12 +31,12 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
||||||
fields_mini = ['id', 'name', 'username']
|
fields_mini = ['id', 'name', 'username']
|
||||||
fields_write_only = ['password', 'public_key', 'private_key']
|
fields_write_only = ['password', 'public_key', 'private_key']
|
||||||
fields_small = fields_mini + fields_write_only + [
|
fields_small = fields_mini + fields_write_only + [
|
||||||
'type', 'type_display', 'protocol', 'login_mode', 'login_mode_display',
|
'token', 'ssh_key_fingerprint',
|
||||||
'priority', 'sudo', 'shell', 'sftp_root', 'token', 'ssh_key_fingerprint',
|
'type', 'type_display', 'protocol', 'is_asset_protocol',
|
||||||
'home', 'system_groups', 'ad_domain',
|
'login_mode', 'login_mode_display', 'priority',
|
||||||
|
'sudo', 'shell', 'sftp_root', 'home', 'system_groups', 'ad_domain',
|
||||||
'username_same_with_user', 'auto_push', 'auto_generate_key',
|
'username_same_with_user', 'auto_push', 'auto_generate_key',
|
||||||
'date_created', 'date_updated',
|
'date_created', 'date_updated', 'comment', 'created_by',
|
||||||
'comment', 'created_by',
|
|
||||||
]
|
]
|
||||||
fields_m2m = ['cmd_filters', 'assets_amount']
|
fields_m2m = ['cmd_filters', 'assets_amount']
|
||||||
fields = fields_small + fields_m2m
|
fields = fields_small + fields_m2m
|
||||||
|
@ -53,6 +53,7 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
||||||
'login_mode_display': {'label': _('Login mode display')},
|
'login_mode_display': {'label': _('Login mode display')},
|
||||||
'created_by': {'read_only': True},
|
'created_by': {'read_only': True},
|
||||||
'ad_domain': {'required': False, 'allow_blank': True, 'label': _('Ad domain')},
|
'ad_domain': {'required': False, 'allow_blank': True, 'label': _('Ad domain')},
|
||||||
|
'is_asset_protocol': {'label': _('Is asset protocol')}
|
||||||
}
|
}
|
||||||
|
|
||||||
def validate_auto_push(self, value):
|
def validate_auto_push(self, value):
|
||||||
|
|
|
@ -160,7 +160,7 @@ class BaseService(object):
|
||||||
if self.process:
|
if self.process:
|
||||||
try:
|
try:
|
||||||
self.process.wait(1) # 不wait,子进程可能无法回收
|
self.process.wait(1) # 不wait,子进程可能无法回收
|
||||||
except subprocess.TimeoutExpired:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if self.is_running:
|
if self.is_running:
|
||||||
|
|
Binary file not shown.
|
@ -35,12 +35,12 @@ msgid "Name"
|
||||||
msgstr "名称"
|
msgstr "名称"
|
||||||
|
|
||||||
#: acls/models/base.py:27 assets/models/cmd_filter.py:54
|
#: acls/models/base.py:27 assets/models/cmd_filter.py:54
|
||||||
#: assets/models/user.py:203
|
#: assets/models/user.py:207
|
||||||
msgid "Priority"
|
msgid "Priority"
|
||||||
msgstr "优先级"
|
msgstr "优先级"
|
||||||
|
|
||||||
#: acls/models/base.py:28 assets/models/cmd_filter.py:54
|
#: acls/models/base.py:28 assets/models/cmd_filter.py:54
|
||||||
#: assets/models/user.py:203
|
#: assets/models/user.py:207
|
||||||
msgid "1-100, the lower the value will be match first"
|
msgid "1-100, the lower the value will be match first"
|
||||||
msgstr "优先级可选范围为 1-100 (数值越小越优先)"
|
msgstr "优先级可选范围为 1-100 (数值越小越优先)"
|
||||||
|
|
||||||
|
@ -51,8 +51,6 @@ msgstr "优先级可选范围为 1-100 (数值越小越优先)"
|
||||||
msgid "Active"
|
msgid "Active"
|
||||||
msgstr "激活中"
|
msgstr "激活中"
|
||||||
|
|
||||||
# msgid "Date created"
|
|
||||||
# msgstr "创建日期"
|
|
||||||
#: acls/models/base.py:32 applications/models/application.py:179
|
#: acls/models/base.py:32 applications/models/application.py:179
|
||||||
#: assets/models/asset.py:144 assets/models/asset.py:220
|
#: assets/models/asset.py:144 assets/models/asset.py:220
|
||||||
#: assets/models/base.py:180 assets/models/cluster.py:29
|
#: assets/models/base.py:180 assets/models/cluster.py:29
|
||||||
|
@ -62,7 +60,7 @@ msgstr "激活中"
|
||||||
#: orgs/models.py:27 perms/models/base.py:53 settings/models.py:34
|
#: orgs/models.py:27 perms/models/base.py:53 settings/models.py:34
|
||||||
#: terminal/models/storage.py:26 terminal/models/terminal.py:114
|
#: terminal/models/storage.py:26 terminal/models/terminal.py:114
|
||||||
#: tickets/models/ticket.py:71 users/models/group.py:16
|
#: tickets/models/ticket.py:71 users/models/group.py:16
|
||||||
#: users/models/user.py:590 xpack/plugins/change_auth_plan/models.py:88
|
#: users/models/user.py:590 xpack/plugins/change_auth_plan/models/base.py:41
|
||||||
#: xpack/plugins/cloud/models.py:35 xpack/plugins/cloud/models.py:113
|
#: xpack/plugins/cloud/models.py:35 xpack/plugins/cloud/models.py:113
|
||||||
#: xpack/plugins/gathered_user/models.py:26
|
#: xpack/plugins/gathered_user/models.py:26
|
||||||
msgid "Comment"
|
msgid "Comment"
|
||||||
|
@ -114,20 +112,16 @@ msgstr "用户"
|
||||||
msgid "Login confirm"
|
msgid "Login confirm"
|
||||||
msgstr "登录复核"
|
msgstr "登录复核"
|
||||||
|
|
||||||
#: acls/models/login_asset_acl.py:21
|
|
||||||
msgid "System User"
|
|
||||||
msgstr "系统用户"
|
|
||||||
|
|
||||||
#: acls/models/login_asset_acl.py:22
|
#: acls/models/login_asset_acl.py:22
|
||||||
#: applications/serializers/attrs/application_category/remote_app.py:37
|
#: applications/serializers/attrs/application_category/remote_app.py:37
|
||||||
#: assets/models/asset.py:357 assets/models/authbook.py:15
|
#: assets/models/asset.py:357 assets/models/authbook.py:15
|
||||||
#: assets/models/gathered_user.py:14 assets/serializers/system_user.py:200
|
#: assets/models/gathered_user.py:14 assets/serializers/system_user.py:201
|
||||||
#: audits/models.py:38 perms/models/asset_permission.py:99
|
#: audits/models.py:38 perms/models/asset_permission.py:99
|
||||||
#: templates/index.html:82 terminal/backends/command/models.py:19
|
#: templates/index.html:82 terminal/backends/command/models.py:19
|
||||||
#: terminal/backends/command/serializers.py:13 terminal/models/session.py:40
|
#: terminal/backends/command/serializers.py:13 terminal/models/session.py:40
|
||||||
#: users/templates/users/user_asset_permission.html:40
|
#: users/templates/users/user_asset_permission.html:40
|
||||||
#: users/templates/users/user_asset_permission.html:70
|
#: users/templates/users/user_asset_permission.html:70
|
||||||
#: xpack/plugins/change_auth_plan/models.py:315
|
#: xpack/plugins/change_auth_plan/models/asset.py:195
|
||||||
#: xpack/plugins/cloud/models.py:217
|
#: xpack/plugins/cloud/models.py:217
|
||||||
msgid "Asset"
|
msgid "Asset"
|
||||||
msgstr "资产"
|
msgstr "资产"
|
||||||
|
@ -173,7 +167,6 @@ msgstr "格式为逗号分隔的字符串, * 表示匹配所有. "
|
||||||
|
|
||||||
#: acls/serializers/login_asset_acl.py:17
|
#: acls/serializers/login_asset_acl.py:17
|
||||||
#: acls/serializers/login_asset_acl.py:51
|
#: acls/serializers/login_asset_acl.py:51
|
||||||
#: applications/serializers/application.py:74
|
|
||||||
#: applications/serializers/attrs/application_type/chrome.py:20
|
#: applications/serializers/attrs/application_type/chrome.py:20
|
||||||
#: applications/serializers/attrs/application_type/custom.py:21
|
#: applications/serializers/attrs/application_type/custom.py:21
|
||||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:30
|
#: applications/serializers/attrs/application_type/mysql_workbench.py:30
|
||||||
|
@ -182,8 +175,8 @@ msgstr "格式为逗号分隔的字符串, * 表示匹配所有. "
|
||||||
#: audits/models.py:105 authentication/forms.py:15 authentication/forms.py:17
|
#: audits/models.py:105 authentication/forms.py:15 authentication/forms.py:17
|
||||||
#: ops/models/adhoc.py:148 users/forms/profile.py:31 users/models/user.py:555
|
#: ops/models/adhoc.py:148 users/forms/profile.py:31 users/models/user.py:555
|
||||||
#: users/templates/users/_select_user_modal.html:14
|
#: users/templates/users/_select_user_modal.html:14
|
||||||
#: xpack/plugins/change_auth_plan/models.py:51
|
#: xpack/plugins/change_auth_plan/models/asset.py:35
|
||||||
#: xpack/plugins/change_auth_plan/models.py:311
|
#: xpack/plugins/change_auth_plan/models/asset.py:191
|
||||||
#: xpack/plugins/cloud/serializers.py:67
|
#: xpack/plugins/cloud/serializers.py:67
|
||||||
msgid "Username"
|
msgid "Username"
|
||||||
msgstr "用户名"
|
msgstr "用户名"
|
||||||
|
@ -212,7 +205,7 @@ msgid ""
|
||||||
msgstr "格式为逗号分隔的字符串, * 表示匹配所有. 可选的协议有: {}"
|
msgstr "格式为逗号分隔的字符串, * 表示匹配所有. 可选的协议有: {}"
|
||||||
|
|
||||||
#: acls/serializers/login_asset_acl.py:55 assets/models/asset.py:184
|
#: acls/serializers/login_asset_acl.py:55 assets/models/asset.py:184
|
||||||
#: assets/models/domain.py:63 assets/models/user.py:204
|
#: assets/models/domain.py:63 assets/models/user.py:208
|
||||||
#: terminal/serializers/session.py:30 terminal/serializers/storage.py:69
|
#: terminal/serializers/session.py:30 terminal/serializers/storage.py:69
|
||||||
msgid "Protocol"
|
msgid "Protocol"
|
||||||
msgstr "协议"
|
msgstr "协议"
|
||||||
|
@ -234,9 +227,11 @@ msgstr "所有复核人都不属于组织 `{}`"
|
||||||
msgid "My applications"
|
msgid "My applications"
|
||||||
msgstr "我的应用"
|
msgstr "我的应用"
|
||||||
|
|
||||||
#: applications/const.py:8
|
#: applications/const.py:8 applications/models/account.py:10
|
||||||
#: applications/serializers/attrs/application_category/db.py:14
|
#: applications/serializers/attrs/application_category/db.py:14
|
||||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:26
|
#: applications/serializers/attrs/application_type/mysql_workbench.py:26
|
||||||
|
#: xpack/plugins/change_auth_plan/models/app.py:32
|
||||||
|
#: xpack/plugins/change_auth_plan/models/app.py:139
|
||||||
msgid "Database"
|
msgid "Database"
|
||||||
msgstr "数据库"
|
msgstr "数据库"
|
||||||
|
|
||||||
|
@ -248,25 +243,44 @@ msgstr "远程应用"
|
||||||
msgid "Custom"
|
msgid "Custom"
|
||||||
msgstr "自定义"
|
msgstr "自定义"
|
||||||
|
|
||||||
|
#: applications/models/account.py:11 assets/models/authbook.py:16
|
||||||
|
#: assets/models/user.py:281 audits/models.py:39
|
||||||
|
#: perms/models/application_permission.py:31
|
||||||
|
#: perms/models/asset_permission.py:101 templates/_nav.html:45
|
||||||
|
#: terminal/backends/command/models.py:20
|
||||||
|
#: terminal/backends/command/serializers.py:14 terminal/models/session.py:42
|
||||||
|
#: users/templates/users/_granted_assets.html:27
|
||||||
|
#: users/templates/users/user_asset_permission.html:42
|
||||||
|
#: users/templates/users/user_asset_permission.html:76
|
||||||
|
#: users/templates/users/user_asset_permission.html:159
|
||||||
|
#: users/templates/users/user_database_app_permission.html:40
|
||||||
|
#: users/templates/users/user_database_app_permission.html:67
|
||||||
|
#: xpack/plugins/change_auth_plan/models/app.py:36
|
||||||
|
msgid "System user"
|
||||||
|
msgstr "系统用户"
|
||||||
|
|
||||||
#: applications/models/application.py:50 templates/_nav.html:60
|
#: applications/models/application.py:50 templates/_nav.html:60
|
||||||
msgid "Applications"
|
msgid "Applications"
|
||||||
msgstr "应用管理"
|
msgstr "应用管理"
|
||||||
|
|
||||||
#: applications/models/application.py:168
|
#: applications/models/application.py:168
|
||||||
#: applications/serializers/application.py:80 assets/models/label.py:21
|
#: applications/serializers/application.py:82 assets/models/label.py:21
|
||||||
#: perms/models/application_permission.py:20
|
#: perms/models/application_permission.py:20
|
||||||
#: perms/serializers/application/user_permission.py:33
|
#: perms/serializers/application/user_permission.py:33
|
||||||
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:20
|
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:20
|
||||||
|
#: xpack/plugins/change_auth_plan/models/app.py:25
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "类别"
|
msgstr "类别"
|
||||||
|
|
||||||
#: applications/models/application.py:171
|
#: applications/models/application.py:171
|
||||||
#: applications/serializers/application.py:82 assets/models/cmd_filter.py:53
|
#: applications/serializers/application.py:84 assets/models/cmd_filter.py:53
|
||||||
#: assets/models/user.py:202 perms/models/application_permission.py:23
|
#: assets/models/user.py:206 perms/models/application_permission.py:23
|
||||||
#: perms/serializers/application/user_permission.py:34
|
#: perms/serializers/application/user_permission.py:34
|
||||||
#: terminal/models/storage.py:55 terminal/models/storage.py:116
|
#: terminal/models/storage.py:55 terminal/models/storage.py:116
|
||||||
#: tickets/models/flow.py:50 tickets/models/ticket.py:48
|
#: tickets/models/flow.py:50 tickets/models/ticket.py:48
|
||||||
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:27
|
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:27
|
||||||
|
#: xpack/plugins/change_auth_plan/models/app.py:28
|
||||||
|
#: xpack/plugins/change_auth_plan/models/app.py:148
|
||||||
msgid "Type"
|
msgid "Type"
|
||||||
msgstr "类型"
|
msgstr "类型"
|
||||||
|
|
||||||
|
@ -279,15 +293,15 @@ msgstr "网域"
|
||||||
msgid "Attrs"
|
msgid "Attrs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: applications/serializers/application.py:50
|
#: applications/serializers/application.py:59
|
||||||
#: applications/serializers/application.py:81 assets/serializers/label.py:13
|
#: applications/serializers/application.py:83 assets/serializers/label.py:13
|
||||||
#: perms/serializers/application/permission.py:18
|
#: perms/serializers/application/permission.py:18
|
||||||
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:24
|
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:24
|
||||||
msgid "Category display"
|
msgid "Category display"
|
||||||
msgstr "类别名称"
|
msgstr "类别名称"
|
||||||
|
|
||||||
#: applications/serializers/application.py:51
|
#: applications/serializers/application.py:60
|
||||||
#: applications/serializers/application.py:83
|
#: applications/serializers/application.py:85
|
||||||
#: assets/serializers/system_user.py:26 audits/serializers.py:29
|
#: assets/serializers/system_user.py:26 audits/serializers.py:29
|
||||||
#: perms/serializers/application/permission.py:19
|
#: perms/serializers/application/permission.py:19
|
||||||
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:31
|
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:31
|
||||||
|
@ -300,46 +314,6 @@ msgstr "类型名称"
|
||||||
msgid "Id"
|
msgid "Id"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: applications/serializers/application.py:75
|
|
||||||
#: applications/serializers/application.py:110
|
|
||||||
#: applications/serializers/attrs/application_type/chrome.py:23
|
|
||||||
#: applications/serializers/attrs/application_type/custom.py:25
|
|
||||||
#: applications/serializers/attrs/application_type/mysql_workbench.py:34
|
|
||||||
#: applications/serializers/attrs/application_type/vmware_client.py:30
|
|
||||||
#: assets/models/base.py:177 audits/signals_handler.py:63
|
|
||||||
#: authentication/forms.py:22
|
|
||||||
#: authentication/templates/authentication/login.html:164
|
|
||||||
#: settings/serializers/auth/ldap.py:44 users/forms/profile.py:21
|
|
||||||
#: users/templates/users/user_otp_check_password.html:13
|
|
||||||
#: users/templates/users/user_password_update.html:43
|
|
||||||
#: users/templates/users/user_password_verify.html:18
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:72
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:207
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:318
|
|
||||||
#: xpack/plugins/cloud/serializers.py:69
|
|
||||||
msgid "Password"
|
|
||||||
msgstr "密码"
|
|
||||||
|
|
||||||
#: applications/serializers/application.py:76 assets/models/authbook.py:16
|
|
||||||
#: assets/models/user.py:277 audits/models.py:39
|
|
||||||
#: perms/models/application_permission.py:31
|
|
||||||
#: perms/models/asset_permission.py:101 templates/_nav.html:45
|
|
||||||
#: terminal/backends/command/models.py:20
|
|
||||||
#: terminal/backends/command/serializers.py:14 terminal/models/session.py:42
|
|
||||||
#: users/templates/users/_granted_assets.html:27
|
|
||||||
#: users/templates/users/user_asset_permission.html:42
|
|
||||||
#: users/templates/users/user_asset_permission.html:76
|
|
||||||
#: users/templates/users/user_asset_permission.html:159
|
|
||||||
#: users/templates/users/user_database_app_permission.html:40
|
|
||||||
#: users/templates/users/user_database_app_permission.html:67
|
|
||||||
msgid "System user"
|
|
||||||
msgstr "系统用户"
|
|
||||||
|
|
||||||
#: applications/serializers/application.py:77 assets/serializers/account.py:31
|
|
||||||
#: assets/serializers/account.py:52
|
|
||||||
msgid "System user display"
|
|
||||||
msgstr "系统用户名称"
|
|
||||||
|
|
||||||
#: applications/serializers/application.py:78
|
#: applications/serializers/application.py:78
|
||||||
msgid "App"
|
msgid "App"
|
||||||
msgstr "应用"
|
msgstr "应用"
|
||||||
|
@ -348,21 +322,6 @@ msgstr "应用"
|
||||||
msgid "Application name"
|
msgid "Application name"
|
||||||
msgstr "应用名称"
|
msgstr "应用名称"
|
||||||
|
|
||||||
#: applications/serializers/application.py:84
|
|
||||||
msgid "Union id"
|
|
||||||
msgstr "联合ID"
|
|
||||||
|
|
||||||
#: applications/serializers/application.py:85 orgs/mixins/models.py:46
|
|
||||||
#: orgs/mixins/serializers.py:25 orgs/models.py:37 orgs/models.py:432
|
|
||||||
#: orgs/serializers.py:106 tickets/serializers/ticket/ticket.py:77
|
|
||||||
msgid "Organization"
|
|
||||||
msgstr "组织"
|
|
||||||
|
|
||||||
#: applications/serializers/application.py:86 assets/serializers/asset.py:98
|
|
||||||
#: assets/serializers/system_user.py:217 orgs/mixins/serializers.py:26
|
|
||||||
msgid "Org name"
|
|
||||||
msgstr "组织名称"
|
|
||||||
|
|
||||||
#: applications/serializers/attrs/application_category/cloud.py:9
|
#: applications/serializers/attrs/application_category/cloud.py:9
|
||||||
#: assets/models/cluster.py:40
|
#: assets/models/cluster.py:40
|
||||||
msgid "Cluster"
|
msgid "Cluster"
|
||||||
|
@ -400,6 +359,24 @@ msgstr "该字段是必填项。"
|
||||||
msgid "Target URL"
|
msgid "Target URL"
|
||||||
msgstr "目标URL"
|
msgstr "目标URL"
|
||||||
|
|
||||||
|
#: applications/serializers/attrs/application_type/chrome.py:23
|
||||||
|
#: applications/serializers/attrs/application_type/custom.py:25
|
||||||
|
#: applications/serializers/attrs/application_type/mysql_workbench.py:34
|
||||||
|
#: applications/serializers/attrs/application_type/vmware_client.py:30
|
||||||
|
#: assets/models/base.py:177 audits/signals_handler.py:63
|
||||||
|
#: authentication/forms.py:22
|
||||||
|
#: authentication/templates/authentication/login.html:164
|
||||||
|
#: settings/serializers/settings.py:95 users/forms/profile.py:21
|
||||||
|
#: users/templates/users/user_otp_check_password.html:13
|
||||||
|
#: users/templates/users/user_password_update.html:43
|
||||||
|
#: users/templates/users/user_password_verify.html:18
|
||||||
|
#: xpack/plugins/change_auth_plan/models/base.py:39
|
||||||
|
#: xpack/plugins/change_auth_plan/models/base.py:114
|
||||||
|
#: xpack/plugins/change_auth_plan/models/base.py:182
|
||||||
|
#: xpack/plugins/cloud/serializers.py:69
|
||||||
|
msgid "Password"
|
||||||
|
msgstr "密码"
|
||||||
|
|
||||||
#: applications/serializers/attrs/application_type/custom.py:13
|
#: applications/serializers/attrs/application_type/custom.py:13
|
||||||
msgid "Operating parameter"
|
msgid "Operating parameter"
|
||||||
msgstr "运行参数"
|
msgstr "运行参数"
|
||||||
|
@ -452,9 +429,9 @@ msgstr "系统平台"
|
||||||
msgid "Protocols"
|
msgid "Protocols"
|
||||||
msgstr "协议组"
|
msgstr "协议组"
|
||||||
|
|
||||||
#: assets/models/asset.py:189 assets/models/user.py:194
|
#: assets/models/asset.py:189 assets/models/user.py:198
|
||||||
#: perms/models/asset_permission.py:100
|
#: perms/models/asset_permission.py:100
|
||||||
#: xpack/plugins/change_auth_plan/models.py:60
|
#: xpack/plugins/change_auth_plan/models/asset.py:44
|
||||||
#: xpack/plugins/gathered_user/models.py:24
|
#: xpack/plugins/gathered_user/models.py:24
|
||||||
msgid "Nodes"
|
msgid "Nodes"
|
||||||
msgstr "节点"
|
msgstr "节点"
|
||||||
|
@ -466,7 +443,7 @@ msgid "Is active"
|
||||||
msgstr "激活"
|
msgstr "激活"
|
||||||
|
|
||||||
#: assets/models/asset.py:193 assets/models/cluster.py:19
|
#: assets/models/asset.py:193 assets/models/cluster.py:19
|
||||||
#: assets/models/user.py:191 assets/models/user.py:326 templates/_nav.html:44
|
#: assets/models/user.py:195 assets/models/user.py:330 templates/_nav.html:44
|
||||||
msgid "Admin user"
|
msgid "Admin user"
|
||||||
msgstr "特权用户"
|
msgstr "特权用户"
|
||||||
|
|
||||||
|
@ -543,13 +520,12 @@ msgstr "标签管理"
|
||||||
#: assets/models/cmd_filter.py:67 assets/models/group.py:21
|
#: assets/models/cmd_filter.py:67 assets/models/group.py:21
|
||||||
#: common/db/models.py:70 common/mixins/models.py:49 orgs/models.py:25
|
#: common/db/models.py:70 common/mixins/models.py:49 orgs/models.py:25
|
||||||
#: orgs/models.py:437 perms/models/base.py:51 users/models/user.py:598
|
#: orgs/models.py:437 perms/models/base.py:51 users/models/user.py:598
|
||||||
#: users/serializers/group.py:33 xpack/plugins/change_auth_plan/models.py:92
|
#: users/serializers/group.py:33
|
||||||
|
#: xpack/plugins/change_auth_plan/models/base.py:45
|
||||||
#: xpack/plugins/cloud/models.py:119 xpack/plugins/gathered_user/models.py:30
|
#: xpack/plugins/cloud/models.py:119 xpack/plugins/gathered_user/models.py:30
|
||||||
msgid "Created by"
|
msgid "Created by"
|
||||||
msgstr "创建者"
|
msgstr "创建者"
|
||||||
|
|
||||||
# msgid "Created by"
|
|
||||||
# msgstr "创建者"
|
|
||||||
#: assets/models/asset.py:219 assets/models/base.py:181
|
#: assets/models/asset.py:219 assets/models/base.py:181
|
||||||
#: assets/models/cluster.py:26 assets/models/domain.py:27
|
#: assets/models/cluster.py:26 assets/models/domain.py:27
|
||||||
#: assets/models/gathered_user.py:19 assets/models/group.py:22
|
#: assets/models/gathered_user.py:19 assets/models/group.py:22
|
||||||
|
@ -589,15 +565,15 @@ msgstr "可连接性"
|
||||||
msgid "Date verified"
|
msgid "Date verified"
|
||||||
msgstr "校验日期"
|
msgstr "校验日期"
|
||||||
|
|
||||||
#: assets/models/base.py:178 xpack/plugins/change_auth_plan/models.py:82
|
#: assets/models/base.py:178 xpack/plugins/change_auth_plan/models/asset.py:54
|
||||||
#: xpack/plugins/change_auth_plan/models.py:214
|
#: xpack/plugins/change_auth_plan/models/asset.py:126
|
||||||
#: xpack/plugins/change_auth_plan/models.py:325
|
#: xpack/plugins/change_auth_plan/models/asset.py:202
|
||||||
msgid "SSH private key"
|
msgid "SSH private key"
|
||||||
msgstr "SSH密钥"
|
msgstr "SSH密钥"
|
||||||
|
|
||||||
#: assets/models/base.py:179 xpack/plugins/change_auth_plan/models.py:85
|
#: assets/models/base.py:179 xpack/plugins/change_auth_plan/models/asset.py:57
|
||||||
#: xpack/plugins/change_auth_plan/models.py:210
|
#: xpack/plugins/change_auth_plan/models/asset.py:122
|
||||||
#: xpack/plugins/change_auth_plan/models.py:321
|
#: xpack/plugins/change_auth_plan/models/asset.py:198
|
||||||
msgid "SSH public key"
|
msgid "SSH public key"
|
||||||
msgstr "SSH公钥"
|
msgstr "SSH公钥"
|
||||||
|
|
||||||
|
@ -649,7 +625,7 @@ msgstr "系统"
|
||||||
msgid "Default Cluster"
|
msgid "Default Cluster"
|
||||||
msgstr "默认Cluster"
|
msgstr "默认Cluster"
|
||||||
|
|
||||||
#: assets/models/cmd_filter.py:33 assets/models/user.py:209
|
#: assets/models/cmd_filter.py:33 assets/models/user.py:213
|
||||||
msgid "Command filter"
|
msgid "Command filter"
|
||||||
msgstr "命令过滤器"
|
msgstr "命令过滤器"
|
||||||
|
|
||||||
|
@ -751,7 +727,7 @@ msgstr "全称"
|
||||||
msgid "Parent key"
|
msgid "Parent key"
|
||||||
msgstr "ssh私钥"
|
msgstr "ssh私钥"
|
||||||
|
|
||||||
#: assets/models/node.py:559 assets/serializers/system_user.py:199
|
#: assets/models/node.py:559 assets/serializers/system_user.py:200
|
||||||
#: users/templates/users/user_asset_permission.html:41
|
#: users/templates/users/user_asset_permission.html:41
|
||||||
#: users/templates/users/user_asset_permission.html:73
|
#: users/templates/users/user_asset_permission.html:73
|
||||||
#: users/templates/users/user_asset_permission.html:158
|
#: users/templates/users/user_asset_permission.html:158
|
||||||
|
@ -759,65 +735,65 @@ msgstr "ssh私钥"
|
||||||
msgid "Node"
|
msgid "Node"
|
||||||
msgstr "节点"
|
msgstr "节点"
|
||||||
|
|
||||||
#: assets/models/user.py:185
|
#: assets/models/user.py:189
|
||||||
msgid "Automatic managed"
|
msgid "Automatic managed"
|
||||||
msgstr "托管密码"
|
msgstr "托管密码"
|
||||||
|
|
||||||
#: assets/models/user.py:186
|
#: assets/models/user.py:190
|
||||||
msgid "Manually input"
|
msgid "Manually input"
|
||||||
msgstr "手动输入"
|
msgstr "手动输入"
|
||||||
|
|
||||||
#: assets/models/user.py:190
|
#: assets/models/user.py:194
|
||||||
msgid "Common user"
|
msgid "Common user"
|
||||||
msgstr "普通用户"
|
msgstr "普通用户"
|
||||||
|
|
||||||
#: assets/models/user.py:193
|
#: assets/models/user.py:197
|
||||||
msgid "Username same with user"
|
msgid "Username same with user"
|
||||||
msgstr "用户名与用户相同"
|
msgstr "用户名与用户相同"
|
||||||
|
|
||||||
#: assets/models/user.py:196 assets/serializers/domain.py:28
|
#: assets/models/user.py:200 assets/serializers/domain.py:28
|
||||||
#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models.py:56
|
#: templates/_nav.html:39 xpack/plugins/change_auth_plan/models/asset.py:40
|
||||||
msgid "Assets"
|
msgid "Assets"
|
||||||
msgstr "资产"
|
msgstr "资产"
|
||||||
|
|
||||||
#: assets/models/user.py:200 templates/_nav.html:17
|
#: assets/models/user.py:204 templates/_nav.html:17
|
||||||
#: users/views/profile/pubkey.py:37
|
#: users/views/profile/pubkey.py:37
|
||||||
msgid "Users"
|
msgid "Users"
|
||||||
msgstr "用户管理"
|
msgstr "用户管理"
|
||||||
|
|
||||||
#: assets/models/user.py:201
|
#: assets/models/user.py:205
|
||||||
msgid "User groups"
|
msgid "User groups"
|
||||||
msgstr "用户组"
|
msgstr "用户组"
|
||||||
|
|
||||||
#: assets/models/user.py:205
|
#: assets/models/user.py:209
|
||||||
msgid "Auto push"
|
msgid "Auto push"
|
||||||
msgstr "自动推送"
|
msgstr "自动推送"
|
||||||
|
|
||||||
#: assets/models/user.py:206
|
#: assets/models/user.py:210
|
||||||
msgid "Sudo"
|
msgid "Sudo"
|
||||||
msgstr "Sudo"
|
msgstr "Sudo"
|
||||||
|
|
||||||
#: assets/models/user.py:207
|
#: assets/models/user.py:211
|
||||||
msgid "Shell"
|
msgid "Shell"
|
||||||
msgstr "Shell"
|
msgstr "Shell"
|
||||||
|
|
||||||
#: assets/models/user.py:208
|
#: assets/models/user.py:212
|
||||||
msgid "Login mode"
|
msgid "Login mode"
|
||||||
msgstr "认证方式"
|
msgstr "认证方式"
|
||||||
|
|
||||||
#: assets/models/user.py:210
|
#: assets/models/user.py:214
|
||||||
msgid "SFTP Root"
|
msgid "SFTP Root"
|
||||||
msgstr "SFTP根路径"
|
msgstr "SFTP根路径"
|
||||||
|
|
||||||
#: assets/models/user.py:211 authentication/models.py:94
|
#: assets/models/user.py:215 authentication/models.py:94
|
||||||
msgid "Token"
|
msgid "Token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: assets/models/user.py:212
|
#: assets/models/user.py:216
|
||||||
msgid "Home"
|
msgid "Home"
|
||||||
msgstr "家目录"
|
msgstr "家目录"
|
||||||
|
|
||||||
#: assets/models/user.py:213
|
#: assets/models/user.py:217
|
||||||
msgid "System groups"
|
msgid "System groups"
|
||||||
msgstr "用户组"
|
msgstr "用户组"
|
||||||
|
|
||||||
|
@ -826,6 +802,10 @@ msgstr "用户组"
|
||||||
msgid "%(value)s is not an even number"
|
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/account.py:31 assets/serializers/account.py:52
|
||||||
|
msgid "System user display"
|
||||||
|
msgstr "系统用户名称"
|
||||||
|
|
||||||
#: assets/serializers/asset.py:20
|
#: assets/serializers/asset.py:20
|
||||||
msgid "Protocol format should {}/{}"
|
msgid "Protocol format should {}/{}"
|
||||||
msgstr "协议格式 {}/{}"
|
msgstr "协议格式 {}/{}"
|
||||||
|
@ -846,6 +826,11 @@ msgstr "节点名称"
|
||||||
msgid "Hardware info"
|
msgid "Hardware info"
|
||||||
msgstr "硬件信息"
|
msgstr "硬件信息"
|
||||||
|
|
||||||
|
#: assets/serializers/asset.py:98 assets/serializers/system_user.py:218
|
||||||
|
#: orgs/mixins/serializers.py:26
|
||||||
|
msgid "Org name"
|
||||||
|
msgstr "用户名"
|
||||||
|
|
||||||
#: assets/serializers/asset.py:99
|
#: assets/serializers/asset.py:99
|
||||||
msgid "Admin user display"
|
msgid "Admin user display"
|
||||||
msgstr "特权用户名称"
|
msgstr "特权用户名称"
|
||||||
|
@ -890,7 +875,7 @@ msgstr "密钥指纹"
|
||||||
msgid "Nodes amount"
|
msgid "Nodes amount"
|
||||||
msgstr "节点数量"
|
msgstr "节点数量"
|
||||||
|
|
||||||
#: assets/serializers/system_user.py:53 assets/serializers/system_user.py:201
|
#: assets/serializers/system_user.py:53 assets/serializers/system_user.py:202
|
||||||
msgid "Login mode display"
|
msgid "Login mode display"
|
||||||
msgstr "认证方式名称"
|
msgstr "认证方式名称"
|
||||||
|
|
||||||
|
@ -898,27 +883,31 @@ msgstr "认证方式名称"
|
||||||
msgid "Ad domain"
|
msgid "Ad domain"
|
||||||
msgstr "Ad 网域"
|
msgstr "Ad 网域"
|
||||||
|
|
||||||
#: assets/serializers/system_user.py:95
|
#: assets/serializers/system_user.py:56
|
||||||
|
msgid "Is asset protocol"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: assets/serializers/system_user.py:96
|
||||||
msgid "Username same with user with protocol {} only allow 1"
|
msgid "Username same with user with protocol {} only allow 1"
|
||||||
msgstr "用户名和用户相同的一种协议只允许存在一个"
|
msgstr "用户名和用户相同的一种协议只允许存在一个"
|
||||||
|
|
||||||
#: assets/serializers/system_user.py:109
|
#: assets/serializers/system_user.py:110
|
||||||
msgid "* Automatic login mode must fill in the username."
|
msgid "* Automatic login mode must fill in the username."
|
||||||
msgstr "自动登录模式,必须填写用户名"
|
msgstr "自动登录模式,必须填写用户名"
|
||||||
|
|
||||||
#: assets/serializers/system_user.py:123
|
#: assets/serializers/system_user.py:124
|
||||||
msgid "Path should starts with /"
|
msgid "Path should starts with /"
|
||||||
msgstr "路径应该以 / 开头"
|
msgstr "路径应该以 / 开头"
|
||||||
|
|
||||||
#: assets/serializers/system_user.py:148
|
#: assets/serializers/system_user.py:149
|
||||||
msgid "Password or private key required"
|
msgid "Password or private key required"
|
||||||
msgstr "密码或密钥密码需要一个"
|
msgstr "密码或密钥密码需要一个"
|
||||||
|
|
||||||
#: assets/serializers/system_user.py:216
|
#: assets/serializers/system_user.py:217
|
||||||
msgid "System user name"
|
msgid "System user name"
|
||||||
msgstr "系统用户名称"
|
msgstr "系统用户名称"
|
||||||
|
|
||||||
#: assets/serializers/system_user.py:226
|
#: assets/serializers/system_user.py:227
|
||||||
msgid "Asset hostname"
|
msgid "Asset hostname"
|
||||||
msgstr "资产主机名"
|
msgstr "资产主机名"
|
||||||
|
|
||||||
|
@ -1092,8 +1081,8 @@ msgstr "成功"
|
||||||
#: terminal/models/session.py:52
|
#: terminal/models/session.py:52
|
||||||
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:53
|
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:53
|
||||||
#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:45
|
#: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:45
|
||||||
#: xpack/plugins/change_auth_plan/models.py:194
|
#: xpack/plugins/change_auth_plan/models/base.py:105
|
||||||
#: xpack/plugins/change_auth_plan/models.py:340
|
#: xpack/plugins/change_auth_plan/models/base.py:189
|
||||||
#: xpack/plugins/gathered_user/models.py:76
|
#: xpack/plugins/gathered_user/models.py:76
|
||||||
msgid "Date start"
|
msgid "Date start"
|
||||||
msgstr "开始日期"
|
msgstr "开始日期"
|
||||||
|
@ -2123,7 +2112,7 @@ msgid "Regularly perform"
|
||||||
msgstr "定期执行"
|
msgstr "定期执行"
|
||||||
|
|
||||||
#: ops/mixin.py:106 ops/mixin.py:147
|
#: ops/mixin.py:106 ops/mixin.py:147
|
||||||
#: xpack/plugins/change_auth_plan/serializers.py:60
|
#: xpack/plugins/change_auth_plan/serializers/base.py:42
|
||||||
msgid "Periodic perform"
|
msgid "Periodic perform"
|
||||||
msgstr "定时执行"
|
msgstr "定时执行"
|
||||||
|
|
||||||
|
@ -2202,8 +2191,8 @@ msgstr "开始时间"
|
||||||
msgid "End time"
|
msgid "End time"
|
||||||
msgstr "完成时间"
|
msgstr "完成时间"
|
||||||
|
|
||||||
#: ops/models/adhoc.py:246 xpack/plugins/change_auth_plan/models.py:197
|
#: ops/models/adhoc.py:246 xpack/plugins/change_auth_plan/models/base.py:108
|
||||||
#: xpack/plugins/change_auth_plan/models.py:343
|
#: xpack/plugins/change_auth_plan/models/base.py:190
|
||||||
#: xpack/plugins/gathered_user/models.py:79
|
#: xpack/plugins/gathered_user/models.py:79
|
||||||
msgid "Time"
|
msgid "Time"
|
||||||
msgstr "时间"
|
msgstr "时间"
|
||||||
|
@ -2285,6 +2274,12 @@ msgstr "当前组织 ({}) 不能被删除"
|
||||||
msgid "The organization have resource ({}) cannot be deleted"
|
msgid "The organization have resource ({}) cannot be deleted"
|
||||||
msgstr "组织存在资源 ({}) 不能被删除"
|
msgstr "组织存在资源 ({}) 不能被删除"
|
||||||
|
|
||||||
|
#: orgs/mixins/models.py:46 orgs/mixins/serializers.py:25 orgs/models.py:37
|
||||||
|
#: orgs/models.py:432 orgs/serializers.py:106
|
||||||
|
#: tickets/serializers/ticket/ticket.py:77
|
||||||
|
msgid "Organization"
|
||||||
|
msgstr "组织审计员"
|
||||||
|
|
||||||
#: orgs/models.py:17 users/const.py:12
|
#: orgs/models.py:17 users/const.py:12
|
||||||
msgid "Organization administrator"
|
msgid "Organization administrator"
|
||||||
msgstr "组织管理员"
|
msgstr "组织管理员"
|
||||||
|
@ -2935,6 +2930,7 @@ msgstr "仅管理员"
|
||||||
msgid "Global MFA auth"
|
msgid "Global MFA auth"
|
||||||
msgstr "全局启用 MFA 认证"
|
msgstr "全局启用 MFA 认证"
|
||||||
|
|
||||||
|
|
||||||
#: settings/serializers/security.py:33
|
#: settings/serializers/security.py:33
|
||||||
msgid "Limit the number of login failures"
|
msgid "Limit the number of login failures"
|
||||||
msgstr "限制登录失败次数"
|
msgstr "限制登录失败次数"
|
||||||
|
@ -2947,6 +2943,7 @@ msgstr "禁止登录时间间隔"
|
||||||
msgid ""
|
msgid ""
|
||||||
"Unit: minute, If the user has failed to log in for a limited number of "
|
"Unit: minute, If the user has failed to log in for a limited number of "
|
||||||
"times, no login is allowed during this time interval."
|
"times, no login is allowed during this time interval."
|
||||||
|
|
||||||
msgstr "单位:分, 当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录"
|
msgstr "单位:分, 当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录"
|
||||||
|
|
||||||
#: settings/serializers/security.py:45
|
#: settings/serializers/security.py:45
|
||||||
|
@ -4311,7 +4308,7 @@ msgstr "工单受理人"
|
||||||
|
|
||||||
#: tickets/models/ticket.py:45
|
#: tickets/models/ticket.py:45
|
||||||
msgid "Title"
|
msgid "Title"
|
||||||
msgstr "标题"
|
msgstr ""
|
||||||
|
|
||||||
#: tickets/models/ticket.py:53
|
#: tickets/models/ticket.py:53
|
||||||
msgid "State"
|
msgid "State"
|
||||||
|
@ -4624,8 +4621,9 @@ msgstr "两次密码不一致"
|
||||||
msgid "Is first login"
|
msgid "Is first login"
|
||||||
msgstr "首次登录"
|
msgstr "首次登录"
|
||||||
|
|
||||||
#: users/serializers/user.py:22 xpack/plugins/change_auth_plan/models.py:65
|
#: users/serializers/user.py:22
|
||||||
#: xpack/plugins/change_auth_plan/serializers.py:33
|
#: xpack/plugins/change_auth_plan/models/base.py:32
|
||||||
|
#: xpack/plugins/change_auth_plan/serializers/base.py:24
|
||||||
msgid "Password strategy"
|
msgid "Password strategy"
|
||||||
msgstr "密码策略"
|
msgstr "密码策略"
|
||||||
|
|
||||||
|
@ -5263,84 +5261,111 @@ msgstr "* 新密码不能是最近 {} 次的密码"
|
||||||
msgid "Reset password success, return to login page"
|
msgid "Reset password success, return to login page"
|
||||||
msgstr "重置密码成功,返回到登录页面"
|
msgstr "重置密码成功,返回到登录页面"
|
||||||
|
|
||||||
|
#: xpack/plugins/change_auth_plan/api/asset.py:83
|
||||||
|
#: xpack/plugins/change_auth_plan/api/asset.py:141
|
||||||
|
msgid "The parameter 'action' must be [{}]"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/meta.py:9
|
#: xpack/plugins/change_auth_plan/meta.py:9
|
||||||
#: xpack/plugins/change_auth_plan/models.py:100
|
#: xpack/plugins/change_auth_plan/models/asset.py:63
|
||||||
#: xpack/plugins/change_auth_plan/models.py:201
|
#: xpack/plugins/change_auth_plan/models/asset.py:119
|
||||||
msgid "Change auth plan"
|
msgid "Change auth plan"
|
||||||
msgstr "改密计划"
|
msgstr "改密计划"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:40
|
#: xpack/plugins/change_auth_plan/models/app.py:41
|
||||||
msgid "Custom password"
|
#: xpack/plugins/change_auth_plan/models/app.py:90
|
||||||
msgstr "自定义密码"
|
msgid "Database Change auth plan"
|
||||||
|
msgstr "改密计划"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:41
|
#: xpack/plugins/change_auth_plan/models/app.py:94
|
||||||
msgid "All assets use the same random password"
|
#: xpack/plugins/change_auth_plan/models/app.py:146
|
||||||
msgstr "所有资产使用相同的随机密码"
|
msgid "Database Change auth plan execution"
|
||||||
|
msgstr "改密计划执行"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:42
|
#: xpack/plugins/change_auth_plan/models/app.py:142
|
||||||
msgid "All assets use different random password"
|
msgid "SystemUser"
|
||||||
msgstr "所有资产使用不同的随机密码"
|
msgstr "系统用户"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:46
|
#: xpack/plugins/change_auth_plan/models/app.py:151
|
||||||
|
msgid "Database Change auth plan task"
|
||||||
|
msgstr "改密计划任务"
|
||||||
|
|
||||||
|
#: xpack/plugins/change_auth_plan/models/asset.py:30
|
||||||
msgid "Append SSH KEY"
|
msgid "Append SSH KEY"
|
||||||
msgstr "追加新密钥"
|
msgstr "追加新密钥"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:47
|
#: xpack/plugins/change_auth_plan/models/asset.py:31
|
||||||
msgid "Empty and append SSH KEY"
|
msgid "Empty and append SSH KEY"
|
||||||
msgstr "清空所有密钥再追加新密钥"
|
msgstr "清空所有密钥再追加新密钥"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:48
|
#: xpack/plugins/change_auth_plan/models/asset.py:32
|
||||||
msgid "Empty current user and append SSH KEY"
|
msgid "Empty current user and append SSH KEY"
|
||||||
msgstr "清空当前账号密钥再追加新密钥"
|
msgstr "清空当前账号密钥再追加新密钥"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:69
|
#: xpack/plugins/change_auth_plan/models/asset.py:50
|
||||||
msgid "Password rules"
|
#: xpack/plugins/change_auth_plan/serializers/asset.py:34
|
||||||
msgstr "密码规则"
|
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:78
|
|
||||||
#: xpack/plugins/change_auth_plan/serializers.py:35
|
|
||||||
msgid "SSH Key strategy"
|
msgid "SSH Key strategy"
|
||||||
msgstr "SSH Key 策略"
|
msgstr "SSH Key 策略"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:189
|
#: xpack/plugins/change_auth_plan/models/asset.py:130
|
||||||
msgid "Manual trigger"
|
#: xpack/plugins/change_auth_plan/models/asset.py:206
|
||||||
msgstr "手动触发"
|
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:190
|
|
||||||
msgid "Timing trigger"
|
|
||||||
msgstr "定时触发"
|
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:204
|
|
||||||
msgid "Change auth plan snapshot"
|
|
||||||
msgstr "改密计划快照"
|
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:218
|
|
||||||
#: xpack/plugins/change_auth_plan/serializers.py:166
|
|
||||||
msgid "Trigger mode"
|
|
||||||
msgstr "触发模式"
|
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:223
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:329
|
|
||||||
msgid "Change auth plan execution"
|
msgid "Change auth plan execution"
|
||||||
msgstr "改密计划执行"
|
msgstr "改密计划执行"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:302
|
#: xpack/plugins/change_auth_plan/models/asset.py:213
|
||||||
|
msgid "Change auth plan task"
|
||||||
|
msgstr "改密计划任务"
|
||||||
|
|
||||||
|
#: xpack/plugins/change_auth_plan/models/base.py:24
|
||||||
|
msgid "Custom password"
|
||||||
|
msgstr "自定义密码"
|
||||||
|
|
||||||
|
#: xpack/plugins/change_auth_plan/models/base.py:25
|
||||||
|
msgid "All assets use the same random password"
|
||||||
|
msgstr "使用相同的随机密码"
|
||||||
|
|
||||||
|
#: xpack/plugins/change_auth_plan/models/base.py:26
|
||||||
|
msgid "All assets use different random password"
|
||||||
|
msgstr "使用不同的随机密码"
|
||||||
|
|
||||||
|
#: xpack/plugins/change_auth_plan/models/base.py:36
|
||||||
|
msgid "Password rules"
|
||||||
|
msgstr "密码规则"
|
||||||
|
|
||||||
|
#: xpack/plugins/change_auth_plan/models/base.py:100
|
||||||
|
msgid "Manual trigger"
|
||||||
|
msgstr "手动触发"
|
||||||
|
|
||||||
|
#: xpack/plugins/change_auth_plan/models/base.py:101
|
||||||
|
msgid "Timing trigger"
|
||||||
|
msgstr "定时触发"
|
||||||
|
|
||||||
|
#: xpack/plugins/change_auth_plan/models/base.py:111
|
||||||
|
msgid "Change auth plan snapshot"
|
||||||
|
msgstr "改密计划快照"
|
||||||
|
|
||||||
|
#: xpack/plugins/change_auth_plan/models/base.py:118
|
||||||
|
#: xpack/plugins/change_auth_plan/serializers/base.py:70
|
||||||
|
msgid "Trigger mode"
|
||||||
|
msgstr "触发模式"
|
||||||
|
|
||||||
|
#: xpack/plugins/change_auth_plan/models/base.py:173
|
||||||
msgid "Ready"
|
msgid "Ready"
|
||||||
msgstr "准备"
|
msgstr "准备"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:303
|
#: xpack/plugins/change_auth_plan/models/base.py:174
|
||||||
msgid "Preflight check"
|
msgid "Preflight check"
|
||||||
msgstr "改密前的校验"
|
msgstr "改密前的校验"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:304
|
#: xpack/plugins/change_auth_plan/models/base.py:175
|
||||||
msgid "Change auth"
|
msgid "Change auth"
|
||||||
msgstr "执行改密"
|
msgstr "执行改密"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:305
|
#: xpack/plugins/change_auth_plan/models/base.py:176
|
||||||
msgid "Verify auth"
|
msgid "Verify auth"
|
||||||
msgstr "验证密码/密钥"
|
msgstr "验证密码/密钥"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:306
|
#: xpack/plugins/change_auth_plan/models/base.py:177
|
||||||
msgid "Keep auth"
|
msgid "Keep auth"
|
||||||
msgstr "保存密码/密钥"
|
msgstr "保存密码/密钥"
|
||||||
|
|
||||||
|
@ -5348,55 +5373,51 @@ msgstr "保存密码/密钥"
|
||||||
msgid "Step"
|
msgid "Step"
|
||||||
msgstr "步骤"
|
msgstr "步骤"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/models.py:350
|
#: xpack/plugins/change_auth_plan/serializers/asset.py:31
|
||||||
msgid "Change auth plan task"
|
|
||||||
msgstr "改密计划任务"
|
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/serializers.py:29
|
|
||||||
msgid "Change Password"
|
msgid "Change Password"
|
||||||
msgstr "修改密码"
|
msgstr "修改密码"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/serializers.py:30
|
#: xpack/plugins/change_auth_plan/serializers/asset.py:32
|
||||||
msgid "Change SSH Key"
|
msgid "Change SSH Key"
|
||||||
msgstr "修改密钥"
|
msgstr "修改密钥"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/serializers.py:61
|
#: xpack/plugins/change_auth_plan/serializers/asset.py:65
|
||||||
msgid "Run times"
|
|
||||||
msgstr "执行次数"
|
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/serializers.py:79
|
|
||||||
msgid "Require password strategy perform setting"
|
msgid "Require password strategy perform setting"
|
||||||
msgstr "需要密码策略执行设置"
|
msgstr "需要密码策略执行设置"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/serializers.py:82
|
#: xpack/plugins/change_auth_plan/serializers/asset.py:68
|
||||||
msgid "Require password perform setting"
|
msgid "Require password perform setting"
|
||||||
msgstr "需要密码执行设置"
|
msgstr "需要密码执行设置"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/serializers.py:85
|
#: xpack/plugins/change_auth_plan/serializers/asset.py:71
|
||||||
msgid "Require password rule perform setting"
|
msgid "Require password rule perform setting"
|
||||||
msgstr "需要密码规则执行设置"
|
msgstr "需要密码规则执行设置"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/serializers.py:97
|
#: xpack/plugins/change_auth_plan/serializers/asset.py:87
|
||||||
msgid "* Please enter the correct password length"
|
|
||||||
msgstr "* 请输入正确的密码长度"
|
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/serializers.py:100
|
|
||||||
msgid "* Password length range 6-30 bits"
|
|
||||||
msgstr "* 密码长度范围 6-30 位"
|
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/serializers.py:118
|
|
||||||
msgid "Require ssh key strategy or ssh key perform setting"
|
msgid "Require ssh key strategy or ssh key perform setting"
|
||||||
msgstr "需要ssh密钥策略或ssh密钥执行设置"
|
msgstr "需要ssh密钥策略或ssh密钥执行设置"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/utils.py:485
|
#: xpack/plugins/change_auth_plan/serializers/base.py:43
|
||||||
|
msgid "Run times"
|
||||||
|
msgstr "执行次数"
|
||||||
|
|
||||||
|
#: xpack/plugins/change_auth_plan/serializers/base.py:54
|
||||||
|
msgid "* Please enter the correct password length"
|
||||||
|
msgstr "* 请输入正确的密码长度"
|
||||||
|
|
||||||
|
#: xpack/plugins/change_auth_plan/serializers/base.py:57
|
||||||
|
msgid "* Password length range 6-30 bits"
|
||||||
|
msgstr "* 密码长度范围 6-30 位"
|
||||||
|
|
||||||
|
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:248
|
||||||
msgid "Invalid/incorrect password"
|
msgid "Invalid/incorrect password"
|
||||||
msgstr "无效/错误 密码"
|
msgstr "无效/错误 密码"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/utils.py:487
|
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:250
|
||||||
msgid "Failed to connect to the host"
|
msgid "Failed to connect to the host"
|
||||||
msgstr "连接主机失败"
|
msgstr "连接主机失败"
|
||||||
|
|
||||||
#: xpack/plugins/change_auth_plan/utils.py:489
|
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:252
|
||||||
msgid "Data could not be sent to remote"
|
msgid "Data could not be sent to remote"
|
||||||
msgstr "无法将数据发送到远程"
|
msgstr "无法将数据发送到远程"
|
||||||
|
|
||||||
|
@ -5492,10 +5513,6 @@ msgstr "云服务商"
|
||||||
msgid "Cloud account"
|
msgid "Cloud account"
|
||||||
msgstr "云账号"
|
msgstr "云账号"
|
||||||
|
|
||||||
#: xpack/plugins/cloud/models.py:82 xpack/plugins/cloud/serializers.py:207
|
|
||||||
msgid "Account"
|
|
||||||
msgstr "账户"
|
|
||||||
|
|
||||||
#: xpack/plugins/cloud/models.py:85 xpack/plugins/cloud/serializers.py:179
|
#: xpack/plugins/cloud/models.py:85 xpack/plugins/cloud/serializers.py:179
|
||||||
msgid "Regions"
|
msgid "Regions"
|
||||||
msgstr "地域"
|
msgstr "地域"
|
||||||
|
@ -5816,135 +5833,3 @@ msgstr "旗舰版"
|
||||||
#: xpack/plugins/license/models.py:77
|
#: xpack/plugins/license/models.py:77
|
||||||
msgid "Community edition"
|
msgid "Community edition"
|
||||||
msgstr "社区版"
|
msgstr "社区版"
|
||||||
|
|
||||||
#~ msgid "Approval level"
|
|
||||||
#~ msgstr "同意"
|
|
||||||
|
|
||||||
#~ msgid "Login challenge enabled"
|
|
||||||
#~ msgstr "登录页面开启CHALLENGE输入框"
|
|
||||||
|
|
||||||
#~ msgid "Login captcha enabled"
|
|
||||||
#~ msgstr "登录页面开启验证码"
|
|
||||||
|
|
||||||
#~ msgid "Insecure command level"
|
|
||||||
#~ msgstr "不安全命令等级"
|
|
||||||
|
|
||||||
#~ msgid "Encrypt password"
|
|
||||||
#~ msgstr "密码加密"
|
|
||||||
|
|
||||||
#~ msgid "Create User"
|
|
||||||
#~ msgstr "创建用户"
|
|
||||||
|
|
||||||
#~ msgid "Apply attr to use"
|
|
||||||
#~ msgstr "申请可用属性"
|
|
||||||
|
|
||||||
#~ msgid "User login only in users"
|
|
||||||
#~ msgstr "仅在用户列表中用户认证"
|
|
||||||
|
|
||||||
#~ msgid "Approved applications"
|
|
||||||
#~ msgstr "批准的应用"
|
|
||||||
|
|
||||||
#~ msgid "Approved system users"
|
|
||||||
#~ msgstr "批准的系统用户"
|
|
||||||
|
|
||||||
#~ msgid "Approved date expired"
|
|
||||||
#~ msgstr "批准的失效日期"
|
|
||||||
|
|
||||||
#~ msgid "Applied IP group"
|
|
||||||
#~ msgstr "申请的IP组"
|
|
||||||
|
|
||||||
#~ msgid "Approved assets"
|
|
||||||
#~ msgstr "批准的资产"
|
|
||||||
|
|
||||||
#~ msgid "Approved actions"
|
|
||||||
#~ msgstr "批准的动作"
|
|
||||||
|
|
||||||
#~ msgid "Ticket action"
|
|
||||||
#~ msgstr "工单动作"
|
|
||||||
|
|
||||||
#~ msgid "Ticket processor"
|
|
||||||
#~ msgstr "工单处理人"
|
|
||||||
|
|
||||||
#~ msgid "Processor display"
|
|
||||||
#~ msgstr "处理人名称"
|
|
||||||
|
|
||||||
#~ msgid "Application group"
|
|
||||||
#~ msgstr "应用组"
|
|
||||||
|
|
||||||
#~ msgid "System user group"
|
|
||||||
#~ msgstr "系统用户组"
|
|
||||||
|
|
||||||
#~ msgid "Permission name"
|
|
||||||
#~ msgstr "授权名称"
|
|
||||||
|
|
||||||
#~ msgid "Approve applications"
|
|
||||||
#~ msgstr "批准的应用"
|
|
||||||
|
|
||||||
#~ msgid "No `Application` are found under Organization `{}`"
|
|
||||||
#~ msgstr "在组织 `{}` 下没有发现 `应用`"
|
|
||||||
|
|
||||||
#~ msgid "No `SystemUser` are found under Organization `{}`"
|
|
||||||
#~ msgstr "在组织 `{}` 下没有发现 `系统用户`"
|
|
||||||
|
|
||||||
#~ msgid "IP group"
|
|
||||||
#~ msgstr "IP组"
|
|
||||||
|
|
||||||
#~ msgid "Hostname group"
|
|
||||||
#~ msgstr "主机名组"
|
|
||||||
|
|
||||||
#~ msgid "Approve assets"
|
|
||||||
#~ msgstr "批准的资产"
|
|
||||||
|
|
||||||
#~ msgid "No `Asset` are found under Organization `{}`"
|
|
||||||
#~ msgstr "在组织 `{}` 下没有发现 `资产`"
|
|
||||||
|
|
||||||
#~ msgid "Action display"
|
|
||||||
#~ msgstr "动作名称"
|
|
||||||
|
|
||||||
#~ msgid "None of the assignees belong to Organization `{}` admins"
|
|
||||||
#~ msgstr "所有受理人都不属于组织 `{}` 下的管理员"
|
|
||||||
|
|
||||||
#~ msgid "* Please enter custom password"
|
|
||||||
#~ msgstr "* 请输入自定义密码"
|
|
||||||
|
|
||||||
#~ msgid "FeiShu Error, Please contact your system administrator"
|
|
||||||
#~ msgstr "飞书错误,请联系系统管理员"
|
|
||||||
|
|
||||||
#~ msgid "Category(Display)"
|
|
||||||
#~ msgstr "类别 (显示名称)"
|
|
||||||
|
|
||||||
#~ msgid "Type(Dispaly)"
|
|
||||||
#~ msgstr "类型 (显示名称)"
|
|
||||||
|
|
||||||
#~ msgid "Users name"
|
|
||||||
#~ msgstr "用户名"
|
|
||||||
|
|
||||||
#~ msgid "User groups name"
|
|
||||||
#~ msgstr "用户组名称"
|
|
||||||
|
|
||||||
#~ msgid "Assets name"
|
|
||||||
#~ msgstr "资产名称"
|
|
||||||
|
|
||||||
#~ msgid "System users name"
|
|
||||||
#~ msgstr "系统用户名称"
|
|
||||||
|
|
||||||
#~ msgid "Admin user MFA auth"
|
|
||||||
#~ msgstr "所有管理员启用 MFA"
|
|
||||||
|
|
||||||
#~ msgid "Admin user enable MFA"
|
|
||||||
#~ msgstr "强制管理员启用 MFA"
|
|
||||||
|
|
||||||
#~ msgid "Password update"
|
|
||||||
#~ msgstr "密码更新"
|
|
||||||
|
|
||||||
#~ msgid "All user enable MFA"
|
|
||||||
#~ msgstr "强制所有用户启用 MFA"
|
|
||||||
|
|
||||||
#~ msgid "Application category"
|
|
||||||
#~ msgstr "应用类别"
|
|
||||||
|
|
||||||
#~ msgid "Application type"
|
|
||||||
#~ msgstr "应用类型"
|
|
||||||
|
|
||||||
#~ msgid "Trigger"
|
|
||||||
#~ msgstr "触发"
|
|
||||||
|
|
|
@ -19,8 +19,8 @@ class UserGroupGrantedApplicationsApi(CommonApiMixin, ListAPIView):
|
||||||
获取用户组直接授权的应用
|
获取用户组直接授权的应用
|
||||||
"""
|
"""
|
||||||
permission_classes = (IsOrgAdminOrAppUser,)
|
permission_classes = (IsOrgAdminOrAppUser,)
|
||||||
serializer_class = serializers.ApplicationGrantedSerializer
|
serializer_class = serializers.AppGrantedSerializer
|
||||||
only_fields = serializers.ApplicationGrantedSerializer.Meta.only_fields
|
only_fields = serializers.AppGrantedSerializer.Meta.only_fields
|
||||||
filterset_fields = ['id', 'name', 'category', 'type', 'comment']
|
filterset_fields = ['id', 'name', 'category', 'type', 'comment']
|
||||||
search_fields = ['name', 'comment']
|
search_fields = ['name', 'comment']
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,8 @@ __all__ = [
|
||||||
|
|
||||||
|
|
||||||
class AllGrantedApplicationsMixin(CommonApiMixin, ListAPIView):
|
class AllGrantedApplicationsMixin(CommonApiMixin, ListAPIView):
|
||||||
only_fields = serializers.ApplicationGrantedSerializer.Meta.only_fields
|
only_fields = serializers.AppGrantedSerializer.Meta.only_fields
|
||||||
serializer_class = serializers.ApplicationGrantedSerializer
|
serializer_class = serializers.AppGrantedSerializer
|
||||||
filterset_fields = {
|
filterset_fields = {
|
||||||
'id': ['exact'],
|
'id': ['exact'],
|
||||||
'name': ['exact'],
|
'name': ['exact'],
|
||||||
|
|
|
@ -6,10 +6,10 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from assets.models import SystemUser
|
from assets.models import SystemUser
|
||||||
from applications.models import Application
|
from applications.models import Application
|
||||||
from applications.serializers import ApplicationSerializerMixin
|
from applications.serializers import AppSerializerMixin
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'ApplicationGrantedSerializer', 'ApplicationSystemUserSerializer'
|
'AppGrantedSerializer', 'ApplicationSystemUserSerializer'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ class ApplicationSystemUserSerializer(serializers.ModelSerializer):
|
||||||
read_only_fields = fields
|
read_only_fields = fields
|
||||||
|
|
||||||
|
|
||||||
class ApplicationGrantedSerializer(ApplicationSerializerMixin, serializers.ModelSerializer):
|
class AppGrantedSerializer(AppSerializerMixin, serializers.ModelSerializer):
|
||||||
"""
|
"""
|
||||||
被授权应用的数据结构
|
被授权应用的数据结构
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
from . import common
|
from . import asset_permission
|
||||||
|
from . import app_permission
|
||||||
from . import refresh_perms
|
from . import refresh_perms
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
from django.db.models.signals import m2m_changed
|
||||||
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
from users.models import User, UserGroup
|
||||||
|
from assets.models import SystemUser
|
||||||
|
from applications.models import Application
|
||||||
|
from common.utils import get_logger
|
||||||
|
from common.exceptions import M2MReverseNotAllowed
|
||||||
|
from common.decorator import on_transaction_commit
|
||||||
|
from common.const.signals import POST_ADD
|
||||||
|
from perms.models import ApplicationPermission
|
||||||
|
from applications.models import Account as AppAccount
|
||||||
|
|
||||||
|
|
||||||
|
logger = get_logger(__file__)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(m2m_changed, sender=ApplicationPermission.applications.through)
|
||||||
|
@on_transaction_commit
|
||||||
|
def on_app_permission_applications_changed(sender, instance, action, reverse, pk_set, **kwargs):
|
||||||
|
if reverse:
|
||||||
|
raise M2MReverseNotAllowed
|
||||||
|
if action != POST_ADD:
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.debug("Application permission applications change signal received")
|
||||||
|
system_users = instance.system_users.all()
|
||||||
|
set_remote_app_asset_system_users_if_need(instance, system_users=system_users)
|
||||||
|
|
||||||
|
apps = Application.objects.filter(pk__in=pk_set)
|
||||||
|
set_app_accounts(apps, system_users)
|
||||||
|
|
||||||
|
|
||||||
|
def set_app_accounts(apps, system_users):
|
||||||
|
for app, system_user in itertools.product(apps, system_users):
|
||||||
|
AppAccount.objects.get_or_create(
|
||||||
|
defaults={'app': app, 'systemuser': system_user},
|
||||||
|
app=app, systemuser=system_user
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def set_remote_app_asset_system_users_if_need(instance: ApplicationPermission, system_users=None,
|
||||||
|
users=None, groups=None):
|
||||||
|
if not instance.category_remote_app:
|
||||||
|
return
|
||||||
|
|
||||||
|
attrs = instance.applications.all().values_list('attrs', flat=True)
|
||||||
|
asset_ids = [attr['asset'] for attr in attrs if attr.get('asset')]
|
||||||
|
if not asset_ids:
|
||||||
|
return
|
||||||
|
|
||||||
|
system_users = system_users or instance.system_users.all()
|
||||||
|
for system_user in system_users:
|
||||||
|
system_user.assets.add(*asset_ids)
|
||||||
|
|
||||||
|
if system_user.username_same_with_user:
|
||||||
|
users = users or instance.users.all()
|
||||||
|
groups = groups or instance.user_groups.all()
|
||||||
|
system_user.groups.add(*groups)
|
||||||
|
system_user.users.add(*users)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(m2m_changed, sender=ApplicationPermission.system_users.through)
|
||||||
|
@on_transaction_commit
|
||||||
|
def on_app_permission_system_users_changed(sender, instance, action, reverse, pk_set, **kwargs):
|
||||||
|
if reverse:
|
||||||
|
raise M2MReverseNotAllowed
|
||||||
|
if action != POST_ADD:
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.debug("Application permission system_users change signal received")
|
||||||
|
system_users = SystemUser.objects.filter(pk__in=pk_set)
|
||||||
|
|
||||||
|
set_remote_app_asset_system_users_if_need(instance, system_users=system_users)
|
||||||
|
apps = instance.applications.all()
|
||||||
|
set_app_accounts(apps, system_users)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(m2m_changed, sender=ApplicationPermission.users.through)
|
||||||
|
@on_transaction_commit
|
||||||
|
def on_app_permission_users_changed(sender, instance, action, reverse, pk_set, **kwargs):
|
||||||
|
if reverse:
|
||||||
|
raise M2MReverseNotAllowed
|
||||||
|
if action != POST_ADD:
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.debug("Application permission users change signal received")
|
||||||
|
users = User.objects.filter(pk__in=pk_set)
|
||||||
|
set_remote_app_asset_system_users_if_need(instance, users=users)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(m2m_changed, sender=ApplicationPermission.user_groups.through)
|
||||||
|
@on_transaction_commit
|
||||||
|
def on_app_permission_user_groups_changed(sender, instance, action, reverse, pk_set, **kwargs):
|
||||||
|
if reverse:
|
||||||
|
raise M2MReverseNotAllowed
|
||||||
|
if action != POST_ADD:
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.debug("Application permission user groups change signal received")
|
||||||
|
groups = UserGroup.objects.filter(pk__in=pk_set)
|
||||||
|
set_remote_app_asset_system_users_if_need(instance, groups=groups)
|
|
@ -3,19 +3,20 @@
|
||||||
from django.db.models.signals import m2m_changed
|
from django.db.models.signals import m2m_changed
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from users.models import User, UserGroup
|
from users.models import User
|
||||||
from assets.models import SystemUser
|
from assets.models import SystemUser
|
||||||
from applications.models import Application
|
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
|
from common.decorator import on_transaction_commit
|
||||||
from common.exceptions import M2MReverseNotAllowed
|
from common.exceptions import M2MReverseNotAllowed
|
||||||
from common.const.signals import POST_ADD
|
from common.const.signals import POST_ADD
|
||||||
from perms.models import AssetPermission, ApplicationPermission
|
from perms.models import AssetPermission
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=User.groups.through)
|
@receiver(m2m_changed, sender=User.groups.through)
|
||||||
|
@on_transaction_commit
|
||||||
def on_user_groups_change(sender, instance, action, reverse, pk_set, **kwargs):
|
def on_user_groups_change(sender, instance, action, reverse, pk_set, **kwargs):
|
||||||
"""
|
"""
|
||||||
UserGroup 增加 User 时,增加的 User 需要与 UserGroup 关联的动态系统用户相关联
|
UserGroup 增加 User 时,增加的 User 需要与 UserGroup 关联的动态系统用户相关联
|
||||||
|
@ -39,12 +40,13 @@ def on_user_groups_change(sender, instance, action, reverse, pk_set, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=AssetPermission.nodes.through)
|
@receiver(m2m_changed, sender=AssetPermission.nodes.through)
|
||||||
|
@on_transaction_commit
|
||||||
def on_permission_nodes_changed(instance, action, reverse, pk_set, model, **kwargs):
|
def on_permission_nodes_changed(instance, action, reverse, pk_set, model, **kwargs):
|
||||||
if reverse:
|
if reverse:
|
||||||
raise M2MReverseNotAllowed
|
raise M2MReverseNotAllowed
|
||||||
|
|
||||||
if action != POST_ADD:
|
if action != POST_ADD:
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.debug("Asset permission nodes change signal received")
|
logger.debug("Asset permission nodes change signal received")
|
||||||
nodes = model.objects.filter(pk__in=pk_set)
|
nodes = model.objects.filter(pk__in=pk_set)
|
||||||
system_users = instance.system_users.all()
|
system_users = instance.system_users.all()
|
||||||
|
@ -55,12 +57,13 @@ def on_permission_nodes_changed(instance, action, reverse, pk_set, model, **kwar
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=AssetPermission.assets.through)
|
@receiver(m2m_changed, sender=AssetPermission.assets.through)
|
||||||
|
@on_transaction_commit
|
||||||
def on_permission_assets_changed(instance, action, reverse, pk_set, model, **kwargs):
|
def on_permission_assets_changed(instance, action, reverse, pk_set, model, **kwargs):
|
||||||
if reverse:
|
if reverse:
|
||||||
raise M2MReverseNotAllowed
|
raise M2MReverseNotAllowed
|
||||||
|
|
||||||
if action != POST_ADD:
|
if action != POST_ADD:
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.debug("Asset permission assets change signal received")
|
logger.debug("Asset permission assets change signal received")
|
||||||
assets = model.objects.filter(pk__in=pk_set)
|
assets = model.objects.filter(pk__in=pk_set)
|
||||||
|
|
||||||
|
@ -71,33 +74,38 @@ def on_permission_assets_changed(instance, action, reverse, pk_set, model, **kwa
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=AssetPermission.system_users.through)
|
@receiver(m2m_changed, sender=AssetPermission.system_users.through)
|
||||||
|
@on_transaction_commit
|
||||||
def on_asset_permission_system_users_changed(instance, action, reverse, **kwargs):
|
def on_asset_permission_system_users_changed(instance, action, reverse, **kwargs):
|
||||||
if reverse:
|
if reverse:
|
||||||
raise M2MReverseNotAllowed
|
raise M2MReverseNotAllowed
|
||||||
|
|
||||||
if action != POST_ADD:
|
if action != POST_ADD:
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.debug("Asset permission system_users change signal received")
|
logger.debug("Asset permission system_users change signal received")
|
||||||
system_users = kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
|
system_users = kwargs['model'].objects.filter(pk__in=kwargs['pk_set'])
|
||||||
assets = instance.assets.all().values_list('id', flat=True)
|
assets = instance.assets.all().values_list('id', flat=True)
|
||||||
nodes = instance.nodes.all().values_list('id', flat=True)
|
nodes = instance.nodes.all().values_list('id', flat=True)
|
||||||
users = instance.users.all().values_list('id', flat=True)
|
|
||||||
groups = instance.user_groups.all().values_list('id', flat=True)
|
|
||||||
for system_user in system_users:
|
for system_user in system_users:
|
||||||
system_user.nodes.add(*tuple(nodes))
|
system_user.nodes.add(*tuple(nodes))
|
||||||
system_user.assets.add(*tuple(assets))
|
system_user.assets.add(*tuple(assets))
|
||||||
|
|
||||||
|
# 动态系统用户,需要关联用户和用户组了
|
||||||
if system_user.username_same_with_user:
|
if system_user.username_same_with_user:
|
||||||
|
users = instance.users.all().values_list('id', flat=True)
|
||||||
|
groups = instance.user_groups.all().values_list('id', flat=True)
|
||||||
system_user.groups.add(*tuple(groups))
|
system_user.groups.add(*tuple(groups))
|
||||||
system_user.users.add(*tuple(users))
|
system_user.users.add(*tuple(users))
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=AssetPermission.users.through)
|
@receiver(m2m_changed, sender=AssetPermission.users.through)
|
||||||
|
@on_transaction_commit
|
||||||
def on_asset_permission_users_changed(instance, action, reverse, pk_set, model, **kwargs):
|
def on_asset_permission_users_changed(instance, action, reverse, pk_set, model, **kwargs):
|
||||||
if reverse:
|
if reverse:
|
||||||
raise M2MReverseNotAllowed
|
raise M2MReverseNotAllowed
|
||||||
|
|
||||||
if action != POST_ADD:
|
if action != POST_ADD:
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.debug("Asset permission users change signal received")
|
logger.debug("Asset permission users change signal received")
|
||||||
users = model.objects.filter(pk__in=pk_set)
|
users = model.objects.filter(pk__in=pk_set)
|
||||||
system_users = instance.system_users.all()
|
system_users = instance.system_users.all()
|
||||||
|
@ -109,13 +117,13 @@ def on_asset_permission_users_changed(instance, action, reverse, pk_set, model,
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=AssetPermission.user_groups.through)
|
@receiver(m2m_changed, sender=AssetPermission.user_groups.through)
|
||||||
def on_asset_permission_user_groups_changed(instance, action, pk_set, model,
|
@on_transaction_commit
|
||||||
reverse, **kwargs):
|
def on_asset_permission_user_groups_changed(instance, action, pk_set, model, reverse, **kwargs):
|
||||||
if reverse:
|
if reverse:
|
||||||
raise M2MReverseNotAllowed
|
raise M2MReverseNotAllowed
|
||||||
|
|
||||||
if action != POST_ADD:
|
if action != POST_ADD:
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.debug("Asset permission user groups change signal received")
|
logger.debug("Asset permission user groups change signal received")
|
||||||
groups = model.objects.filter(pk__in=pk_set)
|
groups = model.objects.filter(pk__in=pk_set)
|
||||||
system_users = instance.system_users.all()
|
system_users = instance.system_users.all()
|
||||||
|
@ -126,87 +134,6 @@ def on_asset_permission_user_groups_changed(instance, action, pk_set, model,
|
||||||
system_user.groups.add(*tuple(groups))
|
system_user.groups.add(*tuple(groups))
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=ApplicationPermission.system_users.through)
|
|
||||||
def on_application_permission_system_users_changed(sender, instance: ApplicationPermission, action, reverse, pk_set, **kwargs):
|
|
||||||
if reverse:
|
|
||||||
raise M2MReverseNotAllowed
|
|
||||||
if not instance.category_remote_app:
|
|
||||||
return
|
|
||||||
if action != POST_ADD:
|
|
||||||
return
|
|
||||||
|
|
||||||
system_users = SystemUser.objects.filter(pk__in=pk_set)
|
|
||||||
logger.debug("Application permission system_users change signal received")
|
|
||||||
attrs = instance.applications.all().values_list('attrs', flat=True)
|
|
||||||
|
|
||||||
asset_ids = [attr['asset'] for attr in attrs if attr.get('asset')]
|
|
||||||
if not asset_ids:
|
|
||||||
return
|
|
||||||
|
|
||||||
for system_user in system_users:
|
|
||||||
system_user.assets.add(*asset_ids)
|
|
||||||
if system_user.username_same_with_user:
|
|
||||||
user_ids = instance.users.all().values_list('id', flat=True)
|
|
||||||
group_ids = instance.user_groups.all().values_list('id', flat=True)
|
|
||||||
system_user.groups.add(*group_ids)
|
|
||||||
system_user.users.add(*user_ids)
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=ApplicationPermission.users.through)
|
|
||||||
def on_application_permission_users_changed(sender, instance, action, reverse, pk_set, **kwargs):
|
|
||||||
if reverse:
|
|
||||||
raise M2MReverseNotAllowed
|
|
||||||
|
|
||||||
if not instance.category_remote_app:
|
|
||||||
return
|
|
||||||
|
|
||||||
if action != POST_ADD:
|
|
||||||
return
|
|
||||||
|
|
||||||
logger.debug("Application permission users change signal received")
|
|
||||||
user_ids = User.objects.filter(pk__in=pk_set).values_list('id', flat=True)
|
|
||||||
system_users = instance.system_users.all()
|
|
||||||
|
|
||||||
for system_user in system_users:
|
|
||||||
if system_user.username_same_with_user:
|
|
||||||
system_user.users.add(*user_ids)
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=ApplicationPermission.user_groups.through)
|
|
||||||
def on_application_permission_user_groups_changed(sender, instance, action, reverse, pk_set, **kwargs):
|
|
||||||
if reverse:
|
|
||||||
raise M2MReverseNotAllowed
|
|
||||||
if not instance.category_remote_app:
|
|
||||||
return
|
|
||||||
if action != POST_ADD:
|
|
||||||
return
|
|
||||||
|
|
||||||
logger.debug("Application permission user groups change signal received")
|
|
||||||
group_ids = UserGroup.objects.filter(pk__in=pk_set).values_list('id', flat=True)
|
|
||||||
system_users = instance.system_users.all()
|
|
||||||
|
|
||||||
for system_user in system_users:
|
|
||||||
if system_user.username_same_with_user:
|
|
||||||
system_user.groups.add(*group_ids)
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=ApplicationPermission.applications.through)
|
|
||||||
def on_application_permission_applications_changed(sender, instance, action, reverse, pk_set, **kwargs):
|
|
||||||
if reverse:
|
|
||||||
raise M2MReverseNotAllowed
|
|
||||||
|
|
||||||
if not instance.category_remote_app:
|
|
||||||
return
|
|
||||||
|
|
||||||
if action != POST_ADD:
|
|
||||||
return
|
|
||||||
|
|
||||||
attrs = Application.objects.filter(id__in=pk_set).values_list('attrs', flat=True)
|
|
||||||
asset_ids = [attr['asset'] for attr in attrs if attr.get('asset')]
|
|
||||||
if not asset_ids:
|
|
||||||
return
|
|
||||||
|
|
||||||
system_users = instance.system_users.all()
|
|
||||||
|
|
||||||
for system_user in system_users:
|
|
||||||
system_user.assets.add(*asset_ids)
|
|
|
@ -115,3 +115,6 @@ azure-mgmt-subscription==1.0.0
|
||||||
qingcloud-sdk==1.2.12
|
qingcloud-sdk==1.2.12
|
||||||
django-simple-history==3.0.0
|
django-simple-history==3.0.0
|
||||||
google-cloud-compute==0.5.0
|
google-cloud-compute==0.5.0
|
||||||
|
PyMySQL==1.0.2
|
||||||
|
cx-Oracle==8.2.1
|
||||||
|
psycopg2-binary==2.9.1
|
||||||
|
|
Loading…
Reference in New Issue