diff --git a/apps/assets/api.py b/apps/assets/api.py index 3bc6c5639..e5c5a44ff 100644 --- a/apps/assets/api.py +++ b/apps/assets/api.py @@ -26,7 +26,7 @@ from .hands import IsSuperUser, IsValidUser, IsSuperUserOrAppUser, \ get_user_granted_assets from .models import AssetGroup, Asset, Cluster, SystemUser, AdminUser 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_system_user_connectability_manual @@ -40,18 +40,14 @@ class AssetViewSet(IDInFilterMixin, BulkModelViewSet): """ queryset = Asset.objects.all() serializer_class = serializers.AssetSerializer - permission_classes = (IsValidUser,) + permission_classes = (IsSuperUserOrAppUser,) def get_queryset(self): - if self.request.user.is_superuser or self.request.user.is_app: - 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]) - + queryset = super().get_queryset() cluster_id = self.request.query_params.get('cluster_id') asset_group_id = self.request.query_params.get('asset_group_id') admin_user_id = self.request.query_params.get('admin_user_id') + system_user_id = self.request.query_params.get('system_user_id') if 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()] clusters = [cluster.id for cluster in admin_user.cluster_set.all()] 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 @@ -99,15 +112,6 @@ class GroupAddAssetsApi(generics.UpdateAPIView): 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): """ Cluster api set, for add,delete,update,list,retrieve resource @@ -117,7 +121,6 @@ class ClusterViewSet(IDInFilterMixin, BulkModelViewSet): permission_classes = (IsSuperUser,) -# TOdo class ClusterTestAssetsAliveApi(generics.RetrieveAPIView): """ Test cluster asset can connect using admin user or not @@ -127,6 +130,9 @@ class ClusterTestAssetsAliveApi(generics.RetrieveAPIView): def retrieve(self, request, *args, **kwargs): 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): @@ -256,7 +262,7 @@ class AdminUserTestConnectiveApi(generics.RetrieveAPIView): def retrieve(self, request, *args, **kwargs): 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"}) diff --git a/apps/assets/forms.py b/apps/assets/forms.py index 431c174a6..68aaddc43 100644 --- a/apps/assets/forms.py +++ b/apps/assets/forms.py @@ -36,7 +36,7 @@ class AssetCreateForm(forms.ModelForm): def clean_admin_user(self): cluster = self.cleaned_data.get('cluster') 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")) return self.cleaned_data['admin_user'] @@ -64,7 +64,7 @@ class AssetUpdateForm(forms.ModelForm): def clean_admin_user(self): cluster = self.cleaned_data.get('cluster') 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")) return self.cleaned_data['admin_user'] @@ -124,20 +124,25 @@ class AssetGroupForm(forms.ModelForm): label=_('Asset'), required=False, widget=forms.SelectMultiple( - attrs={'class': 'select2', 'data-placeholder': _('Select assets')}) + attrs={'class': 'select2', 'data-placeholder': _('Select assets')} ) + ) - def __init__(self, *args, **kwargs): - if kwargs.get('instance', None): + def __init__(self, **kwargs): + instance = kwargs.get('instance') + if instance: initial = kwargs.get('initial', {}) - initial['assets'] = kwargs['instance'].assets.all() - super(AssetGroupForm, self).__init__(*args, **kwargs) + initial.update({ + 'assets': instance.assets.all(), + }) + kwargs['initial'] = initial + super().__init__(**kwargs) - def _save_m2m(self): - super(AssetGroupForm, self)._save_m2m() - assets = self.cleaned_data['assets'] - self.instance.assets.clear() - self.instance.assets.add(*tuple(assets)) + def save(self, commit=True): + group = super().save(commit=commit) + assets= self.cleaned_data['assets'] + group.assets.set(assets) + return group class Meta: model = AssetGroup @@ -150,10 +155,19 @@ class AssetGroupForm(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: model = Cluster - fields = ['name', "bandwidth", "operator", 'contact', 'admin_user', + fields = ['name', "bandwidth", "operator", 'contact', 'admin_user', 'system_users', 'phone', 'address', 'intranet', 'extranet', 'comment'] widgets = { 'name': forms.TextInput(attrs={'placeholder': _('Name')}), @@ -162,9 +176,21 @@ class ClusterForm(forms.ModelForm): } help_texts = { '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): # Form field name can not start with `_`, so redefine it, @@ -172,9 +198,10 @@ class AdminUserForm(forms.ModelForm): widget=forms.PasswordInput, max_length=128, strip=True, required=False, help_text=_('Password or private key password'), + label=_("Password"), ) # 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): # Because we define custom field, so we need rewrite :method: `save` @@ -204,12 +231,14 @@ class AdminUserForm(forms.ModelForm): return private_key_file def clean(self): + super().clean() password = self.cleaned_data['password'] private_key_file = self.cleaned_data.get('private_key_file', '') - if not self.instance and not (password or private_key_file): - raise forms.ValidationError( - _('Password and private key file must be input one')) + if not password and not private_key_file: + raise forms.ValidationError(_( + 'Password and private key file must be input one' + )) class Meta: model = AdminUser @@ -229,9 +258,10 @@ class SystemUserForm(forms.ModelForm): # Admin user assets define, let user select, save it in form not in view auto_generate_key = forms.BooleanField(initial=True, required=False) # Form field name can not start with `_`, so redefine it, - password = forms.CharField(widget=forms.PasswordInput, required=False, max_length=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 - private_key_file = forms.FileField(required=False) + private_key_file = forms.FileField(required=False, label=_("Private key")) def save(self, commit=True): # 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')}), 'username': forms.TextInput(attrs={'placeholder': _('Username')}), 'cluster': forms.SelectMultiple( - attrs={'class': 'select2', - 'data-placeholder': _(' Select clusters')}), + attrs={ + 'class': 'select2', + 'data-placeholder': _(' Select clusters') + } + ), } help_texts = { 'name': '* required', 'username': '* required', - 'cluster': 'If auto push checked, system user will be create at cluster assets', - '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', + 'cluster': _('If auto push checked, system user will be create at cluster assets'), + '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'), } diff --git a/apps/assets/models/asset.py b/apps/assets/models/asset.py index 6d1ba3f20..c83443077 100644 --- a/apps/assets/models/asset.py +++ b/apps/assets/models/asset.py @@ -18,6 +18,16 @@ __all__ = ['Asset'] 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): # Todo: Move them to settings STATUS_CHOICES = ( @@ -44,7 +54,7 @@ class Asset(models.Model): hostname = models.CharField(max_length=128, unique=True, verbose_name=_('Hostname')) port = models.IntegerField(default=22, verbose_name=_('Port')) groups = models.ManyToManyField(AssetGroup, blank=True, related_name='assets', verbose_name=_('Asset groups')) - 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')) 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'),) @@ -158,6 +168,7 @@ class Asset(models.Model): class Meta: unique_together = ('ip', 'port') + verbose_name = _("Asset") @classmethod def generate_fake(cls, count=100): diff --git a/apps/assets/models/cluster.py b/apps/assets/models/cluster.py index 3b66555c3..8d093979e 100644 --- a/apps/assets/models/cluster.py +++ b/apps/assets/models/cluster.py @@ -37,6 +37,7 @@ class Cluster(models.Model): class Meta: ordering = ['name'] + verbose_name = _("Cluster") @classmethod def generate_fake(cls, count=5): diff --git a/apps/assets/models/group.py b/apps/assets/models/group.py index 18b0c5289..c01a2a529 100644 --- a/apps/assets/models/group.py +++ b/apps/assets/models/group.py @@ -27,6 +27,7 @@ class AssetGroup(models.Model): class Meta: ordering = ['name'] + verbose_name = _("Asset group") @classmethod def initial(cls): diff --git a/apps/assets/models/user.py b/apps/assets/models/user.py index 863535ef2..aa44a539c 100644 --- a/apps/assets/models/user.py +++ b/apps/assets/models/user.py @@ -81,7 +81,11 @@ class AssetUser(models.Model): @property def public_key(self): - return signer.unsign(self._public_key) + key = signer.unsign(self._public_key) + if key: + return key + else: + return None @property def public_key_obj(self): @@ -170,7 +174,6 @@ class AdminUser(AssetUser): info = None return info - def get_related_assets(self): assets = [] for cluster in self.cluster_set.all(): @@ -184,6 +187,7 @@ class AdminUser(AssetUser): class Meta: ordering = ['name'] + verbose_name = _("Admin user") @classmethod def generate_fake(cls, count=10): @@ -224,7 +228,7 @@ class SystemUser(AssetUser): def get_clusters_assets(self): from .asset import Asset - clusters = self.cluster.all() + clusters = self.get_clusters() return Asset.objects.filter(cluster__in=clusters) def get_clusters(self): @@ -262,6 +266,7 @@ class SystemUser(AssetUser): class Meta: ordering = ['name'] + verbose_name = _("System user") @classmethod def generate_fake(cls, count=10): diff --git a/apps/assets/serializers.py b/apps/assets/serializers.py index 1e6662160..401aeac2a 100644 --- a/apps/assets/serializers.py +++ b/apps/assets/serializers.py @@ -64,6 +64,7 @@ class AdminUserSerializer(serializers.ModelSerializer): """ assets_amount = serializers.SerializerMethodField() unreachable_amount = serializers.SerializerMethodField() + reachable_amount = serializers.SerializerMethodField() class Meta: model = AdminUser @@ -75,7 +76,15 @@ class AdminUserSerializer(serializers.ModelSerializer): if data: return len(data.get('dark')) 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 def get_assets_amount(obj): @@ -183,7 +192,7 @@ class AssetGrantedSerializer(serializers.ModelSerializer): class Meta(object): model = Asset 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",) @staticmethod diff --git a/apps/assets/signals_handler.py b/apps/assets/signals_handler.py index dfd264677..63dc3e882 100644 --- a/apps/assets/signals_handler.py +++ b/apps/assets/signals_handler.py @@ -27,16 +27,17 @@ def test_asset_conn_on_created(asset): def push_cluster_system_users_to_asset(asset): - logger.info("Push cluster system user to asset: {}".format(asset)) - task_name = _("Push cluster system users to asset") - system_users = asset.cluster.systemuser_set.all() - push_system_user_util.delay(system_users, [asset], task_name) + if asset.cluster: + logger.info("Push cluster system user to asset: {}".format(asset)) + task_name = _("Push cluster system users to asset") + 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") def on_asset_created(sender, instance=None, created=False, **kwargs): 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) test_asset_conn_on_created(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") def on_cluster_init(sender, instance, **kwargs): 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") @@ -103,11 +104,11 @@ def on_cluster_assets_changed(sender, instance, **kwargs): 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): system_users_origin = instance.__origin_system_users 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: logger.debug("Receive cluster change system users signal") system_users = [] diff --git a/apps/assets/tasks.py b/apps/assets/tasks.py index ab74c170a..f06f720d9 100644 --- a/apps/assets/tasks.py +++ b/apps/assets/tasks.py @@ -25,7 +25,7 @@ disk_pattern = re.compile(r'^hd|sd|xvd') @shared_task 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 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 if task_name is None: - task_name = "Test asset connectability" + task_name = _("Test asset connectability") hosts = [asset.hostname] + if not hosts: + logger.info("No hosts, passed") + return {} tasks = const.TEST_ADMIN_USER_CONN_TASKS task, created = update_or_create_ansible_task( 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() hosts = [asset.hostname for asset in assets] tasks = const.TEST_SYSTEM_USER_CONN_TASKS + if not hosts: + logger.info("No hosts, passed") + return {} task, created = update_or_create_ansible_task( task_name, hosts=hosts, tasks=tasks, pattern='all', options=const.TASK_OPTIONS, @@ -274,7 +280,7 @@ def test_system_user_connectability_util(system_user, task_name): @shared_task 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) @@ -303,6 +309,10 @@ def test_system_user_connectability_period(): #### Push system user tasks #### def get_push_system_user_tasks(system_user): + # Set root as system user is dangerous + if system_user.username == "root": + return [] + tasks = [ { 'name': 'Add user {}'.format(system_user.username), @@ -310,7 +320,7 @@ def get_push_system_user_tasks(system_user): 'module': 'user', 'args': 'name={} shell={} state=present password={}'.format( 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: tasks.extend(get_push_system_user_tasks(system_user)) - print("Task: ", tasks) if not tasks: - return + logger.info("Not tasks, passed") + return {} hosts = [asset.hostname for asset in assets] + if not hosts: + logger.info("Not hosts, passed") + return {} task, created = update_or_create_ansible_task( task_name=task_name, hosts=hosts, tasks=tasks, pattern='all', 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: tasks.extend(get_push_system_user_tasks(system_user)) - task_name = _("Push system user to cluster assets period: {}->{}").format( - cluster.name, ', '.join(s.name for s in system_users) + task_name = _("Push cluster system users to assets period: {}").format( + cluster.name ) hosts = [asset.hostname for asset in cluster.assets.all()] update_or_create_ansible_task( diff --git a/apps/assets/templates/assets/_system_user.html b/apps/assets/templates/assets/_system_user.html index 99b64af30..34501ef49 100644 --- a/apps/assets/templates/assets/_system_user.html +++ b/apps/assets/templates/assets/_system_user.html @@ -3,8 +3,8 @@ {% load static %} {% load bootstrap3 %} {% block custom_head_css_js %} - - + + {% endblock %} {% block content %} diff --git a/apps/assets/templates/assets/admin_user_assets.html b/apps/assets/templates/assets/admin_user_assets.html index 4b0429605..dcaaef312 100644 --- a/apps/assets/templates/assets/admin_user_assets.html +++ b/apps/assets/templates/assets/admin_user_assets.html @@ -21,11 +21,11 @@ {% trans 'Assets list' %}
  • - Update + {% trans 'Update' %}
  • - Delete + {% trans 'Delete' %}
  • @@ -60,7 +60,7 @@ {% trans 'IP' %} {% trans 'Port' %} {% trans 'Type' %} - {% trans 'Alive' %} + {% trans 'Reachable' %} @@ -144,7 +144,7 @@ $(document).ready(function () { url: the_url, error: error, method: 'GET', - success_message: "{% trans "Task has been send, seen left asset status" %}" + success_message: "{% trans 'Task has been send, seen left asset status' %}" }); }) diff --git a/apps/assets/templates/assets/admin_user_create_update.html b/apps/assets/templates/assets/admin_user_create_update.html index d7d5094ff..3d1772172 100644 --- a/apps/assets/templates/assets/admin_user_create_update.html +++ b/apps/assets/templates/assets/admin_user_create_update.html @@ -3,8 +3,8 @@ {% load static %} {% load bootstrap3 %} {% block custom_head_css_js %} - - + + {% endblock %} {% block content %} diff --git a/apps/assets/templates/assets/admin_user_detail.html b/apps/assets/templates/assets/admin_user_detail.html index b7fca5f7a..18464dde4 100644 --- a/apps/assets/templates/assets/admin_user_detail.html +++ b/apps/assets/templates/assets/admin_user_detail.html @@ -21,11 +21,11 @@ {% trans 'Assets list' %}
  • - Update + {% trans 'Update' %}
  • - Delete + {% trans 'Delete' %}
  • @@ -133,7 +133,6 @@ function bindToCluster(clusters) { $('.select2-selection__rendered').empty(); $('#cluster_selected').val(''); $.map(jumpserver.cluster_selected, function(cluster_name, index) { - console.log(index); $('#opt_' + index).remove(); // change tr html of user groups. $('#table-clusters tbody').append( diff --git a/apps/assets/templates/assets/admin_user_list.html b/apps/assets/templates/assets/admin_user_list.html index cc7cfc8cf..f7c13a32f 100644 --- a/apps/assets/templates/assets/admin_user_list.html +++ b/apps/assets/templates/assets/admin_user_list.html @@ -21,8 +21,10 @@ {% trans 'Name' %} {% trans 'Username' %} - {% trans 'Asset num' %} + {% trans 'Asset' %} + {% trans 'Reachable' %} {% trans 'Unreachable' %} + {% trans 'Ratio' %} {% trans 'Comment' %} {% trans 'Action' %} @@ -41,17 +43,50 @@ $(document).ready(function(){ {targets: 1, createdCell: function (td, cellData, rowData) { var detail_btn = '' + cellData + ''; $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); - }}, + }}, + {targets: 4, createdCell: function (td, cellData) { + var innerHtml = ""; + if (cellData !== 0) { + innerHtml = "" + cellData + ""; + } else { + innerHtml = "" + cellData + ""; + } + $(td).html('' + innerHtml + ''); + }}, + {targets: 5, createdCell: function (td, cellData) { + var innerHtml = ""; + if (cellData !== 0) { + innerHtml = "" + cellData + ""; + } else { + innerHtml = "" + cellData + ""; + } + $(td).html('' + innerHtml + ''); + }}, {targets: 6, createdCell: function (td, cellData, rowData) { -{# var script_btn = '{% trans "Script" %}'.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 = "" + val + "% "; + } else { + innerHtml = "" + val + "% "; + } + $(td).html('' + innerHtml + ''); + + }}, + {targets: 8, createdCell: function (td, cellData, rowData) { var update_btn = '{% trans "Update" %}'.replace('{{ DEFAULT_PK }}', cellData); var del_btn = '{% trans "Delete" %}'.replace('{{ DEFAULT_PK }}', cellData); -{# $(td).html(script_btn + update_btn + del_btn)#} $(td).html(update_btn + del_btn) }}], ajax_url: '{% url "api-assets:admin-user-list" %}', 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); }) diff --git a/apps/assets/templates/assets/asset_detail.html b/apps/assets/templates/assets/asset_detail.html index e19691628..fc2320420 100644 --- a/apps/assets/templates/assets/asset_detail.html +++ b/apps/assets/templates/assets/asset_detail.html @@ -21,11 +21,11 @@ {% if user.is_superuser %}
  • - Update + {% trans 'Update' %}
  • - Delete + {% trans 'Delete' %}
  • {% endif %} diff --git a/apps/assets/templates/assets/asset_group_create.html b/apps/assets/templates/assets/asset_group_create.html index 3b951d4d1..36ca40fc1 100644 --- a/apps/assets/templates/assets/asset_group_create.html +++ b/apps/assets/templates/assets/asset_group_create.html @@ -1,119 +1,31 @@ -{% extends 'base.html' %} -{% load i18n %} +{% extends '_base_create_update.html' %} {% load static %} {% load bootstrap3 %} -{% block custom_head_css_js %} - - -{% endblock %} -{% block content %} -
    -
    -
    -
    -
    -
    {{ action }}
    - -
    +{% load i18n %} -
    -
    -
    -
    -
    - {% csrf_token %} -

    资产组信息

    - {% bootstrap_field form.name layout="horizontal" %} - {% bootstrap_field form.comment layout="horizontal" %} -{#
    #} -{#

    用户选择的资产

    #} -{#
    #} -{# #} -{#
    #} -{#
    #} -{#

    #} -{# {% for asset in assets_on_list %}#} -{# #} -{# {% endfor %}#} -{#

    #} -{#
    #} -{#
    #} -{#
    #} -
    -
    -
    - - -
    -
    -
    -
    -
    -
    -
    -
    -
    +{% block form %} +
    + {% csrf_token %} + {% bootstrap_field form.name layout="horizontal" %} + {% bootstrap_field form.assets layout="horizontal" %} + {% bootstrap_field form.comment layout="horizontal" %} + +
    +
    +
    + +
    -
    - - - - + {% endblock %} {% block custom_foot_js %} {% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/asset_group_detail.html b/apps/assets/templates/assets/asset_group_detail.html index be8655d20..4a9b719b1 100644 --- a/apps/assets/templates/assets/asset_group_detail.html +++ b/apps/assets/templates/assets/asset_group_detail.html @@ -3,8 +3,8 @@ {% load i18n %} {% block custom_head_css_js %} - - + + {% endblock %} {% block content %} @@ -212,7 +217,6 @@ $(document).ready(function () { addAssets(assets_id); }) - .on('click', '.btn-leave-group', function () { var $this = $(this); 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'); assets.remove(delete_asset_id); - console.log(assets); var data = {"assets": assets}; 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); }) diff --git a/apps/assets/templates/assets/asset_group_list.html b/apps/assets/templates/assets/asset_group_list.html index 83fcacd1a..e27d78867 100644 --- a/apps/assets/templates/assets/asset_group_list.html +++ b/apps/assets/templates/assets/asset_group_list.html @@ -75,8 +75,6 @@ $(document).ready(function(){ return false; } var the_url = '{% url "api-assets:asset-group-list" %}'; - console.log(plain_id_list); - console.log(the_url); function doDelete() { swal({ title: "{% trans 'Are you sure?' %}", diff --git a/apps/assets/templates/assets/asset_list.html b/apps/assets/templates/assets/asset_list.html index 6bab2f5e3..0a19ba3de 100644 --- a/apps/assets/templates/assets/asset_list.html +++ b/apps/assets/templates/assets/asset_list.html @@ -109,7 +109,7 @@ function initTable() { $(document).ready(function(){ initTable(); }) -.on('click', '#btn_export', function () { +.on('click', '.btn_export', function () { var $data_table = $('#asset_list_table').DataTable(); var rows = $data_table.rows('.selected').data(); 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'); $form.find('.help-block').remove(); function success (data) { diff --git a/apps/assets/templates/assets/asset_update.html b/apps/assets/templates/assets/asset_update.html index fea3249e6..b0cbc484b 100644 --- a/apps/assets/templates/assets/asset_update.html +++ b/apps/assets/templates/assets/asset_update.html @@ -46,7 +46,6 @@

    {% trans 'Other' %}

    {% bootstrap_field form.status layout="horizontal" %} - {% bootstrap_field form.env layout="horizontal" %} {% bootstrap_field form.comment layout="horizontal" %} {% bootstrap_field form.is_active layout="horizontal" %} diff --git a/apps/assets/templates/assets/cluster_assets.html b/apps/assets/templates/assets/cluster_assets.html index 72f4ed81f..b194a5034 100644 --- a/apps/assets/templates/assets/cluster_assets.html +++ b/apps/assets/templates/assets/cluster_assets.html @@ -3,8 +3,8 @@ {% load i18n %} {% block custom_head_css_js %} - - + + @@ -94,7 +94,7 @@ @@ -204,7 +204,12 @@ $(document).ready(function () { addAssets(assets_id); }) .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' %}" + }); }) {% endblock %} diff --git a/apps/assets/templates/assets/cluster_create_update.html b/apps/assets/templates/assets/cluster_create_update.html index b36af260e..38fc6e3de 100644 --- a/apps/assets/templates/assets/cluster_create_update.html +++ b/apps/assets/templates/assets/cluster_create_update.html @@ -3,8 +3,8 @@ {% load static %} {% load bootstrap3 %} {% block custom_head_css_js %} - - + + {% endblock %} {% block content %}
    @@ -40,6 +40,7 @@

    {% trans 'Settings' %}

    {% bootstrap_field form.admin_user layout="horizontal" %} + {% bootstrap_field form.system_users layout="horizontal" %}

    {% trans 'Other' %}

    @@ -69,10 +70,7 @@ {% block custom_foot_js %} {% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/cluster_detail.html b/apps/assets/templates/assets/cluster_detail.html index cd2ecd25e..837e36e68 100644 --- a/apps/assets/templates/assets/cluster_detail.html +++ b/apps/assets/templates/assets/cluster_detail.html @@ -3,8 +3,8 @@ {% load i18n %} {% block custom_head_css_js %} - - + + {% endblock %} {% block content %}
    @@ -22,11 +22,11 @@
  • - Update + {% trans 'Update' %}
  • - Delete + {% trans 'Delete' %}
  • diff --git a/apps/assets/templates/assets/cluster_list.html b/apps/assets/templates/assets/cluster_list.html index b6c0abfb2..e4743b346 100644 --- a/apps/assets/templates/assets/cluster_list.html +++ b/apps/assets/templates/assets/cluster_list.html @@ -8,7 +8,7 @@ {% block table_search %}{% endblock %} {% block table_container %} diff --git a/apps/assets/templates/assets/system_user_asset.html b/apps/assets/templates/assets/system_user_asset.html index 75e1b264d..afff889f6 100644 --- a/apps/assets/templates/assets/system_user_asset.html +++ b/apps/assets/templates/assets/system_user_asset.html @@ -3,8 +3,8 @@ {% load i18n %} {% block custom_head_css_js %} - - + + {% endblock %} {% block content %}
    @@ -22,7 +22,7 @@
  • - Update + {% trans 'Update' %}
  • diff --git a/apps/assets/templates/assets/system_user_detail.html b/apps/assets/templates/assets/system_user_detail.html index c4ee49443..0bf591bb2 100644 --- a/apps/assets/templates/assets/system_user_detail.html +++ b/apps/assets/templates/assets/system_user_detail.html @@ -23,7 +23,12 @@
  • - Update + {% trans 'Update' %} +
  • +
  • + + {% trans 'Delete' %} +
  • @@ -259,6 +264,13 @@ $(document).ready(function () { return $(this).data('gid'); }).get(); 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); }) {% endblock %} diff --git a/apps/assets/templates/assets/user_asset_list.html b/apps/assets/templates/assets/user_asset_list.html index 100e09525..20c7d4d50 100644 --- a/apps/assets/templates/assets/user_asset_list.html +++ b/apps/assets/templates/assets/user_asset_list.html @@ -42,7 +42,6 @@ function initTable() { columnDefs: [ {targets: 1, createdCell: function (td, cellData, rowData) { {% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %} - console.log('{{ the_url }}'); var detail_btn = '' + cellData + ''; $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id)); }}, @@ -67,7 +66,7 @@ function initTable() { $(td).html(conn_btn) }} ], - ajax_url: '{% url "api-assets:asset-list" %}', + ajax_url: '{% url "api-assets:user-asset-list" %}', columns: [ {data: "id"}, {data: "hostname" }, {data: "ip" }, {data: "port" }, {data: "get_type_display" }, {data: "get_env_display"}, {data: "hardware_info"}, diff --git a/apps/assets/urls/api_urls.py b/apps/assets/urls/api_urls.py index 24e7a6c3b..503464b31 100644 --- a/apps/assets/urls/api_urls.py +++ b/apps/assets/urls/api_urls.py @@ -21,16 +21,18 @@ urlpatterns = [ api.AssetRefreshHardwareApi.as_view(), name='asset-refresh'), url(r'^v1/assets/(?P[0-9a-zA-Z\-]{36})/alive/$', 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 url(r'^v1/groups/(?P[0-9a-zA-Z\-]{36})/assets/$', api.GroupUpdateAssetsApi.as_view(), name='group-update-assets'), url(r'^v1/groups/(?P[0-9a-zA-Z\-]{36})/assets/add/$', api.GroupAddAssetsApi.as_view(), name='group-add-assets'), # update the Cluster, and add or delete the assets to the Cluster - url(r'^v1/cluster/(?P[0-9a-zA-Z\-]{36})/assets/$', - api.ClusterUpdateAssetsApi.as_view(), name='cluster-update-assets'), url(r'^v1/cluster/(?P[0-9a-zA-Z\-]{36})/assets/$', api.ClusterAddAssetsApi.as_view(), name='cluster-add-assets'), + url(r'^v1/cluster/(?P[0-9a-zA-Z\-]{36})/assets/connective/$', + api.ClusterTestAssetsAliveApi.as_view(), name='cluster-test-connective'), url(r'^v1/admin-user/(?P[0-9a-zA-Z\-]{36})/clusters/$', api.AdminUserAddClustersApi.as_view(), name='admin-user-add-clusters'), url(r'^v1/admin-user/(?P[0-9a-zA-Z\-]{36})/connective/$', diff --git a/apps/assets/views/admin_user.py b/apps/assets/views/admin_user.py index 713f1fc53..e3f6bc6b3 100644 --- a/apps/assets/views/admin_user.py +++ b/apps/assets/views/admin_user.py @@ -2,20 +2,22 @@ from __future__ import absolute_import, unicode_literals from django.utils.translation import ugettext as _ 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.views.generic import TemplateView, ListView +from django.views.generic.edit import CreateView, DeleteView, UpdateView from django.contrib.messages.views import SuccessMessageMixin from django.views.generic.detail import DetailView, SingleObjectMixin +from common.const import create_success_msg, update_success_msg from .. import forms -from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser +from ..models import AdminUser, Cluster from ..hands import AdminUserRequiredMixin -__all__ = ['AdminUserCreateView', 'AdminUserDetailView', - 'AdminUserDeleteView', 'AdminUserListView', - 'AdminUserUpdateView', 'AdminUserAssetsView', - ] +__all__ = [ + 'AdminUserCreateView', 'AdminUserDetailView', + 'AdminUserDeleteView', 'AdminUserListView', + 'AdminUserUpdateView', 'AdminUserAssetsView', +] class AdminUserListView(AdminUserRequiredMixin, TemplateView): @@ -38,6 +40,7 @@ class AdminUserCreateView(AdminUserRequiredMixin, form_class = forms.AdminUserForm template_name = 'assets/admin_user_create_update.html' success_url = reverse_lazy('assets:admin-user-list') + success_message = create_success_msg def get_context_data(self, **kwargs): context = { @@ -47,20 +50,13 @@ class AdminUserCreateView(AdminUserRequiredMixin, kwargs.update(context) return super().get_context_data(**kwargs) - def get_success_message(self, cleaned_data): - success_message = _( - 'Create admin user {name} successfully.'.format( - url=reverse_lazy('assets:admin-user-detail', - kwargs={'pk': self.object.pk}), - name=self.object.name, - )) - return success_message - -class AdminUserUpdateView(AdminUserRequiredMixin, UpdateView): +class AdminUserUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView): model = AdminUser form_class = forms.AdminUserForm 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): context = { @@ -70,11 +66,6 @@ class AdminUserUpdateView(AdminUserRequiredMixin, UpdateView): kwargs.update(context) 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): model = AdminUser diff --git a/apps/assets/views/asset.py b/apps/assets/views/asset.py index 0de933395..d251b7a15 100644 --- a/apps/assets/views/asset.py +++ b/apps/assets/views/asset.py @@ -21,10 +21,11 @@ from django.core.cache import cache from django.utils import timezone from django.contrib.auth.mixins import LoginRequiredMixin from django.shortcuts import redirect - +from django.contrib.messages.views import SuccessMessageMixin from common.mixins import JSONResponseMixin 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 ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser from ..hands import AdminUserRequiredMixin @@ -46,7 +47,6 @@ class AssetListView(AdminUserRequiredMixin, TemplateView): context = { 'app': _('Assets'), 'action': _('Asset list'), - # 'groups': AssetGroup.objects.all(), 'system_users': SystemUser.objects.all(), } kwargs.update(context) @@ -66,7 +66,7 @@ class UserAssetListView(LoginRequiredMixin, TemplateView): return super().get_context_data(**kwargs) -class AssetCreateView(AdminUserRequiredMixin, CreateView): +class AssetCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView): model = Asset form_class = forms.AssetCreateForm template_name = 'assets/asset_create.html' @@ -87,6 +87,9 @@ class AssetCreateView(AdminUserRequiredMixin, CreateView): kwargs.update(context) 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): paginate_by = settings.CONFIG.DISPLAY_PER_PAGE @@ -147,7 +150,7 @@ class AssetBulkUpdateView(AdminUserRequiredMixin, ListView): return super().get_context_data(**kwargs) -class AssetUpdateView(AdminUserRequiredMixin, UpdateView): +class AssetUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView): model = Asset form_class = forms.AssetUpdateForm template_name = 'assets/asset_update.html' @@ -159,7 +162,10 @@ class AssetUpdateView(AdminUserRequiredMixin, UpdateView): 'action': _('Update asset'), } 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): @@ -184,14 +190,14 @@ class AssetDetailView(DetailView): 'system_users_all': SystemUser.objects.all(), } kwargs.update(context) - return super(AssetDetailView, self).get_context_data(**kwargs) + return super().get_context_data(**kwargs) @method_decorator(csrf_exempt, name='dispatch') class AssetExportView(View): def get(self, request): 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) fields = [ field for field in Asset._meta.fields diff --git a/apps/assets/views/cluster.py b/apps/assets/views/cluster.py index f8540bed1..e1a2f6fba 100644 --- a/apps/assets/views/cluster.py +++ b/apps/assets/views/cluster.py @@ -1,17 +1,21 @@ # coding:utf-8 -from __future__ import absolute_import, unicode_literals from django.utils.translation import ugettext as _ 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.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 ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser from ..hands import AdminUserRequiredMixin -__all__ = ['ClusterListView', 'ClusterCreateView', 'ClusterUpdateView', - 'ClusterDetailView', 'ClusterDeleteView', 'ClusterAssetsView'] +__all__ = [ + 'ClusterListView', 'ClusterCreateView', 'ClusterUpdateView', + 'ClusterDetailView', 'ClusterDeleteView', 'ClusterAssetsView', +] class ClusterListView(AdminUserRequiredMixin, TemplateView): @@ -21,39 +25,40 @@ class ClusterListView(AdminUserRequiredMixin, TemplateView): context = { 'app': _('Assets'), 'action': _('Cluster list'), - # 'keyword': self.request.GET.get('keyword', '') } kwargs.update(context) return super().get_context_data(**kwargs) -class ClusterCreateView(AdminUserRequiredMixin, CreateView): +class ClusterCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView): model = Cluster form_class = forms.ClusterForm template_name = 'assets/cluster_create_update.html' success_url = reverse_lazy('assets:cluster-list') + success_message = create_success_msg def get_context_data(self, **kwargs): context = { 'app': _('assets'), - 'action': _('Create Cluster'), + 'action': _('Create cluster'), } kwargs.update(context) return super().get_context_data(**kwargs) def form_valid(self, form): cluster = form.save(commit=False) - cluster.created_by = self.request.user.username or 'System' + cluster.created_by = self.request.user.username cluster.save() return super().form_valid(form) -class ClusterUpdateView(AdminUserRequiredMixin, UpdateView): +class ClusterUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView): model = Cluster form_class = forms.ClusterForm template_name = 'assets/cluster_create_update.html' context_object_name = 'cluster' success_url = reverse_lazy('assets:cluster-list') + success_message = update_success_msg def form_valid(self, form): cluster = form.save(commit=False) diff --git a/apps/assets/views/group.py b/apps/assets/views/group.py index 5e87d9dc7..0ae65eaa0 100644 --- a/apps/assets/views/group.py +++ b/apps/assets/views/group.py @@ -7,42 +7,41 @@ from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateVi from django.urls import reverse_lazy from django.views.generic.detail import DetailView, SingleObjectMixin 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 ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser from ..hands import AdminUserRequiredMixin -__all__ = ['AssetGroupCreateView', 'AssetGroupDetailView', - 'AssetGroupUpdateView', 'AssetGroupListView', - 'AssetGroupDeleteView', - ] +__all__ = [ + 'AssetGroupCreateView', 'AssetGroupDetailView', + 'AssetGroupUpdateView', 'AssetGroupListView', + 'AssetGroupDeleteView', +] -class AssetGroupCreateView(AdminUserRequiredMixin, CreateView): +class AssetGroupCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView): model = AssetGroup form_class = forms.AssetGroupForm template_name = 'assets/asset_group_create.html' success_url = reverse_lazy('assets:asset-group-list') + success_message = create_success_msg def get_context_data(self, **kwargs): context = { 'app': _('Assets'), 'action': _('Create asset group'), - 'assets_count': 0, } kwargs.update(context) - return super(AssetGroupCreateView, self).get_context_data(**kwargs) + return super().get_context_data(**kwargs) def form_valid(self, form): - asset_group = form.save() - assets_id_list = self.request.POST.getlist('assets', []) - assets = [get_object_or_404(Asset, id=int(asset_id)) - for asset_id in assets_id_list] - 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) + group = form.save() + group.created_by = self.request.user.username + group.save() + return super().form_valid(form) class AssetGroupListView(AdminUserRequiredMixin, TemplateView): @@ -54,7 +53,6 @@ class AssetGroupListView(AdminUserRequiredMixin, TemplateView): 'action': _('Asset group list'), 'assets': Asset.objects.all(), 'system_users': SystemUser.objects.all(), - 'keyword': self.request.GET.get('keyword', '') } kwargs.update(context) return super(AssetGroupListView, self).get_context_data(**kwargs) @@ -77,27 +75,20 @@ class AssetGroupDetailView(AdminUserRequiredMixin, DetailView): return super().get_context_data(**kwargs) -class AssetGroupUpdateView(AdminUserRequiredMixin, UpdateView): +class AssetGroupUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView): model = AssetGroup form_class = forms.AssetGroupForm template_name = 'assets/asset_group_create.html' success_url = reverse_lazy('assets:asset-group-list') - - def get(self, request, *args, **kwargs): - self.object = self.get_object(queryset=AssetGroup.objects.all()) - return super(AssetGroupUpdateView, self).get(request, *args, **kwargs) + success_message = update_success_msg def get_context_data(self, **kwargs): - assets_all = self.object.assets.all() context = { 'app': _('Assets'), 'action': _('Create asset group'), - 'assets_on_list': assets_all, - 'assets_count': len(assets_all), - 'group_id': self.object.id, } kwargs.update(context) - return super(AssetGroupUpdateView, self).get_context_data(**kwargs) + return super().get_context_data(**kwargs) class AssetGroupDeleteView(AdminUserRequiredMixin, DeleteView): diff --git a/apps/assets/views/system_user.py b/apps/assets/views/system_user.py index 885ae12b7..f7e7eaa35 100644 --- a/apps/assets/views/system_user.py +++ b/apps/assets/views/system_user.py @@ -1,24 +1,23 @@ # ~*~ coding: utf-8 ~*~ -from django.contrib import messages -from django.shortcuts import redirect, reverse from django.utils.translation import ugettext as _ -from django.db import transaction -from django.views.generic import TemplateView, ListView, FormView +from django.views.generic import TemplateView from django.views.generic.edit import CreateView, DeleteView, UpdateView from django.urls import reverse_lazy 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 ..hands import AdminUserRequiredMixin -__all__ = ['SystemUserCreateView', 'SystemUserUpdateView', - 'SystemUserDetailView', 'SystemUserDeleteView', - 'SystemUserAssetView', 'SystemUserListView', - ] +__all__ = [ + 'SystemUserCreateView', 'SystemUserUpdateView', + 'SystemUserDetailView', 'SystemUserDeleteView', + 'SystemUserAssetView', 'SystemUserListView', +] class SystemUserListView(AdminUserRequiredMixin, TemplateView): @@ -38,10 +37,7 @@ class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVi form_class = SystemUserForm template_name = 'assets/system_user_create.html' success_url = reverse_lazy('assets:system-user-list') - - @transaction.atomic - def post(self, request, *args, **kwargs): - return super(SystemUserCreateView, self).post(request, *args, **kwargs) + success_message = create_success_msg def get_context_data(self, **kwargs): context = { @@ -51,20 +47,13 @@ class SystemUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVi kwargs.update(context) 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 {name} ' - 'successfully.'.format(url=url, name=self.object.name) - ) - return success_message - - -class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView): +class SystemUserUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView): model = SystemUser form_class = SystemUserUpdateForm 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): context = { @@ -74,11 +63,6 @@ class SystemUserUpdateView(AdminUserRequiredMixin, UpdateView): kwargs.update(context) 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): template_name = 'assets/system_user_detail.html' @@ -109,8 +93,8 @@ class SystemUserAssetView(AdminUserRequiredMixin, DetailView): def get_context_data(self, **kwargs): context = { - 'app': 'assets', - 'action': 'System user asset', + 'app': _('assets'), + 'action': _('System user asset'), } kwargs.update(context) return super().get_context_data(**kwargs) diff --git a/apps/common/const.py b/apps/common/const.py new file mode 100644 index 000000000..a28b0f1db --- /dev/null +++ b/apps/common/const.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# + +from django.utils.translation import ugettext as _ + +create_success_msg = _("%(name)s was created successfully") +update_success_msg = _("%(name)s was updated successfully") \ No newline at end of file diff --git a/apps/common/utils.py b/apps/common/utils.py index 733f91a18..753fdd541 100644 --- a/apps/common/utils.py +++ b/apps/common/utils.py @@ -287,10 +287,10 @@ def make_signature(access_key_secret, date=None): return content_md5(data) -def encrypt_password(password): +def encrypt_password(password, salt=None): from passlib.hash import sha512_crypt if password: - return sha512_crypt.using(rounds=5000).hash(password) + return sha512_crypt.using(rounds=5000).hash(password, salt=salt) return None diff --git a/apps/jumpserver/middleware.py b/apps/jumpserver/middleware.py index f93edf73a..64accde21 100644 --- a/apps/jumpserver/middleware.py +++ b/apps/jumpserver/middleware.py @@ -4,24 +4,44 @@ import os import re import pytz from django.utils import timezone -from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse -DEMO_MODE = os.environ.get("DEMO_MODE", "") -SAFE_URL = r'^/users/login|^/api/terminal/v1/.*|/api/terminal/.*|/api/users/v1/auth/|/api/users/v1/profile/' +class TimezoneMiddleware: + def __init__(self, get_response): + self.get_response = get_response - -class TimezoneMiddleware(MiddlewareMixin): - def process_request(self, request): + def __call__(self, request): tzname = request.META.get('TZ') if tzname: timezone.activate(pytz.timezone(tzname)) else: timezone.deactivate() + response = self.get_response(request) + return response -class DemoMiddleware(MiddlewareMixin): - def process_request(self, request): - if DEMO_MODE and request.method not in ["GET", "HEAD"] and not re.match(SAFE_URL, request.path): - return HttpResponse("Demo mode, only get request accept", status=403) +class DemoMiddleware: + DEMO_MODE_ENABLED = os.environ.get("DEMO_MODE", "") in ("1", "ok", "True") + SAFE_URL_PATTERN = re.compile( + 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 diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py index 45c6fba88..ce2d06ed0 100644 --- a/apps/jumpserver/settings.py +++ b/apps/jumpserver/settings.py @@ -240,9 +240,8 @@ LOGGING = { # Internationalization # https://docs.djangoproject.com/en/1.10/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = 'zh-cn' -# TIME_ZONE = 'UTC' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True @@ -300,7 +299,8 @@ REST_FRAMEWORK = { 'users.authentication.SessionAuthentication', ), '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 = [ @@ -374,4 +374,5 @@ BOOTSTRAP3 = { 'horizontal_field_class': 'col-md-9', # Set placeholder attributes to label if no placeholder is provided 'set_placeholder': True, + 'success_css_class': '', } diff --git a/apps/jumpserver/urls.py b/apps/jumpserver/urls.py index 21d42d0dd..839492e7a 100644 --- a/apps/jumpserver/urls.py +++ b/apps/jumpserver/urls.py @@ -36,6 +36,6 @@ urlpatterns = [ if settings.DEBUG: urlpatterns += [ 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) diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 64af76ad9..0e2eafee3 100644 Binary files a/apps/locale/zh/LC_MESSAGES/django.mo and b/apps/locale/zh/LC_MESSAGES/django.mo differ diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 1962f867a..a997277e8 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Jumpserver 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-01-01 15:33+0800\n" +"POT-Creation-Date: 2018-01-10 00:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: Jumpserver team\n" @@ -17,8 +17,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: assets/forms.py:23 assets/forms.py:53 assets/forms.py:99 perms/forms.py:36 -#: perms/templates/perms/asset_permission_asset.html:127 users/forms.py:240 +#: assets/forms.py:23 assets/forms.py:53 assets/forms.py:99 perms/forms.py:37 +#: perms/templates/perms/asset_permission_asset.html:116 users/forms.py:242 msgid "Select asset groups" msgstr "选择资产组" @@ -36,19 +36,19 @@ msgstr "主机级别管理用户,如果没有设置则默认使用集群级别 #: assets/forms.py:40 assets/forms.py:68 msgid "You need set a admin user if cluster not have" -msgstr "" +msgstr "集群没有管理用户,你需要为集群设置管理用户或设置一个主机级别的管理用户" #: assets/forms.py:54 msgid "Default using cluster admin user" msgstr "默认使用管理用户" #: assets/forms.py:76 assets/forms.py:81 assets/forms.py:127 -#: assets/templates/assets/asset_group_detail.html:70 perms/forms.py:33 -#: perms/templates/perms/asset_permission_asset.html:99 users/forms.py:237 +#: assets/templates/assets/asset_group_detail.html:70 perms/forms.py:34 +#: perms/templates/perms/asset_permission_asset.html:88 users/forms.py:239 msgid "Select assets" msgstr "选择资产" -#: assets/forms.py:86 assets/models/asset.py:45 +#: assets/forms.py:86 assets/models/asset.py:55 #: assets/templates/assets/admin_user_assets.html:61 #: assets/templates/assets/asset_detail.html:69 #: assets/templates/assets/asset_group_detail.html:47 @@ -56,12 +56,13 @@ msgstr "选择资产" #: assets/templates/assets/cluster_assets.html:53 #: assets/templates/assets/system_user_asset.html:54 #: assets/templates/assets/user_asset_list.html:21 -#: perms/templates/perms/asset_permission_asset.html:56 #: users/templates/users/user_group_granted_asset.html:51 msgid "Port" msgstr "端口" -#: assets/forms.py:124 assets/templates/assets/asset_group_list.html:16 +#: assets/forms.py:124 assets/models/asset.py:171 +#: assets/templates/assets/admin_user_list.html:24 +#: assets/templates/assets/asset_group_list.html:16 #: assets/templates/assets/system_user_list.html:26 perms/models.py:17 #: perms/templates/perms/asset_permission_create_update.html:40 #: perms/templates/perms/asset_permission_list.html:28 templates/_nav.html:22 @@ -75,7 +76,22 @@ msgstr "端口" msgid "Asset" msgstr "资产" -#: assets/forms.py:159 assets/forms.py:219 assets/forms.py:278 +#: assets/forms.py:161 perms/forms.py:40 +#: perms/templates/perms/asset_permission_detail.html:144 users/forms.py:245 +msgid "Select system users" +msgstr "选择系统用户" + +#: assets/forms.py:163 +#: assets/templates/assets/_asset_group_bulk_update_modal.html:22 +#: assets/templates/assets/cluster_list.html:22 +msgid "System users" +msgstr "系统用户" + +#: assets/forms.py:165 +msgid "Selected system users will be create at cluster assets" +msgstr "选择的系统用户将会在该集群资产上创建" + +#: assets/forms.py:173 assets/forms.py:248 assets/forms.py:308 #: assets/models/cluster.py:18 assets/models/group.py:20 #: assets/models/user.py:28 assets/templates/assets/admin_user_detail.html:56 #: assets/templates/assets/admin_user_list.html:22 @@ -84,13 +100,13 @@ msgstr "资产" #: assets/templates/assets/cluster_list.html:19 #: assets/templates/assets/system_user_detail.html:53 #: assets/templates/assets/system_user_list.html:24 ops/models.py:31 -#: ops/templates/ops/task_detail.html:56 ops/templates/ops/task_list.html:39 +#: ops/templates/ops/task_detail.html:56 ops/templates/ops/task_list.html:34 #: perms/models.py:14 #: perms/templates/perms/asset_permission_create_update.html:33 #: perms/templates/perms/asset_permission_detail.html:62 #: perms/templates/perms/asset_permission_list.html:25 #: perms/templates/perms/asset_permission_user.html:54 terminal/models.py:14 -#: terminal/models.py:117 terminal/templates/terminal/terminal_detail.html:43 +#: terminal/models.py:118 terminal/templates/terminal/terminal_detail.html:43 #: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14 #: users/models/user.py:36 users/templates/users/_select_user_modal.html:13 #: users/templates/users/user_detail.html:62 @@ -104,19 +120,37 @@ msgstr "资产" msgid "Name" msgstr "名称" -#: assets/forms.py:174 +#: assets/forms.py:179 +msgid "Cluster level admin user" +msgstr "集群级别管理用户" + +#: assets/forms.py:200 msgid "Password or private key password" msgstr "密码或秘钥不合法" -#: assets/forms.py:202 assets/forms.py:260 assets/forms.py:321 +#: assets/forms.py:201 assets/forms.py:262 assets/models/user.py:30 +#: users/forms.py:16 users/forms.py:24 users/templates/users/login.html:56 +#: users/templates/users/reset_password.html:52 +#: users/templates/users/user_create.html:11 +#: users/templates/users/user_password_update.html:40 +#: users/templates/users/user_profile_update.html:40 +#: users/templates/users/user_pubkey_update.html:40 +msgid "Password" +msgstr "密码" + +#: assets/forms.py:204 assets/forms.py:264 users/models/user.py:46 +msgid "Private key" +msgstr "ssh私钥" + +#: assets/forms.py:229 assets/forms.py:290 assets/forms.py:354 msgid "Invalid private key" msgstr "ssh密钥不合法" -#: assets/forms.py:212 +#: assets/forms.py:240 msgid "Password and private key file must be input one" msgstr "密码和私钥, 必须输入一个" -#: assets/forms.py:220 assets/forms.py:279 assets/models/user.py:29 +#: assets/forms.py:249 assets/forms.py:309 assets/models/user.py:29 #: assets/templates/assets/admin_user_detail.html:60 #: assets/templates/assets/admin_user_list.html:23 #: assets/templates/assets/system_user_detail.html:57 @@ -132,59 +166,73 @@ msgstr "密码和私钥, 必须输入一个" msgid "Username" msgstr "用户名" -#: assets/forms.py:267 assets/forms.py:327 +#: assets/forms.py:297 assets/forms.py:360 msgid "Auth info required, private_key or password" msgstr "密钥和密码必须填写一个" -#: assets/forms.py:282 +#: assets/forms.py:313 msgid " Select clusters" msgstr "选择集群" -#: assets/models/asset.py:24 +#: assets/forms.py:320 +msgid "If auto push checked, system user will be create at cluster assets" +msgstr "如果选择了自动推送,系统用户将会创建在集群资产上" + +#: assets/forms.py:321 +msgid "Auto push system user to asset" +msgstr "自动推送系统用户到资产" + +#: assets/forms.py:322 +msgid "" +"High level will be using login asset as default, if user was granted more " +"than 2 system user" +msgstr "高优先级的系统用户将会作为默认登录用户" + +#: assets/models/asset.py:34 msgid "In use" msgstr "使用中" -#: assets/models/asset.py:25 +#: assets/models/asset.py:35 msgid "Out of use" msgstr "未使用" -#: assets/models/asset.py:28 +#: assets/models/asset.py:38 msgid "Server" msgstr "物理机" -#: assets/models/asset.py:29 +#: assets/models/asset.py:39 msgid "VM" msgstr "虚拟机" -#: assets/models/asset.py:30 +#: assets/models/asset.py:40 msgid "Switch" msgstr "交换机" -#: assets/models/asset.py:31 +#: assets/models/asset.py:41 msgid "Router" msgstr "路由器" -#: assets/models/asset.py:32 +#: assets/models/asset.py:42 msgid "Firewall" msgstr "防火墙" -#: assets/models/asset.py:33 +#: assets/models/asset.py:43 msgid "Storage" msgstr "存储" -#: assets/models/asset.py:36 +#: assets/models/asset.py:46 msgid "Production" msgstr "生产环境" -#: assets/models/asset.py:37 +#: assets/models/asset.py:47 msgid "Development" msgstr "开发环境" -#: assets/models/asset.py:38 +#: assets/models/asset.py:48 msgid "Testing" msgstr "测试环境" -#: assets/models/asset.py:43 assets/templates/assets/admin_user_assets.html:60 +#: assets/models/asset.py:53 assets/templates/assets/admin_user_assets.html:60 #: assets/templates/assets/asset_detail.html:61 #: assets/templates/assets/asset_group_detail.html:46 #: assets/templates/assets/asset_list.html:31 @@ -198,7 +246,7 @@ msgstr "测试环境" msgid "IP" msgstr "IP" -#: assets/models/asset.py:44 assets/templates/assets/admin_user_assets.html:59 +#: assets/models/asset.py:54 assets/templates/assets/admin_user_assets.html:59 #: assets/templates/assets/asset_detail.html:57 #: assets/templates/assets/asset_group_detail.html:45 #: assets/templates/assets/asset_list.html:30 @@ -211,116 +259,116 @@ msgstr "IP" msgid "Hostname" msgstr "主机名" -#: assets/models/asset.py:46 assets/templates/assets/asset_detail.html:213 -#: assets/views/asset.py:212 assets/views/asset.py:252 +#: assets/models/asset.py:56 assets/templates/assets/asset_detail.html:213 +#: assets/views/asset.py:218 assets/views/asset.py:258 msgid "Asset groups" msgstr "资产组" -#: assets/models/asset.py:47 assets/models/user.py:215 -#: assets/templates/assets/asset_detail.html:85 +#: assets/models/asset.py:57 assets/models/cluster.py:40 +#: assets/models/user.py:219 assets/templates/assets/asset_detail.html:85 #: assets/templates/assets/asset_list.html:33 templates/_nav.html:24 msgid "Cluster" msgstr "集群" -#: assets/models/asset.py:48 assets/templates/assets/asset_detail.html:129 +#: assets/models/asset.py:58 assets/templates/assets/asset_detail.html:129 msgid "Is active" msgstr "激活" -#: assets/models/asset.py:49 assets/templates/assets/asset_detail.html:133 +#: assets/models/asset.py:59 assets/templates/assets/asset_detail.html:133 msgid "Asset type" msgstr "系统类型" -#: assets/models/asset.py:50 assets/templates/assets/asset_detail.html:137 +#: assets/models/asset.py:60 assets/templates/assets/asset_detail.html:137 msgid "Asset environment" msgstr "资产环境" -#: assets/models/asset.py:51 assets/templates/assets/asset_detail.html:125 +#: assets/models/asset.py:61 assets/templates/assets/asset_detail.html:125 msgid "Asset status" msgstr "资产状态" -#: assets/models/asset.py:54 assets/models/cluster.py:19 -#: assets/templates/assets/asset_detail.html:73 +#: assets/models/asset.py:64 assets/models/cluster.py:19 +#: assets/models/user.py:190 assets/templates/assets/asset_detail.html:73 #: assets/templates/assets/cluster_list.html:20 templates/_nav.html:25 msgid "Admin user" msgstr "管理用户" -#: assets/models/asset.py:57 assets/templates/assets/asset_detail.html:65 +#: assets/models/asset.py:67 assets/templates/assets/asset_detail.html:65 msgid "Public IP" msgstr "公网IP" -#: assets/models/asset.py:58 +#: assets/models/asset.py:68 msgid "Remote control card IP" msgstr "远控卡IP" -#: assets/models/asset.py:59 assets/templates/assets/asset_detail.html:89 +#: assets/models/asset.py:69 assets/templates/assets/asset_detail.html:89 msgid "Cabinet number" msgstr "机柜编号" -#: assets/models/asset.py:60 assets/templates/assets/asset_detail.html:93 +#: assets/models/asset.py:70 assets/templates/assets/asset_detail.html:93 msgid "Cabinet position" msgstr "机柜层号" -#: assets/models/asset.py:61 assets/templates/assets/asset_detail.html:145 +#: assets/models/asset.py:71 assets/templates/assets/asset_detail.html:145 msgid "Asset number" msgstr "资产编号" -#: assets/models/asset.py:64 assets/templates/assets/asset_detail.html:97 +#: assets/models/asset.py:74 assets/templates/assets/asset_detail.html:97 msgid "Vendor" msgstr "制造商" -#: assets/models/asset.py:65 assets/templates/assets/asset_detail.html:101 +#: assets/models/asset.py:75 assets/templates/assets/asset_detail.html:101 msgid "Model" msgstr "型号" -#: assets/models/asset.py:66 assets/templates/assets/asset_detail.html:141 +#: assets/models/asset.py:76 assets/templates/assets/asset_detail.html:141 msgid "Serial number" msgstr "序列号" -#: assets/models/asset.py:68 +#: assets/models/asset.py:78 msgid "CPU model" msgstr "CPU型号" -#: assets/models/asset.py:69 +#: assets/models/asset.py:79 msgid "CPU count" msgstr "CPU数量" -#: assets/models/asset.py:70 +#: assets/models/asset.py:80 msgid "CPU cores" msgstr "CPU核数" -#: assets/models/asset.py:71 assets/templates/assets/asset_detail.html:109 +#: assets/models/asset.py:81 assets/templates/assets/asset_detail.html:109 msgid "Memory" msgstr "内存" -#: assets/models/asset.py:72 +#: assets/models/asset.py:82 msgid "Disk total" msgstr "硬盘大小" -#: assets/models/asset.py:73 +#: assets/models/asset.py:83 msgid "Disk info" msgstr "硬盘信息" -#: assets/models/asset.py:75 assets/templates/assets/asset_detail.html:117 +#: assets/models/asset.py:85 assets/templates/assets/asset_detail.html:117 msgid "Platform" msgstr "系统平台" -#: assets/models/asset.py:76 assets/templates/assets/asset_detail.html:121 +#: assets/models/asset.py:86 assets/templates/assets/asset_detail.html:121 msgid "OS" msgstr "操作系统" -#: assets/models/asset.py:77 +#: assets/models/asset.py:87 msgid "OS version" msgstr "系统版本" -#: assets/models/asset.py:78 +#: assets/models/asset.py:88 msgid "OS arch" msgstr "系统架构" -#: assets/models/asset.py:79 +#: assets/models/asset.py:89 msgid "Hostname raw" msgstr "主机名原始" -#: assets/models/asset.py:81 assets/models/cluster.py:28 +#: assets/models/asset.py:91 assets/models/cluster.py:28 #: assets/models/group.py:21 assets/models/user.py:36 #: assets/templates/assets/admin_user_detail.html:68 #: assets/templates/assets/asset_detail.html:149 @@ -332,7 +380,7 @@ msgstr "主机名原始" msgid "Created by" msgstr "创建者" -#: assets/models/asset.py:82 assets/models/cluster.py:26 +#: assets/models/asset.py:92 assets/models/cluster.py:26 #: assets/models/group.py:22 assets/templates/assets/admin_user_detail.html:64 #: assets/templates/assets/cluster_detail.html:89 #: assets/templates/assets/system_user_detail.html:87 @@ -343,10 +391,10 @@ msgstr "创建者" msgid "Date created" msgstr "创建日期" -#: assets/models/asset.py:83 assets/models/cluster.py:29 +#: assets/models/asset.py:93 assets/models/cluster.py:29 #: assets/models/group.py:23 assets/models/user.py:33 #: assets/templates/assets/admin_user_detail.html:72 -#: assets/templates/assets/admin_user_list.html:26 +#: assets/templates/assets/admin_user_list.html:28 #: assets/templates/assets/asset_detail.html:157 #: assets/templates/assets/asset_group_list.html:17 #: assets/templates/assets/cluster_detail.html:97 @@ -391,11 +439,11 @@ msgstr "外网" msgid "Operator" msgstr "运营商" -#: assets/models/cluster.py:36 assets/models/group.py:33 +#: assets/models/cluster.py:36 assets/models/group.py:34 msgid "Default" msgstr "默认" -#: assets/models/cluster.py:36 users/models/user.py:259 +#: assets/models/cluster.py:36 users/models/user.py:263 msgid "System" msgstr "系统" @@ -403,20 +451,15 @@ msgstr "系统" msgid "Default Cluster" msgstr "默认Cluster" -#: assets/models/group.py:33 +#: assets/models/group.py:30 perms/models.py:18 +#: perms/templates/perms/asset_permission_list.html:29 templates/_nav.html:23 +msgid "Asset group" +msgstr "资产组" + +#: assets/models/group.py:34 msgid "Default asset group" msgstr "默认资产组" -#: assets/models/user.py:30 users/forms.py:16 users/forms.py:24 -#: users/templates/users/login.html:56 -#: users/templates/users/reset_password.html:52 -#: users/templates/users/user_create.html:11 -#: users/templates/users/user_password_update.html:40 -#: users/templates/users/user_profile_update.html:40 -#: users/templates/users/user_pubkey_update.html:40 -msgid "Password" -msgstr "密码" - #: assets/models/user.py:31 msgid "SSH private key" msgstr "ssh密钥" @@ -425,42 +468,55 @@ msgstr "ssh密钥" msgid "SSH public key" msgstr "ssh公钥" -#: assets/models/user.py:216 +#: assets/models/user.py:220 msgid "Priority" -msgstr "" +msgstr "优先级" -#: assets/models/user.py:217 assets/templates/assets/system_user_detail.html:61 +#: assets/models/user.py:221 assets/templates/assets/system_user_detail.html:61 msgid "Protocol" msgstr "协议" -#: assets/models/user.py:218 assets/templates/assets/_system_user.html:59 +#: assets/models/user.py:222 assets/templates/assets/_system_user.html:59 #: assets/templates/assets/system_user_detail.html:113 #: assets/templates/assets/system_user_update.html:11 msgid "Auto push" msgstr "自动推送" -#: assets/models/user.py:219 assets/templates/assets/system_user_detail.html:65 +#: assets/models/user.py:223 assets/templates/assets/system_user_detail.html:65 msgid "Sudo" msgstr "Sudo" -#: assets/models/user.py:220 assets/templates/assets/system_user_detail.html:70 +#: assets/models/user.py:224 assets/templates/assets/system_user_detail.html:70 msgid "Shell" msgstr "Shell" +#: assets/models/user.py:269 perms/models.py:19 +#: perms/templates/perms/asset_permission_detail.html:136 +#: perms/templates/perms/asset_permission_list.html:30 templates/_nav.html:26 +#: terminal/backends/command/models.py:12 terminal/models.py:94 +#: terminal/templates/terminal/command_list.html:48 +#: terminal/templates/terminal/command_list.html:74 +#: terminal/templates/terminal/session_list.html:49 +#: terminal/templates/terminal/session_list.html:73 +#: users/templates/users/user_granted_asset.html:50 +#: users/templates/users/user_group_granted_asset.html:52 +msgid "System user" +msgstr "系统用户" + #: assets/models/utils.py:29 #, python-format msgid "%(value)s is not an even number" msgstr "%(value)s is not an even number" -#: assets/signals_handler.py:31 +#: assets/signals_handler.py:32 msgid "Push cluster system users to asset" msgstr "推送集群系统用户到资产" -#: assets/signals_handler.py:63 assets/signals_handler.py:125 +#: assets/signals_handler.py:64 assets/signals_handler.py:126 msgid "Push system user to cluster assets: {}->{}" msgstr "推送系统用户到: {}->{}" -#: assets/signals_handler.py:102 +#: assets/signals_handler.py:103 msgid "Push system user to assets" msgstr "推送系统用户到资产" @@ -478,23 +534,31 @@ msgstr "定期更新资产硬件信息" #: assets/tasks.py:189 msgid "Test admin user connectability period: {}" -msgstr "定期测试管理用户可以连接性" +msgstr "定期测试管理用户可连接性: {}" #: assets/tasks.py:203 msgid "Test admin user connectability: {}" msgstr "测试管理用户可连接性: {}" -#: assets/tasks.py:289 -msgid "Test system user connectability period: {}" +#: assets/tasks.py:212 +msgid "Test asset connectability" +msgstr "测试资产可连接性" + +#: assets/tasks.py:283 +msgid "Test system user connectability: {}" msgstr "测试系统用户可连接性: {}" -#: assets/tasks.py:363 +#: assets/tasks.py:295 +msgid "Test system user connectability period: {}" +msgstr "定期测试系统用户可连接性: {}" + +#: assets/tasks.py:376 msgid "Push system user to cluster assets: {}" msgstr "推送系统用户到资产: {}" -#: assets/tasks.py:384 -msgid "Push system user to cluster assets period: {}->{}" -msgstr "定期推送系统用户到资产: {}->{}" +#: assets/tasks.py:397 +msgid "Push cluster system users to assets period: {}" +msgstr "定期推送集群系统用户到资产: {}" #: assets/templates/assets/_asset_group_bulk_update_modal.html:5 msgid "Update asset group" @@ -506,16 +570,16 @@ msgstr "仅修改你需要更新的字段" #: assets/templates/assets/_asset_group_bulk_update_modal.html:12 #: assets/templates/assets/system_user_asset.html:21 -#: assets/views/admin_user.py:27 assets/views/admin_user.py:44 -#: assets/views/admin_user.py:67 assets/views/admin_user.py:88 -#: assets/views/admin_user.py:115 assets/views/asset.py:47 -#: assets/views/asset.py:61 assets/views/asset.py:84 assets/views/asset.py:141 -#: assets/views/asset.py:158 assets/views/asset.py:179 -#: assets/views/cluster.py:22 assets/views/cluster.py:80 -#: assets/views/cluster.py:97 assets/views/group.py:30 assets/views/group.py:53 -#: assets/views/group.py:71 assets/views/group.py:93 -#: assets/views/system_user.py:29 assets/views/system_user.py:48 -#: assets/views/system_user.py:71 assets/views/system_user.py:91 +#: assets/views/admin_user.py:29 assets/views/admin_user.py:47 +#: assets/views/admin_user.py:63 assets/views/admin_user.py:79 +#: assets/views/admin_user.py:106 assets/views/asset.py:48 +#: assets/views/asset.py:61 assets/views/asset.py:84 assets/views/asset.py:144 +#: assets/views/asset.py:161 assets/views/asset.py:185 +#: assets/views/cluster.py:26 assets/views/cluster.py:85 +#: assets/views/cluster.py:102 assets/views/group.py:34 +#: assets/views/group.py:52 assets/views/group.py:69 assets/views/group.py:87 +#: assets/views/system_user.py:28 assets/views/system_user.py:44 +#: assets/views/system_user.py:60 assets/views/system_user.py:75 #: templates/_nav.html:19 msgid "Assets" msgstr "资产管理" @@ -524,11 +588,6 @@ msgstr "资产管理" msgid "Select Asset" msgstr "选择资产" -#: assets/templates/assets/_asset_group_bulk_update_modal.html:22 -#: assets/templates/assets/cluster_list.html:22 -msgid "System users" -msgstr "系统用户" - #: assets/templates/assets/_asset_group_bulk_update_modal.html:24 msgid "Select System Users" msgstr "选择系统用户" @@ -561,7 +620,7 @@ msgstr "如果设置了id,则会使用该行信息更新该id的资产" #: assets/templates/assets/_system_user.html:16 #: assets/templates/assets/system_user_list.html:16 -#: assets/views/system_user.py:49 +#: assets/views/system_user.py:45 msgid "Create system user" msgstr "创建系统用户" @@ -588,7 +647,7 @@ msgstr "自动生成秘钥" #: assets/templates/assets/_system_user.html:65 #: assets/templates/assets/asset_create.html:32 #: assets/templates/assets/asset_update.html:47 -#: assets/templates/assets/cluster_create_update.html:45 +#: assets/templates/assets/cluster_create_update.html:46 #: perms/templates/perms/asset_permission_create_update.html:45 #: terminal/templates/terminal/terminal_update.html:40 msgid "Other" @@ -598,8 +657,9 @@ msgstr "其它" #: assets/templates/assets/admin_user_create_update.html:45 #: assets/templates/assets/asset_bulk_update.html:23 #: assets/templates/assets/asset_create.html:40 -#: assets/templates/assets/asset_update.html:56 -#: assets/templates/assets/cluster_create_update.html:53 +#: assets/templates/assets/asset_group_create.html:16 +#: assets/templates/assets/asset_update.html:55 +#: assets/templates/assets/cluster_create_update.html:54 #: perms/templates/perms/asset_permission_create_update.html:67 #: terminal/templates/terminal/terminal_update.html:45 #: users/templates/users/_user.html:49 @@ -616,9 +676,10 @@ msgstr "重置" #: assets/templates/assets/admin_user_create_update.html:46 #: assets/templates/assets/asset_bulk_update.html:24 #: assets/templates/assets/asset_create.html:41 +#: assets/templates/assets/asset_group_create.html:17 #: assets/templates/assets/asset_list.html:55 -#: assets/templates/assets/asset_update.html:57 -#: assets/templates/assets/cluster_create_update.html:54 +#: assets/templates/assets/asset_update.html:56 +#: assets/templates/assets/cluster_create_update.html:55 #: perms/templates/perms/asset_permission_create_update.html:68 #: terminal/templates/terminal/terminal_update.html:46 #: users/templates/users/_user.html:50 @@ -652,6 +713,52 @@ msgstr "详情" msgid "Assets list" msgstr "资产列表" +#: assets/templates/assets/admin_user_assets.html:24 +#: assets/templates/assets/admin_user_detail.html:24 +#: assets/templates/assets/admin_user_list.html:83 +#: assets/templates/assets/asset_detail.html:24 +#: assets/templates/assets/asset_group_detail.html:18 +#: assets/templates/assets/asset_group_detail.html:172 +#: assets/templates/assets/asset_group_list.html:42 +#: assets/templates/assets/asset_list.html:95 +#: assets/templates/assets/cluster_assets.html:170 +#: assets/templates/assets/cluster_detail.html:25 +#: assets/templates/assets/cluster_list.html:43 +#: assets/templates/assets/system_user_asset.html:25 +#: assets/templates/assets/system_user_detail.html:26 +#: assets/templates/assets/system_user_list.html:84 +#: perms/templates/perms/asset_permission_detail.html:30 +#: perms/templates/perms/asset_permission_list.html:73 +#: terminal/templates/terminal/terminal_detail.html:16 +#: terminal/templates/terminal/terminal_list.html:71 +#: users/templates/users/user_detail.html:25 +#: users/templates/users/user_group_detail.html:28 +#: users/templates/users/user_group_list.html:39 +#: users/templates/users/user_list.html:76 +msgid "Update" +msgstr "更新" + +#: assets/templates/assets/admin_user_assets.html:28 +#: assets/templates/assets/admin_user_detail.html:28 +#: assets/templates/assets/admin_user_list.html:84 +#: assets/templates/assets/asset_detail.html:28 +#: assets/templates/assets/asset_group_list.html:43 +#: assets/templates/assets/asset_list.html:96 +#: assets/templates/assets/cluster_detail.html:29 +#: assets/templates/assets/cluster_list.html:44 +#: assets/templates/assets/system_user_list.html:85 +#: ops/templates/ops/task_list.html:71 +#: perms/templates/perms/asset_permission_detail.html:34 +#: perms/templates/perms/asset_permission_list.html:74 +#: terminal/templates/terminal/terminal_list.html:73 +#: users/templates/users/user_detail.html:29 +#: users/templates/users/user_group_detail.html:32 +#: users/templates/users/user_group_list.html:41 +#: users/templates/users/user_list.html:80 +#: users/templates/users/user_list.html:84 +msgid "Delete" +msgstr "删除" + #: assets/templates/assets/admin_user_assets.html:37 #: assets/templates/assets/asset_group_detail.html:26 #: perms/templates/perms/asset_permission_asset.html:35 @@ -668,11 +775,13 @@ msgid "Type" msgstr "类型" #: assets/templates/assets/admin_user_assets.html:63 -#: assets/templates/assets/asset_group_detail.html:49 -#: assets/templates/assets/cluster_assets.html:55 -#: terminal/templates/terminal/terminal_list.html:35 -msgid "Alive" -msgstr "在线" +#: assets/templates/assets/admin_user_list.html:25 +#: assets/templates/assets/asset_detail.html:376 +#: assets/templates/assets/asset_list.html:38 +#: assets/templates/assets/system_user_asset.html:55 +#: assets/templates/assets/system_user_list.html:27 +msgid "Reachable" +msgstr "可连接" #: assets/templates/assets/admin_user_assets.html:75 #: assets/templates/assets/cluster_assets.html:68 @@ -699,7 +808,7 @@ msgstr "任务已下发,查看左侧资产状态" #: assets/templates/assets/admin_user_create_update.html:16 #: assets/templates/assets/admin_user_list.html:14 -#: assets/views/admin_user.py:45 +#: assets/views/admin_user.py:48 msgid "Create admin user" msgstr "创建管理用户" @@ -709,7 +818,7 @@ msgstr "使用集群管理用户" #: assets/templates/assets/admin_user_detail.html:101 #: assets/templates/assets/asset_detail.html:230 -#: assets/templates/assets/asset_group_list.html:87 +#: assets/templates/assets/asset_group_list.html:85 #: assets/templates/assets/asset_list.html:202 #: assets/templates/assets/cluster_assets.html:104 #: assets/templates/assets/cluster_list.html:89 @@ -719,25 +828,26 @@ msgstr "使用集群管理用户" #: users/templates/users/user_detail.html:338 #: users/templates/users/user_detail.html:363 #: users/templates/users/user_detail.html:386 -#: users/templates/users/user_group_create_update.html:46 +#: users/templates/users/user_group_create_update.html:32 #: users/templates/users/user_group_list.html:82 #: users/templates/users/user_list.html:184 #: users/templates/users/user_profile.html:181 msgid "Confirm" msgstr "确认" -#: assets/templates/assets/admin_user_list.html:24 -#: assets/templates/assets/cluster_list.html:21 -#: users/templates/users/_select_user_modal.html:17 -msgid "Asset num" -msgstr "资产数量" - -#: assets/templates/assets/admin_user_list.html:25 +#: assets/templates/assets/admin_user_list.html:26 #: assets/templates/assets/system_user_list.html:28 msgid "Unreachable" msgstr "不可达" #: assets/templates/assets/admin_user_list.html:27 +#: assets/templates/assets/system_user_list.html:29 +#: ops/templates/ops/adhoc_history.html:54 +#: ops/templates/ops/task_history.html:57 +msgid "Ratio" +msgstr "比例" + +#: assets/templates/assets/admin_user_list.html:29 #: assets/templates/assets/asset_group_detail.html:50 #: assets/templates/assets/asset_group_list.html:18 #: assets/templates/assets/asset_list.html:39 @@ -746,50 +856,22 @@ msgstr "不可达" #: assets/templates/assets/system_user_list.html:31 #: assets/templates/assets/user_asset_list.html:27 #: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:61 -#: ops/templates/ops/task_history.html:62 ops/templates/ops/task_list.html:46 +#: ops/templates/ops/task_history.html:62 ops/templates/ops/task_list.html:41 #: perms/templates/perms/asset_permission_list.html:32 -#: terminal/templates/terminal/session_list.html:78 +#: terminal/templates/terminal/session_list.html:79 #: terminal/templates/terminal/terminal_list.html:36 #: users/templates/users/user_group_list.html:15 #: users/templates/users/user_list.html:28 msgid "Action" msgstr "动作" -#: assets/templates/assets/admin_user_list.html:47 -#: assets/templates/assets/asset_group_detail.html:172 -#: assets/templates/assets/asset_group_list.html:42 -#: assets/templates/assets/asset_list.html:95 -#: assets/templates/assets/cluster_assets.html:170 -#: assets/templates/assets/cluster_list.html:43 -#: assets/templates/assets/system_user_list.html:84 -#: perms/templates/perms/asset_permission_list.html:73 -#: terminal/templates/terminal/terminal_list.html:71 -#: users/templates/users/user_group_list.html:39 -#: users/templates/users/user_list.html:76 -msgid "Update" -msgstr "更新" - -#: assets/templates/assets/admin_user_list.html:48 -#: assets/templates/assets/asset_group_list.html:43 -#: assets/templates/assets/asset_list.html:96 -#: assets/templates/assets/cluster_list.html:44 -#: assets/templates/assets/system_user_list.html:85 -#: ops/templates/ops/task_list.html:76 -#: perms/templates/perms/asset_permission_list.html:74 -#: terminal/templates/terminal/terminal_list.html:73 -#: users/templates/users/user_group_list.html:41 -#: users/templates/users/user_list.html:80 -#: users/templates/users/user_list.html:84 -msgid "Delete" -msgstr "删除" - #: assets/templates/assets/asset_create.html:28 #: assets/templates/assets/asset_update.html:33 msgid "Group" msgstr "组" -#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:180 -#: assets/views/cluster.py:98 +#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:186 +#: assets/views/cluster.py:103 msgid "Asset detail" msgstr "资产详情" @@ -822,6 +904,7 @@ msgstr "快速修改" #: assets/templates/assets/asset_list.html:37 #: assets/templates/assets/user_asset_list.html:25 perms/models.py:20 #: perms/templates/perms/asset_permission_create_update.html:47 +#: perms/templates/perms/asset_permission_detail.html:116 #: terminal/templates/terminal/terminal_list.html:34 #: users/templates/users/_select_user_modal.html:18 #: users/templates/users/user_detail.html:127 @@ -847,26 +930,25 @@ msgstr "添加到资产组" msgid "Update successfully!" msgstr "更新成功" -#: assets/templates/assets/asset_detail.html:376 -#: assets/templates/assets/asset_list.html:38 -#: assets/templates/assets/system_user_asset.html:55 -#: assets/templates/assets/system_user_list.html:27 -msgid "Reachable" -msgstr "可连接" - #: assets/templates/assets/asset_group_detail.html:16 msgid "Group assets" msgstr "组下资产" +#: assets/templates/assets/asset_group_detail.html:49 +#: assets/templates/assets/cluster_assets.html:55 +#: terminal/templates/terminal/terminal_list.html:35 +msgid "Alive" +msgstr "在线" + #: assets/templates/assets/asset_group_detail.html:62 msgid "Add assets to this group" msgstr "添加资产到该组" #: assets/templates/assets/asset_group_detail.html:79 -#: perms/templates/perms/asset_permission_asset.html:108 +#: perms/templates/perms/asset_permission_asset.html:97 #: perms/templates/perms/asset_permission_detail.html:153 -#: perms/templates/perms/asset_permission_user.html:108 -#: perms/templates/perms/asset_permission_user.html:136 +#: perms/templates/perms/asset_permission_user.html:97 +#: perms/templates/perms/asset_permission_user.html:125 #: users/templates/users/user_group_detail.html:95 msgid "Add" msgstr "添加" @@ -875,12 +957,12 @@ msgstr "添加" msgid "Remove" msgstr "移除" -#: assets/templates/assets/asset_group_list.html:7 assets/views/group.py:31 -#: assets/views/group.py:94 +#: assets/templates/assets/asset_group_list.html:7 assets/views/group.py:35 +#: assets/views/group.py:88 msgid "Create asset group" msgstr "创建资产组" -#: assets/templates/assets/asset_group_list.html:82 +#: assets/templates/assets/asset_group_list.html:80 #: assets/templates/assets/asset_list.html:197 #: assets/templates/assets/cluster_list.html:84 #: assets/templates/assets/system_user_list.html:129 @@ -891,29 +973,29 @@ msgstr "创建资产组" msgid "Are you sure?" msgstr "你确认吗?" -#: assets/templates/assets/asset_group_list.html:83 +#: assets/templates/assets/asset_group_list.html:81 #: users/templates/users/user_group_list.html:78 msgid "This will delete the selected groups !!!" msgstr "删除选择组" -#: assets/templates/assets/asset_group_list.html:91 +#: assets/templates/assets/asset_group_list.html:89 msgid "Group deleted" msgstr "组已被删除" -#: assets/templates/assets/asset_group_list.html:92 -#: assets/templates/assets/asset_group_list.html:97 +#: assets/templates/assets/asset_group_list.html:90 +#: assets/templates/assets/asset_group_list.html:95 msgid "Group Delete" msgstr "删除" -#: assets/templates/assets/asset_group_list.html:96 +#: assets/templates/assets/asset_group_list.html:94 msgid "Group deleting failed." msgstr "删除失败" -#: assets/templates/assets/asset_group_list.html:159 +#: assets/templates/assets/asset_group_list.html:157 msgid "The selected asset groups has been updated successfully." msgstr "更新成功" -#: assets/templates/assets/asset_group_list.html:160 +#: assets/templates/assets/asset_group_list.html:158 msgid "AssetGroup Updated" msgstr "资产组更新" @@ -1000,7 +1082,7 @@ msgid "Test assets connective" msgstr "测试资产可连接性" #: assets/templates/assets/cluster_assets.html:77 -#: ops/templates/ops/task_list.html:75 +#: ops/templates/ops/task_list.html:70 msgid "Run" msgstr "执行" @@ -1012,14 +1094,20 @@ msgstr "添加资产到" msgid "Select asset" msgstr "选择资产" +#: assets/templates/assets/cluster_assets.html:211 +#: assets/templates/assets/system_user_asset.html:162 +msgid "Task has been send, seen left assets status" +msgstr "任务已下发,查看左侧资产状态" + #: assets/templates/assets/cluster_create_update.html:41 #: users/templates/users/user_profile.html:20 msgid "Settings" msgstr "设置" -#: assets/templates/assets/cluster_list.html:11 assets/views/cluster.py:39 -msgid "Create Cluster" -msgstr "创建Cluster" +#: assets/templates/assets/cluster_list.html:21 +#: users/templates/users/_select_user_modal.html:17 +msgid "Asset num" +msgstr "资产数量" #: assets/templates/assets/cluster_list.html:85 msgid "This will delete the selected cluster" @@ -1064,10 +1152,6 @@ msgstr "推送" msgid "Task has been send, Go to ops task list seen result" msgstr "任务已下发,查看ops任务列表" -#: assets/templates/assets/system_user_asset.html:162 -msgid "Task has been send, seen left assets status" -msgstr "任务已下发,查看左侧资产状态" - #: assets/templates/assets/system_user_detail.html:22 msgid "Attached assets" msgstr "关联的资产" @@ -1088,12 +1172,6 @@ msgstr "集群" msgid "Add to cluster" msgstr "添加到集群" -#: assets/templates/assets/system_user_list.html:29 -#: ops/templates/ops/adhoc_history.html:54 -#: ops/templates/ops/task_history.html:57 -msgid "Ratio" -msgstr "比例" - #: assets/templates/assets/system_user_list.html:130 msgid "This will delete the selected System Users !!!" msgstr "删除选择系统用户" @@ -1115,84 +1193,93 @@ msgstr "系统用户删除失败" msgid "Connective" msgstr "连接性" -#: assets/templates/assets/user_asset_list.html:66 +#: assets/templates/assets/user_asset_list.html:65 msgid "Connect" msgstr "连接" -#: assets/views/admin_user.py:28 +#: assets/views/admin_user.py:30 msgid "Admin user list" msgstr "管理用户列表" -#: assets/views/admin_user.py:52 -#, python-brace-format -msgid "Create admin user {name} successfully." -msgstr "创建管理用户 {name} 成功" - -#: assets/views/admin_user.py:68 +#: assets/views/admin_user.py:64 msgid "Update admin user" msgstr "更新管理用户" -#: assets/views/admin_user.py:89 assets/views/admin_user.py:116 +#: assets/views/admin_user.py:80 assets/views/admin_user.py:107 msgid "Admin user detail" msgstr "管理用户详情" -#: assets/views/asset.py:48 assets/views/asset.py:62 +#: assets/views/asset.py:49 assets/views/asset.py:62 msgid "Asset list" msgstr "资产列表" -#: assets/views/asset.py:142 +#: assets/views/asset.py:145 msgid "Bulk update asset" msgstr "批量更新资产" -#: assets/views/asset.py:159 +#: assets/views/asset.py:162 msgid "Update asset" msgstr "编辑资产" -#: assets/views/asset.py:292 +#: assets/views/asset.py:298 msgid "already exists" msgstr "已经存在" -#: assets/views/cluster.py:23 +#: assets/views/cluster.py:27 msgid "Cluster list" msgstr "集群列表" -#: assets/views/cluster.py:38 assets/views/cluster.py:65 +#: assets/views/cluster.py:42 assets/views/cluster.py:70 +#: assets/views/system_user.py:96 msgid "assets" msgstr "资产管理" -#: assets/views/cluster.py:66 +#: assets/views/cluster.py:43 +msgid "Create cluster" +msgstr "创建集群" + +#: assets/views/cluster.py:71 msgid "Update Cluster" msgstr "更新Cluster" -#: assets/views/cluster.py:81 +#: assets/views/cluster.py:86 msgid "Cluster detail" msgstr "集群详情" -#: assets/views/group.py:54 +#: assets/views/group.py:53 msgid "Asset group list" msgstr "资产组列表" -#: assets/views/group.py:72 +#: assets/views/group.py:70 msgid "Asset group detail" msgstr "资产组详情" -#: assets/views/system_user.py:30 +#: assets/views/system_user.py:29 msgid "System user list" msgstr "系统用户列表" -#: assets/views/system_user.py:57 -#, python-brace-format -msgid "Create system user {name} successfully." -msgstr "创建系统用户 {name} 成功" - -#: assets/views/system_user.py:72 +#: assets/views/system_user.py:61 msgid "Update system user" msgstr "更新系统用户" -#: assets/views/system_user.py:92 +#: assets/views/system_user.py:76 msgid "System user detail" msgstr "系统用户详情" +#: assets/views/system_user.py:97 +msgid "System user asset" +msgstr "系统用户集群资产" + +#: common/const.py:6 +#, python-format +msgid "%(name)s was created successfully" +msgstr "%(name)s 创建成功" + +#: common/const.py:7 +#, python-format +msgid "%(name)s was updated successfully" +msgstr "%(name)s 更新成功" + #: common/mixins.py:29 msgid "is discard" msgstr "" @@ -1235,7 +1322,7 @@ msgid "Options" msgstr "选项" #: ops/models.py:152 ops/templates/ops/adhoc_detail.html:53 -#: ops/templates/ops/task_adhoc.html:56 ops/templates/ops/task_list.html:42 +#: ops/templates/ops/task_adhoc.html:56 ops/templates/ops/task_list.html:37 msgid "Hosts" msgstr "主机" @@ -1257,36 +1344,36 @@ msgstr "Become" msgid "Create by" msgstr "创建者" -#: ops/models.py:306 +#: ops/models.py:307 msgid "Start time" msgstr "开始时间" -#: ops/models.py:307 +#: ops/models.py:308 msgid "End time" msgstr "完成时间" -#: ops/models.py:308 ops/templates/ops/adhoc_history.html:57 -#: ops/templates/ops/task_history.html:60 ops/templates/ops/task_list.html:45 +#: ops/models.py:309 ops/templates/ops/adhoc_history.html:57 +#: ops/templates/ops/task_history.html:60 ops/templates/ops/task_list.html:40 msgid "Time" msgstr "时间" -#: ops/models.py:309 ops/templates/ops/adhoc_detail.html:106 +#: ops/models.py:310 ops/templates/ops/adhoc_detail.html:106 #: ops/templates/ops/adhoc_history.html:55 #: ops/templates/ops/adhoc_history_detail.html:66 #: ops/templates/ops/task_detail.html:80 ops/templates/ops/task_history.html:58 msgid "Is finished" msgstr "是否完成" -#: ops/models.py:310 ops/templates/ops/adhoc_history.html:56 +#: ops/models.py:311 ops/templates/ops/adhoc_history.html:56 #: ops/templates/ops/task_history.html:59 msgid "Is success" msgstr "是否成功" -#: ops/models.py:311 +#: ops/models.py:312 msgid "Adhoc raw result" msgstr "结果" -#: ops/models.py:312 +#: ops/models.py:313 msgid "Adhoc result summary" msgstr "汇总" @@ -1296,7 +1383,7 @@ msgid "Version detail" msgstr "版本详情" #: ops/templates/ops/adhoc_detail.html:22 -#: ops/templates/ops/adhoc_history.html:22 ops/views.py:120 +#: ops/templates/ops/adhoc_history.html:22 ops/views.py:105 msgid "Version run history" msgstr "执行历史" @@ -1308,7 +1395,7 @@ msgstr "执行历史" msgid "ID" msgstr "ID" -#: ops/templates/ops/adhoc_detail.html:94 ops/templates/ops/task_list.html:40 +#: ops/templates/ops/adhoc_detail.html:94 ops/templates/ops/task_list.html:35 msgid "Run times" msgstr "执行次数" @@ -1352,8 +1439,8 @@ msgstr "执行历史" #: ops/templates/ops/adhoc_history.html:52 #: ops/templates/ops/adhoc_history_detail.html:58 -#: ops/templates/ops/task_history.html:55 terminal/models.py:100 -#: terminal/templates/terminal/session_list.html:76 +#: ops/templates/ops/task_history.html:55 terminal/models.py:101 +#: terminal/templates/terminal/session_list.html:77 msgid "Date start" msgstr "开始日期" @@ -1368,7 +1455,7 @@ msgstr "失败/成功/总" msgid "Version" msgstr "版本" -#: ops/templates/ops/adhoc_history_detail.html:19 ops/views.py:133 +#: ops/templates/ops/adhoc_history_detail.html:19 ops/views.py:118 msgid "Run history detail" msgstr "执行历史详情" @@ -1394,12 +1481,12 @@ msgid "Success assets" msgstr "成功资产" #: ops/templates/ops/task_adhoc.html:19 ops/templates/ops/task_detail.html:19 -#: ops/templates/ops/task_history.html:19 ops/views.py:58 +#: ops/templates/ops/task_history.html:19 ops/views.py:53 msgid "Task detail" msgstr "任务详情" #: ops/templates/ops/task_adhoc.html:22 ops/templates/ops/task_detail.html:22 -#: ops/templates/ops/task_history.html:22 ops/views.py:71 +#: ops/templates/ops/task_history.html:22 ops/views.py:66 msgid "Task versions" msgstr "任务各版本" @@ -1414,6 +1501,7 @@ msgstr "版本" #: ops/templates/ops/task_adhoc.html:60 #: terminal/templates/terminal/command_list.html:76 +#: terminal/templates/terminal/session_detail.html:50 msgid "Datetime" msgstr "日期" @@ -1429,7 +1517,7 @@ msgstr "最新版本" msgid "Contents" msgstr "内容" -#: ops/templates/ops/task_list.html:25 ops/templates/ops/task_list.html:30 +#: ops/templates/ops/task_list.html:20 ops/templates/ops/task_list.html:25 #: templates/_base_list.html:43 templates/_header_bar.html:8 #: terminal/templates/terminal/command_list.html:60 #: users/templates/users/login_log_list.html:35 @@ -1437,73 +1525,74 @@ msgstr "内容" msgid "Search" msgstr "搜索" -#: ops/templates/ops/task_list.html:41 +#: ops/templates/ops/task_list.html:36 msgid "Versions" msgstr "版本" -#: ops/templates/ops/task_list.html:43 +#: ops/templates/ops/task_list.html:38 msgid "Success" msgstr "成功" -#: ops/templates/ops/task_list.html:44 +#: ops/templates/ops/task_list.html:39 #: users/templates/users/login_log_list.html:54 msgid "Date" msgstr "日期" -#: ops/views.py:41 ops/views.py:57 ops/views.py:70 ops/views.py:83 -#: ops/views.py:106 ops/views.py:119 ops/views.py:132 +#: ops/templates/ops/task_list.html:125 +msgid "Task start: " +msgstr "任务开始: " + +#: ops/views.py:36 ops/views.py:52 ops/views.py:65 ops/views.py:78 +#: ops/views.py:91 ops/views.py:104 ops/views.py:117 msgid "Ops" msgstr "作业中心" -#: ops/views.py:42 +#: ops/views.py:37 msgid "Task list" msgstr "任务列表" -#: ops/views.py:84 +#: ops/views.py:79 msgid "Task run history" msgstr "执行历史" #: perms/forms.py:16 users/forms.py:144 users/forms.py:149 users/forms.py:161 -#: users/forms.py:190 +#: users/forms.py:191 msgid "Select users" msgstr "选择用户" #: perms/forms.py:18 perms/models.py:15 #: perms/templates/perms/asset_permission_create_update.html:36 #: perms/templates/perms/asset_permission_list.html:26 templates/_nav.html:12 -#: templates/_user_profile.html:14 terminal/backends/command/models.py:10 -#: terminal/models.py:92 terminal/templates/terminal/command_list.html:32 +#: terminal/backends/command/models.py:10 terminal/models.py:92 +#: terminal/templates/terminal/command_list.html:32 #: terminal/templates/terminal/command_list.html:72 #: terminal/templates/terminal/session_list.html:33 -#: terminal/templates/terminal/session_list.html:71 users/models/user.py:31 -#: users/templates/users/user_group_detail.html:78 users/views/user.py:348 +#: terminal/templates/terminal/session_list.html:71 users/forms.py:187 +#: users/models/user.py:31 users/templates/users/user_group_detail.html:78 +#: users/views/user.py:338 msgid "User" msgstr "用户" -#: perms/forms.py:30 perms/templates/perms/asset_permission_user.html:127 +#: perms/forms.py:31 perms/templates/perms/asset_permission_user.html:116 msgid "Select user groups" msgstr "选择用户组" -#: perms/forms.py:39 perms/templates/perms/asset_permission_detail.html:144 -#: users/forms.py:243 -msgid "Select system users" -msgstr "选择系统用户" +#: perms/forms.py:52 +msgid "User or group at least one required" +msgstr "用户和组至少需要选一个" -#: perms/forms.py:44 -msgid "User or user group at least one required" -msgstr "" +#: perms/forms.py:60 +msgid "Asset or group at least one required" +msgstr "资产或组至少需要选择一个" -#: perms/forms.py:45 -msgid "Asset or Asset group at least one required" -msgstr "" +#: perms/forms.py:78 +msgid "Asset {} of cluster {} not have [{}] system users, please check \n" +msgstr "资产 {} 所在集群 {} 不包含系统用户 [{}] 请检查\n" -#: perms/forms.py:59 -msgid "Asset {} not have [{}] system users, please check \n" -msgstr "" - -#: perms/forms.py:67 -msgid "Asset {}: {} not have [{}] system users, please check" -msgstr "" +#: perms/forms.py:87 +msgid "" +"Asset {}(group {}) of cluster {} not have [{}] system users, please check \n" +msgstr "资产 {}(组 {}) 所在集群 {} 不包含系统用户 [{}] 请检查\n" #: perms/models.py:16 perms/templates/perms/asset_permission_list.html:27 #: templates/_nav.html:13 users/models/user.py:38 @@ -1513,23 +1602,6 @@ msgstr "" msgid "User group" msgstr "用户组" -#: perms/models.py:18 perms/templates/perms/asset_permission_list.html:29 -#: templates/_nav.html:23 -msgid "Asset group" -msgstr "资产组" - -#: perms/models.py:19 perms/templates/perms/asset_permission_detail.html:136 -#: perms/templates/perms/asset_permission_list.html:30 templates/_nav.html:26 -#: terminal/backends/command/models.py:12 terminal/models.py:94 -#: terminal/templates/terminal/command_list.html:48 -#: terminal/templates/terminal/command_list.html:74 -#: terminal/templates/terminal/session_list.html:49 -#: terminal/templates/terminal/session_list.html:73 -#: users/templates/users/user_granted_asset.html:50 -#: users/templates/users/user_group_granted_asset.html:52 -msgid "System user" -msgstr "系统用户" - #: perms/models.py:21 perms/templates/perms/asset_permission_detail.html:86 #: users/models/user.py:50 users/templates/users/user_detail.html:94 #: users/templates/users/user_profile.html:96 @@ -1548,21 +1620,15 @@ msgstr "用户或用户组" msgid "Assets and asset groups" msgstr "资产或资产组" -#: perms/templates/perms/asset_permission_asset.html:57 -#: perms/templates/perms/asset_permission_list.html:31 -#: perms/templates/perms/asset_permission_user.html:57 -msgid "Is valid" -msgstr "有效" - -#: perms/templates/perms/asset_permission_asset.html:91 +#: perms/templates/perms/asset_permission_asset.html:80 msgid "Add asset to this permission" msgstr "添加资产" -#: perms/templates/perms/asset_permission_asset.html:119 +#: perms/templates/perms/asset_permission_asset.html:108 msgid "Add asset group to this permission" msgstr "添加资产组" -#: perms/templates/perms/asset_permission_asset.html:136 +#: perms/templates/perms/asset_permission_asset.html:125 #: users/templates/users/user_detail.html:195 msgid "Join" msgstr "加入" @@ -1596,70 +1662,53 @@ msgstr "系统用户数量" msgid "Create permission" msgstr "创建授权规则" +#: perms/templates/perms/asset_permission_list.html:31 +msgid "Is valid" +msgstr "有效" + #: perms/templates/perms/asset_permission_user.html:35 msgid "User list of " msgstr "用户列表" -#: perms/templates/perms/asset_permission_user.html:56 users/models/user.py:37 -#: users/templates/users/user_detail.html:70 -#: users/templates/users/user_profile.html:59 -msgid "Email" -msgstr "邮件" - -#: perms/templates/perms/asset_permission_user.html:91 +#: perms/templates/perms/asset_permission_user.html:80 msgid "Add user to asset permission" msgstr "添加用户" -#: perms/templates/perms/asset_permission_user.html:99 +#: perms/templates/perms/asset_permission_user.html:88 #: users/templates/users/login_log_list.html:28 msgid "Select user" msgstr "选择用户" -#: perms/templates/perms/asset_permission_user.html:119 +#: perms/templates/perms/asset_permission_user.html:108 msgid "Add user group to asset permission" msgstr "添加用户组" -#: perms/views.py:27 perms/views.py:77 perms/views.py:103 perms/views.py:128 -#: perms/views.py:165 perms/views.py:195 templates/_nav.html:30 +#: perms/views.py:28 perms/views.py:44 perms/views.py:60 perms/views.py:74 +#: perms/views.py:111 perms/views.py:141 templates/_nav.html:30 msgid "Perms" msgstr "权限管理" -#: perms/views.py:28 +#: perms/views.py:29 msgid "Asset permission list" msgstr "资产授权列表" -#: perms/views.py:63 -#, python-brace-format -msgid "Create asset permission {name} successfully." -msgstr "创建授权 {name} 成功" - -#: perms/views.py:78 +#: perms/views.py:45 msgid "Create asset permission" msgstr "创建权限规则" -#: perms/views.py:89 -#, python-brace-format -msgid "Create asset permission {name} success." -msgstr "创建授权 {name} 成功" - -#: perms/views.py:104 +#: perms/views.py:61 msgid "Update asset permission" msgstr "更新资产授权" -#: perms/views.py:115 -#, python-brace-format -msgid "Update asset permission {name} success." -msgstr "更新授权 {name} 成功" - -#: perms/views.py:129 +#: perms/views.py:75 msgid "Asset permission detail" msgstr "资产授权详情" -#: perms/views.py:166 +#: perms/views.py:112 msgid "Asset permission user list" msgstr "资产授权包含用户" -#: perms/views.py:196 +#: perms/views.py:142 msgid "Asset permission asset list" msgstr "资产组授权包含资产" @@ -1671,16 +1720,34 @@ msgstr "欢迎使用Jumpserver开源跳板机系统" msgid "Help" msgstr "帮助" -#: templates/_header_bar.html:24 templates/_user_profile.html:29 +#: templates/_header_bar.html:33 templates/_nav_user.html:9 +#: users/templates/users/_user.html:42 +#: users/templates/users/user_password_update.html:37 +#: users/templates/users/user_profile.html:17 +#: users/templates/users/user_profile_update.html:37 +#: users/templates/users/user_profile_update.html:57 +#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:320 +msgid "Profile" +msgstr "个人信息" + +#: templates/_header_bar.html:37 +msgid "Admin page" +msgstr "管理页面" + +#: templates/_header_bar.html:39 +msgid "User page" +msgstr "用户页面" + +#: templates/_header_bar.html:42 msgid "Logout" msgstr "注销登录" -#: templates/_header_bar.html:28 users/templates/users/login.html:42 +#: templates/_header_bar.html:46 users/templates/users/login.html:42 #: users/templates/users/login.html:61 msgid "Login" msgstr "登录" -#: templates/_header_bar.html:41 templates/_nav.html:4 +#: templates/_header_bar.html:59 templates/_nav.html:4 msgid "Dashboard" msgstr "仪表盘" @@ -1714,11 +1781,11 @@ msgstr "" msgid "Close" msgstr "关闭" -#: templates/_nav.html:9 users/views/group.py:30 users/views/group.py:46 -#: users/views/group.py:72 users/views/group.py:89 users/views/login.py:192 -#: users/views/login.py:241 users/views/user.py:55 users/views/user.py:70 -#: users/views/user.py:95 users/views/user.py:151 users/views/user.py:308 -#: users/views/user.py:322 users/views/user.py:366 users/views/user.py:388 +#: templates/_nav.html:9 users/views/group.py:28 users/views/group.py:44 +#: users/views/group.py:62 users/views/group.py:79 users/views/login.py:193 +#: users/views/login.py:242 users/views/user.py:57 users/views/user.py:72 +#: users/views/user.py:92 users/views/user.py:148 users/views/user.py:305 +#: users/views/user.py:319 users/views/user.py:356 users/views/user.py:378 msgid "Users" msgstr "用户管理" @@ -1739,11 +1806,11 @@ msgid "Task" msgstr "任务" #: templates/_nav.html:47 templates/_nav.html:50 -#: terminal/templates/terminal/session_list.html:74 -#: terminal/views/command.py:47 terminal/views/session.py:54 -#: terminal/views/session.py:77 terminal/views/session.py:94 -#: terminal/views/session.py:116 terminal/views/terminal.py:31 -#: terminal/views/terminal.py:46 terminal/views/terminal.py:58 +#: terminal/templates/terminal/session_list.html:75 +#: terminal/views/command.py:47 terminal/views/session.py:75 +#: terminal/views/session.py:92 terminal/views/session.py:114 +#: terminal/views/terminal.py:31 terminal/views/terminal.py:46 +#: terminal/views/terminal.py:58 msgid "Terminal" msgstr "终端" @@ -1755,43 +1822,18 @@ msgstr "在线会话" msgid "Session offline" msgstr "离线会话" -#: templates/_nav.html:53 terminal/models.py:98 +#: templates/_nav.html:53 terminal/models.py:99 #: terminal/templates/terminal/command_list.html:55 #: terminal/templates/terminal/command_list.html:71 -#: terminal/templates/terminal/session_list.html:75 +#: terminal/templates/terminal/session_detail.html:48 +#: terminal/templates/terminal/session_list.html:76 msgid "Command" msgstr "命令" -#: templates/_nav.html:73 -msgid "Visit us" -msgstr "访问官网" - #: templates/_nav_user.html:4 msgid "My assets" msgstr "我的资产" -#: templates/_nav_user.html:9 templates/_user_profile.html:19 -#: users/templates/users/_user.html:42 -#: users/templates/users/user_password_update.html:37 -#: users/templates/users/user_profile.html:17 -#: users/templates/users/user_profile_update.html:37 -#: users/templates/users/user_profile_update.html:57 -#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:323 -msgid "Profile" -msgstr "个人信息" - -#: templates/_user_profile.html:20 -msgid "Profile settings" -msgstr "个人信息设置" - -#: templates/_user_profile.html:24 -msgid "Admin page" -msgstr "管理页面" - -#: templates/_user_profile.html:26 -msgid "User page" -msgstr "用户页面" - #: templates/captcha/image.html:3 msgid "Play CAPTCHA as audio file" msgstr "语言播放验证码" @@ -1818,16 +1860,12 @@ msgid "Session" msgstr "会话" #: terminal/forms.py:15 -msgid "A unique addr of every terminal, user browser can arrive it" -msgstr "" +msgid "Coco ssh listen port" +msgstr "SSH 监听端口" #: terminal/forms.py:16 -msgid "Coco ssh listen port" -msgstr "" - -#: terminal/forms.py:17 msgid "Coco http/ws listen port" -msgstr "" +msgstr "Http/Websocket 监听端口" #: terminal/models.py:15 msgid "Remote Address" @@ -1847,7 +1885,7 @@ msgstr "在线会话" #: terminal/models.py:69 msgid "CPU Usage" -msgstr "" +msgstr "CPU使用" #: terminal/models.py:70 msgid "Memory Used" @@ -1855,34 +1893,39 @@ msgstr "内存使用" #: terminal/models.py:71 msgid "Connections" -msgstr "连接" +msgstr "连接数" #: terminal/models.py:72 msgid "Threads" -msgstr "线程" +msgstr "线程数" #: terminal/models.py:73 msgid "Boot Time" msgstr "运行时间" -#: terminal/models.py:97 terminal/templates/terminal/session_list.html:98 +#: terminal/models.py:96 terminal/templates/terminal/session_list.html:74 +#: terminal/templates/terminal/terminal_detail.html:47 +msgid "Remote addr" +msgstr "远端地址" + +#: terminal/models.py:98 terminal/templates/terminal/session_list.html:100 msgid "Replay" msgstr "回放" -#: terminal/models.py:101 +#: terminal/models.py:102 msgid "Date end" msgstr "结束日期" -#: terminal/models.py:118 +#: terminal/models.py:119 msgid "Args" msgstr "参数" #: terminal/templates/terminal/command_list.html:88 msgid "Goto" -msgstr "" +msgstr "转到" #: terminal/templates/terminal/session_detail.html:17 -#: terminal/views/session.py:117 +#: terminal/views/session.py:115 msgid "Session detail" msgstr "会话详情" @@ -1912,19 +1955,19 @@ msgstr "监控" msgid "Terminate session" msgstr "终止会话" -#: terminal/templates/terminal/session_list.html:77 +#: terminal/templates/terminal/session_list.html:78 msgid "Duration" msgstr "时长" -#: terminal/templates/terminal/session_list.html:100 +#: terminal/templates/terminal/session_list.html:102 msgid "Monitor" msgstr "监控" -#: terminal/templates/terminal/session_list.html:101 +#: terminal/templates/terminal/session_list.html:103 msgid "Terminate" msgstr "终断" -#: terminal/templates/terminal/session_list.html:117 +#: terminal/templates/terminal/session_list.html:119 msgid "Terminate task send, waiting ..." msgstr "终断任务已发送,请等待" @@ -1933,10 +1976,6 @@ msgstr "终断任务已发送,请等待" msgid "Terminal detail" msgstr "终端详情" -#: terminal/templates/terminal/terminal_detail.html:47 -msgid "Remote address" -msgstr "远端地址" - #: terminal/templates/terminal/terminal_detail.html:51 #: terminal/templates/terminal/terminal_list.html:31 msgid "SSH port" @@ -1971,14 +2010,14 @@ msgstr "接受终端注册" msgid "Info" msgstr "信息" -#: terminal/views/session.py:55 terminal/views/session.py:95 -msgid "Session offline list" -msgstr "离线会话" - -#: terminal/views/session.py:78 +#: terminal/views/session.py:76 msgid "Session online list" msgstr "在线会话" +#: terminal/views/session.py:93 +msgid "Session offline list" +msgstr "离线会话" + #: terminal/views/terminal.py:32 msgid "Terminal list" msgstr "终端列表" @@ -2119,7 +2158,7 @@ msgstr "Agent" msgid "Date login" msgstr "登录日期" -#: users/models/user.py:30 users/models/user.py:255 +#: users/models/user.py:30 users/models/user.py:259 msgid "Administrator" msgstr "管理员" @@ -2127,6 +2166,11 @@ msgstr "管理员" msgid "Application" msgstr "应用程序" +#: users/models/user.py:37 users/templates/users/user_detail.html:70 +#: users/templates/users/user_profile.html:59 +msgid "Email" +msgstr "邮件" + #: users/models/user.py:39 users/templates/users/_select_user_modal.html:15 #: users/templates/users/user_detail.html:86 #: users/templates/users/user_list.html:25 @@ -2146,10 +2190,6 @@ msgstr "微信" msgid "Enable OTP" msgstr "二次验证" -#: users/models/user.py:46 -msgid "Private key" -msgstr "ssh私钥" - #: users/models/user.py:47 users/templates/users/user_password_update.html:43 #: users/templates/users/user_profile.html:71 #: users/templates/users/user_profile_update.html:43 @@ -2157,7 +2197,7 @@ msgstr "ssh私钥" msgid "Public key" msgstr "ssh公钥" -#: users/models/user.py:258 +#: users/models/user.py:262 msgid "Administrator is the super user of system" msgstr "Administrator是初始的超级管理员" @@ -2259,7 +2299,7 @@ msgid "Setting" msgstr "设置" #: users/templates/users/user_create.html:4 -#: users/templates/users/user_list.html:16 users/views/user.py:70 +#: users/templates/users/user_list.html:16 users/views/user.py:72 msgid "Create user" msgstr "创建用户" @@ -2270,7 +2310,7 @@ msgstr "生成重置密码连接,通过邮件发送给用户" #: users/templates/users/user_detail.html:19 #: users/templates/users/user_granted_asset.html:18 #: users/templates/users/user_group_granted_asset.html:18 -#: users/views/user.py:152 +#: users/views/user.py:149 msgid "User detail" msgstr "用户详情" @@ -2306,13 +2346,13 @@ msgstr "已发送邮件到用户邮箱" msgid "" "This will reset the user's password. A password-reset email will be sent to " "the user\\'s mailbox." -msgstr "" +msgstr "重设密码邮件将会发送到用户邮箱" #: users/templates/users/user_detail.html:348 msgid "" "The reset-ssh-public-key E-mail has been sent successfully. Please inform " "the user to update his new ssh public key." -msgstr "" +msgstr "重设秘钥邮件将会发送到用户邮箱" #: users/templates/users/user_detail.html:349 #: users/templates/users/user_profile.html:144 @@ -2345,11 +2385,11 @@ msgstr "授权资产" msgid "Asset groups granted of " msgstr "授权资产组" -#: users/templates/users/user_group_create_update.html:45 +#: users/templates/users/user_group_create_update.html:31 msgid "Cancel" msgstr "取消" -#: users/templates/users/user_group_detail.html:22 users/views/group.py:90 +#: users/templates/users/user_group_detail.html:22 users/views/group.py:80 msgid "User group detail" msgstr "资产组详情" @@ -2361,7 +2401,7 @@ msgstr "添加用户" msgid "Valid" msgstr "可用" -#: users/templates/users/user_group_list.html:5 users/views/group.py:47 +#: users/templates/users/user_group_list.html:5 users/views/group.py:45 msgid "Create user group" msgstr "创建用户组" @@ -2399,8 +2439,8 @@ msgstr "用户删除失败" msgid "OTP" msgstr "" -#: users/templates/users/user_profile.html:100 users/views/user.py:181 -#: users/views/user.py:233 +#: users/templates/users/user_profile.html:100 users/views/user.py:178 +#: users/views/user.py:230 msgid "User groups" msgstr "用户组" @@ -2424,7 +2464,7 @@ msgstr "指纹" msgid "Update public key" msgstr "更新密钥" -#: users/templates/users/user_update.html:4 users/views/user.py:95 +#: users/templates/users/user_update.html:4 users/views/user.py:92 msgid "Update user" msgstr "编辑用户" @@ -2558,17 +2598,17 @@ msgstr "禁用或失效" msgid "Password or SSH public key invalid" msgstr "密码或秘钥不合法" -#: users/views/group.py:31 +#: users/views/group.py:29 msgid "User group list" msgstr "用户组列表" -#: users/views/group.py:73 +#: users/views/group.py:63 msgid "Update user group" msgstr "编辑用户组" #: users/views/login.py:54 msgid "Please enable cookies and try again." -msgstr "" +msgstr "设置你的浏览器支持cookie" #: users/views/login.py:83 msgid "Logout success" @@ -2578,81 +2618,69 @@ msgstr "退出登录成功" msgid "Logout success, return login page" msgstr "退出登录成功,返回到登录页面" -#: users/views/login.py:99 +#: users/views/login.py:100 msgid "Email address invalid, please input again" msgstr "邮箱地址错误,重新输入" -#: users/views/login.py:112 +#: users/views/login.py:113 msgid "Send reset password message" msgstr "发送重置密码邮件" -#: users/views/login.py:113 +#: users/views/login.py:114 msgid "Send reset password mail success, login your mail box and follow it " msgstr "" "发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)" -#: users/views/login.py:127 +#: users/views/login.py:128 msgid "Reset password success" msgstr "重置密码成功" -#: users/views/login.py:128 +#: users/views/login.py:129 msgid "Reset password success, return to login page" msgstr "重置密码成功,返回到登录页面" -#: users/views/login.py:145 users/views/login.py:158 +#: users/views/login.py:146 users/views/login.py:159 msgid "Token invalid or expired" msgstr "Token错误或失效" -#: users/views/login.py:154 +#: users/views/login.py:155 msgid "Password not same" msgstr "密码不一致" -#: users/views/login.py:192 +#: users/views/login.py:193 msgid "First login" msgstr "首次登陆" -#: users/views/login.py:242 +#: users/views/login.py:243 msgid "Login log list" msgstr "登录日志" -#: users/views/user.py:56 +#: users/views/user.py:58 msgid "User list" msgstr "用户列表" -#: users/views/user.py:66 users/views/user.py:335 -#, python-brace-format -msgid "Create user {name} successfully." -msgstr "创建用户 {name} 成功" - -#: users/views/user.py:105 +#: users/views/user.py:102 msgid "Bulk update user success" msgstr "批量更新用户成功" -#: users/views/user.py:210 +#: users/views/user.py:207 msgid "Invalid file." msgstr "文件不合法" -#: users/views/user.py:309 +#: users/views/user.py:306 msgid "User granted assets" msgstr "用户授权资产" -#: users/views/user.py:349 +#: users/views/user.py:339 msgid "Profile setting" msgstr "个人信息设置" -#: users/views/user.py:367 +#: users/views/user.py:357 msgid "Password update" msgstr "密码更新" -#: users/views/user.py:389 +#: users/views/user.py:379 msgid "Public key update" msgstr "秘钥更新" -#~ msgid "Audits" -#~ msgstr "审计中心" -#~ msgid "Proxy log list" -#~ msgstr "Session列表" - -#~ msgid "If also set private key, use that first" -#~ msgstr "如果设置私钥,则优先使用密钥" diff --git a/apps/ops/api.py b/apps/ops/api.py index 2ecf2238a..09f5e67e7 100644 --- a/apps/ops/api.py +++ b/apps/ops/api.py @@ -2,11 +2,13 @@ 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 .models import Task, AdHoc, AdHocRunHistory from .serializers import TaskSerializer, AdHocSerializer, AdHocRunHistorySerializer +from .tasks import run_ansible_task class TaskViewSet(viewsets.ModelViewSet): @@ -15,6 +17,17 @@ class TaskViewSet(viewsets.ModelViewSet): 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): queryset = AdHoc.objects.all() serializer_class = AdHocSerializer diff --git a/apps/ops/hands.py b/apps/ops/hands.py index d7175db18..b6e3d3479 100644 --- a/apps/ops/hands.py +++ b/apps/ops/hands.py @@ -1,4 +1,4 @@ # ~*~ coding: utf-8 ~*~ from users.permissions import IsSuperUser - +from users.utils import AdminUserRequiredMixin \ No newline at end of file diff --git a/apps/ops/models.py b/apps/ops/models.py index 3f83e8ffd..accdfe78f 100644 --- a/apps/ops/models.py +++ b/apps/ops/models.py @@ -235,6 +235,7 @@ class AdHoc(models.Model): return result.results_raw, result.results_summary except AnsibleError as e: logger.error("Failed run adhoc {}, {}".format(self.task.name, e)) + pass @become.setter def become(self, item): diff --git a/apps/ops/templates/ops/adhoc_detail.html b/apps/ops/templates/ops/adhoc_detail.html index 6134b1ce4..abbb16c04 100644 --- a/apps/ops/templates/ops/adhoc_detail.html +++ b/apps/ops/templates/ops/adhoc_detail.html @@ -3,9 +3,9 @@ {% load i18n %} {% block custom_head_css_js %} - + - + {% endblock %} {% block content %} diff --git a/apps/ops/templates/ops/adhoc_history.html b/apps/ops/templates/ops/adhoc_history.html index 95689fb89..802e8e8f6 100644 --- a/apps/ops/templates/ops/adhoc_history.html +++ b/apps/ops/templates/ops/adhoc_history.html @@ -3,9 +3,9 @@ {% load i18n %} {% block custom_head_css_js %} - + - + {% endblock %} {% block content %} diff --git a/apps/ops/templates/ops/adhoc_history_detail.html b/apps/ops/templates/ops/adhoc_history_detail.html index 5439ae571..f3d18f8ba 100644 --- a/apps/ops/templates/ops/adhoc_history_detail.html +++ b/apps/ops/templates/ops/adhoc_history_detail.html @@ -3,9 +3,9 @@ {% load i18n %} {% block custom_head_css_js %} - + - + {% endblock %} {% block content %} diff --git a/apps/ops/templates/ops/task_adhoc.html b/apps/ops/templates/ops/task_adhoc.html index 2b26b058c..2d2c4de5c 100644 --- a/apps/ops/templates/ops/task_adhoc.html +++ b/apps/ops/templates/ops/task_adhoc.html @@ -3,9 +3,9 @@ {% load i18n %} {% block custom_head_css_js %} - + - + {% endblock %} {% block content %} diff --git a/apps/ops/templates/ops/task_detail.html b/apps/ops/templates/ops/task_detail.html index dab26d1dc..4da7e0f58 100644 --- a/apps/ops/templates/ops/task_detail.html +++ b/apps/ops/templates/ops/task_detail.html @@ -3,9 +3,9 @@ {% load i18n %} {% block custom_head_css_js %} - + - + {% endblock %} {% block content %} @@ -89,7 +89,7 @@ diff --git a/apps/ops/templates/ops/task_history.html b/apps/ops/templates/ops/task_history.html index 6aebce351..cc620237d 100644 --- a/apps/ops/templates/ops/task_history.html +++ b/apps/ops/templates/ops/task_history.html @@ -3,9 +3,9 @@ {% load i18n %} {% block custom_head_css_js %} - + - + {% endblock %} {% block content %} diff --git a/apps/ops/templates/ops/task_list.html b/apps/ops/templates/ops/task_list.html index a127a0ff6..e564eec73 100644 --- a/apps/ops/templates/ops/task_list.html +++ b/apps/ops/templates/ops/task_list.html @@ -67,6 +67,7 @@ {% endif %} @@ -98,10 +99,32 @@ $(document).ready(function() { }).on('click', '.btn-del', function () { 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 the_url = '{% url "api-ops:task-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid); 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 + }); + }) {% endblock %} diff --git a/apps/ops/urls/api_urls.py b/apps/ops/urls/api_urls.py index 545487f00..ab007c383 100644 --- a/apps/ops/urls/api_urls.py +++ b/apps/ops/urls/api_urls.py @@ -1,6 +1,7 @@ # ~*~ coding: utf-8 ~*~ from __future__ import unicode_literals +from django.conf.urls import url from rest_framework.routers import DefaultRouter 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/history', api.AdHocRunHistorySet, 'history') -urlpatterns = [] +urlpatterns = [ + url(r'^v1/tasks/(?P[0-9a-zA-Z\-]{36})/run/$', api.TaskRun.as_view(), name='task-run'), +] urlpatterns += router.urls diff --git a/apps/ops/views.py b/apps/ops/views.py index 2c58e496e..4b090a8a3 100644 --- a/apps/ops/views.py +++ b/apps/ops/views.py @@ -6,9 +6,10 @@ from django.views.generic import ListView, DetailView from common.mixins import DatetimeSearchMixin 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 model = Task ordering = ('-date_created',) @@ -42,7 +43,7 @@ class TaskListView(DatetimeSearchMixin, ListView): return super().get_context_data(**kwargs) -class TaskDetailView(DetailView): +class TaskDetailView(AdminUserRequiredMixin, DetailView): model = Task template_name = 'ops/task_detail.html' @@ -55,7 +56,7 @@ class TaskDetailView(DetailView): return super().get_context_data(**kwargs) -class TaskAdhocView(DetailView): +class TaskAdhocView(AdminUserRequiredMixin, DetailView): model = Task template_name = 'ops/task_adhoc.html' @@ -68,7 +69,7 @@ class TaskAdhocView(DetailView): return super().get_context_data(**kwargs) -class TaskHistoryView(DetailView): +class TaskHistoryView(AdminUserRequiredMixin, DetailView): model = Task template_name = 'ops/task_history.html' @@ -81,7 +82,7 @@ class TaskHistoryView(DetailView): return super().get_context_data(**kwargs) -class AdHocDetailView(DetailView): +class AdHocDetailView(AdminUserRequiredMixin, DetailView): model = AdHoc template_name = 'ops/adhoc_detail.html' @@ -94,7 +95,7 @@ class AdHocDetailView(DetailView): return super().get_context_data(**kwargs) -class AdHocHistoryView(DetailView): +class AdHocHistoryView(AdminUserRequiredMixin, DetailView): model = AdHoc template_name = 'ops/adhoc_history.html' @@ -107,7 +108,7 @@ class AdHocHistoryView(DetailView): return super().get_context_data(**kwargs) -class AdHocHistoryDetailView(DetailView): +class AdHocHistoryDetailView(AdminUserRequiredMixin, DetailView): model = AdHocRunHistory template_name = 'ops/adhoc_history_detail.html' diff --git a/apps/perms/forms.py b/apps/perms/forms.py index fbb0c8226..4e3c0bf72 100644 --- a/apps/perms/forms.py +++ b/apps/perms/forms.py @@ -15,7 +15,8 @@ class AssetPermissionForm(forms.ModelForm): widget=forms.SelectMultiple( attrs={'class': 'select2', 'data-placeholder': _('Select users')}, ), - label=_("User") + label=_("User"), + required=False, ) class Meta: @@ -41,35 +42,54 @@ class AssetPermissionForm(forms.ModelForm): help_texts = { 'name': '* 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): from assets.utils import check_assets_have_system_user errors = [] assets = self.cleaned_data['assets'] - asset_groups = self.cleaned_data['asset_groups'] - system_users = self.cleaned_data['system_users'] + asset_groups = self.cleaned_data.get('asset_groups') + 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) if error_data: 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( asset.hostname, + asset.cluster.name, ", ".join(system_user.name for system_user in system_users) )) errors.append(error) 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() error_data = check_assets_have_system_user(assets, system_users) for asset, system_users in error_data.items(): 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) )) if errors: diff --git a/apps/perms/templates/perms/asset_permission_asset.html b/apps/perms/templates/perms/asset_permission_asset.html index 4ae615f1f..5cfc44c05 100644 --- a/apps/perms/templates/perms/asset_permission_asset.html +++ b/apps/perms/templates/perms/asset_permission_asset.html @@ -3,8 +3,8 @@ {% load i18n %} {% block custom_head_css_js %} - - + + {% endblock %} {% block content %}
    @@ -53,8 +53,6 @@
    - - @@ -63,15 +61,6 @@ - - - diff --git a/apps/perms/templates/perms/asset_permission_detail.html b/apps/perms/templates/perms/asset_permission_detail.html index 5b945a900..5540ca515 100644 --- a/apps/perms/templates/perms/asset_permission_detail.html +++ b/apps/perms/templates/perms/asset_permission_detail.html @@ -3,8 +3,8 @@ {% load i18n %} {% block custom_head_css_js %} - - + + {% endblock %} {% block content %} @@ -27,11 +27,11 @@ {% trans 'Assets and asset groups' %}
  • - Update + {% trans 'Update' %}
  • - Delete + {% trans 'Delete' %}
  • @@ -113,7 +113,7 @@
    {% for task in object.latest_adhoc.tasks %} - {{ forloop.counter }}. {{ task.name }} : {{ task.action.module }}
    + {{ forloop.counter }}. {{ task.name }} ::: {{ task.action.module }}
    {% endfor %}
    + {% trans "Run" %} {% trans "Delete" %}
    {% trans 'Hostname' %} {% trans 'IP' %}{% trans 'Port' %}{% trans 'Is valid' %}
    {{ asset.hostname }} {{ asset.ip }}{{ user.port }} - {% if asset.is_active %} - - {% else %} - - {% endif %} -
    - +
    Active:{% trans 'Active' %} :
    @@ -139,8 +139,8 @@ - - + - - + {% for system_user in system_users %} - + - - @@ -63,15 +61,6 @@ - - - @@ -231,7 +220,6 @@ $(document).ready(function () { $.map(jumpserver.users_selected, function(value, index) { users_id.push(index); }); - console.log(users_id); addUsers(users_id); }).on('click', '.btn-remove-user', function () { var user_id = $(this).data("gid"); diff --git a/apps/perms/urls/api_urls.py b/apps/perms/urls/api_urls.py index f59bb178e..a9fad1eac 100644 --- a/apps/perms/urls/api_urls.py +++ b/apps/perms/urls/api_urls.py @@ -7,9 +7,7 @@ from .. import api app_name = 'perms' router = routers.DefaultRouter() -router.register('v1/asset-permissions', - api.AssetPermissionViewSet, - 'asset-permission') +router.register('v1/asset-permissions', api.AssetPermissionViewSet, 'asset-permission') urlpatterns = [ # 用户可以使用自己的Token或其它认证查看自己授权的资产,资产组等 diff --git a/apps/perms/views.py b/apps/perms/views.py index d3759d064..6fb2cbca7 100644 --- a/apps/perms/views.py +++ b/apps/perms/views.py @@ -11,6 +11,7 @@ from django.contrib.messages.views import SuccessMessageMixin from django.views.generic.detail import DetailView, SingleObjectMixin from django.contrib import messages +from common.const import create_success_msg, update_success_msg from .hands import AdminUserRequiredMixin, User, UserGroup, SystemUser, \ Asset, AssetGroup from .models import AssetPermission @@ -31,46 +32,12 @@ class AssetPermissionListView(AdminUserRequiredMixin, ListView): 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 = "WARNING: System user " \ - "should in behind clusters, so that " \ - "system user cat auto push to the cluster assets:
    " - 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 {name} ' - 'successfully.'.format(url=url, name=self.object.name)) - return success_message - - class AssetPermissionCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView): model = AssetPermission form_class = AssetPermissionForm template_name = 'perms/asset_permission_create_update.html' success_url = reverse_lazy('perms:asset-permission-list') - warning = None + success_message = create_success_msg def get_context_data(self, **kwargs): context = { @@ -80,23 +47,13 @@ class AssetPermissionCreateView(AdminUserRequiredMixin, SuccessMessageMixin, Cre kwargs.update(context) 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 {name} ' - 'success.'.format(url=url, name=self.object.name) - ) - return success_message - class AssetPermissionUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView): model = AssetPermission form_class = AssetPermissionForm template_name = 'perms/asset_permission_create_update.html' success_url = reverse_lazy("perms:asset-permission-list") + success_message = update_success_msg def get_context_data(self, **kwargs): context = { @@ -106,17 +63,6 @@ class AssetPermissionUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, Upd kwargs.update(context) 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 {name} ' - 'success.'.format(url=url, name=self.object.name) - ) - return success_message - class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView): template_name = 'perms/asset_permission_detail.html' diff --git a/apps/static/js/jumpserver.js b/apps/static/js/jumpserver.js index 5812e0191..a76c44187 100644 --- a/apps/static/js/jumpserver.js +++ b/apps/static/js/jumpserver.js @@ -61,7 +61,6 @@ function GetTableDataBox() { id_list.push(i); } } - console.log(id_list); for (i in id_list) { console.log(tabProduct); tableData.push(GetRowData(tabProduct.rows[id_list[i]])); @@ -357,5 +356,15 @@ String.prototype.format = function(args) { function setCookie(key, value) { var expires = new Date(); 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=/'; + } } diff --git a/apps/templates/_base_create_update.html b/apps/templates/_base_create_update.html index fdc5269e2..a38a6133d 100644 --- a/apps/templates/_base_create_update.html +++ b/apps/templates/_base_create_update.html @@ -3,8 +3,8 @@ {% load static %} {% load bootstrap3 %} {% block custom_head_css_js %} - - + + {% block custom_head_css_js_create %} {% endblock %} {% endblock %} diff --git a/apps/templates/_base_list.html b/apps/templates/_base_list.html index 6385994e0..191ba8151 100644 --- a/apps/templates/_base_list.html +++ b/apps/templates/_base_list.html @@ -3,8 +3,8 @@ {% load i18n %} {% block custom_head_css_js %} - - + + {% endblock %} {% block content %} diff --git a/apps/templates/_header_bar.html b/apps/templates/_header_bar.html index 9c5f64580..a8866dfcc 100644 --- a/apps/templates/_header_bar.html +++ b/apps/templates/_header_bar.html @@ -3,11 +3,11 @@ - + - + @@ -84,24 +84,24 @@
    +
    +
    {{ system_user.name }} @@ -237,6 +237,16 @@ $(document).ready(function () { }).get(); updateSystemUser(system_users); $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), + }); }) {% endblock %} diff --git a/apps/perms/templates/perms/asset_permission_list.html b/apps/perms/templates/perms/asset_permission_list.html index da4c88f80..a8bdab5a1 100644 --- a/apps/perms/templates/perms/asset_permission_list.html +++ b/apps/perms/templates/perms/asset_permission_list.html @@ -69,9 +69,11 @@ function initTable() { $(td).html('') } }}, - {targets: 8, createdCell: function (td, cellData) { + {targets: 8, createdCell: function (td, cellData, rowData) { var update_btn = '{% trans "Update" %}'.replace('{{ DEFAULT_PK }}', cellData); - var del_btn = '{% trans "Delete" %}'.replace('{{ DEFAULT_PK }}', cellData); + var del_btn = '{% trans "Delete" %}' + .replace('{{ DEFAULT_PK }}', cellData) + .replace('99991938', rowData.name); $(td).html(update_btn + del_btn); }} diff --git a/apps/perms/templates/perms/asset_permission_user.html b/apps/perms/templates/perms/asset_permission_user.html index 8f24cbeea..2e64368aa 100644 --- a/apps/perms/templates/perms/asset_permission_user.html +++ b/apps/perms/templates/perms/asset_permission_user.html @@ -3,8 +3,8 @@ {% load i18n %} {% block custom_head_css_js %} - - + + {% endblock %} {% block content %}
    @@ -53,8 +53,6 @@
    {% trans 'Name' %} {% trans 'Username' %}{% trans 'Email' %}{% trans 'Is valid' %}
    {{ user.name }} {{ user.username }}{{ user.email }} - {% if user.is_expired and user.is_active %} - - {% else %} - - {% endif %} -
    IDCommand{% trans 'Command' %} Datetime{% trans 'Datetime' %}
    {% if object.is_finished %} - - - + + {% else %} - - - - - + + + + + + + + + + @@ -88,6 +89,7 @@ + @@ -97,7 +99,7 @@ {% if session.is_finished %} {% trans "Replay" %} {% else %} - {% trans "Monitor" %} + {% trans "Terminate" %} {% endif %} diff --git a/apps/terminal/templates/terminal/terminal_detail.html b/apps/terminal/templates/terminal/terminal_detail.html index d9e615f1b..ea0ba6614 100644 --- a/apps/terminal/templates/terminal/terminal_detail.html +++ b/apps/terminal/templates/terminal/terminal_detail.html @@ -13,7 +13,7 @@ {% trans 'Terminal detail' %}
  • - Update + {% trans 'Update' %}
  • @@ -44,7 +44,7 @@ - + diff --git a/apps/terminal/templates/terminal/terminal_list.html b/apps/terminal/templates/terminal/terminal_list.html index 314ed6c9a..f040f92ee 100644 --- a/apps/terminal/templates/terminal/terminal_list.html +++ b/apps/terminal/templates/terminal/terminal_list.html @@ -136,7 +136,6 @@ $(document).ready(function(){ }).on('click', '.btn-connect', function () { var $this = $(this); var id = $this.data('id'); - console.log(id) }) {% endblock %} diff --git a/apps/terminal/templates/terminal/terminal_update.html b/apps/terminal/templates/terminal/terminal_update.html index 624dc6e7e..9ebd9d2d8 100644 --- a/apps/terminal/templates/terminal/terminal_update.html +++ b/apps/terminal/templates/terminal/terminal_update.html @@ -3,8 +3,8 @@ {% load static %} {% load bootstrap3 %} {% block custom_head_css_js %} - - + + {% endblock %} diff --git a/apps/terminal/views/session.py b/apps/terminal/views/session.py index e0caa9771..087e16b68 100644 --- a/apps/terminal/views/session.py +++ b/apps/terminal/views/session.py @@ -1,7 +1,7 @@ # -*- 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.utils.translation import ugettext as _ from django.utils import timezone @@ -51,9 +51,9 @@ class SessionListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView): def get_context_data(self, **kwargs): context = { - 'user_list': utils.get_user_list_from_cache(), - 'asset_list': utils.get_asset_list_from_cache(), - 'system_user_list': utils.get_system_user_list_from_cache(), + 'user_list': utils.get_session_user_list(), + 'asset_list': utils.get_session_asset_list(), + 'system_user_list': utils.get_session_system_user_list(), 'date_from': self.date_from, 'date_to': self.date_to, 'user': self.user, diff --git a/apps/users/api.py b/apps/users/api.py index 0511e7ecf..326f2c3ec 100644 --- a/apps/users/api.py +++ b/apps/users/api.py @@ -128,7 +128,7 @@ class UserAuthApi(APIView): user_agent = request.data.get('HTTP_USER_AGENT', '') 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( username=username, password=password, diff --git a/apps/users/forms.py b/apps/users/forms.py index 48021ec74..651df78d3 100644 --- a/apps/users/forms.py +++ b/apps/users/forms.py @@ -29,7 +29,7 @@ class UserCreateUpdateForm(forms.ModelForm): model = User fields = [ 'username', 'name', 'email', 'groups', 'wechat', - 'phone', 'role', 'date_expired', 'comment', 'password' + 'phone', 'role', 'date_expired', 'comment', ] help_texts = { 'username': '* required', @@ -38,13 +38,16 @@ class UserCreateUpdateForm(forms.ModelForm): } widgets = { 'groups': forms.SelectMultiple( - attrs={'class': 'select2', - 'data-placeholder': _('Join user groups')}), + attrs={ + 'class': 'select2', + 'data-placeholder': _('Join user groups') + } + ), } def save(self, commit=True): - user = super().save(commit=commit) password = self.cleaned_data.get('password') + user = super().save(commit=commit) if password: user.set_password(password) user.save() @@ -184,12 +187,14 @@ class UserBulkUpdateForm(forms.ModelForm): class UserGroupForm(forms.ModelForm): users = forms.ModelMultipleChoiceField( queryset=User.objects.all(), + label=_("User"), widget=forms.SelectMultiple( attrs={ 'class': 'select2', 'data-placeholder': _('Select users') } - ) + ), + required=False, ) def __init__(self, **kwargs): diff --git a/apps/users/models/user.py b/apps/users/models/user.py index 8b2e33ec1..899cec4cb 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -168,6 +168,11 @@ class User(AbstractUser): token = PrivateToken.objects.create(user=self) 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): from .authentication import PrivateToken PrivateToken.objects.filter(user=self).delete() @@ -214,13 +219,12 @@ class User(AbstractUser): @classmethod def create_app_user(cls, name, comment): - from . import AccessKey app = cls.objects.create( username=name, name=name, email='{}@local.domain'.format(name), is_active=False, role='App', enable_otp=False, comment=comment, is_first_login=False, created_by='System' ) - access_key = AccessKey.objects.create(user=app) + access_key = app.create_access_key() return app, access_key @classmethod diff --git a/apps/users/templates/users/user_detail.html b/apps/users/templates/users/user_detail.html index 2298b885e..78c5ac542 100644 --- a/apps/users/templates/users/user_detail.html +++ b/apps/users/templates/users/user_detail.html @@ -3,9 +3,9 @@ {% load i18n %} {% block custom_head_css_js %} - + - + {% endblock %} {% block content %} @@ -22,11 +22,11 @@ {% trans 'Asset granted' %}
  • - Update + {% trans 'Update' %}
  • - Delete + {% trans 'Delete' %}
  • diff --git a/apps/users/templates/users/user_group_create_update.html b/apps/users/templates/users/user_group_create_update.html index 2a5727244..6baef2a94 100644 --- a/apps/users/templates/users/user_group_create_update.html +++ b/apps/users/templates/users/user_group_create_update.html @@ -3,8 +3,8 @@ {% load i18n %} {% load bootstrap3 %} {% block custom_head_css_js %} - - + + {% endblock %} {% block content %} @@ -25,20 +25,6 @@ {% csrf_token %} {% bootstrap_field form.name layout="horizontal" %} {% bootstrap_field form.users layout="horizontal" %} -{#
    #} -{# #} -{#
    #} -{# #} -{#
    #} -{#
    #} {% bootstrap_field form.comment layout="horizontal" %}
    @@ -57,7 +43,9 @@ {% block custom_foot_js %} {% endblock %} diff --git a/apps/users/templates/users/user_group_detail.html b/apps/users/templates/users/user_group_detail.html index f13395764..bb10398a5 100644 --- a/apps/users/templates/users/user_group_detail.html +++ b/apps/users/templates/users/user_group_detail.html @@ -3,11 +3,11 @@ {% load i18n %} {% block custom_head_css_js %} - + - + {% endblock %} @@ -25,11 +25,11 @@ {# {% trans 'Asset granted' %}#} {# #}
  • - Update + {% trans 'Update' %}
  • - Delete + {% trans 'Delete' %}
  • @@ -171,7 +171,6 @@ $(document).ready(function () { var users = $('.bdg_user').map(function() { return $(this).data('uid'); }).get(); - console.log(users); updateGroupMember(users) }).on('click', '#btn_add_user', function() { if (Object.keys(jumpserver.users_selected).length === 0) { diff --git a/apps/users/templates/users/user_group_granted_asset.html b/apps/users/templates/users/user_group_granted_asset.html index b0171e221..7944101f2 100644 --- a/apps/users/templates/users/user_group_granted_asset.html +++ b/apps/users/templates/users/user_group_granted_asset.html @@ -4,8 +4,8 @@ {% load i18n %} {% block custom_head_css_js %} - - + + {% endblock %} {% block content %}
    diff --git a/apps/users/templates/users/user_list.html b/apps/users/templates/users/user_list.html index 4b32612dd..ab9bcf3c7 100644 --- a/apps/users/templates/users/user_list.html +++ b/apps/users/templates/users/user_list.html @@ -223,7 +223,7 @@ $(document).ready(function(){ var $this = $(this); var name = $this.data('name'); 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); }) diff --git a/apps/users/views/group.py b/apps/users/views/group.py index f1658a116..4b11e7901 100644 --- a/apps/users/views/group.py +++ b/apps/users/views/group.py @@ -2,17 +2,15 @@ from __future__ import unicode_literals from django import forms -from django.shortcuts import reverse, redirect from django.utils.translation import ugettext as _ from django.urls import reverse_lazy -from django.views.generic import ListView from django.views.generic.base import TemplateView -from django.views.generic.edit import CreateView, UpdateView, FormMixin -from django.views.generic.detail import DetailView, SingleObjectMixin +from django.views.generic.edit import CreateView, UpdateView +from django.views.generic.detail import DetailView from django.contrib.messages.views import SuccessMessageMixin 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 ..utils import AdminUserRequiredMixin from .. import forms @@ -39,7 +37,7 @@ class UserGroupCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVie form_class = forms.UserGroupForm template_name = 'users/user_group_create_update.html' success_url = reverse_lazy('users:user-group-list') - success_message = ' {name} was created successfully' + success_message = create_success_msg def get_context_data(self, **kwargs): context = { @@ -49,21 +47,13 @@ class UserGroupCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVie kwargs.update(context) 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, UpdateView): +class UserGroupUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView): model = UserGroup form_class = forms.UserGroupForm template_name = 'users/user_group_create_update.html' success_url = reverse_lazy('users:user-group-list') + success_message = update_success_msg def get_context_data(self, **kwargs): users = User.objects.all() diff --git a/apps/users/views/login.py b/apps/users/views/login.py index a83789563..493e4936c 100644 --- a/apps/users/views/login.py +++ b/apps/users/views/login.py @@ -53,7 +53,8 @@ class UserLoginView(FormView): if not self.request.session.test_cookie_worked(): return HttpResponse(_("Please enable cookies and try again.")) 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', '') write_login_log_async.delay( self.request.user.username, type='W', @@ -82,6 +83,7 @@ class UserLogoutView(TemplateView): context = { 'title': _('Logout success'), 'messages': _('Logout success, return login page'), + 'interval': 1, 'redirect_url': reverse('users:login'), 'auto_redirect': True, } diff --git a/apps/users/views/user.py b/apps/users/views/user.py index ec54e1d0c..6b86ddc1b 100644 --- a/apps/users/views/user.py +++ b/apps/users/views/user.py @@ -27,12 +27,14 @@ from django.views.generic.detail import DetailView, SingleObjectMixin from django.views.decorators.csrf import csrf_exempt 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 ..models import User, UserGroup from ..utils import AdminUserRequiredMixin from ..signals import on_user_created -from common.mixins import JSONResponseMixin -from common.utils import get_logger, get_object_or_none, is_uuid + __all__ = [ 'UserListView', 'UserCreateView', 'UserDetailView', @@ -63,7 +65,7 @@ class UserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView): form_class = forms.UserCreateUpdateForm template_name = 'users/user_create.html' success_url = reverse_lazy('users:user-list') - success_message = _('Create user {name} successfully.') + success_message = create_success_msg def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -77,19 +79,14 @@ class UserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView): on_user_created.send(self.__class__, user=user) 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, UpdateView): +class UserUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView): model = User form_class = forms.UserCreateUpdateForm template_name = 'users/user_update.html' context_object_name = 'user_object' success_url = reverse_lazy('users:user-list') + success_message = update_success_msg def get_context_data(self, **kwargs): context = {'app': _('Users'), 'action': _('Update user')} @@ -332,17 +329,10 @@ class UserProfileUpdateView(LoginRequiredMixin, UpdateView): model = User form_class = forms.UserProfileForm success_url = reverse_lazy('users:user-profile') - success_message = _('Create user {name} successfully.') def get_object(self, queryset=None): 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): context = { 'app': _('User'),
    {% trans 'Replay session' %}: +
    {% trans 'Replay session' %}: - +
    {% trans 'Monitor session' %}: - - - -
    {% trans 'Terminate session' %}: diff --git a/apps/terminal/templates/terminal/session_list.html b/apps/terminal/templates/terminal/session_list.html index d5ed0d54b..3bf2600c8 100644 --- a/apps/terminal/templates/terminal/session_list.html +++ b/apps/terminal/templates/terminal/session_list.html @@ -71,6 +71,7 @@ {% trans 'User' %} {% trans 'Asset' %} {% trans 'System user' %}{% trans 'Remote addr' %} {% trans 'Terminal' %} {% trans 'Command' %} {% trans 'Date start' %}{{ session.user }} {{ session.asset }} {{ session.system_user }}{{ session.remote_addr|default:"" }} {{ session.terminal.name }} {{ session.id | get_session_command_amount }} {{ terminal.name }}
    {% trans 'Remote address' %}:{% trans 'Remote addr' %}: {{ terminal.remote_addr }}