mirror of https://github.com/jumpserver/jumpserver
[Update] 修改 RemoteApp 前端 Form 渲染逻辑 (#3523)
* [Update] 修改 RemoteApp 前端 Form 渲染逻辑 * [Update] RemoteApp 表单添加默认值pull/3524/head
parent
b2932803b0
commit
b4498f2267
|
@ -12,29 +12,6 @@ REMOTE_APP_TYPE_MYSQL_WORKBENCH = 'mysql_workbench'
|
||||||
REMOTE_APP_TYPE_VMWARE_CLIENT = 'vmware_client'
|
REMOTE_APP_TYPE_VMWARE_CLIENT = 'vmware_client'
|
||||||
REMOTE_APP_TYPE_CUSTOM = 'custom'
|
REMOTE_APP_TYPE_CUSTOM = 'custom'
|
||||||
|
|
||||||
REMOTE_APP_TYPE_CHOICES = (
|
|
||||||
(
|
|
||||||
_('Browser'),
|
|
||||||
(
|
|
||||||
(REMOTE_APP_TYPE_CHROME, 'Chrome'),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
(
|
|
||||||
_('Database tools'),
|
|
||||||
(
|
|
||||||
(REMOTE_APP_TYPE_MYSQL_WORKBENCH, 'MySQL Workbench'),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
(
|
|
||||||
_('Virtualization tools'),
|
|
||||||
(
|
|
||||||
(REMOTE_APP_TYPE_VMWARE_CLIENT, 'vSphere Client'),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
(REMOTE_APP_TYPE_CUSTOM, _('Custom')),
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
# Fields attribute write_only default => False
|
# Fields attribute write_only default => False
|
||||||
|
|
||||||
REMOTE_APP_TYPE_CHROME_FIELDS = [
|
REMOTE_APP_TYPE_CHROME_FIELDS = [
|
||||||
|
@ -60,9 +37,16 @@ REMOTE_APP_TYPE_CUSTOM_FIELDS = [
|
||||||
{'name': 'custom_password', 'write_only': True}
|
{'name': 'custom_password', 'write_only': True}
|
||||||
]
|
]
|
||||||
|
|
||||||
REMOTE_APP_TYPE_MAP_FIELDS = {
|
REMOTE_APP_TYPE_FIELDS_MAP = {
|
||||||
REMOTE_APP_TYPE_CHROME: REMOTE_APP_TYPE_CHROME_FIELDS,
|
REMOTE_APP_TYPE_CHROME: REMOTE_APP_TYPE_CHROME_FIELDS,
|
||||||
REMOTE_APP_TYPE_MYSQL_WORKBENCH: REMOTE_APP_TYPE_MYSQL_WORKBENCH_FIELDS,
|
REMOTE_APP_TYPE_MYSQL_WORKBENCH: REMOTE_APP_TYPE_MYSQL_WORKBENCH_FIELDS,
|
||||||
REMOTE_APP_TYPE_VMWARE_CLIENT: REMOTE_APP_TYPE_VMWARE_CLIENT_FIELDS,
|
REMOTE_APP_TYPE_VMWARE_CLIENT: REMOTE_APP_TYPE_VMWARE_CLIENT_FIELDS,
|
||||||
REMOTE_APP_TYPE_CUSTOM: REMOTE_APP_TYPE_CUSTOM_FIELDS
|
REMOTE_APP_TYPE_CUSTOM: REMOTE_APP_TYPE_CUSTOM_FIELDS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
REMOTE_APP_TYPE_CHOICES = (
|
||||||
|
(REMOTE_APP_TYPE_CHROME, 'Chrome'),
|
||||||
|
(REMOTE_APP_TYPE_MYSQL_WORKBENCH, 'MySQL Workbench'),
|
||||||
|
(REMOTE_APP_TYPE_VMWARE_CLIENT, 'vSphere Client'),
|
||||||
|
(REMOTE_APP_TYPE_CUSTOM, _('Custom')),
|
||||||
|
)
|
||||||
|
|
|
@ -5,18 +5,52 @@ from django.utils.translation import ugettext as _
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
from orgs.mixins.forms import OrgModelForm
|
from orgs.mixins.forms import OrgModelForm
|
||||||
from assets.models import SystemUser
|
|
||||||
|
|
||||||
from ..models import RemoteApp
|
from ..models import RemoteApp
|
||||||
from .. import const
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'RemoteAppCreateUpdateForm',
|
'RemoteAppChromeForm', 'RemoteAppMySQLWorkbenchForm',
|
||||||
|
'RemoteAppVMwareForm', 'RemoteAppCustomForm'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class RemoteAppTypeChromeForm(forms.ModelForm):
|
class BaseRemoteAppForm(OrgModelForm):
|
||||||
|
default_initial_data = {}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
# 过滤RDP资产和系统用户
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
field_asset = self.fields['asset']
|
||||||
|
field_asset.queryset = field_asset.queryset.has_protocol('rdp')
|
||||||
|
self.fields['type'].widget.attrs['disabled'] = True
|
||||||
|
self.fields.move_to_end('comment')
|
||||||
|
self.initial_default()
|
||||||
|
|
||||||
|
def initial_default(self):
|
||||||
|
for name, value in self.default_initial_data.items():
|
||||||
|
field = self.fields.get(name)
|
||||||
|
if not field:
|
||||||
|
continue
|
||||||
|
field.initial = value
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = RemoteApp
|
||||||
|
fields = [
|
||||||
|
'name', 'asset', 'type', 'path', 'comment'
|
||||||
|
]
|
||||||
|
widgets = {
|
||||||
|
'asset': forms.Select(attrs={
|
||||||
|
'class': 'select2', 'data-placeholder': _('Asset')
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class RemoteAppChromeForm(BaseRemoteAppForm):
|
||||||
|
default_initial_data = {
|
||||||
|
'path': r'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe'
|
||||||
|
}
|
||||||
|
|
||||||
chrome_target = forms.CharField(
|
chrome_target = forms.CharField(
|
||||||
max_length=128, label=_('Target URL'), required=False
|
max_length=128, label=_('Target URL'), required=False
|
||||||
)
|
)
|
||||||
|
@ -29,7 +63,12 @@ class RemoteAppTypeChromeForm(forms.ModelForm):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RemoteAppTypeMySQLWorkbenchForm(forms.ModelForm):
|
class RemoteAppMySQLWorkbenchForm(BaseRemoteAppForm):
|
||||||
|
default_initial_data = {
|
||||||
|
'path': r'C:\Program Files\MySQL\MySQL Workbench 8.0 CE'
|
||||||
|
r'\MySQLWorkbench.exe'
|
||||||
|
}
|
||||||
|
|
||||||
mysql_workbench_ip = forms.CharField(
|
mysql_workbench_ip = forms.CharField(
|
||||||
max_length=128, label=_('Database IP'), required=False
|
max_length=128, label=_('Database IP'), required=False
|
||||||
)
|
)
|
||||||
|
@ -45,7 +84,12 @@ class RemoteAppTypeMySQLWorkbenchForm(forms.ModelForm):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RemoteAppTypeVMwareForm(forms.ModelForm):
|
class RemoteAppVMwareForm(BaseRemoteAppForm):
|
||||||
|
default_initial_data = {
|
||||||
|
'path': r'C:\Program Files (x86)\VMware\Infrastructure'
|
||||||
|
r'\Virtual Infrastructure Client\Launcher\VpxClient.exe'
|
||||||
|
}
|
||||||
|
|
||||||
vmware_target = forms.CharField(
|
vmware_target = forms.CharField(
|
||||||
max_length=128, label=_('Target address'), required=False
|
max_length=128, label=_('Target address'), required=False
|
||||||
)
|
)
|
||||||
|
@ -58,7 +102,8 @@ class RemoteAppTypeVMwareForm(forms.ModelForm):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RemoteAppTypeCustomForm(forms.ModelForm):
|
class RemoteAppCustomForm(BaseRemoteAppForm):
|
||||||
|
|
||||||
custom_cmdline = forms.CharField(
|
custom_cmdline = forms.CharField(
|
||||||
max_length=128, label=_('Operating parameter'), required=False
|
max_length=128, label=_('Operating parameter'), required=False
|
||||||
)
|
)
|
||||||
|
@ -73,51 +118,3 @@ class RemoteAppTypeCustomForm(forms.ModelForm):
|
||||||
max_length=128, label=_('Login password'), required=False
|
max_length=128, label=_('Login password'), required=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RemoteAppTypeForms(
|
|
||||||
RemoteAppTypeChromeForm,
|
|
||||||
RemoteAppTypeMySQLWorkbenchForm,
|
|
||||||
RemoteAppTypeVMwareForm,
|
|
||||||
RemoteAppTypeCustomForm
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class RemoteAppCreateUpdateForm(RemoteAppTypeForms, OrgModelForm):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
# 过滤RDP资产和系统用户
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
field_asset = self.fields['asset']
|
|
||||||
field_asset.queryset = field_asset.queryset.has_protocol('rdp')
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = RemoteApp
|
|
||||||
fields = [
|
|
||||||
'name', 'asset', 'type', 'path', 'comment'
|
|
||||||
]
|
|
||||||
widgets = {
|
|
||||||
'asset': forms.Select(attrs={
|
|
||||||
'class': 'select2', 'data-placeholder': _('Asset')
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
def _clean_params(self):
|
|
||||||
app_type = self.data.get('type')
|
|
||||||
fields = const.REMOTE_APP_TYPE_MAP_FIELDS.get(app_type, [])
|
|
||||||
params = {}
|
|
||||||
for field in fields:
|
|
||||||
name = field['name']
|
|
||||||
value = self.cleaned_data[name]
|
|
||||||
params.update({name: value})
|
|
||||||
return params
|
|
||||||
|
|
||||||
def _save_params(self, instance):
|
|
||||||
params = self._clean_params()
|
|
||||||
instance.params = params
|
|
||||||
instance.save()
|
|
||||||
return instance
|
|
||||||
|
|
||||||
def save(self, commit=True):
|
|
||||||
instance = super().save(commit=commit)
|
|
||||||
instance = self._save_params(instance)
|
|
||||||
return instance
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ class RemoteApp(OrgModelMixin):
|
||||||
_parameters.append(self.type)
|
_parameters.append(self.type)
|
||||||
path = '\"%s\"' % self.path
|
path = '\"%s\"' % self.path
|
||||||
_parameters.append(path)
|
_parameters.append(path)
|
||||||
for field in const.REMOTE_APP_TYPE_MAP_FIELDS[self.type]:
|
for field in const.REMOTE_APP_TYPE_FIELDS_MAP[self.type]:
|
||||||
value = self.params.get(field['name'])
|
value = self.params.get(field['name'])
|
||||||
if value is None:
|
if value is None:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import copy
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from common.serializers import AdaptedBulkListSerializer
|
from common.serializers import AdaptedBulkListSerializer
|
||||||
|
@ -18,26 +18,53 @@ __all__ = [
|
||||||
|
|
||||||
|
|
||||||
class RemoteAppParamsDictField(CustomMetaDictField):
|
class RemoteAppParamsDictField(CustomMetaDictField):
|
||||||
type_map_fields = const.REMOTE_APP_TYPE_MAP_FIELDS
|
type_fields_map = const.REMOTE_APP_TYPE_FIELDS_MAP
|
||||||
default_type = const.REMOTE_APP_TYPE_CHROME
|
default_type = const.REMOTE_APP_TYPE_CHROME
|
||||||
|
convert_key_remove_type_prefix = False
|
||||||
|
convert_key_to_upper = False
|
||||||
|
|
||||||
|
|
||||||
class RemoteAppSerializer(BulkOrgResourceModelSerializer):
|
class RemoteAppSerializer(BulkOrgResourceModelSerializer):
|
||||||
params = RemoteAppParamsDictField()
|
params = RemoteAppParamsDictField()
|
||||||
|
type_fields_map = const.REMOTE_APP_TYPE_FIELDS_MAP
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RemoteApp
|
model = RemoteApp
|
||||||
list_serializer_class = AdaptedBulkListSerializer
|
list_serializer_class = AdaptedBulkListSerializer
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'name', 'asset', 'type', 'path', 'params',
|
'id', 'name', 'asset', 'asset_info', 'type', 'get_type_display',
|
||||||
'comment', 'created_by', 'date_created', 'asset_info',
|
'path', 'params', 'date_created', 'created_by', 'comment',
|
||||||
'get_type_display',
|
|
||||||
]
|
]
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
'created_by', 'date_created', 'asset_info',
|
'created_by', 'date_created', 'asset_info',
|
||||||
'get_type_display'
|
'get_type_display'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def process_params(self, instance, validated_data):
|
||||||
|
new_params = copy.deepcopy(validated_data.get('params', {}))
|
||||||
|
tp = validated_data.get('type', '')
|
||||||
|
|
||||||
|
if tp != instance.type:
|
||||||
|
return new_params
|
||||||
|
|
||||||
|
old_params = instance.params
|
||||||
|
fields = self.type_fields_map.get(instance.type, [])
|
||||||
|
for field in fields:
|
||||||
|
if not field.get('write_only', False):
|
||||||
|
continue
|
||||||
|
field_name = field['name']
|
||||||
|
new_value = new_params.get(field_name, '')
|
||||||
|
old_value = old_params.get(field_name, '')
|
||||||
|
field_value = new_value if new_value else old_value
|
||||||
|
new_params[field_name] = field_value
|
||||||
|
|
||||||
|
return new_params
|
||||||
|
|
||||||
|
def update(self, instance, validated_data):
|
||||||
|
params = self.process_params(instance, validated_data)
|
||||||
|
validated_data['params'] = params
|
||||||
|
return super().update(instance, validated_data)
|
||||||
|
|
||||||
|
|
||||||
class RemoteAppConnectionInfoSerializer(serializers.ModelSerializer):
|
class RemoteAppConnectionInfoSerializer(serializers.ModelSerializer):
|
||||||
parameter_remote_app = serializers.SerializerMethodField()
|
parameter_remote_app = serializers.SerializerMethodField()
|
||||||
|
|
|
@ -4,51 +4,8 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block form %}
|
{% block form %}
|
||||||
<form id="appForm" method="post" class="form-horizontal">
|
<form id="RemoteAppForm" method="post" class="form-horizontal">
|
||||||
{% if form.non_field_errors %}
|
{% bootstrap_form form layout="horizontal" %}
|
||||||
<div class="alert alert-danger">
|
|
||||||
{{ form.non_field_errors }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% csrf_token %}
|
|
||||||
{% bootstrap_field form.name layout="horizontal" %}
|
|
||||||
{% bootstrap_field form.asset layout="horizontal" %}
|
|
||||||
{% bootstrap_field form.type layout="horizontal" %}
|
|
||||||
{% bootstrap_field form.path layout="horizontal" %}
|
|
||||||
|
|
||||||
<div class="hr-line-dashed"></div>
|
|
||||||
|
|
||||||
{# chrome #}
|
|
||||||
<div class="chrome-fields hidden">
|
|
||||||
{% bootstrap_field form.chrome_target layout="horizontal" %}
|
|
||||||
{% bootstrap_field form.chrome_username layout="horizontal" %}
|
|
||||||
{% bootstrap_field form.chrome_password layout="horizontal" %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{# mysql workbench #}
|
|
||||||
<div class="mysql_workbench-fields hidden">
|
|
||||||
{% bootstrap_field form.mysql_workbench_ip layout="horizontal" %}
|
|
||||||
{% bootstrap_field form.mysql_workbench_name layout="horizontal" %}
|
|
||||||
{% bootstrap_field form.mysql_workbench_username layout="horizontal" %}
|
|
||||||
{% bootstrap_field form.mysql_workbench_password layout="horizontal" %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{# vmware #}
|
|
||||||
<div class="vmware_client-fields hidden">
|
|
||||||
{% bootstrap_field form.vmware_target layout="horizontal" %}
|
|
||||||
{% bootstrap_field form.vmware_username layout="horizontal" %}
|
|
||||||
{% bootstrap_field form.vmware_password layout="horizontal" %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{# custom #}
|
|
||||||
<div class="custom-fields hidden">
|
|
||||||
{% bootstrap_field form.custom_cmdline layout="horizontal" %}
|
|
||||||
{% bootstrap_field form.custom_target layout="horizontal" %}
|
|
||||||
{% bootstrap_field form.custom_username layout="horizontal" %}
|
|
||||||
{% bootstrap_field form.custom_password layout="horizontal" %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% bootstrap_field form.comment layout="horizontal" %}
|
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-4 col-sm-offset-2">
|
<div class="col-sm-4 col-sm-offset-2">
|
||||||
|
@ -57,93 +14,49 @@
|
||||||
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var app_type_id = '#' + '{{ form.type.id_for_label }}';
|
var app_type_id = '#' + '{{ form.type.id_for_label }}';
|
||||||
var app_path_id = '#' + '{{ form.path.id_for_label }}';
|
|
||||||
var all_type_fields = [
|
function getFormDataType(){
|
||||||
'.chrome-fields',
|
|
||||||
'.mysql_workbench-fields',
|
|
||||||
'.vmware_client-fields',
|
|
||||||
'.custom-fields'
|
|
||||||
];
|
|
||||||
var app_type_map_default_fields_value = {
|
|
||||||
'chrome': {
|
|
||||||
'app_path': 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe'
|
|
||||||
},
|
|
||||||
'mysql_workbench': {
|
|
||||||
'app_path': 'C:\\Program Files\\MySQL\\MySQL Workbench 8.0 CE\\MySQLWorkbench.exe'
|
|
||||||
},
|
|
||||||
'vmware_client': {
|
|
||||||
'app_path': 'C:\\Program Files (x86)\\VMware\\Infrastructure\\Virtual Infrastructure Client\\Launcher\\VpxClient.exe'
|
|
||||||
},
|
|
||||||
'custom': {'app_path': ''}
|
|
||||||
};
|
|
||||||
function getAppType(){
|
|
||||||
return $(app_type_id+ " option:selected").val();
|
return $(app_type_id+ " option:selected").val();
|
||||||
}
|
}
|
||||||
function initialDefaultValue(){
|
function constructFormDataParams(data){
|
||||||
var app_type = getAppType();
|
|
||||||
var app_path = $(app_path_id).val();
|
|
||||||
if(app_path){
|
|
||||||
app_type_map_default_fields_value[app_type]['app_path'] = app_path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function setDefaultValue(){
|
|
||||||
// 设置类型相关字段的默认值
|
|
||||||
var app_type = getAppType();
|
|
||||||
var app_path = app_type_map_default_fields_value[app_type]['app_path'];
|
|
||||||
$(app_path_id).val(app_path)
|
|
||||||
}
|
|
||||||
function hiddenFields(){
|
|
||||||
var app_type = getAppType();
|
|
||||||
$.each(all_type_fields, function(index, value){
|
|
||||||
$(value).addClass('hidden')
|
|
||||||
});
|
|
||||||
$('.' + app_type + '-fields').removeClass('hidden');
|
|
||||||
}
|
|
||||||
function constructParams(data) {
|
|
||||||
var typeList = ['chrome', 'mysql_workbench', 'vmware_client', 'custom'];
|
|
||||||
var params = {};
|
var params = {};
|
||||||
$.each(typeList, function(index, value){
|
var type =data.type;
|
||||||
if (data.type === value){
|
|
||||||
for (var k in data){
|
for (var k in data){
|
||||||
if (k.startsWith(value)){
|
if (k.startsWith(type)){
|
||||||
params[k] = data[k]
|
params[k] = data[k];
|
||||||
|
delete data[k]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return params
|
||||||
}
|
}
|
||||||
});
|
function getFormData(form){
|
||||||
return params;
|
var data = form.serializeObject();
|
||||||
|
data['type'] = getFormDataType();
|
||||||
|
data['params'] = constructFormDataParams(data);
|
||||||
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('.select2').select2({
|
$('.select2').select2({
|
||||||
closeOnSelect: true
|
closeOnSelect: true
|
||||||
});
|
});
|
||||||
initialDefaultValue();
|
}).on("submit", "form", function (evt) {
|
||||||
hiddenFields();
|
|
||||||
setDefaultValue();
|
|
||||||
})
|
|
||||||
.on('change', app_type_id, function(){
|
|
||||||
hiddenFields();
|
|
||||||
setDefaultValue();
|
|
||||||
})
|
|
||||||
.on("submit", "form", function (evt) {
|
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
var the_url = '{% url "api-applications:remote-app-list" %}';
|
var the_url = '{% url "api-applications:remote-app-list" %}';
|
||||||
var redirect_to = '{% url "applications:remote-app-list" %}';
|
var redirect_to = '{% url "applications:remote-app-list" %}';
|
||||||
var method = "POST";
|
var method = "POST";
|
||||||
{% if type == "update" %}
|
{% if api_action == "update" %}
|
||||||
the_url = '{% url "api-applications:remote-app-detail" object.id %}';
|
the_url = '{% url "api-applications:remote-app-detail" object.id %}';
|
||||||
method = "PUT";
|
method = "PUT";
|
||||||
{% endif %}
|
{% endif %}
|
||||||
var form = $("form");
|
var form = $("form");
|
||||||
var data = form.serializeObject();
|
var data = getFormData(form);
|
||||||
data["params"] = constructParams(data);
|
|
||||||
var props = {
|
var props = {
|
||||||
url: the_url,
|
url: the_url,
|
||||||
data: data,
|
data: data,
|
||||||
|
|
|
@ -6,8 +6,16 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block table_search %}{% endblock %}
|
{% block table_search %}{% endblock %}
|
||||||
{% block table_container %}
|
{% block table_container %}
|
||||||
<div class="uc pull-left m-r-5">
|
<div class="btn-group uc pull-left m-r-5">
|
||||||
<a href="{% url 'applications:remote-app-create' %}" class="btn btn-sm btn-primary"> {% trans "Create RemoteApp" %} </a>
|
<button class="btn btn-sm btn-primary">
|
||||||
|
{% trans "Create RemoteApp" %}
|
||||||
|
</button>
|
||||||
|
<button data-toggle="dropdown" class="btn btn-primary btn-sm dropdown-toggle"><span class="caret"></span></button>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
{% for key, value in type_choices %}
|
||||||
|
<li><a class="" href="{% url 'applications:remote-app-create' %}?type={{ key }}">{{ value }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-striped table-bordered table-hover " id="remote_app_list_table" >
|
<table class="table table-striped table-bordered table-hover " id="remote_app_list_table" >
|
||||||
<thead>
|
<thead>
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
#
|
#
|
||||||
|
|
||||||
|
from django.http import Http404
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
from django.views.generic.edit import CreateView, UpdateView
|
from django.views.generic.edit import CreateView, UpdateView
|
||||||
from django.views.generic.detail import DetailView
|
from django.views.generic.detail import DetailView
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
|
||||||
from django.urls import reverse_lazy
|
|
||||||
|
|
||||||
|
|
||||||
from common.permissions import PermissionsMixin, IsOrgAdmin, IsValidUser
|
from common.permissions import PermissionsMixin, IsOrgAdmin, IsValidUser
|
||||||
from common.const import create_success_msg, update_success_msg
|
|
||||||
|
|
||||||
from ..models import RemoteApp
|
from ..models import RemoteApp
|
||||||
from .. import forms
|
from .. import forms, const
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
@ -30,53 +27,79 @@ class RemoteAppListView(PermissionsMixin, TemplateView):
|
||||||
context = {
|
context = {
|
||||||
'app': _('Applications'),
|
'app': _('Applications'),
|
||||||
'action': _('RemoteApp list'),
|
'action': _('RemoteApp list'),
|
||||||
|
'type_choices': const.REMOTE_APP_TYPE_CHOICES,
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class RemoteAppCreateView(PermissionsMixin, SuccessMessageMixin, CreateView):
|
class BaseRemoteAppCreateUpdateView:
|
||||||
template_name = 'applications/remote_app_create_update.html'
|
template_name = 'applications/remote_app_create_update.html'
|
||||||
model = RemoteApp
|
model = RemoteApp
|
||||||
form_class = forms.RemoteAppCreateUpdateForm
|
|
||||||
success_url = reverse_lazy('applications:remote-app-list')
|
|
||||||
permission_classes = [IsOrgAdmin]
|
permission_classes = [IsOrgAdmin]
|
||||||
|
default_type = const.REMOTE_APP_TYPE_CHROME
|
||||||
|
form_class = forms.RemoteAppChromeForm
|
||||||
|
form_class_choices = {
|
||||||
|
const.REMOTE_APP_TYPE_CHROME: forms.RemoteAppChromeForm,
|
||||||
|
const.REMOTE_APP_TYPE_MYSQL_WORKBENCH: forms.RemoteAppMySQLWorkbenchForm,
|
||||||
|
const.REMOTE_APP_TYPE_VMWARE_CLIENT: forms.RemoteAppVMwareForm,
|
||||||
|
const.REMOTE_APP_TYPE_CUSTOM: forms.RemoteAppCustomForm
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_initial(self):
|
||||||
|
return {'type': self.get_type()}
|
||||||
|
|
||||||
|
def get_type(self):
|
||||||
|
return self.default_type
|
||||||
|
|
||||||
|
def get_form_class(self):
|
||||||
|
tp = self.get_type()
|
||||||
|
form_class = self.form_class_choices.get(tp)
|
||||||
|
if not form_class:
|
||||||
|
raise Http404()
|
||||||
|
return form_class
|
||||||
|
|
||||||
|
|
||||||
|
class RemoteAppCreateView(BaseRemoteAppCreateUpdateView,
|
||||||
|
PermissionsMixin, CreateView):
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'app': _('Applications'),
|
'app': _('Applications'),
|
||||||
'action': _('Create RemoteApp'),
|
'action': _('Create RemoteApp'),
|
||||||
'type': 'create'
|
'api_action': 'create'
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def get_success_message(self, cleaned_data):
|
def get_type(self):
|
||||||
return create_success_msg % ({'name': cleaned_data['name']})
|
tp = self.request.GET.get("type")
|
||||||
|
if tp:
|
||||||
|
return tp.lower()
|
||||||
|
return super().get_type()
|
||||||
|
|
||||||
|
|
||||||
class RemoteAppUpdateView(PermissionsMixin, SuccessMessageMixin, UpdateView):
|
class RemoteAppUpdateView(BaseRemoteAppCreateUpdateView,
|
||||||
template_name = 'applications/remote_app_create_update.html'
|
PermissionsMixin, UpdateView):
|
||||||
model = RemoteApp
|
|
||||||
form_class = forms.RemoteAppCreateUpdateForm
|
|
||||||
success_url = reverse_lazy('applications:remote-app-list')
|
|
||||||
permission_classes = [IsOrgAdmin]
|
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
return {k: v for k, v in self.object.params.items()}
|
initial_data = super().get_initial()
|
||||||
|
params = {k: v for k, v in self.object.params.items()}
|
||||||
|
initial_data.update(params)
|
||||||
|
return initial_data
|
||||||
|
|
||||||
|
def get_type(self):
|
||||||
|
return self.object.type
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'app': _('Applications'),
|
'app': _('Applications'),
|
||||||
'action': _('Update RemoteApp'),
|
'action': _('Update RemoteApp'),
|
||||||
'type': 'update'
|
'api_action': 'update'
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def get_success_message(self, cleaned_data):
|
|
||||||
return update_success_msg % ({'name': cleaned_data['name']})
|
|
||||||
|
|
||||||
|
|
||||||
class RemoteAppDetailView(PermissionsMixin, DetailView):
|
class RemoteAppDetailView(PermissionsMixin, DetailView):
|
||||||
template_name = 'applications/remote_app_detail.html'
|
template_name = 'applications/remote_app_detail.html'
|
||||||
|
|
|
@ -51,12 +51,13 @@ class CustomMetaDictField(serializers.DictField):
|
||||||
CommandStorage meta field
|
CommandStorage meta field
|
||||||
ReplayStorage meta field
|
ReplayStorage meta field
|
||||||
"""
|
"""
|
||||||
type_map_fields = {}
|
type_fields_map = {}
|
||||||
default_type = None
|
default_type = None
|
||||||
need_convert_key = False
|
convert_key_remove_type_prefix = False
|
||||||
|
convert_key_to_upper = False
|
||||||
|
|
||||||
def filter_attribute(self, attribute, instance):
|
def filter_attribute(self, attribute, instance):
|
||||||
fields = self.type_map_fields.get(instance.type, [])
|
fields = self.type_fields_map.get(instance.type, [])
|
||||||
for field in fields:
|
for field in fields:
|
||||||
if field.get('write_only', False):
|
if field.get('write_only', False):
|
||||||
attribute.pop(field['name'], None)
|
attribute.pop(field['name'], None)
|
||||||
|
@ -70,29 +71,35 @@ class CustomMetaDictField(serializers.DictField):
|
||||||
attribute = self.filter_attribute(attribute, instance)
|
attribute = self.filter_attribute(attribute, instance)
|
||||||
return attribute
|
return attribute
|
||||||
|
|
||||||
def convert_value_key(self, dictionary, value):
|
def convert_value_key_remove_type_prefix(self, dictionary, value):
|
||||||
if not self.need_convert_key:
|
if not self.convert_key_remove_type_prefix:
|
||||||
# remote app
|
|
||||||
return value
|
return value
|
||||||
tp = dictionary.get('type')
|
tp = dictionary.get('type')
|
||||||
_value = {}
|
|
||||||
for k, v in value.items():
|
|
||||||
prefix = '{}_'.format(tp)
|
prefix = '{}_'.format(tp)
|
||||||
_k = k
|
convert_value = {}
|
||||||
|
for k, v in value.items():
|
||||||
if k.lower().startswith(prefix):
|
if k.lower().startswith(prefix):
|
||||||
_k = k.lower().split(prefix, 1)[1]
|
k = k.lower().split(prefix, 1)[1]
|
||||||
_k = _k.upper()
|
convert_value[k] = v
|
||||||
_value[_k] = value[k]
|
return convert_value
|
||||||
return _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):
|
def filter_value_key(self, dictionary, value):
|
||||||
tp = dictionary.get('type', self.default_type)
|
tp = dictionary.get('type')
|
||||||
fields = self.type_map_fields.get(tp, [])
|
fields = self.type_fields_map.get(tp, [])
|
||||||
fields_names = [field['name'] for field in fields]
|
fields_names = [field['name'] for field in fields]
|
||||||
no_need_keys = [k for k in value.keys() if k not in fields_names]
|
filter_value = {k: v for k, v in value.items() if k in fields_names}
|
||||||
for k in no_need_keys:
|
return filter_value
|
||||||
value.pop(k)
|
|
||||||
return value
|
|
||||||
|
|
||||||
def get_value(self, dictionary):
|
def get_value(self, dictionary):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -49,7 +49,7 @@ REPLAY_STORAGE_TYPE_AZURE_FIELDS = [
|
||||||
{'name': 'ENDPOINT_SUFFIX'}
|
{'name': 'ENDPOINT_SUFFIX'}
|
||||||
]
|
]
|
||||||
|
|
||||||
REPLAY_STORAGE_TYPE_MAP_FIELDS = {
|
REPLAY_STORAGE_TYPE_FIELDS_MAP = {
|
||||||
REPLAY_STORAGE_TYPE_NULL: REPLAY_STORAGE_TYPE_EMPTY_FIELDS,
|
REPLAY_STORAGE_TYPE_NULL: REPLAY_STORAGE_TYPE_EMPTY_FIELDS,
|
||||||
REPLAY_STORAGE_TYPE_SERVER: 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_S3: REPLAY_STORAGE_TYPE_S3_FIELDS,
|
||||||
|
@ -89,7 +89,7 @@ COMMAND_STORAGE_TYPE_ES_FIELDS = [
|
||||||
{'name': 'DOC_TYPE'}
|
{'name': 'DOC_TYPE'}
|
||||||
]
|
]
|
||||||
|
|
||||||
COMMAND_STORAGE_TYPE_MAP_FIELDS = {
|
COMMAND_STORAGE_TYPE_FIELDS_MAP = {
|
||||||
COMMAND_STORAGE_TYPE_NULL: COMMAND_STORAGE_TYPE_EMPTY_FIELDS,
|
COMMAND_STORAGE_TYPE_NULL: COMMAND_STORAGE_TYPE_EMPTY_FIELDS,
|
||||||
COMMAND_STORAGE_TYPE_SERVER: 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_ES: COMMAND_STORAGE_TYPE_ES_FIELDS,
|
||||||
|
|
|
@ -9,13 +9,14 @@ from .. import const
|
||||||
|
|
||||||
|
|
||||||
class ReplayStorageMetaDictField(CustomMetaDictField):
|
class ReplayStorageMetaDictField(CustomMetaDictField):
|
||||||
type_map_fields = const.REPLAY_STORAGE_TYPE_MAP_FIELDS
|
type_fields_map = const.REPLAY_STORAGE_TYPE_FIELDS_MAP
|
||||||
default_type = const.REPLAY_STORAGE_TYPE_SERVER
|
default_type = const.REPLAY_STORAGE_TYPE_SERVER
|
||||||
need_convert_key = True
|
convert_key_remove_type_prefix = True
|
||||||
|
convert_key_to_upper = True
|
||||||
|
|
||||||
|
|
||||||
class BaseStorageSerializerMixin:
|
class BaseStorageSerializerMixin:
|
||||||
type_map_fields = None
|
type_fields_map = None
|
||||||
|
|
||||||
def process_meta(self, instance, validated_data):
|
def process_meta(self, instance, validated_data):
|
||||||
new_meta = copy.deepcopy(validated_data.get('meta', {}))
|
new_meta = copy.deepcopy(validated_data.get('meta', {}))
|
||||||
|
@ -25,7 +26,7 @@ class BaseStorageSerializerMixin:
|
||||||
return new_meta
|
return new_meta
|
||||||
|
|
||||||
old_meta = instance.meta
|
old_meta = instance.meta
|
||||||
fields = self.type_map_fields.get(instance.type, [])
|
fields = self.type_fields_map.get(instance.type, [])
|
||||||
for field in fields:
|
for field in fields:
|
||||||
if not field.get('write_only', False):
|
if not field.get('write_only', False):
|
||||||
continue
|
continue
|
||||||
|
@ -48,7 +49,7 @@ class ReplayStorageSerializer(BaseStorageSerializerMixin,
|
||||||
|
|
||||||
meta = ReplayStorageMetaDictField()
|
meta = ReplayStorageMetaDictField()
|
||||||
|
|
||||||
type_map_fields = const.REPLAY_STORAGE_TYPE_MAP_FIELDS
|
type_fields_map = const.REPLAY_STORAGE_TYPE_FIELDS_MAP
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ReplayStorage
|
model = ReplayStorage
|
||||||
|
@ -56,9 +57,10 @@ class ReplayStorageSerializer(BaseStorageSerializerMixin,
|
||||||
|
|
||||||
|
|
||||||
class CommandStorageMetaDictField(CustomMetaDictField):
|
class CommandStorageMetaDictField(CustomMetaDictField):
|
||||||
type_map_fields = const.COMMAND_STORAGE_TYPE_MAP_FIELDS
|
type_fields_map = const.COMMAND_STORAGE_TYPE_FIELDS_MAP
|
||||||
default_type = const.COMMAND_STORAGE_TYPE_SERVER
|
default_type = const.COMMAND_STORAGE_TYPE_SERVER
|
||||||
need_convert_key = True
|
convert_key_remove_type_prefix = True
|
||||||
|
convert_key_to_upper = True
|
||||||
|
|
||||||
|
|
||||||
class CommandStorageSerializer(BaseStorageSerializerMixin,
|
class CommandStorageSerializer(BaseStorageSerializerMixin,
|
||||||
|
@ -66,7 +68,7 @@ class CommandStorageSerializer(BaseStorageSerializerMixin,
|
||||||
|
|
||||||
meta = CommandStorageMetaDictField()
|
meta = CommandStorageMetaDictField()
|
||||||
|
|
||||||
type_map_fields = const.COMMAND_STORAGE_TYPE_MAP_FIELDS
|
type_fields_map = const.COMMAND_STORAGE_TYPE_FIELDS_MAP
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CommandStorage
|
model = CommandStorage
|
||||||
|
|
Loading…
Reference in New Issue