mirror of https://github.com/jumpserver/jumpserver
[Feature] 修改adminuser systemuser cluster及他们的关系
parent
0c9e24dc59
commit
cbc000696e
|
@ -39,21 +39,20 @@ class AssetViewSet(IDInFilterMixin, BulkModelViewSet):
|
|||
|
||||
def get_queryset(self):
|
||||
if self.request.user.is_superuser:
|
||||
queryset = super(AssetViewSet, self).get_queryset()
|
||||
queryset = super().get_queryset()
|
||||
else:
|
||||
queryset = get_user_granted_assets(self.request.user)
|
||||
cluster_id = self.request.query_params.get('cluster_id', '')
|
||||
system_users_id = self.request.query_params.get('system_user_id', '')
|
||||
asset_group_id = self.request.query_params.get('asset_group_id', '')
|
||||
admin_user_id = self.request.query_params.get('admin_user_id', '')
|
||||
cluster_id = self.request.query_params.get('cluster_id')
|
||||
asset_group_id = self.request.query_params.get('asset_group_id')
|
||||
admin_user_id = self.request.query_params.get('admin_user_id')
|
||||
if cluster_id:
|
||||
queryset = queryset.filter(cluster__id=cluster_id)
|
||||
if system_users_id:
|
||||
queryset = queryset.filter(system_users__id=system_users_id)
|
||||
if admin_user_id:
|
||||
queryset = queryset.filter(admin_user__id=admin_user_id)
|
||||
if asset_group_id:
|
||||
queryset = queryset.filter(groups__id=asset_group_id)
|
||||
if admin_user_id:
|
||||
admin_user = get_object_or_404(AdminUser, id=admin_user_id)
|
||||
clusters = [cluster.id for cluster in admin_user.cluster_set.all()]
|
||||
queryset = queryset.filter(cluster__id__in=clusters)
|
||||
return queryset
|
||||
|
||||
|
||||
|
|
|
@ -10,40 +10,60 @@ logger = get_logger(__file__)
|
|||
|
||||
|
||||
class AssetCreateForm(forms.ModelForm):
|
||||
# Form field name can not start with `_`, so redefine it,
|
||||
password = forms.CharField(
|
||||
widget=forms.PasswordInput, max_length=100,
|
||||
strip=True, required=False,
|
||||
help_text=_('If also set private key, use that first'),
|
||||
)
|
||||
# Need use upload private key file except paste private key content
|
||||
private_key_file = forms.FileField(required=False)
|
||||
|
||||
def save(self, commit=True):
|
||||
# Because we define custom field, so we need rewrite :method: `save`
|
||||
obj = super().save(commit=commit)
|
||||
password = self.cleaned_data['password']
|
||||
private_key = self.cleaned_data['private_key_file']
|
||||
|
||||
if password:
|
||||
obj.password = password
|
||||
if private_key:
|
||||
obj.private_key = private_key
|
||||
obj.save()
|
||||
return obj
|
||||
|
||||
def clean_private_key_file(self):
|
||||
private_key_file = self.cleaned_data['private_key_file']
|
||||
if private_key_file:
|
||||
private_key = private_key_file.read()
|
||||
if not validate_ssh_private_key(private_key):
|
||||
raise forms.ValidationError(_('Invalid private key'))
|
||||
return private_key
|
||||
return private_key_file
|
||||
|
||||
class Meta:
|
||||
model = Asset
|
||||
fields = [
|
||||
'hostname', 'ip', 'public_ip', 'port', 'type', 'comment',
|
||||
'admin_user', "cluster", 'groups', 'status', 'env', 'is_active'
|
||||
'cluster', 'groups', 'status', 'env', 'is_active', 'username',
|
||||
|
||||
]
|
||||
widgets = {
|
||||
'groups': forms.SelectMultiple(
|
||||
attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select asset groups')}),
|
||||
'admin_user': forms.Select(
|
||||
attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select asset admin user')}),
|
||||
}
|
||||
help_texts = {
|
||||
'hostname': '* required',
|
||||
'ip': '* required',
|
||||
'system_users': _('System user will be granted for user to login '
|
||||
'assets (using ansible create automatic)'),
|
||||
'admin_user': _('Admin user should be exist on asset already, '
|
||||
'And have sudo ALL permission'),
|
||||
}
|
||||
|
||||
def clean_admin_user(self):
|
||||
if not self.cleaned_data['admin_user']:
|
||||
raise forms.ValidationError(_('Select admin user'))
|
||||
return self.cleaned_data['admin_user']
|
||||
|
||||
|
||||
class AssetUpdateForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Asset
|
||||
fields = [
|
||||
'hostname', 'ip', 'port', 'groups', 'admin_user', "cluster", 'is_active',
|
||||
'hostname', 'ip', 'port', 'groups', "cluster", 'is_active',
|
||||
'type', 'env', 'status', 'public_ip', 'remote_card_ip', 'cabinet_no',
|
||||
'cabinet_pos', 'number', 'comment'
|
||||
]
|
||||
|
@ -51,17 +71,10 @@ class AssetUpdateForm(forms.ModelForm):
|
|||
'groups': forms.SelectMultiple(
|
||||
attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select asset groups')}),
|
||||
'admin_user': forms.Select(
|
||||
attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select asset admin user')}),
|
||||
}
|
||||
help_texts = {
|
||||
'hostname': '* required',
|
||||
'ip': '* required',
|
||||
'system_users': _('System user will be granted for user '
|
||||
'to login assets (using ansible create automatic)'),
|
||||
'admin_user': _('Admin user should be exist on asset '
|
||||
'already, And have sudo ALL permission'),
|
||||
}
|
||||
|
||||
|
||||
|
@ -77,22 +90,16 @@ class AssetBulkUpdateForm(forms.ModelForm):
|
|||
}
|
||||
)
|
||||
)
|
||||
port = forms.IntegerField(min_value=1, max_value=65535,
|
||||
required=False, label=_('Port'))
|
||||
port = forms.IntegerField(min_value=1, max_value=65535, required=False, label=_('Port'))
|
||||
|
||||
class Meta:
|
||||
model = Asset
|
||||
fields = [
|
||||
'assets', 'port', 'groups', 'admin_user', "cluster",
|
||||
'assets', 'port', 'groups', "cluster",
|
||||
'type', 'env', 'status',
|
||||
]
|
||||
widgets = {
|
||||
'groups': forms.SelectMultiple(
|
||||
attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select asset groups')}),
|
||||
'admin_user': forms.Select(
|
||||
attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select asset admin user')}),
|
||||
'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Select asset groups')}),
|
||||
}
|
||||
|
||||
def save(self, commit=True):
|
||||
|
@ -140,40 +147,19 @@ class AssetGroupForm(forms.ModelForm):
|
|||
|
||||
|
||||
class ClusterForm(forms.ModelForm):
|
||||
# See AdminUserForm comment same it
|
||||
assets = forms.ModelMultipleChoiceField(
|
||||
queryset=Asset.objects.all(),
|
||||
label=_('Asset'),
|
||||
required=False,
|
||||
widget=forms.SelectMultiple(
|
||||
attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if kwargs.get('instance'):
|
||||
initial = kwargs.get('initial', {})
|
||||
initial['assets'] = kwargs['instance'].assets.all()
|
||||
super(ClusterForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def _save_m2m(self):
|
||||
super(ClusterForm, self)._save_m2m()
|
||||
assets = self.cleaned_data['assets']
|
||||
self.instance.assets.clear()
|
||||
self.instance.assets.add(*tuple(assets))
|
||||
|
||||
class Meta:
|
||||
model = Cluster
|
||||
fields = ['name', "bandwidth", "operator", 'contact',
|
||||
fields = ['name', "bandwidth", "operator", 'contact', 'admin_user',
|
||||
'phone', 'address', 'intranet', 'extranet', 'comment']
|
||||
widgets = {
|
||||
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
|
||||
'intranet': forms.Textarea(
|
||||
attrs={'placeholder': 'IP段之间用逗号隔开,如:192.168.1.0/24,192.168.1.0/24'}),
|
||||
'extranet': forms.Textarea(
|
||||
attrs={'placeholder': 'IP段之间用逗号隔开,如:201.1.32.1/24,202.2.32.1/24'})
|
||||
'intranet': forms.Textarea(attrs={'placeholder': 'IP段之间用逗号隔开,如:192.168.1.0/24,192.168.1.0/24'}),
|
||||
'extranet': forms.Textarea(attrs={'placeholder': 'IP段之间用逗号隔开,如:201.1.32.1/24,202.2.32.1/24'})
|
||||
}
|
||||
help_texts = {
|
||||
'name': '* required'
|
||||
'name': '* required',
|
||||
'admin_user': 'The assets of this cluster will use this admin user as his admin user',
|
||||
}
|
||||
|
||||
|
||||
|
@ -237,8 +223,7 @@ class SystemUserForm(forms.ModelForm):
|
|||
# Admin user assets define, let user select, save it in form not in view
|
||||
auto_generate_key = forms.BooleanField(initial=True, required=False)
|
||||
# Form field name can not start with `_`, so redefine it,
|
||||
password = forms.CharField(widget=forms.PasswordInput, required=False,
|
||||
max_length=100, strip=True)
|
||||
password = forms.CharField(widget=forms.PasswordInput, required=False, max_length=100, strip=True)
|
||||
# Need use upload private key file except paste private key content
|
||||
private_key_file = forms.FileField(required=False)
|
||||
|
||||
|
@ -289,15 +274,19 @@ class SystemUserForm(forms.ModelForm):
|
|||
fields = [
|
||||
'name', 'username', 'protocol', 'auto_generate_key', 'password',
|
||||
'private_key_file', 'auth_method', 'auto_push', 'sudo',
|
||||
'comment', 'shell'
|
||||
'comment', 'shell', 'cluster'
|
||||
]
|
||||
widgets = {
|
||||
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
|
||||
'username': forms.TextInput(attrs={'placeholder': _('Username')}),
|
||||
'cluster': forms.SelectMultiple(
|
||||
attrs={'class': 'select2',
|
||||
'data-placeholder': _(' Select clusters')}),
|
||||
}
|
||||
help_texts = {
|
||||
'name': '* required',
|
||||
'username': '* required',
|
||||
'cluster': 'If auto push checked, then push system user to that cluster assets',
|
||||
'auto_push': 'Auto push system user to asset',
|
||||
}
|
||||
|
||||
|
@ -306,8 +295,7 @@ class SystemUserUpdateForm(forms.ModelForm):
|
|||
# Admin user assets define, let user select, save it in form not in view
|
||||
auto_generate_key = forms.BooleanField(initial=False, required=False)
|
||||
# Form field name can not start with `_`, so redefine it,
|
||||
password = forms.CharField(widget=forms.PasswordInput, required=False,
|
||||
max_length=100, strip=True)
|
||||
password = forms.CharField(widget=forms.PasswordInput, required=False, max_length=100, strip=True)
|
||||
# Need use upload private key file except paste private key content
|
||||
private_key_file = forms.FileField(required=False)
|
||||
|
||||
|
@ -341,17 +329,21 @@ class SystemUserUpdateForm(forms.ModelForm):
|
|||
class Meta:
|
||||
model = SystemUser
|
||||
fields = [
|
||||
'name', 'username', 'protocol', 'auto_generate_key', 'password',
|
||||
'private_key_file', 'auth_method', 'auto_push', 'sudo',
|
||||
'comment', 'shell'
|
||||
'name', 'username', 'protocol',
|
||||
'auth_method', 'auto_push', 'sudo',
|
||||
'comment', 'shell', 'cluster'
|
||||
]
|
||||
widgets = {
|
||||
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
|
||||
'username': forms.TextInput(attrs={'placeholder': _('Username')}),
|
||||
'cluster': forms.SelectMultiple(
|
||||
attrs={'class': 'select2',
|
||||
'data-placeholder': _(' Select clusters')}),
|
||||
}
|
||||
help_texts = {
|
||||
'name': '* required',
|
||||
'username': '* required',
|
||||
'cluster': 'If auto push checked, then push system user to that cluster assets',
|
||||
'auto_push': 'Auto push system user to asset',
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,17 @@
|
|||
#
|
||||
|
||||
import uuid
|
||||
import os
|
||||
import logging
|
||||
from hashlib import md5
|
||||
|
||||
from django.db import models
|
||||
import logging
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.cache import cache
|
||||
|
||||
from common.utils import signer, ssh_key_string_to_obj
|
||||
from .utils import private_key_validator
|
||||
from .cluster import Cluster
|
||||
from .group import AssetGroup
|
||||
from .user import AdminUser, SystemUser
|
||||
|
@ -47,14 +52,17 @@ class Asset(models.Model):
|
|||
hostname = models.CharField(max_length=128, unique=True, verbose_name=_('Hostname'))
|
||||
port = models.IntegerField(default=22, verbose_name=_('Port'))
|
||||
groups = models.ManyToManyField(AssetGroup, blank=True, related_name='assets', verbose_name=_('Asset groups'))
|
||||
admin_user = models.ForeignKey(AdminUser, null=True, blank=True, related_name='assets', on_delete=models.SET_NULL, verbose_name=_("Admin user"))
|
||||
system_users = models.ManyToManyField(SystemUser, blank=True, related_name='assets', verbose_name=_("System User"))
|
||||
cluster = models.ForeignKey(Cluster, blank=True, null=True, related_name='assets', on_delete=models.SET_NULL, verbose_name=_('Cluster'),)
|
||||
is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
|
||||
type = models.CharField(choices=TYPE_CHOICES, max_length=16, blank=True, null=True, default='Server', verbose_name=_('Asset type'),)
|
||||
env = models.CharField(choices=ENV_CHOICES, max_length=8, blank=True, null=True, default='Prod', verbose_name=_('Asset environment'),)
|
||||
status = models.CharField(choices=STATUS_CHOICES, max_length=12, null=True, blank=True, default='In use', verbose_name=_('Asset status'))
|
||||
|
||||
# Auth
|
||||
username = models.CharField(max_length=16, blank=True, null=True, verbose_name=_('Username'))
|
||||
_password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
|
||||
_private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ])
|
||||
|
||||
# Some information
|
||||
public_ip = models.GenericIPAddressField(max_length=32, blank=True, null=True, verbose_name=_('Public IP'))
|
||||
remote_card_ip = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('Remote control card IP'))
|
||||
|
@ -96,6 +104,41 @@ class Asset(models.Model):
|
|||
return True, ''
|
||||
return False, warning
|
||||
|
||||
@property
|
||||
def password(self):
|
||||
if self._password:
|
||||
return signer.unsign(self._password)
|
||||
else:
|
||||
return ''
|
||||
|
||||
@password.setter
|
||||
def password(self, password_raw):
|
||||
self._password = signer.sign(password_raw)
|
||||
|
||||
@property
|
||||
def private_key(self):
|
||||
if self._private_key:
|
||||
key_str = signer.unsign(self._private_key)
|
||||
return ssh_key_string_to_obj(key_str)
|
||||
else:
|
||||
return None
|
||||
|
||||
@private_key.setter
|
||||
def private_key(self, private_key_raw):
|
||||
self._private_key = signer.sign(private_key_raw)
|
||||
|
||||
@property
|
||||
def private_key_file(self):
|
||||
if not self.private_key:
|
||||
return None
|
||||
project_dir = settings.PROJECT_DIR
|
||||
tmp_dir = os.path.join(project_dir, 'tmp')
|
||||
key_name = md5(self._private_key.encode()).hexdigest()
|
||||
key_path = os.path.join(tmp_dir, key_name)
|
||||
if not os.path.exists(key_path):
|
||||
self.private_key.write_private_key_file(key_path)
|
||||
return key_path
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
|
@ -115,15 +158,15 @@ class Asset(models.Model):
|
|||
Todo: May be move to ops implements it
|
||||
"""
|
||||
data = self.to_json()
|
||||
if self.admin_user:
|
||||
if self.cluster and self.cluster.admin_user:
|
||||
data.update({
|
||||
'username': self.admin_user.username,
|
||||
'password': self.admin_user.password,
|
||||
'private_key': self.admin_user.private_key_file,
|
||||
'username': self.cluster.admin_user.username,
|
||||
'password': self.cluster.admin_user.password,
|
||||
'private_key': self.cluster.admin_user.private_key_file,
|
||||
'become': {
|
||||
'method': self.admin_user.become_method,
|
||||
'user': self.admin_user.become_user,
|
||||
'pass': self.admin_user.become_pass,
|
||||
'method': self.cluster.admin_user.become_method,
|
||||
'user': self.cluster.admin_user.become_user,
|
||||
'pass': self.cluster.admin_user.become_pass,
|
||||
}
|
||||
})
|
||||
return data
|
||||
|
|
|
@ -18,6 +18,7 @@ logger = logging.getLogger(__name__)
|
|||
class Cluster(models.Model):
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
name = models.CharField(max_length=32, verbose_name=_('Name'))
|
||||
admin_user = models.ForeignKey('assets.AdminUser', on_delete=models.CASCADE, verbose_name=_("Admin user"))
|
||||
bandwidth = models.CharField(max_length=32, blank=True, verbose_name=_('Bandwidth'))
|
||||
contact = models.CharField(max_length=128, blank=True, verbose_name=_('Contact'))
|
||||
phone = models.CharField(max_length=32, blank=True, verbose_name=_('Phone'))
|
||||
|
|
|
@ -23,9 +23,8 @@ class AssetGroup(models.Model):
|
|||
date_created = models.DateTimeField(auto_now_add=True, null=True, verbose_name=_('Date created'))
|
||||
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
||||
|
||||
def __unicode__(self):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
__str__ = __unicode__
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
|
|
|
@ -8,25 +8,18 @@ import logging
|
|||
import uuid
|
||||
from hashlib import md5
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.conf import settings
|
||||
|
||||
from common.utils import signer, validate_ssh_private_key, ssh_key_string_to_obj
|
||||
from common.utils import signer, ssh_key_string_to_obj
|
||||
from .utils import private_key_validator
|
||||
|
||||
__all__ = ['AdminUser', 'SystemUser', 'private_key_validator']
|
||||
|
||||
__all__ = ['AdminUser', 'SystemUser',]
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def private_key_validator(value):
|
||||
if not validate_ssh_private_key(value):
|
||||
raise ValidationError(
|
||||
_('%(value)s is not an even number'),
|
||||
params={'value': value},
|
||||
)
|
||||
|
||||
|
||||
class AdminUser(models.Model):
|
||||
"""
|
||||
A privileged user that ansible can use it to push system user and so on
|
||||
|
@ -103,10 +96,12 @@ class AdminUser(models.Model):
|
|||
def become_pass(self, password):
|
||||
self._become_pass = signer.sign(password)
|
||||
|
||||
|
||||
@property
|
||||
def assets_amount(self):
|
||||
return self.assets.count()
|
||||
amount = 0
|
||||
for cluster in self.cluster_set.all():
|
||||
amount += cluster.assets.all().count()
|
||||
return amount
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
|
@ -143,6 +138,7 @@ class SystemUser(models.Model):
|
|||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
|
||||
username = models.CharField(max_length=16, verbose_name=_('Username'))
|
||||
cluster = models.ManyToManyField('assets.Cluster', verbose_name=_("Cluster"))
|
||||
_password = models.CharField(max_length=256, blank=True, verbose_name=_('Password'))
|
||||
protocol = models.CharField(max_length=16, choices=PROTOCOL_CHOICES, default='ssh', verbose_name=_('Protocol'))
|
||||
_private_key = models.TextField(max_length=8192, blank=True, verbose_name=_('SSH private key'))
|
||||
|
|
|
@ -2,22 +2,34 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
from . import Cluster, SystemUser, AdminUser, AssetGroup, Asset
|
||||
from django.core.exceptions import ValidationError
|
||||
from common.utils import validate_ssh_private_key
|
||||
|
||||
|
||||
__all__ = ['init_model', 'generate_fake']
|
||||
|
||||
|
||||
def init_model():
|
||||
from . import Cluster, SystemUser, AdminUser, AssetGroup, Asset
|
||||
for cls in [Cluster, SystemUser, AdminUser, AssetGroup, Asset]:
|
||||
if hasattr(cls, 'initial'):
|
||||
cls.initial()
|
||||
|
||||
|
||||
def generate_fake():
|
||||
from . import Cluster, SystemUser, AdminUser, AssetGroup, Asset
|
||||
for cls in [Cluster, SystemUser, AdminUser, AssetGroup, Asset]:
|
||||
if hasattr(cls, 'generate_fake'):
|
||||
cls.generate_fake()
|
||||
|
||||
|
||||
def private_key_validator(value):
|
||||
if not validate_ssh_private_key(value):
|
||||
raise ValidationError(
|
||||
_('%(value)s is not an even number'),
|
||||
params={'value': value},
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pass
|
||||
|
|
|
@ -63,7 +63,7 @@ class ClusterUpdateAssetsSerializer(serializers.ModelSerializer):
|
|||
|
||||
|
||||
class AdminUserSerializer(serializers.ModelSerializer):
|
||||
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
|
||||
assets_amount = serializers.SerializerMethodField()
|
||||
unreachable_amount = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
|
@ -78,14 +78,18 @@ class AdminUserSerializer(serializers.ModelSerializer):
|
|||
else:
|
||||
return 'Unknown'
|
||||
|
||||
def get_field_names(self, declared_fields, info):
|
||||
fields = super(AdminUserSerializer, self).get_field_names(declared_fields, info)
|
||||
fields.append('assets_amount')
|
||||
return fields
|
||||
@staticmethod
|
||||
def get_assets_amount(obj):
|
||||
amount = 0
|
||||
clusters = obj.cluster_set.all()
|
||||
for cluster in clusters:
|
||||
amount += len(cluster.assets.all())
|
||||
return amount
|
||||
|
||||
|
||||
class SystemUserSerializer(serializers.ModelSerializer):
|
||||
unreachable_amount = serializers.SerializerMethodField()
|
||||
assets_amount = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = SystemUser
|
||||
|
@ -99,10 +103,12 @@ class SystemUserSerializer(serializers.ModelSerializer):
|
|||
else:
|
||||
return "Unknown"
|
||||
|
||||
def get_field_names(self, declared_fields, info):
|
||||
fields = super(SystemUserSerializer, self).get_field_names(declared_fields, info)
|
||||
fields.extend(['assets_amount'])
|
||||
return fields
|
||||
@staticmethod
|
||||
def get_assets_amount(obj):
|
||||
amount = 0
|
||||
for cluster in obj.cluster.all():
|
||||
amount += cluster.assets.all().count()
|
||||
return amount
|
||||
|
||||
|
||||
class AssetSystemUserSerializer(serializers.ModelSerializer):
|
||||
|
@ -200,6 +206,7 @@ class MyAssetGrantedSerializer(AssetGrantedSerializer):
|
|||
|
||||
class ClusterSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
||||
assets_amount = serializers.SerializerMethodField()
|
||||
admin_user_name = serializers.SerializerMethodField()
|
||||
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
|
||||
|
||||
class Meta:
|
||||
|
@ -210,10 +217,9 @@ class ClusterSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
|||
def get_assets_amount(obj):
|
||||
return obj.assets.count()
|
||||
|
||||
def get_field_names(self, declared_fields, info):
|
||||
fields = super(ClusterSerializer, self).get_field_names(declared_fields, info)
|
||||
fields.append('assets_amount')
|
||||
return fields
|
||||
@staticmethod
|
||||
def get_admin_user_name(obj):
|
||||
return obj.admin_user.name
|
||||
|
||||
|
||||
class AssetGroupGrantedSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
{% bootstrap_field form.name layout="horizontal" %}
|
||||
{% bootstrap_field form.username layout="horizontal" %}
|
||||
{% bootstrap_field form.protocol layout="horizontal" %}
|
||||
{% bootstrap_field form.cluster layout="horizontal" %}
|
||||
<h3>{% trans 'Auth' %}</h3>
|
||||
{% bootstrap_field form.auth_method layout="horizontal" %}
|
||||
{% block auth %}
|
||||
|
|
|
@ -50,37 +50,22 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<table class="table table-hover" id="system_user_liste">
|
||||
<table class="table table-striped table-bordered table-hover" id="asset_list_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">
|
||||
<input type="checkbox" id="check_all" class="ipt_check_all" >
|
||||
</th>
|
||||
<th>{% trans 'Hostname' %}</th>
|
||||
<th>{% trans 'IP' %}</th>
|
||||
<th>{% trans 'Port' %}</th>
|
||||
<th>{% trans 'Alive' %}</th>
|
||||
<th>{% trans 'Type' %}</th>
|
||||
<th>{% trans 'Valid' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for asset in page_obj %}
|
||||
<tr>
|
||||
<td>{{ asset.hostname }}</td>
|
||||
<td>{{ asset.ip }}</td>
|
||||
<td>{{ asset.port }}</td>
|
||||
{% if asset.is_connective == '1' %}
|
||||
<td>
|
||||
<i class="fa fa-check text-navy"></i>
|
||||
</td>
|
||||
{% else %}
|
||||
<td>
|
||||
<i class="fa fa-times text-danger"></i>
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row">
|
||||
{% include '_pagination.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -104,69 +89,12 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Replace asset admin user with this' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<form>
|
||||
<tr class="no-borders-tr">
|
||||
<td colspan="2">
|
||||
<select data-placeholder="{% trans 'Select asset' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
|
||||
{% for asset in assets_remain %}
|
||||
<option value="{{ asset.id }}">{{ asset.ip }}:{{ asset.port }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="no-borders-tr">
|
||||
<td colspan="2">
|
||||
<button type="button" class="btn btn-info btn-sm btn-replace-asset-admin_user">{% trans 'Replace' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-warning">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Replace asset group admin user with this' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<form>
|
||||
<tr class="no-borders-tr">
|
||||
<td colspan="2">
|
||||
<select data-placeholder="{% trans 'Select asset groups' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
|
||||
{% for asset_group in asset_groups %}
|
||||
<option value="{{ asset_group.id }}">{{ asset_group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="no-borders-tr">
|
||||
<td colspan="2">
|
||||
<button type="button" class="btn btn-warning btn-sm btn-replace-asset_groups-admin_user">{% trans 'Replace' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
|
@ -220,6 +148,64 @@ function objectRemove(obj, name, url, data) {
|
|||
}
|
||||
jumpserver.assets_selected = {};
|
||||
jumpserver.asset_groups_selected = {};
|
||||
|
||||
function initTable() {
|
||||
var options = {
|
||||
ele: $('#asset_list_table'),
|
||||
buttons: [],
|
||||
order: [],
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a href="{% url "assets:asset-detail" pk=99991937 %}" data-aid="'+rowData.id+'">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('99991937', rowData.id));
|
||||
}},
|
||||
{targets: 5, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}}],
|
||||
ajax_url: '{% url "api-assets:asset-list" %}?admin_user_id={{ admin_user.id }}',
|
||||
columns: [{data: function(){return ""}}, {data: "hostname" }, {data: "ip" }, {data: "port" },
|
||||
{data: "type" }, {data: "is_active" }],
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
}
|
||||
|
||||
function adminUserDelete(name, url) {
|
||||
function doDelete() {
|
||||
var body = {};
|
||||
var success = function() {
|
||||
swal('Deleted!', "[ "+name+"]"+" has been deleted ", "success");
|
||||
window.location.href="{% url 'assets:cluster-list' %}";
|
||||
};
|
||||
var fail = function() {
|
||||
swal("Failed", "Delete"+"[ "+name+" ]"+"failed", "error");
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: url,
|
||||
body: JSON.stringify(body),
|
||||
method: 'DELETE',
|
||||
success: success,
|
||||
error: fail
|
||||
});
|
||||
}
|
||||
swal({
|
||||
title: 'Are you sure delete ?',
|
||||
text: " [" + name + "] ",
|
||||
type: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonText: 'Cancel',
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: 'Confirm',
|
||||
closeOnConfirm: false
|
||||
}, function () {
|
||||
doDelete()
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2()
|
||||
.on("select2:select", function (evt) {
|
||||
|
@ -232,150 +218,9 @@ $(document).ready(function () {
|
|||
delete jumpserver.assets_selected[data.id];
|
||||
delete jumpserver.asset_groups_selected[data.id]
|
||||
});
|
||||
var options = {
|
||||
ele: $('#system_user_assets_table'),
|
||||
buttons: [],
|
||||
order: [],
|
||||
columnDefs: [
|
||||
{targets: 0, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a href="{% url "assets:asset-detail" pk=99991937 %}" data-aid="'+rowData.id+'">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('99991937', rowData.id));
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData, rowData) {
|
||||
var update_btn = '<a href="{% url "assets:asset-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('99991937', rowData.id);
|
||||
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_asset_remove" data-aid="99991937">{% trans "Remove" %}</a>'.replace('99991937', rowData.id);
|
||||
$(td).html(update_btn + del_btn)
|
||||
}}
|
||||
|
||||
],
|
||||
ajax_url: '{% url "api-assets:asset-list" %}?admin_user_id={{ admin_user.id }}',
|
||||
columns: [{data: "hostname" }, {data: "ip" }, {data: "port" },
|
||||
{data: "is_active" }, {data: "id"}],
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
|
||||
function adminUserDelete(name, url) {
|
||||
function doDelete() {
|
||||
var body = {};
|
||||
var success = function() {
|
||||
swal('Deleted!', "[ "+name+"]"+" has been deleted ", "success");
|
||||
window.location.href="{% url 'assets:cluster-list' %}";
|
||||
};
|
||||
var fail = function() {
|
||||
swal("Failed", "Delete"+"[ "+name+" ]"+"failed", "error");
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: url,
|
||||
body: JSON.stringify(body),
|
||||
method: 'DELETE',
|
||||
success: success,
|
||||
error: fail
|
||||
});
|
||||
}
|
||||
swal({
|
||||
title: 'Are you sure delete ?',
|
||||
text: " [" + name + "] ",
|
||||
type: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonText: 'Cancel',
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: 'Confirm',
|
||||
closeOnConfirm: false
|
||||
}, function () {
|
||||
doDelete()
|
||||
});
|
||||
}
|
||||
initTable();
|
||||
})
|
||||
|
||||
.on('click', '.btn-replace-asset-admin_user', function () {
|
||||
if (Object.keys(jumpserver.assets_selected).length === 0) {
|
||||
return false;
|
||||
}
|
||||
jumpserver.asset_groups_selected = {};
|
||||
var $data_table = $("#system_user_assets_table").DataTable();
|
||||
var assets = [];
|
||||
$.map(jumpserver.assets_selected, function(value, index) {
|
||||
assets.push(parseInt(index));
|
||||
});
|
||||
assets.unique();
|
||||
var data = [];
|
||||
var admin_user_id = "{{ admin_user.id }}";
|
||||
var the_url = '{% url "api-assets:asset-list" %}';
|
||||
for (var i=0; i<assets.length; i++) {
|
||||
data.push({"id": assets[i], "admin_user": admin_user_id});
|
||||
}
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
body: JSON.stringify(data),
|
||||
method: 'PATCH'
|
||||
});
|
||||
$data_table.ajax.reload();
|
||||
})
|
||||
|
||||
.on('click', '.btn-replace-asset_groups-admin_user', function () {
|
||||
if (Object.keys(jumpserver.asset_groups_selected).length === 0) {
|
||||
return false;
|
||||
}
|
||||
jumpserver.assets_selected = {};
|
||||
var $data_table = $("#system_user_assets_table").DataTable();
|
||||
var asset_groups = [];
|
||||
var assets = [];
|
||||
var data = [];
|
||||
var the_url = '{% url "api-assets:asset-list" %}';
|
||||
$.map(jumpserver.asset_groups_selected, function(value, index) {
|
||||
asset_groups.push(parseInt(index));
|
||||
});
|
||||
$.ajax({
|
||||
url: '{% url "api-assets:asset-group-list" %}?id__in=['+asset_groups.join(',')+']',
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
success: function (result) {
|
||||
for (var i=0; i<result.length; i++) {
|
||||
for (var j=0; j<result[i]['assets'].length; j++) {
|
||||
assets.push(result[i]['assets'][j])
|
||||
}
|
||||
}
|
||||
for (var z=0; z<assets.length; z++) {
|
||||
data.push({"id":assets[z], "admin_user":"{{admin_user.id}}" });
|
||||
}
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
body: JSON.stringify(data),
|
||||
method: 'PATCH'
|
||||
});
|
||||
$data_table.ajax.reload();
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
.on('click', '.btn_asset_remove', function () {
|
||||
var $this = $(this);
|
||||
var the_url = "{% url 'api-assets:admin-user-detail' pk=admin_user.id %}";
|
||||
var name = $(this).closest("tr").find(":nth-child(1) > a").html();
|
||||
var assets = [];
|
||||
var delete_asset_id = $(this).data('aid');
|
||||
$.ajax({
|
||||
url: the_url,
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
success: function (result) {
|
||||
for (var i=0; i<result['assets'].length; i++) {
|
||||
assets.push(result['assets'][i])
|
||||
}
|
||||
assets.remove(delete_asset_id);
|
||||
var data = {"assets": assets};
|
||||
objectRemove($this, name, the_url, data);
|
||||
}
|
||||
})
|
||||
}).on('click', '.btn-delete-admin-user', function () {
|
||||
.on('click', '.btn-delete-admin-user', function () {
|
||||
var $this = $(this);
|
||||
var name = "{{ admin_user.name }}";
|
||||
var uid = "{{ admin_user.id }}";
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="col-sm-7" style="padding-left: 0;">
|
||||
<div class="col-sm-8" style="padding-left: 0;">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label"><b>{{ admin_user.name }}</b></span>
|
||||
|
@ -77,7 +77,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
|
||||
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Quick update' %}
|
||||
|
@ -86,15 +86,7 @@
|
|||
<table class="table">
|
||||
<tbody>
|
||||
<tr class="no-borders-tr">
|
||||
<td width="50%">{% trans 'Reset private key' %}:</td>
|
||||
<td>
|
||||
<span style="float: right">
|
||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Reset' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%">{% trans 'Reset password' %}:</td>
|
||||
<td width="50%">{% trans 'Reset auth' %}:</td>
|
||||
<td>
|
||||
<span style="float: right">
|
||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Reset' %}</button>
|
||||
|
@ -164,164 +156,44 @@ function objectRemove(obj, name, url, data) {
|
|||
doRemove()
|
||||
});
|
||||
}
|
||||
|
||||
function adminUserDelete(name, url) {
|
||||
function doDelete() {
|
||||
var body = {};
|
||||
var success = function() {
|
||||
swal('Deleted!', "[ "+name+"]"+" has been deleted ", "success");
|
||||
window.location.href="{% url 'assets:cluster-list' %}";
|
||||
};
|
||||
var fail = function() {
|
||||
swal("Failed", "Delete"+"[ "+name+" ]"+"failed", "error");
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: url,
|
||||
body: JSON.stringify(body),
|
||||
method: 'DELETE',
|
||||
success: success,
|
||||
error: fail
|
||||
});
|
||||
}
|
||||
swal({
|
||||
title: 'Are you sure delete ?',
|
||||
text: " [" + name + "] ",
|
||||
type: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonText: 'Cancel',
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: 'Confirm',
|
||||
closeOnConfirm: false
|
||||
}, function () {
|
||||
doDelete()
|
||||
});
|
||||
}
|
||||
|
||||
jumpserver.assets_selected = {};
|
||||
jumpserver.asset_groups_selected = {};
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2()
|
||||
.on("select2:select", function (evt) {
|
||||
var data = evt.params.data;
|
||||
jumpserver.assets_selected[data.id] = data.text;
|
||||
jumpserver.asset_groups_selected[data.id] = data.text;
|
||||
})
|
||||
.on('select2:unselect', function(evt) {
|
||||
var data = evt.params.data;
|
||||
delete jumpserver.assets_selected[data.id];
|
||||
delete jumpserver.asset_groups_selected[data.id]
|
||||
});
|
||||
var options = {
|
||||
ele: $('#system_user_assets_table'),
|
||||
buttons: [],
|
||||
order: [],
|
||||
columnDefs: [
|
||||
{targets: 0, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a href="{% url "assets:asset-detail" pk=99991937 %}" data-aid="'+rowData.id+'">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('99991937', rowData.id));
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData, rowData) {
|
||||
var update_btn = '<a href="{% url "assets:asset-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('99991937', rowData.id);
|
||||
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_asset_remove" data-aid="99991937">{% trans "Remove" %}</a>'.replace('99991937', rowData.id);
|
||||
$(td).html(update_btn + del_btn)
|
||||
}}
|
||||
|
||||
],
|
||||
ajax_url: '{% url "api-assets:asset-list" %}?admin_user_id={{ admin_user.id }}',
|
||||
columns: [{data: "hostname" }, {data: "ip" }, {data: "port" },
|
||||
{data: "is_active" }, {data: "id"}],
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
|
||||
function adminUserDelete(name, url) {
|
||||
function doDelete() {
|
||||
var body = {};
|
||||
var success = function() {
|
||||
swal('Deleted!', "[ "+name+"]"+" has been deleted ", "success");
|
||||
window.location.href="{% url 'assets:cluster-list' %}";
|
||||
};
|
||||
var fail = function() {
|
||||
swal("Failed", "Delete"+"[ "+name+" ]"+"failed", "error");
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: url,
|
||||
body: JSON.stringify(body),
|
||||
method: 'DELETE',
|
||||
success: success,
|
||||
error: fail
|
||||
});
|
||||
}
|
||||
swal({
|
||||
title: 'Are you sure delete ?',
|
||||
text: " [" + name + "] ",
|
||||
type: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonText: 'Cancel',
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: 'Confirm',
|
||||
closeOnConfirm: false
|
||||
}, function () {
|
||||
doDelete()
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
.on('click', '.btn-replace-asset-admin_user', function () {
|
||||
if (Object.keys(jumpserver.assets_selected).length === 0) {
|
||||
return false;
|
||||
}
|
||||
jumpserver.asset_groups_selected = {};
|
||||
var $data_table = $("#system_user_assets_table").DataTable();
|
||||
var assets = [];
|
||||
$.map(jumpserver.assets_selected, function(value, index) {
|
||||
assets.push(parseInt(index));
|
||||
});
|
||||
assets.unique();
|
||||
var data = [];
|
||||
var admin_user_id = "{{ admin_user.id }}";
|
||||
var the_url = '{% url "api-assets:asset-list" %}';
|
||||
for (var i=0; i<assets.length; i++) {
|
||||
data.push({"id": assets[i], "admin_user": admin_user_id});
|
||||
}
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
body: JSON.stringify(data),
|
||||
method: 'PATCH'
|
||||
});
|
||||
$data_table.ajax.reload();
|
||||
})
|
||||
|
||||
.on('click', '.btn-replace-asset_groups-admin_user', function () {
|
||||
if (Object.keys(jumpserver.asset_groups_selected).length === 0) {
|
||||
return false;
|
||||
}
|
||||
jumpserver.assets_selected = {};
|
||||
var $data_table = $("#system_user_assets_table").DataTable();
|
||||
var asset_groups = [];
|
||||
var assets = [];
|
||||
var data = [];
|
||||
var the_url = '{% url "api-assets:asset-list" %}';
|
||||
$.map(jumpserver.asset_groups_selected, function(value, index) {
|
||||
asset_groups.push(parseInt(index));
|
||||
});
|
||||
$.ajax({
|
||||
url: '{% url "api-assets:asset-group-list" %}?id__in=['+asset_groups.join(',')+']',
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
success: function (result) {
|
||||
for (var i=0; i<result.length; i++) {
|
||||
for (var j=0; j<result[i]['assets'].length; j++) {
|
||||
assets.push(result[i]['assets'][j])
|
||||
}
|
||||
}
|
||||
for (var z=0; z<assets.length; z++) {
|
||||
data.push({"id":assets[z], "admin_user":{{admin_user.id}} });
|
||||
}
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
body: JSON.stringify(data),
|
||||
method: 'PATCH'
|
||||
});
|
||||
$data_table.ajax.reload();
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
.on('click', '.btn_asset_remove', function () {
|
||||
var $this = $(this);
|
||||
var the_url = "{% url 'api-assets:admin-user-detail' pk=admin_user.id %}";
|
||||
var name = $(this).closest("tr").find(":nth-child(1) > a").html();
|
||||
var assets = [];
|
||||
var delete_asset_id = $(this).data('aid');
|
||||
$.ajax({
|
||||
url: the_url,
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
success: function (result) {
|
||||
for (var i=0; i<result['assets'].length; i++) {
|
||||
assets.push(result['assets'][i])
|
||||
}
|
||||
assets.remove(delete_asset_id);
|
||||
var data = {"assets": assets};
|
||||
objectRemove($this, name, the_url, data);
|
||||
}
|
||||
})
|
||||
}).on('click', '.btn-delete-admin-user', function () {
|
||||
.on('click', '.btn-delete-admin-user', function () {
|
||||
var $this = $(this);
|
||||
var name = "{{ admin_user.name }}";
|
||||
var uid = "{{ admin_user.id }}";
|
||||
|
|
|
@ -2,8 +2,15 @@
|
|||
{% load i18n static %}
|
||||
{% block table_search %}
|
||||
{% endblock %}
|
||||
|
||||
{% block help_message %}
|
||||
<div class="alert alert-info help-message">
|
||||
管理用户是 服务器上已存在的特权用户,Jumpserver使用该用户来 `推送系统用户`、`获取资产硬件信息`等
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block table_container %}
|
||||
<div class="uc pull-left m-l-5 m-r-5">
|
||||
<div class="uc pull-left m-r-5">
|
||||
<a href="{% url "assets:admin-user-create" %}" class="btn btn-sm btn-primary"> {% trans "Create admin user" %} </a>
|
||||
</div>
|
||||
<table class="table table-striped table-bordered table-hover " id="admin_user_list_table" >
|
||||
|
|
|
@ -20,13 +20,15 @@
|
|||
{% bootstrap_field form.env layout="horizontal" %}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Group' %}</h3>
|
||||
{% bootstrap_field form.cluster layout="horizontal" %}
|
||||
{% bootstrap_field form.groups layout="horizontal" %}
|
||||
<h3>{% trans 'Auth' %}</h3>
|
||||
{% bootstrap_field form.username layout="horizontal" %}
|
||||
{% bootstrap_field form.password layout="horizontal" %}
|
||||
{% bootstrap_field form.private_key_file layout="horizontal" %}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Asset user' %}</h3>
|
||||
{% bootstrap_field form.admin_user layout="horizontal" %}
|
||||
<h3>{% trans 'Cluster and group' %}</h3>
|
||||
{% bootstrap_field form.cluster layout="horizontal" %}
|
||||
{% bootstrap_field form.groups layout="horizontal" %}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Other' %}</h3>
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
<li class="active">
|
||||
<a href="{% url 'assets:asset-detail' pk=asset.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Asset detail' %} </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'assets:asset-detail' pk=asset.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Auth' %} </a>
|
||||
</li>
|
||||
{% if user.is_superuser %}
|
||||
<li class="pull-right">
|
||||
<a class="btn btn-outline btn-default" href="{% url 'assets:asset-update' pk=asset.id %}"><i class="fa fa-edit"></i>Update</a>
|
||||
|
@ -173,17 +176,19 @@
|
|||
<tbody>
|
||||
<tr class="no-borders-tr">
|
||||
<td width="50%">{% trans 'Active' %}:</td>
|
||||
<td><span class="pull-right">
|
||||
<div class="switch">
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" {% if asset.is_active %} checked {% endif %} class="onoffswitch-checkbox" id="is_active">
|
||||
<label class="onoffswitch-label" for="is_active">
|
||||
<span class="onoffswitch-inner"></span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</span></td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<div class="switch">
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" {% if asset.is_active %} checked {% endif %} class="onoffswitch-checkbox" id="is_active">
|
||||
<label class="onoffswitch-label" for="is_active">
|
||||
<span class="onoffswitch-inner"></span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Refresh hardware' %}:</td>
|
||||
|
@ -194,10 +199,10 @@
|
|||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Test admin user' %}:</td>
|
||||
<td>{% trans 'Reset auth' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_test_admin_user" style="width: 54px;">{% trans 'Test' %}</button>
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_test_admin_user" style="width: 54px;">{% trans 'Reset' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -242,41 +247,6 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-warning">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Push system users' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table group_edit" id="add-asset2systemuser">
|
||||
<tbody>
|
||||
<form>
|
||||
<tr class="no-borders-tr">
|
||||
<td colspan="2">
|
||||
<select data-placeholder="{% trans 'Select system users' %}" class="select2 system-user" style="width: 100%" multiple="" tabindex="4">
|
||||
{% for system_user in system_users_all %}
|
||||
<option value="{{ system_user.id }}" id="opt_{{ system_user.id }}">{{ system_user.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="no-borders-tr">
|
||||
<td colspan="2">
|
||||
<button type="button" class="btn btn-warning btn-sm btn-system-user">{% trans 'Confirm' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
{% for system_user in system_users %}
|
||||
<tr>
|
||||
<td ><b class="bdg_group" data-sid={{ system_user.id }}>{{ system_user.name }}</b></td>
|
||||
<td>
|
||||
<button class="btn btn-danger btn-xs pull-right btn_leave_system" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -30,36 +30,34 @@
|
|||
<div class="panel blank-panel">
|
||||
<div class="panel-body">
|
||||
<div class="tab-content">
|
||||
<div id="tab-1" class="ibox float-e-margins tab-pane active"></div>
|
||||
<form id="groupForm" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
<h3 class="widget-head-color-box">资产组信息</h3>
|
||||
{% bootstrap_field form.name layout="horizontal" %}
|
||||
{% bootstrap_field form.comment layout="horizontal" %}
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3 class="widget-head-color-box">用户选择的资产</h3>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" id="asset_on_count">已选({{ assets_count }})</label>
|
||||
<div class="col-sm-9" id="asset_sed">
|
||||
<div class="form-asset-on" id="add_asset">
|
||||
<p id="asset_on_p">
|
||||
{% for asset in assets_on_list %}
|
||||
<button name='asset_hostname' title='{{ asset.ip }}' type='button' class='btn btn-default btn-xs'>{{ asset.hostname }}</button>
|
||||
{% endfor %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-4 col-sm-offset-5">
|
||||
<button class="btn btn-white" type="reset"> 重置 </button>
|
||||
<button class="btn btn-primary" type="submit"> 提交 </button>
|
||||
<div id='box2'> </div>
|
||||
</div>
|
||||
<form id="groupForm" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
<h3 class="widget-head-color-box">资产组信息</h3>
|
||||
{% bootstrap_field form.name layout="horizontal" %}
|
||||
{% bootstrap_field form.comment layout="horizontal" %}
|
||||
{# <div class="hr-line-dashed"></div>#}
|
||||
{# <h3 class="widget-head-color-box">用户选择的资产</h3>#}
|
||||
{# <div class="form-group">#}
|
||||
{# <label class="col-sm-2 control-label" id="asset_on_count">已选({{ assets_count }})</label>#}
|
||||
{# <div class="col-sm-9" id="asset_sed">#}
|
||||
{# <div class="form-asset-on" id="add_asset">#}
|
||||
{# <p id="asset_on_p">#}
|
||||
{# {% for asset in assets_on_list %}#}
|
||||
{# <button name='asset_hostname' title='{{ asset.ip }}' type='button' class='btn btn-default btn-xs'>{{ asset.hostname }}</button>#}
|
||||
{# {% endfor %}#}
|
||||
{# </p>#}
|
||||
{# </div>#}
|
||||
{# </div>#}
|
||||
{# </div>#}
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-4 col-sm-offset-5">
|
||||
<button class="btn btn-white" type="reset"> 重置 </button>
|
||||
<button class="btn btn-primary" type="submit"> 提交 </button>
|
||||
<div id='box2'> </div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -13,17 +13,17 @@
|
|||
<div class="ibox float-e-margins">
|
||||
<div class="panel-options">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a></li>
|
||||
<li class="active"><a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Group assets' %} </a></li>
|
||||
<li class="pull-right">
|
||||
<a class="btn btn-outline btn-default" href="{% url 'assets:asset-group-update' pk=asset_group.id %}"><i class="fa fa-edit"></i>Update</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="col-sm-7" style="padding-left: 0">
|
||||
<div class="col-sm-8" style="padding-left: 0">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span style="float: left"></span>{% trans 'Asset list of ' %} <b>{{ asset_group.name }}</b></span>
|
||||
<span style="float: left">{% trans 'Asset list of ' %} <b>{{ asset_group.name }} </b><span class="badge"> {{ asset_group.assets.all.count }}</span></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
|
@ -45,9 +45,9 @@
|
|||
<th>{% trans 'Hostname' %}</th>
|
||||
<th>{% trans 'IP' %}</th>
|
||||
<th>{% trans 'Port' %}</th>
|
||||
<th>{% trans 'Type' %}</th>
|
||||
<th>{% trans 'Type' %}</th>
|
||||
<th>{% trans 'Alive' %}</th>
|
||||
<th>{% trans 'Action' %}</th>
|
||||
<th>{% trans 'Action' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -56,11 +56,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
|
||||
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Push system users' %}
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Add assets to this group' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table">
|
||||
|
@ -68,7 +67,7 @@
|
|||
<form>
|
||||
<tr class="no-borders-tr">
|
||||
<td colspan="2">
|
||||
<select data-placeholder="{% trans 'Select system users' %}" class="select2 system-user-select" style="width: 100%" multiple="" tabindex="4">
|
||||
<select data-placeholder="{% trans 'Select assets' %}" class="select2 system-user-select" style="width: 100%" multiple="" tabindex="4">
|
||||
{% for system_user in system_users %}
|
||||
<option value="{{ system_user.id }}"> {{ system_user.name }} </option>
|
||||
{% endfor %}
|
||||
|
@ -91,8 +90,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{# </div>#}
|
||||
|
||||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
|
@ -151,25 +148,6 @@ function leaveGroup(obj, name, url, data) {
|
|||
});
|
||||
}
|
||||
|
||||
function pushSystemUser(sysUserID) {
|
||||
var the_url = "{% url 'api-assets:asset-group-push-system-user' pk=asset_group.id %}";
|
||||
var body = {
|
||||
system_user: sysUserID
|
||||
};
|
||||
var success = function(data) {
|
||||
var url = "{% url 'ops:task-detail' pk=234234234 %}".replace("234234234", data);
|
||||
setTimeout(function () {
|
||||
location.href = url
|
||||
}, 1000);
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
});
|
||||
}
|
||||
|
||||
Array.prototype.remove = function(val) {
|
||||
var index = this.indexOf(val);
|
||||
if (index > -1) {
|
||||
|
@ -189,21 +167,8 @@ Array.prototype.unique = function(){
|
|||
return res;
|
||||
};
|
||||
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2();
|
||||
|
||||
$('.select2.asset-select').select2()
|
||||
.on('select2:select', function(evt) {
|
||||
var data = evt.params.data;
|
||||
jumpserver.assets_selected[data.id] = data.text;
|
||||
console.log(jumpserver.assets_selected)
|
||||
})
|
||||
.on('select2:unselect', function(evt) {
|
||||
var data = evt.params.data;
|
||||
delete jumpserver.assets_selected[data.id]
|
||||
});
|
||||
|
||||
var options = {
|
||||
function initTable() {
|
||||
var options = {
|
||||
ele: $('#asset_list_table'),
|
||||
buttons: [],
|
||||
order: [],
|
||||
|
@ -231,6 +196,24 @@ $(document).ready(function () {
|
|||
op_html: $('#actions').html()
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2();
|
||||
|
||||
$('.select2.asset-select').select2()
|
||||
.on('select2:select', function(evt) {
|
||||
var data = evt.params.data;
|
||||
jumpserver.assets_selected[data.id] = data.text;
|
||||
console.log(jumpserver.assets_selected)
|
||||
})
|
||||
.on('select2:unselect', function(evt) {
|
||||
var data = evt.params.data;
|
||||
delete jumpserver.assets_selected[data.id]
|
||||
});
|
||||
initTable();
|
||||
|
||||
})
|
||||
|
||||
.on('click', ".btn-asset-group-add-asset", function () {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
{% block table_search %}
|
||||
{% endblock %}
|
||||
{% block table_container %}
|
||||
<div class="uc pull-left m-l-5 m-r-5">
|
||||
<div class="uc pull-left m-r-5">
|
||||
<a href="{% url "assets:asset-group-create" %}" class="btn btn-sm btn-primary"> {% trans "Create asset group" %} </a>
|
||||
</div>
|
||||
<table class="table table-striped table-bordered table-hover " id="asset_groups_list_table" >
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block table_container %}
|
||||
<div class="uc pull-left m-l-5 m-r-5"><a href="{% url "assets:asset-create" %}" class="btn btn-sm btn-primary"> {% trans "Create asset" %} </a></div>
|
||||
<div class="uc pull-left m-r-5"><a href="{% url "assets:asset-create" %}" class="btn btn-sm btn-primary"> {% trans "Create asset" %} </a></div>
|
||||
<table class="table table-striped table-bordered table-hover " id="asset_list_table" >
|
||||
<thead>
|
||||
<tr>
|
||||
|
|
|
@ -24,14 +24,10 @@
|
|||
{% bootstrap_field form.type layout="horizontal" %}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Group' %}</h3>
|
||||
<h3>{% trans 'Cluster and group' %}</h3>
|
||||
{% bootstrap_field form.cluster layout="horizontal" %}
|
||||
{% bootstrap_field form.groups layout="horizontal" %}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Asset user' %}</h3>
|
||||
{% bootstrap_field form.admin_user layout="horizontal" %}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Configuration' %}</h3>
|
||||
{% bootstrap_field form.number layout="horizontal" %}
|
||||
|
|
|
@ -25,10 +25,10 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="col-sm-7" style="padding-left: 0;">
|
||||
<div class="col-sm-8" style="padding-left: 0;">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span style="float: left">{% trans 'Cluster assets' %} <b>{{ cluster.name }} </b><span class="badge"></span></span>
|
||||
<span style="float: left">{% trans 'Cluster assets' %} <b>{{ cluster.name }} </b><span class="badge">{{ cluster.assets.all.count }}</span></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
|
@ -61,23 +61,10 @@
|
|||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div id="actions" class="hide">
|
||||
<div class="input-group">
|
||||
<select class="form-control m-b" style="width: auto" id="slct_bulk_update">
|
||||
<option value="delete">{% trans 'Remove selected' %}</option>
|
||||
</select>
|
||||
<div class="input-group-btn pull-left" style="padding-left: 5px;">
|
||||
<button id='btn_bulk_update' style="height: 32px;" class="btn btn-sm btn-warning">
|
||||
{% trans 'Submit' %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
|
||||
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Add assets to' %} {{ cluster.name }}
|
||||
|
@ -164,17 +151,8 @@ function deleteClusterAssets(assets) {
|
|||
});
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2()
|
||||
.on("select2:select", function (evt) {
|
||||
var data = evt.params.data;
|
||||
jumpserver.assets_selected[data.id] = data.text;
|
||||
})
|
||||
.on('select2:unselect', function(evt) {
|
||||
var data = evt.params.data;
|
||||
delete jumpserver.assets_selected[data.id];
|
||||
});
|
||||
var options = {
|
||||
function initTable() {
|
||||
var options = {
|
||||
ele: $('#cluster_assets_table'),
|
||||
buttons: [],
|
||||
order: [],
|
||||
|
@ -196,7 +174,19 @@ $(document).ready(function () {
|
|||
op_html: $('#actions').html()
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2()
|
||||
.on("select2:select", function (evt) {
|
||||
var data = evt.params.data;
|
||||
jumpserver.assets_selected[data.id] = data.text;
|
||||
})
|
||||
.on('select2:unselect', function(evt) {
|
||||
var data = evt.params.data;
|
||||
delete jumpserver.assets_selected[data.id];
|
||||
});
|
||||
initTable();
|
||||
})
|
||||
|
||||
.on('click', '.btn-asset-attach', function () {
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
{% csrf_token %}
|
||||
<h3 class="widget-head-color-box">基本信息</h3>
|
||||
{% bootstrap_field form.name layout="horizontal" %}
|
||||
{% bootstrap_field form.admin_user layout="horizontal" %}
|
||||
{% bootstrap_field form.address layout="horizontal" %}
|
||||
{% bootstrap_field form.contact layout="horizontal" %}
|
||||
{% bootstrap_field form.phone layout="horizontal" %}
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="col-sm-7" style="padding-left: 0;">
|
||||
<div class="col-sm-8" style="padding-left: 0;">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label"><b>{{ cluster.name }}</b></span>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
{% endblock %}
|
||||
{% block table_search %}{% endblock %}
|
||||
{% block table_container %}
|
||||
<div class="uc pull-left m-l-5 m-r-5">
|
||||
<div class="uc pull-left m-r-5">
|
||||
<a href="{% url "assets:cluster-create" %}" class="btn btn-sm btn-primary"> {% trans "Create Cluster" %} </a>
|
||||
</div>
|
||||
<table class="table table-striped table-bordered table-hover " id="cluster_list_table" >
|
||||
|
@ -16,6 +16,7 @@
|
|||
<input type="checkbox" id="check_all" class="ipt_check_all" >
|
||||
</th>
|
||||
<th class="text-center"><a href="{% url 'assets:cluster-list' %}?sort=name">{% trans 'Name' %}</a></th>
|
||||
<th class="text-center">{% trans 'Admin user' %}</th>
|
||||
<th class="text-center">{% trans 'Asset num' %}</th>
|
||||
<th class="text-center">{% trans 'Contact' %}</th>
|
||||
<th class="text-center">{% trans 'Phone' %}</th>
|
||||
|
@ -51,13 +52,13 @@ $(document).ready(function(){
|
|||
$(td).html(detail_btn.replace('99991937', rowData.id));
|
||||
}},
|
||||
|
||||
{targets: 6, createdCell: function (td, cellData, rowData) {
|
||||
{targets: 7, createdCell: function (td, cellData, rowData) {
|
||||
var update_btn = '<a href="{% url "assets:cluster-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('99991937', cellData);
|
||||
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_cluster_delete" data-uid="99991937">{% trans "Delete" %}</a>'.replace('99991937', cellData);
|
||||
$(td).html(update_btn + del_btn)
|
||||
}}],
|
||||
ajax_url: '{% url "api-assets:cluster-list" %}',
|
||||
columns: [{data: function(){return ""}}, {data: "name" }, {data: "assets_amount" }, {data: "contact" }, {data: "phone" },
|
||||
columns: [{data: function(){return ""}}, {data: "name" }, {data: "admin_user_name"}, {data: "assets_amount" }, {data: "contact" }, {data: "phone" },
|
||||
{data: "operator" }, {data: "id" }],
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="col-sm-7" style="padding-left: 0;">
|
||||
<div class="col-sm-8" style="padding-left: 0;">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span style="float: left">{% trans 'Assets of ' %} <b>{{ system_user.name }} </b><span class="badge">{{ paginator.count }}</span></span>
|
||||
|
@ -48,90 +48,38 @@
|
|||
<th>{% trans 'IP' %}</th>
|
||||
<th>{% trans 'Port' %}</th>
|
||||
<th>{% trans 'Reachable' %}</th>
|
||||
<th>{% trans 'Action' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for asset in page_obj %}
|
||||
<tr>
|
||||
<td>{{ asset.hostname }}</td>
|
||||
<td>{{ asset.ip }}</td>
|
||||
<td>{{ asset.port }}</td>
|
||||
<td>
|
||||
|
||||
<i class="fa fa-check text-navy"></i>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-danger pull-right btn-xs" type="button"><i class="fa fa-minus"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
|
||||
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Attach to assets ' %}
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Quick update' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<form>
|
||||
<tr class="no-borders-tr">
|
||||
<td colspan="2">
|
||||
<select data-placeholder="{% trans 'Select asset' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
|
||||
{% for asset in assets_remain %}
|
||||
<option value="{{ asset.id }}">{{ asset.ip}}:{{ asset.port }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="no-borders-tr">
|
||||
<td colspan="2">
|
||||
<button type="button" class="btn btn-primary btn-sm btn-add-asset2system-user">{% trans 'Confirm' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Attach to asset groups' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table group_edit">
|
||||
<tbody>
|
||||
<form>
|
||||
<tr>
|
||||
<td colspan="2" class="no-borders">
|
||||
<select data-placeholder="{% trans 'Add asset group' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
|
||||
{% for asset_group in asset_groups_remain %}
|
||||
<option value="{{ asset_group.id }}">{{ asset_group.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="no-borders">
|
||||
<button type="button" class="btn btn-info btn-sm" id="btn_add_user_group">{% trans 'Attach AssetGroup' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
|
||||
{% for asset_group in asset_groups %}
|
||||
<tr>
|
||||
<td ><b class="bdg_asset_groups" data-gid={{ asset_group.id }}>{{ asset_group.name }}</b></td>
|
||||
<td>
|
||||
<button class="btn btn-danger pull-right btn-xs btn-leave-system_user" type="button"><i class="fa fa-minus"></i></button>
|
||||
</td>
|
||||
<tr class="no-borders-tr">
|
||||
<td width="50%">{% trans 'Push system user manually' %}:</td>
|
||||
<td>
|
||||
<span style="float: right">
|
||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Push' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%">{% trans 'Refresh assets connectivity' %}:</td>
|
||||
<td>
|
||||
<span style="float: right">
|
||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Refresh' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -142,8 +90,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
|
@ -166,6 +112,30 @@ Array.prototype.unique = function(){
|
|||
}
|
||||
return res;
|
||||
};
|
||||
function initAssetsTable() {
|
||||
var options = {
|
||||
ele: $('#system_user_list'),
|
||||
buttons: [],
|
||||
order: [],
|
||||
columnDefs: [
|
||||
{targets: 0, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a href="{% url "assets:asset-detail" pk=99991937 %}" data-aid="'+rowData.id+'">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('99991937', rowData.id));
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-assets:asset-list" %}?system_user_id={{ system_user.id }}',
|
||||
columns: [{data: "hostname" }, {data: "ip" }, {data: "port" }, {data: "is_online" }],
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
}
|
||||
function objectDelete(obj, name, url, data) {
|
||||
function doDelete() {
|
||||
var body = data;
|
||||
|
@ -234,33 +204,7 @@ $(document).ready(function () {
|
|||
delete jumpserver.assets_selected[data.id];
|
||||
delete jumpserver.asset_groups_selected[data.id];
|
||||
});
|
||||
var options = {
|
||||
ele: $('#system_user_list'),
|
||||
buttons: [],
|
||||
order: [],
|
||||
columnDefs: [
|
||||
{targets: 0, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a href="{% url "assets:asset-detail" pk=99991937 %}" data-aid="'+rowData.id+'">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('99991937', rowData.id));
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData, rowData) {
|
||||
var update_btn = '<a href="{% url "assets:asset-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('99991937', rowData.id);
|
||||
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_asset_delete" data-aid="99991937">{% trans "Delete" %}</a>'.replace('99991937', rowData.id);
|
||||
$(td).html(update_btn + del_btn)
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-assets:asset-list" %}?system_user_id={{ system_user.id }}',
|
||||
columns: [{data: "hostname" }, {data: "ip" }, {data: "port" }, {data: function () { return ""; } }, {data: "id"}],
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
initAssetsTable();
|
||||
})
|
||||
|
||||
.on('click', '.btn-add-asset2system-user', function () {
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="col-sm-7" style="padding-left: 0;">
|
||||
<div class="col-sm-8" style="padding-left: 0;">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label"><b>{{ system_user.name }}</b></span>
|
||||
|
@ -105,7 +105,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
|
||||
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Quick update' %}
|
||||
|
@ -114,25 +114,23 @@
|
|||
<table class="table">
|
||||
<tbody>
|
||||
<tr class="no-borders-tr">
|
||||
<td width="50%">{% trans 'Get manual install script' %}:</td>
|
||||
<td width="50%">{% trans 'Auto push' %}:</td>
|
||||
<td>
|
||||
<span style="float: right">
|
||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Get' %}</button>
|
||||
<span class="pull-right">
|
||||
<div class="switch">
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" {% if system_user.auto_push %} checked {% endif %} class="onoffswitch-checkbox" id="is_active">
|
||||
<label class="onoffswitch-label" for="is_active">
|
||||
<span class="onoffswitch-inner"></span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td width="50%">{% trans 'Retest asset connectivity' %}:</td>
|
||||
<td>
|
||||
<span style="float: right">
|
||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Start' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td width="50%">{% trans 'Reset private key' %}:</td>
|
||||
<td width="50%">{% trans 'Reset auth' %}:</td>
|
||||
<td>
|
||||
<span style="float: right">
|
||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Reset' %}</button>
|
||||
|
@ -149,8 +147,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block table_container %}
|
||||
<div class="uc pull-left m-l-5 m-r-5">
|
||||
<div class="uc pull-left m-r-5">
|
||||
<a href="{% url 'assets:system-user-create' %}" class="btn btn-sm btn-primary "> {% trans "Create system user" %} </a>
|
||||
</div>
|
||||
<table class="table table-striped table-bordered table-hover " id="system_user_list_table" >
|
||||
|
|
|
@ -4,50 +4,12 @@
|
|||
{% load bootstrap3 %}
|
||||
|
||||
{% block auth %}
|
||||
<div class="password-auth hidden">
|
||||
{% bootstrap_field form.password layout="horizontal" %}
|
||||
</div>
|
||||
<div class="public-key-auth">
|
||||
<div>
|
||||
{% bootstrap_field form.private_key_file layout="horizontal" %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
var auth_method = '#'+'{{ form.auth_method.id_for_label }}';
|
||||
var auto_generate_key = '#'+'{{ form.auto_generate_key.id_for_label }}';
|
||||
function authMethodDisplay() {
|
||||
if ($(auth_method).val() == 'P') {
|
||||
$('.password-auth').removeClass('hidden');
|
||||
$('.public-key-auth').addClass('hidden');
|
||||
$('#'+'{{ form.password.id_for_label }}').removeAttr('disabled');
|
||||
|
||||
} else if ($(auth_method).val() == 'K') {
|
||||
$('.password-auth').addClass('hidden');
|
||||
$('.public-key-auth').removeClass('hidden');
|
||||
$('#'+'{{ form.password.id_for_label }}').removeAttr('required');
|
||||
$('#'+'{{ form.password.id_for_label }}').attr('disabled', 'disabled');
|
||||
|
||||
if ($(auto_generate_key).prop('checked')){
|
||||
$('#'+'{{ form.private_key_file.id_for_label }}').closest('.form-group').addClass('hidden');
|
||||
} else {
|
||||
$('#'+'{{ form.private_key_file.id_for_label }}').closest('.form-group').removeClass('hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2();
|
||||
authMethodDisplay();
|
||||
$(auth_method).change(function () {
|
||||
authMethodDisplay();
|
||||
});
|
||||
$(auto_generate_key).change(function () {
|
||||
authMethodDisplay();
|
||||
});
|
||||
$('.select2').select2();
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -89,7 +89,10 @@ class AdminUserDetailView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
|||
return super(AdminUserDetailView, self).get(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return self.object.assets.all()
|
||||
queryset = []
|
||||
for cluster in self.object.cluster_set.all():
|
||||
queryset.extend(list(cluster.assets.all()))
|
||||
return queryset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
asset_groups = AssetGroup.objects.all()
|
||||
|
@ -114,9 +117,11 @@ class AdminUserAssetsView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
|||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
self.queryset = self.object.assets.all()
|
||||
sorted(self.queryset, key=lambda x: x.is_connective() is False)
|
||||
return self.queryset
|
||||
queryset = []
|
||||
for cluster in self.object.cluster_set.all():
|
||||
queryset.extend(list(cluster.assets.all()))
|
||||
self.queryset = queryset
|
||||
return queryset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
|
|
|
@ -183,7 +183,6 @@ class AssetDetailView(DetailView):
|
|||
|
||||
def get_context_data(self, **kwargs):
|
||||
asset_groups = self.object.groups.all()
|
||||
system_users = self.object.system_users.all()
|
||||
context = {
|
||||
'app': 'Assets',
|
||||
'action': 'Asset detail',
|
||||
|
@ -191,7 +190,6 @@ class AssetDetailView(DetailView):
|
|||
if asset_group not in asset_groups],
|
||||
'asset_groups': asset_groups,
|
||||
'system_users_all': SystemUser.objects.all(),
|
||||
'system_users': system_users,
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(AssetDetailView, self).get_context_data(**kwargs)
|
||||
|
|
|
@ -10,7 +10,7 @@ from django.urls import reverse_lazy
|
|||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.views.generic.detail import DetailView, SingleObjectMixin
|
||||
|
||||
from .. import forms
|
||||
from ..forms import SystemUserForm, SystemUserUpdateForm
|
||||
from ..models import Asset, AssetGroup, SystemUser
|
||||
from ..hands import AdminUserRequiredMixin
|
||||
from perms.utils import associate_system_users_and_assets
|
||||
|
@ -36,7 +36,7 @@ class SystemUserListView(AdminUserRequiredMixin, TemplateView):
|
|||
|
||||
class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
||||
model = SystemUser
|
||||
form_class = forms.SystemUserForm
|
||||
form_class = SystemUserForm
|
||||
template_name = 'assets/system_user_create.html'
|
||||
success_url = reverse_lazy('assets:system-user-list')
|
||||
|
||||
|
@ -65,7 +65,7 @@ class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVi
|
|||
|
||||
class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView):
|
||||
model = SystemUser
|
||||
form_class = forms.SystemUserUpdateForm
|
||||
form_class = SystemUserUpdateForm
|
||||
template_name = 'assets/system_user_update.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
@ -110,31 +110,16 @@ class SystemUserDeleteView(AdminUserRequiredMixin, DeleteView):
|
|||
success_url = reverse_lazy('assets:system-user-list')
|
||||
|
||||
|
||||
class SystemUserAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
class SystemUserAssetView(AdminUserRequiredMixin, DetailView):
|
||||
model = SystemUser
|
||||
template_name = 'assets/system_user_asset.html'
|
||||
context_object_name = 'system_user'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object(queryset=SystemUser.objects.all())
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return self.object.assets.all()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
assets = self.get_queryset()
|
||||
context = {
|
||||
'app': 'assets',
|
||||
'action': 'System user asset',
|
||||
'assets_remain': [asset for asset in Asset.objects.all() if asset not in assets],
|
||||
'asset_groups': AssetGroup.objects.all(),
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(SystemUserAssetView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ class AdHocSerializer(serializers.ModelSerializer):
|
|||
class AdHocRunHistorySerializer(serializers.ModelSerializer):
|
||||
task = serializers.SerializerMethodField()
|
||||
adhoc_short_id = serializers.SerializerMethodField()
|
||||
stat = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = AdHocRunHistory
|
||||
|
@ -38,6 +39,14 @@ class AdHocRunHistorySerializer(serializers.ModelSerializer):
|
|||
def get_task(obj):
|
||||
return obj.adhoc.task.id
|
||||
|
||||
@staticmethod
|
||||
def get_stat(obj):
|
||||
return {
|
||||
"total": len(obj.adhoc.hosts),
|
||||
"success": len(obj.summary["contacted"]),
|
||||
"failed": len(obj.summary["dark"]),
|
||||
}
|
||||
|
||||
def get_field_names(self, declared_fields, info):
|
||||
fields = super().get_field_names(declared_fields, info)
|
||||
fields.extend(['summary', 'short_id'])
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
<th>{% trans 'Run as' %}</th>
|
||||
<th>{% trans 'Become' %}</th>
|
||||
<th>{% trans 'Datetime' %}</th>
|
||||
<th></th>
|
||||
<th>{% trans 'Action' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -104,12 +104,17 @@
|
|||
} else {
|
||||
$(td).html(cellData.user)
|
||||
}
|
||||
|
||||
}}
|
||||
}},
|
||||
{targets: 7, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a class="btn btn-xs btn-primary m-l-xs btn-run" data-uid="99991937">{% trans "Detail" %}</a>'.replace('99991937', cellData);
|
||||
if (cellData) {
|
||||
$(td).html(detail_btn);
|
||||
}
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-ops:adhoc-list" %}?task={{ object.pk }}',
|
||||
columns: [{data: function(){return ""}}, {data: "short_id" }, {data: "hosts"}, {data: "pattern"},
|
||||
{data: "run_as"}, {data: "become"}, {data: "date_created"}]
|
||||
{data: "run_as"}, {data: "become"}, {data: "date_created"}, {data: "id"}]
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
})
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<div class="col-sm-12" style="padding-left: 0">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span style="float: left">{% trans 'Versions of ' %} <b>{{ object.name }}</b></span>
|
||||
<span style="float: left">{% trans 'History of ' %} <b>{{ object.name }}</b></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
|
@ -57,7 +57,8 @@
|
|||
<th>{% trans 'Is finished' %}</th>
|
||||
<th>{% trans 'Is success' %}</th>
|
||||
<th>{% trans 'Time' %}</th>
|
||||
<th></th>
|
||||
<th>{% trans 'Version' %}</th>
|
||||
<th>{% trans 'Action' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -86,10 +87,12 @@
|
|||
{# var detail_btn = '<a href="' + cellData + '</a>';#}
|
||||
$(td).html(cellData);
|
||||
}},
|
||||
{# {targets: 2, createdCell: function (td, cellData, rowData) {#}
|
||||
{# var dataLength = cellData.length;#}
|
||||
{# $(td).html(dataLength);#}
|
||||
{# }},#}
|
||||
{targets: 2, createdCell: function (td, cellData) {
|
||||
var total = "<span>" + cellData.total + "</span>";
|
||||
var success = "<span class='text-navy'>" + cellData.success + "</span>";
|
||||
var failed = "<span class='text-danger'>" + cellData.failed + "</span>";
|
||||
$(td).html(failed + '/' + success + '/' + total );
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
|
@ -110,12 +113,17 @@
|
|||
} else {
|
||||
$(td).html("0" + ' s')
|
||||
}
|
||||
|
||||
}}
|
||||
}},
|
||||
{targets: 7, createdCell: function (td, cellData) {
|
||||
var run_btn = '<a class="btn btn-xs btn-primary m-l-xs btn-run" data-uid="99991937">{% trans "Detail" %}</a>'.replace('99991937', cellData);
|
||||
if (cellData) {
|
||||
$(td).html(run_btn);
|
||||
}
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-ops:history-list" %}?task={{ object.pk }}',
|
||||
columns: [{data: function(){return ""}}, {data: "date_start"}, {data: "adhoc_short_id"},
|
||||
{data: "adhoc_short_id"}, {data: "adhoc_short_id"}, {data: "timedelta"}]
|
||||
columns: [{data: function(){return ""}}, {data: "date_start"}, {data: "stat"}, {data: "adhoc_short_id"},
|
||||
{data: "adhoc_short_id"}, {data: "timedelta"}, {data: 'adhoc_short_id'}, {data: "id"}]
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
})
|
||||
|
|
|
@ -277,3 +277,16 @@ div.dataTables_wrapper div.dataTables_filter {
|
|||
margin-top: 5px;
|
||||
padding: 5px 12px;
|
||||
}
|
||||
|
||||
#op.col-md-6{
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.help-message {
|
||||
padding-left: 10px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
margin-bottom:0;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px
|
||||
}
|
|
@ -591,7 +591,7 @@ body.canvas-menu.mini-navbar nav.navbar-static-side {
|
|||
border-radius: 3px;
|
||||
}
|
||||
.float-e-margins .btn {
|
||||
margin-bottom: 5px;
|
||||
/*margin-bottom: 5px;*/
|
||||
}
|
||||
.btn-w-m {
|
||||
min-width: 120px;
|
||||
|
@ -3440,13 +3440,13 @@ video {
|
|||
overflow-x: hidden;
|
||||
}
|
||||
.wrapper {
|
||||
padding: 0 20px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.wrapper-content {
|
||||
padding: 20px 10px 40px;
|
||||
padding: 10px 10px 10px;
|
||||
}
|
||||
#page-wrapper {
|
||||
padding: 0 15px;
|
||||
padding: 0 10px;
|
||||
min-height: 568px;
|
||||
position: relative !important;
|
||||
}
|
||||
|
|
|
@ -98,30 +98,6 @@ function move_left(from, to, from_o, to_o) {
|
|||
});
|
||||
}
|
||||
|
||||
//function move_all(from, to) {
|
||||
// $("#" + from).children().each(function () {
|
||||
// $("#" + to).append(this);
|
||||
// });
|
||||
//}
|
||||
//
|
||||
|
||||
//function selectAllOption(){
|
||||
// var checklist = document.getElementsByName ("selected");
|
||||
// if(document.getElementById("select_all").checked)
|
||||
// {
|
||||
// for(var i=0;i<checklist.length;i++)
|
||||
// {
|
||||
// checklist[i].checked = 1;
|
||||
// }
|
||||
// }else{
|
||||
// for(var j=0;j<checklist.length;j++)
|
||||
// {
|
||||
// checklist[j].checked = 0;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
function selectAll(){
|
||||
// Select all check box
|
||||
|
@ -131,15 +107,6 @@ function selectAll(){
|
|||
}
|
||||
|
||||
|
||||
// function getIDall() {
|
||||
// var check_array = [];
|
||||
// $(".gradeX input:checked").each(function () {
|
||||
// var id = $(this).attr("value");
|
||||
// check_array.push(id);
|
||||
// });
|
||||
// return check_array.join(",");
|
||||
// }
|
||||
|
||||
function getCookie(name) {
|
||||
var cookieValue = null;
|
||||
if (document.cookie && document.cookie !== '') {
|
||||
|
@ -289,7 +256,7 @@ jumpserver.initDataTable = function (options) {
|
|||
createdCell: function(td, cellData) {
|
||||
$(td).html('<input type="checkbox" class="text-center ipt_check" id=99991937>'.replace('99991937', cellData));
|
||||
}},
|
||||
{className: 'text-center', targets: '_all'}
|
||||
{className: 'text-center', targets: '_all'}
|
||||
];
|
||||
columnDefs = options.columnDefs ? options.columnDefs.concat(columnDefs) : columnDefs;
|
||||
var table = ele.DataTable({
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
{% include '_message.html' %}
|
||||
{% block first_login_message %}
|
||||
{% if user.is_authenticated and user.is_first_login %}
|
||||
<div class="alert alert-danger" style="margin: 20px auto 0px">
|
||||
<div class="alert alert-danger help-message">
|
||||
{% url 'users:user-first-login' as first_login_url %}
|
||||
{% blocktrans %}
|
||||
Your information was incomplete. Please click <a href="{{ first_login_url }}"> this link </a>to complete your information.
|
||||
|
@ -32,7 +32,7 @@
|
|||
{% endblock %}
|
||||
{% block update_public_key_message %}
|
||||
{% if user.is_authenticated and not user.is_public_key_valid %}
|
||||
<div class="alert alert-danger" style="margin: 20px auto 0px">
|
||||
<div class="alert alert-danger help-message">
|
||||
{% url 'users:user-pubkey-update' as user_pubkey_update %}
|
||||
{% blocktrans %}
|
||||
Your ssh public key not set or expired. Please click <a href="{{ user_pubkey_update }}"> this link </a>to update your
|
||||
|
@ -40,6 +40,7 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block help_message %}{% endblock %}
|
||||
{% block content %}{% endblock %}
|
||||
{% include '_footer.html' %}
|
||||
</div>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="col-sm-7" style="padding-left: 0;">
|
||||
<div class="col-sm-8" style="padding-left: 0;">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span style="float: left">{% trans 'Asset permission of ' %} <b>{{ user.name }}</b></span>
|
||||
|
@ -65,7 +65,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
|
||||
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Quick create permission for user' %}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="col-sm-7" style="padding-left: 0;">
|
||||
<div class="col-sm-8" style="padding-left: 0;">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span style="float: left">{% trans 'Assets granted of ' %} <b>{{ user_group.name }}</b></span>
|
||||
|
@ -62,7 +62,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
|
||||
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span style="float: left">{% trans 'Asset groups granted of ' %} <b>{{ user_group.name }}</b></span>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
</div>
|
||||
{% endblock %}
|
||||
{% block table_container %}
|
||||
<div class="uc pull-left m-l-5 m-r-5"><a href="{% url "users:user-create" %}" class="btn btn-sm btn-primary"> {% trans "Create user" %} </a></div>
|
||||
<div class="uc pull-left m-r-5"><a href="{% url "users:user-create" %}" class="btn btn-sm btn-primary"> {% trans "Create user" %} </a></div>
|
||||
<table class="table table-striped table-bordered table-hover " id="user_list_table" >
|
||||
<thead>
|
||||
<tr>
|
||||
|
|
Loading…
Reference in New Issue