From b4e1ac1953a329a8ecd60b36e83e9f40a3b56f86 Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 18 Dec 2017 22:48:19 +0800 Subject: [PATCH] =?UTF-8?q?[Bugfix]=20=E4=BF=AE=E5=A4=8D=E8=B5=84=E4=BA=A7?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E4=B8=AD=E4=B8=80=E4=BA=9Bbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api.py | 115 ++++------ apps/assets/forms.py | 32 ++- apps/assets/serializers.py | 40 +--- .../templates/assets/admin_user_detail.html | 121 +++++----- .../assets/templates/assets/asset_detail.html | 1 - .../templates/assets/asset_group_detail.html | 63 ++--- .../templates/assets/asset_group_list.html | 13 -- .../templates/assets/cluster_assets.html | 215 ++---------------- .../assets/templates/assets/cluster_list.html | 12 - apps/assets/urls/api_urls.py | 29 +-- apps/assets/views/asset.py | 20 +- apps/common/utils.py | 10 +- apps/locale/zh/LC_MESSAGES/django.mo | Bin 24649 -> 24649 bytes apps/locale/zh/LC_MESSAGES/django.po | 2 +- apps/ops/utils.py | 49 ---- .../templates/users/user_group_detail.html | 3 +- apps/users/views/user.py | 19 +- 17 files changed, 210 insertions(+), 534 deletions(-) diff --git a/apps/assets/api.py b/apps/assets/api.py index e1ef7032f..ab3507b3d 100644 --- a/apps/assets/api.py +++ b/apps/assets/api.py @@ -74,23 +74,30 @@ class AssetUpdateGroupApi(generics.RetrieveUpdateAPIView): permission_classes = (IsSuperUser,) -class AssetGroupUpdateApi(generics.RetrieveUpdateAPIView): +class GroupUpdateAssetsApi(generics.RetrieveUpdateAPIView): """ Asset group, update it's asset member """ queryset = AssetGroup.objects.all() - serializer_class = serializers.AssetGroupUpdateSerializer + serializer_class = serializers.GroupUpdateAssetsSerializer permission_classes = (IsSuperUser,) -class AssetGroupUpdateSystemUserApi(generics.RetrieveUpdateAPIView): - """ - Asset group push system user - """ +class GroupAddAssetsApi(generics.UpdateAPIView): queryset = AssetGroup.objects.all() - serializer_class = serializers.AssetGroupUpdateSystemUserSerializer + serializer_class = serializers.GroupUpdateAssetsSerializer permission_classes = (IsSuperUser,) + def update(self, request, *args, **kwargs): + group = self.get_object() + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + assets = serializer.validated_data['assets'] + group.assets.add(*tuple(assets)) + return Response({"msg": "ok"}) + else: + return Response({'error': serializer.errors}, status=400) + class ClusterUpdateAssetsApi(generics.RetrieveUpdateAPIView): """ @@ -110,6 +117,24 @@ class ClusterViewSet(IDInFilterMixin, BulkModelViewSet): permission_classes = (IsSuperUser,) +class ClusterAddAssetsApi(generics.UpdateAPIView): + queryset = Cluster.objects.all() + serializer_class = serializers.ClusterUpdateAssetsSerializer + permission_classes = (IsSuperUser,) + + def update(self, request, *args, **kwargs): + cluster = self.get_object() + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + assets = serializer.validated_data['assets'] + for asset in assets: + asset.cluster = cluster + asset.save() + return Response({"msg": "ok"}) + else: + return Response({'error': serializer.errors}, status=400) + + class AdminUserViewSet(IDInFilterMixin, BulkModelViewSet): """ Admin user api set, for add,delete,update,list,retrieve resource @@ -119,52 +144,31 @@ class AdminUserViewSet(IDInFilterMixin, BulkModelViewSet): permission_classes = (IsSuperUser,) -class SystemUserViewSet(IDInFilterMixin, BulkModelViewSet): - """ - System user api set, for add,delete,update,list,retrieve resource - """ - queryset = SystemUser.objects.all() - serializer_class = serializers.SystemUserSerializer - permission_classes = (IsSuperUserOrAppUser,) - - -class SystemUserUpdateApi(generics.RetrieveUpdateAPIView): - """ - Asset update it's system user - - when update then push system user to asset. - """ - queryset = Asset.objects.all() - serializer_class = serializers.AssetUpdateSystemUserSerializer +class AdminUserAddClustersApi(generics.UpdateAPIView): + queryset = AdminUser.objects.all() + serializer_class = serializers.AdminUserUpdateClusterSerializer permission_classes = (IsSuperUser,) - def patch(self, request, *args, **kwargs): - asset = self.get_object() - old_system_users = set(asset.system_users.all()) - response = super(SystemUserUpdateApi, self).patch(request, *args, **kwargs) - system_users_new = set(asset.system_users.all()) - system_users = system_users_new - old_system_users - system_users = [system_user._to_secret_json() for system_user in system_users] - push_users.delay([asset._to_secret_json()], system_users) - return response - - -class SystemUserUpdateAssetsApi(generics.RetrieveUpdateAPIView): - """ - System user update it's assets - """ - queryset = SystemUser.objects.all() - serializer_class = serializers.SystemUserUpdateAssetsSerializer - permission_classes = (IsSuperUser,) + def update(self, request, *args, **kwargs): + admin_user = self.get_object() + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + clusters = serializer.validated_data['clusters'] + for cluster in clusters: + cluster.admin_user = admin_user + cluster.save() + return Response({"msg": "ok"}) + else: + return Response({'error': serializer.errors}, status=400) -class SystemUserUpdateAssetGroupApi(generics.RetrieveUpdateAPIView): +class SystemUserViewSet(IDInFilterMixin, BulkModelViewSet): """ - System user update asset group + System user api set, for add,delete,update,list,retrieve resource """ queryset = SystemUser.objects.all() - serializer_class = serializers.SystemUserUpdateAssetGroupSerializer - permission_classes = (IsSuperUser,) + serializer_class = serializers.SystemUserSerializer + permission_classes = (IsSuperUserOrAppUser,) class AssetListUpdateApi(IDInFilterMixin, ListBulkCreateUpdateDestroyAPIView): @@ -229,22 +233,3 @@ class AssetAdminUserTestView(AssetRefreshHardwareView): else: return Response('0', status=502) - -class AssetGroupPushSystemUserView(generics.UpdateAPIView): - """ - Asset group push system user api - """ - queryset = AssetGroup.objects.all() - permission_classes = (IsSuperUser,) - serializer_class = serializers.AssetSerializer - - def patch(self, request, *args, **kwargs): - asset_group = self.get_object() - assets = asset_group.assets.all() - system_user_id = self.request.data['system_user'] - system_user = get_object_or_none(SystemUser, id=system_user_id) - if not assets or not system_user: - return Response('Invalid system user id or asset group id', status=404) - task = push_users.delay([asset._to_secret_json() for asset in assets], - system_user._to_secret_json()) - return Response(task.id) diff --git a/apps/assets/forms.py b/apps/assets/forms.py index abd6f8254..2b701dcec 100644 --- a/apps/assets/forms.py +++ b/apps/assets/forms.py @@ -61,6 +61,7 @@ class AssetBulkUpdateForm(forms.ModelForm): required=True, help_text='* required', label=_('Select assets'), + choices=[(asset.id, asset.hostname) for asset in Asset.objects.all()], widget=forms.SelectMultiple( attrs={ 'class': 'select2', @@ -68,7 +69,12 @@ class AssetBulkUpdateForm(forms.ModelForm): } ) ) - port = forms.IntegerField(min_value=1, max_value=65535, required=False, label=_('Port')) + port = forms.IntegerField( + label=_('Port'), + required=False, + min_value=1, + max_value=65535, + ) class Meta: model = Asset @@ -81,9 +87,16 @@ class AssetBulkUpdateForm(forms.ModelForm): } def save(self, commit=True): - cleaned_data = {k: v for k, v in self.cleaned_data.items() if v is not None} + changed_fields = [] + for field in self._meta.fields: + if self.data.get(field) is not None: + changed_fields.append(field) + + cleaned_data = {k: v for k, v in self.cleaned_data.items() + if k in changed_fields} + print(cleaned_data) assets_id = cleaned_data.pop('assets') - groups = cleaned_data.pop('groups') + groups = cleaned_data.pop('groups', []) assets = Asset.objects.filter(id__in=assets_id) assets.update(**cleaned_data) if groups: @@ -153,17 +166,18 @@ class AdminUserForm(forms.ModelForm): def save(self, commit=True): # Because we define custom field, so we need rewrite :method: `save` - admin_user = super(AdminUserForm, self).save(commit=commit) + admin_user = super().save(commit=commit) password = self.cleaned_data['password'] private_key = self.cleaned_data['private_key_file'] + public_key = None + + if not password: + password = None - if password: - admin_user.password = password if private_key: public_key = ssh_pubkey_gen(private_key) - admin_user.private_key = private_key - admin_user.public_key = public_key - admin_user.save() + + admin_user.set_auth(password=password, public_key=public_key, private_key=private_key) return admin_user def clean_private_key_file(self): diff --git a/apps/assets/serializers.py b/apps/assets/serializers.py index 41871759f..be54089cb 100644 --- a/apps/assets/serializers.py +++ b/apps/assets/serializers.py @@ -47,7 +47,7 @@ class AssetUpdateSystemUserSerializer(serializers.ModelSerializer): fields = ['id', 'system_users'] -class AssetGroupUpdateSerializer(serializers.ModelSerializer): +class GroupUpdateAssetsSerializer(serializers.ModelSerializer): """ 资产组更新需要的数据结构 """ @@ -58,17 +58,6 @@ class AssetGroupUpdateSerializer(serializers.ModelSerializer): fields = ['id', 'assets'] -class AssetGroupUpdateSystemUserSerializer(serializers.ModelSerializer): - """ - 资产组更新系统用户定义的数据结构 - """ - system_users = serializers.PrimaryKeyRelatedField(many=True, queryset=SystemUser.objects.all()) - - class Meta: - model = AssetGroup - fields = ['id', 'system_users'] - - class ClusterUpdateAssetsSerializer(serializers.ModelSerializer): """ 集群更新资产数据结构 @@ -135,35 +124,24 @@ class SystemUserSerializer(serializers.ModelSerializer): return amount -class AssetSystemUserSerializer(serializers.ModelSerializer): - """ - 查看授权的资产系统用户的数据结构,这个和AssetSerializer不同,字段少 - """ - class Meta: - model = SystemUser - fields = ('id', 'name', 'username', 'priority', 'protocol', 'comment',) - - -class SystemUserUpdateAssetsSerializer(serializers.ModelSerializer): +class AdminUserUpdateClusterSerializer(serializers.ModelSerializer): """ - 系统用户更新关联资产的数据结构 + 管理用户更新关联到的集群 """ - assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) + clusters = serializers.PrimaryKeyRelatedField(many=True, queryset=Cluster.objects.all()) class Meta: - model = SystemUser - fields = ['id', 'assets'] + model = AdminUser + fields = ['id', 'clusters'] -class SystemUserUpdateAssetGroupSerializer(serializers.ModelSerializer): +class AssetSystemUserSerializer(serializers.ModelSerializer): """ - 系统用户更新资产组的api + 查看授权的资产系统用户的数据结构,这个和AssetSerializer不同,字段少 """ - asset_groups = serializers.PrimaryKeyRelatedField(many=True, queryset=AssetGroup.objects.all()) - class Meta: model = SystemUser - fields = ['id', 'asset_groups'] + fields = ('id', 'name', 'username', 'priority', 'protocol', 'comment',) class SystemUserSimpleSerializer(serializers.ModelSerializer): diff --git a/apps/assets/templates/assets/admin_user_detail.html b/apps/assets/templates/assets/admin_user_detail.html index 1f80b8fe9..5f0646197 100644 --- a/apps/assets/templates/assets/admin_user_detail.html +++ b/apps/assets/templates/assets/admin_user_detail.html @@ -102,12 +102,12 @@ {% trans 'Using this as cluster admin user' %}
- +
{% for cluster in admin_user.cluster_set.all %} - - + {% endfor %} @@ -161,74 +158,48 @@ Array.prototype.unique = function(){ } return res; }; -function objectRemove(obj, name, url, data) { - function doRemove() { - var body = data; - var success = function() { - swal('Remove!', "[ "+name+"]"+" has been deleted ", "success"); - $(obj).parent().parent().remove(); - }; - var fail = function() { - swal("Failed", "Remove"+"[ "+name+" ]"+"failed", "error"); - }; - APIUpdateAttr({ - url: url, - body: JSON.stringify(body), - method: 'PATCH', - success: success, - error: fail + +function bindToCluster(clusters) { + var the_url = "{% url 'api-assets:admin-user-add-clusters' pk=admin_user.id %}"; + var body = { + clusters: clusters + }; + var success = function(data) { + // remove all the selected groups from select > option and rendered ul element; + $('.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( + '' + + '' + + '' + ) }); - } - swal({ - title: 'Are you sure remove ?', - text: " [" + name + "] ", - type: "warning", - showCancelButton: true, - cancelButtonText: 'Cancel', - confirmButtonColor: "#DD6B55", - confirmButtonText: 'Confirm', - closeOnConfirm: false - }, function () { - doRemove() + $.map(jumpserver.cluster_selected, function(value, index) { + $('#opt_' + index).remove(); + }); + // clear jumpserver.groups_selected + jumpserver.cluster_selected = {}; + }; + APIUpdateAttr({ + url: the_url, + body: JSON.stringify(body), + success: success }); } -function adminUserDelete(name, url) { - function doDelete() { - var body = {}; - var success = function() { - swal('Deleted!', "[ "+name+"]"+" has been deleted ", "success"); - window.location.href="{% url 'assets:cluster-list' %}"; - }; - var fail = function() { - swal("Failed", "Delete"+"[ "+name+" ]"+"failed", "error"); - }; - APIUpdateAttr({ - url: url, - body: JSON.stringify(body), - method: 'DELETE', - success: success, - error: fail - }); - } - swal({ - title: 'Are you sure delete ?', - text: " [" + name + "] ", - type: "warning", - showCancelButton: true, - cancelButtonText: 'Cancel', - confirmButtonColor: "#DD6B55", - confirmButtonText: 'Confirm', - closeOnConfirm: false - }, function () { - doDelete() - }); -} - -jumpserver.assets_selected = {}; -jumpserver.asset_groups_selected = {}; +jumpserver.cluster_selected = {}; $(document).ready(function () { - $('.select2').select2(); + $('.select2').select2().on('select2:select', function(evt) { + var data = evt.params.data; + jumpserver.cluster_selected[data.id] = data.text; + }).on('select2:unselect', function(evt) { + var data = evt.params.data; + delete jumpserver.cluster_selected[data.id] + }); }) .on('click', '.btn-delete-admin-user', function () { var $this = $(this); @@ -238,5 +209,15 @@ $(document).ready(function () { var redirect_url = "{% url 'assets:admin-user-list' %}"; objectDelete($this, name, the_url, redirect_url); }) +.on('click', '#btn-add-cluster', function () { + if (Object.keys(jumpserver.cluster_selected).length === 0) { + return false; + } + var clusters = []; + $.map(jumpserver.cluster_selected, function(value, index) { + clusters.push(index); + }); + bindToCluster(clusters) +}) {% endblock %} diff --git a/apps/assets/templates/assets/asset_detail.html b/apps/assets/templates/assets/asset_detail.html index ba4986b4b..44e5bb547 100644 --- a/apps/assets/templates/assets/asset_detail.html +++ b/apps/assets/templates/assets/asset_detail.html @@ -247,7 +247,6 @@ {% block custom_foot_js %} {% endblock %} diff --git a/apps/assets/templates/assets/cluster_list.html b/apps/assets/templates/assets/cluster_list.html index 0ba0631c2..e80bdf847 100644 --- a/apps/assets/templates/assets/cluster_list.html +++ b/apps/assets/templates/assets/cluster_list.html @@ -27,18 +27,6 @@
- {% for cluster in cluster_remain %} {% endfor %} @@ -116,17 +116,14 @@
- +
{{ cluster.name }} - - {{ cluster.name }}
' + cluster_name + '
-
-
- -
- -
-
-
{% endblock %} {% block content_bottom_left %}{% endblock %} {% block custom_foot_js %} diff --git a/apps/assets/urls/api_urls.py b/apps/assets/urls/api_urls.py index b08fcc632..55718d5e5 100644 --- a/apps/assets/urls/api_urls.py +++ b/apps/assets/urls/api_urls.py @@ -19,37 +19,22 @@ urlpatterns = [ name='system-user-auth-info'), url(r'^v1/assets/(?P[0-9a-zA-Z\-]{36})/groups/$', api.AssetUpdateGroupApi.as_view(), name='asset-update-group'), - url(r'^v1/assets/(?P[0-9a-zA-Z\-]{36})/refresh/$', api.AssetRefreshHardwareView.as_view(), name='asset-refresh'), url(r'^v1/assets/(?P[0-9a-zA-Z\-]{36})/admin-user-test/$', api.AssetAdminUserTestView.as_view(), name='asset-admin-user-test'), - - url(r'^v1/assets/(?P[0-9a-zA-Z\-]{36})/system-users/$', - api.SystemUserUpdateApi.as_view(), name='asset-update-system-users'), - - url(r'^v1/groups/(?P[0-9a-zA-Z\-]{36})/push-system-user/$', - api.AssetGroupPushSystemUserView.as_view(), name='asset-group-push-system-user'), - - # update the system users, which add and delete the asset to the system user - url(r'^v1/system-user/(?P[0-9a-zA-Z\-]{36})/assets/$', - api.SystemUserUpdateAssetsApi.as_view(), name='systemuser-update-assets'), - - url(r'^v1/system-user/(?P[0-9a-zA-Z\-]{36})/groups/$', - api.SystemUserUpdateAssetGroupApi.as_view(), name='systemuser-update-assetgroups'), - # 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.AssetGroupUpdateApi.as_view(), name='asset-groups-update'), - - # update the asset group, and add or delete the system_user to the group - url(r'^v1/groups/(?P[0-9a-zA-Z\-]{36})/system-users/$', - api.AssetGroupUpdateSystemUserApi.as_view(), name='asset-groups-update-systemusers'), - + 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/admin-user/(?P[0-9a-zA-Z\-]{36})/clusters/$', + api.AdminUserAddClustersApi.as_view(), name='admin-user-add-clusters'), ] urlpatterns += router.urls diff --git a/apps/assets/views/asset.py b/apps/assets/views/asset.py index 355feb936..431b643e2 100644 --- a/apps/assets/views/asset.py +++ b/apps/assets/views/asset.py @@ -24,7 +24,7 @@ from django.shortcuts import redirect from common.mixins import JSONResponseMixin -from common.utils import get_object_or_none, get_logger +from common.utils import get_object_or_none, get_logger, is_uuid from .. import forms from ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser from ..hands import AdminUserRequiredMixin @@ -112,16 +112,18 @@ class AssetBulkUpdateView(AdminUserRequiredMixin, ListView): form_class = forms.AssetBulkUpdateForm template_name = 'assets/asset_bulk_update.html' success_url = reverse_lazy('assets:asset-list') + id_list = None + form = None def get(self, request, *args, **kwargs): assets_id = self.request.GET.get('assets_id', '') - self.assets_id_list = [int(i) for i in assets_id.split(',') if i.isdigit()] + self.id_list = [i for i in assets_id.split(',')] if kwargs.get('form'): self.form = kwargs['form'] elif assets_id: self.form = self.form_class( - initial={'assets': self.assets_id_list} + initial={'assets': self.id_list} ) else: self.form = self.form_class() @@ -136,13 +138,11 @@ class AssetBulkUpdateView(AdminUserRequiredMixin, ListView): return self.get(request, form=form, *args, **kwargs) def get_context_data(self, **kwargs): - # assets_list = Asset.objects.filter(id__in=self.assets_id_list) context = { 'app': 'Assets', 'action': 'Bulk update asset', 'form': self.form, - 'assets_selected': self.assets_id_list, - 'assets': Asset.objects.all(), + 'assets_selected': self.id_list, } kwargs.update(context) return super().get_context_data(**kwargs) @@ -270,13 +270,6 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView): asset_dict = dict(zip(attr, row)) id_ = asset_dict.pop('id', 0) - - try: - id_ = int(id_) - except ValueError: - id_ = 0 - - asset = get_object_or_none(Asset, id=id_) for k, v in asset_dict.items(): if k == 'cluster': v = get_object_or_none(Cluster, name=v) @@ -296,6 +289,7 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView): continue asset_dict[k] = v + asset = get_object_or_none(Asset, id=id_) if is_uuid(id_) else None if not asset: try: groups = asset_dict.pop('groups') diff --git a/apps/common/utils.py b/apps/common/utils.py index 2213a7b6c..236ae2e02 100644 --- a/apps/common/utils.py +++ b/apps/common/utils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # - +import re from collections import OrderedDict from six import string_types import base64 @@ -29,6 +29,7 @@ from django.utils import timezone from .compat import to_bytes, to_string SECRET_KEY = settings.SECRET_KEY +UUID_PATTERN = re.compile(r'[0-9a-zA-Z\-]{36}') def reverse(view_name, urlconf=None, args=None, kwargs=None, @@ -382,4 +383,11 @@ def get_short_uuid_str(): return str(uuid.uuid4()).split('-')[-1] +def is_uuid(s): + if UUID_PATTERN.match(s): + return True + else: + return False + + signer = Signer() diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 10fbcbe407ae975ffc8e3e9b537b2249255885e9..9ba70bf815549523f6ecd3866c46385842cac18c 100644 GIT binary patch delta 21 dcmX?kfbrx3#tmD2*j~