mirror of https://github.com/jumpserver/jumpserver
				
				
				
			
		
			
				
	
	
		
			104 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			104 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Python
		
	
	
import os
 | 
						|
import shutil
 | 
						|
 | 
						|
from django.conf import settings
 | 
						|
from django.core.files.storage import default_storage
 | 
						|
from django.db import models
 | 
						|
from django.utils._os import safe_join
 | 
						|
from django.utils.translation import gettext_lazy as _
 | 
						|
from rest_framework.serializers import ValidationError
 | 
						|
 | 
						|
from common.db.models import JMSBaseModel
 | 
						|
from common.utils import lazyproperty
 | 
						|
from common.utils.yml import yaml_load_with_i18n
 | 
						|
 | 
						|
__all__ = ['VirtualApp', 'VirtualAppPublication']
 | 
						|
 | 
						|
 | 
						|
class VirtualApp(JMSBaseModel):
 | 
						|
    name = models.SlugField(max_length=128, verbose_name=_('Name'), unique=True)
 | 
						|
    display_name = models.CharField(max_length=128, verbose_name=_('Display name'))
 | 
						|
    version = models.CharField(max_length=16, verbose_name=_('Version'))
 | 
						|
    author = models.CharField(max_length=128, verbose_name=_('Author'))
 | 
						|
    is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
 | 
						|
    protocols = models.JSONField(default=list, verbose_name=_('Protocol'))
 | 
						|
    image_name = models.CharField(max_length=128, verbose_name=_('Image name'))
 | 
						|
    image_protocol = models.CharField(max_length=16, default='vnc', verbose_name=_('Image protocol'))
 | 
						|
    image_port = models.IntegerField(default=5900, verbose_name=_('Image port'))
 | 
						|
    comment = models.TextField(default='', blank=True, verbose_name=_('Comment'))
 | 
						|
    tags = models.JSONField(default=list, verbose_name=_('Tags'))
 | 
						|
    providers = models.ManyToManyField(
 | 
						|
        through_fields=('app', 'provider',), through='VirtualAppPublication',
 | 
						|
        to='AppProvider', verbose_name=_('Providers')
 | 
						|
    )
 | 
						|
 | 
						|
    class Meta:
 | 
						|
        verbose_name = _('Virtual app')
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return self.name
 | 
						|
 | 
						|
    @property
 | 
						|
    def path(self):
 | 
						|
        return default_storage.path('virtual_apps/{}'.format(self.name))
 | 
						|
 | 
						|
    @lazyproperty
 | 
						|
    def readme(self):
 | 
						|
        readme_file = os.path.join(self.path, 'README.md')
 | 
						|
        if os.path.isfile(readme_file):
 | 
						|
            with open(readme_file, 'r') as f:
 | 
						|
                return f.read()
 | 
						|
        return ''
 | 
						|
 | 
						|
    @property
 | 
						|
    def icon(self):
 | 
						|
        path = os.path.join(self.path, 'icon.png')
 | 
						|
        if not os.path.exists(path):
 | 
						|
            return None
 | 
						|
        return os.path.join(settings.MEDIA_URL, 'virtual_apps', self.name, 'icon.png')
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def validate_pkg(d):
 | 
						|
        files = ['manifest.yml', 'icon.png', ]
 | 
						|
        for name in files:
 | 
						|
            path = safe_join(d, name)
 | 
						|
            if not os.path.exists(path):
 | 
						|
                raise ValidationError({'error': _('Applet pkg not valid, Missing file {}').format(name)})
 | 
						|
 | 
						|
        with open(safe_join(d, 'manifest.yml'), encoding='utf8') as f:
 | 
						|
            manifest = yaml_load_with_i18n(f)
 | 
						|
 | 
						|
        if not manifest.get('name', ''):
 | 
						|
            raise ValidationError({'error': 'Missing name in manifest.yml'})
 | 
						|
        return manifest
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def install_from_dir(cls, path):
 | 
						|
        from terminal.serializers import VirtualAppSerializer
 | 
						|
        manifest = cls.validate_pkg(path)
 | 
						|
        name = manifest['name']
 | 
						|
        instance = cls.objects.filter(name=name).first()
 | 
						|
        serializer = VirtualAppSerializer(instance=instance, data=manifest)
 | 
						|
        serializer.is_valid(raise_exception=True)
 | 
						|
        instance = serializer.save()
 | 
						|
 | 
						|
        pkg_path = default_storage.path('virtual_apps/{}'.format(name))
 | 
						|
        if os.path.exists(pkg_path):
 | 
						|
            shutil.rmtree(pkg_path)
 | 
						|
        shutil.copytree(path, pkg_path)
 | 
						|
        return instance, serializer
 | 
						|
 | 
						|
 | 
						|
class VirtualAppPublication(JMSBaseModel):
 | 
						|
    provider = models.ForeignKey(
 | 
						|
        'AppProvider', on_delete=models.CASCADE, related_name='publications', verbose_name=_('App Provider')
 | 
						|
    )
 | 
						|
    app = models.ForeignKey(
 | 
						|
        'VirtualApp', on_delete=models.CASCADE, related_name='publications', verbose_name=_('Virtual app')
 | 
						|
    )
 | 
						|
    status = models.CharField(max_length=16, default='pending', verbose_name=_('Status'))
 | 
						|
 | 
						|
    class Meta:
 | 
						|
        verbose_name = _('Virtual app publication')
 | 
						|
        unique_together = ('provider', 'app')
 |