mirror of https://github.com/jumpserver/jumpserver
pref: 添加 applet 创建 api
parent
1372d6322d
commit
5606082ca3
|
@ -67,6 +67,7 @@ class HostTypes(BaseType):
|
|||
return {
|
||||
cls.LINUX: [
|
||||
{'name': 'Linux'},
|
||||
{'name': 'Gateway'}
|
||||
],
|
||||
cls.UNIX: [
|
||||
{'name': 'Unix'},
|
||||
|
@ -75,16 +76,31 @@ class HostTypes(BaseType):
|
|||
{'name': 'AIX', 'automation': {
|
||||
'push_account_method': 'push_account_aix',
|
||||
'change_secret_method': 'push_secret_aix'
|
||||
}},
|
||||
}}
|
||||
],
|
||||
cls.WINDOWS: [
|
||||
{'name': 'Windows'},
|
||||
{'name': 'Windows-TLS', 'protocols_setting': {
|
||||
'rdp': {'security': 'tls'},
|
||||
}},
|
||||
{'name': 'Windows-RDP', 'protocols_setting': {
|
||||
'rdp': {'security': 'rdp'},
|
||||
}}
|
||||
{
|
||||
'name': 'Windows-TLS',
|
||||
'protocols_setting': {
|
||||
'rdp': {'security': 'tls'},
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'Windows-RDP',
|
||||
'protocols_setting': {
|
||||
'rdp': {'security': 'rdp'},
|
||||
}
|
||||
},
|
||||
{
|
||||
'name': 'RemoteAppHost',
|
||||
'_protocols': ['rdp', 'ssh'],
|
||||
'protocols_setting': {
|
||||
'ssh': {
|
||||
'required': True
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
cls.OTHER_HOST: []
|
||||
}
|
||||
|
|
|
@ -224,7 +224,10 @@ class AllTypes(ChoicesMixin):
|
|||
if _protocols:
|
||||
protocols_data = [p for p in protocols_data if p['name'] in _protocols]
|
||||
for p in protocols_data:
|
||||
p['setting'] = {**_protocols_setting.get(p['name'], {}), **p.get('setting', {})}
|
||||
setting = _protocols_setting.get(p['name'], {})
|
||||
p['required'] = setting.pop('required', False)
|
||||
p['default'] = setting.pop('default', False)
|
||||
p['setting'] = {**setting, **p.get('setting', {})}
|
||||
|
||||
platform_data = {
|
||||
**default_platform_data, **d,
|
||||
|
|
|
@ -55,7 +55,7 @@ class Migration(migrations.Migration):
|
|||
migrations.AddField(
|
||||
model_name='changesecretautomation',
|
||||
name='secret_strategy',
|
||||
field=models.CharField(choices=[('specific', 'Specific'), ('random_one', 'All assets use the same random password'), ('random_all', 'All assets use different random password')], default='random_one', max_length=16, verbose_name='Secret strategy'),
|
||||
field=models.CharField(choices=[('specific', 'Specific'), ('random_one', 'All assets use the same random password'), ('random_all', 'All assets use different random password')], default='specific', max_length=16, verbose_name='Secret strategy'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='changesecretautomation',
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
from .terminal import *
|
||||
from .session import *
|
||||
from .command import *
|
||||
from .task import *
|
||||
from .storage import *
|
||||
from .status import *
|
||||
from .sharing import *
|
||||
from .endpoint import *
|
||||
from .component import *
|
||||
from .applet import *
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
from .applet import *
|
||||
from .host import *
|
|
@ -0,0 +1,71 @@
|
|||
import os.path
|
||||
import shutil
|
||||
import zipfile
|
||||
|
||||
import yaml
|
||||
from django.core.files.storage import default_storage
|
||||
from rest_framework import viewsets
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
|
||||
from terminal import serializers, models
|
||||
from terminal.serializers import AppletUploadSerializer
|
||||
|
||||
|
||||
class AppletViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.Applet.objects.all()
|
||||
serializer_class = serializers.AppletSerializer
|
||||
rbac_perms = {
|
||||
'upload': 'terminal.add_applet',
|
||||
}
|
||||
|
||||
@action(detail=False, methods=['post'], serializer_class=AppletUploadSerializer)
|
||||
def upload(self, request, *args, **kwargs):
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
file = serializer.validated_data['file']
|
||||
save_to = 'applets/{}'.format(file.name + '.tmp.zip')
|
||||
if default_storage.exists(save_to):
|
||||
default_storage.delete(save_to)
|
||||
rel_path = default_storage.save(save_to, file)
|
||||
|
||||
path = default_storage.path(rel_path)
|
||||
extract_to = default_storage.path('applets/{}.tmp'.format(file.name))
|
||||
if os.path.exists(extract_to):
|
||||
shutil.rmtree(extract_to)
|
||||
|
||||
update = request.query_params.get('update')
|
||||
with zipfile.ZipFile(path) as zp:
|
||||
if zp.testzip() is not None:
|
||||
return Response({'msg': 'Invalid Zip file'}, status=400)
|
||||
zp.extractall(extract_to)
|
||||
|
||||
tmp_dir = os.path.join(extract_to, file.name.replace('.zip', ''))
|
||||
files = ['manifest.yml', 'icon.png', 'i18n.yml']
|
||||
for name in files:
|
||||
path = os.path.join(tmp_dir, name)
|
||||
if not os.path.exists(path):
|
||||
return Response({'error': 'Missing file: {}'.format(path)}, status=400)
|
||||
|
||||
with open(os.path.join(tmp_dir, 'manifest.yml')) as f:
|
||||
manifest = yaml.safe_load(f)
|
||||
|
||||
name = manifest.get('name', '')
|
||||
instance = models.Applet.objects.filter(name=name).first()
|
||||
if instance and not update:
|
||||
return Response({'error': 'Applet already exists: {}'.format(name)}, status=400)
|
||||
|
||||
serializer = serializers.AppletSerializer(data=manifest, instance=instance)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
save_to = default_storage.path('applets/{}'.format(name))
|
||||
if os.path.exists(save_to):
|
||||
shutil.rmtree(save_to)
|
||||
shutil.move(tmp_dir, save_to)
|
||||
serializer.save()
|
||||
return Response(serializer.data, status=201)
|
||||
|
||||
|
||||
class AppletPublicationViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.AppletPublication.objects.all()
|
||||
serializer_class = serializers.AppletPublicationSerializer
|
|
@ -0,0 +1,16 @@
|
|||
from rest_framework import viewsets
|
||||
|
||||
from terminal import serializers, models
|
||||
|
||||
__all__ = ['AppletHostViewSet', 'AppletHostDeploymentViewSet']
|
||||
|
||||
|
||||
class AppletHostViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.AppletHost.objects.all()
|
||||
serializer_class = serializers.AppletHostSerializer
|
||||
|
||||
|
||||
class AppletHostDeploymentViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.AppletHostDeployment.objects.all()
|
||||
serializer_class = serializers.AppletHostDeploymentSerializer
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
from .terminal import *
|
||||
from .storage import *
|
||||
from .status import *
|
||||
from .endpoint import *
|
|
@ -2,15 +2,15 @@ from rest_framework.decorators import action
|
|||
from rest_framework.response import Response
|
||||
from rest_framework import status
|
||||
from rest_framework.request import Request
|
||||
|
||||
from common.drf.api import JMSBulkModelViewSet
|
||||
from common.permissions import IsValidUserOrConnectionToken
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.shortcuts import get_object_or_404
|
||||
from assets.models import Asset
|
||||
from orgs.utils import tmp_to_root_org
|
||||
from terminal.models import Session
|
||||
from ..models import Endpoint, EndpointRule
|
||||
from .. import serializers
|
||||
from common.permissions import IsValidUserOrConnectionToken
|
||||
from terminal.models import Session, Endpoint, EndpointRule
|
||||
from terminal import serializers
|
||||
|
||||
|
||||
__all__ = ['EndpointViewSet', 'EndpointRuleViewSet']
|
|
@ -9,9 +9,9 @@ from rest_framework import viewsets, generics
|
|||
from rest_framework.views import Response
|
||||
from rest_framework import status
|
||||
|
||||
from ..models import Terminal, Status, Session
|
||||
from .. import serializers
|
||||
from ..utils import TypedComponentsStatusMetricsUtil
|
||||
from terminal.models import Terminal, Status, Session
|
||||
from terminal import serializers
|
||||
from terminal.utils import TypedComponentsStatusMetricsUtil
|
||||
|
||||
logger = logging.getLogger(__file__)
|
||||
|
|
@ -11,8 +11,8 @@ from django_filters import utils
|
|||
from terminal import const
|
||||
from common.const.http import GET
|
||||
from terminal.filters import CommandStorageFilter, CommandFilter, CommandFilterForStorageTree
|
||||
from ..models import CommandStorage, ReplayStorage
|
||||
from ..serializers import CommandStorageSerializer, ReplayStorageSerializer
|
||||
from terminal.models import CommandStorage, ReplayStorage
|
||||
from terminal.serializers import CommandStorageSerializer, ReplayStorageSerializer
|
||||
|
||||
__all__ = [
|
||||
'CommandStorageViewSet', 'CommandStorageTestConnectiveApi',
|
|
@ -14,9 +14,9 @@ from common.exceptions import JMSException
|
|||
from common.drf.api import JMSBulkModelViewSet
|
||||
from common.utils import get_object_or_none, get_request_ip
|
||||
from common.permissions import WithBootstrapToken
|
||||
from ..models import Terminal
|
||||
from .. import serializers
|
||||
from .. import exceptions
|
||||
from terminal.models import Terminal
|
||||
from terminal import serializers
|
||||
from terminal import exceptions
|
||||
|
||||
__all__ = [
|
||||
'TerminalViewSet', 'TerminalConfig',
|
|
@ -0,0 +1,4 @@
|
|||
from .session import *
|
||||
from .sharing import *
|
||||
from .command import *
|
||||
from .task import *
|
|
@ -13,11 +13,11 @@ from common.drf.api import JMSBulkModelViewSet
|
|||
from common.utils import get_logger
|
||||
from terminal.backends.command.serializers import InsecureCommandAlertSerializer
|
||||
from terminal.exceptions import StorageInvalid
|
||||
from ..backends import (
|
||||
from terminal.backends import (
|
||||
get_command_storage, get_multi_command_storage,
|
||||
SessionCommandSerializer,
|
||||
)
|
||||
from ..notifications import CommandAlertMessage
|
||||
from terminal.notifications import CommandAlertMessage
|
||||
|
||||
logger = get_logger(__name__)
|
||||
__all__ = ['CommandViewSet', 'InsecureCommandAlertAPI']
|
|
@ -24,15 +24,16 @@ from common.drf.renders import PassthroughRenderer
|
|||
from orgs.mixins.api import OrgBulkModelViewSet
|
||||
from orgs.utils import tmp_to_root_org, tmp_to_org
|
||||
from users.models import User
|
||||
from .. import utils
|
||||
from ..utils import find_session_replay_local, download_session_replay
|
||||
from ..models import Session
|
||||
from .. import serializers
|
||||
from terminal.utils import is_session_approver
|
||||
from terminal.utils import (
|
||||
find_session_replay_local, download_session_replay,
|
||||
is_session_approver, get_session_replay_url
|
||||
)
|
||||
from terminal.models import Session
|
||||
from terminal import serializers
|
||||
|
||||
__all__ = [
|
||||
'SessionViewSet', 'SessionReplayViewSet', 'SessionJoinValidateAPI',
|
||||
'MySessionAPIView',
|
||||
'SessionViewSet', 'SessionReplayViewSet',
|
||||
'SessionJoinValidateAPI', 'MySessionAPIView',
|
||||
]
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
@ -93,7 +94,7 @@ class SessionViewSet(OrgBulkModelViewSet):
|
|||
url_name='replay-download')
|
||||
def download(self, request, *args, **kwargs):
|
||||
session = self.get_object()
|
||||
local_path, url = utils.get_session_replay_url(session)
|
||||
local_path, url = get_session_replay_url(session)
|
||||
if local_path is None:
|
||||
return Response({"error": url}, status=404)
|
||||
file = self.prepare_offline_file(session, local_path)
|
|
@ -5,9 +5,8 @@ from django.conf import settings
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from common.const.http import PATCH
|
||||
from common.permissions import IsValidUser
|
||||
from orgs.mixins.api import OrgModelViewSet
|
||||
from .. import serializers, models
|
||||
from terminal import serializers, models
|
||||
|
||||
__all__ = ['SessionSharingViewSet', 'SessionJoinRecordsViewSet']
|
||||
|
|
@ -7,10 +7,10 @@ from rest_framework import status
|
|||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from common.utils import get_object_or_none
|
||||
from ..models import Session, Task
|
||||
from .. import serializers
|
||||
from terminal.utils import is_session_approver
|
||||
from orgs.utils import tmp_to_root_org
|
||||
from terminal.models import Session, Task
|
||||
from terminal import serializers
|
||||
from terminal.utils import is_session_approver
|
||||
|
||||
__all__ = ['TaskViewSet', 'KillSessionAPI', 'KillSessionForTicketAPI']
|
||||
logger = logging.getLogger(__file__)
|
|
@ -1,4 +1,4 @@
|
|||
# Generated by Django 3.2.14 on 2022-10-21 06:33
|
||||
# Generated by Django 3.2.14 on 2022-10-24 06:52
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
@ -8,6 +8,7 @@ import uuid
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0110_auto_20221021_1506'),
|
||||
('terminal', '0053_auto_20220830_1244'),
|
||||
]
|
||||
|
||||
|
@ -22,10 +23,13 @@ class Migration(migrations.Migration):
|
|||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=128, unique=True, verbose_name='Name')),
|
||||
('version', models.CharField(max_length=16, verbose_name='Version')),
|
||||
('type', models.CharField(choices=[('app', 'App'), ('web', 'Web')], max_length=16, verbose_name='Type')),
|
||||
('icon', models.ImageField(upload_to='applet/icon', verbose_name='Icon')),
|
||||
('author', models.CharField(max_length=128, verbose_name='Author')),
|
||||
('type', models.CharField(choices=[('general', 'General'), ('web', 'Web')], default='general', max_length=16, verbose_name='Type')),
|
||||
('path', models.FilePathField(verbose_name='Path')),
|
||||
('vcs_type', models.CharField(max_length=16, null=True, verbose_name='VCS type')),
|
||||
('vcs_url', models.CharField(max_length=256, null=True, verbose_name='URL')),
|
||||
('protocols', models.JSONField(default=list, verbose_name='Protocol')),
|
||||
('tags', models.JSONField(default=list, verbose_name='Tags')),
|
||||
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
|
||||
],
|
||||
options={
|
||||
|
@ -33,14 +37,13 @@ class Migration(migrations.Migration):
|
|||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AppletProvider',
|
||||
name='AppletHost',
|
||||
fields=[
|
||||
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
|
||||
('updated_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Updated by')),
|
||||
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
|
||||
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
|
||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=128, unique=True, verbose_name='Name')),
|
||||
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
|
||||
('account_automation', models.BooleanField(default=False, verbose_name='Account automation')),
|
||||
('date_synced', models.DateTimeField(blank=True, null=True, verbose_name='Date synced')),
|
||||
|
@ -50,22 +53,6 @@ class Migration(migrations.Migration):
|
|||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ProviderDeployment',
|
||||
fields=[
|
||||
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
|
||||
('updated_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Updated by')),
|
||||
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
|
||||
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
|
||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('status', models.CharField(max_length=16, verbose_name='Status')),
|
||||
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
|
||||
('provider', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='terminal.appletprovider', verbose_name='Provider')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AppletPublication',
|
||||
fields=[
|
||||
|
@ -77,20 +64,36 @@ class Migration(migrations.Migration):
|
|||
('status', models.CharField(max_length=16, verbose_name='Status')),
|
||||
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
|
||||
('applet', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='terminal.applet', verbose_name='Applet')),
|
||||
('provider', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='terminal.appletprovider', verbose_name='Provider')),
|
||||
('host', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='terminal.applethost', verbose_name='Host')),
|
||||
],
|
||||
options={
|
||||
'unique_together': {('applet', 'provider')},
|
||||
'unique_together': {('applet', 'host')},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AppletHostDeployment',
|
||||
fields=[
|
||||
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
|
||||
('updated_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Updated by')),
|
||||
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
|
||||
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
|
||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
('status', models.CharField(max_length=16, verbose_name='Status')),
|
||||
('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
|
||||
('host', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='terminal.applethost', verbose_name='Hosting')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='appletprovider',
|
||||
model_name='applethost',
|
||||
name='applets',
|
||||
field=models.ManyToManyField(through='terminal.AppletPublication', to='terminal.Applet', verbose_name='Applet'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='appletprovider',
|
||||
name='asset',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='assets.asset', verbose_name='Asset'),
|
||||
model_name='applethost',
|
||||
name='host',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='assets.host', verbose_name='Host'),
|
||||
),
|
||||
]
|
|
@ -1,2 +1,2 @@
|
|||
from .applet import *
|
||||
from .provider import *
|
||||
from .host import *
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
import yaml
|
||||
import os.path
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
@ -9,25 +13,69 @@ __all__ = ['Applet', 'AppletPublication']
|
|||
|
||||
class Applet(JMSBaseModel):
|
||||
class Type(models.TextChoices):
|
||||
app = 'app', _('App')
|
||||
general = 'general', _('General')
|
||||
web = 'web', _('Web')
|
||||
|
||||
class VCSType(models.TextChoices):
|
||||
manual = 'manual', _('Manual')
|
||||
git = 'git', _('Git')
|
||||
archive = 'archive', _('Remote gzip')
|
||||
|
||||
name = models.CharField(max_length=128, verbose_name=_('Name'), unique=True)
|
||||
version = models.CharField(max_length=16, verbose_name=_('Version'))
|
||||
type = models.CharField(max_length=16, choices=Type.choices, verbose_name=_('Type'))
|
||||
icon = models.ImageField(upload_to='applet/icon', verbose_name=_('Icon'))
|
||||
author = models.CharField(max_length=128, verbose_name=_('Author'))
|
||||
path = models.FilePathField(verbose_name=_('Path'))
|
||||
type = models.CharField(max_length=16, verbose_name=_('Type'), default='general', choices=Type.choices)
|
||||
vcs_type = models.CharField(max_length=16, verbose_name=_('VCS type'), null=True)
|
||||
vcs_url = models.CharField(max_length=256, verbose_name=_('URL'), null=True)
|
||||
protocols = models.JSONField(default=list, verbose_name=_('Protocol'))
|
||||
tags = models.JSONField(default=list, verbose_name=_('Tags'))
|
||||
comment = models.TextField(default='', blank=True, verbose_name=_('Comment'))
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def manifest(self):
|
||||
path = os.path.join(self.path, 'manifest.yml')
|
||||
if not os.path.exists(path):
|
||||
return None
|
||||
with open(path, 'r') as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
path = os.path.join(self.path, 'icon.png')
|
||||
if not os.path.exists(path):
|
||||
return None
|
||||
with open(path, 'rb') as f:
|
||||
return f.read()
|
||||
|
||||
@classmethod
|
||||
def validate_manifest(cls, manifest):
|
||||
fields = ['name', 'display_name', 'version', 'author', 'type', 'tags', 'protocols']
|
||||
for field in fields:
|
||||
if field not in manifest:
|
||||
raise ValidationError(f'Missing field {field}')
|
||||
if manifest['type'] not in [i[0] for i in cls.Type.choices]:
|
||||
raise ValidationError('Invalid type')
|
||||
if not isinstance(manifest['protocols'], list):
|
||||
raise ValidationError('Invalid protocols')
|
||||
|
||||
@classmethod
|
||||
def create_by_manifest(cls, manifest):
|
||||
obj = cls()
|
||||
for k, v in manifest.items():
|
||||
setattr(obj, k, v)
|
||||
obj.save()
|
||||
return obj
|
||||
|
||||
|
||||
class AppletPublication(JMSBaseModel):
|
||||
applet = models.ForeignKey('Applet', on_delete=models.PROTECT, verbose_name=_('Applet'))
|
||||
provider = models.ForeignKey('AppletProvider', on_delete=models.PROTECT, verbose_name=_('Provider'))
|
||||
host = models.ForeignKey('AppletHost', on_delete=models.PROTECT, verbose_name=_('Host'))
|
||||
status = models.CharField(max_length=16, verbose_name=_('Status'))
|
||||
comment = models.TextField(default='', blank=True, verbose_name=_('Comment'))
|
||||
|
||||
class Meta:
|
||||
unique_together = ('applet', 'provider')
|
||||
unique_together = ('applet', 'host')
|
||||
|
|
|
@ -1,31 +1,34 @@
|
|||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from celery import current_app
|
||||
|
||||
from common.db.models import JMSBaseModel
|
||||
|
||||
|
||||
__all__ = ['AppletProvider', 'ProviderDeployment']
|
||||
__all__ = ['AppletHost', 'AppletHostDeployment']
|
||||
|
||||
|
||||
class AppletProvider(JMSBaseModel):
|
||||
name = models.CharField(max_length=128, verbose_name=_('Name'), unique=True)
|
||||
asset = models.ForeignKey('assets.Asset', on_delete=models.PROTECT, verbose_name=_('Asset'))
|
||||
class AppletHost(JMSBaseModel):
|
||||
host = models.ForeignKey('assets.Host', on_delete=models.PROTECT, verbose_name=_('Host'))
|
||||
comment = models.TextField(default='', blank=True, verbose_name=_('Comment'))
|
||||
account_automation = models.BooleanField(default=False, verbose_name=_('Account automation'))
|
||||
date_synced = models.DateTimeField(null=True, blank=True, verbose_name=_('Date synced'))
|
||||
status = models.CharField(max_length=16, verbose_name=_('Status'))
|
||||
applets = models.ManyToManyField(
|
||||
'Applet', verbose_name=_('Applet'),
|
||||
through='AppletPublication', through_fields=('provider', 'applet'),
|
||||
through='AppletPublication', through_fields=('host', 'applet'),
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.host.name
|
||||
|
||||
class ProviderDeployment(JMSBaseModel):
|
||||
provider = models.ForeignKey('AppletProvider', on_delete=models.CASCADE, verbose_name=_('Provider'))
|
||||
|
||||
class AppletHostDeployment(JMSBaseModel):
|
||||
host = models.ForeignKey('AppletHost', on_delete=models.CASCADE, verbose_name=_('Hosting'))
|
||||
status = models.CharField(max_length=16, verbose_name=_('Status'))
|
||||
comment = models.TextField(default='', blank=True, verbose_name=_('Comment'))
|
||||
|
||||
def install(self):
|
||||
def __str__(self):
|
||||
return self.host
|
||||
|
||||
def start(self):
|
||||
pass
|
|
@ -5,3 +5,4 @@ from .session import *
|
|||
from .storage import *
|
||||
from .sharing import *
|
||||
from .endpoint import *
|
||||
from .applet import *
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from common.drf.fields import ObjectRelatedField
|
||||
from assets.models import Host
|
||||
from ..models import Applet, AppletPublication, AppletHost, AppletHostDeployment
|
||||
|
||||
|
||||
__all__ = [
|
||||
'AppletSerializer', 'AppletPublicationSerializer',
|
||||
'AppletHostSerializer', 'AppletHostDeploymentSerializer',
|
||||
'AppletUploadSerializer'
|
||||
]
|
||||
|
||||
|
||||
class AppletSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Applet
|
||||
fields_mini = ['id', 'name']
|
||||
read_only_fields = [
|
||||
'date_created', 'date_updated'
|
||||
]
|
||||
fields = fields_mini + [
|
||||
'version', 'author', 'type', 'protocols', 'comment'
|
||||
] + read_only_fields
|
||||
|
||||
|
||||
class AppletUploadSerializer(serializers.Serializer):
|
||||
file = serializers.FileField()
|
||||
|
||||
|
||||
class AppletPublicationSerializer(serializers.ModelSerializer):
|
||||
applet = ObjectRelatedField(queryset=Applet.objects.all())
|
||||
host = ObjectRelatedField(queryset=AppletHost.objects.all())
|
||||
|
||||
class Meta:
|
||||
model = AppletPublication
|
||||
fields_mini = ['id', 'applet', 'host']
|
||||
read_only_fields = ['date_created', 'date_updated']
|
||||
fields = fields_mini + [
|
||||
'status', 'comment',
|
||||
] + read_only_fields
|
||||
|
||||
|
||||
class AppletHostSerializer(serializers.ModelSerializer):
|
||||
host = ObjectRelatedField(queryset=Host.objects.all())
|
||||
|
||||
class Meta:
|
||||
model = AppletHost
|
||||
fields_mini = ['id', 'host']
|
||||
read_only_fields = ['date_created', 'date_updated']
|
||||
fields = fields_mini + [
|
||||
'comment', 'account_automation', 'date_synced', 'status',
|
||||
] + read_only_fields
|
||||
|
||||
|
||||
class AppletHostDeploymentSerializer(serializers.ModelSerializer):
|
||||
host = ObjectRelatedField(queryset=AppletHost.objects.all())
|
||||
|
||||
class Meta:
|
||||
model = AppletHostDeployment
|
||||
fields_mini = ['id', 'host']
|
||||
read_only_fields = ['date_created', 'date_updated']
|
||||
fields = fields_mini + [
|
||||
'status', 'comment',
|
||||
] + read_only_fields
|
|
@ -24,6 +24,11 @@ router.register(r'session-sharings', api.SessionSharingViewSet, 'session-sharing
|
|||
router.register(r'session-join-records', api.SessionJoinRecordsViewSet, 'session-sharing-record')
|
||||
router.register(r'endpoints', api.EndpointViewSet, 'endpoint')
|
||||
router.register(r'endpoint-rules', api.EndpointRuleViewSet, 'endpoint-rule')
|
||||
router.register(r'applets', api.AppletViewSet, 'applet')
|
||||
router.register(r'applet-hosts', api.AppletHostViewSet, 'applet-host')
|
||||
router.register(r'applet-publication', api.AppletPublicationViewSet, 'applet-publication')
|
||||
router.register(r'applet-host-deployment', api.AppletHostDeploymentViewSet, 'applet-host-deployment')
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('my-sessions/', api.MySessionAPIView.as_view(), name='my-session'),
|
||||
|
|
Loading…
Reference in New Issue