diff --git a/apps/assets/api.py b/apps/assets/api.py index dfea55741..317ed51c2 100644 --- a/apps/assets/api.py +++ b/apps/assets/api.py @@ -30,12 +30,13 @@ from . import serializers 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 +from .utils import LabelFilter logger = get_logger(__file__) -class AssetViewSet(CustomFilterMixin, BulkModelViewSet): +class AssetViewSet(CustomFilterMixin, LabelFilter, BulkModelViewSet): """ API endpoint that allows Asset to be viewed or edited. """ diff --git a/apps/assets/forms.py b/apps/assets/forms.py index 2653ca793..b3ee468c6 100644 --- a/apps/assets/forms.py +++ b/apps/assets/forms.py @@ -5,7 +5,6 @@ from django.utils.translation import gettext_lazy as _ from .models import Cluster, Asset, AssetGroup, AdminUser, SystemUser, Label from common.utils import validate_ssh_private_key, ssh_pubkey_gen, ssh_key_gen, get_logger - logger = get_logger(__file__) @@ -19,10 +18,18 @@ class AssetCreateForm(forms.ModelForm): ] widgets = { - 'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Select asset groups')}), - 'cluster': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select cluster')}), - 'admin_user': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select admin user')}), - 'labels': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select labels')}), + 'groups': forms.SelectMultiple(attrs={ + 'class': 'select2', 'data-placeholder': _('Select asset groups') + }), + 'cluster': forms.Select(attrs={ + 'class': 'select2', 'data-placeholder': _('Select cluster') + }), + 'admin_user': forms.Select(attrs={ + 'class': 'select2', 'data-placeholder': _('Select admin user') + }), + 'labels': forms.SelectMultiple(attrs={ + 'class': 'select2', 'data-placeholder': _('Select labels') + }), 'port': forms.TextInput(), } help_texts = { @@ -40,9 +47,13 @@ class AssetCreateForm(forms.ModelForm): raise forms.ValidationError(_("You need set a admin user if cluster not have")) return self.cleaned_data['admin_user'] - def save(self, commit=True): - print(self.cleaned_data) - return super().save(commit=commit) + def is_valid(self): + print(self.data) + result = super().is_valid() + if not result: + print(self.errors) + print(self.cleaned_data) + return result class AssetUpdateForm(forms.ModelForm): @@ -54,8 +65,19 @@ class AssetUpdateForm(forms.ModelForm): 'cabinet_pos', 'number', 'comment', 'admin_user', 'labels' ] widgets = { - 'groups': forms.SelectMultiple(attrs={'class': 'select2', 'data-placeholder': _('Select asset groups')}), - 'admin_user': forms.Select(attrs={'class': 'select2', 'data-placeholder': _("Default using cluster admin user")}) + 'groups': forms.SelectMultiple(attrs={ + 'class': 'select2', 'data-placeholder': _('Select asset groups') + }), + 'cluster': forms.Select(attrs={ + 'class': 'select2', 'data-placeholder': _('Select cluster') + }), + 'admin_user': forms.Select(attrs={ + 'class': 'select2', 'data-placeholder': _('Select admin user') + }), + 'labels': forms.SelectMultiple(attrs={ + 'class': 'select2', 'data-placeholder': _('Select labels') + }), + 'port': forms.TextInput(), } help_texts = { 'hostname': '* required', @@ -72,9 +94,9 @@ class AssetUpdateForm(forms.ModelForm): raise forms.ValidationError(_("You need set a admin user if cluster not have")) return self.cleaned_data['admin_user'] - def save(self, commit=True): - print(self.cleaned_data) - return super().save(commit=commit) + def is_valid(self): + print(self.data) + return super().is_valid() class AssetBulkUpdateForm(forms.ModelForm): diff --git a/apps/assets/templates/assets/asset_create.html b/apps/assets/templates/assets/asset_create.html index 8378d5f14..30cba19cb 100644 --- a/apps/assets/templates/assets/asset_create.html +++ b/apps/assets/templates/assets/asset_create.html @@ -32,25 +32,31 @@

{% trans 'Labels' %}

-
+
- {% for name, labels in form.labels.field.queryset|group_labels %} {% for label in labels %} {% if label in form.labels.initial %} - + {% else %} - + {% endif %} {% endfor %} {% endfor %} + {% if form.errors.labels %} + {% for e in form.errors.labels %} +
{{ e }}
+ {% endfor %} + {% endif %}
+

{% trans 'Other' %}

{% bootstrap_field form.comment layout="horizontal" %} @@ -67,11 +73,20 @@ {% endblock %} {% block custom_foot_js %} - + {% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/asset_list.html b/apps/assets/templates/assets/asset_list.html index 625fc030d..3d6a42e5e 100644 --- a/apps/assets/templates/assets/asset_list.html +++ b/apps/assets/templates/assets/asset_list.html @@ -23,6 +23,14 @@ {% block table_container %}
{% trans "Create asset" %}
+
+ + +
@@ -114,6 +122,20 @@ function initTable() { $(document).ready(function(){ initTable(); + $(".select2").select2(); +}) +.on('click', '.labels li', function () { + var val = $(this).text(); + {#var origin_val = $("#asset_list_table_filter input").val();#} + {#var new_val;#} + {#if (origin_val === "") {#} + {# new_val = val;#} + {# } else { #} + {# new_val = origin_val + " " + val;#} + {# } #} + $("#asset_list_table_filter input").val(val); + {#$('#asset_list_table').DataTable().search(val).draw();#} + jumpserver.table.search(val).draw(); }) .on('click', '.btn_export', function () { var $data_table = $('#asset_list_table').DataTable(); diff --git a/apps/assets/utils.py b/apps/assets/utils.py index ab63bbafc..67642be2e 100644 --- a/apps/assets/utils.py +++ b/apps/assets/utils.py @@ -1,8 +1,13 @@ # ~*~ coding: utf-8 ~*~ # from collections import defaultdict +from functools import reduce +import operator + +from django.db.models import Q + from common.utils import get_object_or_none -from .models import Asset, SystemUser +from .models import Asset, SystemUser, Label def get_assets_by_id_list(id_list): @@ -27,3 +32,23 @@ def check_assets_have_system_user(assets, system_users): if asset.cluster not in clusters: errors[asset].append(system_user) return errors + + +class LabelFilter: + def filter_queryset(self, queryset): + query_keys = self.request.query_params.keys() + all_label_keys = Label.objects.values_list('name', flat=True) + valid_keys = set(all_label_keys) & set(query_keys) + labels_query = {} + for key in valid_keys: + labels_query[key] = self.request.query_params.get(key) + + conditions = [] + for k, v in labels_query.items(): + query = {'labels__name': k, 'labels__value': v} + conditions.append(query) + + if conditions: + for kwargs in conditions: + queryset = queryset.filter(**kwargs) + return queryset diff --git a/apps/assets/views/asset.py b/apps/assets/views/asset.py index b2f57e323..c14b0c54f 100644 --- a/apps/assets/views/asset.py +++ b/apps/assets/views/asset.py @@ -27,7 +27,7 @@ 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 ..models import Asset, AssetGroup, AdminUser, Cluster, SystemUser, Label from ..hands import AdminUserRequiredMixin @@ -48,6 +48,7 @@ class AssetListView(AdminUserRequiredMixin, TemplateView): 'app': _('Assets'), 'action': _('Asset list'), 'system_users': SystemUser.objects.all(), + 'labels': Label.objects.all().order_by('name'), } kwargs.update(context) return super().get_context_data(**kwargs) @@ -72,12 +73,13 @@ class AssetCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView): template_name = 'assets/asset_create.html' success_url = reverse_lazy('assets:asset-list') - def form_valid(self, form): - asset = form.save() - asset.created_by = self.request.user.username or 'Admin' - asset.date_created = timezone.now() - asset.save() - return super().form_valid(form) + # def form_valid(self, form): + # print("form valid") + # asset = form.save() + # asset.created_by = self.request.user.username or 'Admin' + # asset.date_created = timezone.now() + # asset.save() + # return super().form_valid(form) def get_context_data(self, **kwargs): context = { diff --git a/apps/static/css/jumpserver.css b/apps/static/css/jumpserver.css index 999fe5810..2a3226796 100644 --- a/apps/static/css/jumpserver.css +++ b/apps/static/css/jumpserver.css @@ -338,4 +338,6 @@ div.dataTables_wrapper div.dataTables_filter { .nav.nav-tabs li.active a { border: none; -} \ No newline at end of file +} + + diff --git a/apps/static/js/jumpserver.js b/apps/static/js/jumpserver.js index aca70a5a0..8a0e97605 100644 --- a/apps/static/js/jumpserver.js +++ b/apps/static/js/jumpserver.js @@ -383,7 +383,22 @@ jumpserver.initServerSideDataTable = function (options) { } if (data.search !== null) { var search_val = data.search.value; - data.search = search_val; + var search_list = search_val.split(" "); + var search_attr = {}; + var search_raw = []; + + search_list.map(function (val, index) { + var kv = val.split(":"); + if (kv.length === 2) { + search_attr[kv[0]] = kv[1] + } else { + search_raw.push(kv) + } + }); + data.search = search_raw.join(""); + $.each(search_attr, function (k, v) { + data[k] = v + }) } if (data.order !== null && data.order.length === 1) { var col = data.order[0].column; @@ -446,6 +461,7 @@ jumpserver.initServerSideDataTable = function (options) { } }); + jumpserver.table = table; return table; };