Commit cbc00069 authored by ibuler's avatar ibuler

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

parent 0c9e24dc
...@@ -39,21 +39,20 @@ class AssetViewSet(IDInFilterMixin, BulkModelViewSet): ...@@ -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__) ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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 @@ ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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__) ...@@ -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): ...@@ -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,23 +8,16 @@ import logging ...@@ -8,23 +8,16 @@ 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']
logger = logging.getLogger(__name__)
def private_key_validator(value): __all__ = ['AdminUser', 'SystemUser',]
if not validate_ssh_private_key(value): logger = logging.getLogger(__name__)
raise ValidationError(
_('%(value)s is not an even number'),
params={'value': value},
)
class AdminUser(models.Model): class AdminUser(models.Model):
...@@ -103,10 +96,12 @@ class AdminUser(models.Model): ...@@ -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): ...@@ -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 @@ ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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 @@ ...@@ -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 %}
......
...@@ -31,7 +31,7 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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,164 +156,44 @@ function objectRemove(obj, name, url, data) { ...@@ -164,164 +156,44 @@ function objectRemove(obj, name, url, data) {
doRemove() 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.assets_selected = {};
jumpserver.asset_groups_selected = {}; jumpserver.asset_groups_selected = {};
$(document).ready(function () { $(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-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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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,17 +176,19 @@ ...@@ -173,17 +176,19 @@
<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>
<div class="switch"> <span class="pull-right">
<div class="onoffswitch"> <div class="switch">
<input type="checkbox" {% if asset.is_active %} checked {% endif %} class="onoffswitch-checkbox" id="is_active"> <div class="onoffswitch">
<label class="onoffswitch-label" for="is_active"> <input type="checkbox" {% if asset.is_active %} checked {% endif %} class="onoffswitch-checkbox" id="is_active">
<span class="onoffswitch-inner"></span> <label class="onoffswitch-label" for="is_active">
<span class="onoffswitch-switch"></span> <span class="onoffswitch-inner"></span>
</label> <span class="onoffswitch-switch"></span>
</div> </label>
</div> </div>
</span></td> </div>
</span>
</td>
</tr> </tr>
<tr> <tr>
<td>{% trans 'Refresh hardware' %}:</td> <td>{% trans 'Refresh hardware' %}:</td>
...@@ -194,10 +199,10 @@ ...@@ -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 @@ ...@@ -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,36 +30,34 @@ ...@@ -30,36 +30,34 @@
<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"> <button class="btn btn-white" type="reset"> 重置 </button>
<button class="btn btn-white" type="reset"> 重置 </button> <button class="btn btn-primary" type="submit"> 提交 </button>
<button class="btn btn-primary" type="submit"> 提交 </button> <div id='box2'> </div>
<div id='box2'> </div>
</div>
</div> </div>
</form> </div>
</div> </form>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -13,17 +13,17 @@ ...@@ -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>
...@@ -45,9 +45,9 @@ ...@@ -45,9 +45,9 @@
<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 'Type' %}</th> <th>{% trans 'Type' %}</th>
<th>{% trans 'Alive' %}</th> <th>{% trans 'Alive' %}</th>
<th>{% trans 'Action' %}</th> <th>{% trans 'Action' %}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
...@@ -56,11 +56,10 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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) { ...@@ -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,21 +167,8 @@ Array.prototype.unique = function(){ ...@@ -189,21 +167,8 @@ Array.prototype.unique = function(){
return res; return res;
}; };
$(document).ready(function () { function initTable() {
$('.select2').select2(); var options = {
$('.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 = {
ele: $('#asset_list_table'), ele: $('#asset_list_table'),
buttons: [], buttons: [],
order: [], order: [],
...@@ -231,6 +196,24 @@ $(document).ready(function () { ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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> </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 'Add assets to' %} {{ cluster.name }} <i class="fa fa-info-circle"></i> {% trans 'Add assets to' %} {{ cluster.name }}
...@@ -164,17 +151,8 @@ function deleteClusterAssets(assets) { ...@@ -164,17 +151,8 @@ function deleteClusterAssets(assets) {
}); });
} }
$(document).ready(function () { function initTable() {
$('.select2').select2() var options = {
.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 = {
ele: $('#cluster_assets_table'), ele: $('#cluster_assets_table'),
buttons: [], buttons: [],
order: [], order: [],
...@@ -196,7 +174,19 @@ $(document).ready(function () { ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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(){ ...@@ -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()
}; };
......
...@@ -28,7 +28,7 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 %}
\ No newline at end of file
...@@ -89,7 +89,10 @@ class AdminUserDetailView(AdminUserRequiredMixin, SingleObjectMixin, ListView): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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 ...@@ -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): ...@@ -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 ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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
}
\ No newline at end of file
...@@ -591,7 +591,7 @@ body.canvas-menu.mini-navbar nav.navbar-static-side { ...@@ -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 { ...@@ -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) { ...@@ -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(){ ...@@ -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 !== '') {
...@@ -289,7 +256,7 @@ jumpserver.initDataTable = function (options) { ...@@ -289,7 +256,7 @@ jumpserver.initDataTable = function (options) {
createdCell: function(td, cellData) { createdCell: function(td, cellData) {
$(td).html('<input type="checkbox" class="text-center ipt_check" id=99991937>'.replace('99991937', 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; columnDefs = options.columnDefs ? options.columnDefs.concat(columnDefs) : columnDefs;
var table = ele.DataTable({ var table = ele.DataTable({
......
...@@ -22,7 +22,7 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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>
......
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