mirror of https://github.com/jumpserver/jumpserver
Merge remote-tracking branch 'origin/dev' into dev
commit
7f3d32a876
|
@ -26,7 +26,7 @@ from .hands import IsSuperUser, IsValidUser, IsSuperUserOrAppUser, \
|
||||||
get_user_granted_assets
|
get_user_granted_assets
|
||||||
from .models import AssetGroup, Asset, Cluster, SystemUser, AdminUser
|
from .models import AssetGroup, Asset, Cluster, SystemUser, AdminUser
|
||||||
from . import serializers
|
from . import serializers
|
||||||
from .tasks import update_asset_hardware_info_manual, test_admin_user_connectability_util, \
|
from .tasks import update_asset_hardware_info_manual, test_admin_user_connectability_manual, \
|
||||||
test_asset_connectability_manual, push_system_user_to_cluster_assets_manual, \
|
test_asset_connectability_manual, push_system_user_to_cluster_assets_manual, \
|
||||||
test_system_user_connectability_manual
|
test_system_user_connectability_manual
|
||||||
|
|
||||||
|
@ -40,18 +40,14 @@ class AssetViewSet(IDInFilterMixin, BulkModelViewSet):
|
||||||
"""
|
"""
|
||||||
queryset = Asset.objects.all()
|
queryset = Asset.objects.all()
|
||||||
serializer_class = serializers.AssetSerializer
|
serializer_class = serializers.AssetSerializer
|
||||||
permission_classes = (IsValidUser,)
|
permission_classes = (IsSuperUserOrAppUser,)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
if self.request.user.is_superuser or self.request.user.is_app:
|
queryset = super().get_queryset()
|
||||||
queryset = super().get_queryset()
|
|
||||||
else:
|
|
||||||
assets_granted = get_user_granted_assets(self.request.user)
|
|
||||||
queryset = self.queryset.filter(id__in=[asset.id for asset in assets_granted])
|
|
||||||
|
|
||||||
cluster_id = self.request.query_params.get('cluster_id')
|
cluster_id = self.request.query_params.get('cluster_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')
|
||||||
|
system_user_id = self.request.query_params.get('system_user_id')
|
||||||
|
|
||||||
if cluster_id:
|
if cluster_id:
|
||||||
queryset = queryset.filter(cluster__id=cluster_id)
|
queryset = queryset.filter(cluster__id=cluster_id)
|
||||||
|
@ -62,6 +58,23 @@ class AssetViewSet(IDInFilterMixin, BulkModelViewSet):
|
||||||
assets_direct = [asset.id for asset in admin_user.asset_set.all()]
|
assets_direct = [asset.id for asset in admin_user.asset_set.all()]
|
||||||
clusters = [cluster.id for cluster in admin_user.cluster_set.all()]
|
clusters = [cluster.id for cluster in admin_user.cluster_set.all()]
|
||||||
queryset = queryset.filter(Q(cluster__id__in=clusters)|Q(id__in=assets_direct))
|
queryset = queryset.filter(Q(cluster__id__in=clusters)|Q(id__in=assets_direct))
|
||||||
|
if system_user_id:
|
||||||
|
system_user = get_object_or_404(SystemUser, id=system_user_id)
|
||||||
|
clusters = system_user.get_clusters()
|
||||||
|
queryset = queryset.filter(cluster__in=clusters)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
class UserAssetListView(generics.ListAPIView):
|
||||||
|
queryset = Asset.objects.all()
|
||||||
|
serializer_class = serializers.AssetSerializer
|
||||||
|
permission_classes = (IsValidUser,)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
assets_granted = get_user_granted_assets(self.request.user)
|
||||||
|
queryset = self.queryset.filter(
|
||||||
|
id__in=[asset.id for asset in assets_granted]
|
||||||
|
)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,15 +112,6 @@ class GroupAddAssetsApi(generics.UpdateAPIView):
|
||||||
return Response({'error': serializer.errors}, status=400)
|
return Response({'error': serializer.errors}, status=400)
|
||||||
|
|
||||||
|
|
||||||
class ClusterUpdateAssetsApi(generics.RetrieveUpdateAPIView):
|
|
||||||
"""
|
|
||||||
Cluster update asset member
|
|
||||||
"""
|
|
||||||
queryset = Cluster.objects.all()
|
|
||||||
serializer_class = serializers.ClusterUpdateAssetsSerializer
|
|
||||||
permission_classes = (IsSuperUser,)
|
|
||||||
|
|
||||||
|
|
||||||
class ClusterViewSet(IDInFilterMixin, BulkModelViewSet):
|
class ClusterViewSet(IDInFilterMixin, BulkModelViewSet):
|
||||||
"""
|
"""
|
||||||
Cluster api set, for add,delete,update,list,retrieve resource
|
Cluster api set, for add,delete,update,list,retrieve resource
|
||||||
|
@ -117,7 +121,6 @@ class ClusterViewSet(IDInFilterMixin, BulkModelViewSet):
|
||||||
permission_classes = (IsSuperUser,)
|
permission_classes = (IsSuperUser,)
|
||||||
|
|
||||||
|
|
||||||
# TOdo
|
|
||||||
class ClusterTestAssetsAliveApi(generics.RetrieveAPIView):
|
class ClusterTestAssetsAliveApi(generics.RetrieveAPIView):
|
||||||
"""
|
"""
|
||||||
Test cluster asset can connect using admin user or not
|
Test cluster asset can connect using admin user or not
|
||||||
|
@ -127,6 +130,9 @@ class ClusterTestAssetsAliveApi(generics.RetrieveAPIView):
|
||||||
|
|
||||||
def retrieve(self, request, *args, **kwargs):
|
def retrieve(self, request, *args, **kwargs):
|
||||||
cluster = self.get_object()
|
cluster = self.get_object()
|
||||||
|
admin_user = cluster.admin_user
|
||||||
|
test_admin_user_connectability_manual.delay(admin_user)
|
||||||
|
return Response("Task has been send, seen left assets status")
|
||||||
|
|
||||||
|
|
||||||
class ClusterAddAssetsApi(generics.UpdateAPIView):
|
class ClusterAddAssetsApi(generics.UpdateAPIView):
|
||||||
|
@ -256,7 +262,7 @@ class AdminUserTestConnectiveApi(generics.RetrieveAPIView):
|
||||||
|
|
||||||
def retrieve(self, request, *args, **kwargs):
|
def retrieve(self, request, *args, **kwargs):
|
||||||
admin_user = self.get_object()
|
admin_user = self.get_object()
|
||||||
test_admin_user_connectability_util.delay(admin_user)
|
test_admin_user_connectability_manual.delay(admin_user)
|
||||||
return Response({"msg": "Task created"})
|
return Response({"msg": "Task created"})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ class AssetCreateForm(forms.ModelForm):
|
||||||
def clean_admin_user(self):
|
def clean_admin_user(self):
|
||||||
cluster = self.cleaned_data.get('cluster')
|
cluster = self.cleaned_data.get('cluster')
|
||||||
admin_user = self.cleaned_data.get('admin_user')
|
admin_user = self.cleaned_data.get('admin_user')
|
||||||
if not cluster.admin_user and not admin_user:
|
if not admin_user and (cluster and not cluster.admin_user):
|
||||||
raise forms.ValidationError(_("You need set a admin user if cluster not have"))
|
raise forms.ValidationError(_("You need set a admin user if cluster not have"))
|
||||||
return self.cleaned_data['admin_user']
|
return self.cleaned_data['admin_user']
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ class AssetUpdateForm(forms.ModelForm):
|
||||||
def clean_admin_user(self):
|
def clean_admin_user(self):
|
||||||
cluster = self.cleaned_data.get('cluster')
|
cluster = self.cleaned_data.get('cluster')
|
||||||
admin_user = self.cleaned_data.get('admin_user')
|
admin_user = self.cleaned_data.get('admin_user')
|
||||||
if not cluster.admin_user and not admin_user:
|
if not admin_user and (cluster and not cluster.admin_user):
|
||||||
raise forms.ValidationError(_("You need set a admin user if cluster not have"))
|
raise forms.ValidationError(_("You need set a admin user if cluster not have"))
|
||||||
return self.cleaned_data['admin_user']
|
return self.cleaned_data['admin_user']
|
||||||
|
|
||||||
|
@ -124,20 +124,25 @@ class AssetGroupForm(forms.ModelForm):
|
||||||
label=_('Asset'),
|
label=_('Asset'),
|
||||||
required=False,
|
required=False,
|
||||||
widget=forms.SelectMultiple(
|
widget=forms.SelectMultiple(
|
||||||
attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
|
attrs={'class': 'select2', 'data-placeholder': _('Select assets')}
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
if kwargs.get('instance', None):
|
instance = kwargs.get('instance')
|
||||||
|
if instance:
|
||||||
initial = kwargs.get('initial', {})
|
initial = kwargs.get('initial', {})
|
||||||
initial['assets'] = kwargs['instance'].assets.all()
|
initial.update({
|
||||||
super(AssetGroupForm, self).__init__(*args, **kwargs)
|
'assets': instance.assets.all(),
|
||||||
|
})
|
||||||
|
kwargs['initial'] = initial
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
def _save_m2m(self):
|
def save(self, commit=True):
|
||||||
super(AssetGroupForm, self)._save_m2m()
|
group = super().save(commit=commit)
|
||||||
assets = self.cleaned_data['assets']
|
assets= self.cleaned_data['assets']
|
||||||
self.instance.assets.clear()
|
group.assets.set(assets)
|
||||||
self.instance.assets.add(*tuple(assets))
|
return group
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = AssetGroup
|
model = AssetGroup
|
||||||
|
@ -150,10 +155,19 @@ class AssetGroupForm(forms.ModelForm):
|
||||||
|
|
||||||
|
|
||||||
class ClusterForm(forms.ModelForm):
|
class ClusterForm(forms.ModelForm):
|
||||||
|
system_users = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=SystemUser.objects.all(),
|
||||||
|
widget=forms.SelectMultiple(
|
||||||
|
attrs={'class': 'select2', 'data-placeholder': _('Select system users')}
|
||||||
|
),
|
||||||
|
label=_('System users'),
|
||||||
|
required=False,
|
||||||
|
help_text=_("Selected system users will be create at cluster assets"),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Cluster
|
model = Cluster
|
||||||
fields = ['name', "bandwidth", "operator", 'contact', 'admin_user',
|
fields = ['name', "bandwidth", "operator", 'contact', 'admin_user', 'system_users',
|
||||||
'phone', 'address', 'intranet', 'extranet', 'comment']
|
'phone', 'address', 'intranet', 'extranet', 'comment']
|
||||||
widgets = {
|
widgets = {
|
||||||
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
|
'name': forms.TextInput(attrs={'placeholder': _('Name')}),
|
||||||
|
@ -162,9 +176,21 @@ class ClusterForm(forms.ModelForm):
|
||||||
}
|
}
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'name': '* required',
|
'name': '* required',
|
||||||
'admin_user': 'The assets of this cluster will use this admin user as his admin user',
|
'admin_user': _("Cluster level admin user"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
if kwargs.get('instance', None):
|
||||||
|
initial = kwargs.get('initial', {})
|
||||||
|
initial['system_users'] = kwargs['instance'].systemuser_set.all()
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def save(self, commit=True):
|
||||||
|
instance = super().save(commit=commit)
|
||||||
|
system_users = self.cleaned_data['system_users']
|
||||||
|
instance.systemuser_set.set(system_users)
|
||||||
|
return instance
|
||||||
|
|
||||||
|
|
||||||
class AdminUserForm(forms.ModelForm):
|
class AdminUserForm(forms.ModelForm):
|
||||||
# Form field name can not start with `_`, so redefine it,
|
# Form field name can not start with `_`, so redefine it,
|
||||||
|
@ -172,9 +198,10 @@ class AdminUserForm(forms.ModelForm):
|
||||||
widget=forms.PasswordInput, max_length=128,
|
widget=forms.PasswordInput, max_length=128,
|
||||||
strip=True, required=False,
|
strip=True, required=False,
|
||||||
help_text=_('Password or private key password'),
|
help_text=_('Password or private key password'),
|
||||||
|
label=_("Password"),
|
||||||
)
|
)
|
||||||
# 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, label=_("Private key"))
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
# Because we define custom field, so we need rewrite :method: `save`
|
# Because we define custom field, so we need rewrite :method: `save`
|
||||||
|
@ -204,12 +231,14 @@ class AdminUserForm(forms.ModelForm):
|
||||||
return private_key_file
|
return private_key_file
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
super().clean()
|
||||||
password = self.cleaned_data['password']
|
password = self.cleaned_data['password']
|
||||||
private_key_file = self.cleaned_data.get('private_key_file', '')
|
private_key_file = self.cleaned_data.get('private_key_file', '')
|
||||||
|
|
||||||
if not self.instance and not (password or private_key_file):
|
if not password and not private_key_file:
|
||||||
raise forms.ValidationError(
|
raise forms.ValidationError(_(
|
||||||
_('Password and private key file must be input one'))
|
'Password and private key file must be input one'
|
||||||
|
))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = AdminUser
|
model = AdminUser
|
||||||
|
@ -229,9 +258,10 @@ 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, max_length=128, strip=True)
|
password = forms.CharField(widget=forms.PasswordInput, required=False,
|
||||||
|
max_length=128, strip=True, label=_("Password"))
|
||||||
# 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, label=_("Private key"))
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
# Because we define custom field, so we need rewrite :method: `save`
|
# Because we define custom field, so we need rewrite :method: `save`
|
||||||
|
@ -278,15 +308,18 @@ class SystemUserForm(forms.ModelForm):
|
||||||
'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(
|
'cluster': forms.SelectMultiple(
|
||||||
attrs={'class': 'select2',
|
attrs={
|
||||||
'data-placeholder': _(' Select clusters')}),
|
'class': 'select2',
|
||||||
|
'data-placeholder': _(' Select clusters')
|
||||||
|
}
|
||||||
|
),
|
||||||
}
|
}
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'name': '* required',
|
'name': '* required',
|
||||||
'username': '* required',
|
'username': '* required',
|
||||||
'cluster': 'If auto push checked, system user will be create at cluster assets',
|
'cluster': _('If auto push checked, system user will be create at cluster assets'),
|
||||||
'auto_push': 'Auto push system user to asset',
|
'auto_push': _('Auto push system user to asset'),
|
||||||
'priority': 'High level will be using login asset as default, if user was granted more than 2 system user',
|
'priority': _('High level will be using login asset as default, if user was granted more than 2 system user'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,16 @@ __all__ = ['Asset']
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def default_cluster():
|
||||||
|
from .cluster import Cluster
|
||||||
|
name = "Default"
|
||||||
|
defaults = {"name": name}
|
||||||
|
cluster, created = Cluster.objects.get_or_create(
|
||||||
|
defaults=defaults, name=name
|
||||||
|
)
|
||||||
|
return cluster.id
|
||||||
|
|
||||||
|
|
||||||
class Asset(models.Model):
|
class Asset(models.Model):
|
||||||
# Todo: Move them to settings
|
# Todo: Move them to settings
|
||||||
STATUS_CHOICES = (
|
STATUS_CHOICES = (
|
||||||
|
@ -44,7 +54,7 @@ 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'))
|
||||||
cluster = models.ForeignKey(Cluster, blank=True, null=True, related_name='assets', on_delete=models.SET_NULL, verbose_name=_('Cluster'))
|
cluster = models.ForeignKey(Cluster, related_name='assets', default=default_cluster, on_delete=models.SET_DEFAULT, 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'),)
|
||||||
|
@ -158,6 +168,7 @@ class Asset(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ('ip', 'port')
|
unique_together = ('ip', 'port')
|
||||||
|
verbose_name = _("Asset")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_fake(cls, count=100):
|
def generate_fake(cls, count=100):
|
||||||
|
|
|
@ -37,6 +37,7 @@ class Cluster(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['name']
|
ordering = ['name']
|
||||||
|
verbose_name = _("Cluster")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_fake(cls, count=5):
|
def generate_fake(cls, count=5):
|
||||||
|
|
|
@ -27,6 +27,7 @@ class AssetGroup(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['name']
|
ordering = ['name']
|
||||||
|
verbose_name = _("Asset group")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def initial(cls):
|
def initial(cls):
|
||||||
|
|
|
@ -81,7 +81,11 @@ class AssetUser(models.Model):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def public_key(self):
|
def public_key(self):
|
||||||
return signer.unsign(self._public_key)
|
key = signer.unsign(self._public_key)
|
||||||
|
if key:
|
||||||
|
return key
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def public_key_obj(self):
|
def public_key_obj(self):
|
||||||
|
@ -170,7 +174,6 @@ class AdminUser(AssetUser):
|
||||||
info = None
|
info = None
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
def get_related_assets(self):
|
def get_related_assets(self):
|
||||||
assets = []
|
assets = []
|
||||||
for cluster in self.cluster_set.all():
|
for cluster in self.cluster_set.all():
|
||||||
|
@ -184,6 +187,7 @@ class AdminUser(AssetUser):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['name']
|
ordering = ['name']
|
||||||
|
verbose_name = _("Admin user")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_fake(cls, count=10):
|
def generate_fake(cls, count=10):
|
||||||
|
@ -224,7 +228,7 @@ class SystemUser(AssetUser):
|
||||||
|
|
||||||
def get_clusters_assets(self):
|
def get_clusters_assets(self):
|
||||||
from .asset import Asset
|
from .asset import Asset
|
||||||
clusters = self.cluster.all()
|
clusters = self.get_clusters()
|
||||||
return Asset.objects.filter(cluster__in=clusters)
|
return Asset.objects.filter(cluster__in=clusters)
|
||||||
|
|
||||||
def get_clusters(self):
|
def get_clusters(self):
|
||||||
|
@ -262,6 +266,7 @@ class SystemUser(AssetUser):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['name']
|
ordering = ['name']
|
||||||
|
verbose_name = _("System user")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_fake(cls, count=10):
|
def generate_fake(cls, count=10):
|
||||||
|
|
|
@ -64,6 +64,7 @@ class AdminUserSerializer(serializers.ModelSerializer):
|
||||||
"""
|
"""
|
||||||
assets_amount = serializers.SerializerMethodField()
|
assets_amount = serializers.SerializerMethodField()
|
||||||
unreachable_amount = serializers.SerializerMethodField()
|
unreachable_amount = serializers.SerializerMethodField()
|
||||||
|
reachable_amount = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = AdminUser
|
model = AdminUser
|
||||||
|
@ -75,7 +76,15 @@ class AdminUserSerializer(serializers.ModelSerializer):
|
||||||
if data:
|
if data:
|
||||||
return len(data.get('dark'))
|
return len(data.get('dark'))
|
||||||
else:
|
else:
|
||||||
return 'Unknown'
|
return 0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_reachable_amount(obj):
|
||||||
|
data = cache.get(ADMIN_USER_CONN_CACHE_KEY.format(obj.name))
|
||||||
|
if data:
|
||||||
|
return len(data.get('contacted'))
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_assets_amount(obj):
|
def get_assets_amount(obj):
|
||||||
|
@ -183,7 +192,7 @@ class AssetGrantedSerializer(serializers.ModelSerializer):
|
||||||
class Meta(object):
|
class Meta(object):
|
||||||
model = Asset
|
model = Asset
|
||||||
fields = ("id", "hostname", "ip", "port", "system_users_granted",
|
fields = ("id", "hostname", "ip", "port", "system_users_granted",
|
||||||
"is_inherited", "is_active", "system_users_join",
|
"is_inherited", "is_active", "system_users_join", "os",
|
||||||
"platform", "comment",)
|
"platform", "comment",)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -27,16 +27,17 @@ def test_asset_conn_on_created(asset):
|
||||||
|
|
||||||
|
|
||||||
def push_cluster_system_users_to_asset(asset):
|
def push_cluster_system_users_to_asset(asset):
|
||||||
logger.info("Push cluster system user to asset: {}".format(asset))
|
if asset.cluster:
|
||||||
task_name = _("Push cluster system users to asset")
|
logger.info("Push cluster system user to asset: {}".format(asset))
|
||||||
system_users = asset.cluster.systemuser_set.all()
|
task_name = _("Push cluster system users to asset")
|
||||||
push_system_user_util.delay(system_users, [asset], task_name)
|
system_users = asset.cluster.systemuser_set.all()
|
||||||
|
push_system_user_util.delay(system_users, [asset], task_name)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Asset, dispatch_uid="my_unique_identifier")
|
@receiver(post_save, sender=Asset, dispatch_uid="my_unique_identifier")
|
||||||
def on_asset_created(sender, instance=None, created=False, **kwargs):
|
def on_asset_created(sender, instance=None, created=False, **kwargs):
|
||||||
if instance and created:
|
if instance and created:
|
||||||
logger.info("Asset `` create signal received".format(instance))
|
logger.info("Asset `{}` create signal received".format(instance))
|
||||||
update_asset_hardware_info_on_created(instance)
|
update_asset_hardware_info_on_created(instance)
|
||||||
test_asset_conn_on_created(instance)
|
test_asset_conn_on_created(instance)
|
||||||
push_cluster_system_users_to_asset(instance)
|
push_cluster_system_users_to_asset(instance)
|
||||||
|
@ -77,7 +78,7 @@ def on_system_user_created_or_updated(sender, instance=None, **kwargs):
|
||||||
@receiver(post_init, sender=Cluster, dispatch_uid="my_unique_identifier")
|
@receiver(post_init, sender=Cluster, dispatch_uid="my_unique_identifier")
|
||||||
def on_cluster_init(sender, instance, **kwargs):
|
def on_cluster_init(sender, instance, **kwargs):
|
||||||
instance.__original_assets = tuple(instance.assets.values_list('pk', flat=True))
|
instance.__original_assets = tuple(instance.assets.values_list('pk', flat=True))
|
||||||
# instance.__origin_system_users = tuple(instance.systemuser_set.all())
|
instance.__origin_system_users = tuple(instance.systemuser_set.values_list('pk', flat=True))
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Cluster, dispatch_uid="my_unique_identifier")
|
@receiver(post_save, sender=Cluster, dispatch_uid="my_unique_identifier")
|
||||||
|
@ -103,11 +104,11 @@ def on_cluster_assets_changed(sender, instance, **kwargs):
|
||||||
push_system_user_util.delay(system_users, assets, task_name)
|
push_system_user_util.delay(system_users, assets, task_name)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Cluster, dispatch_uid="my_unique_identifier")
|
@receiver(post_save, sender=Cluster, dispatch_uid="my_unique_identifier2")
|
||||||
def on_cluster_system_user_changed(sender, instance, **kwargs):
|
def on_cluster_system_user_changed(sender, instance, **kwargs):
|
||||||
system_users_origin = instance.__origin_system_users
|
system_users_origin = instance.__origin_system_users
|
||||||
system_user_new = instance.systemuser_set.values_list('pk', flat=True)
|
system_user_new = instance.systemuser_set.values_list('pk', flat=True)
|
||||||
system_users_added = set(system_user_new) - system_users_origin
|
system_users_added = set(system_user_new) - set(system_users_origin)
|
||||||
if system_users_added:
|
if system_users_added:
|
||||||
logger.debug("Receive cluster change system users signal")
|
logger.debug("Receive cluster change system users signal")
|
||||||
system_users = []
|
system_users = []
|
||||||
|
|
|
@ -25,7 +25,7 @@ disk_pattern = re.compile(r'^hd|sd|xvd')
|
||||||
@shared_task
|
@shared_task
|
||||||
def set_assets_hardware_info(result, **kwargs):
|
def set_assets_hardware_info(result, **kwargs):
|
||||||
"""
|
"""
|
||||||
Unsing ops task run result, to update asset info
|
Using ops task run result, to update asset info
|
||||||
|
|
||||||
@shared_task must be exit, because we using it as a task callback, is must
|
@shared_task must be exit, because we using it as a task callback, is must
|
||||||
be a celery task also
|
be a celery task also
|
||||||
|
@ -209,8 +209,11 @@ def test_asset_connectability_util(asset, task_name=None):
|
||||||
from ops.utils import update_or_create_ansible_task
|
from ops.utils import update_or_create_ansible_task
|
||||||
|
|
||||||
if task_name is None:
|
if task_name is None:
|
||||||
task_name = "Test asset connectability"
|
task_name = _("Test asset connectability")
|
||||||
hosts = [asset.hostname]
|
hosts = [asset.hostname]
|
||||||
|
if not hosts:
|
||||||
|
logger.info("No hosts, passed")
|
||||||
|
return {}
|
||||||
tasks = const.TEST_ADMIN_USER_CONN_TASKS
|
tasks = const.TEST_ADMIN_USER_CONN_TASKS
|
||||||
task, created = update_or_create_ansible_task(
|
task, created = update_or_create_ansible_task(
|
||||||
task_name=task_name, hosts=hosts, tasks=tasks, pattern='all',
|
task_name=task_name, hosts=hosts, tasks=tasks, pattern='all',
|
||||||
|
@ -262,6 +265,9 @@ def test_system_user_connectability_util(system_user, task_name):
|
||||||
assets = system_user.get_clusters_assets()
|
assets = system_user.get_clusters_assets()
|
||||||
hosts = [asset.hostname for asset in assets]
|
hosts = [asset.hostname for asset in assets]
|
||||||
tasks = const.TEST_SYSTEM_USER_CONN_TASKS
|
tasks = const.TEST_SYSTEM_USER_CONN_TASKS
|
||||||
|
if not hosts:
|
||||||
|
logger.info("No hosts, passed")
|
||||||
|
return {}
|
||||||
task, created = update_or_create_ansible_task(
|
task, created = update_or_create_ansible_task(
|
||||||
task_name, hosts=hosts, tasks=tasks, pattern='all',
|
task_name, hosts=hosts, tasks=tasks, pattern='all',
|
||||||
options=const.TASK_OPTIONS,
|
options=const.TASK_OPTIONS,
|
||||||
|
@ -274,7 +280,7 @@ def test_system_user_connectability_util(system_user, task_name):
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def test_system_user_connectability_manual(system_user):
|
def test_system_user_connectability_manual(system_user):
|
||||||
task_name = "Test system user connectability: {}".format(system_user)
|
task_name = _("Test system user connectability: {}").format(system_user)
|
||||||
return test_system_user_connectability_util(system_user, task_name)
|
return test_system_user_connectability_util(system_user, task_name)
|
||||||
|
|
||||||
|
|
||||||
|
@ -303,6 +309,10 @@ def test_system_user_connectability_period():
|
||||||
#### Push system user tasks ####
|
#### Push system user tasks ####
|
||||||
|
|
||||||
def get_push_system_user_tasks(system_user):
|
def get_push_system_user_tasks(system_user):
|
||||||
|
# Set root as system user is dangerous
|
||||||
|
if system_user.username == "root":
|
||||||
|
return []
|
||||||
|
|
||||||
tasks = [
|
tasks = [
|
||||||
{
|
{
|
||||||
'name': 'Add user {}'.format(system_user.username),
|
'name': 'Add user {}'.format(system_user.username),
|
||||||
|
@ -310,7 +320,7 @@ def get_push_system_user_tasks(system_user):
|
||||||
'module': 'user',
|
'module': 'user',
|
||||||
'args': 'name={} shell={} state=present password={}'.format(
|
'args': 'name={} shell={} state=present password={}'.format(
|
||||||
system_user.username, system_user.shell,
|
system_user.username, system_user.shell,
|
||||||
encrypt_password(system_user.password),
|
encrypt_password(system_user.password, salt="K3mIlKK"),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -346,11 +356,14 @@ def push_system_user_util(system_users, assets, task_name):
|
||||||
for system_user in system_users:
|
for system_user in system_users:
|
||||||
tasks.extend(get_push_system_user_tasks(system_user))
|
tasks.extend(get_push_system_user_tasks(system_user))
|
||||||
|
|
||||||
print("Task: ", tasks)
|
|
||||||
if not tasks:
|
if not tasks:
|
||||||
return
|
logger.info("Not tasks, passed")
|
||||||
|
return {}
|
||||||
|
|
||||||
hosts = [asset.hostname for asset in assets]
|
hosts = [asset.hostname for asset in assets]
|
||||||
|
if not hosts:
|
||||||
|
logger.info("Not hosts, passed")
|
||||||
|
return {}
|
||||||
task, created = update_or_create_ansible_task(
|
task, created = update_or_create_ansible_task(
|
||||||
task_name=task_name, hosts=hosts, tasks=tasks, pattern='all',
|
task_name=task_name, hosts=hosts, tasks=tasks, pattern='all',
|
||||||
options=const.TASK_OPTIONS, run_as_admin=True, created_by='System'
|
options=const.TASK_OPTIONS, run_as_admin=True, created_by='System'
|
||||||
|
@ -381,8 +394,8 @@ def push_system_user_period():
|
||||||
for system_user in system_users:
|
for system_user in system_users:
|
||||||
tasks.extend(get_push_system_user_tasks(system_user))
|
tasks.extend(get_push_system_user_tasks(system_user))
|
||||||
|
|
||||||
task_name = _("Push system user to cluster assets period: {}->{}").format(
|
task_name = _("Push cluster system users to assets period: {}").format(
|
||||||
cluster.name, ', '.join(s.name for s in system_users)
|
cluster.name
|
||||||
)
|
)
|
||||||
hosts = [asset.hostname for asset in cluster.assets.all()]
|
hosts = [asset.hostname for asset in cluster.assets.all()]
|
||||||
update_or_create_ansible_task(
|
update_or_create_ansible_task(
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -21,11 +21,11 @@
|
||||||
<a href="{% url 'assets:admin-user-assets' pk=admin_user.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Assets list' %} </a>
|
<a href="{% url 'assets:admin-user-assets' pk=admin_user.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Assets list' %} </a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-default" href="{% url 'assets:admin-user-update' pk=admin_user.id %}"><i class="fa fa-edit"></i>Update</a>
|
<a class="btn btn-outline btn-default" href="{% url 'assets:admin-user-update' pk=admin_user.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-danger btn-delete-admin-user">
|
<a class="btn btn-outline btn-danger btn-delete-admin-user">
|
||||||
<i class="fa fa-edit"></i>Delete
|
<i class="fa fa-trash-o"></i>{% trans 'Delete' %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
<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 'Reachable' %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -144,7 +144,7 @@ $(document).ready(function () {
|
||||||
url: the_url,
|
url: the_url,
|
||||||
error: error,
|
error: error,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
success_message: "{% trans "Task has been send, seen left asset status" %}"
|
success_message: "{% trans 'Task has been send, seen left asset status' %}"
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -21,11 +21,11 @@
|
||||||
<a href="{% url 'assets:admin-user-assets' pk=admin_user.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Assets list' %} </a>
|
<a href="{% url 'assets:admin-user-assets' pk=admin_user.pk %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Assets list' %} </a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-default" href="{% url 'assets:admin-user-update' pk=admin_user.id %}"><i class="fa fa-edit"></i>Update</a>
|
<a class="btn btn-outline btn-default" href="{% url 'assets:admin-user-update' pk=admin_user.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-danger btn-delete-admin-user">
|
<a class="btn btn-outline btn-danger btn-delete-admin-user">
|
||||||
<i class="fa fa-edit"></i>Delete
|
<i class="fa fa-trash-o"></i>{% trans 'Delete' %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -133,7 +133,6 @@ function bindToCluster(clusters) {
|
||||||
$('.select2-selection__rendered').empty();
|
$('.select2-selection__rendered').empty();
|
||||||
$('#cluster_selected').val('');
|
$('#cluster_selected').val('');
|
||||||
$.map(jumpserver.cluster_selected, function(cluster_name, index) {
|
$.map(jumpserver.cluster_selected, function(cluster_name, index) {
|
||||||
console.log(index);
|
|
||||||
$('#opt_' + index).remove();
|
$('#opt_' + index).remove();
|
||||||
// change tr html of user groups.
|
// change tr html of user groups.
|
||||||
$('#table-clusters tbody').append(
|
$('#table-clusters tbody').append(
|
||||||
|
|
|
@ -21,8 +21,10 @@
|
||||||
</th>
|
</th>
|
||||||
<th class="text-center">{% trans 'Name' %}</th>
|
<th class="text-center">{% trans 'Name' %}</th>
|
||||||
<th class="text-center">{% trans 'Username' %}</th>
|
<th class="text-center">{% trans 'Username' %}</th>
|
||||||
<th class="text-center">{% trans 'Asset num' %}</th>
|
<th class="text-center">{% trans 'Asset' %}</th>
|
||||||
|
<th class="text-center">{% trans 'Reachable' %}</th>
|
||||||
<th class="text-center">{% trans 'Unreachable' %}</th>
|
<th class="text-center">{% trans 'Unreachable' %}</th>
|
||||||
|
<th class="text-center">{% trans 'Ratio' %}</th>
|
||||||
<th class="text-center">{% trans 'Comment' %}</th>
|
<th class="text-center">{% trans 'Comment' %}</th>
|
||||||
<th class="text-center">{% trans 'Action' %}</th>
|
<th class="text-center">{% trans 'Action' %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -41,17 +43,50 @@ $(document).ready(function(){
|
||||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||||
var detail_btn = '<a href="{% url "assets:admin-user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
|
var detail_btn = '<a href="{% url "assets:admin-user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
|
||||||
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
|
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
|
||||||
}},
|
}},
|
||||||
|
{targets: 4, createdCell: function (td, cellData) {
|
||||||
|
var innerHtml = "";
|
||||||
|
if (cellData !== 0) {
|
||||||
|
innerHtml = "<span class='text-navy'>" + cellData + "</span>";
|
||||||
|
} else {
|
||||||
|
innerHtml = "<span>" + cellData + "</span>";
|
||||||
|
}
|
||||||
|
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData +'">' + innerHtml + '</span>');
|
||||||
|
}},
|
||||||
|
{targets: 5, createdCell: function (td, cellData) {
|
||||||
|
var innerHtml = "";
|
||||||
|
if (cellData !== 0) {
|
||||||
|
innerHtml = "<span class='text-danger'>" + cellData + "</span>";
|
||||||
|
} else {
|
||||||
|
innerHtml = "<span>" + cellData + "</span>";
|
||||||
|
}
|
||||||
|
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');
|
||||||
|
}},
|
||||||
{targets: 6, createdCell: function (td, cellData, rowData) {
|
{targets: 6, createdCell: function (td, cellData, rowData) {
|
||||||
{# var script_btn = '<a href="{% url "assets:admin-user-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-primary">{% trans "Script" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);#}
|
var val = 0;
|
||||||
|
var innerHtml = "";
|
||||||
|
var total = rowData.assets_amount;
|
||||||
|
var reachable = rowData.reachable_amount;
|
||||||
|
if (total !== 0) {
|
||||||
|
val = reachable/total * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val === 100) {
|
||||||
|
innerHtml = "<span class='text-navy'>" + val + "% </span>";
|
||||||
|
} else {
|
||||||
|
innerHtml = "<span class='text-danger'>" + val + "% </span>";
|
||||||
|
}
|
||||||
|
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');
|
||||||
|
|
||||||
|
}},
|
||||||
|
{targets: 8, createdCell: function (td, cellData, rowData) {
|
||||||
var update_btn = '<a href="{% url "assets:admin-user-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
var update_btn = '<a href="{% url "assets:admin-user-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
||||||
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_admin_user_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_admin_user_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
||||||
{# $(td).html(script_btn + update_btn + del_btn)#}
|
|
||||||
$(td).html(update_btn + del_btn)
|
$(td).html(update_btn + del_btn)
|
||||||
}}],
|
}}],
|
||||||
ajax_url: '{% url "api-assets:admin-user-list" %}',
|
ajax_url: '{% url "api-assets:admin-user-list" %}',
|
||||||
columns: [{data: function(){return ""}}, {data: "name" }, {data: "username" }, {data: "assets_amount" },
|
columns: [{data: function(){return ""}}, {data: "name" }, {data: "username" }, {data: "assets_amount" },
|
||||||
{data: "unreachable_amount"}, {data: "comment" }, {data: "id" }]
|
{data: "reachable_amount"}, {data: "unreachable_amount"}, {data: "id"}, {data: "comment" }, {data: "id" }]
|
||||||
};
|
};
|
||||||
jumpserver.initDataTable(options);
|
jumpserver.initDataTable(options);
|
||||||
})
|
})
|
||||||
|
|
|
@ -21,11 +21,11 @@
|
||||||
</li>
|
</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>{% trans 'Update' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-danger btn-delete-asset">
|
<a class="btn btn-outline btn-danger btn-delete-asset">
|
||||||
<i class="fa fa-edit"></i>Delete
|
<i class="fa fa-trash-o"></i>{% trans 'Delete' %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,119 +1,31 @@
|
||||||
{% extends 'base.html' %}
|
{% extends '_base_create_update.html' %}
|
||||||
{% load i18n %}
|
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
{% block custom_head_css_js %}
|
{% load i18n %}
|
||||||
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
|
||||||
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
<div class="wrapper wrapper-content animated fadeInRight">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<div class="ibox float-e-margins">
|
|
||||||
<div id="ibox-content" class="ibox-title">
|
|
||||||
<h5> {{ action }}</h5>
|
|
||||||
<div class="ibox-tools">
|
|
||||||
<a class="collapse-link">
|
|
||||||
<i class="fa fa-chevron-up"></i>
|
|
||||||
</a>
|
|
||||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
|
||||||
<i class="fa fa-wrench"></i>
|
|
||||||
</a>
|
|
||||||
<a class="close-link">
|
|
||||||
<i class="fa fa-times"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ibox-content">
|
{% block form %}
|
||||||
<div class="panel blank-panel">
|
<form id="groupForm" method="post" class="form-horizontal">
|
||||||
<div class="panel-body">
|
{% csrf_token %}
|
||||||
<div class="tab-content">
|
{% bootstrap_field form.name layout="horizontal" %}
|
||||||
<form id="groupForm" method="post" class="form-horizontal">
|
{% bootstrap_field form.assets layout="horizontal" %}
|
||||||
{% csrf_token %}
|
{% bootstrap_field form.comment layout="horizontal" %}
|
||||||
<h3 class="widget-head-color-box">资产组信息</h3>
|
|
||||||
{% bootstrap_field form.name layout="horizontal" %}
|
<div class="hr-line-dashed"></div>
|
||||||
{% bootstrap_field form.comment layout="horizontal" %}
|
<div class="form-group">
|
||||||
{# <div class="hr-line-dashed"></div>#}
|
<div class="col-sm-4 col-sm-offset-2">
|
||||||
{# <h3 class="widget-head-color-box">用户选择的资产</h3>#}
|
<button class="btn btn-default" type="reset"> {% trans 'Reset' %}</button>
|
||||||
{# <div class="form-group">#}
|
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
||||||
{# <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>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
|
|
||||||
<!-- 模态框(Modal) -->
|
|
||||||
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-lg">
|
|
||||||
<div class="modal-content" id="box">
|
|
||||||
<!--此部分为主体内容,将远程加载进来-->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('.select2').select2();
|
$('.select2').select2({
|
||||||
$('.select2-system-user').select2();
|
closeOnSelect: false
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#add_asset').on('click',function(){
|
|
||||||
$('#modal').modal('show');
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#modal').modal({
|
|
||||||
show: false,
|
|
||||||
backdrop: 'static',
|
|
||||||
keyboard: 'false',
|
|
||||||
remote:"{% url 'assets:asset-modal-list' %}?group_id={{ group_id }}"
|
|
||||||
});
|
|
||||||
$('#modal').on('show.bs.modal',function(){
|
|
||||||
//alert('当调用show方法时,立即触发;')
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#modal').on('shown.bs.modal',function(){
|
|
||||||
//alert('当弹窗完全加载完后,再触发;')
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#modal').on('hide.bs.modal',function(){
|
|
||||||
//alert('当关闭时,立即触发;')
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#modal').on('hidden.bs.modal',function(){
|
|
||||||
//alert('当关完全关闭后,再触发;')
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#modal').on('loaded.bs.modal',function(){
|
|
||||||
//alert('当远程数据加载完毕后,再触发;')
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -3,8 +3,8 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="wrapper wrapper-content animated fadeInRight">
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
@ -15,7 +15,12 @@
|
||||||
<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 'Group assets' %} </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>{% trans 'Update' %}</a>
|
||||||
|
</li>
|
||||||
|
<li class="pull-right">
|
||||||
|
<a class="btn btn-outline btn-danger btn-del">
|
||||||
|
<i class="fa fa-trash-o"></i>{% trans 'Delete' %}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -212,7 +217,6 @@ $(document).ready(function () {
|
||||||
addAssets(assets_id);
|
addAssets(assets_id);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
.on('click', '.btn-leave-group', function () {
|
.on('click', '.btn-leave-group', function () {
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
var the_url = "{% url 'api-assets:group-update-assets' pk=asset_group.id %}";
|
var the_url = "{% url 'api-assets:group-update-assets' pk=asset_group.id %}";
|
||||||
|
@ -223,9 +227,15 @@ $(document).ready(function () {
|
||||||
});
|
});
|
||||||
var delete_asset_id = $(this).data('aid');
|
var delete_asset_id = $(this).data('aid');
|
||||||
assets.remove(delete_asset_id);
|
assets.remove(delete_asset_id);
|
||||||
console.log(assets);
|
|
||||||
var data = {"assets": assets};
|
var data = {"assets": assets};
|
||||||
leaveGroup($this, name, the_url, data);
|
leaveGroup($this, name, the_url, data);
|
||||||
|
}).on('click', '.btn-del', function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var name = "{{ asset_group.name}}";
|
||||||
|
var uid = "{{ asset_group.id }}";
|
||||||
|
var the_url = '{% url "api-assets:asset-group-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
|
||||||
|
var redirect_url = "{% url 'assets:asset-group-list' %}";
|
||||||
|
objectDelete($this, name, the_url, redirect_url);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -75,8 +75,6 @@ $(document).ready(function(){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var the_url = '{% url "api-assets:asset-group-list" %}';
|
var the_url = '{% url "api-assets:asset-group-list" %}';
|
||||||
console.log(plain_id_list);
|
|
||||||
console.log(the_url);
|
|
||||||
function doDelete() {
|
function doDelete() {
|
||||||
swal({
|
swal({
|
||||||
title: "{% trans 'Are you sure?' %}",
|
title: "{% trans 'Are you sure?' %}",
|
||||||
|
|
|
@ -109,7 +109,7 @@ function initTable() {
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
initTable();
|
initTable();
|
||||||
})
|
})
|
||||||
.on('click', '#btn_export', function () {
|
.on('click', '.btn_export', function () {
|
||||||
var $data_table = $('#asset_list_table').DataTable();
|
var $data_table = $('#asset_list_table').DataTable();
|
||||||
var rows = $data_table.rows('.selected').data();
|
var rows = $data_table.rows('.selected').data();
|
||||||
var assets = [];
|
var assets = [];
|
||||||
|
@ -129,7 +129,7 @@ $(document).ready(function(){
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.on('click', '#btn_import', function () {
|
.on('click', '#btn_asset_import', function () {
|
||||||
var $form = $('#fm_asset_import');
|
var $form = $('#fm_asset_import');
|
||||||
$form.find('.help-block').remove();
|
$form.find('.help-block').remove();
|
||||||
function success (data) {
|
function success (data) {
|
||||||
|
|
|
@ -46,7 +46,6 @@
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
<h3>{% trans 'Other' %}</h3>
|
<h3>{% trans 'Other' %}</h3>
|
||||||
{% bootstrap_field form.status layout="horizontal" %}
|
{% bootstrap_field form.status layout="horizontal" %}
|
||||||
{% bootstrap_field form.env layout="horizontal" %}
|
|
||||||
{% bootstrap_field form.comment layout="horizontal" %}
|
{% bootstrap_field form.comment layout="horizontal" %}
|
||||||
{% bootstrap_field form.is_active layout="horizontal" %}
|
{% bootstrap_field form.is_active layout="horizontal" %}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -94,7 +94,7 @@
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<select data-placeholder="{% trans 'Select asset' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
|
<select data-placeholder="{% trans 'Select asset' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
|
||||||
{% for asset in assets_remain %}
|
{% for asset in assets_remain %}
|
||||||
<option value="{{ asset.id }}" id="opt_{{ asset.id }}">{{ asset.ip}}:{{ asset.port }}</option>
|
<option value="{{ asset.id }}" id="opt_{{ asset.id }}">{{ asset.hostname}}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
|
@ -204,7 +204,12 @@ $(document).ready(function () {
|
||||||
addAssets(assets_id);
|
addAssets(assets_id);
|
||||||
})
|
})
|
||||||
.on('click', '#btn-test-assets', function () {
|
.on('click', '#btn-test-assets', function () {
|
||||||
console.log('ok');
|
var the_url = "{% url 'api-assets:cluster-test-connective' pk=cluster.id %}";
|
||||||
|
APIUpdateAttr({
|
||||||
|
url: the_url,
|
||||||
|
method: 'GET',
|
||||||
|
success_message: "{% trans 'Task has been send, seen left assets status' %}"
|
||||||
|
});
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="wrapper wrapper-content animated fadeInRight">
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
@ -40,6 +40,7 @@
|
||||||
|
|
||||||
<h3 class="widget-head-color-box">{% trans 'Settings' %}</h3>
|
<h3 class="widget-head-color-box">{% trans 'Settings' %}</h3>
|
||||||
{% bootstrap_field form.admin_user layout="horizontal" %}
|
{% bootstrap_field form.admin_user layout="horizontal" %}
|
||||||
|
{% bootstrap_field form.system_users layout="horizontal" %}
|
||||||
|
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
<h3 class="widget-head-color-box">{% trans 'Other' %}</h3>
|
<h3 class="widget-head-color-box">{% trans 'Other' %}</h3>
|
||||||
|
@ -69,10 +70,7 @@
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('.select2').select2({
|
$('.select2').select2();
|
||||||
dropdownAutoWidth : true,
|
});
|
||||||
width: 'auto'
|
|
||||||
});
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -3,8 +3,8 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="wrapper wrapper-content animated fadeInRight">
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
@ -22,11 +22,11 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-default" href="{% url 'assets:cluster-update' pk=cluster.id %}"><i class="fa fa-edit"></i>Update</a>
|
<a class="btn btn-outline btn-default" href="{% url 'assets:cluster-update' pk=cluster.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-danger btn-delete-cluster">
|
<a class="btn btn-outline btn-danger btn-delete-cluster">
|
||||||
<i class="fa fa-edit"></i>Delete
|
<i class="fa fa-trash-o"></i>{% trans 'Delete' %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
{% block table_search %}{% endblock %}
|
{% block table_search %}{% endblock %}
|
||||||
{% block table_container %}
|
{% block table_container %}
|
||||||
<div class="uc pull-left 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" >
|
||||||
<thead>
|
<thead>
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="wrapper wrapper-content animated fadeInRight">
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-default" href="{% url 'assets:system-user-update' pk=system_user.id %}"><i class="fa fa-edit"></i>Update</a>
|
<a class="btn btn-outline btn-default" href="{% url 'assets:system-user-update' pk=system_user.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -23,7 +23,12 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-default" href="{% url 'assets:system-user-update' pk=system_user.id %}"><i class="fa fa-edit"></i>Update</a>
|
<a class="btn btn-outline btn-default" href="{% url 'assets:system-user-update' pk=system_user.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
|
||||||
|
</li>
|
||||||
|
<li class="pull-right">
|
||||||
|
<a class="btn btn-outline btn-danger btn-del">
|
||||||
|
<i class="fa fa-trash-o"></i>{% trans 'Delete' %}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -259,6 +264,13 @@ $(document).ready(function () {
|
||||||
return $(this).data('gid');
|
return $(this).data('gid');
|
||||||
}).get();
|
}).get();
|
||||||
updateSystemUserCluster(clusters);
|
updateSystemUserCluster(clusters);
|
||||||
|
}).on('click', '.btn-del', function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var name = "{{ system_user.name}}";
|
||||||
|
var uid = "{{ system_user.id }}";
|
||||||
|
var the_url = '{% url "api-assets:system-user-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
|
||||||
|
var redirect_url = "{% url 'assets:system-user-list' %}";
|
||||||
|
objectDelete($this, name, the_url, redirect_url);
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -42,7 +42,6 @@ function initTable() {
|
||||||
columnDefs: [
|
columnDefs: [
|
||||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||||
{% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %}
|
{% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %}
|
||||||
console.log('{{ the_url }}');
|
|
||||||
var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>';
|
var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>';
|
||||||
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
|
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
|
||||||
}},
|
}},
|
||||||
|
@ -67,7 +66,7 @@ function initTable() {
|
||||||
$(td).html(conn_btn)
|
$(td).html(conn_btn)
|
||||||
}}
|
}}
|
||||||
],
|
],
|
||||||
ajax_url: '{% url "api-assets:asset-list" %}',
|
ajax_url: '{% url "api-assets:user-asset-list" %}',
|
||||||
columns: [
|
columns: [
|
||||||
{data: "id"}, {data: "hostname" }, {data: "ip" }, {data: "port" },
|
{data: "id"}, {data: "hostname" }, {data: "ip" }, {data: "port" },
|
||||||
{data: "get_type_display" }, {data: "get_env_display"}, {data: "hardware_info"},
|
{data: "get_type_display" }, {data: "get_env_display"}, {data: "hardware_info"},
|
||||||
|
|
|
@ -21,16 +21,18 @@ urlpatterns = [
|
||||||
api.AssetRefreshHardwareApi.as_view(), name='asset-refresh'),
|
api.AssetRefreshHardwareApi.as_view(), name='asset-refresh'),
|
||||||
url(r'^v1/assets/(?P<pk>[0-9a-zA-Z\-]{36})/alive/$',
|
url(r'^v1/assets/(?P<pk>[0-9a-zA-Z\-]{36})/alive/$',
|
||||||
api.AssetAdminUserTestApi.as_view(), name='asset-alive-test'),
|
api.AssetAdminUserTestApi.as_view(), name='asset-alive-test'),
|
||||||
|
url(r'^v1/assets/user-assets/$',
|
||||||
|
api.UserAssetListView.as_view(), name='user-asset-list'),
|
||||||
# update the asset group, which add or delete the asset to the group
|
# update the asset group, which add or delete the asset to the group
|
||||||
url(r'^v1/groups/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$',
|
url(r'^v1/groups/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$',
|
||||||
api.GroupUpdateAssetsApi.as_view(), name='group-update-assets'),
|
api.GroupUpdateAssetsApi.as_view(), name='group-update-assets'),
|
||||||
url(r'^v1/groups/(?P<pk>[0-9a-zA-Z\-]{36})/assets/add/$',
|
url(r'^v1/groups/(?P<pk>[0-9a-zA-Z\-]{36})/assets/add/$',
|
||||||
api.GroupAddAssetsApi.as_view(), name='group-add-assets'),
|
api.GroupAddAssetsApi.as_view(), name='group-add-assets'),
|
||||||
# update the Cluster, and add or delete the assets to the Cluster
|
# update the Cluster, and add or delete the assets to the Cluster
|
||||||
url(r'^v1/cluster/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$',
|
|
||||||
api.ClusterUpdateAssetsApi.as_view(), name='cluster-update-assets'),
|
|
||||||
url(r'^v1/cluster/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$',
|
url(r'^v1/cluster/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$',
|
||||||
api.ClusterAddAssetsApi.as_view(), name='cluster-add-assets'),
|
api.ClusterAddAssetsApi.as_view(), name='cluster-add-assets'),
|
||||||
|
url(r'^v1/cluster/(?P<pk>[0-9a-zA-Z\-]{36})/assets/connective/$',
|
||||||
|
api.ClusterTestAssetsAliveApi.as_view(), name='cluster-test-connective'),
|
||||||
url(r'^v1/admin-user/(?P<pk>[0-9a-zA-Z\-]{36})/clusters/$',
|
url(r'^v1/admin-user/(?P<pk>[0-9a-zA-Z\-]{36})/clusters/$',
|
||||||
api.AdminUserAddClustersApi.as_view(), name='admin-user-add-clusters'),
|
api.AdminUserAddClustersApi.as_view(), name='admin-user-add-clusters'),
|
||||||
url(r'^v1/admin-user/(?P<pk>[0-9a-zA-Z\-]{36})/connective/$',
|
url(r'^v1/admin-user/(?P<pk>[0-9a-zA-Z\-]{36})/connective/$',
|
||||||
|
|
|
@ -2,20 +2,22 @@
|
||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.views.generic import TemplateView, ListView, View
|
|
||||||
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
|
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
|
from django.views.generic import TemplateView, ListView
|
||||||
|
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||||
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 common.const import create_success_msg, update_success_msg
|
||||||
from .. import forms
|
from .. import forms
|
||||||
from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser
|
from ..models import AdminUser, Cluster
|
||||||
from ..hands import AdminUserRequiredMixin
|
from ..hands import AdminUserRequiredMixin
|
||||||
|
|
||||||
__all__ = ['AdminUserCreateView', 'AdminUserDetailView',
|
__all__ = [
|
||||||
'AdminUserDeleteView', 'AdminUserListView',
|
'AdminUserCreateView', 'AdminUserDetailView',
|
||||||
'AdminUserUpdateView', 'AdminUserAssetsView',
|
'AdminUserDeleteView', 'AdminUserListView',
|
||||||
]
|
'AdminUserUpdateView', 'AdminUserAssetsView',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class AdminUserListView(AdminUserRequiredMixin, TemplateView):
|
class AdminUserListView(AdminUserRequiredMixin, TemplateView):
|
||||||
|
@ -38,6 +40,7 @@ class AdminUserCreateView(AdminUserRequiredMixin,
|
||||||
form_class = forms.AdminUserForm
|
form_class = forms.AdminUserForm
|
||||||
template_name = 'assets/admin_user_create_update.html'
|
template_name = 'assets/admin_user_create_update.html'
|
||||||
success_url = reverse_lazy('assets:admin-user-list')
|
success_url = reverse_lazy('assets:admin-user-list')
|
||||||
|
success_message = create_success_msg
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
|
@ -47,20 +50,13 @@ class AdminUserCreateView(AdminUserRequiredMixin,
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def get_success_message(self, cleaned_data):
|
|
||||||
success_message = _(
|
|
||||||
'Create admin user <a href="{url}">{name}</a> successfully.'.format(
|
|
||||||
url=reverse_lazy('assets:admin-user-detail',
|
|
||||||
kwargs={'pk': self.object.pk}),
|
|
||||||
name=self.object.name,
|
|
||||||
))
|
|
||||||
return success_message
|
|
||||||
|
|
||||||
|
class AdminUserUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
class AdminUserUpdateView(AdminUserRequiredMixin, UpdateView):
|
|
||||||
model = AdminUser
|
model = AdminUser
|
||||||
form_class = forms.AdminUserForm
|
form_class = forms.AdminUserForm
|
||||||
template_name = 'assets/admin_user_create_update.html'
|
template_name = 'assets/admin_user_create_update.html'
|
||||||
|
success_url = reverse_lazy('assets:admin-user-list')
|
||||||
|
success_message = update_success_msg
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
|
@ -70,11 +66,6 @@ class AdminUserUpdateView(AdminUserRequiredMixin, UpdateView):
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def get_success_url(self):
|
|
||||||
success_url = reverse_lazy('assets:admin-user-detail',
|
|
||||||
kwargs={'pk': self.object.pk})
|
|
||||||
return success_url
|
|
||||||
|
|
||||||
|
|
||||||
class AdminUserDetailView(AdminUserRequiredMixin, DetailView):
|
class AdminUserDetailView(AdminUserRequiredMixin, DetailView):
|
||||||
model = AdminUser
|
model = AdminUser
|
||||||
|
|
|
@ -21,10 +21,11 @@ from django.core.cache import cache
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
|
||||||
from common.mixins import JSONResponseMixin
|
from common.mixins import JSONResponseMixin
|
||||||
from common.utils import get_object_or_none, get_logger, is_uuid
|
from common.utils import get_object_or_none, get_logger, is_uuid
|
||||||
|
from common.const import create_success_msg, update_success_msg
|
||||||
from .. import forms
|
from .. import forms
|
||||||
from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser
|
from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser
|
||||||
from ..hands import AdminUserRequiredMixin
|
from ..hands import AdminUserRequiredMixin
|
||||||
|
@ -46,7 +47,6 @@ class AssetListView(AdminUserRequiredMixin, TemplateView):
|
||||||
context = {
|
context = {
|
||||||
'app': _('Assets'),
|
'app': _('Assets'),
|
||||||
'action': _('Asset list'),
|
'action': _('Asset list'),
|
||||||
# 'groups': AssetGroup.objects.all(),
|
|
||||||
'system_users': SystemUser.objects.all(),
|
'system_users': SystemUser.objects.all(),
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
|
@ -66,7 +66,7 @@ class UserAssetListView(LoginRequiredMixin, TemplateView):
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AssetCreateView(AdminUserRequiredMixin, CreateView):
|
class AssetCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
model = Asset
|
model = Asset
|
||||||
form_class = forms.AssetCreateForm
|
form_class = forms.AssetCreateForm
|
||||||
template_name = 'assets/asset_create.html'
|
template_name = 'assets/asset_create.html'
|
||||||
|
@ -87,6 +87,9 @@ class AssetCreateView(AdminUserRequiredMixin, CreateView):
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
def get_success_message(self, cleaned_data):
|
||||||
|
return create_success_msg % ({"name": cleaned_data["hostname"]})
|
||||||
|
|
||||||
|
|
||||||
class AssetModalListView(AdminUserRequiredMixin, ListView):
|
class AssetModalListView(AdminUserRequiredMixin, ListView):
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||||
|
@ -147,7 +150,7 @@ class AssetBulkUpdateView(AdminUserRequiredMixin, ListView):
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AssetUpdateView(AdminUserRequiredMixin, UpdateView):
|
class AssetUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
model = Asset
|
model = Asset
|
||||||
form_class = forms.AssetUpdateForm
|
form_class = forms.AssetUpdateForm
|
||||||
template_name = 'assets/asset_update.html'
|
template_name = 'assets/asset_update.html'
|
||||||
|
@ -159,7 +162,10 @@ class AssetUpdateView(AdminUserRequiredMixin, UpdateView):
|
||||||
'action': _('Update asset'),
|
'action': _('Update asset'),
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super(AssetUpdateView, self).get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
def get_success_message(self, cleaned_data):
|
||||||
|
return update_success_msg % ({"name": cleaned_data["hostname"]})
|
||||||
|
|
||||||
|
|
||||||
class AssetDeleteView(AdminUserRequiredMixin, DeleteView):
|
class AssetDeleteView(AdminUserRequiredMixin, DeleteView):
|
||||||
|
@ -184,14 +190,14 @@ class AssetDetailView(DetailView):
|
||||||
'system_users_all': SystemUser.objects.all(),
|
'system_users_all': SystemUser.objects.all(),
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super(AssetDetailView, self).get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(csrf_exempt, name='dispatch')
|
@method_decorator(csrf_exempt, name='dispatch')
|
||||||
class AssetExportView(View):
|
class AssetExportView(View):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
spm = request.GET.get('spm', '')
|
spm = request.GET.get('spm', '')
|
||||||
assets_id_default = [Asset.objects.first().id] if Asset.objects.first() else [1]
|
assets_id_default = [Asset.objects.first().id] if Asset.objects.first() else []
|
||||||
assets_id = cache.get(spm, assets_id_default)
|
assets_id = cache.get(spm, assets_id_default)
|
||||||
fields = [
|
fields = [
|
||||||
field for field in Asset._meta.fields
|
field for field in Asset._meta.fields
|
||||||
|
|
|
@ -1,17 +1,21 @@
|
||||||
# coding:utf-8
|
# coding:utf-8
|
||||||
from __future__ import absolute_import, unicode_literals
|
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.views.generic import TemplateView, ListView, View
|
from django.views.generic import TemplateView, ListView, View
|
||||||
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
|
from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.views.generic.detail import DetailView, SingleObjectMixin
|
from django.views.generic.detail import DetailView, SingleObjectMixin
|
||||||
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
|
||||||
|
from common.const import create_success_msg, update_success_msg
|
||||||
from .. import forms
|
from .. import forms
|
||||||
from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser
|
from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser
|
||||||
from ..hands import AdminUserRequiredMixin
|
from ..hands import AdminUserRequiredMixin
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['ClusterListView', 'ClusterCreateView', 'ClusterUpdateView',
|
__all__ = [
|
||||||
'ClusterDetailView', 'ClusterDeleteView', 'ClusterAssetsView']
|
'ClusterListView', 'ClusterCreateView', 'ClusterUpdateView',
|
||||||
|
'ClusterDetailView', 'ClusterDeleteView', 'ClusterAssetsView',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class ClusterListView(AdminUserRequiredMixin, TemplateView):
|
class ClusterListView(AdminUserRequiredMixin, TemplateView):
|
||||||
|
@ -21,39 +25,40 @@ class ClusterListView(AdminUserRequiredMixin, TemplateView):
|
||||||
context = {
|
context = {
|
||||||
'app': _('Assets'),
|
'app': _('Assets'),
|
||||||
'action': _('Cluster list'),
|
'action': _('Cluster list'),
|
||||||
# 'keyword': self.request.GET.get('keyword', '')
|
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ClusterCreateView(AdminUserRequiredMixin, CreateView):
|
class ClusterCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
model = Cluster
|
model = Cluster
|
||||||
form_class = forms.ClusterForm
|
form_class = forms.ClusterForm
|
||||||
template_name = 'assets/cluster_create_update.html'
|
template_name = 'assets/cluster_create_update.html'
|
||||||
success_url = reverse_lazy('assets:cluster-list')
|
success_url = reverse_lazy('assets:cluster-list')
|
||||||
|
success_message = create_success_msg
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'app': _('assets'),
|
'app': _('assets'),
|
||||||
'action': _('Create Cluster'),
|
'action': _('Create cluster'),
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
cluster = form.save(commit=False)
|
cluster = form.save(commit=False)
|
||||||
cluster.created_by = self.request.user.username or 'System'
|
cluster.created_by = self.request.user.username
|
||||||
cluster.save()
|
cluster.save()
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
class ClusterUpdateView(AdminUserRequiredMixin, UpdateView):
|
class ClusterUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
model = Cluster
|
model = Cluster
|
||||||
form_class = forms.ClusterForm
|
form_class = forms.ClusterForm
|
||||||
template_name = 'assets/cluster_create_update.html'
|
template_name = 'assets/cluster_create_update.html'
|
||||||
context_object_name = 'cluster'
|
context_object_name = 'cluster'
|
||||||
success_url = reverse_lazy('assets:cluster-list')
|
success_url = reverse_lazy('assets:cluster-list')
|
||||||
|
success_message = update_success_msg
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
cluster = form.save(commit=False)
|
cluster = form.save(commit=False)
|
||||||
|
|
|
@ -7,42 +7,41 @@ from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateVi
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.views.generic.detail import DetailView, SingleObjectMixin
|
from django.views.generic.detail import DetailView, SingleObjectMixin
|
||||||
from django.shortcuts import get_object_or_404, reverse, redirect
|
from django.shortcuts import get_object_or_404, reverse, redirect
|
||||||
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
|
||||||
|
from common.const import create_success_msg, update_success_msg
|
||||||
from .. import forms
|
from .. import forms
|
||||||
from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser
|
from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser
|
||||||
from ..hands import AdminUserRequiredMixin
|
from ..hands import AdminUserRequiredMixin
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['AssetGroupCreateView', 'AssetGroupDetailView',
|
__all__ = [
|
||||||
'AssetGroupUpdateView', 'AssetGroupListView',
|
'AssetGroupCreateView', 'AssetGroupDetailView',
|
||||||
'AssetGroupDeleteView',
|
'AssetGroupUpdateView', 'AssetGroupListView',
|
||||||
]
|
'AssetGroupDeleteView',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
|
class AssetGroupCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
model = AssetGroup
|
model = AssetGroup
|
||||||
form_class = forms.AssetGroupForm
|
form_class = forms.AssetGroupForm
|
||||||
template_name = 'assets/asset_group_create.html'
|
template_name = 'assets/asset_group_create.html'
|
||||||
success_url = reverse_lazy('assets:asset-group-list')
|
success_url = reverse_lazy('assets:asset-group-list')
|
||||||
|
success_message = create_success_msg
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'app': _('Assets'),
|
'app': _('Assets'),
|
||||||
'action': _('Create asset group'),
|
'action': _('Create asset group'),
|
||||||
'assets_count': 0,
|
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super(AssetGroupCreateView, self).get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
asset_group = form.save()
|
group = form.save()
|
||||||
assets_id_list = self.request.POST.getlist('assets', [])
|
group.created_by = self.request.user.username
|
||||||
assets = [get_object_or_404(Asset, id=int(asset_id))
|
group.save()
|
||||||
for asset_id in assets_id_list]
|
return super().form_valid(form)
|
||||||
asset_group.created_by = self.request.user.username or 'Admin'
|
|
||||||
asset_group.assets.add(*tuple(assets))
|
|
||||||
asset_group.save()
|
|
||||||
return super(AssetGroupCreateView, self).form_valid(form)
|
|
||||||
|
|
||||||
|
|
||||||
class AssetGroupListView(AdminUserRequiredMixin, TemplateView):
|
class AssetGroupListView(AdminUserRequiredMixin, TemplateView):
|
||||||
|
@ -54,7 +53,6 @@ class AssetGroupListView(AdminUserRequiredMixin, TemplateView):
|
||||||
'action': _('Asset group list'),
|
'action': _('Asset group list'),
|
||||||
'assets': Asset.objects.all(),
|
'assets': Asset.objects.all(),
|
||||||
'system_users': SystemUser.objects.all(),
|
'system_users': SystemUser.objects.all(),
|
||||||
'keyword': self.request.GET.get('keyword', '')
|
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super(AssetGroupListView, self).get_context_data(**kwargs)
|
return super(AssetGroupListView, self).get_context_data(**kwargs)
|
||||||
|
@ -77,27 +75,20 @@ class AssetGroupDetailView(AdminUserRequiredMixin, DetailView):
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AssetGroupUpdateView(AdminUserRequiredMixin, UpdateView):
|
class AssetGroupUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
model = AssetGroup
|
model = AssetGroup
|
||||||
form_class = forms.AssetGroupForm
|
form_class = forms.AssetGroupForm
|
||||||
template_name = 'assets/asset_group_create.html'
|
template_name = 'assets/asset_group_create.html'
|
||||||
success_url = reverse_lazy('assets:asset-group-list')
|
success_url = reverse_lazy('assets:asset-group-list')
|
||||||
|
success_message = update_success_msg
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
self.object = self.get_object(queryset=AssetGroup.objects.all())
|
|
||||||
return super(AssetGroupUpdateView, self).get(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
assets_all = self.object.assets.all()
|
|
||||||
context = {
|
context = {
|
||||||
'app': _('Assets'),
|
'app': _('Assets'),
|
||||||
'action': _('Create asset group'),
|
'action': _('Create asset group'),
|
||||||
'assets_on_list': assets_all,
|
|
||||||
'assets_count': len(assets_all),
|
|
||||||
'group_id': self.object.id,
|
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super(AssetGroupUpdateView, self).get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AssetGroupDeleteView(AdminUserRequiredMixin, DeleteView):
|
class AssetGroupDeleteView(AdminUserRequiredMixin, DeleteView):
|
||||||
|
|
|
@ -1,24 +1,23 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
# ~*~ coding: utf-8 ~*~
|
||||||
|
|
||||||
from django.contrib import messages
|
|
||||||
from django.shortcuts import redirect, reverse
|
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.db import transaction
|
from django.views.generic import TemplateView
|
||||||
from django.views.generic import TemplateView, ListView, FormView
|
|
||||||
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||||
from django.urls import reverse_lazy
|
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
|
||||||
|
|
||||||
from ..forms import SystemUserForm, SystemUserUpdateForm, SystemUserAuthForm
|
from common.const import create_success_msg, update_success_msg
|
||||||
|
from ..forms import SystemUserForm, SystemUserUpdateForm
|
||||||
from ..models import SystemUser, Cluster
|
from ..models import SystemUser, Cluster
|
||||||
from ..hands import AdminUserRequiredMixin
|
from ..hands import AdminUserRequiredMixin
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['SystemUserCreateView', 'SystemUserUpdateView',
|
__all__ = [
|
||||||
'SystemUserDetailView', 'SystemUserDeleteView',
|
'SystemUserCreateView', 'SystemUserUpdateView',
|
||||||
'SystemUserAssetView', 'SystemUserListView',
|
'SystemUserDetailView', 'SystemUserDeleteView',
|
||||||
]
|
'SystemUserAssetView', 'SystemUserListView',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class SystemUserListView(AdminUserRequiredMixin, TemplateView):
|
class SystemUserListView(AdminUserRequiredMixin, TemplateView):
|
||||||
|
@ -38,10 +37,7 @@ class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVi
|
||||||
form_class = 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')
|
||||||
|
success_message = create_success_msg
|
||||||
@transaction.atomic
|
|
||||||
def post(self, request, *args, **kwargs):
|
|
||||||
return super(SystemUserCreateView, self).post(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
|
@ -51,20 +47,13 @@ class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVi
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def get_success_message(self, cleaned_data):
|
|
||||||
url = reverse('assets:system-user-detail', kwargs={'pk': self.object.pk})
|
|
||||||
success_message = _(
|
|
||||||
'Create system user <a href="{url}">{name}</a> '
|
|
||||||
'successfully.'.format(url=url, name=self.object.name)
|
|
||||||
)
|
|
||||||
|
|
||||||
return success_message
|
class SystemUserUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
|
|
||||||
|
|
||||||
class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView):
|
|
||||||
model = SystemUser
|
model = SystemUser
|
||||||
form_class = SystemUserUpdateForm
|
form_class = SystemUserUpdateForm
|
||||||
template_name = 'assets/system_user_update.html'
|
template_name = 'assets/system_user_update.html'
|
||||||
|
success_url = reverse_lazy('assets:system-user-list')
|
||||||
|
success_message = update_success_msg
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
|
@ -74,11 +63,6 @@ class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView):
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def get_success_url(self):
|
|
||||||
success_url = reverse_lazy('assets:system-user-detail',
|
|
||||||
kwargs={'pk': self.object.pk})
|
|
||||||
return success_url
|
|
||||||
|
|
||||||
|
|
||||||
class SystemUserDetailView(AdminUserRequiredMixin, DetailView):
|
class SystemUserDetailView(AdminUserRequiredMixin, DetailView):
|
||||||
template_name = 'assets/system_user_detail.html'
|
template_name = 'assets/system_user_detail.html'
|
||||||
|
@ -109,8 +93,8 @@ class SystemUserAssetView(AdminUserRequiredMixin, DetailView):
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'app': 'assets',
|
'app': _('assets'),
|
||||||
'action': 'System user asset',
|
'action': _('System user asset'),
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
|
create_success_msg = _("<b>%(name)s</b> was created successfully")
|
||||||
|
update_success_msg = _("<b>%(name)s</b> was updated successfully")
|
|
@ -287,10 +287,10 @@ def make_signature(access_key_secret, date=None):
|
||||||
return content_md5(data)
|
return content_md5(data)
|
||||||
|
|
||||||
|
|
||||||
def encrypt_password(password):
|
def encrypt_password(password, salt=None):
|
||||||
from passlib.hash import sha512_crypt
|
from passlib.hash import sha512_crypt
|
||||||
if password:
|
if password:
|
||||||
return sha512_crypt.using(rounds=5000).hash(password)
|
return sha512_crypt.using(rounds=5000).hash(password, salt=salt)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,24 +4,44 @@ import os
|
||||||
import re
|
import re
|
||||||
import pytz
|
import pytz
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.deprecation import MiddlewareMixin
|
|
||||||
from django.shortcuts import HttpResponse
|
from django.shortcuts import HttpResponse
|
||||||
|
|
||||||
|
|
||||||
DEMO_MODE = os.environ.get("DEMO_MODE", "")
|
class TimezoneMiddleware:
|
||||||
SAFE_URL = r'^/users/login|^/api/terminal/v1/.*|/api/terminal/.*|/api/users/v1/auth/|/api/users/v1/profile/'
|
def __init__(self, get_response):
|
||||||
|
self.get_response = get_response
|
||||||
|
|
||||||
|
def __call__(self, request):
|
||||||
class TimezoneMiddleware(MiddlewareMixin):
|
|
||||||
def process_request(self, request):
|
|
||||||
tzname = request.META.get('TZ')
|
tzname = request.META.get('TZ')
|
||||||
if tzname:
|
if tzname:
|
||||||
timezone.activate(pytz.timezone(tzname))
|
timezone.activate(pytz.timezone(tzname))
|
||||||
else:
|
else:
|
||||||
timezone.deactivate()
|
timezone.deactivate()
|
||||||
|
response = self.get_response(request)
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
class DemoMiddleware(MiddlewareMixin):
|
class DemoMiddleware:
|
||||||
def process_request(self, request):
|
DEMO_MODE_ENABLED = os.environ.get("DEMO_MODE", "") in ("1", "ok", "True")
|
||||||
if DEMO_MODE and request.method not in ["GET", "HEAD"] and not re.match(SAFE_URL, request.path):
|
SAFE_URL_PATTERN = re.compile(
|
||||||
return HttpResponse("Demo mode, only get request accept", status=403)
|
r'^/users/login|'
|
||||||
|
r'^/api/terminal/v1/.*|'
|
||||||
|
r'^/api/terminal/.*|'
|
||||||
|
r'^/api/users/v1/auth/|'
|
||||||
|
r'^/api/users/v1/profile/'
|
||||||
|
)
|
||||||
|
SAFE_METHOD = ("GET", "HEAD")
|
||||||
|
|
||||||
|
def __init__(self, get_response):
|
||||||
|
self.get_response = get_response
|
||||||
|
|
||||||
|
if self.DEMO_MODE_ENABLED:
|
||||||
|
print("Demo mode enabled, reject unsafe method and url")
|
||||||
|
|
||||||
|
def __call__(self, request):
|
||||||
|
if self.DEMO_MODE_ENABLED and request.method not in self.SAFE_METHOD \
|
||||||
|
and not self.SAFE_URL_PATTERN.match(request.path):
|
||||||
|
return HttpResponse("Demo mode, only safe request accepted", status=403)
|
||||||
|
else:
|
||||||
|
response = self.get_response(request)
|
||||||
|
return response
|
||||||
|
|
|
@ -240,9 +240,8 @@ LOGGING = {
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/1.10/topics/i18n/
|
# https://docs.djangoproject.com/en/1.10/topics/i18n/
|
||||||
LANGUAGE_CODE = 'en-us'
|
LANGUAGE_CODE = 'zh-cn'
|
||||||
|
|
||||||
# TIME_ZONE = 'UTC'
|
|
||||||
TIME_ZONE = 'Asia/Shanghai'
|
TIME_ZONE = 'Asia/Shanghai'
|
||||||
|
|
||||||
USE_I18N = True
|
USE_I18N = True
|
||||||
|
@ -300,7 +299,8 @@ REST_FRAMEWORK = {
|
||||||
'users.authentication.SessionAuthentication',
|
'users.authentication.SessionAuthentication',
|
||||||
),
|
),
|
||||||
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
|
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
|
||||||
'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S',
|
'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S %z',
|
||||||
|
'DATETIME_INPUT_FORMATS': ['%Y-%m-%d %H:%M:%S %z'],
|
||||||
}
|
}
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
AUTHENTICATION_BACKENDS = [
|
||||||
|
@ -374,4 +374,5 @@ BOOTSTRAP3 = {
|
||||||
'horizontal_field_class': 'col-md-9',
|
'horizontal_field_class': 'col-md-9',
|
||||||
# Set placeholder attributes to label if no placeholder is provided
|
# Set placeholder attributes to label if no placeholder is provided
|
||||||
'set_placeholder': True,
|
'set_placeholder': True,
|
||||||
|
'success_css_class': '',
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,6 @@ urlpatterns = [
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
urlpatterns += [
|
urlpatterns += [
|
||||||
url(r'^docs/', schema_view, name="docs"),
|
url(r'^docs/', schema_view, name="docs"),
|
||||||
] + static(settings.STATIC_URL, document_root=settings.STATIC_DIR) \
|
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) \
|
||||||
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
||||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -2,11 +2,13 @@
|
||||||
|
|
||||||
|
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from rest_framework import viewsets
|
from rest_framework import viewsets, generics
|
||||||
|
from rest_framework.views import Response
|
||||||
|
|
||||||
from .hands import IsSuperUser
|
from .hands import IsSuperUser
|
||||||
from .models import Task, AdHoc, AdHocRunHistory
|
from .models import Task, AdHoc, AdHocRunHistory
|
||||||
from .serializers import TaskSerializer, AdHocSerializer, AdHocRunHistorySerializer
|
from .serializers import TaskSerializer, AdHocSerializer, AdHocRunHistorySerializer
|
||||||
|
from .tasks import run_ansible_task
|
||||||
|
|
||||||
|
|
||||||
class TaskViewSet(viewsets.ModelViewSet):
|
class TaskViewSet(viewsets.ModelViewSet):
|
||||||
|
@ -15,6 +17,17 @@ class TaskViewSet(viewsets.ModelViewSet):
|
||||||
permission_classes = (IsSuperUser,)
|
permission_classes = (IsSuperUser,)
|
||||||
|
|
||||||
|
|
||||||
|
class TaskRun(generics.RetrieveAPIView):
|
||||||
|
queryset = Task.objects.all()
|
||||||
|
serializer_class = TaskViewSet
|
||||||
|
permission_classes = (IsSuperUser,)
|
||||||
|
|
||||||
|
def retrieve(self, request, *args, **kwargs):
|
||||||
|
task = self.get_object()
|
||||||
|
run_ansible_task.delay(str(task.id))
|
||||||
|
return Response({"msg": "start"})
|
||||||
|
|
||||||
|
|
||||||
class AdHocViewSet(viewsets.ModelViewSet):
|
class AdHocViewSet(viewsets.ModelViewSet):
|
||||||
queryset = AdHoc.objects.all()
|
queryset = AdHoc.objects.all()
|
||||||
serializer_class = AdHocSerializer
|
serializer_class = AdHocSerializer
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
# ~*~ coding: utf-8 ~*~
|
||||||
|
|
||||||
from users.permissions import IsSuperUser
|
from users.permissions import IsSuperUser
|
||||||
|
from users.utils import AdminUserRequiredMixin
|
|
@ -235,6 +235,7 @@ class AdHoc(models.Model):
|
||||||
return result.results_raw, result.results_summary
|
return result.results_raw, result.results_summary
|
||||||
except AnsibleError as e:
|
except AnsibleError as e:
|
||||||
logger.error("Failed run adhoc {}, {}".format(self.task.name, e))
|
logger.error("Failed run adhoc {}, {}".format(self.task.name, e))
|
||||||
|
pass
|
||||||
|
|
||||||
@become.setter
|
@become.setter
|
||||||
def become(self, item):
|
def become(self, item):
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
@ -89,7 +89,7 @@
|
||||||
<td>
|
<td>
|
||||||
<b>
|
<b>
|
||||||
{% for task in object.latest_adhoc.tasks %}
|
{% for task in object.latest_adhoc.tasks %}
|
||||||
{{ forloop.counter }}. {{ task.name }} : {{ task.action.module }} <br/>
|
{{ forloop.counter }}. {{ task.name }} ::: {{ task.action.module }} <br/>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</b>
|
</b>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
|
<a data-uid="{{ object.id }}" class="btn btn-xs btn-primary btn-run">{% trans "Run" %}</a>
|
||||||
<a data-uid="{{ object.id }}" class="btn btn-xs btn-danger btn-del">{% trans "Delete" %}</a>
|
<a data-uid="{{ object.id }}" class="btn btn-xs btn-danger btn-del">{% trans "Delete" %}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -98,10 +99,32 @@ $(document).ready(function() {
|
||||||
|
|
||||||
}).on('click', '.btn-del', function () {
|
}).on('click', '.btn-del', function () {
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
|
var name = $this.closest("tr").find(":nth-child(2)").children('a').html();
|
||||||
var uid = $this.data('uid');
|
var uid = $this.data('uid');
|
||||||
var the_url = '{% url "api-ops:task-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
|
var the_url = '{% url "api-ops:task-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
|
||||||
objectDelete($this, name, the_url);
|
objectDelete($this, name, the_url);
|
||||||
|
}).on('click', '.btn-run', function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var name = $this.closest("tr").find(":nth-child(2)").children('a').html();
|
||||||
|
var uid = $this.data('uid');
|
||||||
|
var the_url = '{% url "api-ops:task-run" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
|
||||||
|
var error = function (data) {
|
||||||
|
alert(data)
|
||||||
|
};
|
||||||
|
var success = function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
console.log("ok")
|
||||||
|
}, 1000);
|
||||||
|
window.location = "{% url 'ops:task-detail' pk=DEFAULT_PK %}".replace('{{ DEFAULT_PK }}', uid);
|
||||||
|
};
|
||||||
|
APIUpdateAttr({
|
||||||
|
url: the_url,
|
||||||
|
error: error,
|
||||||
|
method: 'GET',
|
||||||
|
success: success,
|
||||||
|
success_message: "{% trans 'Task start: ' %}" + " " + name
|
||||||
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
# ~*~ coding: utf-8 ~*~
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.conf.urls import url
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
from .. import api
|
from .. import api
|
||||||
|
|
||||||
|
@ -12,6 +13,8 @@ router.register(r'v1/tasks', api.TaskViewSet, 'task')
|
||||||
router.register(r'v1/adhoc', api.AdHocViewSet, 'adhoc')
|
router.register(r'v1/adhoc', api.AdHocViewSet, 'adhoc')
|
||||||
router.register(r'v1/history', api.AdHocRunHistorySet, 'history')
|
router.register(r'v1/history', api.AdHocRunHistorySet, 'history')
|
||||||
|
|
||||||
urlpatterns = []
|
urlpatterns = [
|
||||||
|
url(r'^v1/tasks/(?P<pk>[0-9a-zA-Z\-]{36})/run/$', api.TaskRun.as_view(), name='task-run'),
|
||||||
|
]
|
||||||
|
|
||||||
urlpatterns += router.urls
|
urlpatterns += router.urls
|
||||||
|
|
|
@ -6,9 +6,10 @@ from django.views.generic import ListView, DetailView
|
||||||
|
|
||||||
from common.mixins import DatetimeSearchMixin
|
from common.mixins import DatetimeSearchMixin
|
||||||
from .models import Task, AdHoc, AdHocRunHistory
|
from .models import Task, AdHoc, AdHocRunHistory
|
||||||
|
from .hands import AdminUserRequiredMixin
|
||||||
|
|
||||||
|
|
||||||
class TaskListView(DatetimeSearchMixin, ListView):
|
class TaskListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView):
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||||
model = Task
|
model = Task
|
||||||
ordering = ('-date_created',)
|
ordering = ('-date_created',)
|
||||||
|
@ -42,7 +43,7 @@ class TaskListView(DatetimeSearchMixin, ListView):
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class TaskDetailView(DetailView):
|
class TaskDetailView(AdminUserRequiredMixin, DetailView):
|
||||||
model = Task
|
model = Task
|
||||||
template_name = 'ops/task_detail.html'
|
template_name = 'ops/task_detail.html'
|
||||||
|
|
||||||
|
@ -55,7 +56,7 @@ class TaskDetailView(DetailView):
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class TaskAdhocView(DetailView):
|
class TaskAdhocView(AdminUserRequiredMixin, DetailView):
|
||||||
model = Task
|
model = Task
|
||||||
template_name = 'ops/task_adhoc.html'
|
template_name = 'ops/task_adhoc.html'
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ class TaskAdhocView(DetailView):
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class TaskHistoryView(DetailView):
|
class TaskHistoryView(AdminUserRequiredMixin, DetailView):
|
||||||
model = Task
|
model = Task
|
||||||
template_name = 'ops/task_history.html'
|
template_name = 'ops/task_history.html'
|
||||||
|
|
||||||
|
@ -81,7 +82,7 @@ class TaskHistoryView(DetailView):
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AdHocDetailView(DetailView):
|
class AdHocDetailView(AdminUserRequiredMixin, DetailView):
|
||||||
model = AdHoc
|
model = AdHoc
|
||||||
template_name = 'ops/adhoc_detail.html'
|
template_name = 'ops/adhoc_detail.html'
|
||||||
|
|
||||||
|
@ -94,7 +95,7 @@ class AdHocDetailView(DetailView):
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AdHocHistoryView(DetailView):
|
class AdHocHistoryView(AdminUserRequiredMixin, DetailView):
|
||||||
model = AdHoc
|
model = AdHoc
|
||||||
template_name = 'ops/adhoc_history.html'
|
template_name = 'ops/adhoc_history.html'
|
||||||
|
|
||||||
|
@ -107,7 +108,7 @@ class AdHocHistoryView(DetailView):
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class AdHocHistoryDetailView(DetailView):
|
class AdHocHistoryDetailView(AdminUserRequiredMixin, DetailView):
|
||||||
model = AdHocRunHistory
|
model = AdHocRunHistory
|
||||||
template_name = 'ops/adhoc_history_detail.html'
|
template_name = 'ops/adhoc_history_detail.html'
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,8 @@ class AssetPermissionForm(forms.ModelForm):
|
||||||
widget=forms.SelectMultiple(
|
widget=forms.SelectMultiple(
|
||||||
attrs={'class': 'select2', 'data-placeholder': _('Select users')},
|
attrs={'class': 'select2', 'data-placeholder': _('Select users')},
|
||||||
),
|
),
|
||||||
label=_("User")
|
label=_("User"),
|
||||||
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -41,35 +42,54 @@ class AssetPermissionForm(forms.ModelForm):
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'name': '* required',
|
'name': '* required',
|
||||||
'system_users': '* required',
|
'system_users': '* required',
|
||||||
'user_groups': _('User or user group at least one required'),
|
|
||||||
'asset_groups': _('Asset or Asset group at least one required'),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def clean_user_groups(self):
|
||||||
|
users = self.cleaned_data.get('users')
|
||||||
|
user_groups = self.cleaned_data.get('user_groups')
|
||||||
|
|
||||||
|
if not users and not user_groups:
|
||||||
|
raise forms.ValidationError(_("User or group at least one required"))
|
||||||
|
return self.cleaned_data["user_groups"]
|
||||||
|
|
||||||
|
def clean_asset_groups(self):
|
||||||
|
assets = self.cleaned_data.get('assets')
|
||||||
|
asset_groups = self.cleaned_data.get('asset_groups')
|
||||||
|
|
||||||
|
if not assets and not asset_groups:
|
||||||
|
raise forms.ValidationError(_("Asset or group at least one required"))
|
||||||
|
|
||||||
|
return self.cleaned_data["asset_groups"]
|
||||||
|
|
||||||
def clean_system_users(self):
|
def clean_system_users(self):
|
||||||
from assets.utils import check_assets_have_system_user
|
from assets.utils import check_assets_have_system_user
|
||||||
|
|
||||||
errors = []
|
errors = []
|
||||||
assets = self.cleaned_data['assets']
|
assets = self.cleaned_data['assets']
|
||||||
asset_groups = self.cleaned_data['asset_groups']
|
asset_groups = self.cleaned_data.get('asset_groups')
|
||||||
system_users = self.cleaned_data['system_users']
|
system_users = self.cleaned_data.get('system_users')
|
||||||
|
|
||||||
|
if not asset_groups and not assets:
|
||||||
|
return self.cleaned_data.get("system_users")
|
||||||
|
|
||||||
error_data = check_assets_have_system_user(assets, system_users)
|
error_data = check_assets_have_system_user(assets, system_users)
|
||||||
if error_data:
|
if error_data:
|
||||||
for asset, system_users in error_data.items():
|
for asset, system_users in error_data.items():
|
||||||
msg = _("Asset {} not have [{}] system users, please check \n")
|
msg = _("Asset {} of cluster {} not have [{}] system users, please check \n")
|
||||||
error = forms.ValidationError(msg.format(
|
error = forms.ValidationError(msg.format(
|
||||||
asset.hostname,
|
asset.hostname,
|
||||||
|
asset.cluster.name,
|
||||||
", ".join(system_user.name for system_user in system_users)
|
", ".join(system_user.name for system_user in system_users)
|
||||||
))
|
))
|
||||||
errors.append(error)
|
errors.append(error)
|
||||||
|
|
||||||
for group in asset_groups:
|
for group in asset_groups:
|
||||||
msg = _("Asset {}: {} not have [{}] system users, please check")
|
msg = _("Asset {}(group {}) of cluster {} not have [{}] system users, please check \n")
|
||||||
assets = group.assets.all()
|
assets = group.assets.all()
|
||||||
error_data = check_assets_have_system_user(assets, system_users)
|
error_data = check_assets_have_system_user(assets, system_users)
|
||||||
for asset, system_users in error_data.items():
|
for asset, system_users in error_data.items():
|
||||||
errors.append(msg.format(
|
errors.append(msg.format(
|
||||||
group.name, asset.hostname,
|
asset.hostname, group.name, asset.cluster.name,
|
||||||
", ".join(system_user.name for system_user in system_users)
|
", ".join(system_user.name for system_user in system_users)
|
||||||
))
|
))
|
||||||
if errors:
|
if errors:
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="wrapper wrapper-content animated fadeInRight">
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
@ -53,8 +53,6 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans 'Hostname' %}</th>
|
<th>{% trans 'Hostname' %}</th>
|
||||||
<th>{% trans 'IP' %}</th>
|
<th>{% trans 'IP' %}</th>
|
||||||
<th>{% trans 'Port' %}</th>
|
|
||||||
<th>{% trans 'Is valid' %}</th>
|
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -63,15 +61,6 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ asset.hostname }}</td>
|
<td>{{ asset.hostname }}</td>
|
||||||
<td>{{ asset.ip }}</td>
|
<td>{{ asset.ip }}</td>
|
||||||
<td>{{ user.port }}</td>
|
|
||||||
<td>
|
|
||||||
{% if asset.is_active %}
|
|
||||||
<i class="fa fa-times text-danger"></i>
|
|
||||||
{% else %}
|
|
||||||
<i class="fa fa-check text-navy"></i>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<button title="{{ asset.inherit_from_asset_groups }}" data-gid="{{ asset.id }}" class="btn btn-danger btn-xs btn-remove-asset {% if asset.is_inherit_from_asset_groups %} disabled {% endif %}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
|
<button title="{{ asset.inherit_from_asset_groups }}" data-gid="{{ asset.id }}" class="btn btn-danger btn-xs btn-remove-asset {% if asset.is_inherit_from_asset_groups %} disabled {% endif %}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
@ -27,11 +27,11 @@
|
||||||
<i class="fa fa-bar-chart-o"></i> {% trans 'Assets and asset groups' %}</a>
|
<i class="fa fa-bar-chart-o"></i> {% trans 'Assets and asset groups' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-default" href="{% url 'perms:asset-permission-update' pk=asset_permission.id %}"><i class="fa fa-edit"></i>Update</a>
|
<a class="btn btn-outline btn-default" href="{% url 'perms:asset-permission-update' pk=asset_permission.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-danger btn-delete-perm">
|
<a class="btn btn-outline btn-danger btn-delete-perm">
|
||||||
<i class="fa fa-edit"></i>Delete
|
<i class="fa fa-trash-o"></i>{% trans 'Delete' %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -113,7 +113,7 @@
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr class="no-borders-tr">
|
<tr class="no-borders-tr">
|
||||||
<td width="50%">Active:</td>
|
<td width="50%">{% trans 'Active' %} :</td>
|
||||||
<td><span style="float: right">
|
<td><span style="float: right">
|
||||||
<div class="switch">
|
<div class="switch">
|
||||||
<div class="onoffswitch">
|
<div class="onoffswitch">
|
||||||
|
@ -139,8 +139,8 @@
|
||||||
<table class="table" id="system-user-table">
|
<table class="table" id="system-user-table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<form>
|
<form>
|
||||||
<tr>
|
<tr class="no-borders-tr">
|
||||||
<td colspan="2" class="no-borders">
|
<td colspan="2">
|
||||||
<select data-placeholder="{% trans 'Select system users' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
|
<select data-placeholder="{% trans 'Select system users' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
|
||||||
{% for system_user in system_users_remain %}
|
{% for system_user in system_users_remain %}
|
||||||
<option value="{{ system_user.id }}" id="opt_{{ system_user.id }}">{{ system_user.name }}</option>
|
<option value="{{ system_user.id }}" id="opt_{{ system_user.id }}">{{ system_user.name }}</option>
|
||||||
|
@ -148,15 +148,15 @@
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr class="no-borders-tr">
|
||||||
<td colspan="2" class="no-borders">
|
<td colspan="2">
|
||||||
<button type="button" class="btn btn-info btn-small" id="btn-add-system-user">{% trans 'Add' %}</button>
|
<button type="button" class="btn btn-info btn-small" id="btn-add-system-user">{% trans 'Add' %}</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% for system_user in system_users %}
|
{% for system_user in system_users %}
|
||||||
<tr>
|
<tr {% if forloop.counter == 1 %} class="no-borders-tr" {% endif %} >
|
||||||
<td ><b class="bdg-system-user" data-uid={{ system_user.id }}>{{ system_user.name }}</b></td>
|
<td ><b class="bdg-system-user" data-uid={{ system_user.id }}>{{ system_user.name }}</b></td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-danger btn-xs btn-remove-user" data-uid="{{ system_user.id }}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
|
<button class="btn btn-danger btn-xs btn-remove-user" data-uid="{{ system_user.id }}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
|
||||||
|
@ -237,6 +237,16 @@ $(document).ready(function () {
|
||||||
}).get();
|
}).get();
|
||||||
updateSystemUser(system_users);
|
updateSystemUser(system_users);
|
||||||
$tr.remove()
|
$tr.remove()
|
||||||
|
}).on('click', '#is_active', function () {
|
||||||
|
var the_url = '{% url "api-perms:asset-permission-detail" pk=asset_permission.id %}';
|
||||||
|
var checked = $(this).prop('checked');
|
||||||
|
var body = {
|
||||||
|
'is_active': checked
|
||||||
|
};
|
||||||
|
APIUpdateAttr({
|
||||||
|
url: the_url,
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
});
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -69,9 +69,11 @@ function initTable() {
|
||||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
{targets: 8, createdCell: function (td, cellData) {
|
{targets: 8, createdCell: function (td, cellData, rowData) {
|
||||||
var update_btn = '<a href="{% url "perms:asset-permission-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
var update_btn = '<a href="{% url "perms:asset-permission-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
||||||
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del-permission" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-uid="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Delete" %}</a>'
|
||||||
|
.replace('{{ DEFAULT_PK }}', cellData)
|
||||||
|
.replace('99991938', rowData.name);
|
||||||
$(td).html(update_btn + del_btn);
|
$(td).html(update_btn + del_btn);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="wrapper wrapper-content animated fadeInRight">
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
@ -53,8 +53,6 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans 'Name' %}</th>
|
<th>{% trans 'Name' %}</th>
|
||||||
<th>{% trans 'Username' %}</th>
|
<th>{% trans 'Username' %}</th>
|
||||||
<th>{% trans 'Email' %}</th>
|
|
||||||
<th>{% trans 'Is valid' %}</th>
|
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -63,15 +61,6 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ user.name }}</td>
|
<td>{{ user.name }}</td>
|
||||||
<td>{{ user.username }}</td>
|
<td>{{ user.username }}</td>
|
||||||
<td>{{ user.email }}</td>
|
|
||||||
<td>
|
|
||||||
{% if user.is_expired and user.is_active %}
|
|
||||||
<i class="fa fa-times text-danger"></i>
|
|
||||||
{% else %}
|
|
||||||
<i class="fa fa-check text-navy"></i>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-danger btn-xs btn-remove-user {% if user.is_inherit_from_user_groups %} disabled {% endif %}" data-gid="{{ user.id }}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
|
<button class="btn btn-danger btn-xs btn-remove-user {% if user.is_inherit_from_user_groups %} disabled {% endif %}" data-gid="{{ user.id }}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
|
||||||
</td>
|
</td>
|
||||||
|
@ -231,7 +220,6 @@ $(document).ready(function () {
|
||||||
$.map(jumpserver.users_selected, function(value, index) {
|
$.map(jumpserver.users_selected, function(value, index) {
|
||||||
users_id.push(index);
|
users_id.push(index);
|
||||||
});
|
});
|
||||||
console.log(users_id);
|
|
||||||
addUsers(users_id);
|
addUsers(users_id);
|
||||||
}).on('click', '.btn-remove-user', function () {
|
}).on('click', '.btn-remove-user', function () {
|
||||||
var user_id = $(this).data("gid");
|
var user_id = $(this).data("gid");
|
||||||
|
|
|
@ -7,9 +7,7 @@ from .. import api
|
||||||
app_name = 'perms'
|
app_name = 'perms'
|
||||||
|
|
||||||
router = routers.DefaultRouter()
|
router = routers.DefaultRouter()
|
||||||
router.register('v1/asset-permissions',
|
router.register('v1/asset-permissions', api.AssetPermissionViewSet, 'asset-permission')
|
||||||
api.AssetPermissionViewSet,
|
|
||||||
'asset-permission')
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# 用户可以使用自己的Token或其它认证查看自己授权的资产,资产组等
|
# 用户可以使用自己的Token或其它认证查看自己授权的资产,资产组等
|
||||||
|
|
|
@ -11,6 +11,7 @@ from django.contrib.messages.views import SuccessMessageMixin
|
||||||
from django.views.generic.detail import DetailView, SingleObjectMixin
|
from django.views.generic.detail import DetailView, SingleObjectMixin
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
|
||||||
|
from common.const import create_success_msg, update_success_msg
|
||||||
from .hands import AdminUserRequiredMixin, User, UserGroup, SystemUser, \
|
from .hands import AdminUserRequiredMixin, User, UserGroup, SystemUser, \
|
||||||
Asset, AssetGroup
|
Asset, AssetGroup
|
||||||
from .models import AssetPermission
|
from .models import AssetPermission
|
||||||
|
@ -31,46 +32,12 @@ class AssetPermissionListView(AdminUserRequiredMixin, ListView):
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class MessageMixin:
|
|
||||||
def form_valid(self, form):
|
|
||||||
response = super().form_valid(form)
|
|
||||||
errors = self.object.check_system_user_in_assets()
|
|
||||||
if errors:
|
|
||||||
message = self.get_warning_messages(errors)
|
|
||||||
messages.warning(self.request, message)
|
|
||||||
else:
|
|
||||||
message = self.get_success_message(form.cleaned_data)
|
|
||||||
messages.success(self.request, message)
|
|
||||||
|
|
||||||
success_message = self.get_success_message(form.cleaned_data)
|
|
||||||
if success_message:
|
|
||||||
messages.success(self.request, success_message)
|
|
||||||
return response
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_warning_messages(errors):
|
|
||||||
message = "<b><i class='fa fa-warning'></i>WARNING: System user " \
|
|
||||||
"should in behind clusters, so that " \
|
|
||||||
"system user cat auto push to the cluster assets:</b> <br>"
|
|
||||||
for system_user, clusters in errors.items():
|
|
||||||
message += " >>> {}: {} ".format(system_user.name, ", ".join((cluster.name for cluster in clusters)))
|
|
||||||
return message
|
|
||||||
|
|
||||||
def get_success_message(self, cleaned_data):
|
|
||||||
url = reverse_lazy('perms:asset-permission-detail',
|
|
||||||
kwargs={'pk': self.object.pk})
|
|
||||||
success_message = _(
|
|
||||||
'Create asset permission <a href="{url}"> {name} </a> '
|
|
||||||
'successfully.'.format(url=url, name=self.object.name))
|
|
||||||
return success_message
|
|
||||||
|
|
||||||
|
|
||||||
class AssetPermissionCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
class AssetPermissionCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
model = AssetPermission
|
model = AssetPermission
|
||||||
form_class = AssetPermissionForm
|
form_class = AssetPermissionForm
|
||||||
template_name = 'perms/asset_permission_create_update.html'
|
template_name = 'perms/asset_permission_create_update.html'
|
||||||
success_url = reverse_lazy('perms:asset-permission-list')
|
success_url = reverse_lazy('perms:asset-permission-list')
|
||||||
warning = None
|
success_message = create_success_msg
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
|
@ -80,23 +47,13 @@ class AssetPermissionCreateView(AdminUserRequiredMixin, SuccessMessageMixin, Cre
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def get_success_message(self, cleaned_data):
|
|
||||||
url = reverse_lazy(
|
|
||||||
'perms:asset-permission-detail',
|
|
||||||
kwargs={'pk': self.object.pk}
|
|
||||||
)
|
|
||||||
success_message = _(
|
|
||||||
'Create asset permission <a href="{url}"> {name} </a> '
|
|
||||||
'success.'.format(url=url, name=self.object.name)
|
|
||||||
)
|
|
||||||
return success_message
|
|
||||||
|
|
||||||
|
|
||||||
class AssetPermissionUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
|
class AssetPermissionUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
model = AssetPermission
|
model = AssetPermission
|
||||||
form_class = AssetPermissionForm
|
form_class = AssetPermissionForm
|
||||||
template_name = 'perms/asset_permission_create_update.html'
|
template_name = 'perms/asset_permission_create_update.html'
|
||||||
success_url = reverse_lazy("perms:asset-permission-list")
|
success_url = reverse_lazy("perms:asset-permission-list")
|
||||||
|
success_message = update_success_msg
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
|
@ -106,17 +63,6 @@ class AssetPermissionUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, Upd
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def get_success_message(self, cleaned_data):
|
|
||||||
url = reverse_lazy(
|
|
||||||
'perms:asset-permission-detail',
|
|
||||||
kwargs={'pk': self.object.pk}
|
|
||||||
)
|
|
||||||
success_message = _(
|
|
||||||
'Update asset permission <a href="{url}"> {name} </a> '
|
|
||||||
'success.'.format(url=url, name=self.object.name)
|
|
||||||
)
|
|
||||||
return success_message
|
|
||||||
|
|
||||||
|
|
||||||
class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView):
|
class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView):
|
||||||
template_name = 'perms/asset_permission_detail.html'
|
template_name = 'perms/asset_permission_detail.html'
|
||||||
|
|
|
@ -61,7 +61,6 @@ function GetTableDataBox() {
|
||||||
id_list.push(i);
|
id_list.push(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(id_list);
|
|
||||||
for (i in id_list) {
|
for (i in id_list) {
|
||||||
console.log(tabProduct);
|
console.log(tabProduct);
|
||||||
tableData.push(GetRowData(tabProduct.rows[id_list[i]]));
|
tableData.push(GetRowData(tabProduct.rows[id_list[i]]));
|
||||||
|
@ -357,5 +356,15 @@ String.prototype.format = function(args) {
|
||||||
function setCookie(key, value) {
|
function setCookie(key, value) {
|
||||||
var expires = new Date();
|
var expires = new Date();
|
||||||
expires.setTime(expires.getTime() + (24 * 60 * 60 * 1000));
|
expires.setTime(expires.getTime() + (24 * 60 * 60 * 1000));
|
||||||
document.cookie = key + '=' + value + ';expires=' + expires.toUTCString();
|
document.cookie = key + '=' + value + ';expires=' + expires.toUTCString() + ';path=/';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function delCookie(key) {
|
||||||
|
var expires = new Date();
|
||||||
|
expires.setTime(expires.getTime() - 1);
|
||||||
|
var val = getCookie(key);
|
||||||
|
if (val !== null) {
|
||||||
|
document.cookie = key + '=' + val + ";expires" + expires.toUTCString() + ';path=/';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
{% block custom_head_css_js_create %} {% endblock %}
|
{% block custom_head_css_js_create %} {% endblock %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/datatables/datatables.min.css" %}" rel="stylesheet">
|
<link href="{% static "css/plugins/datatables/datatables.min.css" %}" rel="stylesheet">
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
<script src="{% static "js/plugins/datatables/datatables.min.js" %}"></script>
|
<script src="{% static "js/plugins/datatables/datatables.min.js" %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
<nav class="navbar navbar-static-top white-bg" role="navigation" style="margin-bottom: 0">
|
<nav class="navbar navbar-static-top white-bg" role="navigation" style="margin-bottom: 0">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<a class="navbar-minimalize minimalize-styl-2 btn btn-primary " href="#"><i class="fa fa-bars"></i> </a>
|
<a class="navbar-minimalize minimalize-styl-2 btn btn-primary " href="#"><i class="fa fa-bars"></i> </a>
|
||||||
<form role="search" class="navbar-form-custom" method="get" action="">
|
<!--<form role="search" class="navbar-form-custom" method="get" action="">-->
|
||||||
<div class="form-group">
|
<!--<div class="form-group">-->
|
||||||
<input type="text" placeholder="{% trans 'Search' %}..." class="form-control" name="search" id="top-search">
|
<!--<input type="text" placeholder="{% trans 'Search' %}..." class="form-control" name="search" id="top-search">-->
|
||||||
</div>
|
<!--</div>-->
|
||||||
</form>
|
<!--</form>-->
|
||||||
</div>
|
</div>
|
||||||
<ul class="nav navbar-top-links navbar-right">
|
<ul class="nav navbar-top-links navbar-right">
|
||||||
<li>
|
<li>
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
{% if user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
|
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
|
||||||
<span class="m-r-sm text-muted welcome-message">
|
<span class="m-r-sm text-muted welcome-message">
|
||||||
<img alt="image" class="img-circle" width="40" height="40" src="{{ request.user.avatar_url }}"/>
|
<img alt="image" class="img-circle" width="40" height="40" src="{{ request.user.avatar_url }}"/>
|
||||||
|
@ -30,17 +30,16 @@
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu animated fadeInRight m-t-xs">
|
<ul class="dropdown-menu animated fadeInRight m-t-xs">
|
||||||
<li><a href="{% url 'users:user-profile' %}">{% trans 'Profile' %}</a></li>
|
<li><a href="{% url 'users:user-profile' %}"><i class="fa fa-cogs"> </i><span> {% trans 'Profile' %}</span></a></li>
|
||||||
<li><a href="{% url 'users:user-profile-update' %}">{% trans 'Profile settings' %}</a></li>
|
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
{% if request.user.is_superuser %}
|
{% if request.user.is_superuser %}
|
||||||
{% if request.COOKIES.IN_ADMIN_PAGE == 'No' %}
|
{% if request.COOKIES.IN_ADMIN_PAGE == 'No' %}
|
||||||
<li><a id="switch_admin">{% trans 'Admin page' %}</a></li>
|
<li><a id="switch_admin"><i class="fa fa-exchange"></i><span> {% trans 'Admin page' %}</span></a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li><a id="switch_user">{% trans 'User page' %}</a></li>
|
<li><a id="switch_user"><i class="fa fa-exchange"></i><span> {% trans 'User page' %}</span></a></li>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
<li><a href="{% url 'users:logout' %}"><i class="fa fa-sign-out"></i> {% trans 'Logout' %}</a></li>
|
||||||
<li><a href="{% url 'users:logout' %}">{% trans 'Logout' %}</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'users:login' %}">
|
<a href="{% url 'users:login' %}">
|
||||||
|
|
|
@ -18,16 +18,19 @@
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
})
|
})
|
||||||
.on('click', '#switch_admin', function () {
|
.on('click', '#switch_admin', function () {
|
||||||
|
var cookieName = "IN_ADMIN_PAGE";
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
setCookie("IN_ADMIN_PAGE", "Yes");
|
delCookie(cookieName);
|
||||||
|
setCookie(cookieName, "Yes");
|
||||||
window.location = "/"
|
window.location = "/"
|
||||||
}, 100)
|
}, 100)
|
||||||
})
|
})
|
||||||
.on('click', '#switch_user', function () {
|
.on('click', '#switch_user', function () {
|
||||||
|
var cookieName = "IN_ADMIN_PAGE";
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
console.log("Set to No");
|
delCookie(cookieName);
|
||||||
setCookie("IN_ADMIN_PAGE", "No");
|
setCookie(cookieName, "No");
|
||||||
window.location = "/"
|
window.location = "{% url 'assets:user-asset-list' %}"
|
||||||
}, 100);
|
}, 100);
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -110,7 +110,6 @@ class StatusViewSet(viewsets.ModelViewSet):
|
||||||
|
|
||||||
def handle_sessions(self):
|
def handle_sessions(self):
|
||||||
sessions_active = []
|
sessions_active = []
|
||||||
|
|
||||||
for session_data in self.request.data.get("sessions", []):
|
for session_data in self.request.data.get("sessions", []):
|
||||||
self.create_or_update_session(session_data)
|
self.create_or_update_session(session_data)
|
||||||
if not session_data["is_finished"]:
|
if not session_data["is_finished"]:
|
||||||
|
@ -165,7 +164,7 @@ class StatusViewSet(viewsets.ModelViewSet):
|
||||||
|
|
||||||
class SessionViewSet(viewsets.ModelViewSet):
|
class SessionViewSet(viewsets.ModelViewSet):
|
||||||
queryset = Session.objects.all()
|
queryset = Session.objects.all()
|
||||||
serializers_class = SessionSerializer
|
serializer_class = SessionSerializer
|
||||||
permission_classes = (IsSuperUserOrAppUser,)
|
permission_classes = (IsSuperUserOrAppUser,)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
|
|
@ -12,7 +12,6 @@ class TerminalForm(forms.ModelForm):
|
||||||
model = Terminal
|
model = Terminal
|
||||||
fields = ['name', 'remote_addr', 'ssh_port', 'http_port', 'comment']
|
fields = ['name', 'remote_addr', 'ssh_port', 'http_port', 'comment']
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'remote_addr': _('A unique addr of every terminal, user browser can arrive it'),
|
|
||||||
'ssh_port': _("Coco ssh listen port"),
|
'ssh_port': _("Coco ssh listen port"),
|
||||||
'http_port': _("Coco http/ws listen port"),
|
'http_port': _("Coco http/ws listen port"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,7 @@ class Session(models.Model):
|
||||||
asset = models.CharField(max_length=1024, verbose_name=_("Asset"))
|
asset = models.CharField(max_length=1024, verbose_name=_("Asset"))
|
||||||
system_user = models.CharField(max_length=128, verbose_name=_("System user"))
|
system_user = models.CharField(max_length=128, verbose_name=_("System user"))
|
||||||
login_from = models.CharField(max_length=2, choices=LOGIN_FROM_CHOICES, default="ST")
|
login_from = models.CharField(max_length=2, choices=LOGIN_FROM_CHOICES, default="ST")
|
||||||
|
remote_addr = models.CharField(max_length=15, verbose_name=_("Remote addr"), blank=True, null=True)
|
||||||
is_finished = models.BooleanField(default=False)
|
is_finished = models.BooleanField(default=False)
|
||||||
has_replay = models.BooleanField(default=False, verbose_name=_("Replay"))
|
has_replay = models.BooleanField(default=False, verbose_name=_("Replay"))
|
||||||
has_command = models.BooleanField(default=False, verbose_name=_("Command"))
|
has_command = models.BooleanField(default=False, verbose_name=_("Command"))
|
||||||
|
|
|
@ -45,9 +45,9 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th data-toggle="true">ID</th>
|
<th data-toggle="true">ID</th>
|
||||||
<th>Command</th>
|
<th>{% trans 'Command' %}</th>
|
||||||
<th data-hide="all"></th>
|
<th data-hide="all"></th>
|
||||||
<th>Datetime</th>
|
<th>{% trans 'Datetime' %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -84,24 +84,24 @@
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
{% if object.is_finished %}
|
{% if object.is_finished %}
|
||||||
<tr>
|
<tr class="no-borders-tr">
|
||||||
<td class="no-borders">{% trans 'Replay session' %}:</td>
|
<td>{% trans 'Replay session' %}:</td>
|
||||||
<td class="no-borders">
|
<td>
|
||||||
<span class="pull-right">
|
<span class="pull-right">
|
||||||
<button type="button" class="btn btn-primary btn-xs" id="btn_reset_password" style="width: 54px">{% trans 'Go' %}</button>
|
<button type="button" onclick="window.open('/luna/replay/{{ object.id }}','luna', 'height=600, width=800, top=0, left=0, toolbar=no, menubar=no, scrollbars=no, location=no, status=no')" class="btn btn-primary btn-xs" id="btn_reset_password" style="width: 54px">{% trans 'Go' %}</button>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% else %}
|
{% else %}
|
||||||
<tr>
|
<!--<tr>-->
|
||||||
<td class="no-borders" >{% trans 'Monitor session' %}:</td>
|
<!--<td class="no-borders" >{% trans 'Monitor session' %}:</td>-->
|
||||||
<td class="no-borders" >
|
<!--<td class="no-borders" >-->
|
||||||
<span class="pull-right">
|
<!--<span class="pull-right">-->
|
||||||
<button type="button" class="btn btn-primary btn-xs " style="width: 54px">{% trans 'Go' %}</button>
|
<!--<button type="button" class="btn btn-primary btn-xs " style="width: 54px">{% trans 'Go' %}</button>-->
|
||||||
</span>
|
<!--</span>-->
|
||||||
</td>
|
<!--</td>-->
|
||||||
</tr>
|
<!--</tr>-->
|
||||||
<tr>
|
<tr class="no-borders-tr">
|
||||||
<td>{% trans 'Terminate session' %}:</td>
|
<td>{% trans 'Terminate session' %}:</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="pull-right">
|
<span class="pull-right">
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
<th class="text-center">{% trans 'User' %}</th>
|
<th class="text-center">{% trans 'User' %}</th>
|
||||||
<th class="text-center">{% trans 'Asset' %}</th>
|
<th class="text-center">{% trans 'Asset' %}</th>
|
||||||
<th class="text-center">{% trans 'System user' %}</th>
|
<th class="text-center">{% trans 'System user' %}</th>
|
||||||
|
<th class="text-center">{% trans 'Remote addr' %}</th>
|
||||||
<th class="text-center">{% trans 'Terminal' %}</th>
|
<th class="text-center">{% trans 'Terminal' %}</th>
|
||||||
<th class="text-center">{% trans 'Command' %}</th>
|
<th class="text-center">{% trans 'Command' %}</th>
|
||||||
<th class="text-center">{% trans 'Date start' %}</th>
|
<th class="text-center">{% trans 'Date start' %}</th>
|
||||||
|
@ -88,6 +89,7 @@
|
||||||
<td class="text-center">{{ session.user }}</td>
|
<td class="text-center">{{ session.user }}</td>
|
||||||
<td class="text-center">{{ session.asset }}</td>
|
<td class="text-center">{{ session.asset }}</td>
|
||||||
<td class="text-center">{{ session.system_user }}</td>
|
<td class="text-center">{{ session.system_user }}</td>
|
||||||
|
<td class="text-center">{{ session.remote_addr|default:"" }}</td>
|
||||||
<td class="text-center">{{ session.terminal.name }}</td>
|
<td class="text-center">{{ session.terminal.name }}</td>
|
||||||
<td class="text-center">{{ session.id | get_session_command_amount }}</td>
|
<td class="text-center">{{ session.id | get_session_command_amount }}</td>
|
||||||
|
|
||||||
|
@ -97,7 +99,7 @@
|
||||||
{% if session.is_finished %}
|
{% if session.is_finished %}
|
||||||
<a onclick="window.open('/luna/replay/{{ session.id }}','luna', 'height=600, width=800, top=0, left=0, toolbar=no, menubar=no, scrollbars=no, location=no, status=no')" class="btn btn-xs btn-warning btn-replay" >{% trans "Replay" %}</a>
|
<a onclick="window.open('/luna/replay/{{ session.id }}','luna', 'height=600, width=800, top=0, left=0, toolbar=no, menubar=no, scrollbars=no, location=no, status=no')" class="btn btn-xs btn-warning btn-replay" >{% trans "Replay" %}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a onclick="window.open('/luna/monitor/{{ session.id }}','luna', 'height=600, width=800, top=0, left=0, toolbar=no, menubar=no, scrollbars=no, location=no, status=no')" class="btn btn-xs btn-warning btn-monitor" >{% trans "Monitor" %}</a>
|
<!--<a onclick="window.open('/luna/monitor/{{ session.id }}','luna', 'height=600, width=800, top=0, left=0, toolbar=no, menubar=no, scrollbars=no, location=no, status=no')" class="btn btn-xs btn-warning btn-monitor" >{% trans "Monitor" %}</a>-->
|
||||||
<a class="btn btn-xs btn-danger btn-term" value="{{ session.id }}" terminal="{{ session.terminal.id }}" >{% trans "Terminate" %}</a>
|
<a class="btn btn-xs btn-danger btn-term" value="{{ session.id }}" terminal="{{ session.terminal.id }}" >{% trans "Terminate" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Terminal detail' %} </a>
|
<a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Terminal detail' %} </a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-default" href="{% url 'terminal:terminal-update' pk=terminal.id %}"><i class="fa fa-edit"></i>Update</a>
|
<a class="btn btn-outline btn-default" href="{% url 'terminal:terminal-update' pk=terminal.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
<td><b>{{ terminal.name }}</b></td>
|
<td><b>{{ terminal.name }}</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{% trans 'Remote address' %}:</td>
|
<td>{% trans 'Remote addr' %}:</td>
|
||||||
<td><b>{{ terminal.remote_addr }}</b></td>
|
<td><b>{{ terminal.remote_addr }}</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -136,7 +136,6 @@ $(document).ready(function(){
|
||||||
}).on('click', '.btn-connect', function () {
|
}).on('click', '.btn-connect', function () {
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
var id = $this.data('id');
|
var id = $this.data('id');
|
||||||
console.log(id)
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
<link href="{% static "css/plugins/datepicker/datepicker3.css" %}" rel="stylesheet">
|
<link href="{% static "css/plugins/datepicker/datepicker3.css" %}" rel="stylesheet">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
|
|
||||||
from django.views.generic import ListView, UpdateView, DeleteView, DetailView, TemplateView
|
from django.views.generic import ListView
|
||||||
from django.views.generic.edit import SingleObjectMixin
|
from django.views.generic.edit import SingleObjectMixin
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -51,9 +51,9 @@ class SessionListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView):
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'user_list': utils.get_user_list_from_cache(),
|
'user_list': utils.get_session_user_list(),
|
||||||
'asset_list': utils.get_asset_list_from_cache(),
|
'asset_list': utils.get_session_asset_list(),
|
||||||
'system_user_list': utils.get_system_user_list_from_cache(),
|
'system_user_list': utils.get_session_system_user_list(),
|
||||||
'date_from': self.date_from,
|
'date_from': self.date_from,
|
||||||
'date_to': self.date_to,
|
'date_to': self.date_to,
|
||||||
'user': self.user,
|
'user': self.user,
|
||||||
|
|
|
@ -128,7 +128,7 @@ class UserAuthApi(APIView):
|
||||||
user_agent = request.data.get('HTTP_USER_AGENT', '')
|
user_agent = request.data.get('HTTP_USER_AGENT', '')
|
||||||
|
|
||||||
if not login_ip:
|
if not login_ip:
|
||||||
login_ip = request.META.get("REMOTE_ADDR")
|
login_ip = request.META.get('HTTP_X_FORWARDED_FOR') or request.META.get("REMOTE_ADDR")
|
||||||
|
|
||||||
user, msg = check_user_valid(
|
user, msg = check_user_valid(
|
||||||
username=username, password=password,
|
username=username, password=password,
|
||||||
|
|
|
@ -29,7 +29,7 @@ class UserCreateUpdateForm(forms.ModelForm):
|
||||||
model = User
|
model = User
|
||||||
fields = [
|
fields = [
|
||||||
'username', 'name', 'email', 'groups', 'wechat',
|
'username', 'name', 'email', 'groups', 'wechat',
|
||||||
'phone', 'role', 'date_expired', 'comment', 'password'
|
'phone', 'role', 'date_expired', 'comment',
|
||||||
]
|
]
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'username': '* required',
|
'username': '* required',
|
||||||
|
@ -38,13 +38,16 @@ class UserCreateUpdateForm(forms.ModelForm):
|
||||||
}
|
}
|
||||||
widgets = {
|
widgets = {
|
||||||
'groups': forms.SelectMultiple(
|
'groups': forms.SelectMultiple(
|
||||||
attrs={'class': 'select2',
|
attrs={
|
||||||
'data-placeholder': _('Join user groups')}),
|
'class': 'select2',
|
||||||
|
'data-placeholder': _('Join user groups')
|
||||||
|
}
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
user = super().save(commit=commit)
|
|
||||||
password = self.cleaned_data.get('password')
|
password = self.cleaned_data.get('password')
|
||||||
|
user = super().save(commit=commit)
|
||||||
if password:
|
if password:
|
||||||
user.set_password(password)
|
user.set_password(password)
|
||||||
user.save()
|
user.save()
|
||||||
|
@ -184,12 +187,14 @@ class UserBulkUpdateForm(forms.ModelForm):
|
||||||
class UserGroupForm(forms.ModelForm):
|
class UserGroupForm(forms.ModelForm):
|
||||||
users = forms.ModelMultipleChoiceField(
|
users = forms.ModelMultipleChoiceField(
|
||||||
queryset=User.objects.all(),
|
queryset=User.objects.all(),
|
||||||
|
label=_("User"),
|
||||||
widget=forms.SelectMultiple(
|
widget=forms.SelectMultiple(
|
||||||
attrs={
|
attrs={
|
||||||
'class': 'select2',
|
'class': 'select2',
|
||||||
'data-placeholder': _('Select users')
|
'data-placeholder': _('Select users')
|
||||||
}
|
}
|
||||||
)
|
),
|
||||||
|
required=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
|
|
|
@ -168,6 +168,11 @@ class User(AbstractUser):
|
||||||
token = PrivateToken.objects.create(user=self)
|
token = PrivateToken.objects.create(user=self)
|
||||||
return token.key
|
return token.key
|
||||||
|
|
||||||
|
def create_access_key(self):
|
||||||
|
from . import AccessKey
|
||||||
|
access_key = AccessKey.objects.create(user=self)
|
||||||
|
return access_key
|
||||||
|
|
||||||
def refresh_private_token(self):
|
def refresh_private_token(self):
|
||||||
from .authentication import PrivateToken
|
from .authentication import PrivateToken
|
||||||
PrivateToken.objects.filter(user=self).delete()
|
PrivateToken.objects.filter(user=self).delete()
|
||||||
|
@ -214,13 +219,12 @@ class User(AbstractUser):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_app_user(cls, name, comment):
|
def create_app_user(cls, name, comment):
|
||||||
from . import AccessKey
|
|
||||||
app = cls.objects.create(
|
app = cls.objects.create(
|
||||||
username=name, name=name, email='{}@local.domain'.format(name),
|
username=name, name=name, email='{}@local.domain'.format(name),
|
||||||
is_active=False, role='App', enable_otp=False, comment=comment,
|
is_active=False, role='App', enable_otp=False, comment=comment,
|
||||||
is_first_login=False, created_by='System'
|
is_first_login=False, created_by='System'
|
||||||
)
|
)
|
||||||
access_key = AccessKey.objects.create(user=app)
|
access_key = app.create_access_key()
|
||||||
return app, access_key
|
return app, access_key
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
@ -22,11 +22,11 @@
|
||||||
<a href="{% url 'users:user-granted-asset' pk=user_object.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a>
|
<a href="{% url 'users:user-granted-asset' pk=user_object.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-default" href="{% url 'users:user-update' pk=user_object.id %}"><i class="fa fa-edit"></i>Update</a>
|
<a class="btn btn-outline btn-default" href="{% url 'users:user-update' pk=user_object.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-danger btn-delete-user">
|
<a class="btn btn-outline btn-danger btn-delete-user">
|
||||||
<i class="fa fa-edit"></i>Delete
|
<i class="fa fa-trash-o"></i>{% trans 'Delete' %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
@ -25,20 +25,6 @@
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% bootstrap_field form.name layout="horizontal" %}
|
{% bootstrap_field form.name layout="horizontal" %}
|
||||||
{% bootstrap_field form.users layout="horizontal" %}
|
{% bootstrap_field form.users layout="horizontal" %}
|
||||||
{# <div class="form-group">#}
|
|
||||||
{# <label for="users" class="col-sm-2 control-label">{% trans 'Users' %}</label>#}
|
|
||||||
{# <div class="col-sm-9">#}
|
|
||||||
{# <select name="users" id="id_users" data-placeholder="{% trans 'Select User' %}" class="select2 form-control m-b" multiple tabindex="2">#}
|
|
||||||
{# {% for user in users %}#}
|
|
||||||
{# {% if user.id in group_users %}#}
|
|
||||||
{# <option value="{{ user.id }}" selected>{{ user.name }}</option>#}
|
|
||||||
{# {% else %}#}
|
|
||||||
{# <option value="{{ user.id }}">{{ user.name }}</option>#}
|
|
||||||
{# {% endif %}#}
|
|
||||||
{# {% endfor %}#}
|
|
||||||
{# </select>#}
|
|
||||||
{# </div>#}
|
|
||||||
{# </div>#}
|
|
||||||
{% bootstrap_field form.comment layout="horizontal" %}
|
{% bootstrap_field form.comment layout="horizontal" %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-4 col-sm-offset-2">
|
<div class="col-sm-4 col-sm-offset-2">
|
||||||
|
@ -57,7 +43,9 @@
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('.select2').select2();
|
$('.select2').select2({
|
||||||
|
closeOnSelect: false
|
||||||
|
});
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||||
<link href="{% static "css/plugins/datatables/datatables.min.css" %}" rel="stylesheet">
|
<link href="{% static "css/plugins/datatables/datatables.min.css" %}" rel="stylesheet">
|
||||||
<link href="{% static "css/plugins/awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css" %}" rel="stylesheet">
|
<link href="{% static "css/plugins/awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css" %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||||
<script src="{% static "js/plugins/datatables/datatables.min.js" %}"></script>
|
<script src="{% static "js/plugins/datatables/datatables.min.js" %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -25,11 +25,11 @@
|
||||||
{# <a href="{% url 'users:user-group-granted-asset' pk=user_group.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a>#}
|
{# <a href="{% url 'users:user-group-granted-asset' pk=user_group.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a>#}
|
||||||
{# </li>#}
|
{# </li>#}
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-default" href="{% url 'users:user-group-update' pk=user_group.id %}"><i class="fa fa-edit"></i>Update</a>
|
<a class="btn btn-outline btn-default" href="{% url 'users:user-group-update' pk=user_group.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-danger btn-delete-user-group">
|
<a class="btn btn-outline btn-danger btn-delete-user-group">
|
||||||
<i class="fa fa-edit"></i>Delete
|
<i class="fa fa-trash-o"></i>{% trans 'Delete' %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -171,7 +171,6 @@ $(document).ready(function () {
|
||||||
var users = $('.bdg_user').map(function() {
|
var users = $('.bdg_user').map(function() {
|
||||||
return $(this).data('uid');
|
return $(this).data('uid');
|
||||||
}).get();
|
}).get();
|
||||||
console.log(users);
|
|
||||||
updateGroupMember(users)
|
updateGroupMember(users)
|
||||||
}).on('click', '#btn_add_user', function() {
|
}).on('click', '#btn_add_user', function() {
|
||||||
if (Object.keys(jumpserver.users_selected).length === 0) {
|
if (Object.keys(jumpserver.users_selected).length === 0) {
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="wrapper wrapper-content animated fadeInRight">
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
|
|
@ -223,7 +223,7 @@ $(document).ready(function(){
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
var name = $this.data('name');
|
var name = $this.data('name');
|
||||||
var uid = $this.data('uid');
|
var uid = $this.data('uid');
|
||||||
var the_url = '{% url "api-users:user-detail" pk='00000000-0000-0000-0000-000000000000' %}'.replace('00000000-0000-0000-0000-000000000000', uid);
|
var the_url = '{% url "api-users:user-detail" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", uid);
|
||||||
objectDelete($this, name, the_url);
|
objectDelete($this, name, the_url);
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -2,17 +2,15 @@
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.shortcuts import reverse, redirect
|
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.views.generic import ListView
|
|
||||||
from django.views.generic.base import TemplateView
|
from django.views.generic.base import TemplateView
|
||||||
from django.views.generic.edit import CreateView, UpdateView, FormMixin
|
from django.views.generic.edit import CreateView, UpdateView
|
||||||
from django.views.generic.detail import DetailView, SingleObjectMixin
|
from django.views.generic.detail import DetailView
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from perms.models import AssetPermission
|
from common.const import create_success_msg, update_success_msg
|
||||||
from ..models import User, UserGroup
|
from ..models import User, UserGroup
|
||||||
from ..utils import AdminUserRequiredMixin
|
from ..utils import AdminUserRequiredMixin
|
||||||
from .. import forms
|
from .. import forms
|
||||||
|
@ -39,7 +37,7 @@ class UserGroupCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVie
|
||||||
form_class = forms.UserGroupForm
|
form_class = forms.UserGroupForm
|
||||||
template_name = 'users/user_group_create_update.html'
|
template_name = 'users/user_group_create_update.html'
|
||||||
success_url = reverse_lazy('users:user-group-list')
|
success_url = reverse_lazy('users:user-group-list')
|
||||||
success_message = '<a href={url}> {name} </a> was created successfully'
|
success_message = create_success_msg
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
|
@ -49,21 +47,13 @@ class UserGroupCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVie
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def get_success_message(self, cleaned_data):
|
|
||||||
url = reverse_lazy(
|
|
||||||
'users:user-group-detail',
|
|
||||||
kwargs={'pk': self.object.id}
|
|
||||||
)
|
|
||||||
return self.success_message.format(
|
|
||||||
url=url, name=self.object.name
|
|
||||||
)
|
|
||||||
|
|
||||||
|
class UserGroupUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
class UserGroupUpdateView(AdminUserRequiredMixin, UpdateView):
|
|
||||||
model = UserGroup
|
model = UserGroup
|
||||||
form_class = forms.UserGroupForm
|
form_class = forms.UserGroupForm
|
||||||
template_name = 'users/user_group_create_update.html'
|
template_name = 'users/user_group_create_update.html'
|
||||||
success_url = reverse_lazy('users:user-group-list')
|
success_url = reverse_lazy('users:user-group-list')
|
||||||
|
success_message = update_success_msg
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
users = User.objects.all()
|
users = User.objects.all()
|
||||||
|
|
|
@ -53,7 +53,8 @@ class UserLoginView(FormView):
|
||||||
if not self.request.session.test_cookie_worked():
|
if not self.request.session.test_cookie_worked():
|
||||||
return HttpResponse(_("Please enable cookies and try again."))
|
return HttpResponse(_("Please enable cookies and try again."))
|
||||||
auth_login(self.request, form.get_user())
|
auth_login(self.request, form.get_user())
|
||||||
login_ip = self.request.META.get('REMOTE_ADDR', '')
|
login_ip = self.request.META.get('HTTP_X_FORWARDED_FOR') or \
|
||||||
|
self.request.META.get('REMOTE_ADDR', '')
|
||||||
user_agent = self.request.META.get('HTTP_USER_AGENT', '')
|
user_agent = self.request.META.get('HTTP_USER_AGENT', '')
|
||||||
write_login_log_async.delay(
|
write_login_log_async.delay(
|
||||||
self.request.user.username, type='W',
|
self.request.user.username, type='W',
|
||||||
|
@ -82,6 +83,7 @@ class UserLogoutView(TemplateView):
|
||||||
context = {
|
context = {
|
||||||
'title': _('Logout success'),
|
'title': _('Logout success'),
|
||||||
'messages': _('Logout success, return login page'),
|
'messages': _('Logout success, return login page'),
|
||||||
|
'interval': 1,
|
||||||
'redirect_url': reverse('users:login'),
|
'redirect_url': reverse('users:login'),
|
||||||
'auto_redirect': True,
|
'auto_redirect': True,
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,12 +27,14 @@ from django.views.generic.detail import DetailView, SingleObjectMixin
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from django.contrib.auth import logout as auth_logout
|
from django.contrib.auth import logout as auth_logout
|
||||||
|
|
||||||
|
from common.const import create_success_msg, update_success_msg
|
||||||
|
from common.mixins import JSONResponseMixin
|
||||||
|
from common.utils import get_logger, get_object_or_none, is_uuid
|
||||||
from .. import forms
|
from .. import forms
|
||||||
from ..models import User, UserGroup
|
from ..models import User, UserGroup
|
||||||
from ..utils import AdminUserRequiredMixin
|
from ..utils import AdminUserRequiredMixin
|
||||||
from ..signals import on_user_created
|
from ..signals import on_user_created
|
||||||
from common.mixins import JSONResponseMixin
|
|
||||||
from common.utils import get_logger, get_object_or_none, is_uuid
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'UserListView', 'UserCreateView', 'UserDetailView',
|
'UserListView', 'UserCreateView', 'UserDetailView',
|
||||||
|
@ -63,7 +65,7 @@ class UserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
form_class = forms.UserCreateUpdateForm
|
form_class = forms.UserCreateUpdateForm
|
||||||
template_name = 'users/user_create.html'
|
template_name = 'users/user_create.html'
|
||||||
success_url = reverse_lazy('users:user-list')
|
success_url = reverse_lazy('users:user-list')
|
||||||
success_message = _('Create user <a href="{url}">{name}</a> successfully.')
|
success_message = create_success_msg
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
@ -77,19 +79,14 @@ class UserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
on_user_created.send(self.__class__, user=user)
|
on_user_created.send(self.__class__, user=user)
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
def get_success_message(self, cleaned_data):
|
|
||||||
url = reverse_lazy('users:user-detail', kwargs={'pk': self.object.pk})
|
|
||||||
return self.success_message.format(
|
|
||||||
url=url, name=self.object.name
|
|
||||||
)
|
|
||||||
|
|
||||||
|
class UserUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
class UserUpdateView(AdminUserRequiredMixin, UpdateView):
|
|
||||||
model = User
|
model = User
|
||||||
form_class = forms.UserCreateUpdateForm
|
form_class = forms.UserCreateUpdateForm
|
||||||
template_name = 'users/user_update.html'
|
template_name = 'users/user_update.html'
|
||||||
context_object_name = 'user_object'
|
context_object_name = 'user_object'
|
||||||
success_url = reverse_lazy('users:user-list')
|
success_url = reverse_lazy('users:user-list')
|
||||||
|
success_message = update_success_msg
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {'app': _('Users'), 'action': _('Update user')}
|
context = {'app': _('Users'), 'action': _('Update user')}
|
||||||
|
@ -332,17 +329,10 @@ class UserProfileUpdateView(LoginRequiredMixin, UpdateView):
|
||||||
model = User
|
model = User
|
||||||
form_class = forms.UserProfileForm
|
form_class = forms.UserProfileForm
|
||||||
success_url = reverse_lazy('users:user-profile')
|
success_url = reverse_lazy('users:user-profile')
|
||||||
success_message = _('Create user <a href="{url}">{name}</a> successfully.')
|
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
return self.request.user
|
return self.request.user
|
||||||
|
|
||||||
def get_success_message(self, cleaned_data):
|
|
||||||
url = reverse_lazy('users:user-detail', kwargs={'pk': self.object.pk})
|
|
||||||
return self.success_message.format(
|
|
||||||
url=url, name=self.object.name
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'app': _('User'),
|
'app': _('User'),
|
||||||
|
|
Loading…
Reference in New Issue