diff --git a/apps/assets/const.py b/apps/assets/const.py index 64a928f16..87f17b1af 100644 --- a/apps/assets/const.py +++ b/apps/assets/const.py @@ -93,6 +93,7 @@ class DatabaseTypes(PlatformMixin, models.TextChoices): meta[name] = { 'protocols_limit': [name] } + return meta class RemoteAppTypes(PlatformMixin, models.TextChoices): diff --git a/apps/assets/migrations/0097_auto_20220407_1726.py b/apps/assets/migrations/0097_auto_20220407_1726.py index 61d260458..bd08c3ad3 100644 --- a/apps/assets/migrations/0097_auto_20220407_1726.py +++ b/apps/assets/migrations/0097_auto_20220407_1726.py @@ -3,6 +3,14 @@ from django.db import migrations, models +def migrate_platform_type_to_lower(apps, *args): + platform_model = apps.get_model('assets', 'Platform') + platforms = platform_model.objects.all() + for p in platforms: + p.type = p.type.lower() + p.save() + + class Migration(migrations.Migration): dependencies = [ @@ -31,4 +39,5 @@ class Migration(migrations.Migration): name='protocol', field=models.CharField(choices=[('ssh', 'SSH'), ('rdp', 'RDP'), ('telnet', 'Telnet'), ('vnc', 'VNC'), ('mysql', 'MySQL'), ('mariadb', 'MariaDB'), ('oracle', 'Oracle'), ('postgresql', 'PostgreSQL'), ('sqlserver', 'SQLServer'), ('redis', 'Redis'), ('mongodb', 'MongoDB'), ('k8s', 'K8S')], default='ssh', max_length=16, verbose_name='Protocol'), ), + migrations.RunPython(migrate_platform_type_to_lower) ] diff --git a/apps/assets/models/platform.py b/apps/assets/models/platform.py index 04fcd3f68..186da3dd3 100644 --- a/apps/assets/models/platform.py +++ b/apps/assets/models/platform.py @@ -35,13 +35,20 @@ class Platform(models.Model): verbose_name=_("Admin user default") ) - def get_type_meta(self): - meta = Category.platform_meta().get(self.category, {}) - types = dict(AllTypes.category_types())[self.category] - type_meta = types.platform_meta().get(self.type, {}) + @classmethod + def get_type_meta(cls, category, tp): + meta = Category.platform_meta().get(category, {}) + types = dict(AllTypes.category_types()).get(category) + # if not types: + # return {} + types_meta = types.platform_meta() or {} + type_meta = types_meta.get(tp, {}) meta.update(type_meta) return meta + def get_meta(self): + return self.__class__.get_type_meta(self.category, self.type) + @classmethod def default(cls): linux, created = cls.objects.get_or_create( diff --git a/apps/assets/serializers/asset/common.py b/apps/assets/serializers/asset/common.py index 2e4dd3fb9..883a1d0b8 100644 --- a/apps/assets/serializers/asset/common.py +++ b/apps/assets/serializers/asset/common.py @@ -14,11 +14,10 @@ __all__ = [ class ProtocolField(serializers.RegexField): - protocols = '|'.join(dict(Asset.Protocol.choices).keys()) default_error_messages = { - 'invalid': _('Protocol format should {}/{}').format(protocols, '1-65535') + 'invalid': _('Protocol format should {}/{}').format('protocol', '1-65535') } - regex = r'^(%s)/(\d{1,5})$' % protocols + regex = r'^(\w+)/(\d{1,5})$' def __init__(self, *args, **kwargs): super().__init__(self.regex, **kwargs) @@ -43,18 +42,28 @@ def validate_duplicate_protocols(values): class ProtocolsField(serializers.ListField): default_validators = [validate_duplicate_protocols] - def __init__(self, *args, **kwargs): + def __init__(self, protocols=None, *args, **kwargs): + self.choices = [] + self.set_protocols(protocols) kwargs['child'] = ProtocolField() kwargs['allow_null'] = True kwargs['allow_empty'] = True kwargs['min_length'] = 1 - kwargs['max_length'] = 4 + kwargs['max_length'] = 32 super().__init__(*args, **kwargs) + def set_protocols(self, protocols): + if protocols is None: + protocols = [] + self.choices = [(c, c) for c in protocols] + print("Chocies: ", self.choices) + def to_representation(self, value): if not value: return [] - return value.split(' ') + if isinstance(value, str): + return value.split(' ') + return value class AssetSerializer(CategoryDisplayMixin, OrgResourceModelSerializerMixin): @@ -139,7 +148,7 @@ class AssetSerializer(CategoryDisplayMixin, OrgResourceModelSerializerMixin): validated_data["protocol"] = protocol[0] validated_data["port"] = int(protocol[1]) if protocols_data: - validated_data["protocols"] = ' '.join(protocols_data) + validated_data["protocols"] = protocols_data def perform_nodes_display_create(self, instance, nodes_display): if not nodes_display: diff --git a/apps/assets/serializers/platform.py b/apps/assets/serializers/platform.py index 078edee03..44e8ebb88 100644 --- a/apps/assets/serializers/platform.py +++ b/apps/assets/serializers/platform.py @@ -3,7 +3,8 @@ from django.core.validators import RegexValidator from django.utils.translation import gettext_lazy as _ from assets.models import Platform -from assets.const import AllTypes +from assets.serializers.asset import ProtocolsField +from assets.const import Protocol from .mixin import CategoryDisplayMixin __all__ = ['PlatformSerializer'] @@ -11,6 +12,7 @@ __all__ = ['PlatformSerializer'] class PlatformSerializer(CategoryDisplayMixin, serializers.ModelSerializer): meta = serializers.DictField(required=False, allow_null=True, label=_('Meta')) + protocols_default = ProtocolsField(label=_('Protocols'), required=False) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -19,13 +21,43 @@ class PlatformSerializer(CategoryDisplayMixin, serializers.ModelSerializer): validators = self.fields['name'].validators if isinstance(validators[-1], RegexValidator): validators.pop() + self.set_platform_meta() + + def set_platform_meta(self): + view = self.context.get('view') + if not view: + return + request = view.request + + if isinstance(self.instance, Platform): + category = self.instance.category + tp = self.instance.type + else: + tp = request.query_params.get('type') + category = request.query_params.get('category') + + print("Request: {}".format(self.context.get('request').method), category, tp) + if not all([tp, category]): + return + meta = Platform.get_type_meta(category, tp) + print("Platform meta: {}".format(meta)) + protocols_default = self.fields['protocols_default'] + limits = meta.get('protocols_limit', []) + default_ports = Protocol.default_ports() + protocols = [] + for protocol in limits: + port = default_ports.get(protocol, 22) + protocols.append(f'{protocol}/{port}') + print("set ptocols: ", protocols) + protocols_default.set_protocols(protocols) class Meta: model = Platform fields_mini = ['id', 'name', 'internal'] fields_small = fields_mini + [ 'meta', 'comment', 'charset', - 'category', 'category_display', 'type', 'type_display', + 'category', 'category_display', + 'type', 'type_display', ] fields_fk = [ 'domain_enabled', 'domain_default', diff --git a/apps/common/drf/metadata.py b/apps/common/drf/metadata.py index 569854722..7e4d32527 100644 --- a/apps/common/drf/metadata.py +++ b/apps/common/drf/metadata.py @@ -33,6 +33,7 @@ class SimpleMetadataWithFilters(SimpleMetadata): """ actions = {} view.raw_action = getattr(view, 'action', None) + print("Request in metadata: ", request.path, request.GET) for method in self.methods & set(view.allowed_methods): if hasattr(view, 'action_map'): view.action = view.action_map.get(method.lower(), view.action) @@ -80,14 +81,14 @@ class SimpleMetadataWithFilters(SimpleMetadata): elif getattr(field, 'fields', None): field_info['children'] = self.get_serializer_info(field) - if not isinstance(field, (serializers.RelatedField, serializers.ManyRelatedField)) \ - and hasattr(field, 'choices'): + is_related_field = isinstance(field, (serializers.RelatedField, serializers.ManyRelatedField)) + if not is_related_field and hasattr(field, 'choices'): field_info['choices'] = [ { 'value': choice_value, 'display_name': force_text(choice_name, strings_only=True) } - for choice_value, choice_name in field.choices.items() + for choice_value, choice_name in dict(field.choices).items() ] return field_info