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()
|
attrs = MethodSerializer()
|
||||||
|
|
||||||
def get_attrs_serializer(self):
|
def get_attrs_serializer(self):
|
||||||
request = self.context['request']
|
serializer_class = None
|
||||||
query_type = request.query_params.get('type')
|
if isinstance(self.instance, models.Application):
|
||||||
query_category = request.query_params.get('category')
|
instance_type = self.instance.type
|
||||||
if query_type:
|
serializer_class = type_serializer_classes_mapping.get(instance_type)
|
||||||
serializer_class = type_serializer_classes_mapping.get(query_type)
|
|
||||||
elif query_category:
|
|
||||||
serializer_class = category_serializer_classes_mapping.get(query_category)
|
|
||||||
else:
|
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:
|
if serializer_class is None:
|
||||||
serializer_class = serializers.Serializer
|
serializer_class = serializers.Serializer
|
||||||
serializer = serializer_class()
|
serializer = serializer_class()
|
||||||
|
|
|
@ -6,4 +6,4 @@ __all__ = ['CloudSerializer']
|
||||||
|
|
||||||
|
|
||||||
class CloudSerializer(serializers.Serializer):
|
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):
|
class DBSerializer(serializers.Serializer):
|
||||||
host = serializers.CharField(max_length=128, label=_('Host'))
|
host = serializers.CharField(max_length=128, label=_('Host'), allow_null=True)
|
||||||
port = serializers.IntegerField(label=_('Port'))
|
port = serializers.IntegerField(label=_('Port'), allow_null=True)
|
||||||
# 添加allow_null=True,兼容之前数据库中database字段为None的情况
|
|
||||||
database = serializers.CharField(
|
database = serializers.CharField(
|
||||||
max_length=128, required=True, allow_null=True, label=_('Database')
|
max_length=128, required=True, allow_null=True, label=_('Database')
|
||||||
)
|
)
|
||||||
|
|
|
@ -29,8 +29,12 @@ class CharPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
|
||||||
|
|
||||||
class RemoteAppSerializer(serializers.Serializer):
|
class RemoteAppSerializer(serializers.Serializer):
|
||||||
asset_info = serializers.SerializerMethodField()
|
asset_info = serializers.SerializerMethodField()
|
||||||
asset = CharPrimaryKeyRelatedField(queryset=Asset.objects, required=False, label=_("Asset"))
|
asset = CharPrimaryKeyRelatedField(
|
||||||
path = serializers.CharField(max_length=128, label=_('Application path'))
|
queryset=Asset.objects, required=False, label=_("Asset"), allow_null=True
|
||||||
|
)
|
||||||
|
path = serializers.CharField(
|
||||||
|
max_length=128, label=_('Application path'), allow_null=True
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_asset_info(obj):
|
def get_asset_info(obj):
|
||||||
|
|
|
@ -11,15 +11,16 @@ class ChromeSerializer(RemoteAppSerializer):
|
||||||
CHROME_PATH = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
|
CHROME_PATH = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
|
||||||
|
|
||||||
path = serializers.CharField(
|
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(
|
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(
|
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(
|
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):
|
class CustomSerializer(RemoteAppSerializer):
|
||||||
custom_cmdline = serializers.CharField(
|
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(
|
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(
|
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(
|
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):
|
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'
|
MYSQL_WORKBENCH_PATH = 'C:\Program Files\MySQL\MySQL Workbench 8.0 CE\MySQLWorkbench.exe'
|
||||||
|
|
||||||
path = serializers.CharField(
|
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(
|
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(
|
mysql_workbench_port = serializers.IntegerField(
|
||||||
required=False, label=_('Port')
|
required=False, label=_('Port'),
|
||||||
|
allow_null=True,
|
||||||
)
|
)
|
||||||
mysql_workbench_name = serializers.CharField(
|
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(
|
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(
|
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):
|
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):
|
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())
|
VMWARE_CLIENT_PATH = ''.join(PATH.split())
|
||||||
|
|
||||||
path = serializers.CharField(
|
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(
|
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(
|
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(
|
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):
|
def get_protocol_by_application_type(cls, app_type):
|
||||||
from applications.const import ApplicationTypeChoices
|
from applications.const import ApplicationTypeChoices
|
||||||
if app_type in ApplicationTypeChoices.remote_app_types():
|
if app_type in ApplicationTypeChoices.remote_app_types():
|
||||||
return cls.PROTOCOL_RDP
|
protocol = cls.PROTOCOL_RDP
|
||||||
protocol = None
|
else:
|
||||||
other_types = [*ApplicationTypeChoices.db_types(), *ApplicationTypeChoices.cloud_types()]
|
|
||||||
if app_type in other_types and app_type in cls.APPLICATION_CATEGORY_PROTOCOLS:
|
|
||||||
protocol = app_type
|
protocol = app_type
|
||||||
return protocol
|
if protocol in cls.APPLICATION_CATEGORY_PROTOCOLS:
|
||||||
|
return protocol
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['name']
|
ordering = ['name']
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
|
|
||||||
import copy
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'ReadableHiddenField', 'CustomMetaDictField',
|
'ReadableHiddenField',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,87 +23,3 @@ class ReadableHiddenField(serializers.HiddenField):
|
||||||
if hasattr(value, 'id'):
|
if hasattr(value, 'id'):
|
||||||
return getattr(value, 'id')
|
return getattr(value, 'id')
|
||||||
return value
|
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 import serializers
|
||||||
from rest_framework.serializers import Serializer
|
from rest_framework.serializers import Serializer
|
||||||
from rest_framework.serializers import ModelSerializer
|
from rest_framework.serializers import ModelSerializer
|
||||||
|
@ -38,10 +39,10 @@ class MethodSerializer(serializers.Serializer):
|
||||||
@cached_property
|
@cached_property
|
||||||
def serializer(self) -> serializers.Serializer:
|
def serializer(self) -> serializers.Serializer:
|
||||||
method = getattr(self.parent, self.method_name)
|
method = getattr(self.parent, self.method_name)
|
||||||
return method()
|
_serializer = method()
|
||||||
|
# 设置serializer的parent值,否则在serializer实例中获取parent会出现断层
|
||||||
def get_fields(self):
|
setattr(_serializer, 'parent', self.parent)
|
||||||
return self.serializer.get_fields()
|
return _serializer
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def fields(self):
|
def fields(self):
|
||||||
|
@ -50,10 +51,16 @@ class MethodSerializer(serializers.Serializer):
|
||||||
这样在调用 field.parent 时, 才会达到预期的结果,
|
这样在调用 field.parent 时, 才会达到预期的结果,
|
||||||
比如: serializers.SerializerMethodField
|
比如: serializers.SerializerMethodField
|
||||||
"""
|
"""
|
||||||
fields = BindingDict(self.serializer)
|
return self.serializer.fields
|
||||||
for key, value in self.get_fields().items():
|
|
||||||
fields[key] = value
|
def run_validation(self, data=serializers.empty):
|
||||||
return fields
|
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
|
# Other Serializer
|
||||||
|
|
|
@ -20,10 +20,10 @@ class BaseStorageViewSetMixin:
|
||||||
|
|
||||||
def destroy(self, request, *args, **kwargs):
|
def destroy(self, request, *args, **kwargs):
|
||||||
instance = self.get_object()
|
instance = self.get_object()
|
||||||
if instance.in_defaults():
|
if instance.type_null_or_server:
|
||||||
data = {'msg': _('Deleting the default storage is not allowed')}
|
data = {'msg': _('Deleting the default storage is not allowed')}
|
||||||
return Response(data=data, status=status.HTTP_400_BAD_REQUEST)
|
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')}
|
data = {'msg': _('Cannot delete storage that is being used')}
|
||||||
return Response(data=data, status=status.HTTP_400_BAD_REQUEST)
|
return Response(data=data, status=status.HTTP_400_BAD_REQUEST)
|
||||||
return super().destroy(request, *args, **kwargs)
|
return super().destroy(request, *args, **kwargs)
|
||||||
|
@ -67,11 +67,9 @@ class BaseStorageTestConnectiveMixin:
|
||||||
return Response(data)
|
return Response(data)
|
||||||
|
|
||||||
|
|
||||||
class CommandStorageTestConnectiveApi(BaseStorageTestConnectiveMixin,
|
class CommandStorageTestConnectiveApi(BaseStorageTestConnectiveMixin, generics.RetrieveAPIView):
|
||||||
generics.RetrieveAPIView):
|
|
||||||
queryset = CommandStorage.objects.all()
|
queryset = CommandStorage.objects.all()
|
||||||
|
|
||||||
|
|
||||||
class ReplayStorageTestConnectiveApi(BaseStorageTestConnectiveMixin,
|
class ReplayStorageTestConnectiveApi(BaseStorageTestConnectiveMixin, generics.RetrieveAPIView):
|
||||||
generics.RetrieveAPIView):
|
|
||||||
queryset = ReplayStorage.objects.all()
|
queryset = ReplayStorage.objects.all()
|
||||||
|
|
|
@ -148,7 +148,5 @@ class TerminalConfig(APIView):
|
||||||
permission_classes = (IsAppUser,)
|
permission_classes = (IsAppUser,)
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
user = request.user
|
config = request.user.terminal.config
|
||||||
terminal = user.terminal
|
return Response(config, status=200)
|
||||||
configs = terminal.config
|
|
||||||
return Response(configs, status=200)
|
|
|
@ -8,4 +8,4 @@ class TerminalConfig(AppConfig):
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
from . import signals_handler
|
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 django.utils.functional import LazyObject
|
||||||
|
|
||||||
from .command.serializers import SessionCommandSerializer
|
from .command.serializers import SessionCommandSerializer
|
||||||
from ..const import COMMAND_STORAGE_TYPE_SERVER
|
|
||||||
|
|
||||||
|
|
||||||
TYPE_ENGINE_MAPPING = {
|
TYPE_ENGINE_MAPPING = {
|
||||||
|
@ -30,13 +29,12 @@ def get_terminal_command_storages():
|
||||||
from ..models import CommandStorage
|
from ..models import CommandStorage
|
||||||
storage_list = {}
|
storage_list = {}
|
||||||
for s in CommandStorage.objects.all():
|
for s in CommandStorage.objects.all():
|
||||||
tp = s.type
|
if s.type_server:
|
||||||
if tp == COMMAND_STORAGE_TYPE_SERVER:
|
|
||||||
storage = get_command_storage()
|
storage = get_command_storage()
|
||||||
else:
|
else:
|
||||||
if not TYPE_ENGINE_MAPPING.get(tp):
|
if not TYPE_ENGINE_MAPPING.get(s.type):
|
||||||
continue
|
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 = engine_class.CommandStore(s.config)
|
||||||
storage_list[s.name] = storage
|
storage_list[s.name] = storage
|
||||||
return storage_list
|
return storage_list
|
||||||
|
|
|
@ -1,117 +1,31 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- 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.db.models import TextChoices
|
||||||
from django.utils.translation import ugettext_lazy as _
|
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):
|
class ComponentStatusChoices(TextChoices):
|
||||||
critical = 'critical', _('Critical')
|
critical = 'critical', _('Critical')
|
||||||
|
|
|
@ -2,102 +2,113 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import jms_storage
|
import jms_storage
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from common.mixins import CommonModelMixin
|
from common.mixins import CommonModelMixin
|
||||||
from common.fields.model import EncryptJsonDictTextField
|
from common.fields.model import EncryptJsonDictTextField
|
||||||
from .. import const
|
|
||||||
from .terminal import Terminal
|
from .terminal import Terminal
|
||||||
|
from .. import const
|
||||||
|
|
||||||
|
|
||||||
class CommandStorage(CommonModelMixin):
|
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)
|
name = models.CharField(max_length=128, verbose_name=_("Name"), unique=True)
|
||||||
type = models.CharField(
|
type = models.CharField(
|
||||||
max_length=16, choices=TYPE_CHOICES, verbose_name=_('Type'),
|
max_length=16, choices=const.CommandStorageTypeChoices.choices,
|
||||||
default=TYPE_SERVER
|
default=const.CommandStorageTypeChoices.server.value, verbose_name=_('Type'),
|
||||||
)
|
)
|
||||||
meta = EncryptJsonDictTextField(default={})
|
meta = EncryptJsonDictTextField(default={})
|
||||||
comment = models.TextField(
|
comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment'))
|
||||||
max_length=128, default='', blank=True, verbose_name=_('Comment')
|
|
||||||
)
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
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
|
@property
|
||||||
def config(self):
|
def config(self):
|
||||||
config = self.meta
|
config = self.meta
|
||||||
config.update({'TYPE': self.type})
|
config.update({'TYPE': self.type})
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def in_defaults(self):
|
|
||||||
return self.type in self.TYPE_DEFAULTS
|
|
||||||
|
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
if self.in_defaults():
|
if self.type_null_or_server:
|
||||||
return True
|
return True
|
||||||
storage = jms_storage.get_log_storage(self.config)
|
storage = jms_storage.get_log_storage(self.config)
|
||||||
return storage.ping()
|
return storage.ping()
|
||||||
|
|
||||||
def is_using(self):
|
def is_use(self):
|
||||||
return Terminal.objects.filter(command_storage=self.name).exists()
|
return Terminal.objects.filter(command_storage=self.name).exists()
|
||||||
|
|
||||||
|
|
||||||
class ReplayStorage(CommonModelMixin):
|
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)
|
name = models.CharField(max_length=128, verbose_name=_("Name"), unique=True)
|
||||||
type = models.CharField(
|
type = models.CharField(
|
||||||
max_length=16, choices=TYPE_CHOICES, verbose_name=_('Type'),
|
max_length=16, choices=const.ReplayStorageTypeChoices.choices,
|
||||||
default=TYPE_SERVER
|
default=const.ReplayStorageTypeChoices.server.value, verbose_name=_('Type')
|
||||||
)
|
)
|
||||||
meta = EncryptJsonDictTextField(default={})
|
meta = EncryptJsonDictTextField(default={})
|
||||||
comment = models.TextField(
|
comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment'))
|
||||||
max_length=128, default='', blank=True, verbose_name=_('Comment')
|
|
||||||
)
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def convert_type(self):
|
@property
|
||||||
s3_type_list = [const.REPLAY_STORAGE_TYPE_CEPH]
|
def type_null(self):
|
||||||
tp = self.type
|
return self.type == const.ReplayStorageTypeChoices.null.value
|
||||||
if tp in s3_type_list:
|
|
||||||
tp = const.REPLAY_STORAGE_TYPE_S3
|
|
||||||
return tp
|
|
||||||
|
|
||||||
def get_extra_config(self):
|
@property
|
||||||
extra_config = {'TYPE': self.convert_type()}
|
def type_server(self):
|
||||||
if self.type == const.REPLAY_STORAGE_TYPE_SWIFT:
|
return self.type == const.ReplayStorageTypeChoices.server.value
|
||||||
extra_config.update({'signer': 'S3SignerType'})
|
|
||||||
return extra_config
|
@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
|
@property
|
||||||
def config(self):
|
def config(self):
|
||||||
config = self.meta
|
_config = {}
|
||||||
extra_config = self.get_extra_config()
|
|
||||||
config.update(extra_config)
|
|
||||||
return config
|
|
||||||
|
|
||||||
def in_defaults(self):
|
# add type config
|
||||||
return self.type in self.TYPE_DEFAULTS
|
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):
|
def is_valid(self):
|
||||||
if self.in_defaults():
|
if self.type_null_or_server:
|
||||||
return True
|
return True
|
||||||
storage = jms_storage.get_object_storage(self.config)
|
storage = jms_storage.get_object_storage(self.config)
|
||||||
target = 'tests.py'
|
target = 'tests.py'
|
||||||
src = os.path.join(settings.BASE_DIR, 'common', target)
|
src = os.path.join(settings.BASE_DIR, 'common', target)
|
||||||
return storage.is_valid(src, target)
|
return storage.is_valid(src, target)
|
||||||
|
|
||||||
def is_using(self):
|
def is_use(self):
|
||||||
return Terminal.objects.filter(replay_storage=self.name).exists()
|
return Terminal.objects.filter(replay_storage=self.name).exists()
|
||||||
|
|
|
@ -2,74 +2,197 @@
|
||||||
#
|
#
|
||||||
import copy
|
import copy
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
from urllib.parse import urlparse
|
||||||
from common.drf.fields import CustomMetaDictField
|
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 ..models import ReplayStorage, CommandStorage
|
||||||
from .. import const
|
from .. import const
|
||||||
|
|
||||||
|
|
||||||
class ReplayStorageMetaDictField(CustomMetaDictField):
|
# Replay storage serializers
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
class BaseStorageSerializerMixin:
|
class ReplayStorageTypeBaseSerializer(serializers.Serializer):
|
||||||
type_fields_map = None
|
BUCKET = serializers.CharField(
|
||||||
|
required=True, max_length=1024, label=_('Bucket'), allow_null=True
|
||||||
def process_meta(self, instance, validated_data):
|
)
|
||||||
new_meta = copy.deepcopy(validated_data.get('meta', {}))
|
ACCESS_KEY = serializers.CharField(
|
||||||
tp = validated_data.get('type', '')
|
max_length=1024, required=False, allow_blank=True, write_only=True, label=_('Access key'),
|
||||||
|
allow_null=True,
|
||||||
if tp != instance.type:
|
)
|
||||||
return new_meta
|
SECRET_KEY = serializers.CharField(
|
||||||
|
max_length=1024, required=False, allow_blank=True, write_only=True, label=_('Secret key'),
|
||||||
old_meta = instance.meta
|
allow_null=True,
|
||||||
fields = self.type_fields_map.get(instance.type, [])
|
)
|
||||||
for field in fields:
|
ENDPOINT = serializers.CharField(
|
||||||
if not field.get('write_only', False):
|
required=True, max_length=1024, label=_('Endpoint'), allow_null=True,
|
||||||
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 ReplayStorageSerializer(BaseStorageSerializerMixin,
|
class ReplayStorageTypeS3Serializer(ReplayStorageTypeBaseSerializer):
|
||||||
serializers.ModelSerializer):
|
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:
|
class Meta:
|
||||||
model = ReplayStorage
|
model = ReplayStorage
|
||||||
fields = ['id', 'name', 'type', 'meta', 'comment']
|
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):
|
def get_meta_serializer(self):
|
||||||
type_fields_map = const.COMMAND_STORAGE_TYPE_FIELDS_MAP
|
serializer_class = None
|
||||||
default_type = const.COMMAND_STORAGE_TYPE_SERVER
|
query_type = self.context['request'].query_params.get('type')
|
||||||
convert_key_remove_type_prefix = True
|
if query_type:
|
||||||
convert_key_to_upper = True
|
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,
|
# Command storage serializers
|
||||||
serializers.ModelSerializer):
|
# ---------------------------
|
||||||
|
|
||||||
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:
|
class Meta:
|
||||||
model = CommandStorage
|
model = CommandStorage
|
||||||
fields = ['id', 'name', 'type', 'meta', 'comment']
|
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")
|
logger.info("Clean session replay done")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def upload_session_replay_to_external_storage(session_id):
|
def upload_session_replay_to_external_storage(session_id):
|
||||||
logger.info(f'Start upload session 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 = {
|
configs = {
|
||||||
storage.name: storage.config
|
storage.name: storage.config
|
||||||
for storage in replay_storages
|
for storage in replay_storages
|
||||||
if not storage.in_defaults()
|
if not storage.type_null_or_server
|
||||||
}
|
}
|
||||||
if settings.SERVER_REPLAY_STORAGE:
|
if settings.SERVER_REPLAY_STORAGE:
|
||||||
configs['SERVER_REPLAY_STORAGE'] = settings.SERVER_REPLAY_STORAGE
|
configs['SERVER_REPLAY_STORAGE'] = settings.SERVER_REPLAY_STORAGE
|
||||||
|
|
|
@ -19,7 +19,7 @@ __all__ = ['TicketViewSet']
|
||||||
|
|
||||||
class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet):
|
class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet):
|
||||||
permission_classes = (IsValidUser,)
|
permission_classes = (IsValidUser,)
|
||||||
serializer_class = serializers.TicketSerializer
|
serializer_class = serializers.TicketDisplaySerializer
|
||||||
serializer_classes = {
|
serializer_classes = {
|
||||||
'default': serializers.TicketDisplaySerializer,
|
'default': serializers.TicketDisplaySerializer,
|
||||||
'display': serializers.TicketDisplaySerializer,
|
'display': serializers.TicketDisplaySerializer,
|
||||||
|
|
|
@ -10,9 +10,9 @@ from tickets.utils import convert_model_instance_data_field_name_to_verbose_name
|
||||||
class ConstructDisplayFieldMixin:
|
class ConstructDisplayFieldMixin:
|
||||||
def construct_meta_apply_application_open_fields_display(self):
|
def construct_meta_apply_application_open_fields_display(self):
|
||||||
meta_display_fields = ['apply_category_display', 'apply_type_display']
|
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_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)
|
apply_type_display = ApplicationTypeChoices.get_label(apply_type)
|
||||||
meta_display_values = [apply_category_display, apply_type_display]
|
meta_display_values = [apply_category_display, apply_type_display]
|
||||||
meta_display = dict(zip(meta_display_fields, meta_display_values))
|
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):
|
def construct_meta_apply_application_approve_fields_display(self):
|
||||||
meta_display_fields = ['approve_applications_snapshot', 'approve_system_users_snapshot']
|
meta_display_fields = ['approve_applications_snapshot', 'approve_system_users_snapshot']
|
||||||
approve_applications_id = self.meta['approve_applications']
|
approve_applications_id = self.meta.get('approve_applications', [])
|
||||||
approve_system_users_id = self.meta['approve_system_users']
|
approve_system_users_id = self.meta.get('approve_system_users', [])
|
||||||
with tmp_to_org(self.org_id):
|
with tmp_to_org(self.org_id):
|
||||||
approve_applications_snapshot = list(
|
approve_applications_snapshot = list(
|
||||||
Application.objects.filter(id__in=approve_applications_id).values(
|
Application.objects.filter(id__in=approve_applications_id).values(
|
||||||
|
@ -42,12 +42,12 @@ class ConstructDisplayFieldMixin:
|
||||||
class ConstructBodyMixin:
|
class ConstructBodyMixin:
|
||||||
|
|
||||||
def construct_apply_application_applied_body(self):
|
def construct_apply_application_applied_body(self):
|
||||||
apply_category_display = self.meta['apply_category_display']
|
apply_category_display = self.meta.get('apply_category_display')
|
||||||
apply_type_display = self.meta['apply_type_display']
|
apply_type_display = self.meta.get('apply_type_display')
|
||||||
apply_application_group = self.meta['apply_application_group']
|
apply_application_group = self.meta.get('apply_application_group', [])
|
||||||
apply_system_user_group = self.meta['apply_system_user_group']
|
apply_system_user_group = self.meta.get('apply_system_user_group', [])
|
||||||
apply_date_start = self.meta['apply_date_start']
|
apply_date_start = self.meta.get('apply_date_start')
|
||||||
apply_date_expired = self.meta['apply_date_expired']
|
apply_date_expired = self.meta.get('apply_date_expired')
|
||||||
applied_body = '''{}: {},
|
applied_body = '''{}: {},
|
||||||
{}: {},
|
{}: {},
|
||||||
{}: {},
|
{}: {},
|
||||||
|
@ -66,16 +66,16 @@ class ConstructBodyMixin:
|
||||||
|
|
||||||
def construct_apply_application_approved_body(self):
|
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(
|
approve_applications_snapshot_display = convert_model_instance_data_field_name_to_verbose_name(
|
||||||
Application, approve_applications_snapshot
|
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(
|
approve_system_users_snapshot_display = convert_model_instance_data_field_name_to_verbose_name(
|
||||||
SystemUser, approve_system_users_snapshot
|
SystemUser, approve_system_users_snapshot
|
||||||
)
|
)
|
||||||
approve_date_start = self.meta['approve_date_start']
|
approve_date_start = self.meta.get('approve_date_start')
|
||||||
approve_date_expired = self.meta['approve_date_expired']
|
approve_date_expired = self.meta.get('approve_date_expired')
|
||||||
approved_body = '''{}: {},
|
approved_body = '''{}: {},
|
||||||
{}: {},
|
{}: {},
|
||||||
{}: {},
|
{}: {},
|
||||||
|
@ -97,12 +97,12 @@ class CreatePermissionMixin:
|
||||||
if application_permission:
|
if application_permission:
|
||||||
return application_permission
|
return application_permission
|
||||||
|
|
||||||
apply_category = self.meta['apply_category']
|
apply_category = self.meta.get('apply_category')
|
||||||
apply_type = self.meta['apply_type']
|
apply_type = self.meta.get('apply_type')
|
||||||
approved_applications_id = self.meta['approve_applications']
|
approved_applications_id = self.meta.get('approve_applications', [])
|
||||||
approve_system_users_id = self.meta['approve_system_users']
|
approve_system_users_id = self.meta.get('approve_system_users', [])
|
||||||
approve_date_start = self.meta['approve_date_start']
|
approve_date_start = self.meta.get('approve_date_start')
|
||||||
approve_date_expired = self.meta['approve_date_expired']
|
approve_date_expired = self.meta.get('approve_date_expired')
|
||||||
permission_name = '{}({})'.format(
|
permission_name = '{}({})'.format(
|
||||||
__('Created by ticket ({})'.format(self.title)), str(self.id)[:4]
|
__('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):
|
def construct_meta_apply_asset_open_fields_display(self):
|
||||||
meta_display_fields = ['apply_actions_display']
|
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)
|
apply_actions_display = Action.value_to_choices_display(apply_actions)
|
||||||
|
|
||||||
meta_display_values = [apply_actions_display]
|
meta_display_values = [apply_actions_display]
|
||||||
|
@ -21,10 +21,10 @@ class ConstructDisplayFieldMixin:
|
||||||
meta_display_fields = [
|
meta_display_fields = [
|
||||||
'approve_actions_display', 'approve_assets_snapshot', 'approve_system_users_snapshot'
|
'approve_actions_display', 'approve_assets_snapshot', 'approve_system_users_snapshot'
|
||||||
]
|
]
|
||||||
approve_actions = self.meta['approve_actions']
|
approve_actions = self.meta.get('approve_actions', Action.NONE)
|
||||||
approve_assets_id = self.meta['approve_assets']
|
|
||||||
approve_system_users_id = self.meta['approve_system_users']
|
|
||||||
approve_actions_display = Action.value_to_choices_display(approve_actions)
|
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):
|
with tmp_to_org(self.org_id):
|
||||||
approve_assets_snapshot = list(
|
approve_assets_snapshot = list(
|
||||||
Asset.objects.filter(id__in=approve_assets_id).values(
|
Asset.objects.filter(id__in=approve_assets_id).values(
|
||||||
|
@ -46,12 +46,12 @@ class ConstructDisplayFieldMixin:
|
||||||
|
|
||||||
class ConstructBodyMixin:
|
class ConstructBodyMixin:
|
||||||
def construct_apply_asset_applied_body(self):
|
def construct_apply_asset_applied_body(self):
|
||||||
apply_ip_group = self.meta['apply_ip_group']
|
apply_ip_group = self.meta.get('apply_ip_group', [])
|
||||||
apply_hostname_group = self.meta['apply_hostname_group']
|
apply_hostname_group = self.meta.get('apply_hostname_group', [])
|
||||||
apply_system_user_group = self.meta['apply_system_user_group']
|
apply_system_user_group = self.meta.get('apply_system_user_group', [])
|
||||||
apply_actions_display = self.meta['apply_actions_display']
|
apply_actions_display = self.meta.get('apply_actions_display', [])
|
||||||
apply_date_start = self.meta['apply_date_start']
|
apply_date_start = self.meta.get('apply_date_start')
|
||||||
apply_date_expired = self.meta['apply_date_expired']
|
apply_date_expired = self.meta.get('apply_date_expired')
|
||||||
applied_body = '''{}: {},
|
applied_body = '''{}: {},
|
||||||
{}: {},
|
{}: {},
|
||||||
{}: {},
|
{}: {},
|
||||||
|
@ -68,17 +68,17 @@ class ConstructBodyMixin:
|
||||||
return applied_body
|
return applied_body
|
||||||
|
|
||||||
def construct_apply_asset_approved_body(self):
|
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(
|
approve_assets_snapshot_display = convert_model_instance_data_field_name_to_verbose_name(
|
||||||
Asset, approve_assets_snapshot
|
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(
|
approve_system_users_snapshot_display = convert_model_instance_data_field_name_to_verbose_name(
|
||||||
SystemUser, approve_system_users_snapshot
|
SystemUser, approve_system_users_snapshot
|
||||||
)
|
)
|
||||||
approve_actions_display = self.meta['approve_actions_display']
|
approve_actions_display = self.meta.get('approve_actions_display', [])
|
||||||
approve_date_start = self.meta['approve_date_start']
|
approve_date_start = self.meta.get('approve_date_start')
|
||||||
approve_date_expired = self.meta['approve_date_expired']
|
approve_date_expired = self.meta.get('approve_date_expired')
|
||||||
approved_body = '''{}: {},
|
approved_body = '''{}: {},
|
||||||
{}: {},
|
{}: {},
|
||||||
{}: {},
|
{}: {},
|
||||||
|
@ -101,11 +101,11 @@ class CreatePermissionMixin:
|
||||||
if asset_permission:
|
if asset_permission:
|
||||||
return asset_permission
|
return asset_permission
|
||||||
|
|
||||||
approve_assets_id = self.meta['approve_assets']
|
approve_assets_id = self.meta.get('approve_assets', [])
|
||||||
approve_system_users_id = self.meta['approve_system_users']
|
approve_system_users_id = self.meta.get('approve_system_users', [])
|
||||||
approve_actions = self.meta['approve_actions']
|
approve_actions = self.meta.get('approve_actions', Action.NONE)
|
||||||
approve_date_start = self.meta['approve_date_start']
|
approve_date_start = self.meta.get('approve_date_start')
|
||||||
approve_date_expired = self.meta['approve_date_expired']
|
approve_date_expired = self.meta.get('approve_date_expired')
|
||||||
permission_name = '{}({})'.format(
|
permission_name = '{}({})'.format(
|
||||||
__('Created by ticket ({})'.format(self.title)), str(self.id)[:4]
|
__('Created by ticket ({})'.format(self.title)), str(self.id)[:4]
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,9 +4,9 @@ from django.utils.translation import ugettext as __
|
||||||
class ConstructBodyMixin:
|
class ConstructBodyMixin:
|
||||||
|
|
||||||
def construct_login_confirm_applied_body(self):
|
def construct_login_confirm_applied_body(self):
|
||||||
apply_login_ip = self.meta['apply_login_ip']
|
apply_login_ip = self.meta.get('apply_login_ip')
|
||||||
apply_login_city = self.meta['apply_login_city']
|
apply_login_city = self.meta.get('apply_login_city')
|
||||||
apply_login_datetime = self.meta['apply_login_datetime']
|
apply_login_datetime = self.meta.get('apply_login_datetime')
|
||||||
applied_body = '''{}: {},
|
applied_body = '''{}: {},
|
||||||
{}: {},
|
{}: {},
|
||||||
{}: {}
|
{}: {}
|
||||||
|
|
|
@ -17,14 +17,17 @@ action_approve = const.TicketActionChoices.approve.value
|
||||||
|
|
||||||
type_serializer_classes_mapping = {
|
type_serializer_classes_mapping = {
|
||||||
const.TicketTypeChoices.apply_asset.value: {
|
const.TicketTypeChoices.apply_asset.value: {
|
||||||
|
'default': apply_asset.ApplyAssetSerializer,
|
||||||
action_open: apply_asset.ApplySerializer,
|
action_open: apply_asset.ApplySerializer,
|
||||||
action_approve: apply_asset.ApproveSerializer,
|
action_approve: apply_asset.ApproveSerializer,
|
||||||
},
|
},
|
||||||
const.TicketTypeChoices.apply_application.value: {
|
const.TicketTypeChoices.apply_application.value: {
|
||||||
|
'default': apply_application.ApplyApplicationSerializer,
|
||||||
action_open: apply_application.ApplySerializer,
|
action_open: apply_application.ApplySerializer,
|
||||||
action_approve: apply_application.ApproveSerializer,
|
action_approve: apply_application.ApproveSerializer,
|
||||||
},
|
},
|
||||||
const.TicketTypeChoices.login_confirm.value: {
|
const.TicketTypeChoices.login_confirm.value: {
|
||||||
|
'default': login_confirm.LoginConfirmSerializer,
|
||||||
action_open: login_confirm.ApplySerializer,
|
action_open: login_confirm.ApplySerializer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,88 +1,148 @@
|
||||||
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 django.db.models import Q
|
||||||
from applications.models import Application
|
from applications.models import Application
|
||||||
from applications.const import ApplicationCategoryChoices, ApplicationTypeChoices
|
from applications.const import ApplicationCategoryChoices, ApplicationTypeChoices
|
||||||
from assets.models import SystemUser
|
from assets.models import SystemUser
|
||||||
from .mixin import BaseApproveSerializerMixin
|
from orgs.utils import tmp_to_org
|
||||||
|
from tickets.models import Ticket
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'ApplyApplicationTypeSerializer', 'ApplySerializer', 'ApproveSerializer',
|
'ApplyApplicationSerializer', 'ApplySerializer', 'ApproveSerializer',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class ApplySerializer(serializers.Serializer):
|
class ApplySerializer(serializers.Serializer):
|
||||||
# 申请信息
|
# 申请信息
|
||||||
apply_category = serializers.ChoiceField(
|
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(
|
apply_category_display = serializers.CharField(
|
||||||
read_only=True, label=_('Category display')
|
read_only=True, label=_('Category display'), allow_null=True,
|
||||||
)
|
)
|
||||||
apply_type = serializers.ChoiceField(
|
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(
|
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(
|
apply_application_group = serializers.ListField(
|
||||||
required=False, child=serializers.CharField(), label=_('Application group'),
|
required=False, child=serializers.CharField(), label=_('Application group'),
|
||||||
default=list,
|
default=list, allow_null=True
|
||||||
)
|
)
|
||||||
apply_system_user_group = serializers.ListField(
|
apply_system_user_group = serializers.ListField(
|
||||||
required=False, child=serializers.CharField(), label=_('System user group'),
|
required=False, child=serializers.CharField(), label=_('System user group'),
|
||||||
default=list,
|
default=list, allow_null=True
|
||||||
)
|
)
|
||||||
apply_date_start = serializers.DateTimeField(
|
apply_date_start = serializers.DateTimeField(
|
||||||
required=True, label=_('Date start')
|
required=True, label=_('Date start'), allow_null=True
|
||||||
)
|
)
|
||||||
apply_date_expired = serializers.DateTimeField(
|
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(
|
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(
|
approve_applications_snapshot = serializers.ListField(
|
||||||
required=False, read_only=True, child=serializers.CharField(),
|
required=False, read_only=True, child=serializers.CharField(),
|
||||||
label=_('Approve applications display'),
|
label=_('Approve applications display'), allow_null=True,
|
||||||
default=list
|
default=list
|
||||||
)
|
)
|
||||||
approve_system_users = serializers.ListField(
|
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(
|
approve_system_users_snapshot = serializers.ListField(
|
||||||
required=False, read_only=True, child=serializers.CharField(),
|
required=False, read_only=True, child=serializers.CharField(),
|
||||||
label=_('Approve system user display'),
|
label=_('Approve system user display'), allow_null=True,
|
||||||
default=list
|
default=list
|
||||||
)
|
)
|
||||||
approve_date_start = serializers.DateTimeField(
|
approve_date_start = serializers.DateTimeField(
|
||||||
required=True, label=_('Date start')
|
required=True, label=_('Date start'), allow_null=True
|
||||||
)
|
)
|
||||||
approve_date_expired = serializers.DateTimeField(
|
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):
|
def validate_approve_applications(self, approve_applications):
|
||||||
application_type = self.root.instance.meta['apply_type']
|
if not isinstance(self.root.instance, Ticket):
|
||||||
queries = {'type': application_type}
|
return []
|
||||||
applications_id = self.filter_approve_resources(
|
|
||||||
resource_model=Application, resources_id=approve_applications, queries=queries
|
with tmp_to_org(self.root.instance.org_id):
|
||||||
)
|
apply_type = self.root.instance.meta.get('apply_type')
|
||||||
return applications_id
|
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):
|
def validate_approve_system_users(self, approve_system_users):
|
||||||
application_type = self.root.instance.meta['apply_type']
|
if not isinstance(self.root.instance, Ticket):
|
||||||
protocol = SystemUser.get_protocol_by_application_type(application_type)
|
return []
|
||||||
queries = {'protocol': protocol}
|
|
||||||
system_users_id = self.filter_approve_system_users(approve_system_users, queries)
|
with tmp_to_org(self.root.instance.org_id):
|
||||||
return system_users_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):
|
class ApplyApplicationSerializer(ApplySerializer, ApproveSerializer):
|
||||||
pass
|
# 推荐信息
|
||||||
|
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.utils.translation import ugettext_lazy as _
|
||||||
|
from django.db.models import Q
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from perms.serializers import ActionsField
|
from perms.serializers import ActionsField
|
||||||
from assets.models import Asset, SystemUser
|
from assets.models import Asset, SystemUser
|
||||||
from .mixin import BaseApproveSerializerMixin
|
from orgs.utils import tmp_to_org
|
||||||
|
from tickets.models import Ticket
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
@ -14,74 +16,129 @@ class ApplySerializer(serializers.Serializer):
|
||||||
# 申请信息
|
# 申请信息
|
||||||
apply_ip_group = serializers.ListField(
|
apply_ip_group = serializers.ListField(
|
||||||
required=False, child=serializers.IPAddressField(), label=_('IP group'),
|
required=False, child=serializers.IPAddressField(), label=_('IP group'),
|
||||||
default=list,
|
default=list, allow_null=True,
|
||||||
)
|
)
|
||||||
apply_hostname_group = serializers.ListField(
|
apply_hostname_group = serializers.ListField(
|
||||||
required=False, child=serializers.CharField(), label=_('Hostname group'),
|
required=False, child=serializers.CharField(), label=_('Hostname group'),
|
||||||
default=list,
|
default=list, allow_null=True,
|
||||||
)
|
)
|
||||||
apply_system_user_group = serializers.ListField(
|
apply_system_user_group = serializers.ListField(
|
||||||
required=False, child=serializers.CharField(), label=_('System user group'),
|
required=False, child=serializers.CharField(), label=_('System user group'),
|
||||||
default=list,
|
default=list, allow_null=True
|
||||||
)
|
)
|
||||||
apply_actions = ActionsField(
|
apply_actions = ActionsField(
|
||||||
required=True
|
required=True, allow_null=True
|
||||||
)
|
)
|
||||||
apply_actions_display = serializers.ListField(
|
apply_actions_display = serializers.ListField(
|
||||||
required=False, read_only=True, child=serializers.CharField(),
|
required=False, read_only=True, child=serializers.CharField(),
|
||||||
label=_('Approve assets display'),
|
label=_('Approve assets display'), allow_null=True,
|
||||||
default=list,
|
default=list,
|
||||||
)
|
)
|
||||||
apply_date_start = serializers.DateTimeField(
|
apply_date_start = serializers.DateTimeField(
|
||||||
required=True, label=_('Date start')
|
required=True, label=_('Date start'), allow_null=True,
|
||||||
)
|
)
|
||||||
apply_date_expired = serializers.DateTimeField(
|
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(
|
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(
|
approve_assets_snapshot = serializers.ListField(
|
||||||
required=False, read_only=True, child=serializers.DictField(),
|
required=False, read_only=True, child=serializers.DictField(),
|
||||||
label=_('Approve assets display'),
|
label=_('Approve assets display'), allow_null=True,
|
||||||
default=list,
|
default=list,
|
||||||
)
|
)
|
||||||
approve_system_users = serializers.ListField(
|
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(
|
approve_system_users_snapshot = serializers.ListField(
|
||||||
required=False, read_only=True, child=serializers.DictField(),
|
required=False, read_only=True, child=serializers.DictField(),
|
||||||
label=_('Approve assets display'),
|
label=_('Approve assets display'), allow_null=True,
|
||||||
default=list,
|
default=list,
|
||||||
)
|
)
|
||||||
approve_actions = ActionsField(
|
approve_actions = ActionsField(
|
||||||
required=True
|
required=True, allow_null=True,
|
||||||
)
|
)
|
||||||
approve_actions_display = serializers.ListField(
|
approve_actions_display = serializers.ListField(
|
||||||
required=False, read_only=True, child=serializers.CharField(),
|
required=False, read_only=True, child=serializers.CharField(),
|
||||||
label=_('Approve assets display'),
|
label=_('Approve assets display'), allow_null=True,
|
||||||
default=list,
|
default=list,
|
||||||
)
|
)
|
||||||
approve_date_start = serializers.DateTimeField(
|
approve_date_start = serializers.DateTimeField(
|
||||||
required=True, label=_('Date start')
|
required=True, label=_('Date start'), allow_null=True,
|
||||||
)
|
)
|
||||||
approve_date_expired = serializers.DateTimeField(
|
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):
|
def validate_approve_assets(self, approve_assets):
|
||||||
assets_id = self.filter_approve_resources(resource_model=Asset, resources_id=approve_assets)
|
if not isinstance(self.root.instance, Ticket):
|
||||||
return assets_id
|
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):
|
def validate_approve_system_users(self, approve_system_users):
|
||||||
queries = {'protocol__in': SystemUser.ASSET_CATEGORY_PROTOCOLS}
|
if not isinstance(self.root.instance, Ticket):
|
||||||
system_users_id = self.filter_approve_system_users(approve_system_users, queries)
|
return []
|
||||||
return system_users_id
|
|
||||||
|
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):
|
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__ = [
|
__all__ = [
|
||||||
'ApplySerializer',
|
'ApplySerializer', 'LoginConfirmSerializer',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class ApplySerializer(serializers.Serializer):
|
class ApplySerializer(serializers.Serializer):
|
||||||
# 申请信息
|
# 申请信息
|
||||||
apply_login_ip = serializers.IPAddressField(
|
apply_login_ip = serializers.IPAddressField(
|
||||||
required=True, label=_('Login ip')
|
required=True, label=_('Login ip'), allow_null=True
|
||||||
)
|
)
|
||||||
apply_login_city = serializers.CharField(
|
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(
|
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'))
|
type_display = serializers.ReadOnlyField(source='get_type_display', label=_('Type'))
|
||||||
action_display = serializers.ReadOnlyField(source='get_action_display', label=_('Action'))
|
action_display = serializers.ReadOnlyField(source='get_action_display', label=_('Action'))
|
||||||
status_display = serializers.ReadOnlyField(source='get_status_display', label=_('Status'))
|
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()
|
meta = MethodSerializer()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -38,48 +41,55 @@ class TicketSerializer(OrgResourceModelSerializerMixin):
|
||||||
|
|
||||||
def get_meta_serializer(self):
|
def get_meta_serializer(self):
|
||||||
request = self.context['request']
|
request = self.context['request']
|
||||||
view = self.context['view']
|
default_serializer_class = serializers.Serializer
|
||||||
query_type = request.query_params.get('type')
|
if isinstance(self.instance, Ticket):
|
||||||
query_action = request.query_params.get('action')
|
_type = self.instance.type
|
||||||
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)
|
|
||||||
else:
|
else:
|
||||||
serializer_class = None
|
_type = request.query_params.get('type')
|
||||||
if serializer_class is None:
|
|
||||||
serializer_class = serializers.Serializer
|
if not _type:
|
||||||
serializer = serializer_class()
|
return default_serializer_class()
|
||||||
return serializer
|
|
||||||
|
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 TicketDisplaySerializer(TicketSerializer):
|
||||||
|
|
||||||
class Meta(TicketSerializer.Meta):
|
class Meta:
|
||||||
|
model = Ticket
|
||||||
|
fields = TicketSerializer.Meta.fields
|
||||||
read_only_fields = TicketSerializer.Meta.fields
|
read_only_fields = TicketSerializer.Meta.fields
|
||||||
|
|
||||||
|
|
||||||
class TicketActionSerializer(TicketSerializer):
|
class TicketApplySerializer(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())
|
|
||||||
org_id = serializers.CharField(
|
org_id = serializers.CharField(
|
||||||
max_length=36, allow_blank=True, required=True, label=_("Organization")
|
max_length=36, allow_blank=True, required=True, label=_("Organization")
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta(TicketActionSerializer.Meta):
|
class Meta:
|
||||||
required_fields = TicketActionSerializer.Meta.required_fields + [
|
model = Ticket
|
||||||
'id', 'title', 'type', 'applicant', 'meta', 'assignees', 'comment', 'org_id'
|
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 = {
|
extra_kwargs = {
|
||||||
'type': {'required': True},
|
'type': {'required': True},
|
||||||
|
'org_id': {'required': True},
|
||||||
}
|
}
|
||||||
|
|
||||||
def validate_type(self, tp):
|
def validate_type(self, tp):
|
||||||
|
@ -115,37 +125,43 @@ class TicketApplySerializer(TicketActionSerializer):
|
||||||
return const.TicketActionChoices.open.value
|
return const.TicketActionChoices.open.value
|
||||||
|
|
||||||
|
|
||||||
class TicketProcessSerializer(TicketActionSerializer):
|
class TicketApproveSerializer(TicketSerializer):
|
||||||
processor = ReadableHiddenField(default=serializers.CurrentUserDefault())
|
|
||||||
|
|
||||||
class Meta(TicketActionSerializer.Meta):
|
class Meta:
|
||||||
required_fields = TicketActionSerializer.Meta.required_fields + ['processor']
|
model = Ticket
|
||||||
read_only_fields = list(set(TicketDisplaySerializer.Meta.fields) - set(required_fields))
|
fields = TicketSerializer.Meta.fields
|
||||||
|
required_fields = ['processor', 'action', 'meta']
|
||||||
|
read_only_fields = list(set(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))
|
|
||||||
|
|
||||||
def validate_meta(self, meta):
|
def validate_meta(self, meta):
|
||||||
instance_meta = self.instance.meta
|
_meta = self.instance.meta if self.instance else {}
|
||||||
instance_meta.update(meta)
|
_meta.update(meta)
|
||||||
return instance_meta
|
return _meta
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate_action(action):
|
def validate_action(action):
|
||||||
return const.TicketActionChoices.approve.value
|
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):
|
def validate_action(self, action):
|
||||||
return const.TicketActionChoices.reject.value
|
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):
|
def validate_action(self, action):
|
||||||
return const.TicketActionChoices.close.value
|
return const.TicketActionChoices.close.value
|
||||||
|
|
|
@ -17,26 +17,27 @@ logger = get_logger(__name__)
|
||||||
|
|
||||||
@receiver(pre_save, sender=Ticket)
|
@receiver(pre_save, sender=Ticket)
|
||||||
def on_ticket_pre_save(sender, instance=None, **kwargs):
|
def on_ticket_pre_save(sender, instance=None, **kwargs):
|
||||||
|
instance.set_display_fields()
|
||||||
|
|
||||||
if instance.has_processed:
|
if instance.has_processed:
|
||||||
instance.set_status_closed()
|
instance.set_status_closed()
|
||||||
instance.set_display_fields()
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Ticket)
|
@receiver(post_save, sender=Ticket)
|
||||||
def on_ticket_post_save(sender, instance=None, **kwargs):
|
def on_ticket_post_save(sender, instance=None, created=False, **kwargs):
|
||||||
instance.create_action_comment()
|
|
||||||
if instance.action_open:
|
if created and instance.action_open:
|
||||||
|
instance.create_action_comment()
|
||||||
instance.create_applied_comment()
|
instance.create_applied_comment()
|
||||||
return
|
|
||||||
if instance.action_approve:
|
if not created and instance.has_processed:
|
||||||
instance.create_permission()
|
instance.create_action_comment()
|
||||||
instance.create_approved_comment()
|
msg = 'Ticket () has processed, send mail to applicant: {}'
|
||||||
logger.debug(
|
logger.debug(msg.format(instance.title, instance.applicant_display))
|
||||||
'Ticket () has processed, send mail to applicant: {}'.format(
|
send_ticket_processed_mail_to_applicant(instance)
|
||||||
instance.title, instance.applicant_display
|
if instance.action_approve:
|
||||||
)
|
instance.create_permission()
|
||||||
)
|
instance.create_approved_comment()
|
||||||
send_ticket_processed_mail_to_applicant(instance)
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=Ticket.assignees.through)
|
@receiver(m2m_changed, sender=Ticket.assignees.through)
|
||||||
|
|
Loading…
Reference in New Issue