Commit 5bbad019 authored by ibuler's avatar ibuler

[Feature] 增加标签

parent dad21cad
...@@ -17,15 +17,15 @@ from rest_framework import generics ...@@ -17,15 +17,15 @@ from rest_framework import generics
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework_bulk import BulkModelViewSet from rest_framework_bulk import BulkModelViewSet
from rest_framework_bulk import ListBulkCreateUpdateDestroyAPIView from rest_framework_bulk import ListBulkCreateUpdateDestroyAPIView
from django.shortcuts import get_object_or_404
from django.db.models import Q
from rest_framework.pagination import LimitOffsetPagination from rest_framework.pagination import LimitOffsetPagination
from django.shortcuts import get_object_or_404
from django.db.models import Q, Count
from common.mixins import CustomFilterMixin from common.mixins import CustomFilterMixin
from common.utils import get_logger from common.utils import get_logger
from .hands import IsSuperUser, IsValidUser, IsSuperUserOrAppUser, \ from .hands import IsSuperUser, IsValidUser, IsSuperUserOrAppUser, \
get_user_granted_assets get_user_granted_assets
from .models import AssetGroup, Asset, Cluster, SystemUser, AdminUser from .models import AssetGroup, Asset, Cluster, SystemUser, AdminUser, Label
from . import serializers from . import serializers
from .tasks import update_asset_hardware_info_manual, test_admin_user_connectability_manual, \ from .tasks import update_asset_hardware_info_manual, test_admin_user_connectability_manual, \
test_asset_connectability_manual, push_system_user_to_cluster_assets_manual, \ test_asset_connectability_manual, push_system_user_to_cluster_assets_manual, \
...@@ -295,3 +295,17 @@ class SystemUserTestConnectiveApi(generics.RetrieveAPIView): ...@@ -295,3 +295,17 @@ class SystemUserTestConnectiveApi(generics.RetrieveAPIView):
system_user = self.get_object() system_user = self.get_object()
test_system_user_connectability_manual.delay(system_user) test_system_user_connectability_manual.delay(system_user)
return Response({"msg": "Task created"}) return Response({"msg": "Task created"})
class LabelViewSet(BulkModelViewSet):
queryset = Label.objects.annotate(asset_count=Count("assets"))\
.annotate(admin_user_count=Count("adminuser")) \
.annotate(system_user_count=Count("systemuser"))
permission_classes = (IsSuperUser,)
serializer_class = serializers.LabelSerializer
def list(self, request, *args, **kwargs):
if request.query_params.get("distinct"):
self.serializer_class = serializers.LabelDistinctSerializer
self.queryset = self.queryset.values("name").distinct()
return super().list(request, *args, **kwargs)
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from .user import AdminUser, SystemUser from .user import AdminUser, SystemUser
from .label import Label
from .cluster import * from .cluster import *
from .group import * from .group import *
from .asset import * from .asset import *
......
...@@ -88,6 +88,8 @@ class Asset(models.Model): ...@@ -88,6 +88,8 @@ class Asset(models.Model):
os_arch = models.CharField(max_length=16, blank=True, null=True, verbose_name=_('OS arch')) os_arch = models.CharField(max_length=16, blank=True, null=True, verbose_name=_('OS arch'))
hostname_raw = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('Hostname raw')) hostname_raw = models.CharField(max_length=128, blank=True, null=True, verbose_name=_('Hostname raw'))
labels = models.ManyToManyField('assets.Label', blank=True, related_name='assets', verbose_name=_("Labels"))
created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by')) created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by'))
date_created = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date created')) date_created = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date created'))
comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment')) comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment'))
......
# -*- coding: utf-8 -*-
#
import uuid
from django.db import models
from django.utils.translation import ugettext_lazy as _
class Label(models.Model):
SYSTEM_CATEGORY = "S"
USER_CATEGORY = "U"
CATEGORY_CHOICES = (
("S", _("System")),
("U", _("User"))
)
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, verbose_name=_("Name"))
value = models.CharField(max_length=128, verbose_name=_("Value"))
category = models.CharField(max_length=128, choices=CATEGORY_CHOICES, verbose_name=_("Category"))
is_active = models.BooleanField(default=True, verbose_name=_("Is active"))
comment = models.TextField(blank=True, null=True, verbose_name=_("Comment"))
date_created = models.DateTimeField(
auto_now_add=True, null=True, blank=True, verbose_name=_('Date created')
)
def __str__(self):
return "{}:{}".format(self.name, self.value)
class Meta:
db_table = "assets_label"
...@@ -30,6 +30,7 @@ class AssetUser(models.Model): ...@@ -30,6 +30,7 @@ class AssetUser(models.Model):
_password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password')) _password = models.CharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
_private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ]) _private_key = models.TextField(max_length=4096, blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ])
_public_key = models.TextField(max_length=4096, blank=True, verbose_name=_('SSH public key')) _public_key = models.TextField(max_length=4096, blank=True, verbose_name=_('SSH public key'))
labels = models.ManyToManyField('assets.Label', blank=True, verbose_name=_("Labels"))
comment = models.TextField(blank=True, verbose_name=_('Comment')) comment = models.TextField(blank=True, verbose_name=_('Comment'))
date_created = models.DateTimeField(auto_now_add=True) date_created = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True) date_updated = models.DateTimeField(auto_now=True)
......
...@@ -4,7 +4,7 @@ from rest_framework import serializers ...@@ -4,7 +4,7 @@ from rest_framework import serializers
from rest_framework_bulk.serializers import BulkListSerializer from rest_framework_bulk.serializers import BulkListSerializer
from common.mixins import BulkSerializerMixin from common.mixins import BulkSerializerMixin
from .models import AssetGroup, Asset, Cluster, AdminUser, SystemUser from .models import AssetGroup, Asset, Cluster, AdminUser, SystemUser, Label
from .const import ADMIN_USER_CONN_CACHE_KEY, SYSTEM_USER_CONN_CACHE_KEY from .const import ADMIN_USER_CONN_CACHE_KEY, SYSTEM_USER_CONN_CACHE_KEY
...@@ -284,3 +284,44 @@ class MyAssetGroupGrantedSerializer(serializers.ModelSerializer): ...@@ -284,3 +284,44 @@ class MyAssetGroupGrantedSerializer(serializers.ModelSerializer):
@staticmethod @staticmethod
def get_assets_amount(obj): def get_assets_amount(obj):
return len(obj.assets_granted) return len(obj.assets_granted)
class LabelSerializer(serializers.ModelSerializer):
asset_count = serializers.SerializerMethodField()
admin_user_count = serializers.SerializerMethodField()
system_user_count = serializers.SerializerMethodField()
class Meta:
model = Label
fields = '__all__'
list_serializer_class = BulkListSerializer
@staticmethod
def get_asset_count(obj):
return obj.asset_count
@staticmethod
def get_admin_user_count(obj):
return obj.admin_user_count
@staticmethod
def get_system_user_count(obj):
return obj.system_user_count
def get_field_names(self, declared_fields, info):
fields = super().get_field_names(declared_fields, info)
fields.extend(['get_category_display'])
return fields
class LabelDistinctSerializer(serializers.ModelSerializer):
value = serializers.SerializerMethodField()
class Meta:
model = Label
fields = ("name", "value")
@staticmethod
def get_value(obj):
labels = Label.objects.filter(name=obj["name"])
return ', '.join([label.value for label in labels])
{% extends '_base_list.html' %}
{% load i18n static %}
{% block table_search %}{% endblock %}
{% block table_container %}
<div class="uc pull-left m-r-5">
<a href="" class="btn btn-sm btn-primary"> {% trans "Create label" %} </a>
</div>
<table class="table table-striped table-bordered table-hover " id="label_list_table" >
<thead>
<tr>
<th class="text-center">
<input type="checkbox" id="check_all" class="ipt_check_all" >
</th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'Value' %}</th>
<th class="text-center">{% trans 'Asset' %}</th>
<th class="text-center">{% trans 'Admin user' %}</th>
<th class="text-center">{% trans 'System user' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
{% endblock %}
{% block content_bottom_left %}{% endblock %}
{% block custom_foot_js %}
<script>
function initTable() {
var options = {
ele: $('#label_list_table'),
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
{# var detail_btn = '<a href="{% url "assets:label-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';#}
var detail_btn = '<a>' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}},
{targets: 6, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "assets:cluster-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_cluster_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
$(td).html(update_btn + del_btn)
}}],
ajax_url: '{% url "api-assets:label-list" %}?sort=name',
columns: [
{data: "id"}, {data: "name" }, {data: "value" },
{data: "asset_count" }, {data: "admin_user_count" },
{data: "system_user_count" }, {data: "id"}
],
op_html: $('#actions').html()
};
jumpserver.initDataTable(options);
}
$(document).ready(function(){
initTable();
})
.on('click', '.btn_cluster_delete', function () {
var $this = $(this);
var $data_table = $('#cluster_list_table').DataTable();
var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
var uid = $this.data('uid');
var the_url = '{% url "api-assets:cluster-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
objectDelete($this, name, the_url);
setTimeout( function () {
$data_table.ajax.reload();
}, 3000);
});
</script>
{% endblock %}
...@@ -12,6 +12,7 @@ router.register(r'v1/assets', api.AssetViewSet, 'asset') ...@@ -12,6 +12,7 @@ router.register(r'v1/assets', api.AssetViewSet, 'asset')
router.register(r'v1/clusters', api.ClusterViewSet, 'cluster') router.register(r'v1/clusters', api.ClusterViewSet, 'cluster')
router.register(r'v1/admin-user', api.AdminUserViewSet, 'admin-user') router.register(r'v1/admin-user', api.AdminUserViewSet, 'admin-user')
router.register(r'v1/system-user', api.SystemUserViewSet, 'system-user') router.register(r'v1/system-user', api.SystemUserViewSet, 'system-user')
router.register(r'v1/labels', api.LabelViewSet, 'label')
urlpatterns = [ urlpatterns = [
url(r'^v1/assets-bulk/$', api.AssetListUpdateApi.as_view(), name='asset-bulk-update'), url(r'^v1/assets-bulk/$', api.AssetListUpdateApi.as_view(), name='asset-bulk-update'),
......
...@@ -53,5 +53,6 @@ urlpatterns = [ ...@@ -53,5 +53,6 @@ urlpatterns = [
# url(r'^system-user/(?P<pk>[0-9a-zA-Z\-]{36})/asset-group$', views.SystemUserAssetGroupView.as_view(), # url(r'^system-user/(?P<pk>[0-9a-zA-Z\-]{36})/asset-group$', views.SystemUserAssetGroupView.as_view(),
# name='system-user-asset-group'), # name='system-user-asset-group'),
url(r'^label/$', views.LabelListView.as_view(), name='label-list'),
] ]
...@@ -4,4 +4,5 @@ from .group import * ...@@ -4,4 +4,5 @@ from .group import *
from .cluster import * from .cluster import *
from .system_user import * from .system_user import *
from .admin_user import * from .admin_user import *
from .label import *
# -*- coding: utf-8 -*-
#
from django.views.generic import ListView, TemplateView, CreateView, \
UpdateView, DeleteView, DetailView
from django.utils.translation import ugettext_lazy as _
from common.mixins import AdminUserRequiredMixin
__all__ = (
"LabelListView", "LabelCreateView", "LabelUpdateView",
"LabelDetailView", "LabelDeleteView",
)
class LabelListView(AdminUserRequiredMixin, TemplateView):
template_name = 'assets/label_list.html'
def get_context_data(self, **kwargs):
context = {
'app': _('Assets'),
'action': _('Label list'),
}
kwargs.update(context)
return super().get_context_data(**kwargs)
class LabelCreateView(AdminUserRequiredMixin, CreateView):
pass
class LabelUpdateView(AdminUserRequiredMixin, UpdateView):
pass
class LabelDetailView(AdminUserRequiredMixin, DetailView):
pass
class LabelDeleteView(AdminUserRequiredMixin, DeleteView):
pass
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
<li id="cluster"><a href="{% url 'assets:cluster-list' %}">{% trans 'Cluster' %}</a></li> <li id="cluster"><a href="{% url 'assets:cluster-list' %}">{% trans 'Cluster' %}</a></li>
<li id="admin-user"><a href="{% url 'assets:admin-user-list' %}">{% trans 'Admin user' %}</a></li> <li id="admin-user"><a href="{% url 'assets:admin-user-list' %}">{% trans 'Admin user' %}</a></li>
<li id="system-user"><a href="{% url 'assets:system-user-list' %}">{% trans 'System user' %}</a></li> <li id="system-user"><a href="{% url 'assets:system-user-list' %}">{% trans 'System user' %}</a></li>
<li id="system-user"><a href="{% url 'assets:label-list' %}">{% trans 'Label' %}</a></li>
</ul> </ul>
</li> </li>
<li id="perms"> <li id="perms">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment