mirror of https://github.com/jumpserver/jumpserver
reactor: 重构命令&录像存储模块的Serializer及相关模块 (#5392)
* reactor: 重构命令&录像存储模块的Serializer及相关模块 Co-authored-by: Bai <bugatti_it@163.com>pull/5406/head
parent
b3f359d47b
commit
86a055638c
|
@ -18,15 +18,19 @@ class ApplicationSerializerMixin(serializers.Serializer):
|
|||
attrs = MethodSerializer()
|
||||
|
||||
def get_attrs_serializer(self):
|
||||
request = self.context['request']
|
||||
query_type = request.query_params.get('type')
|
||||
query_category = request.query_params.get('category')
|
||||
if query_type:
|
||||
serializer_class = type_serializer_classes_mapping.get(query_type)
|
||||
elif query_category:
|
||||
serializer_class = category_serializer_classes_mapping.get(query_category)
|
||||
serializer_class = None
|
||||
if isinstance(self.instance, models.Application):
|
||||
instance_type = self.instance.type
|
||||
serializer_class = type_serializer_classes_mapping.get(instance_type)
|
||||
else:
|
||||
serializer_class = None
|
||||
request = self.context['request']
|
||||
query_type = request.query_params.get('type')
|
||||
query_category = request.query_params.get('category')
|
||||
if query_type:
|
||||
serializer_class = type_serializer_classes_mapping.get(query_type)
|
||||
elif query_category:
|
||||
serializer_class = category_serializer_classes_mapping.get(query_category)
|
||||
|
||||
if serializer_class is None:
|
||||
serializer_class = serializers.Serializer
|
||||
serializer = serializer_class()
|
||||
|
|
|
@ -6,4 +6,4 @@ __all__ = ['CloudSerializer']
|
|||
|
||||
|
||||
class CloudSerializer(serializers.Serializer):
|
||||
cluster = serializers.CharField(max_length=1024, label=_('Cluster'))
|
||||
cluster = serializers.CharField(max_length=1024, label=_('Cluster'), allow_null=True)
|
||||
|
|
|
@ -8,9 +8,8 @@ __all__ = ['DBSerializer']
|
|||
|
||||
|
||||
class DBSerializer(serializers.Serializer):
|
||||
host = serializers.CharField(max_length=128, label=_('Host'))
|
||||
port = serializers.IntegerField(label=_('Port'))
|
||||
# 添加allow_null=True,兼容之前数据库中database字段为None的情况
|
||||
host = serializers.CharField(max_length=128, label=_('Host'), allow_null=True)
|
||||
port = serializers.IntegerField(label=_('Port'), allow_null=True)
|
||||
database = serializers.CharField(
|
||||
max_length=128, required=True, allow_null=True, label=_('Database')
|
||||
)
|
||||
|
|
|
@ -29,8 +29,12 @@ class CharPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
|
|||
|
||||
class RemoteAppSerializer(serializers.Serializer):
|
||||
asset_info = serializers.SerializerMethodField()
|
||||
asset = CharPrimaryKeyRelatedField(queryset=Asset.objects, required=False, label=_("Asset"))
|
||||
path = serializers.CharField(max_length=128, label=_('Application path'))
|
||||
asset = CharPrimaryKeyRelatedField(
|
||||
queryset=Asset.objects, required=False, label=_("Asset"), allow_null=True
|
||||
)
|
||||
path = serializers.CharField(
|
||||
max_length=128, label=_('Application path'), allow_null=True
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_asset_info(obj):
|
||||
|
|
|
@ -11,15 +11,16 @@ class ChromeSerializer(RemoteAppSerializer):
|
|||
CHROME_PATH = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
|
||||
|
||||
path = serializers.CharField(
|
||||
max_length=128, label=_('Application path'), default=CHROME_PATH
|
||||
max_length=128, label=_('Application path'), default=CHROME_PATH, allow_null=True,
|
||||
)
|
||||
chrome_target = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, label=_('Target URL')
|
||||
max_length=128, allow_blank=True, required=False, label=_('Target URL'), allow_null=True,
|
||||
)
|
||||
chrome_username = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, label=_('Username')
|
||||
max_length=128, allow_blank=True, required=False, label=_('Username'), allow_null=True,
|
||||
)
|
||||
chrome_password = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password')
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password'),
|
||||
allow_null=True
|
||||
)
|
||||
|
||||
|
|
|
@ -10,14 +10,18 @@ __all__ = ['CustomSerializer']
|
|||
|
||||
class CustomSerializer(RemoteAppSerializer):
|
||||
custom_cmdline = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, label=_('Operating parameter')
|
||||
max_length=128, allow_blank=True, required=False, label=_('Operating parameter'),
|
||||
allow_null=True,
|
||||
)
|
||||
custom_target = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, label=_('Target url')
|
||||
max_length=128, allow_blank=True, required=False, label=_('Target url'),
|
||||
allow_null=True,
|
||||
)
|
||||
custom_username = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, label=_('Username')
|
||||
max_length=128, allow_blank=True, required=False, label=_('Username'),
|
||||
allow_null=True,
|
||||
)
|
||||
custom_password = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password')
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password'),
|
||||
allow_null=True,
|
||||
)
|
||||
|
|
|
@ -8,7 +8,7 @@ __all__ = ['MySQLSerializer']
|
|||
|
||||
|
||||
class MySQLSerializer(DBSerializer):
|
||||
port = serializers.IntegerField(default=3306, label=_('Port'))
|
||||
port = serializers.IntegerField(default=3306, label=_('Port'), allow_null=True)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -11,20 +11,26 @@ class MySQLWorkbenchSerializer(RemoteAppSerializer):
|
|||
MYSQL_WORKBENCH_PATH = 'C:\Program Files\MySQL\MySQL Workbench 8.0 CE\MySQLWorkbench.exe'
|
||||
|
||||
path = serializers.CharField(
|
||||
max_length=128, label=_('Application path'), default=MYSQL_WORKBENCH_PATH
|
||||
max_length=128, label=_('Application path'), default=MYSQL_WORKBENCH_PATH,
|
||||
allow_null=True,
|
||||
)
|
||||
mysql_workbench_ip = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, label=_('IP')
|
||||
max_length=128, allow_blank=True, required=False, label=_('IP'),
|
||||
allow_null=True,
|
||||
)
|
||||
mysql_workbench_port = serializers.IntegerField(
|
||||
required=False, label=_('Port')
|
||||
required=False, label=_('Port'),
|
||||
allow_null=True,
|
||||
)
|
||||
mysql_workbench_name = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, label=_('Database')
|
||||
max_length=128, allow_blank=True, required=False, label=_('Database'),
|
||||
allow_null=True,
|
||||
)
|
||||
mysql_workbench_username = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, label=_('Username')
|
||||
max_length=128, allow_blank=True, required=False, label=_('Username'),
|
||||
allow_null=True,
|
||||
)
|
||||
mysql_workbench_password = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password')
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password'),
|
||||
allow_null=True,
|
||||
)
|
||||
|
|
|
@ -8,5 +8,5 @@ __all__ = ['OracleSerializer']
|
|||
|
||||
|
||||
class OracleSerializer(DBSerializer):
|
||||
port = serializers.IntegerField(default=1521, label=_('Port'))
|
||||
port = serializers.IntegerField(default=1521, label=_('Port'), allow_null=True)
|
||||
|
||||
|
|
|
@ -8,5 +8,5 @@ __all__ = ['PostgreSerializer']
|
|||
|
||||
|
||||
class PostgreSerializer(DBSerializer):
|
||||
port = serializers.IntegerField(default=5432, label=_('Port'))
|
||||
port = serializers.IntegerField(default=5432, label=_('Port'), allow_null=True)
|
||||
|
||||
|
|
|
@ -15,14 +15,18 @@ class VMwareClientSerializer(RemoteAppSerializer):
|
|||
VMWARE_CLIENT_PATH = ''.join(PATH.split())
|
||||
|
||||
path = serializers.CharField(
|
||||
max_length=128, label=_('Application path'), default=VMWARE_CLIENT_PATH
|
||||
max_length=128, label=_('Application path'), default=VMWARE_CLIENT_PATH,
|
||||
allow_null=True
|
||||
)
|
||||
vmware_target = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, label=_('Target URL')
|
||||
max_length=128, allow_blank=True, required=False, label=_('Target URL'),
|
||||
allow_null=True
|
||||
)
|
||||
vmware_username = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, label=_('Username')
|
||||
max_length=128, allow_blank=True, required=False, label=_('Username'),
|
||||
allow_null=True
|
||||
)
|
||||
vmware_password = serializers.CharField(
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password')
|
||||
max_length=128, allow_blank=True, required=False, write_only=True, label=_('Password'),
|
||||
allow_null=True
|
||||
)
|
||||
|
|
|
@ -208,12 +208,11 @@ class SystemUser(BaseUser):
|
|||
def get_protocol_by_application_type(cls, app_type):
|
||||
from applications.const import ApplicationTypeChoices
|
||||
if app_type in ApplicationTypeChoices.remote_app_types():
|
||||
return cls.PROTOCOL_RDP
|
||||
protocol = None
|
||||
other_types = [*ApplicationTypeChoices.db_types(), *ApplicationTypeChoices.cloud_types()]
|
||||
if app_type in other_types and app_type in cls.APPLICATION_CATEGORY_PROTOCOLS:
|
||||
protocol = cls.PROTOCOL_RDP
|
||||
else:
|
||||
protocol = app_type
|
||||
return protocol
|
||||
if protocol in cls.APPLICATION_CATEGORY_PROTOCOLS:
|
||||
return protocol
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
import copy
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
__all__ = [
|
||||
'ReadableHiddenField', 'CustomMetaDictField',
|
||||
'ReadableHiddenField',
|
||||
]
|
||||
|
||||
|
||||
|
@ -24,87 +23,3 @@ class ReadableHiddenField(serializers.HiddenField):
|
|||
if hasattr(value, 'id'):
|
||||
return getattr(value, 'id')
|
||||
return value
|
||||
|
||||
#
|
||||
# OtherField
|
||||
# ----------
|
||||
|
||||
|
||||
# TODO: DELETE 替换完成后删除
|
||||
class CustomMetaDictField(serializers.DictField):
|
||||
"""
|
||||
In use:
|
||||
RemoteApp params field
|
||||
CommandStorage meta field
|
||||
ReplayStorage meta field
|
||||
"""
|
||||
type_fields_map = {}
|
||||
default_type = None
|
||||
convert_key_remove_type_prefix = False
|
||||
convert_key_to_upper = False
|
||||
|
||||
def filter_attribute(self, attribute, instance):
|
||||
fields = self.type_fields_map.get(instance.type, [])
|
||||
for field in fields:
|
||||
if field.get('write_only', False):
|
||||
attribute.pop(field['name'], None)
|
||||
return attribute
|
||||
|
||||
def get_attribute(self, instance):
|
||||
"""
|
||||
序列化时调用
|
||||
"""
|
||||
attribute = super().get_attribute(instance)
|
||||
attribute = self.filter_attribute(attribute, instance)
|
||||
return attribute
|
||||
|
||||
def convert_value_key_remove_type_prefix(self, dictionary, value):
|
||||
if not self.convert_key_remove_type_prefix:
|
||||
return value
|
||||
tp = dictionary.get('type')
|
||||
prefix = '{}_'.format(tp)
|
||||
convert_value = {}
|
||||
for k, v in value.items():
|
||||
if k.lower().startswith(prefix):
|
||||
k = k.lower().split(prefix, 1)[1]
|
||||
convert_value[k] = v
|
||||
return convert_value
|
||||
|
||||
def convert_value_key_to_upper(self, value):
|
||||
if not self.convert_key_to_upper:
|
||||
return value
|
||||
convert_value = {k.upper(): v for k, v in value.items()}
|
||||
return convert_value
|
||||
|
||||
def convert_value_key(self, dictionary, value):
|
||||
value = self.convert_value_key_remove_type_prefix(dictionary, value)
|
||||
value = self.convert_value_key_to_upper(value)
|
||||
return value
|
||||
|
||||
def filter_value_key(self, dictionary, value):
|
||||
tp = dictionary.get('type')
|
||||
fields = self.type_fields_map.get(tp, [])
|
||||
fields_names = [field['name'] for field in fields]
|
||||
filter_value = {k: v for k, v in value.items() if k in fields_names}
|
||||
return filter_value
|
||||
|
||||
@staticmethod
|
||||
def strip_value(value):
|
||||
new_value = {}
|
||||
for k, v in value.items():
|
||||
if isinstance(v, str):
|
||||
v = v.strip()
|
||||
new_value[k] = v
|
||||
return new_value
|
||||
|
||||
def get_value(self, dictionary):
|
||||
"""
|
||||
反序列化时调用
|
||||
"""
|
||||
value = super().get_value(dictionary)
|
||||
value = self.convert_value_key(dictionary, value)
|
||||
value = self.filter_value_key(dictionary, value)
|
||||
value = self.strip_value(value)
|
||||
return value
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import copy
|
||||
from rest_framework import serializers
|
||||
from rest_framework.serializers import Serializer
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
|
@ -38,10 +39,10 @@ class MethodSerializer(serializers.Serializer):
|
|||
@cached_property
|
||||
def serializer(self) -> serializers.Serializer:
|
||||
method = getattr(self.parent, self.method_name)
|
||||
return method()
|
||||
|
||||
def get_fields(self):
|
||||
return self.serializer.get_fields()
|
||||
_serializer = method()
|
||||
# 设置serializer的parent值,否则在serializer实例中获取parent会出现断层
|
||||
setattr(_serializer, 'parent', self.parent)
|
||||
return _serializer
|
||||
|
||||
@cached_property
|
||||
def fields(self):
|
||||
|
@ -50,10 +51,16 @@ class MethodSerializer(serializers.Serializer):
|
|||
这样在调用 field.parent 时, 才会达到预期的结果,
|
||||
比如: serializers.SerializerMethodField
|
||||
"""
|
||||
fields = BindingDict(self.serializer)
|
||||
for key, value in self.get_fields().items():
|
||||
fields[key] = value
|
||||
return fields
|
||||
return self.serializer.fields
|
||||
|
||||
def run_validation(self, data=serializers.empty):
|
||||
return self.serializer.run_validation(data)
|
||||
|
||||
def to_representation(self, instance):
|
||||
return self.serializer.to_representation(instance)
|
||||
|
||||
def get_initial(self):
|
||||
return self.serializer.get_initial()
|
||||
|
||||
|
||||
# Other Serializer
|
||||
|
|
|
@ -20,10 +20,10 @@ class BaseStorageViewSetMixin:
|
|||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
instance = self.get_object()
|
||||
if instance.in_defaults():
|
||||
if instance.type_null_or_server:
|
||||
data = {'msg': _('Deleting the default storage is not allowed')}
|
||||
return Response(data=data, status=status.HTTP_400_BAD_REQUEST)
|
||||
if instance.is_using():
|
||||
if instance.is_use():
|
||||
data = {'msg': _('Cannot delete storage that is being used')}
|
||||
return Response(data=data, status=status.HTTP_400_BAD_REQUEST)
|
||||
return super().destroy(request, *args, **kwargs)
|
||||
|
@ -67,11 +67,9 @@ class BaseStorageTestConnectiveMixin:
|
|||
return Response(data)
|
||||
|
||||
|
||||
class CommandStorageTestConnectiveApi(BaseStorageTestConnectiveMixin,
|
||||
generics.RetrieveAPIView):
|
||||
class CommandStorageTestConnectiveApi(BaseStorageTestConnectiveMixin, generics.RetrieveAPIView):
|
||||
queryset = CommandStorage.objects.all()
|
||||
|
||||
|
||||
class ReplayStorageTestConnectiveApi(BaseStorageTestConnectiveMixin,
|
||||
generics.RetrieveAPIView):
|
||||
class ReplayStorageTestConnectiveApi(BaseStorageTestConnectiveMixin, generics.RetrieveAPIView):
|
||||
queryset = ReplayStorage.objects.all()
|
||||
|
|
|
@ -148,7 +148,5 @@ class TerminalConfig(APIView):
|
|||
permission_classes = (IsAppUser,)
|
||||
|
||||
def get(self, request):
|
||||
user = request.user
|
||||
terminal = user.terminal
|
||||
configs = terminal.config
|
||||
return Response(configs, status=200)
|
||||
config = request.user.terminal.config
|
||||
return Response(config, status=200)
|
|
@ -8,4 +8,4 @@ class TerminalConfig(AppConfig):
|
|||
|
||||
def ready(self):
|
||||
from . import signals_handler
|
||||
return super().ready()
|
||||
return super().ready()
|
||||
|
|
|
@ -3,7 +3,6 @@ from django.conf import settings
|
|||
from django.utils.functional import LazyObject
|
||||
|
||||
from .command.serializers import SessionCommandSerializer
|
||||
from ..const import COMMAND_STORAGE_TYPE_SERVER
|
||||
|
||||
|
||||
TYPE_ENGINE_MAPPING = {
|
||||
|
@ -30,13 +29,12 @@ def get_terminal_command_storages():
|
|||
from ..models import CommandStorage
|
||||
storage_list = {}
|
||||
for s in CommandStorage.objects.all():
|
||||
tp = s.type
|
||||
if tp == COMMAND_STORAGE_TYPE_SERVER:
|
||||
if s.type_server:
|
||||
storage = get_command_storage()
|
||||
else:
|
||||
if not TYPE_ENGINE_MAPPING.get(tp):
|
||||
if not TYPE_ENGINE_MAPPING.get(s.type):
|
||||
continue
|
||||
engine_class = import_module(TYPE_ENGINE_MAPPING[tp])
|
||||
engine_class = import_module(TYPE_ENGINE_MAPPING[s.type])
|
||||
storage = engine_class.CommandStore(s.config)
|
||||
storage_list[s.name] = storage
|
||||
return storage_list
|
||||
|
|
|
@ -1,117 +1,31 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
ASSETS_CACHE_KEY = "terminal__session__assets"
|
||||
USERS_CACHE_KEY = "terminal__session__users"
|
||||
SYSTEM_USER_CACHE_KEY = "terminal__session__system_users"
|
||||
|
||||
|
||||
# Replay Storage
|
||||
|
||||
REPLAY_STORAGE_TYPE_NULL = 'null'
|
||||
REPLAY_STORAGE_TYPE_SERVER = 'server'
|
||||
REPLAY_STORAGE_TYPE_S3 = 's3'
|
||||
REPLAY_STORAGE_TYPE_CEPH = 'ceph'
|
||||
REPLAY_STORAGE_TYPE_SWIFT = 'swift'
|
||||
REPLAY_STORAGE_TYPE_OSS = 'oss'
|
||||
REPLAY_STORAGE_TYPE_AZURE = 'azure'
|
||||
|
||||
REPLAY_STORAGE_TYPE_EMPTY_FIELDS = []
|
||||
REPLAY_STORAGE_TYPE_S3_FIELDS = [
|
||||
{'name': 'BUCKET'},
|
||||
{'name': 'ACCESS_KEY', 'write_only': True},
|
||||
{'name': 'SECRET_KEY', 'write_only': True},
|
||||
{'name': 'ENDPOINT'}
|
||||
]
|
||||
REPLAY_STORAGE_TYPE_CEPH_FIELDS = [
|
||||
{'name': 'BUCKET'},
|
||||
{'name': 'ACCESS_KEY', 'write_only': True},
|
||||
{'name': 'SECRET_KEY', 'write_only': True},
|
||||
{'name': 'ENDPOINT'}
|
||||
]
|
||||
REPLAY_STORAGE_TYPE_SWIFT_FIELDS = [
|
||||
{'name': 'BUCKET'},
|
||||
{'name': 'ACCESS_KEY', 'write_only': True},
|
||||
{'name': 'SECRET_KEY', 'write_only': True},
|
||||
{'name': 'REGION'},
|
||||
{'name': 'ENDPOINT'},
|
||||
{'name': 'PROTOCOL'},
|
||||
]
|
||||
REPLAY_STORAGE_TYPE_OSS_FIELDS = [
|
||||
{'name': 'BUCKET'},
|
||||
{'name': 'ACCESS_KEY', 'write_only': True},
|
||||
{'name': 'SECRET_KEY', 'write_only': True},
|
||||
{'name': 'ENDPOINT'}
|
||||
]
|
||||
REPLAY_STORAGE_TYPE_AZURE_FIELDS = [
|
||||
{'name': 'CONTAINER_NAME'},
|
||||
{'name': 'ACCOUNT_NAME'},
|
||||
{'name': 'ACCOUNT_KEY', 'write_only': True},
|
||||
{'name': 'ENDPOINT_SUFFIX'}
|
||||
]
|
||||
|
||||
REPLAY_STORAGE_TYPE_FIELDS_MAP = {
|
||||
REPLAY_STORAGE_TYPE_NULL: REPLAY_STORAGE_TYPE_EMPTY_FIELDS,
|
||||
REPLAY_STORAGE_TYPE_SERVER: REPLAY_STORAGE_TYPE_EMPTY_FIELDS,
|
||||
REPLAY_STORAGE_TYPE_S3: REPLAY_STORAGE_TYPE_S3_FIELDS,
|
||||
REPLAY_STORAGE_TYPE_CEPH: REPLAY_STORAGE_TYPE_CEPH_FIELDS,
|
||||
REPLAY_STORAGE_TYPE_SWIFT: REPLAY_STORAGE_TYPE_SWIFT_FIELDS,
|
||||
REPLAY_STORAGE_TYPE_OSS: REPLAY_STORAGE_TYPE_OSS_FIELDS,
|
||||
REPLAY_STORAGE_TYPE_AZURE: REPLAY_STORAGE_TYPE_AZURE_FIELDS
|
||||
}
|
||||
|
||||
REPLAY_STORAGE_TYPE_CHOICES_DEFAULT = [
|
||||
(REPLAY_STORAGE_TYPE_NULL, 'Null'),
|
||||
(REPLAY_STORAGE_TYPE_SERVER, 'Server'),
|
||||
]
|
||||
|
||||
REPLAY_STORAGE_TYPE_CHOICES_EXTENDS = [
|
||||
(REPLAY_STORAGE_TYPE_S3, 'S3'),
|
||||
(REPLAY_STORAGE_TYPE_CEPH, 'Ceph'),
|
||||
(REPLAY_STORAGE_TYPE_SWIFT, 'Swift'),
|
||||
(REPLAY_STORAGE_TYPE_OSS, 'OSS'),
|
||||
(REPLAY_STORAGE_TYPE_AZURE, 'Azure')
|
||||
]
|
||||
|
||||
REPLAY_STORAGE_TYPE_CHOICES = REPLAY_STORAGE_TYPE_CHOICES_DEFAULT + \
|
||||
REPLAY_STORAGE_TYPE_CHOICES_EXTENDS
|
||||
|
||||
|
||||
# Command Storage
|
||||
|
||||
COMMAND_STORAGE_TYPE_NULL = 'null'
|
||||
COMMAND_STORAGE_TYPE_SERVER = 'server'
|
||||
COMMAND_STORAGE_TYPE_ES = 'es'
|
||||
|
||||
COMMAND_STORAGE_TYPE_EMPTY_FIELDS = []
|
||||
COMMAND_STORAGE_TYPE_ES_FIELDS = [
|
||||
{'name': 'HOSTS'},
|
||||
{'name': 'INDEX'},
|
||||
{'name': 'DOC_TYPE'}
|
||||
]
|
||||
|
||||
COMMAND_STORAGE_TYPE_FIELDS_MAP = {
|
||||
COMMAND_STORAGE_TYPE_NULL: COMMAND_STORAGE_TYPE_EMPTY_FIELDS,
|
||||
COMMAND_STORAGE_TYPE_SERVER: COMMAND_STORAGE_TYPE_EMPTY_FIELDS,
|
||||
COMMAND_STORAGE_TYPE_ES: COMMAND_STORAGE_TYPE_ES_FIELDS,
|
||||
}
|
||||
|
||||
COMMAND_STORAGE_TYPE_CHOICES_DEFAULT = [
|
||||
(COMMAND_STORAGE_TYPE_NULL, 'Null'),
|
||||
(COMMAND_STORAGE_TYPE_SERVER, 'Server'),
|
||||
]
|
||||
|
||||
COMMAND_STORAGE_TYPE_CHOICES_EXTENDS = [
|
||||
(COMMAND_STORAGE_TYPE_ES, 'Elasticsearch')
|
||||
]
|
||||
|
||||
COMMAND_STORAGE_TYPE_CHOICES = COMMAND_STORAGE_TYPE_CHOICES_DEFAULT + \
|
||||
COMMAND_STORAGE_TYPE_CHOICES_EXTENDS
|
||||
|
||||
|
||||
from django.db.models import TextChoices
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
# Replay & Command Storage Choices
|
||||
# --------------------------------
|
||||
|
||||
|
||||
class ReplayStorageTypeChoices(TextChoices):
|
||||
null = 'null', 'Null',
|
||||
server = 'server', 'Server'
|
||||
s3 = 's3', 'S3'
|
||||
ceph = 'ceph', 'Ceph'
|
||||
swift = 'swift', 'Swift'
|
||||
oss = 'oss', 'OSS'
|
||||
azure = 'azure', 'Azure'
|
||||
|
||||
|
||||
class CommandStorageTypeChoices(TextChoices):
|
||||
null = 'null', 'Null',
|
||||
server = 'server', 'Server'
|
||||
es = 'es', 'Elasticsearch'
|
||||
|
||||
|
||||
# Component Status Choices
|
||||
# ------------------------
|
||||
|
||||
class ComponentStatusChoices(TextChoices):
|
||||
critical = 'critical', _('Critical')
|
||||
|
|
|
@ -2,102 +2,113 @@ from __future__ import unicode_literals
|
|||
|
||||
import os
|
||||
import jms_storage
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.conf import settings
|
||||
|
||||
from common.mixins import CommonModelMixin
|
||||
from common.fields.model import EncryptJsonDictTextField
|
||||
from .. import const
|
||||
from .terminal import Terminal
|
||||
from .. import const
|
||||
|
||||
|
||||
class CommandStorage(CommonModelMixin):
|
||||
TYPE_CHOICES = const.COMMAND_STORAGE_TYPE_CHOICES
|
||||
TYPE_DEFAULTS = dict(const.REPLAY_STORAGE_TYPE_CHOICES_DEFAULT).keys()
|
||||
TYPE_SERVER = const.COMMAND_STORAGE_TYPE_SERVER
|
||||
|
||||
name = models.CharField(max_length=128, verbose_name=_("Name"), unique=True)
|
||||
type = models.CharField(
|
||||
max_length=16, choices=TYPE_CHOICES, verbose_name=_('Type'),
|
||||
default=TYPE_SERVER
|
||||
max_length=16, choices=const.CommandStorageTypeChoices.choices,
|
||||
default=const.CommandStorageTypeChoices.server.value, verbose_name=_('Type'),
|
||||
)
|
||||
meta = EncryptJsonDictTextField(default={})
|
||||
comment = models.TextField(
|
||||
max_length=128, default='', blank=True, verbose_name=_('Comment')
|
||||
)
|
||||
comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment'))
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def type_null(self):
|
||||
return self.type == const.CommandStorageTypeChoices.null.value
|
||||
|
||||
@property
|
||||
def type_server(self):
|
||||
return self.type == const.CommandStorageTypeChoices.server.value
|
||||
|
||||
@property
|
||||
def type_null_or_server(self):
|
||||
return self.type_null or self.type_server
|
||||
|
||||
@property
|
||||
def config(self):
|
||||
config = self.meta
|
||||
config.update({'TYPE': self.type})
|
||||
return config
|
||||
|
||||
def in_defaults(self):
|
||||
return self.type in self.TYPE_DEFAULTS
|
||||
|
||||
def is_valid(self):
|
||||
if self.in_defaults():
|
||||
if self.type_null_or_server:
|
||||
return True
|
||||
storage = jms_storage.get_log_storage(self.config)
|
||||
return storage.ping()
|
||||
|
||||
def is_using(self):
|
||||
def is_use(self):
|
||||
return Terminal.objects.filter(command_storage=self.name).exists()
|
||||
|
||||
|
||||
class ReplayStorage(CommonModelMixin):
|
||||
TYPE_CHOICES = const.REPLAY_STORAGE_TYPE_CHOICES
|
||||
TYPE_SERVER = const.REPLAY_STORAGE_TYPE_SERVER
|
||||
TYPE_DEFAULTS = dict(const.REPLAY_STORAGE_TYPE_CHOICES_DEFAULT).keys()
|
||||
|
||||
name = models.CharField(max_length=128, verbose_name=_("Name"), unique=True)
|
||||
type = models.CharField(
|
||||
max_length=16, choices=TYPE_CHOICES, verbose_name=_('Type'),
|
||||
default=TYPE_SERVER
|
||||
max_length=16, choices=const.ReplayStorageTypeChoices.choices,
|
||||
default=const.ReplayStorageTypeChoices.server.value, verbose_name=_('Type')
|
||||
)
|
||||
meta = EncryptJsonDictTextField(default={})
|
||||
comment = models.TextField(
|
||||
max_length=128, default='', blank=True, verbose_name=_('Comment')
|
||||
)
|
||||
comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment'))
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def convert_type(self):
|
||||
s3_type_list = [const.REPLAY_STORAGE_TYPE_CEPH]
|
||||
tp = self.type
|
||||
if tp in s3_type_list:
|
||||
tp = const.REPLAY_STORAGE_TYPE_S3
|
||||
return tp
|
||||
@property
|
||||
def type_null(self):
|
||||
return self.type == const.ReplayStorageTypeChoices.null.value
|
||||
|
||||
def get_extra_config(self):
|
||||
extra_config = {'TYPE': self.convert_type()}
|
||||
if self.type == const.REPLAY_STORAGE_TYPE_SWIFT:
|
||||
extra_config.update({'signer': 'S3SignerType'})
|
||||
return extra_config
|
||||
@property
|
||||
def type_server(self):
|
||||
return self.type == const.ReplayStorageTypeChoices.server.value
|
||||
|
||||
@property
|
||||
def type_null_or_server(self):
|
||||
return self.type_null or self.type_server
|
||||
|
||||
@property
|
||||
def type_swift(self):
|
||||
return self.type == const.ReplayStorageTypeChoices.swift.value
|
||||
|
||||
@property
|
||||
def type_ceph(self):
|
||||
return self.type == const.ReplayStorageTypeChoices.ceph.value
|
||||
|
||||
@property
|
||||
def config(self):
|
||||
config = self.meta
|
||||
extra_config = self.get_extra_config()
|
||||
config.update(extra_config)
|
||||
return config
|
||||
_config = {}
|
||||
|
||||
def in_defaults(self):
|
||||
return self.type in self.TYPE_DEFAULTS
|
||||
# add type config
|
||||
if self.type_ceph:
|
||||
_type = const.ReplayStorageTypeChoices.s3.value
|
||||
else:
|
||||
_type = self.type
|
||||
_config.update({'TYPE': _type})
|
||||
|
||||
# add special config
|
||||
if self.type_swift:
|
||||
_config.update({'signer': 'S3SignerType'})
|
||||
|
||||
# add meta config
|
||||
_config.update(self.meta)
|
||||
return _config
|
||||
|
||||
def is_valid(self):
|
||||
if self.in_defaults():
|
||||
if self.type_null_or_server:
|
||||
return True
|
||||
storage = jms_storage.get_object_storage(self.config)
|
||||
target = 'tests.py'
|
||||
src = os.path.join(settings.BASE_DIR, 'common', target)
|
||||
return storage.is_valid(src, target)
|
||||
|
||||
def is_using(self):
|
||||
def is_use(self):
|
||||
return Terminal.objects.filter(replay_storage=self.name).exists()
|
||||
|
|
|
@ -2,74 +2,197 @@
|
|||
#
|
||||
import copy
|
||||
from rest_framework import serializers
|
||||
|
||||
from common.drf.fields import CustomMetaDictField
|
||||
from urllib.parse import urlparse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.db.models import TextChoices
|
||||
from common.drf.serializers import MethodSerializer
|
||||
from ..models import ReplayStorage, CommandStorage
|
||||
from .. import const
|
||||
|
||||
|
||||
class ReplayStorageMetaDictField(CustomMetaDictField):
|
||||
type_fields_map = const.REPLAY_STORAGE_TYPE_FIELDS_MAP
|
||||
default_type = const.REPLAY_STORAGE_TYPE_SERVER
|
||||
convert_key_remove_type_prefix = True
|
||||
convert_key_to_upper = True
|
||||
# Replay storage serializers
|
||||
# --------------------------
|
||||
|
||||
|
||||
class BaseStorageSerializerMixin:
|
||||
type_fields_map = None
|
||||
|
||||
def process_meta(self, instance, validated_data):
|
||||
new_meta = copy.deepcopy(validated_data.get('meta', {}))
|
||||
tp = validated_data.get('type', '')
|
||||
|
||||
if tp != instance.type:
|
||||
return new_meta
|
||||
|
||||
old_meta = instance.meta
|
||||
fields = self.type_fields_map.get(instance.type, [])
|
||||
for field in fields:
|
||||
if not field.get('write_only', False):
|
||||
continue
|
||||
field_name = field['name']
|
||||
new_value = new_meta.get(field_name, '')
|
||||
old_value = old_meta.get(field_name, '')
|
||||
field_value = new_value if new_value else old_value
|
||||
new_meta[field_name] = field_value
|
||||
|
||||
return new_meta
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
meta = self.process_meta(instance, validated_data)
|
||||
validated_data['meta'] = meta
|
||||
return super().update(instance, validated_data)
|
||||
class ReplayStorageTypeBaseSerializer(serializers.Serializer):
|
||||
BUCKET = serializers.CharField(
|
||||
required=True, max_length=1024, label=_('Bucket'), allow_null=True
|
||||
)
|
||||
ACCESS_KEY = serializers.CharField(
|
||||
max_length=1024, required=False, allow_blank=True, write_only=True, label=_('Access key'),
|
||||
allow_null=True,
|
||||
)
|
||||
SECRET_KEY = serializers.CharField(
|
||||
max_length=1024, required=False, allow_blank=True, write_only=True, label=_('Secret key'),
|
||||
allow_null=True,
|
||||
)
|
||||
ENDPOINT = serializers.CharField(
|
||||
required=True, max_length=1024, label=_('Endpoint'), allow_null=True,
|
||||
)
|
||||
|
||||
|
||||
class ReplayStorageSerializer(BaseStorageSerializerMixin,
|
||||
serializers.ModelSerializer):
|
||||
class ReplayStorageTypeS3Serializer(ReplayStorageTypeBaseSerializer):
|
||||
endpoint_help_text = '''
|
||||
S3 format: http://s3.{REGION_NAME}.amazonaws.com
|
||||
S3(China) format: http://s3.{REGION_NAME}.amazonaws.com.cn
|
||||
Such as: http://s3.cn-north-1.amazonaws.com.cn
|
||||
'''
|
||||
ENDPOINT = serializers.CharField(
|
||||
required=True, max_length=1024, label=_('Endpoint'), help_text=_(endpoint_help_text),
|
||||
allow_null=True,
|
||||
)
|
||||
|
||||
meta = ReplayStorageMetaDictField()
|
||||
|
||||
type_fields_map = const.REPLAY_STORAGE_TYPE_FIELDS_MAP
|
||||
class ReplayStorageTypeCephSerializer(ReplayStorageTypeBaseSerializer):
|
||||
pass
|
||||
|
||||
|
||||
class ReplayStorageTypeSwiftSerializer(ReplayStorageTypeBaseSerializer):
|
||||
class ProtocolChoices(TextChoices):
|
||||
http = 'http', 'http'
|
||||
https = 'https', 'https'
|
||||
|
||||
REGION = serializers.CharField(
|
||||
required=True, max_length=1024, label=_('Region'), allow_null=True
|
||||
)
|
||||
PROTOCOL = serializers.ChoiceField(
|
||||
choices=ProtocolChoices.choices, default=ProtocolChoices.http.value, label=_('Protocol'),
|
||||
allow_null=True,
|
||||
)
|
||||
|
||||
|
||||
class ReplayStorageTypeOSSSerializer(ReplayStorageTypeBaseSerializer):
|
||||
endpoint_help_text = '''
|
||||
OSS format: http://{REGION_NAME}.aliyuncs.com
|
||||
Such as: http://oss-cn-hangzhou.aliyuncs.com
|
||||
'''
|
||||
ENDPOINT = serializers.CharField(
|
||||
max_length=1024, label=_('Endpoint'), help_text=_(endpoint_help_text), allow_null=True,
|
||||
)
|
||||
|
||||
|
||||
class ReplayStorageTypeAzureSerializer(serializers.Serializer):
|
||||
class EndpointSuffixChoices(TextChoices):
|
||||
china = 'core.chinacloudapi.cn', 'core.chinacloudapi.cn'
|
||||
international = 'core.windows.net', 'core.windows.net'
|
||||
|
||||
CONTAINER_NAME = serializers.CharField(max_length=1024, label=_('Container'), allow_null=True)
|
||||
ACCOUNT_NAME = serializers.CharField(max_length=1024, label=_('Account name'), allow_null=True)
|
||||
ACCOUNT_KEY = serializers.CharField(max_length=1024, label=_('Account key'), allow_null=True)
|
||||
ENDPOINT_SUFFIX = serializers.ChoiceField(
|
||||
choices=EndpointSuffixChoices.choices, default=EndpointSuffixChoices.china.value,
|
||||
label=_('Endpoint suffix'), allow_null=True,
|
||||
)
|
||||
|
||||
# mapping
|
||||
|
||||
|
||||
replay_storage_type_serializer_classes_mapping = {
|
||||
const.ReplayStorageTypeChoices.s3.value: ReplayStorageTypeS3Serializer,
|
||||
const.ReplayStorageTypeChoices.ceph.value: ReplayStorageTypeCephSerializer,
|
||||
const.ReplayStorageTypeChoices.swift.value: ReplayStorageTypeSwiftSerializer,
|
||||
const.ReplayStorageTypeChoices.oss.value: ReplayStorageTypeOSSSerializer,
|
||||
const.ReplayStorageTypeChoices.azure.value: ReplayStorageTypeAzureSerializer
|
||||
}
|
||||
|
||||
# ReplayStorageSerializer
|
||||
|
||||
|
||||
class ReplayStorageSerializer(serializers.ModelSerializer):
|
||||
meta = MethodSerializer()
|
||||
|
||||
class Meta:
|
||||
model = ReplayStorage
|
||||
fields = ['id', 'name', 'type', 'meta', 'comment']
|
||||
|
||||
def validate_meta(self, meta):
|
||||
_meta = self.instance.meta if self.instance else {}
|
||||
_meta.update(meta)
|
||||
return _meta
|
||||
|
||||
class CommandStorageMetaDictField(CustomMetaDictField):
|
||||
type_fields_map = const.COMMAND_STORAGE_TYPE_FIELDS_MAP
|
||||
default_type = const.COMMAND_STORAGE_TYPE_SERVER
|
||||
convert_key_remove_type_prefix = True
|
||||
convert_key_to_upper = True
|
||||
def get_meta_serializer(self):
|
||||
serializer_class = None
|
||||
query_type = self.context['request'].query_params.get('type')
|
||||
if query_type:
|
||||
serializer_class = replay_storage_type_serializer_classes_mapping.get(query_type)
|
||||
if isinstance(self.instance, ReplayStorage):
|
||||
instance_type = self.instance.type
|
||||
serializer_class = replay_storage_type_serializer_classes_mapping.get(instance_type)
|
||||
if serializer_class is None:
|
||||
serializer_class = serializers.Serializer
|
||||
serializer = serializer_class()
|
||||
return serializer
|
||||
|
||||
|
||||
class CommandStorageSerializer(BaseStorageSerializerMixin,
|
||||
serializers.ModelSerializer):
|
||||
# Command storage serializers
|
||||
# ---------------------------
|
||||
|
||||
meta = CommandStorageMetaDictField()
|
||||
|
||||
type_fields_map = const.COMMAND_STORAGE_TYPE_FIELDS_MAP
|
||||
def es_host_format_validator(host):
|
||||
h = urlparse(host)
|
||||
default_error_msg = _('The address format is incorrect')
|
||||
if h.scheme not in ['http', 'https']:
|
||||
raise serializers.ValidationError(default_error_msg)
|
||||
if ':' not in h.netloc:
|
||||
raise serializers.ValidationError(default_error_msg)
|
||||
_host, _port = h.netloc.split(':')
|
||||
if not _host:
|
||||
error_msg = _('Host invalid')
|
||||
raise serializers.ValidationError(error_msg)
|
||||
if not _port.isdigit():
|
||||
error_msg = _('Port invalid')
|
||||
raise serializers.ValidationError(error_msg)
|
||||
return host
|
||||
|
||||
|
||||
class CommandStorageTypeESSerializer(serializers.Serializer):
|
||||
|
||||
hosts_help_text = '''
|
||||
Tip: If there are multiple hosts, use a comma (,) to separate them.
|
||||
(eg: http://www.jumpserver.a.com, http://www.jumpserver.b.com)
|
||||
'''
|
||||
HOSTS = serializers.ListField(
|
||||
child=serializers.CharField(validators=[es_host_format_validator]), label=_('Hosts'),
|
||||
help_text=_(hosts_help_text), allow_null=True
|
||||
)
|
||||
INDEX = serializers.CharField(
|
||||
max_length=1024, default='jumpserver', label=_('Index'), allow_null=True
|
||||
)
|
||||
DOC_TYPE = serializers.CharField(
|
||||
max_length=1024, read_only=True, default='command', label=_('Doc type'), allow_null=True
|
||||
)
|
||||
|
||||
# mapping
|
||||
|
||||
|
||||
command_storage_type_serializer_classes_mapping = {
|
||||
const.CommandStorageTypeChoices.es.value: CommandStorageTypeESSerializer
|
||||
}
|
||||
|
||||
# CommandStorageSerializer
|
||||
|
||||
|
||||
class CommandStorageSerializer(serializers.ModelSerializer):
|
||||
meta = MethodSerializer()
|
||||
|
||||
class Meta:
|
||||
model = CommandStorage
|
||||
fields = ['id', 'name', 'type', 'meta', 'comment']
|
||||
|
||||
def validate_meta(self, meta):
|
||||
_meta = self.instance.meta if self.instance else {}
|
||||
_meta.update(meta)
|
||||
return _meta
|
||||
|
||||
def get_meta_serializer(self):
|
||||
serializer_class = None
|
||||
query_type = self.context['request'].query_params.get('type')
|
||||
if query_type:
|
||||
serializer_class = command_storage_type_serializer_classes_mapping.get(query_type)
|
||||
if isinstance(self.instance, CommandStorage):
|
||||
instance_type = self.instance.type
|
||||
serializer_class = command_storage_type_serializer_classes_mapping.get(instance_type)
|
||||
if serializer_class is None:
|
||||
serializer_class = serializers.Serializer
|
||||
serializer = serializer_class()
|
||||
return serializer
|
||||
|
|
|
@ -73,7 +73,6 @@ def clean_expired_session_period():
|
|||
logger.info("Clean session replay done")
|
||||
|
||||
|
||||
|
||||
@shared_task
|
||||
def upload_session_replay_to_external_storage(session_id):
|
||||
logger.info(f'Start upload session to external storage: {session_id}')
|
||||
|
|
|
@ -39,7 +39,7 @@ def download_session_replay(session):
|
|||
configs = {
|
||||
storage.name: storage.config
|
||||
for storage in replay_storages
|
||||
if not storage.in_defaults()
|
||||
if not storage.type_null_or_server
|
||||
}
|
||||
if settings.SERVER_REPLAY_STORAGE:
|
||||
configs['SERVER_REPLAY_STORAGE'] = settings.SERVER_REPLAY_STORAGE
|
||||
|
|
|
@ -19,7 +19,7 @@ __all__ = ['TicketViewSet']
|
|||
|
||||
class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet):
|
||||
permission_classes = (IsValidUser,)
|
||||
serializer_class = serializers.TicketSerializer
|
||||
serializer_class = serializers.TicketDisplaySerializer
|
||||
serializer_classes = {
|
||||
'default': serializers.TicketDisplaySerializer,
|
||||
'display': serializers.TicketDisplaySerializer,
|
||||
|
|
|
@ -10,9 +10,9 @@ from tickets.utils import convert_model_instance_data_field_name_to_verbose_name
|
|||
class ConstructDisplayFieldMixin:
|
||||
def construct_meta_apply_application_open_fields_display(self):
|
||||
meta_display_fields = ['apply_category_display', 'apply_type_display']
|
||||
apply_category = self.meta['apply_category']
|
||||
apply_category = self.meta.get('apply_category')
|
||||
apply_category_display = ApplicationCategoryChoices.get_label(apply_category)
|
||||
apply_type = self.meta['apply_type']
|
||||
apply_type = self.meta.get('apply_type')
|
||||
apply_type_display = ApplicationTypeChoices.get_label(apply_type)
|
||||
meta_display_values = [apply_category_display, apply_type_display]
|
||||
meta_display = dict(zip(meta_display_fields, meta_display_values))
|
||||
|
@ -20,8 +20,8 @@ class ConstructDisplayFieldMixin:
|
|||
|
||||
def construct_meta_apply_application_approve_fields_display(self):
|
||||
meta_display_fields = ['approve_applications_snapshot', 'approve_system_users_snapshot']
|
||||
approve_applications_id = self.meta['approve_applications']
|
||||
approve_system_users_id = self.meta['approve_system_users']
|
||||
approve_applications_id = self.meta.get('approve_applications', [])
|
||||
approve_system_users_id = self.meta.get('approve_system_users', [])
|
||||
with tmp_to_org(self.org_id):
|
||||
approve_applications_snapshot = list(
|
||||
Application.objects.filter(id__in=approve_applications_id).values(
|
||||
|
@ -42,12 +42,12 @@ class ConstructDisplayFieldMixin:
|
|||
class ConstructBodyMixin:
|
||||
|
||||
def construct_apply_application_applied_body(self):
|
||||
apply_category_display = self.meta['apply_category_display']
|
||||
apply_type_display = self.meta['apply_type_display']
|
||||
apply_application_group = self.meta['apply_application_group']
|
||||
apply_system_user_group = self.meta['apply_system_user_group']
|
||||
apply_date_start = self.meta['apply_date_start']
|
||||
apply_date_expired = self.meta['apply_date_expired']
|
||||
apply_category_display = self.meta.get('apply_category_display')
|
||||
apply_type_display = self.meta.get('apply_type_display')
|
||||
apply_application_group = self.meta.get('apply_application_group', [])
|
||||
apply_system_user_group = self.meta.get('apply_system_user_group', [])
|
||||
apply_date_start = self.meta.get('apply_date_start')
|
||||
apply_date_expired = self.meta.get('apply_date_expired')
|
||||
applied_body = '''{}: {},
|
||||
{}: {},
|
||||
{}: {},
|
||||
|
@ -66,16 +66,16 @@ class ConstructBodyMixin:
|
|||
|
||||
def construct_apply_application_approved_body(self):
|
||||
# 审批信息
|
||||
approve_applications_snapshot = self.meta['approve_applications_snapshot']
|
||||
approve_applications_snapshot = self.meta.get('approve_applications_snapshot', [])
|
||||
approve_applications_snapshot_display = convert_model_instance_data_field_name_to_verbose_name(
|
||||
Application, approve_applications_snapshot
|
||||
)
|
||||
approve_system_users_snapshot = self.meta['approve_system_users_snapshot']
|
||||
approve_system_users_snapshot = self.meta.get('approve_system_users_snapshot', [])
|
||||
approve_system_users_snapshot_display = convert_model_instance_data_field_name_to_verbose_name(
|
||||
SystemUser, approve_system_users_snapshot
|
||||
)
|
||||
approve_date_start = self.meta['approve_date_start']
|
||||
approve_date_expired = self.meta['approve_date_expired']
|
||||
approve_date_start = self.meta.get('approve_date_start')
|
||||
approve_date_expired = self.meta.get('approve_date_expired')
|
||||
approved_body = '''{}: {},
|
||||
{}: {},
|
||||
{}: {},
|
||||
|
@ -97,12 +97,12 @@ class CreatePermissionMixin:
|
|||
if application_permission:
|
||||
return application_permission
|
||||
|
||||
apply_category = self.meta['apply_category']
|
||||
apply_type = self.meta['apply_type']
|
||||
approved_applications_id = self.meta['approve_applications']
|
||||
approve_system_users_id = self.meta['approve_system_users']
|
||||
approve_date_start = self.meta['approve_date_start']
|
||||
approve_date_expired = self.meta['approve_date_expired']
|
||||
apply_category = self.meta.get('apply_category')
|
||||
apply_type = self.meta.get('apply_type')
|
||||
approved_applications_id = self.meta.get('approve_applications', [])
|
||||
approve_system_users_id = self.meta.get('approve_system_users', [])
|
||||
approve_date_start = self.meta.get('approve_date_start')
|
||||
approve_date_expired = self.meta.get('approve_date_expired')
|
||||
permission_name = '{}({})'.format(
|
||||
__('Created by ticket ({})'.format(self.title)), str(self.id)[:4]
|
||||
)
|
||||
|
|
|
@ -10,7 +10,7 @@ class ConstructDisplayFieldMixin:
|
|||
def construct_meta_apply_asset_open_fields_display(self):
|
||||
meta_display_fields = ['apply_actions_display']
|
||||
|
||||
apply_actions = self.meta['apply_actions']
|
||||
apply_actions = self.meta.get('apply_actions', Action.NONE)
|
||||
apply_actions_display = Action.value_to_choices_display(apply_actions)
|
||||
|
||||
meta_display_values = [apply_actions_display]
|
||||
|
@ -21,10 +21,10 @@ class ConstructDisplayFieldMixin:
|
|||
meta_display_fields = [
|
||||
'approve_actions_display', 'approve_assets_snapshot', 'approve_system_users_snapshot'
|
||||
]
|
||||
approve_actions = self.meta['approve_actions']
|
||||
approve_assets_id = self.meta['approve_assets']
|
||||
approve_system_users_id = self.meta['approve_system_users']
|
||||
approve_actions = self.meta.get('approve_actions', Action.NONE)
|
||||
approve_actions_display = Action.value_to_choices_display(approve_actions)
|
||||
approve_assets_id = self.meta.get('approve_assets', [])
|
||||
approve_system_users_id = self.meta.get('approve_system_users', [])
|
||||
with tmp_to_org(self.org_id):
|
||||
approve_assets_snapshot = list(
|
||||
Asset.objects.filter(id__in=approve_assets_id).values(
|
||||
|
@ -46,12 +46,12 @@ class ConstructDisplayFieldMixin:
|
|||
|
||||
class ConstructBodyMixin:
|
||||
def construct_apply_asset_applied_body(self):
|
||||
apply_ip_group = self.meta['apply_ip_group']
|
||||
apply_hostname_group = self.meta['apply_hostname_group']
|
||||
apply_system_user_group = self.meta['apply_system_user_group']
|
||||
apply_actions_display = self.meta['apply_actions_display']
|
||||
apply_date_start = self.meta['apply_date_start']
|
||||
apply_date_expired = self.meta['apply_date_expired']
|
||||
apply_ip_group = self.meta.get('apply_ip_group', [])
|
||||
apply_hostname_group = self.meta.get('apply_hostname_group', [])
|
||||
apply_system_user_group = self.meta.get('apply_system_user_group', [])
|
||||
apply_actions_display = self.meta.get('apply_actions_display', [])
|
||||
apply_date_start = self.meta.get('apply_date_start')
|
||||
apply_date_expired = self.meta.get('apply_date_expired')
|
||||
applied_body = '''{}: {},
|
||||
{}: {},
|
||||
{}: {},
|
||||
|
@ -68,17 +68,17 @@ class ConstructBodyMixin:
|
|||
return applied_body
|
||||
|
||||
def construct_apply_asset_approved_body(self):
|
||||
approve_assets_snapshot = self.meta['approve_assets_snapshot']
|
||||
approve_assets_snapshot = self.meta.get('approve_assets_snapshot', [])
|
||||
approve_assets_snapshot_display = convert_model_instance_data_field_name_to_verbose_name(
|
||||
Asset, approve_assets_snapshot
|
||||
)
|
||||
approve_system_users_snapshot = self.meta['approve_system_users_snapshot']
|
||||
approve_system_users_snapshot = self.meta.get('approve_system_users_snapshot', [])
|
||||
approve_system_users_snapshot_display = convert_model_instance_data_field_name_to_verbose_name(
|
||||
SystemUser, approve_system_users_snapshot
|
||||
)
|
||||
approve_actions_display = self.meta['approve_actions_display']
|
||||
approve_date_start = self.meta['approve_date_start']
|
||||
approve_date_expired = self.meta['approve_date_expired']
|
||||
approve_actions_display = self.meta.get('approve_actions_display', [])
|
||||
approve_date_start = self.meta.get('approve_date_start')
|
||||
approve_date_expired = self.meta.get('approve_date_expired')
|
||||
approved_body = '''{}: {},
|
||||
{}: {},
|
||||
{}: {},
|
||||
|
@ -101,11 +101,11 @@ class CreatePermissionMixin:
|
|||
if asset_permission:
|
||||
return asset_permission
|
||||
|
||||
approve_assets_id = self.meta['approve_assets']
|
||||
approve_system_users_id = self.meta['approve_system_users']
|
||||
approve_actions = self.meta['approve_actions']
|
||||
approve_date_start = self.meta['approve_date_start']
|
||||
approve_date_expired = self.meta['approve_date_expired']
|
||||
approve_assets_id = self.meta.get('approve_assets', [])
|
||||
approve_system_users_id = self.meta.get('approve_system_users', [])
|
||||
approve_actions = self.meta.get('approve_actions', Action.NONE)
|
||||
approve_date_start = self.meta.get('approve_date_start')
|
||||
approve_date_expired = self.meta.get('approve_date_expired')
|
||||
permission_name = '{}({})'.format(
|
||||
__('Created by ticket ({})'.format(self.title)), str(self.id)[:4]
|
||||
)
|
||||
|
|
|
@ -4,9 +4,9 @@ from django.utils.translation import ugettext as __
|
|||
class ConstructBodyMixin:
|
||||
|
||||
def construct_login_confirm_applied_body(self):
|
||||
apply_login_ip = self.meta['apply_login_ip']
|
||||
apply_login_city = self.meta['apply_login_city']
|
||||
apply_login_datetime = self.meta['apply_login_datetime']
|
||||
apply_login_ip = self.meta.get('apply_login_ip')
|
||||
apply_login_city = self.meta.get('apply_login_city')
|
||||
apply_login_datetime = self.meta.get('apply_login_datetime')
|
||||
applied_body = '''{}: {},
|
||||
{}: {},
|
||||
{}: {}
|
||||
|
|
|
@ -17,14 +17,17 @@ action_approve = const.TicketActionChoices.approve.value
|
|||
|
||||
type_serializer_classes_mapping = {
|
||||
const.TicketTypeChoices.apply_asset.value: {
|
||||
'default': apply_asset.ApplyAssetSerializer,
|
||||
action_open: apply_asset.ApplySerializer,
|
||||
action_approve: apply_asset.ApproveSerializer,
|
||||
},
|
||||
const.TicketTypeChoices.apply_application.value: {
|
||||
'default': apply_application.ApplyApplicationSerializer,
|
||||
action_open: apply_application.ApplySerializer,
|
||||
action_approve: apply_application.ApproveSerializer,
|
||||
},
|
||||
const.TicketTypeChoices.login_confirm.value: {
|
||||
'default': login_confirm.LoginConfirmSerializer,
|
||||
action_open: login_confirm.ApplySerializer,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,88 +1,148 @@
|
|||
from rest_framework import serializers
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from django.db.models import Q
|
||||
from applications.models import Application
|
||||
from applications.const import ApplicationCategoryChoices, ApplicationTypeChoices
|
||||
from assets.models import SystemUser
|
||||
from .mixin import BaseApproveSerializerMixin
|
||||
from orgs.utils import tmp_to_org
|
||||
from tickets.models import Ticket
|
||||
|
||||
__all__ = [
|
||||
'ApplyApplicationTypeSerializer', 'ApplySerializer', 'ApproveSerializer',
|
||||
'ApplyApplicationSerializer', 'ApplySerializer', 'ApproveSerializer',
|
||||
]
|
||||
|
||||
|
||||
class ApplySerializer(serializers.Serializer):
|
||||
# 申请信息
|
||||
apply_category = serializers.ChoiceField(
|
||||
required=True, choices=ApplicationCategoryChoices.choices, label=_('Category')
|
||||
required=True, choices=ApplicationCategoryChoices.choices, label=_('Category'),
|
||||
allow_null=True,
|
||||
)
|
||||
apply_category_display = serializers.CharField(
|
||||
read_only=True, label=_('Category display')
|
||||
read_only=True, label=_('Category display'), allow_null=True,
|
||||
)
|
||||
apply_type = serializers.ChoiceField(
|
||||
required=True, choices=ApplicationTypeChoices.choices, label=_('Type')
|
||||
required=True, choices=ApplicationTypeChoices.choices, label=_('Type'),
|
||||
allow_null=True
|
||||
)
|
||||
apply_type_display = serializers.CharField(
|
||||
required=False, read_only=True, label=_('Type display')
|
||||
required=False, read_only=True, label=_('Type display'),
|
||||
allow_null=True
|
||||
)
|
||||
apply_application_group = serializers.ListField(
|
||||
required=False, child=serializers.CharField(), label=_('Application group'),
|
||||
default=list,
|
||||
default=list, allow_null=True
|
||||
)
|
||||
apply_system_user_group = serializers.ListField(
|
||||
required=False, child=serializers.CharField(), label=_('System user group'),
|
||||
default=list,
|
||||
default=list, allow_null=True
|
||||
)
|
||||
apply_date_start = serializers.DateTimeField(
|
||||
required=True, label=_('Date start')
|
||||
required=True, label=_('Date start'), allow_null=True
|
||||
)
|
||||
apply_date_expired = serializers.DateTimeField(
|
||||
required=True, label=_('Date expired')
|
||||
required=True, label=_('Date expired'), allow_null=True
|
||||
)
|
||||
|
||||
|
||||
class ApproveSerializer(BaseApproveSerializerMixin, serializers.Serializer):
|
||||
class ApproveSerializer(serializers.Serializer):
|
||||
# 审批信息
|
||||
approve_applications = serializers.ListField(
|
||||
required=True, child=serializers.UUIDField(), label=_('Approve applications')
|
||||
required=True, child=serializers.UUIDField(), label=_('Approve applications'),
|
||||
allow_null=True
|
||||
)
|
||||
approve_applications_snapshot = serializers.ListField(
|
||||
required=False, read_only=True, child=serializers.CharField(),
|
||||
label=_('Approve applications display'),
|
||||
label=_('Approve applications display'), allow_null=True,
|
||||
default=list
|
||||
)
|
||||
approve_system_users = serializers.ListField(
|
||||
required=True, child=serializers.UUIDField(), label=_('Approve system users')
|
||||
required=True, child=serializers.UUIDField(), label=_('Approve system users'),
|
||||
allow_null=True
|
||||
)
|
||||
approve_system_users_snapshot = serializers.ListField(
|
||||
required=False, read_only=True, child=serializers.CharField(),
|
||||
label=_('Approve system user display'),
|
||||
label=_('Approve system user display'), allow_null=True,
|
||||
default=list
|
||||
)
|
||||
approve_date_start = serializers.DateTimeField(
|
||||
required=True, label=_('Date start')
|
||||
required=True, label=_('Date start'), allow_null=True
|
||||
)
|
||||
approve_date_expired = serializers.DateTimeField(
|
||||
required=True, label=_('Date expired')
|
||||
required=True, label=_('Date expired'), allow_null=True
|
||||
)
|
||||
|
||||
def validate_approve_applications(self, approve_applications):
|
||||
application_type = self.root.instance.meta['apply_type']
|
||||
queries = {'type': application_type}
|
||||
applications_id = self.filter_approve_resources(
|
||||
resource_model=Application, resources_id=approve_applications, queries=queries
|
||||
)
|
||||
return applications_id
|
||||
if not isinstance(self.root.instance, Ticket):
|
||||
return []
|
||||
|
||||
with tmp_to_org(self.root.instance.org_id):
|
||||
apply_type = self.root.instance.meta.get('apply_type')
|
||||
queries = Q(type=apply_type)
|
||||
queries &= Q(id__in=approve_applications)
|
||||
applications_id = Application.objects.filter(queries).values_list('id', flat=True)
|
||||
applications_id = [str(application_id) for application_id in applications_id]
|
||||
if applications_id:
|
||||
return applications_id
|
||||
|
||||
raise serializers.ValidationError(_(
|
||||
'No `Application` are found under Organization `{}`'.format(self.root.instance.org_name)
|
||||
))
|
||||
|
||||
def validate_approve_system_users(self, approve_system_users):
|
||||
application_type = self.root.instance.meta['apply_type']
|
||||
protocol = SystemUser.get_protocol_by_application_type(application_type)
|
||||
queries = {'protocol': protocol}
|
||||
system_users_id = self.filter_approve_system_users(approve_system_users, queries)
|
||||
return system_users_id
|
||||
if not isinstance(self.root.instance, Ticket):
|
||||
return []
|
||||
|
||||
with tmp_to_org(self.root.instance.org_id):
|
||||
apply_type = self.root.instance.meta.get('apply_type')
|
||||
protocol = SystemUser.get_protocol_by_application_type(apply_type)
|
||||
queries = Q(protocol=protocol)
|
||||
queries &= Q(id__in=approve_system_users)
|
||||
system_users_id = SystemUser.objects.filter(queries).values_list('id', flat=True)
|
||||
system_users_id = [str(system_user_id) for system_user_id in system_users_id]
|
||||
if system_users_id:
|
||||
return system_users_id
|
||||
|
||||
raise serializers.ValidationError(_(
|
||||
'No `SystemUser` are found under Organization `{}`'.format(self.root.instance.org_name)
|
||||
))
|
||||
|
||||
|
||||
class ApplyApplicationTypeSerializer(ApplySerializer, ApproveSerializer):
|
||||
pass
|
||||
class ApplyApplicationSerializer(ApplySerializer, ApproveSerializer):
|
||||
# 推荐信息
|
||||
recommend_applications = serializers.SerializerMethodField()
|
||||
recommend_system_users = serializers.SerializerMethodField()
|
||||
|
||||
def get_recommend_applications(self, value):
|
||||
if not isinstance(self.root.instance, Ticket):
|
||||
return []
|
||||
|
||||
apply_application_group = value.get('apply_application_group', [])
|
||||
apply_type = value.get('apply_type')
|
||||
queries = Q()
|
||||
for application in apply_application_group:
|
||||
queries |= Q(name__icontains=application)
|
||||
queries &= Q(type=apply_type)
|
||||
|
||||
with tmp_to_org(self.root.instance.org_id):
|
||||
applications_id = Application.objects.filter(queries).values_list('id', flat=True)[:5]
|
||||
applications_id = [str(application_id) for application_id in applications_id]
|
||||
return applications_id
|
||||
|
||||
def get_recommend_system_users(self, value):
|
||||
if not isinstance(self.root.instance, Ticket):
|
||||
return []
|
||||
|
||||
apply_type = value.get('apply_type')
|
||||
apply_system_user_group = value.get('apply_system_user_group', [])
|
||||
protocol = SystemUser.get_protocol_by_application_type(apply_type)
|
||||
queries = Q()
|
||||
for system_user in apply_system_user_group:
|
||||
queries |= Q(username__icontains=system_user)
|
||||
queries |= Q(name__icontains=system_user)
|
||||
queries &= Q(protocol=protocol)
|
||||
|
||||
with tmp_to_org(self.root.instance.org_id):
|
||||
system_users_id = SystemUser.objects.filter(queries).values_list('id', flat=True)[:5]
|
||||
system_users_id = [str(system_user_id) for system_user_id in system_users_id]
|
||||
return system_users_id
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.db.models import Q
|
||||
from rest_framework import serializers
|
||||
from perms.serializers import ActionsField
|
||||
from assets.models import Asset, SystemUser
|
||||
from .mixin import BaseApproveSerializerMixin
|
||||
from orgs.utils import tmp_to_org
|
||||
from tickets.models import Ticket
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
@ -14,74 +16,129 @@ class ApplySerializer(serializers.Serializer):
|
|||
# 申请信息
|
||||
apply_ip_group = serializers.ListField(
|
||||
required=False, child=serializers.IPAddressField(), label=_('IP group'),
|
||||
default=list,
|
||||
default=list, allow_null=True,
|
||||
)
|
||||
apply_hostname_group = serializers.ListField(
|
||||
required=False, child=serializers.CharField(), label=_('Hostname group'),
|
||||
default=list,
|
||||
default=list, allow_null=True,
|
||||
)
|
||||
apply_system_user_group = serializers.ListField(
|
||||
required=False, child=serializers.CharField(), label=_('System user group'),
|
||||
default=list,
|
||||
default=list, allow_null=True
|
||||
)
|
||||
apply_actions = ActionsField(
|
||||
required=True
|
||||
required=True, allow_null=True
|
||||
)
|
||||
apply_actions_display = serializers.ListField(
|
||||
required=False, read_only=True, child=serializers.CharField(),
|
||||
label=_('Approve assets display'),
|
||||
label=_('Approve assets display'), allow_null=True,
|
||||
default=list,
|
||||
)
|
||||
apply_date_start = serializers.DateTimeField(
|
||||
required=True, label=_('Date start')
|
||||
required=True, label=_('Date start'), allow_null=True,
|
||||
)
|
||||
apply_date_expired = serializers.DateTimeField(
|
||||
required=True, label=_('Date expired')
|
||||
required=True, label=_('Date expired'), allow_null=True,
|
||||
)
|
||||
|
||||
|
||||
class ApproveSerializer(BaseApproveSerializerMixin, serializers.Serializer):
|
||||
class ApproveSerializer(serializers.Serializer):
|
||||
# 审批信息
|
||||
approve_assets = serializers.ListField(
|
||||
required=True, child=serializers.UUIDField(), label=_('Approve assets')
|
||||
required=True, allow_null=True, child=serializers.UUIDField(), label=_('Approve assets')
|
||||
)
|
||||
approve_assets_snapshot = serializers.ListField(
|
||||
required=False, read_only=True, child=serializers.DictField(),
|
||||
label=_('Approve assets display'),
|
||||
label=_('Approve assets display'), allow_null=True,
|
||||
default=list,
|
||||
)
|
||||
approve_system_users = serializers.ListField(
|
||||
required=True, child=serializers.UUIDField(), label=_('Approve system users')
|
||||
required=True, allow_null=True, child=serializers.UUIDField(),
|
||||
label=_('Approve system users')
|
||||
)
|
||||
approve_system_users_snapshot = serializers.ListField(
|
||||
required=False, read_only=True, child=serializers.DictField(),
|
||||
label=_('Approve assets display'),
|
||||
label=_('Approve assets display'), allow_null=True,
|
||||
default=list,
|
||||
)
|
||||
approve_actions = ActionsField(
|
||||
required=True
|
||||
required=True, allow_null=True,
|
||||
)
|
||||
approve_actions_display = serializers.ListField(
|
||||
required=False, read_only=True, child=serializers.CharField(),
|
||||
label=_('Approve assets display'),
|
||||
label=_('Approve assets display'), allow_null=True,
|
||||
default=list,
|
||||
)
|
||||
approve_date_start = serializers.DateTimeField(
|
||||
required=True, label=_('Date start')
|
||||
required=True, label=_('Date start'), allow_null=True,
|
||||
)
|
||||
approve_date_expired = serializers.DateTimeField(
|
||||
required=True, label=_('Date expired')
|
||||
required=True, label=_('Date expired'), allow_null=True
|
||||
)
|
||||
|
||||
def validate_approve_assets(self, approve_assets):
|
||||
assets_id = self.filter_approve_resources(resource_model=Asset, resources_id=approve_assets)
|
||||
return assets_id
|
||||
if not isinstance(self.root.instance, Ticket):
|
||||
return []
|
||||
|
||||
with tmp_to_org(self.root.instance.org_id):
|
||||
assets_id = Asset.objects.filter(id__in=approve_assets).values_list('id', flat=True)
|
||||
assets_id = [str(asset_id) for asset_id in assets_id]
|
||||
if assets_id:
|
||||
return assets_id
|
||||
|
||||
raise serializers.ValidationError(_(
|
||||
'No `Asset` are found under Organization `{}`'.format(self.root.instance.org_name)
|
||||
))
|
||||
|
||||
def validate_approve_system_users(self, approve_system_users):
|
||||
queries = {'protocol__in': SystemUser.ASSET_CATEGORY_PROTOCOLS}
|
||||
system_users_id = self.filter_approve_system_users(approve_system_users, queries)
|
||||
return system_users_id
|
||||
if not isinstance(self.root.instance, Ticket):
|
||||
return []
|
||||
|
||||
with tmp_to_org(self.root.instance.org_id):
|
||||
queries = Q(protocol__in=SystemUser.ASSET_CATEGORY_PROTOCOLS)
|
||||
queries &= Q(id__in=approve_system_users)
|
||||
system_users_id = SystemUser.objects.filter(queries).values_list('id', flat=True)
|
||||
system_users_id = [str(system_user_id) for system_user_id in system_users_id]
|
||||
if system_users_id:
|
||||
return system_users_id
|
||||
|
||||
raise serializers.ValidationError(_(
|
||||
'No `Asset` are found under Organization `{}`'.format(self.root.instance.org_name)
|
||||
))
|
||||
|
||||
|
||||
class ApplyAssetSerializer(ApplySerializer, ApproveSerializer):
|
||||
pass
|
||||
# 推荐信息
|
||||
recommend_assets = serializers.SerializerMethodField()
|
||||
recommend_system_users = serializers.SerializerMethodField()
|
||||
|
||||
def get_recommend_assets(self, value):
|
||||
if not isinstance(self.root.instance, Ticket):
|
||||
return []
|
||||
|
||||
apply_ip_group = value.get('apply_ip_group', [])
|
||||
apply_hostname_group = value.get('apply_hostname_group', [])
|
||||
queries = Q(ip__in=apply_ip_group)
|
||||
for hostname in apply_hostname_group:
|
||||
queries |= Q(hostname__icontains=hostname)
|
||||
|
||||
with tmp_to_org(self.root.instance.org_id):
|
||||
assets_id = Asset.objects.filter(queries).values_list('id', flat=True)[:5]
|
||||
assets_id = [str(asset_id) for asset_id in assets_id]
|
||||
return assets_id
|
||||
|
||||
def get_recommend_system_users(self, value):
|
||||
if not isinstance(self.root.instance, Ticket):
|
||||
return []
|
||||
|
||||
apply_system_user_group = value.get('apply_system_user_group', [])
|
||||
queries = Q()
|
||||
for system_user in apply_system_user_group:
|
||||
queries |= Q(username__icontains=system_user)
|
||||
queries |= Q(name__icontains=system_user)
|
||||
queries &= Q(protocol__in=SystemUser.ASSET_CATEGORY_PROTOCOLS)
|
||||
|
||||
with tmp_to_org(self.root.instance.org_id):
|
||||
system_users_id = SystemUser.objects.filter(queries).values_list('id', flat=True)[:5]
|
||||
system_users_id = [str(system_user_id) for system_user_id in system_users_id]
|
||||
return system_users_id
|
||||
|
|
|
@ -4,19 +4,22 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
|
||||
__all__ = [
|
||||
'ApplySerializer',
|
||||
'ApplySerializer', 'LoginConfirmSerializer',
|
||||
]
|
||||
|
||||
|
||||
class ApplySerializer(serializers.Serializer):
|
||||
# 申请信息
|
||||
apply_login_ip = serializers.IPAddressField(
|
||||
required=True, label=_('Login ip')
|
||||
required=True, label=_('Login ip'), allow_null=True
|
||||
)
|
||||
apply_login_city = serializers.CharField(
|
||||
required=True, max_length=64, label=_('Login city')
|
||||
required=True, max_length=64, label=_('Login city'), allow_null=True
|
||||
)
|
||||
apply_login_datetime = serializers.DateTimeField(
|
||||
required=True, label=_('Login datetime')
|
||||
required=True, label=_('Login datetime'), allow_null=True
|
||||
)
|
||||
|
||||
|
||||
class LoginConfirmSerializer(ApplySerializer):
|
||||
pass
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
from rest_framework import serializers
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orgs.utils import tmp_to_org
|
||||
from assets.models import SystemUser
|
||||
|
||||
|
||||
class BaseApproveSerializerMixin:
|
||||
|
||||
def _filter_approve_resources_by_org(self, model, resources_id):
|
||||
with tmp_to_org(self.root.instance.org_id):
|
||||
org_resources = model.objects.filter(id__in=resources_id)
|
||||
if not org_resources:
|
||||
error = _('None of the approved `{}` belong to Organization `{}`'
|
||||
''.format(model.__name__, self.root.instance.org_name))
|
||||
raise serializers.ValidationError(error)
|
||||
return org_resources
|
||||
|
||||
@staticmethod
|
||||
def _filter_approve_resources_by_queries(model, resources, queries=None):
|
||||
if queries:
|
||||
resources = resources.filter(**queries)
|
||||
if not resources:
|
||||
error = _('None of the approved `{}` does not comply with the filtering rules `{}`'
|
||||
''.format(model.__name__, queries))
|
||||
raise serializers.ValidationError(error)
|
||||
return resources
|
||||
|
||||
def filter_approve_resources(self, resource_model, resources_id, queries=None):
|
||||
resources = self._filter_approve_resources_by_org(resource_model, resources_id)
|
||||
resources = self._filter_approve_resources_by_queries(resource_model, resources, queries)
|
||||
resources_id = list(resources.values_list('id', flat=True))
|
||||
return resources_id
|
||||
|
||||
def filter_approve_system_users(self, system_users_id, queries=None):
|
||||
system_users_id = self.filter_approve_resources(
|
||||
resource_model=SystemUser, resources_id=system_users_id, queries=queries
|
||||
)
|
||||
return system_users_id
|
|
@ -22,6 +22,9 @@ class TicketSerializer(OrgResourceModelSerializerMixin):
|
|||
type_display = serializers.ReadOnlyField(source='get_type_display', label=_('Type'))
|
||||
action_display = serializers.ReadOnlyField(source='get_action_display', label=_('Action'))
|
||||
status_display = serializers.ReadOnlyField(source='get_status_display', label=_('Status'))
|
||||
action = ReadableHiddenField(default=const.TicketActionChoices.open.value)
|
||||
applicant = ReadableHiddenField(default=serializers.CurrentUserDefault())
|
||||
processor = ReadableHiddenField(default=serializers.CurrentUserDefault())
|
||||
meta = MethodSerializer()
|
||||
|
||||
class Meta:
|
||||
|
@ -38,48 +41,55 @@ class TicketSerializer(OrgResourceModelSerializerMixin):
|
|||
|
||||
def get_meta_serializer(self):
|
||||
request = self.context['request']
|
||||
view = self.context['view']
|
||||
query_type = request.query_params.get('type')
|
||||
query_action = request.query_params.get('action')
|
||||
view_action = view.action
|
||||
action = query_action if query_action else view_action
|
||||
if query_type:
|
||||
serializer_class = type_serializer_classes_mapping.get(query_type, {}).get(action)
|
||||
default_serializer_class = serializers.Serializer
|
||||
if isinstance(self.instance, Ticket):
|
||||
_type = self.instance.type
|
||||
else:
|
||||
serializer_class = None
|
||||
if serializer_class is None:
|
||||
serializer_class = serializers.Serializer
|
||||
serializer = serializer_class()
|
||||
return serializer
|
||||
_type = request.query_params.get('type')
|
||||
|
||||
if not _type:
|
||||
return default_serializer_class()
|
||||
|
||||
action_serializer_classes_mapping = type_serializer_classes_mapping.get(_type)
|
||||
if not action_serializer_classes_mapping:
|
||||
return default_serializer_class()
|
||||
|
||||
query_action = request.query_params.get('action')
|
||||
_action = query_action if query_action else self.context['view'].action
|
||||
serializer_class = action_serializer_classes_mapping.get(_action)
|
||||
if serializer_class:
|
||||
return serializer_class()
|
||||
|
||||
serializer_class = action_serializer_classes_mapping.get('default')
|
||||
if serializer_class:
|
||||
return serializer_class()
|
||||
|
||||
return default_serializer_class()
|
||||
|
||||
|
||||
class TicketDisplaySerializer(TicketSerializer):
|
||||
|
||||
class Meta(TicketSerializer.Meta):
|
||||
class Meta:
|
||||
model = Ticket
|
||||
fields = TicketSerializer.Meta.fields
|
||||
read_only_fields = TicketSerializer.Meta.fields
|
||||
|
||||
|
||||
class TicketActionSerializer(TicketSerializer):
|
||||
action = ReadableHiddenField(default=const.TicketActionChoices.open.value)
|
||||
|
||||
class Meta(TicketSerializer.Meta):
|
||||
required_fields = ['action']
|
||||
read_only_fields = list(set(TicketDisplaySerializer.Meta.fields) - set(required_fields))
|
||||
|
||||
|
||||
class TicketApplySerializer(TicketActionSerializer):
|
||||
applicant = ReadableHiddenField(default=serializers.CurrentUserDefault())
|
||||
class TicketApplySerializer(TicketSerializer):
|
||||
org_id = serializers.CharField(
|
||||
max_length=36, allow_blank=True, required=True, label=_("Organization")
|
||||
)
|
||||
|
||||
class Meta(TicketActionSerializer.Meta):
|
||||
required_fields = TicketActionSerializer.Meta.required_fields + [
|
||||
'id', 'title', 'type', 'applicant', 'meta', 'assignees', 'comment', 'org_id'
|
||||
class Meta:
|
||||
model = Ticket
|
||||
fields = TicketSerializer.Meta.fields
|
||||
required_fields = [
|
||||
'id', 'title', 'type', 'applicant', 'action', 'meta', 'assignees', 'comment', 'org_id'
|
||||
]
|
||||
read_only_fields = list(set(TicketDisplaySerializer.Meta.fields) - set(required_fields))
|
||||
read_only_fields = list(set(fields) - set(required_fields))
|
||||
extra_kwargs = {
|
||||
'type': {'required': True},
|
||||
'org_id': {'required': True},
|
||||
}
|
||||
|
||||
def validate_type(self, tp):
|
||||
|
@ -115,37 +125,43 @@ class TicketApplySerializer(TicketActionSerializer):
|
|||
return const.TicketActionChoices.open.value
|
||||
|
||||
|
||||
class TicketProcessSerializer(TicketActionSerializer):
|
||||
processor = ReadableHiddenField(default=serializers.CurrentUserDefault())
|
||||
class TicketApproveSerializer(TicketSerializer):
|
||||
|
||||
class Meta(TicketActionSerializer.Meta):
|
||||
required_fields = TicketActionSerializer.Meta.required_fields + ['processor']
|
||||
read_only_fields = list(set(TicketDisplaySerializer.Meta.fields) - set(required_fields))
|
||||
|
||||
|
||||
class TicketApproveSerializer(TicketProcessSerializer):
|
||||
|
||||
class Meta(TicketProcessSerializer.Meta):
|
||||
required_fields = TicketProcessSerializer.Meta.required_fields + ['meta']
|
||||
read_only_fields = list(set(TicketDisplaySerializer.Meta.fields) - set(required_fields))
|
||||
class Meta:
|
||||
model = Ticket
|
||||
fields = TicketSerializer.Meta.fields
|
||||
required_fields = ['processor', 'action', 'meta']
|
||||
read_only_fields = list(set(fields) - set(required_fields))
|
||||
|
||||
def validate_meta(self, meta):
|
||||
instance_meta = self.instance.meta
|
||||
instance_meta.update(meta)
|
||||
return instance_meta
|
||||
_meta = self.instance.meta if self.instance else {}
|
||||
_meta.update(meta)
|
||||
return _meta
|
||||
|
||||
@staticmethod
|
||||
def validate_action(action):
|
||||
return const.TicketActionChoices.approve.value
|
||||
|
||||
|
||||
class TicketRejectSerializer(TicketProcessSerializer):
|
||||
class TicketRejectSerializer(TicketSerializer):
|
||||
meta = MethodSerializer(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Ticket
|
||||
fields = TicketSerializer.Meta.fields
|
||||
read_only_fields = fields
|
||||
|
||||
def validate_action(self, action):
|
||||
return const.TicketActionChoices.reject.value
|
||||
|
||||
|
||||
class TicketCloseSerializer(TicketProcessSerializer):
|
||||
class TicketCloseSerializer(TicketSerializer):
|
||||
meta = MethodSerializer(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Ticket
|
||||
fields = TicketSerializer.Meta.fields
|
||||
read_only_fields = fields
|
||||
|
||||
def validate_action(self, action):
|
||||
return const.TicketActionChoices.close.value
|
||||
|
|
|
@ -17,26 +17,27 @@ logger = get_logger(__name__)
|
|||
|
||||
@receiver(pre_save, sender=Ticket)
|
||||
def on_ticket_pre_save(sender, instance=None, **kwargs):
|
||||
instance.set_display_fields()
|
||||
|
||||
if instance.has_processed:
|
||||
instance.set_status_closed()
|
||||
instance.set_display_fields()
|
||||
|
||||
|
||||
@receiver(post_save, sender=Ticket)
|
||||
def on_ticket_post_save(sender, instance=None, **kwargs):
|
||||
instance.create_action_comment()
|
||||
if instance.action_open:
|
||||
def on_ticket_post_save(sender, instance=None, created=False, **kwargs):
|
||||
|
||||
if created and instance.action_open:
|
||||
instance.create_action_comment()
|
||||
instance.create_applied_comment()
|
||||
return
|
||||
if instance.action_approve:
|
||||
instance.create_permission()
|
||||
instance.create_approved_comment()
|
||||
logger.debug(
|
||||
'Ticket () has processed, send mail to applicant: {}'.format(
|
||||
instance.title, instance.applicant_display
|
||||
)
|
||||
)
|
||||
send_ticket_processed_mail_to_applicant(instance)
|
||||
|
||||
if not created and instance.has_processed:
|
||||
instance.create_action_comment()
|
||||
msg = 'Ticket () has processed, send mail to applicant: {}'
|
||||
logger.debug(msg.format(instance.title, instance.applicant_display))
|
||||
send_ticket_processed_mail_to_applicant(instance)
|
||||
if instance.action_approve:
|
||||
instance.create_permission()
|
||||
instance.create_approved_comment()
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=Ticket.assignees.through)
|
||||
|
|
Loading…
Reference in New Issue