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
fit2cloud-jiangweidong 2021-09-09 04:04:54 -04:00 committed by GitHub
parent 3e51f4d616
commit 905014d441
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 662 additions and 530 deletions

View File

@ -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

View File

@ -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']

View File

@ -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')

View File

@ -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),
),
]

View File

@ -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)
]

View File

@ -1 +1,2 @@
from .application import * from .application import *
from .account import *

View File

@ -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

View File

@ -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

View File

@ -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():

View File

@ -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)

View File

@ -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

View File

@ -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):

View File

@ -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.

View File

@ -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 "触发"

View File

@ -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']

View File

@ -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'],

View File

@ -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):
""" """
被授权应用的数据结构 被授权应用的数据结构
""" """

View File

@ -1,2 +1,3 @@
from . import common from . import asset_permission
from . import app_permission
from . import refresh_perms from . import refresh_perms

View File

@ -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)

View File

@ -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)

View File

@ -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