mirror of https://github.com/jumpserver/jumpserver
perf: 修改 publications
parent
b159f16513
commit
6ba4b750f2
|
@ -1,5 +1,7 @@
|
||||||
import shutil
|
import shutil
|
||||||
import zipfile
|
import zipfile
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
|
@ -7,6 +9,7 @@ from django.core.files.storage import default_storage
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
|
|
||||||
|
@ -18,21 +21,10 @@ from terminal.serializers import AppletUploadSerializer
|
||||||
__all__ = ['AppletViewSet', 'AppletPublicationViewSet']
|
__all__ = ['AppletViewSet', 'AppletPublicationViewSet']
|
||||||
|
|
||||||
|
|
||||||
class AppletViewSet(viewsets.ModelViewSet):
|
class DownloadUploadMixin:
|
||||||
queryset = Applet.objects.all()
|
get_serializer: Callable
|
||||||
serializer_class = serializers.AppletSerializer
|
request: Request
|
||||||
rbac_perms = {
|
get_object: Callable
|
||||||
'upload': 'terminal.add_applet',
|
|
||||||
'download': 'terminal.view_applet',
|
|
||||||
}
|
|
||||||
|
|
||||||
def perform_destroy(self, instance):
|
|
||||||
if not instance.name:
|
|
||||||
raise ValidationError('Applet is not null')
|
|
||||||
path = default_storage.path('applets/{}'.format(instance.name))
|
|
||||||
if os.path.exists(path):
|
|
||||||
shutil.rmtree(path)
|
|
||||||
instance.delete()
|
|
||||||
|
|
||||||
def extract_and_check_file(self, request):
|
def extract_and_check_file(self, request):
|
||||||
serializer = self.get_serializer(data=self.request.data)
|
serializer = self.get_serializer(data=self.request.data)
|
||||||
|
@ -88,7 +80,7 @@ class AppletViewSet(viewsets.ModelViewSet):
|
||||||
|
|
||||||
@action(detail=True, methods=['get'])
|
@action(detail=True, methods=['get'])
|
||||||
def download(self, request, *args, **kwargs):
|
def download(self, request, *args, **kwargs):
|
||||||
instance = super().get_object()
|
instance = self.get_object()
|
||||||
path = default_storage.path('applets/{}'.format(instance.name))
|
path = default_storage.path('applets/{}'.format(instance.name))
|
||||||
zip_path = shutil.make_archive(path, 'zip', path)
|
zip_path = shutil.make_archive(path, 'zip', path)
|
||||||
with open(zip_path, 'rb') as f:
|
with open(zip_path, 'rb') as f:
|
||||||
|
@ -97,6 +89,34 @@ class AppletViewSet(viewsets.ModelViewSet):
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
class AppletViewSet(DownloadUploadMixin, viewsets.ModelViewSet):
|
||||||
|
queryset = Applet.objects.all()
|
||||||
|
serializer_class = serializers.AppletSerializer
|
||||||
|
rbac_perms = {
|
||||||
|
'upload': 'terminal.add_applet',
|
||||||
|
'download': 'terminal.view_applet',
|
||||||
|
}
|
||||||
|
|
||||||
|
def filter_queryset(self, queryset):
|
||||||
|
queryset = list(super().filter_queryset(queryset))
|
||||||
|
host = self.request.query_params.get('host')
|
||||||
|
if not host:
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
publication_mapper = {p.applet: p for p in AppletPublication.objects.filter(host_id=host)}
|
||||||
|
for applet in queryset:
|
||||||
|
applet.publication = publication_mapper.get(applet)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def perform_destroy(self, instance):
|
||||||
|
if not instance.name:
|
||||||
|
raise ValidationError('Applet is not null')
|
||||||
|
path = default_storage.path('applets/{}'.format(instance.name))
|
||||||
|
if os.path.exists(path):
|
||||||
|
shutil.rmtree(path)
|
||||||
|
instance.delete()
|
||||||
|
|
||||||
|
|
||||||
class AppletPublicationViewSet(viewsets.ModelViewSet):
|
class AppletPublicationViewSet(viewsets.ModelViewSet):
|
||||||
queryset = AppletPublication.objects.all()
|
queryset = AppletPublication.objects.all()
|
||||||
serializer_class = serializers.AppletPublicationSerializer
|
serializer_class = serializers.AppletPublicationSerializer
|
||||||
|
|
|
@ -14,13 +14,6 @@ class AppletHostViewSet(viewsets.ModelViewSet):
|
||||||
serializer_class = serializers.AppletHostSerializer
|
serializer_class = serializers.AppletHostSerializer
|
||||||
queryset = AppletHost.objects.all()
|
queryset = AppletHost.objects.all()
|
||||||
|
|
||||||
@action(methods=['get'], detail=True, url_path='')
|
|
||||||
def not_published_applets(self, request, *args, **kwargs):
|
|
||||||
instance = self.get_object()
|
|
||||||
applets = Applet.objects.exclude(id__in=instance.applets.all())
|
|
||||||
serializer = serializers.AppletSerializer(applets, many=True)
|
|
||||||
return Response(serializer.data)
|
|
||||||
|
|
||||||
|
|
||||||
class AppletHostDeploymentViewSet(viewsets.ModelViewSet):
|
class AppletHostDeploymentViewSet(viewsets.ModelViewSet):
|
||||||
serializer_class = serializers.AppletHostDeploymentSerializer
|
serializer_class = serializers.AppletHostDeploymentSerializer
|
||||||
|
|
|
@ -6,6 +6,7 @@ from django.core.files.storage import default_storage
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from common.utils import lazyproperty
|
||||||
from common.db.models import JMSBaseModel
|
from common.db.models import JMSBaseModel
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +27,10 @@ class Applet(JMSBaseModel):
|
||||||
protocols = models.JSONField(default=list, verbose_name=_('Protocol'))
|
protocols = models.JSONField(default=list, verbose_name=_('Protocol'))
|
||||||
tags = models.JSONField(default=list, verbose_name=_('Tags'))
|
tags = models.JSONField(default=list, verbose_name=_('Tags'))
|
||||||
comment = models.TextField(default='', blank=True, verbose_name=_('Comment'))
|
comment = models.TextField(default='', blank=True, verbose_name=_('Comment'))
|
||||||
hosts = models.ManyToManyField(through_fields=('applet', 'host'), through='AppletPublication', to='AppletHost', verbose_name=_('Hosts'))
|
hosts = models.ManyToManyField(
|
||||||
|
through_fields=('applet', 'host'), through='AppletPublication',
|
||||||
|
to='AppletHost', verbose_name=_('Hosts')
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
@ -50,6 +54,10 @@ class Applet(JMSBaseModel):
|
||||||
return None
|
return None
|
||||||
return os.path.join(settings.MEDIA_URL, 'applets', self.name, 'icon.png')
|
return os.path.join(settings.MEDIA_URL, 'applets', self.name, 'icon.png')
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def publication(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class AppletPublication(JMSBaseModel):
|
class AppletPublication(JMSBaseModel):
|
||||||
applet = models.ForeignKey('Applet', on_delete=models.PROTECT, related_name='publications', verbose_name=_('Applet'))
|
applet = models.ForeignKey('Applet', on_delete=models.PROTECT, related_name='publications', verbose_name=_('Applet'))
|
||||||
|
|
|
@ -6,3 +6,4 @@ from .storage import *
|
||||||
from .sharing import *
|
from .sharing import *
|
||||||
from .endpoint import *
|
from .endpoint import *
|
||||||
from .applet import *
|
from .applet import *
|
||||||
|
from .applet_host import *
|
||||||
|
|
|
@ -2,35 +2,15 @@ from rest_framework import serializers
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from common.drf.fields import ObjectRelatedField, LabeledChoiceField
|
from common.drf.fields import ObjectRelatedField, LabeledChoiceField
|
||||||
from common.validators import ProjectUniqueValidator
|
from ..models import Applet, AppletPublication, AppletHost
|
||||||
from assets.models import Platform
|
|
||||||
from assets.serializers import HostSerializer
|
|
||||||
from ..models import Applet, AppletPublication, AppletHost, AppletHostDeployment
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'AppletSerializer', 'AppletPublicationSerializer',
|
'AppletSerializer', 'AppletPublicationSerializer',
|
||||||
'AppletHostSerializer', 'AppletHostDeploymentSerializer',
|
|
||||||
'AppletUploadSerializer',
|
'AppletUploadSerializer',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class AppletSerializer(serializers.ModelSerializer):
|
|
||||||
icon = serializers.ReadOnlyField(label=_("Icon"))
|
|
||||||
type = LabeledChoiceField(choices=Applet.Type.choices, label=_("Type"))
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Applet
|
|
||||||
fields_mini = ['id', 'name', 'display_name']
|
|
||||||
read_only_fields = [
|
|
||||||
'icon', 'date_created', 'date_updated'
|
|
||||||
]
|
|
||||||
fields = fields_mini + [
|
|
||||||
'version', 'author', 'type', 'protocols',
|
|
||||||
'tags', 'comment'
|
|
||||||
] + read_only_fields
|
|
||||||
|
|
||||||
|
|
||||||
class AppletUploadSerializer(serializers.Serializer):
|
class AppletUploadSerializer(serializers.Serializer):
|
||||||
file = serializers.FileField()
|
file = serializers.FileField()
|
||||||
|
|
||||||
|
@ -48,69 +28,18 @@ class AppletPublicationSerializer(serializers.ModelSerializer):
|
||||||
] + read_only_fields
|
] + read_only_fields
|
||||||
|
|
||||||
|
|
||||||
class DeployOptionsSerializer(serializers.Serializer):
|
class AppletSerializer(serializers.ModelSerializer):
|
||||||
LICENSE_MODE_CHOICES = (
|
icon = serializers.ReadOnlyField(label=_("Icon"))
|
||||||
(4, _('Per Session')),
|
type = LabeledChoiceField(choices=Applet.Type.choices, label=_("Type"))
|
||||||
(2, _('Per Device')),
|
publication = AppletPublicationSerializer(allow_null=True, label=_("Publication"))
|
||||||
)
|
|
||||||
SESSION_PER_USER = (
|
|
||||||
(1, _("Disabled")),
|
|
||||||
(0, _("Enabled")),
|
|
||||||
)
|
|
||||||
RDS_Licensing = serializers.BooleanField(default=False, label=_("RDS Licensing"))
|
|
||||||
RDS_LicenseServer = serializers.CharField(default='127.0.0.1', label=_('RDS License Server'), max_length=1024)
|
|
||||||
RDS_LicensingMode = serializers.ChoiceField(choices=LICENSE_MODE_CHOICES, default=4, label=_('RDS Licensing Mode'))
|
|
||||||
RDS_fSingleSessionPerUser = serializers.ChoiceField(choices=SESSION_PER_USER, default=1, label=_("RDS fSingleSessionPerUser"))
|
|
||||||
RDS_MaxDisconnectionTime = serializers.IntegerField(default=60000, label=_("RDS Max Disconnection Time"))
|
|
||||||
RDS_RemoteAppLogoffTimeLimit = serializers.IntegerField(default=0, label=_("RDS Remote App Logoff Time Limit"))
|
|
||||||
|
|
||||||
|
|
||||||
class AppletHostSerializer(HostSerializer):
|
|
||||||
deploy_options = DeployOptionsSerializer(required=False, label=_("Deploy options"))
|
|
||||||
|
|
||||||
class Meta(HostSerializer.Meta):
|
|
||||||
model = AppletHost
|
|
||||||
fields = HostSerializer.Meta.fields + [
|
|
||||||
'account_automation', 'status', 'date_synced', 'deploy_options'
|
|
||||||
]
|
|
||||||
extra_kwargs = {
|
|
||||||
'status': {'read_only': True},
|
|
||||||
'date_synced': {'read_only': True}
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, *args, data=None, **kwargs):
|
|
||||||
if data:
|
|
||||||
self.set_initial_data(data)
|
|
||||||
kwargs['data'] = data
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def set_initial_data(data):
|
|
||||||
platform = Platform.objects.get(name='RemoteAppHost')
|
|
||||||
data.update({
|
|
||||||
'platform': platform.id,
|
|
||||||
'nodes_display': [
|
|
||||||
'RemoteAppHosts'
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
def get_validators(self):
|
|
||||||
validators = super().get_validators()
|
|
||||||
# 不知道为啥没有继承过来
|
|
||||||
uniq_validator = ProjectUniqueValidator(
|
|
||||||
queryset=AppletHost.objects.all(),
|
|
||||||
fields=('org_id', 'name')
|
|
||||||
)
|
|
||||||
validators.append(uniq_validator)
|
|
||||||
return validators
|
|
||||||
|
|
||||||
|
|
||||||
class AppletHostDeploymentSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = AppletHostDeployment
|
model = Applet
|
||||||
fields_mini = ['id', 'host', 'status']
|
fields_mini = ['id', 'name', 'display_name']
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
'status', 'date_created', 'date_updated',
|
'publication', 'icon', 'date_created', 'date_updated',
|
||||||
'date_start', 'date_finished'
|
|
||||||
]
|
]
|
||||||
fields = fields_mini + ['comment'] + read_only_fields
|
fields = fields_mini + [
|
||||||
|
'version', 'author', 'type', 'protocols',
|
||||||
|
'tags', 'comment'
|
||||||
|
] + read_only_fields
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
from rest_framework import serializers
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from common.validators import ProjectUniqueValidator
|
||||||
|
from assets.models import Platform
|
||||||
|
from assets.serializers import HostSerializer
|
||||||
|
from ..models import AppletHost, AppletHostDeployment, Applet
|
||||||
|
from .applet import AppletSerializer
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'AppletHostSerializer', 'AppletHostDeploymentSerializer',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class DeployOptionsSerializer(serializers.Serializer):
|
||||||
|
LICENSE_MODE_CHOICES = (
|
||||||
|
(4, _('Per Session')),
|
||||||
|
(2, _('Per Device')),
|
||||||
|
)
|
||||||
|
SESSION_PER_USER = (
|
||||||
|
(1, _("Disabled")),
|
||||||
|
(0, _("Enabled")),
|
||||||
|
)
|
||||||
|
RDS_Licensing = serializers.BooleanField(default=False, label=_("RDS Licensing"))
|
||||||
|
RDS_LicenseServer = serializers.CharField(default='127.0.0.1', label=_('RDS License Server'), max_length=1024)
|
||||||
|
RDS_LicensingMode = serializers.ChoiceField(choices=LICENSE_MODE_CHOICES, default=4, label=_('RDS Licensing Mode'))
|
||||||
|
RDS_fSingleSessionPerUser = serializers.ChoiceField(choices=SESSION_PER_USER, default=1, label=_("RDS fSingleSessionPerUser"))
|
||||||
|
RDS_MaxDisconnectionTime = serializers.IntegerField(default=60000, label=_("RDS Max Disconnection Time"))
|
||||||
|
RDS_RemoteAppLogoffTimeLimit = serializers.IntegerField(default=0, label=_("RDS Remote App Logoff Time Limit"))
|
||||||
|
|
||||||
|
|
||||||
|
class AppletHostSerializer(HostSerializer):
|
||||||
|
deploy_options = DeployOptionsSerializer(required=False, label=_("Deploy options"))
|
||||||
|
|
||||||
|
class Meta(HostSerializer.Meta):
|
||||||
|
model = AppletHost
|
||||||
|
fields = HostSerializer.Meta.fields + [
|
||||||
|
'account_automation', 'status', 'date_synced', 'deploy_options'
|
||||||
|
]
|
||||||
|
extra_kwargs = {
|
||||||
|
'status': {'read_only': True},
|
||||||
|
'date_synced': {'read_only': True}
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, data=None, **kwargs):
|
||||||
|
if data:
|
||||||
|
self.set_initial_data(data)
|
||||||
|
kwargs['data'] = data
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set_initial_data(data):
|
||||||
|
platform = Platform.objects.get(name='RemoteAppHost')
|
||||||
|
data.update({
|
||||||
|
'platform': platform.id,
|
||||||
|
'nodes_display': [
|
||||||
|
'RemoteAppHosts'
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
def get_validators(self):
|
||||||
|
validators = super().get_validators()
|
||||||
|
# 不知道为啥没有继承过来
|
||||||
|
uniq_validator = ProjectUniqueValidator(
|
||||||
|
queryset=AppletHost.objects.all(),
|
||||||
|
fields=('org_id', 'name')
|
||||||
|
)
|
||||||
|
validators.append(uniq_validator)
|
||||||
|
return validators
|
||||||
|
|
||||||
|
|
||||||
|
class HostAppletSerializer(AppletSerializer):
|
||||||
|
publication = serializers.SerializerMethodField()
|
||||||
|
|
||||||
|
class Meta(AppletSerializer.Meta):
|
||||||
|
fields = AppletSerializer.Meta.fields + ['publication']
|
||||||
|
|
||||||
|
|
||||||
|
class AppletHostDeploymentSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = AppletHostDeployment
|
||||||
|
fields_mini = ['id', 'host', 'status']
|
||||||
|
read_only_fields = [
|
||||||
|
'status', 'date_created', 'date_updated',
|
||||||
|
'date_start', 'date_finished'
|
||||||
|
]
|
||||||
|
fields = fields_mini + ['comment'] + read_only_fields
|
|
@ -10,9 +10,15 @@ from .models import Applet, AppletHost
|
||||||
|
|
||||||
@receiver(post_save, sender=AppletHost)
|
@receiver(post_save, sender=AppletHost)
|
||||||
def on_applet_host_create(sender, instance, created=False, **kwargs):
|
def on_applet_host_create(sender, instance, created=False, **kwargs):
|
||||||
pass
|
if not created:
|
||||||
|
return
|
||||||
|
applets = Applet.objects.all()
|
||||||
|
instance.applets.set(applets)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Applet)
|
@receiver(post_save, sender=Applet)
|
||||||
def on_applet_create(sender, instance, created=False, **kwargs):
|
def on_applet_create(sender, instance, created=False, **kwargs):
|
||||||
pass
|
if not created:
|
||||||
|
return
|
||||||
|
hosts = AppletHost.objects.all()
|
||||||
|
instance.hosts.set(hosts)
|
||||||
|
|
Loading…
Reference in New Issue