Commit cbc00069 authored by ibuler's avatar ibuler

[Feature] 修改adminuser systemuser cluster及他们的关系

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