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):
|
def get_queryset(self):
|
||||||
if self.request.user.is_superuser:
|
if self.request.user.is_superuser:
|
||||||
queryset = super(AssetViewSet, self).get_queryset()
|
queryset = super().get_queryset()
|
||||||
else:
|
else:
|
||||||
queryset = get_user_granted_assets(self.request.user)
|
queryset = get_user_granted_assets(self.request.user)
|
||||||
cluster_id = self.request.query_params.get('cluster_id', '')
|
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')
|
||||||
asset_group_id = self.request.query_params.get('asset_group_id', '')
|
admin_user_id = self.request.query_params.get('admin_user_id')
|
||||||
admin_user_id = self.request.query_params.get('admin_user_id', '')
|
|
||||||
if cluster_id:
|
if cluster_id:
|
||||||
queryset = queryset.filter(cluster__id=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:
|
if asset_group_id:
|
||||||
queryset = queryset.filter(groups__id=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
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,40 +10,60 @@ logger = get_logger(__file__)
|
||||||
|
|
||||||
|
|
||||||
class AssetCreateForm(forms.ModelForm):
|
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:
|
class Meta:
|
||||||
model = Asset
|
model = Asset
|
||||||
fields = [
|
fields = [
|
||||||
'hostname', 'ip', 'public_ip', 'port', 'type', 'comment',
|
'hostname', 'ip', 'public_ip', 'port', 'type', 'comment',
|
||||||
'admin_user', "cluster", 'groups', 'status', 'env', 'is_active'
|
'cluster', 'groups', 'status', 'env', 'is_active', 'username',
|
||||||
|
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'groups': forms.SelectMultiple(
|
'groups': forms.SelectMultiple(
|
||||||
attrs={'class': 'select2',
|
attrs={'class': 'select2',
|
||||||
'data-placeholder': _('Select asset groups')}),
|
'data-placeholder': _('Select asset groups')}),
|
||||||
'admin_user': forms.Select(
|
|
||||||
attrs={'class': 'select2',
|
|
||||||
'data-placeholder': _('Select asset admin user')}),
|
|
||||||
}
|
}
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'hostname': '* required',
|
'hostname': '* required',
|
||||||
'ip': '* 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 AssetUpdateForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Asset
|
model = Asset
|
||||||
fields = [
|
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',
|
'type', 'env', 'status', 'public_ip', 'remote_card_ip', 'cabinet_no',
|
||||||
'cabinet_pos', 'number', 'comment'
|
'cabinet_pos', 'number', 'comment'
|
||||||
]
|
]
|
||||||
|
@ -51,17 +71,10 @@ class AssetUpdateForm(forms.ModelForm):
|
||||||
'groups': forms.SelectMultiple(
|
'groups': forms.SelectMultiple(
|
||||||
attrs={'class': 'select2',
|
attrs={'class': 'select2',
|
||||||
'data-placeholder': _('Select asset groups')}),
|
'data-placeholder': _('Select asset groups')}),
|
||||||
'admin_user': forms.Select(
|
|
||||||
attrs={'class': 'select2',
|
|
||||||
'data-placeholder': _('Select asset admin user')}),
|
|
||||||
}
|
}
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'hostname': '* required',
|
'hostname': '* required',
|
||||||
'ip': '* 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,
|
port = forms.IntegerField(min_value=1, max_value=65535, required=False, label=_('Port'))
|
||||||
required=False, label=_('Port'))
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Asset
|
model = Asset
|
||||||
fields = [
|
fields = [
|
||||||
'assets', 'port', 'groups', 'admin_user', "cluster",
|
'assets', 'port', 'groups', "cluster",
|
||||||
'type', 'env', 'status',
|
'type', 'env', 'status',
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'groups': forms.SelectMultiple(
|
'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Select asset groups')}),
|
||||||
attrs={'class': 'select2',
|
|
||||||
'data-placeholder': _('Select asset groups')}),
|
|
||||||
'admin_user': forms.Select(
|
|
||||||
attrs={'class': 'select2',
|
|
||||||
'data-placeholder': _('Select asset admin user')}),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
|
@ -140,40 +147,19 @@ class AssetGroupForm(forms.ModelForm):
|
||||||
|
|
||||||
|
|
||||||
class ClusterForm(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:
|
class Meta:
|
||||||
model = Cluster
|
model = Cluster
|
||||||
fields = ['name', "bandwidth", "operator", 'contact',
|
fields = ['name', "bandwidth", "operator", 'contact', 'admin_user',
|
||||||
'phone', 'address', 'intranet', 'extranet', 'comment']
|
'phone', 'address', 'intranet', 'extranet', 'comment']
|
||||||
widgets = {
|
widgets = {
|
||||||
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
|
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
|
||||||
'intranet': forms.Textarea(
|
'intranet': forms.Textarea(attrs={'placeholder': 'IP段之间用逗号隔开,如:192.168.1.0/24,192.168.1.0/24'}),
|
||||||
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'})
|
||||||
'extranet': forms.Textarea(
|
|
||||||
attrs={'placeholder': 'IP段之间用逗号隔开,如:201.1.32.1/24,202.2.32.1/24'})
|
|
||||||
}
|
}
|
||||||
help_texts = {
|
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
|
# Admin user assets define, let user select, save it in form not in view
|
||||||
auto_generate_key = forms.BooleanField(initial=True, required=False)
|
auto_generate_key = forms.BooleanField(initial=True, required=False)
|
||||||
# Form field name can not start with `_`, so redefine it,
|
# Form field name can not start with `_`, so redefine it,
|
||||||
password = forms.CharField(widget=forms.PasswordInput, required=False,
|
password = forms.CharField(widget=forms.PasswordInput, required=False, max_length=100, strip=True)
|
||||||
max_length=100, strip=True)
|
|
||||||
# Need use upload private key file except paste private key content
|
# Need use upload private key file except paste private key content
|
||||||
private_key_file = forms.FileField(required=False)
|
private_key_file = forms.FileField(required=False)
|
||||||
|
|
||||||
|
@ -289,15 +274,19 @@ class SystemUserForm(forms.ModelForm):
|
||||||
fields = [
|
fields = [
|
||||||
'name', 'username', 'protocol', 'auto_generate_key', 'password',
|
'name', 'username', 'protocol', 'auto_generate_key', 'password',
|
||||||
'private_key_file', 'auth_method', 'auto_push', 'sudo',
|
'private_key_file', 'auth_method', 'auto_push', 'sudo',
|
||||||
'comment', 'shell'
|
'comment', 'shell', 'cluster'
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
|
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
|
||||||
'username': forms.TextInput(attrs={'placeholder': _('Username')}),
|
'username': forms.TextInput(attrs={'placeholder': _('Username')}),
|
||||||
|
'cluster': forms.SelectMultiple(
|
||||||
|
attrs={'class': 'select2',
|
||||||
|
'data-placeholder': _(' Select clusters')}),
|
||||||
}
|
}
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'name': '* required',
|
'name': '* required',
|
||||||
'username': '* required',
|
'username': '* required',
|
||||||
|
'cluster': 'If auto push checked, then push system user to that cluster assets',
|
||||||
'auto_push': 'Auto push system user to asset',
|
'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
|
# Admin user assets define, let user select, save it in form not in view
|
||||||
auto_generate_key = forms.BooleanField(initial=False, required=False)
|
auto_generate_key = forms.BooleanField(initial=False, required=False)
|
||||||
# Form field name can not start with `_`, so redefine it,
|
# Form field name can not start with `_`, so redefine it,
|
||||||
password = forms.CharField(widget=forms.PasswordInput, required=False,
|
password = forms.CharField(widget=forms.PasswordInput, required=False, max_length=100, strip=True)
|
||||||
max_length=100, strip=True)
|
|
||||||
# Need use upload private key file except paste private key content
|
# Need use upload private key file except paste private key content
|
||||||
private_key_file = forms.FileField(required=False)
|
private_key_file = forms.FileField(required=False)
|
||||||
|
|
||||||
|
@ -341,17 +329,21 @@ class SystemUserUpdateForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SystemUser
|
model = SystemUser
|
||||||
fields = [
|
fields = [
|
||||||
'name', 'username', 'protocol', 'auto_generate_key', 'password',
|
'name', 'username', 'protocol',
|
||||||
'private_key_file', 'auth_method', 'auto_push', 'sudo',
|
'auth_method', 'auto_push', 'sudo',
|
||||||
'comment', 'shell'
|
'comment', 'shell', 'cluster'
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
|
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
|
||||||
'username': forms.TextInput(attrs={'placeholder': _('Username')}),
|
'username': forms.TextInput(attrs={'placeholder': _('Username')}),
|
||||||
|
'cluster': forms.SelectMultiple(
|
||||||
|
attrs={'class': 'select2',
|
||||||
|
'data-placeholder': _(' Select clusters')}),
|
||||||
}
|
}
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'name': '* required',
|
'name': '* required',
|
||||||
'username': '* required',
|
'username': '* required',
|
||||||
|
'cluster': 'If auto push checked, then push system user to that cluster assets',
|
||||||
'auto_push': 'Auto push system user to asset',
|
'auto_push': 'Auto push system user to asset',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,17 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
from hashlib import md5
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
import logging
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.core.cache import cache
|
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 .cluster import Cluster
|
||||||
from .group import AssetGroup
|
from .group import AssetGroup
|
||||||
from .user import AdminUser, SystemUser
|
from .user import AdminUser, SystemUser
|
||||||
|
@ -47,14 +52,17 @@ class Asset(models.Model):
|
||||||
hostname = models.CharField(max_length=128, unique=True, verbose_name=_('Hostname'))
|
hostname = models.CharField(max_length=128, unique=True, verbose_name=_('Hostname'))
|
||||||
port = models.IntegerField(default=22, verbose_name=_('Port'))
|
port = models.IntegerField(default=22, verbose_name=_('Port'))
|
||||||
groups = models.ManyToManyField(AssetGroup, blank=True, related_name='assets', verbose_name=_('Asset groups'))
|
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'),)
|
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'))
|
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'),)
|
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'),)
|
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'))
|
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
|
# Some information
|
||||||
public_ip = models.GenericIPAddressField(max_length=32, blank=True, null=True, verbose_name=_('Public IP'))
|
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'))
|
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 True, ''
|
||||||
return False, warning
|
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):
|
def to_json(self):
|
||||||
return {
|
return {
|
||||||
'id': self.id,
|
'id': self.id,
|
||||||
|
@ -115,15 +158,15 @@ class Asset(models.Model):
|
||||||
Todo: May be move to ops implements it
|
Todo: May be move to ops implements it
|
||||||
"""
|
"""
|
||||||
data = self.to_json()
|
data = self.to_json()
|
||||||
if self.admin_user:
|
if self.cluster and self.cluster.admin_user:
|
||||||
data.update({
|
data.update({
|
||||||
'username': self.admin_user.username,
|
'username': self.cluster.admin_user.username,
|
||||||
'password': self.admin_user.password,
|
'password': self.cluster.admin_user.password,
|
||||||
'private_key': self.admin_user.private_key_file,
|
'private_key': self.cluster.admin_user.private_key_file,
|
||||||
'become': {
|
'become': {
|
||||||
'method': self.admin_user.become_method,
|
'method': self.cluster.admin_user.become_method,
|
||||||
'user': self.admin_user.become_user,
|
'user': self.cluster.admin_user.become_user,
|
||||||
'pass': self.admin_user.become_pass,
|
'pass': self.cluster.admin_user.become_pass,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return data
|
return data
|
||||||
|
|
|
@ -18,6 +18,7 @@ logger = logging.getLogger(__name__)
|
||||||
class Cluster(models.Model):
|
class Cluster(models.Model):
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
name = models.CharField(max_length=32, verbose_name=_('Name'))
|
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'))
|
bandwidth = models.CharField(max_length=32, blank=True, verbose_name=_('Bandwidth'))
|
||||||
contact = models.CharField(max_length=128, blank=True, verbose_name=_('Contact'))
|
contact = models.CharField(max_length=128, blank=True, verbose_name=_('Contact'))
|
||||||
phone = models.CharField(max_length=32, blank=True, verbose_name=_('Phone'))
|
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'))
|
date_created = models.DateTimeField(auto_now_add=True, null=True, verbose_name=_('Date created'))
|
||||||
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
__str__ = __unicode__
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['name']
|
ordering = ['name']
|
||||||
|
|
|
@ -8,25 +8,18 @@ import logging
|
||||||
import uuid
|
import uuid
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.conf import settings
|
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__)
|
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):
|
class AdminUser(models.Model):
|
||||||
"""
|
"""
|
||||||
A privileged user that ansible can use it to push system user and so on
|
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):
|
def become_pass(self, password):
|
||||||
self._become_pass = signer.sign(password)
|
self._become_pass = signer.sign(password)
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def assets_amount(self):
|
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:
|
class Meta:
|
||||||
ordering = ['name']
|
ordering = ['name']
|
||||||
|
@ -143,6 +138,7 @@ class SystemUser(models.Model):
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
|
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
|
||||||
username = models.CharField(max_length=16, verbose_name=_('Username'))
|
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'))
|
_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'))
|
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'))
|
_private_key = models.TextField(max_length=8192, blank=True, verbose_name=_('SSH private key'))
|
||||||
|
|
|
@ -2,22 +2,34 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- 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']
|
__all__ = ['init_model', 'generate_fake']
|
||||||
|
|
||||||
|
|
||||||
def init_model():
|
def init_model():
|
||||||
|
from . import Cluster, SystemUser, AdminUser, AssetGroup, Asset
|
||||||
for cls in [Cluster, SystemUser, AdminUser, AssetGroup, Asset]:
|
for cls in [Cluster, SystemUser, AdminUser, AssetGroup, Asset]:
|
||||||
if hasattr(cls, 'initial'):
|
if hasattr(cls, 'initial'):
|
||||||
cls.initial()
|
cls.initial()
|
||||||
|
|
||||||
|
|
||||||
def generate_fake():
|
def generate_fake():
|
||||||
|
from . import Cluster, SystemUser, AdminUser, AssetGroup, Asset
|
||||||
for cls in [Cluster, SystemUser, AdminUser, AssetGroup, Asset]:
|
for cls in [Cluster, SystemUser, AdminUser, AssetGroup, Asset]:
|
||||||
if hasattr(cls, 'generate_fake'):
|
if hasattr(cls, 'generate_fake'):
|
||||||
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__':
|
if __name__ == '__main__':
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -63,7 +63,7 @@ class ClusterUpdateAssetsSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
|
||||||
class AdminUserSerializer(serializers.ModelSerializer):
|
class AdminUserSerializer(serializers.ModelSerializer):
|
||||||
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
|
assets_amount = serializers.SerializerMethodField()
|
||||||
unreachable_amount = serializers.SerializerMethodField()
|
unreachable_amount = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -78,14 +78,18 @@ class AdminUserSerializer(serializers.ModelSerializer):
|
||||||
else:
|
else:
|
||||||
return 'Unknown'
|
return 'Unknown'
|
||||||
|
|
||||||
def get_field_names(self, declared_fields, info):
|
@staticmethod
|
||||||
fields = super(AdminUserSerializer, self).get_field_names(declared_fields, info)
|
def get_assets_amount(obj):
|
||||||
fields.append('assets_amount')
|
amount = 0
|
||||||
return fields
|
clusters = obj.cluster_set.all()
|
||||||
|
for cluster in clusters:
|
||||||
|
amount += len(cluster.assets.all())
|
||||||
|
return amount
|
||||||
|
|
||||||
|
|
||||||
class SystemUserSerializer(serializers.ModelSerializer):
|
class SystemUserSerializer(serializers.ModelSerializer):
|
||||||
unreachable_amount = serializers.SerializerMethodField()
|
unreachable_amount = serializers.SerializerMethodField()
|
||||||
|
assets_amount = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SystemUser
|
model = SystemUser
|
||||||
|
@ -99,10 +103,12 @@ class SystemUserSerializer(serializers.ModelSerializer):
|
||||||
else:
|
else:
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
|
|
||||||
def get_field_names(self, declared_fields, info):
|
@staticmethod
|
||||||
fields = super(SystemUserSerializer, self).get_field_names(declared_fields, info)
|
def get_assets_amount(obj):
|
||||||
fields.extend(['assets_amount'])
|
amount = 0
|
||||||
return fields
|
for cluster in obj.cluster.all():
|
||||||
|
amount += cluster.assets.all().count()
|
||||||
|
return amount
|
||||||
|
|
||||||
|
|
||||||
class AssetSystemUserSerializer(serializers.ModelSerializer):
|
class AssetSystemUserSerializer(serializers.ModelSerializer):
|
||||||
|
@ -200,6 +206,7 @@ class MyAssetGrantedSerializer(AssetGrantedSerializer):
|
||||||
|
|
||||||
class ClusterSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
class ClusterSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
||||||
assets_amount = serializers.SerializerMethodField()
|
assets_amount = serializers.SerializerMethodField()
|
||||||
|
admin_user_name = serializers.SerializerMethodField()
|
||||||
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
|
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -210,10 +217,9 @@ class ClusterSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
||||||
def get_assets_amount(obj):
|
def get_assets_amount(obj):
|
||||||
return obj.assets.count()
|
return obj.assets.count()
|
||||||
|
|
||||||
def get_field_names(self, declared_fields, info):
|
@staticmethod
|
||||||
fields = super(ClusterSerializer, self).get_field_names(declared_fields, info)
|
def get_admin_user_name(obj):
|
||||||
fields.append('assets_amount')
|
return obj.admin_user.name
|
||||||
return fields
|
|
||||||
|
|
||||||
|
|
||||||
class AssetGroupGrantedSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
class AssetGroupGrantedSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
{% bootstrap_field form.name layout="horizontal" %}
|
{% bootstrap_field form.name layout="horizontal" %}
|
||||||
{% bootstrap_field form.username layout="horizontal" %}
|
{% bootstrap_field form.username layout="horizontal" %}
|
||||||
{% bootstrap_field form.protocol layout="horizontal" %}
|
{% bootstrap_field form.protocol layout="horizontal" %}
|
||||||
|
{% bootstrap_field form.cluster layout="horizontal" %}
|
||||||
<h3>{% trans 'Auth' %}</h3>
|
<h3>{% trans 'Auth' %}</h3>
|
||||||
{% bootstrap_field form.auth_method layout="horizontal" %}
|
{% bootstrap_field form.auth_method layout="horizontal" %}
|
||||||
{% block auth %}
|
{% block auth %}
|
||||||
|
|
|
@ -50,37 +50,22 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ibox-content">
|
<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>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th class="text-center">
|
||||||
|
<input type="checkbox" id="check_all" class="ipt_check_all" >
|
||||||
|
</th>
|
||||||
<th>{% trans 'Hostname' %}</th>
|
<th>{% trans 'Hostname' %}</th>
|
||||||
<th>{% trans 'IP' %}</th>
|
<th>{% trans 'IP' %}</th>
|
||||||
<th>{% trans 'Port' %}</th>
|
<th>{% trans 'Port' %}</th>
|
||||||
<th>{% trans 'Alive' %}</th>
|
<th>{% trans 'Type' %}</th>
|
||||||
|
<th>{% trans 'Valid' %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<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>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div class="row">
|
|
||||||
{% include '_pagination.html' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -104,69 +89,12 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script>
|
<script>
|
||||||
|
@ -220,47 +148,31 @@ function objectRemove(obj, name, url, data) {
|
||||||
}
|
}
|
||||||
jumpserver.assets_selected = {};
|
jumpserver.assets_selected = {};
|
||||||
jumpserver.asset_groups_selected = {};
|
jumpserver.asset_groups_selected = {};
|
||||||
$(document).ready(function () {
|
|
||||||
$('.select2').select2()
|
function initTable() {
|
||||||
.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 = {
|
var options = {
|
||||||
ele: $('#system_user_assets_table'),
|
ele: $('#asset_list_table'),
|
||||||
buttons: [],
|
buttons: [],
|
||||||
order: [],
|
order: [],
|
||||||
columnDefs: [
|
columnDefs: [
|
||||||
{targets: 0, createdCell: function (td, cellData, rowData) {
|
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||||
var detail_btn = '<a href="{% url "assets:asset-detail" pk=99991937 %}" data-aid="'+rowData.id+'">' + cellData + '</a>';
|
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));
|
$(td).html(detail_btn.replace('99991937', rowData.id));
|
||||||
}},
|
}},
|
||||||
{targets: 3, createdCell: function (td, cellData) {
|
{targets: 5, createdCell: function (td, cellData) {
|
||||||
if (!cellData) {
|
if (!cellData) {
|
||||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||||
} else {
|
} else {
|
||||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
$(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 }}',
|
ajax_url: '{% url "api-assets:asset-list" %}?admin_user_id={{ admin_user.id }}',
|
||||||
columns: [{data: "hostname" }, {data: "ip" }, {data: "port" },
|
columns: [{data: function(){return ""}}, {data: "hostname" }, {data: "ip" }, {data: "port" },
|
||||||
{data: "is_active" }, {data: "id"}],
|
{data: "type" }, {data: "is_active" }],
|
||||||
op_html: $('#actions').html()
|
op_html: $('#actions').html()
|
||||||
};
|
};
|
||||||
jumpserver.initDataTable(options);
|
jumpserver.initDataTable(options);
|
||||||
|
}
|
||||||
|
|
||||||
function adminUserDelete(name, url) {
|
function adminUserDelete(name, url) {
|
||||||
function doDelete() {
|
function doDelete() {
|
||||||
|
@ -293,89 +205,22 @@ $(document).ready(function () {
|
||||||
doDelete()
|
doDelete()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
.on('click', '.btn-replace-asset-admin_user', function () {
|
$(document).ready(function () {
|
||||||
if (Object.keys(jumpserver.assets_selected).length === 0) {
|
$('.select2').select2()
|
||||||
return false;
|
.on("select2:select", function (evt) {
|
||||||
}
|
var data = evt.params.data;
|
||||||
jumpserver.asset_groups_selected = {};
|
jumpserver.assets_selected[data.id] = data.text;
|
||||||
var $data_table = $("#system_user_assets_table").DataTable();
|
jumpserver.asset_groups_selected[data.id] = data.text;
|
||||||
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('select2:unselect', function(evt) {
|
||||||
.on('click', '.btn-replace-asset_groups-admin_user', function () {
|
var data = evt.params.data;
|
||||||
if (Object.keys(jumpserver.asset_groups_selected).length === 0) {
|
delete jumpserver.assets_selected[data.id];
|
||||||
return false;
|
delete jumpserver.asset_groups_selected[data.id]
|
||||||
}
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
initTable();
|
||||||
})
|
})
|
||||||
|
.on('click', '.btn-delete-admin-user', function () {
|
||||||
.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 () {
|
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
var name = "{{ admin_user.name }}";
|
var name = "{{ admin_user.name }}";
|
||||||
var uid = "{{ admin_user.id }}";
|
var uid = "{{ admin_user.id }}";
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<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 float-e-margins">
|
||||||
<div class="ibox-title">
|
<div class="ibox-title">
|
||||||
<span class="label"><b>{{ admin_user.name }}</b></span>
|
<span class="label"><b>{{ admin_user.name }}</b></span>
|
||||||
|
@ -77,7 +77,7 @@
|
||||||
</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 panel-primary">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<i class="fa fa-info-circle"></i> {% trans 'Quick update' %}
|
<i class="fa fa-info-circle"></i> {% trans 'Quick update' %}
|
||||||
|
@ -86,15 +86,7 @@
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="no-borders-tr">
|
<tr class="no-borders-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>
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td width="50%">{% trans 'Reset password' %}:</td>
|
|
||||||
<td>
|
<td>
|
||||||
<span style="float: right">
|
<span style="float: right">
|
||||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Reset' %}</button>
|
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Reset' %}</button>
|
||||||
|
@ -164,49 +156,6 @@ function objectRemove(obj, name, url, data) {
|
||||||
doRemove()
|
doRemove()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
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 adminUserDelete(name, url) {
|
||||||
function doDelete() {
|
function doDelete() {
|
||||||
|
@ -239,89 +188,12 @@ $(document).ready(function () {
|
||||||
doDelete()
|
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 = {};
|
jumpserver.assets_selected = {};
|
||||||
var $data_table = $("#system_user_assets_table").DataTable();
|
jumpserver.asset_groups_selected = {};
|
||||||
var asset_groups = [];
|
$(document).ready(function () {
|
||||||
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-delete-admin-user', function () {
|
||||||
.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 () {
|
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
var name = "{{ admin_user.name }}";
|
var name = "{{ admin_user.name }}";
|
||||||
var uid = "{{ admin_user.id }}";
|
var uid = "{{ admin_user.id }}";
|
||||||
|
|
|
@ -2,8 +2,15 @@
|
||||||
{% load i18n static %}
|
{% load i18n static %}
|
||||||
{% block table_search %}
|
{% block table_search %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block help_message %}
|
||||||
|
<div class="alert alert-info help-message">
|
||||||
|
管理用户是 服务器上已存在的特权用户,Jumpserver使用该用户来 `推送系统用户`、`获取资产硬件信息`等
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block table_container %}
|
{% 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>
|
<a href="{% url "assets:admin-user-create" %}" class="btn btn-sm btn-primary"> {% trans "Create admin user" %} </a>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-striped table-bordered table-hover " id="admin_user_list_table" >
|
<table class="table table-striped table-bordered table-hover " id="admin_user_list_table" >
|
||||||
|
|
|
@ -20,13 +20,15 @@
|
||||||
{% bootstrap_field form.env layout="horizontal" %}
|
{% bootstrap_field form.env layout="horizontal" %}
|
||||||
|
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
<h3>{% trans 'Group' %}</h3>
|
<h3>{% trans 'Auth' %}</h3>
|
||||||
{% bootstrap_field form.cluster layout="horizontal" %}
|
{% bootstrap_field form.username layout="horizontal" %}
|
||||||
{% bootstrap_field form.groups layout="horizontal" %}
|
{% bootstrap_field form.password layout="horizontal" %}
|
||||||
|
{% bootstrap_field form.private_key_file layout="horizontal" %}
|
||||||
|
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
<h3>{% trans 'Asset user' %}</h3>
|
<h3>{% trans 'Cluster and group' %}</h3>
|
||||||
{% bootstrap_field form.admin_user layout="horizontal" %}
|
{% bootstrap_field form.cluster layout="horizontal" %}
|
||||||
|
{% bootstrap_field form.groups layout="horizontal" %}
|
||||||
|
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
<h3>{% trans 'Other' %}</h3>
|
<h3>{% trans 'Other' %}</h3>
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
<li class="active">
|
<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>
|
<a href="{% url 'assets:asset-detail' pk=asset.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Asset detail' %} </a>
|
||||||
</li>
|
</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 %}
|
{% if user.is_superuser %}
|
||||||
<li class="pull-right">
|
<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>
|
<a class="btn btn-outline btn-default" href="{% url 'assets:asset-update' pk=asset.id %}"><i class="fa fa-edit"></i>Update</a>
|
||||||
|
@ -173,7 +176,8 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="no-borders-tr">
|
<tr class="no-borders-tr">
|
||||||
<td width="50%">{% trans 'Active' %}:</td>
|
<td width="50%">{% trans 'Active' %}:</td>
|
||||||
<td><span class="pull-right">
|
<td>
|
||||||
|
<span class="pull-right">
|
||||||
<div class="switch">
|
<div class="switch">
|
||||||
<div class="onoffswitch">
|
<div class="onoffswitch">
|
||||||
<input type="checkbox" {% if asset.is_active %} checked {% endif %} class="onoffswitch-checkbox" id="is_active">
|
<input type="checkbox" {% if asset.is_active %} checked {% endif %} class="onoffswitch-checkbox" id="is_active">
|
||||||
|
@ -183,7 +187,8 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</span></td>
|
</span>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Refresh hardware' %}:</td>
|
<td>{% trans 'Refresh hardware' %}:</td>
|
||||||
|
@ -194,10 +199,10 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Test admin user' %}:</td>
|
<td>{% trans 'Reset auth' %}:</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="pull-right">
|
<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>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -242,41 +247,6 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</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 %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -30,26 +30,25 @@
|
||||||
<div class="panel blank-panel">
|
<div class="panel blank-panel">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="tab-content">
|
<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">
|
<form id="groupForm" method="post" class="form-horizontal">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<h3 class="widget-head-color-box">资产组信息</h3>
|
<h3 class="widget-head-color-box">资产组信息</h3>
|
||||||
{% bootstrap_field form.name layout="horizontal" %}
|
{% bootstrap_field form.name layout="horizontal" %}
|
||||||
{% bootstrap_field form.comment layout="horizontal" %}
|
{% bootstrap_field form.comment layout="horizontal" %}
|
||||||
<div class="hr-line-dashed"></div>
|
{# <div class="hr-line-dashed"></div>#}
|
||||||
<h3 class="widget-head-color-box">用户选择的资产</h3>
|
{# <h3 class="widget-head-color-box">用户选择的资产</h3>#}
|
||||||
<div class="form-group">
|
{# <div class="form-group">#}
|
||||||
<label class="col-sm-2 control-label" id="asset_on_count">已选({{ assets_count }})</label>
|
{# <label class="col-sm-2 control-label" id="asset_on_count">已选({{ assets_count }})</label>#}
|
||||||
<div class="col-sm-9" id="asset_sed">
|
{# <div class="col-sm-9" id="asset_sed">#}
|
||||||
<div class="form-asset-on" id="add_asset">
|
{# <div class="form-asset-on" id="add_asset">#}
|
||||||
<p id="asset_on_p">
|
{# <p id="asset_on_p">#}
|
||||||
{% for asset in assets_on_list %}
|
{# {% for asset in assets_on_list %}#}
|
||||||
<button name='asset_hostname' title='{{ asset.ip }}' type='button' class='btn btn-default btn-xs'>{{ asset.hostname }}</button>
|
{# <button name='asset_hostname' title='{{ asset.ip }}' type='button' class='btn btn-default btn-xs'>{{ asset.hostname }}</button>#}
|
||||||
{% endfor %}
|
{# {% endfor %}#}
|
||||||
</p>
|
{# </p>#}
|
||||||
</div>
|
{# </div>#}
|
||||||
</div>
|
{# </div>#}
|
||||||
</div>
|
{# </div>#}
|
||||||
<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-5">
|
<div class="col-sm-4 col-sm-offset-5">
|
||||||
|
@ -67,7 +66,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 模态框(Modal) -->
|
<!-- 模态框(Modal) -->
|
||||||
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||||
|
|
|
@ -13,17 +13,17 @@
|
||||||
<div class="ibox float-e-margins">
|
<div class="ibox float-e-margins">
|
||||||
<div class="panel-options">
|
<div class="panel-options">
|
||||||
<ul class="nav nav-tabs">
|
<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">
|
<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>
|
<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>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<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 float-e-margins">
|
||||||
<div class="ibox-title">
|
<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">
|
<div class="ibox-tools">
|
||||||
<a class="collapse-link">
|
<a class="collapse-link">
|
||||||
<i class="fa fa-chevron-up"></i>
|
<i class="fa fa-chevron-up"></i>
|
||||||
|
@ -56,11 +56,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
|
||||||
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
|
|
||||||
<div class="panel panel-primary">
|
<div class="panel panel-primary">
|
||||||
<div class="panel-heading">
|
<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>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
|
@ -68,7 +67,7 @@
|
||||||
<form>
|
<form>
|
||||||
<tr class="no-borders-tr">
|
<tr class="no-borders-tr">
|
||||||
<td colspan="2">
|
<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 %}
|
{% for system_user in system_users %}
|
||||||
<option value="{{ system_user.id }}"> {{ system_user.name }} </option>
|
<option value="{{ system_user.id }}"> {{ system_user.name }} </option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -91,8 +90,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{# </div>#}
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script>
|
<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) {
|
Array.prototype.remove = function(val) {
|
||||||
var index = this.indexOf(val);
|
var index = this.indexOf(val);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
|
@ -189,20 +167,7 @@ Array.prototype.unique = function(){
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
$(document).ready(function () {
|
function initTable() {
|
||||||
$('.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 = {
|
var options = {
|
||||||
ele: $('#asset_list_table'),
|
ele: $('#asset_list_table'),
|
||||||
buttons: [],
|
buttons: [],
|
||||||
|
@ -231,6 +196,24 @@ $(document).ready(function () {
|
||||||
op_html: $('#actions').html()
|
op_html: $('#actions').html()
|
||||||
};
|
};
|
||||||
jumpserver.initDataTable(options);
|
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 () {
|
.on('click', ".btn-asset-group-add-asset", function () {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
{% block table_search %}
|
{% block table_search %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block table_container %}
|
{% 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>
|
<a href="{% url "assets:asset-group-create" %}" class="btn btn-sm btn-primary"> {% trans "Create asset group" %} </a>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-striped table-bordered table-hover " id="asset_groups_list_table" >
|
<table class="table table-striped table-bordered table-hover " id="asset_groups_list_table" >
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block table_container %}
|
{% 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" >
|
<table class="table table-striped table-bordered table-hover " id="asset_list_table" >
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -24,14 +24,10 @@
|
||||||
{% bootstrap_field form.type layout="horizontal" %}
|
{% bootstrap_field form.type layout="horizontal" %}
|
||||||
|
|
||||||
<div class="hr-line-dashed"></div>
|
<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.cluster layout="horizontal" %}
|
||||||
{% bootstrap_field form.groups 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>
|
<div class="hr-line-dashed"></div>
|
||||||
<h3>{% trans 'Configuration' %}</h3>
|
<h3>{% trans 'Configuration' %}</h3>
|
||||||
{% bootstrap_field form.number layout="horizontal" %}
|
{% bootstrap_field form.number layout="horizontal" %}
|
||||||
|
|
|
@ -25,10 +25,10 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<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 float-e-margins">
|
||||||
<div class="ibox-title">
|
<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">
|
<div class="ibox-tools">
|
||||||
<a class="collapse-link">
|
<a class="collapse-link">
|
||||||
<i class="fa fa-chevron-up"></i>
|
<i class="fa fa-chevron-up"></i>
|
||||||
|
@ -61,23 +61,10 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</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>
|
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
|
|
||||||
<div class="panel panel-primary">
|
<div class="panel panel-primary">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<i class="fa fa-info-circle"></i> {% trans 'Add assets to' %} {{ cluster.name }}
|
<i class="fa fa-info-circle"></i> {% trans 'Add assets to' %} {{ cluster.name }}
|
||||||
|
@ -164,16 +151,7 @@ function deleteClusterAssets(assets) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
function initTable() {
|
||||||
$('.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 = {
|
var options = {
|
||||||
ele: $('#cluster_assets_table'),
|
ele: $('#cluster_assets_table'),
|
||||||
buttons: [],
|
buttons: [],
|
||||||
|
@ -196,7 +174,19 @@ $(document).ready(function () {
|
||||||
op_html: $('#actions').html()
|
op_html: $('#actions').html()
|
||||||
};
|
};
|
||||||
jumpserver.initDataTable(options);
|
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 () {
|
.on('click', '.btn-asset-attach', function () {
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<h3 class="widget-head-color-box">基本信息</h3>
|
<h3 class="widget-head-color-box">基本信息</h3>
|
||||||
{% bootstrap_field form.name layout="horizontal" %}
|
{% bootstrap_field form.name layout="horizontal" %}
|
||||||
|
{% bootstrap_field form.admin_user layout="horizontal" %}
|
||||||
{% bootstrap_field form.address layout="horizontal" %}
|
{% bootstrap_field form.address layout="horizontal" %}
|
||||||
{% bootstrap_field form.contact layout="horizontal" %}
|
{% bootstrap_field form.contact layout="horizontal" %}
|
||||||
{% bootstrap_field form.phone layout="horizontal" %}
|
{% bootstrap_field form.phone layout="horizontal" %}
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<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 float-e-margins">
|
||||||
<div class="ibox-title">
|
<div class="ibox-title">
|
||||||
<span class="label"><b>{{ cluster.name }}</b></span>
|
<span class="label"><b>{{ cluster.name }}</b></span>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block table_search %}{% endblock %}
|
{% block table_search %}{% endblock %}
|
||||||
{% block table_container %}
|
{% 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>
|
<a href="{% url "assets:cluster-create" %}" class="btn btn-sm btn-primary"> {% trans "Create Cluster" %} </a>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-striped table-bordered table-hover " id="cluster_list_table" >
|
<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" >
|
<input type="checkbox" id="check_all" class="ipt_check_all" >
|
||||||
</th>
|
</th>
|
||||||
<th class="text-center"><a href="{% url 'assets:cluster-list' %}?sort=name">{% trans 'Name' %}</a></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 'Asset num' %}</th>
|
||||||
<th class="text-center">{% trans 'Contact' %}</th>
|
<th class="text-center">{% trans 'Contact' %}</th>
|
||||||
<th class="text-center">{% trans 'Phone' %}</th>
|
<th class="text-center">{% trans 'Phone' %}</th>
|
||||||
|
@ -51,13 +52,13 @@ $(document).ready(function(){
|
||||||
$(td).html(detail_btn.replace('99991937', rowData.id));
|
$(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 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);
|
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)
|
$(td).html(update_btn + del_btn)
|
||||||
}}],
|
}}],
|
||||||
ajax_url: '{% url "api-assets:cluster-list" %}',
|
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" }],
|
{data: "operator" }, {data: "id" }],
|
||||||
op_html: $('#actions').html()
|
op_html: $('#actions').html()
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<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 float-e-margins">
|
||||||
<div class="ibox-title">
|
<div class="ibox-title">
|
||||||
<span style="float: left">{% trans 'Assets of ' %} <b>{{ system_user.name }} </b><span class="badge">{{ paginator.count }}</span></span>
|
<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 'IP' %}</th>
|
||||||
<th>{% trans 'Port' %}</th>
|
<th>{% trans 'Port' %}</th>
|
||||||
<th>{% trans 'Reachable' %}</th>
|
<th>{% trans 'Reachable' %}</th>
|
||||||
<th>{% trans 'Action' %}</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<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>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</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 panel-primary">
|
||||||
<div class="panel-heading">
|
<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>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<form>
|
|
||||||
<tr class="no-borders-tr">
|
<tr class="no-borders-tr">
|
||||||
<td colspan="2">
|
<td width="50%">{% trans 'Push system user manually' %}:</td>
|
||||||
<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>
|
<td>
|
||||||
<button class="btn btn-danger pull-right btn-xs btn-leave-system_user" type="button"><i class="fa fa-minus"></i></button>
|
<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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
@ -142,8 +90,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script>
|
<script>
|
||||||
|
@ -166,6 +112,30 @@ Array.prototype.unique = function(){
|
||||||
}
|
}
|
||||||
return res;
|
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 objectDelete(obj, name, url, data) {
|
||||||
function doDelete() {
|
function doDelete() {
|
||||||
var body = data;
|
var body = data;
|
||||||
|
@ -234,33 +204,7 @@ $(document).ready(function () {
|
||||||
delete jumpserver.assets_selected[data.id];
|
delete jumpserver.assets_selected[data.id];
|
||||||
delete jumpserver.asset_groups_selected[data.id];
|
delete jumpserver.asset_groups_selected[data.id];
|
||||||
});
|
});
|
||||||
var options = {
|
initAssetsTable();
|
||||||
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);
|
|
||||||
})
|
})
|
||||||
|
|
||||||
.on('click', '.btn-add-asset2system-user', function () {
|
.on('click', '.btn-add-asset2system-user', function () {
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<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 float-e-margins">
|
||||||
<div class="ibox-title">
|
<div class="ibox-title">
|
||||||
<span class="label"><b>{{ system_user.name }}</b></span>
|
<span class="label"><b>{{ system_user.name }}</b></span>
|
||||||
|
@ -105,7 +105,7 @@
|
||||||
</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 panel-primary">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<i class="fa fa-info-circle"></i> {% trans 'Quick update' %}
|
<i class="fa fa-info-circle"></i> {% trans 'Quick update' %}
|
||||||
|
@ -114,25 +114,23 @@
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="no-borders-tr">
|
<tr class="no-borders-tr">
|
||||||
<td width="50%">{% trans 'Get manual install script' %}:</td>
|
<td width="50%">{% trans 'Auto push' %}:</td>
|
||||||
<td>
|
<td>
|
||||||
<span style="float: right">
|
<span class="pull-right">
|
||||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Get' %}</button>
|
<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>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td width="50%">{% trans 'Retest asset connectivity' %}:</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 'Start' %}</button>
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td width="50%">{% trans 'Reset private key' %}:</td>
|
|
||||||
<td>
|
<td>
|
||||||
<span style="float: right">
|
<span style="float: right">
|
||||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Reset' %}</button>
|
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Reset' %}</button>
|
||||||
|
@ -149,8 +147,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block table_container %}
|
{% 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>
|
<a href="{% url 'assets:system-user-create' %}" class="btn btn-sm btn-primary "> {% trans "Create system user" %} </a>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-striped table-bordered table-hover " id="system_user_list_table" >
|
<table class="table table-striped table-bordered table-hover " id="system_user_list_table" >
|
||||||
|
|
|
@ -4,50 +4,12 @@
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
|
|
||||||
{% block auth %}
|
{% 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 %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script>
|
<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 () {
|
$(document).ready(function () {
|
||||||
$('.select2').select2();
|
$('.select2').select2();
|
||||||
authMethodDisplay();
|
|
||||||
$(auth_method).change(function () {
|
|
||||||
authMethodDisplay();
|
|
||||||
});
|
|
||||||
$(auto_generate_key).change(function () {
|
|
||||||
authMethodDisplay();
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -89,7 +89,10 @@ class AdminUserDetailView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
||||||
return super(AdminUserDetailView, self).get(request, *args, **kwargs)
|
return super(AdminUserDetailView, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_queryset(self):
|
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):
|
def get_context_data(self, **kwargs):
|
||||||
asset_groups = AssetGroup.objects.all()
|
asset_groups = AssetGroup.objects.all()
|
||||||
|
@ -114,9 +117,11 @@ class AdminUserAssetsView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
||||||
return super().get(request, *args, **kwargs)
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
self.queryset = self.object.assets.all()
|
queryset = []
|
||||||
sorted(self.queryset, key=lambda x: x.is_connective() is False)
|
for cluster in self.object.cluster_set.all():
|
||||||
return self.queryset
|
queryset.extend(list(cluster.assets.all()))
|
||||||
|
self.queryset = queryset
|
||||||
|
return queryset
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
|
|
|
@ -183,7 +183,6 @@ class AssetDetailView(DetailView):
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
asset_groups = self.object.groups.all()
|
asset_groups = self.object.groups.all()
|
||||||
system_users = self.object.system_users.all()
|
|
||||||
context = {
|
context = {
|
||||||
'app': 'Assets',
|
'app': 'Assets',
|
||||||
'action': 'Asset detail',
|
'action': 'Asset detail',
|
||||||
|
@ -191,7 +190,6 @@ class AssetDetailView(DetailView):
|
||||||
if asset_group not in asset_groups],
|
if asset_group not in asset_groups],
|
||||||
'asset_groups': asset_groups,
|
'asset_groups': asset_groups,
|
||||||
'system_users_all': SystemUser.objects.all(),
|
'system_users_all': SystemUser.objects.all(),
|
||||||
'system_users': system_users,
|
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super(AssetDetailView, self).get_context_data(**kwargs)
|
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.contrib.messages.views import SuccessMessageMixin
|
||||||
from django.views.generic.detail import DetailView, SingleObjectMixin
|
from django.views.generic.detail import DetailView, SingleObjectMixin
|
||||||
|
|
||||||
from .. import forms
|
from ..forms import SystemUserForm, SystemUserUpdateForm
|
||||||
from ..models import Asset, AssetGroup, SystemUser
|
from ..models import Asset, AssetGroup, SystemUser
|
||||||
from ..hands import AdminUserRequiredMixin
|
from ..hands import AdminUserRequiredMixin
|
||||||
from perms.utils import associate_system_users_and_assets
|
from perms.utils import associate_system_users_and_assets
|
||||||
|
@ -36,7 +36,7 @@ class SystemUserListView(AdminUserRequiredMixin, TemplateView):
|
||||||
|
|
||||||
class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
model = SystemUser
|
model = SystemUser
|
||||||
form_class = forms.SystemUserForm
|
form_class = SystemUserForm
|
||||||
template_name = 'assets/system_user_create.html'
|
template_name = 'assets/system_user_create.html'
|
||||||
success_url = reverse_lazy('assets:system-user-list')
|
success_url = reverse_lazy('assets:system-user-list')
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVi
|
||||||
|
|
||||||
class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView):
|
class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView):
|
||||||
model = SystemUser
|
model = SystemUser
|
||||||
form_class = forms.SystemUserUpdateForm
|
form_class = SystemUserUpdateForm
|
||||||
template_name = 'assets/system_user_update.html'
|
template_name = 'assets/system_user_update.html'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -110,31 +110,16 @@ class SystemUserDeleteView(AdminUserRequiredMixin, DeleteView):
|
||||||
success_url = reverse_lazy('assets:system-user-list')
|
success_url = reverse_lazy('assets:system-user-list')
|
||||||
|
|
||||||
|
|
||||||
class SystemUserAssetView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
class SystemUserAssetView(AdminUserRequiredMixin, DetailView):
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
model = SystemUser
|
||||||
template_name = 'assets/system_user_asset.html'
|
template_name = 'assets/system_user_asset.html'
|
||||||
context_object_name = 'system_user'
|
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):
|
def get_context_data(self, **kwargs):
|
||||||
assets = self.get_queryset()
|
|
||||||
context = {
|
context = {
|
||||||
'app': 'assets',
|
'app': 'assets',
|
||||||
'action': 'System user asset',
|
'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)
|
kwargs.update(context)
|
||||||
return super(SystemUserAssetView, self).get_context_data(**kwargs)
|
return super(SystemUserAssetView, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ class AdHocSerializer(serializers.ModelSerializer):
|
||||||
class AdHocRunHistorySerializer(serializers.ModelSerializer):
|
class AdHocRunHistorySerializer(serializers.ModelSerializer):
|
||||||
task = serializers.SerializerMethodField()
|
task = serializers.SerializerMethodField()
|
||||||
adhoc_short_id = serializers.SerializerMethodField()
|
adhoc_short_id = serializers.SerializerMethodField()
|
||||||
|
stat = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = AdHocRunHistory
|
model = AdHocRunHistory
|
||||||
|
@ -38,6 +39,14 @@ class AdHocRunHistorySerializer(serializers.ModelSerializer):
|
||||||
def get_task(obj):
|
def get_task(obj):
|
||||||
return obj.adhoc.task.id
|
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):
|
def get_field_names(self, declared_fields, info):
|
||||||
fields = super().get_field_names(declared_fields, info)
|
fields = super().get_field_names(declared_fields, info)
|
||||||
fields.extend(['summary', 'short_id'])
|
fields.extend(['summary', 'short_id'])
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
<th>{% trans 'Run as' %}</th>
|
<th>{% trans 'Run as' %}</th>
|
||||||
<th>{% trans 'Become' %}</th>
|
<th>{% trans 'Become' %}</th>
|
||||||
<th>{% trans 'Datetime' %}</th>
|
<th>{% trans 'Datetime' %}</th>
|
||||||
<th></th>
|
<th>{% trans 'Action' %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -104,12 +104,17 @@
|
||||||
} else {
|
} else {
|
||||||
$(td).html(cellData.user)
|
$(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 }}',
|
ajax_url: '{% url "api-ops:adhoc-list" %}?task={{ object.pk }}',
|
||||||
columns: [{data: function(){return ""}}, {data: "short_id" }, {data: "hosts"}, {data: "pattern"},
|
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);
|
jumpserver.initDataTable(options);
|
||||||
})
|
})
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
<div class="col-sm-12" style="padding-left: 0">
|
<div class="col-sm-12" style="padding-left: 0">
|
||||||
<div class="ibox float-e-margins">
|
<div class="ibox float-e-margins">
|
||||||
<div class="ibox-title">
|
<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">
|
<div class="ibox-tools">
|
||||||
<a class="collapse-link">
|
<a class="collapse-link">
|
||||||
<i class="fa fa-chevron-up"></i>
|
<i class="fa fa-chevron-up"></i>
|
||||||
|
@ -57,7 +57,8 @@
|
||||||
<th>{% trans 'Is finished' %}</th>
|
<th>{% trans 'Is finished' %}</th>
|
||||||
<th>{% trans 'Is success' %}</th>
|
<th>{% trans 'Is success' %}</th>
|
||||||
<th>{% trans 'Time' %}</th>
|
<th>{% trans 'Time' %}</th>
|
||||||
<th></th>
|
<th>{% trans 'Version' %}</th>
|
||||||
|
<th>{% trans 'Action' %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -86,10 +87,12 @@
|
||||||
{# var detail_btn = '<a href="' + cellData + '</a>';#}
|
{# var detail_btn = '<a href="' + cellData + '</a>';#}
|
||||||
$(td).html(cellData);
|
$(td).html(cellData);
|
||||||
}},
|
}},
|
||||||
{# {targets: 2, createdCell: function (td, cellData, rowData) {#}
|
{targets: 2, createdCell: function (td, cellData) {
|
||||||
{# var dataLength = cellData.length;#}
|
var total = "<span>" + cellData.total + "</span>";
|
||||||
{# $(td).html(dataLength);#}
|
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) {
|
{targets: 3, createdCell: function (td, cellData) {
|
||||||
if (!cellData) {
|
if (!cellData) {
|
||||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||||
|
@ -110,12 +113,17 @@
|
||||||
} else {
|
} else {
|
||||||
$(td).html("0" + ' s')
|
$(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 }}',
|
ajax_url: '{% url "api-ops:history-list" %}?task={{ object.pk }}',
|
||||||
columns: [{data: function(){return ""}}, {data: "date_start"}, {data: "adhoc_short_id"},
|
columns: [{data: function(){return ""}}, {data: "date_start"}, {data: "stat"}, {data: "adhoc_short_id"},
|
||||||
{data: "adhoc_short_id"}, {data: "adhoc_short_id"}, {data: "timedelta"}]
|
{data: "adhoc_short_id"}, {data: "timedelta"}, {data: 'adhoc_short_id'}, {data: "id"}]
|
||||||
};
|
};
|
||||||
jumpserver.initDataTable(options);
|
jumpserver.initDataTable(options);
|
||||||
})
|
})
|
||||||
|
|
|
@ -277,3 +277,16 @@ div.dataTables_wrapper div.dataTables_filter {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
padding: 5px 12px;
|
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;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
.float-e-margins .btn {
|
.float-e-margins .btn {
|
||||||
margin-bottom: 5px;
|
/*margin-bottom: 5px;*/
|
||||||
}
|
}
|
||||||
.btn-w-m {
|
.btn-w-m {
|
||||||
min-width: 120px;
|
min-width: 120px;
|
||||||
|
@ -3440,13 +3440,13 @@ video {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
.wrapper {
|
.wrapper {
|
||||||
padding: 0 20px;
|
padding: 0 10px;
|
||||||
}
|
}
|
||||||
.wrapper-content {
|
.wrapper-content {
|
||||||
padding: 20px 10px 40px;
|
padding: 10px 10px 10px;
|
||||||
}
|
}
|
||||||
#page-wrapper {
|
#page-wrapper {
|
||||||
padding: 0 15px;
|
padding: 0 10px;
|
||||||
min-height: 568px;
|
min-height: 568px;
|
||||||
position: relative !important;
|
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(){
|
function selectAll(){
|
||||||
// Select all check box
|
// 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) {
|
function getCookie(name) {
|
||||||
var cookieValue = null;
|
var cookieValue = null;
|
||||||
if (document.cookie && document.cookie !== '') {
|
if (document.cookie && document.cookie !== '') {
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
{% include '_message.html' %}
|
{% include '_message.html' %}
|
||||||
{% block first_login_message %}
|
{% block first_login_message %}
|
||||||
{% if user.is_authenticated and user.is_first_login %}
|
{% 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 %}
|
{% url 'users:user-first-login' as first_login_url %}
|
||||||
{% blocktrans %}
|
{% blocktrans %}
|
||||||
Your information was incomplete. Please click <a href="{{ first_login_url }}"> this link </a>to complete your information.
|
Your information was incomplete. Please click <a href="{{ first_login_url }}"> this link </a>to complete your information.
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block update_public_key_message %}
|
{% block update_public_key_message %}
|
||||||
{% if user.is_authenticated and not user.is_public_key_valid %}
|
{% 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 %}
|
{% url 'users:user-pubkey-update' as user_pubkey_update %}
|
||||||
{% blocktrans %}
|
{% blocktrans %}
|
||||||
Your ssh public key not set or expired. Please click <a href="{{ user_pubkey_update }}"> this link </a>to update your
|
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>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
{% block help_message %}{% endblock %}
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
{% include '_footer.html' %}
|
{% include '_footer.html' %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<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 float-e-margins">
|
||||||
<div class="ibox-title">
|
<div class="ibox-title">
|
||||||
<span style="float: left">{% trans 'Asset permission of ' %} <b>{{ user.name }}</b></span>
|
<span style="float: left">{% trans 'Asset permission of ' %} <b>{{ user.name }}</b></span>
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
</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 panel-primary">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<i class="fa fa-info-circle"></i> {% trans 'Quick create permission for user' %}
|
<i class="fa fa-info-circle"></i> {% trans 'Quick create permission for user' %}
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<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 float-e-margins">
|
||||||
<div class="ibox-title">
|
<div class="ibox-title">
|
||||||
<span style="float: left">{% trans 'Assets granted of ' %} <b>{{ user_group.name }}</b></span>
|
<span style="float: left">{% trans 'Assets granted of ' %} <b>{{ user_group.name }}</b></span>
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
</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="ibox float-e-margins">
|
<div class="ibox float-e-margins">
|
||||||
<div class="ibox-title">
|
<div class="ibox-title">
|
||||||
<span style="float: left">{% trans 'Asset groups granted of ' %} <b>{{ user_group.name }}</b></span>
|
<span style="float: left">{% trans 'Asset groups granted of ' %} <b>{{ user_group.name }}</b></span>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block table_container %}
|
{% 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" >
|
<table class="table table-striped table-bordered table-hover " id="user_list_table" >
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
Loading…
Reference in New Issue