perf: 修改 publications

pull/9008/head
ibuler 2022-11-01 20:37:04 +08:00
parent b159f16513
commit 6ba4b750f2
7 changed files with 154 additions and 109 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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