diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py index 3b61ceb51..d7499760a 100644 --- a/apps/assets/api/node.py +++ b/apps/assets/api/node.py @@ -30,6 +30,7 @@ from .. import serializers logger = get_logger(__file__) __all__ = [ 'NodeViewSet', 'NodeChildrenApi', + 'NodeAssetsApi', 'NodeWithAssetsApi', 'NodeAddAssetsApi', 'NodeRemoveAssetsApi', 'NodeAddChildrenApi', 'RefreshNodeHardwareInfoApi', 'TestNodeConnectiveApi' @@ -47,6 +48,34 @@ class NodeViewSet(BulkModelViewSet): serializer.save() +class NodeWithAssetsApi(generics.ListAPIView): + permission_classes = (IsSuperUser,) + serializers = serializers.NodeSerializer + + def get_node(self): + pk = self.kwargs.get('pk') or self.request.query_params.get('node') + if not pk: + node = Node.root() + else: + node = get_object_or_404(Node, pk) + return node + + def get_queryset(self): + queryset = [] + node = self.get_node() + children = node.get_children() + assets = node.get_assets() + queryset.extend(list(children)) + + for asset in assets: + node = Node() + node.id = asset.id + node.parent = node.id + node.value = asset.hostname + queryset.append(node) + return queryset + + class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView): queryset = Node.objects.all() permission_classes = (IsSuperUser,) @@ -69,14 +98,54 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView): status=201, ) - def get(self, request, *args, **kwargs): - instance = self.get_object() - if self.request.query_params.get("all"): - children = instance.get_all_children() + def get_object(self): + pk = self.kwargs.get('pk') or self.request.query_params.get('id') + if not pk: + node = Node.root() else: - children = instance.get_children() - response = [{"id": node.id, "key": node.key, "value": node.value} for node in children] - return Response(response, status=200) + node = get_object_or_404(Node, pk=pk) + return node + + def get_queryset(self): + queryset = [] + query_all = self.request.query_params.get("all") + query_assets = self.request.query_params.get('assets') + node = self.get_object() + if node == Node.root(): + queryset.append(node) + if query_all: + children = node.get_all_children() + else: + children = node.get_children() + + queryset.extend(list(children)) + if query_assets: + assets = node.get_assets() + for asset in assets: + node_fake = Node() + node_fake.id = asset.id + node_fake.parent = node + node_fake.value = asset.hostname + node_fake.is_asset = True + queryset.append(node_fake) + return queryset + + def get(self, request, *args, **kwargs): + return super().list(request, *args, **kwargs) + + +class NodeAssetsApi(generics.ListAPIView): + permission_classes = (IsSuperUser,) + serializer_class = serializers.AssetSerializer + + def get_queryset(self): + node_id = self.kwargs.get('pk') + query_all = self.request.query_params.get('all') + instance = get_object_or_404(Node, pk=node_id) + if query_all: + return instance.get_all_assets() + else: + return instance.get_assets() class NodeAddChildrenApi(generics.UpdateAPIView): @@ -146,4 +215,3 @@ class TestNodeConnectiveApi(APIView): task_name = _("测试节点下资产是否可连接: {}".format(node.name)) task = test_asset_connectability_util.delay(assets, task_name=task_name) return Response({"task": task.id}) - diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py index 5ce195783..99236f781 100644 --- a/apps/assets/models/node.py +++ b/apps/assets/models/node.py @@ -16,6 +16,8 @@ class Node(models.Model): child_mark = models.IntegerField(default=0) date_create = models.DateTimeField(auto_now_add=True) + is_asset = False + def __str__(self): return self.value @@ -73,6 +75,9 @@ class Node(models.Model): assets = Asset.objects.filter(nodes__in=nodes) return assets + def has_assets(self): + return self.get_all_assets() + def get_all_active_assets(self): return self.get_all_assets().filter(is_active=True) diff --git a/apps/assets/models/user.py b/apps/assets/models/user.py index 2326f1c46..e0de2cf49 100644 --- a/apps/assets/models/user.py +++ b/apps/assets/models/user.py @@ -123,8 +123,6 @@ class SystemUser(AssetUser): def get_assets(self): assets = set(self.assets.all()) - for node in self.nodes.all(): - assets.update(set(node.get_all_assets())) return assets @property diff --git a/apps/assets/serializers/node.py b/apps/assets/serializers/node.py index f6654aef9..736b06c7e 100644 --- a/apps/assets/serializers/node.py +++ b/apps/assets/serializers/node.py @@ -42,7 +42,7 @@ class NodeSerializer(serializers.ModelSerializer): class Meta: model = Node - fields = ['id', 'key', 'value', 'parent', 'assets_amount'] + fields = ['id', 'key', 'value', 'parent', 'assets_amount', 'is_asset'] list_serializer_class = BulkListSerializer @staticmethod diff --git a/apps/assets/tasks.py b/apps/assets/tasks.py index b51798e3d..381e1a4cf 100644 --- a/apps/assets/tasks.py +++ b/apps/assets/tasks.py @@ -276,7 +276,7 @@ def test_system_user_connectability_util(system_user, task_name): :return: """ from ops.utils import update_or_create_ansible_task - assets = system_user.assets + assets = system_user.get_assets() hosts = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()] tasks = const.TEST_SYSTEM_USER_CONN_TASKS if not hosts: diff --git a/apps/assets/urls/api_urls.py b/apps/assets/urls/api_urls.py index d5c275ddd..c4925059a 100644 --- a/apps/assets/urls/api_urls.py +++ b/apps/assets/urls/api_urls.py @@ -36,7 +36,9 @@ urlpatterns = [ url(r'^v1/system-user/(?P[0-9a-zA-Z\-]{36})/connective/$', api.SystemUserTestConnectiveApi.as_view(), name='system-user-connective'), url(r'^v1/nodes/(?P[0-9a-zA-Z\-]{36})/children/$', api.NodeChildrenApi.as_view(), name='node-children'), + url(r'^v1/nodes/children/$', api.NodeChildrenApi.as_view(), name='node-children-2'), url(r'^v1/nodes/(?P[0-9a-zA-Z\-]{36})/children/add/$', api.NodeAddChildrenApi.as_view(), name='node-add-children'), + url(r'^v1/nodes/(?P[0-9a-zA-Z\-]{36})/assets/$', api.NodeAssetsApi.as_view(), name='node-assets'), url(r'^v1/nodes/(?P[0-9a-zA-Z\-]{36})/assets/add/$', api.NodeAddAssetsApi.as_view(), name='node-add-assets'), url(r'^v1/nodes/(?P[0-9a-zA-Z\-]{36})/assets/remove/$', api.NodeRemoveAssetsApi.as_view(), name='node-remove-assets'), url(r'^v1/nodes/(?P[0-9a-zA-Z\-]{36})/refresh-hardware-info/$', api.RefreshNodeHardwareInfoApi.as_view(), name='node-refresh-hardware-info'), diff --git a/apps/common/fields.py b/apps/common/fields.py index e4645b683..a06106cfa 100644 --- a/apps/common/fields.py +++ b/apps/common/fields.py @@ -43,3 +43,7 @@ class StringIDField(serializers.Field): def to_representation(self, value): return {"pk": value.pk, "name": value.__str__()} + +class StringManyToManyField(serializers.RelatedField): + def to_representation(self, value): + return value.__str__() \ No newline at end of file diff --git a/apps/perms/api.py b/apps/perms/api.py index 0ec3a7980..148d366db 100644 --- a/apps/perms/api.py +++ b/apps/perms/api.py @@ -6,6 +6,7 @@ from rest_framework.views import APIView, Response from rest_framework.generics import ListAPIView, get_object_or_404 from rest_framework import viewsets +from common.utils import set_or_append_attr_bulk from users.permissions import IsValidUser, IsSuperUser, IsSuperUserOrAppUser from .utils import AssetPermissionUtil from .models import AssetPermission @@ -27,6 +28,31 @@ class AssetPermissionViewSet(viewsets.ModelViewSet): return serializers.AssetPermissionListSerializer return self.serializer_class + def get_queryset(self): + queryset = super().get_queryset() + asset_id = self.request.query_params.get('asset') + node_id = self.request.query_params.get('node') + inherit_nodes = set() + if not asset_id and not node_id: + return queryset + + permissions = set() + if asset_id: + asset = get_object_or_404(Asset, pk=asset_id) + permissions = set(queryset.filter(assets=asset)) + for node in asset.nodes.all(): + inherit_nodes.update(set(node.ancestor_with_node)) + elif node_id: + node = get_object_or_404(Node, pk=node_id) + permissions = set(queryset.filter(nodes=node)) + inherit_nodes = node.ancestor + + for n in inherit_nodes: + _permissions = queryset.filter(nodes=n) + set_or_append_attr_bulk(_permissions, "inherit", n.value) + permissions.update(_permissions) + return permissions + class UserGrantedAssetsApi(ListAPIView): """ diff --git a/apps/perms/forms.py b/apps/perms/forms.py index 3756fb797..060812d4a 100644 --- a/apps/perms/forms.py +++ b/apps/perms/forms.py @@ -33,3 +33,22 @@ class AssetPermissionForm(forms.ModelForm): labels = { 'nodes': _("Node"), } + + 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"] diff --git a/apps/perms/models.py b/apps/perms/models.py index 8263b1174..6609cd8e2 100644 --- a/apps/perms/models.py +++ b/apps/perms/models.py @@ -31,7 +31,6 @@ class AssetPermission(models.Model): objects = models.Manager() valid = ValidManager() - inherit_from = None def __str__(self): return self.name @@ -46,78 +45,6 @@ class AssetPermission(models.Model): return True return False - def get_granted_users(self): - return list(set(self.users.all()) | self.get_granted_user_groups_member()) - - def get_granted_user_groups_member(self): - users = set() - for user_group in self.user_groups.all(): - for user in user_group.users.all(): - setattr(user, 'is_inherit_from_user_groups', True) - setattr(user, 'inherit_from_user_groups', - getattr(user, 'inherit_from_user_groups', set()).add(user_group)) - users.add(user) - return users - - def get_granted_assets(self): - return list(set(self.assets.all()) | self.get_granted_asset_groups_member()) - - def get_granted_asset_groups_member(self): - assets = set() - for asset_group in self.asset_groups.all(): - for asset in asset_group.assets.all(): - setattr(asset, 'is_inherit_from_asset_groups', True) - setattr(asset, 'inherit_from_asset_groups', - getattr(asset, 'inherit_from_user_groups', set()).add(asset_group)) - assets.add(asset) - return assets - - def check_system_user_in_assets(self): - errors = {} - assets = self.get_granted_assets() - clusters = set([asset.cluster for asset in assets]) - for system_user in self.system_users.all(): - cluster_remain = clusters - set(system_user.cluster.all()) - if cluster_remain: - errors[system_user] = cluster_remain - return errors - - @property - def users_detail(self): - return " ".join([u.name for u in self.users.all()]) - - @property - def user_groups_detail(self): - return " ".join([g.name for g in self.user_groups.all()]) - - @property - def assets_detail(self): - return " ".join([a.hostname for a in self.assets.all()]) - - @property - def nodes_detail(self): - return " ".join([g.value for g in self.nodes.all()]) - - @property - def system_users_detail(self): - return " ".join([s.name for s in self.system_users.all()]) - - @property - def detail(self): - data = "" - if self.users.all(): - comment = _("User") - users = "{}: ".format(comment) - for u in self.users.all(): - users += u.name + " " - data += users + "
" - if self.assets.all(): - assets = _("Assets: ") - for a in self.assets.all(): - assets += a.hostname + " " - data += assets + "
" - return data - class NodePermission(models.Model): id = models.UUIDField(default=uuid.uuid4, primary_key=True) diff --git a/apps/perms/serializers.py b/apps/perms/serializers.py index 22306cad2..baa823a6f 100644 --- a/apps/perms/serializers.py +++ b/apps/perms/serializers.py @@ -3,19 +3,34 @@ from rest_framework import serializers from .models import AssetPermission +from common.fields import StringManyToManyField class AssetPermissionCreateUpdateSerializer(serializers.ModelSerializer): class Meta: model = AssetPermission - exclude = ('id', 'create_by', 'date_created') + exclude = ('id', 'created_by', 'date_created') class AssetPermissionListSerializer(serializers.ModelSerializer): + users = StringManyToManyField(many=True, read_only=True) + user_groups = StringManyToManyField(many=True, read_only=True) + assets = StringManyToManyField(many=True, read_only=True) + nodes = StringManyToManyField(many=True, read_only=True) + system_users = StringManyToManyField(many=True, read_only=True) + inherit = serializers.SerializerMethodField() + class Meta: model = AssetPermission fields = '__all__' + @staticmethod + def get_inherit(obj): + if hasattr(obj, 'inherit'): + return obj.inherit + else: + return None + class AssetPermissionUpdateUserSerializer(serializers.ModelSerializer): diff --git a/apps/perms/templates/perms/asset_permission_list.html b/apps/perms/templates/perms/asset_permission_list.html index 6980ba838..eccef77a2 100644 --- a/apps/perms/templates/perms/asset_permission_list.html +++ b/apps/perms/templates/perms/asset_permission_list.html @@ -1,163 +1,324 @@ -{% extends '_base_list.html' %} -{% load i18n %} +{% extends 'base.html' %} {% load static %} -{% load common_tags %} +{% load i18n %} + {% block custom_head_css_js %} + + + {% endblock %} -{% block content_left_head %} - -{% endblock %} - -{% block table_search %} - -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
- -
-
-
-{% endblock %} -{% block table_container %} - - - - - - - - - - - - - - - - - - - - - {% for object in object_list %} - - - - - - - - - - - - - - - - - {% endfor %} - -
ID{% trans 'Name' %}{% trans 'User' %}{% trans 'User group' %}{% trans 'Asset' %}{% trans 'Node'%}{% trans 'System user' %}{% trans 'Active' %}{% trans 'Action' %}{% trans 'User' %}{% trans 'User group' %}{% trans 'Asset' %}{% trans 'Node' %}{% trans 'System user' %}
{{ forloop.counter }}{{ object.name }}{{ object.users.count }}{{ object.user_groups.count }}{{ object.assets.count }}{{ object.nodes.count }}{{ object.system_users.count }} - {% if object.is_valid %} - - {% else %} - - {% endif %} - - {% trans "Update" %} - {% trans "Delete" %} - {{ object.users_detail }}{{ object.user_groups_detail }}{{ object.assets_detail }}{{ object.nodes_detail }}{{ object.system_users_detail }}
+{% block content %} +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ + + + + + + + + + + + + + + + + +
{% trans 'Name' %}{% trans 'User' %}{% trans 'User group' %}{% trans 'Asset' %}{% trans 'Node'%}{% trans 'System user' %}{% trans 'Active' %}{% trans 'Action' %}
+
+
+
+
{% endblock %} {% block custom_foot_js %} {% endblock %} - - diff --git a/apps/perms/urls/views_urls.py b/apps/perms/urls/views_urls.py index a4a6e49a5..a1acc570c 100644 --- a/apps/perms/urls/views_urls.py +++ b/apps/perms/urls/views_urls.py @@ -9,7 +9,7 @@ urlpatterns = [ url(r'^asset-permission$', views.AssetPermissionListView.as_view(), name='asset-permission-list'), url(r'^asset-permission/create$', views.AssetPermissionCreateView.as_view(), name='asset-permission-create'), url(r'^asset-permission/(?P[0-9a-zA-Z\-]{36})/update$', views.AssetPermissionUpdateView.as_view(), name='asset-permission-update'), - # url(r'^asset-permission/(?P[0-9a-zA-Z\-]{36})$', views.AssetPermissionDetailView.as_view(),name='asset-permission-detail'), + url(r'^asset-permission/(?P[0-9a-zA-Z\-]{36})$', views.AssetPermissionDetailView.as_view(),name='asset-permission-detail'), url(r'^asset-permission/(?P[0-9a-zA-Z\-]{36})/delete$', views.AssetPermissionDeleteView.as_view(), name='asset-permission-delete'), # url(r'^asset-permission/(?P[0-9a-zA-Z\-]{36})/user$', views.AssetPermissionUserView.as_view(), name='asset-permission-user-list'), # url(r'^asset-permission/(?P[0-9a-zA-Z\-]{36})/asset$', views.AssetPermissionAssetView.as_view(), name='asset-permission-asset-list'), diff --git a/apps/perms/views.py b/apps/perms/views.py index 01d621ce4..11d8112e0 100644 --- a/apps/perms/views.py +++ b/apps/perms/views.py @@ -3,14 +3,14 @@ from __future__ import unicode_literals, absolute_import from django.utils.translation import ugettext as _ -from django.views.generic import ListView, CreateView, UpdateView +from django.views.generic import ListView, CreateView, UpdateView, DetailView from django.views.generic.edit import DeleteView from django.urls import reverse_lazy from django.conf import settings -from django.db.models import Q -from .hands import AdminUserRequiredMixin, Node, User, UserGroup, Asset, SystemUser -from .models import AssetPermission, NodePermission +from common.utils import get_object_or_none +from .hands import AdminUserRequiredMixin, Node, Asset +from .models import AssetPermission from .forms import AssetPermissionForm @@ -20,51 +20,9 @@ class AssetPermissionListView(AdminUserRequiredMixin, ListView): paginate_by = settings.DISPLAY_PER_PAGE user = user_group = asset = node = system_user = q = "" - def get_queryset(self): - self.q = self.request.GET.get('q', '') - self.user = self.request.GET.get("user", '') - self.user_group = self.request.GET.get("user_group", '') - self.asset = self.request.GET.get('asset', '') - self.node = self.request.GET.get('node', '') - self.system_user = self.request.GET.get('system_user', '') - filter_kwargs = dict() - if self.user: - filter_kwargs['users__name'] = self.user - if self.user_group: - filter_kwargs['user_groups__name'] = self.user_group - if self.asset: - filter_kwargs['assets__hostname'] = self.asset - if self.node: - filter_kwargs['nodes__value'] = self.node - if self.system_user: - filter_kwargs['system_users__name'] = self.system_user - queryset = self.model.objects.filter(**filter_kwargs) - if self.q: - queryset = queryset.filter( - Q(name__contains=self.q) | - Q(users__name=self.q) | - Q(user_groups__name=self.q) | - Q(assets__hostname=self.q) | - Q(nodes__value=self.q) | - Q(system_users__name=self.q) - ) - queryset = queryset.order_by('-date_start') - return queryset - def get_context_data(self, **kwargs): context = { 'app': _('Perms'), - 'user_list': User.objects.all().values_list('name', flat=True), - 'user_group_list': UserGroup.objects.all().values_list('name', flat=True), - 'asset_list': Asset.objects.all().values_list('hostname', flat=True), - 'node_list': Node.objects.all().values_list('value', flat=True), - 'system_user_list': SystemUser.objects.all().values_list('name', flat=True), - 'user': self.user, - 'user_group': self.user_group, - 'asset': self.asset, - 'node': self.node, - 'system_user': self.system_user, - 'q': self.q, 'action': _('Asset permission list'), } kwargs.update(context) @@ -77,6 +35,19 @@ class AssetPermissionCreateView(AdminUserRequiredMixin, CreateView): template_name = 'perms/asset_permission_create_update.html' success_url = reverse_lazy('perms:asset-permission-list') + def get_form(self, form_class=None): + form = super().get_form(form_class=form_class) + nodes_id = self.request.GET.get("nodes").split(",") + assets_id = self.request.GET.get("assets").split(",") + + if nodes_id: + nodes = Node.objects.filter(id__in=nodes_id) + form['nodes'].initial = nodes + if assets_id: + assets = Asset.objects.filter(id__in=assets_id) + form['assets'].initial = assets + return form + def get_context_data(self, **kwargs): context = { 'app': _('Perms'), @@ -101,6 +72,21 @@ class AssetPermissionUpdateView(AdminUserRequiredMixin, UpdateView): return super().get_context_data(**kwargs) +class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView): + model = AssetPermission + form_class = AssetPermissionForm + template_name = 'perms/asset_permission_detail.html' + success_url = reverse_lazy("perms:asset-permission-list") + + def get_context_data(self, **kwargs): + context = { + 'app': _('Perms'), + 'action': _('Update asset permission') + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + class AssetPermissionDeleteView(AdminUserRequiredMixin, DeleteView): model = AssetPermission template_name = 'delete_confirm.html' diff --git a/apps/static/css/plugins/ztree/awesomeStyle/awesome.css b/apps/static/css/plugins/ztree/awesomeStyle/awesome.css index 773e687ef..045c810ea 100644 --- a/apps/static/css/plugins/ztree/awesomeStyle/awesome.css +++ b/apps/static/css/plugins/ztree/awesomeStyle/awesome.css @@ -212,49 +212,49 @@ website: http://code.google.com/p/jquerytree/ height: 20px; } .ztree li span.button.root_open::before { - content: "\f078"; + content: "\f107"; padding-top: 10px; padding-left: 2px; display: inline-block; } .ztree li span.button.root_close::before { - content: "\f054"; + content: "\f105"; padding-top: 10px; padding-left: 2px; display: inline-block; } .ztree li span.button.roots_open::before { - content: "\f078"; + content: "\f107"; padding-top: 10px; padding-left: 2px; display: inline-block; } .ztree li span.button.roots_close::before { - content: "\f054"; + content: "\f105"; padding-top: 10px; padding-left: 2px; display: inline-block; } .ztree li span.button.center_open::before { - content: "\f078"; + content: "\f107"; padding-top: 10px; padding-left: 2px; display: inline-block; } .ztree li span.button.center_close::before { - content: "\f054"; + content: "\f105"; padding-top: 10px; padding-left: 2px; display: inline-block; } .ztree li span.button.bottom_open::before { - content: "\f078"; + content: "\f107"; padding-top: 10px; padding-left: 2px; display: inline-block; } .ztree li span.button.bottom_close::before { - content: "\f054"; + content: "\f105"; padding-top: 10px; padding-left: 2px; display: inline-block; @@ -300,7 +300,31 @@ website: http://code.google.com/p/jquerytree/ color: #676a6c; } .ztree li span.button.ico_docu::before { - content: "\f114"; + content: "\f07b"; + font-family: FontAwesome; + padding-top: 10px; + padding-left: 2px; + display: inline-block; + color: #676a6c; +} +.ztree li span.button.file_ico_docu::before { + content: "\f022"; + font-family: FontAwesome; + padding-top: 10px; + padding-left: 2px; + display: inline-block; + color: #676a6c; +} +.ztree li span.button.linux_ico_docu::before { + content: "\f17c"; + font-family: FontAwesome; + padding-top: 10px; + padding-left: 2px; + display: inline-block; + color: #676a6c; +} +.ztree li span.button.windows_ico_docu::before { + content: "\f17a"; font-family: FontAwesome; padding-top: 10px; padding-left: 2px; diff --git a/apps/static/css/plugins/ztree/awesomeStyle/awesome.less b/apps/static/css/plugins/ztree/awesomeStyle/awesome.less index 7fe7d4d77..3d1610279 100644 --- a/apps/static/css/plugins/ztree/awesomeStyle/awesome.less +++ b/apps/static/css/plugins/ztree/awesomeStyle/awesome.less @@ -39,11 +39,11 @@ website: http://code.google.com/p/jquerytree/ margin:0; padding:5px; color:@color-normal; background-color: @color-bg; li { padding:0; margin:0; list-style:none; line-height:17px; text-align:left; white-space:nowrap; outline:0; - ul { + ul { margin: 0px; padding:0 0 0 18px; } ul.line { } - a {padding-right:3px; margin:0; cursor:pointer; height:@h; color:@color-normal; background-color: transparent; + a {padding-right:3px; margin:0; cursor:pointer; height:@h; color:@color-normal; background-color: transparent; text-decoration:none; vertical-align:top; display: inline-block; input.rename {height:14px; width:80px; padding:0; margin:0; color: @color-bg; background-color: @color-normal; @@ -64,11 +64,11 @@ website: http://code.google.com/p/jquerytree/ span.button {line-height:0; margin:0; padding: 0; width:@w; height:@h; display: inline-block; vertical-align:top; border:0px solid; cursor: pointer;outline:none; background-color:transparent; background-repeat:no-repeat; background-attachment: scroll; - + &::before{color: @color-normal; font-family: FontAwesome; padding-top:@pad-top;} &.chk { margin:0px; cursor: auto; width: 12px; display: inline-block;padding-top:@pad-top;padding-left:@pad-left; - + &.checkbox_false_full::before {content: @fa-square-o;} &.checkbox_false_full_focus::before {content: @fa-square-o; color:@color-highlight;} &.checkbox_false_part::before {content: @fa-square-o;color: @color-partial;} @@ -82,7 +82,7 @@ website: http://code.google.com/p/jquerytree/ &.checkbox_true_part::before {content: @fa-check-square-o;color: @color-partial} &.checkbox_true_part_focus::before {content: @fa-check-square-o;color: @color-partfocus;} &.checkbox_true_disable::before {content: @fa-check-square-o;color: @color-disabled} - + &.radio_false_full::before {content: @fa-circle-o;} &.radio_false_full_focus::before {content: @fa-circle-o;color: @color-highlight} &.radio_false_part::before {content: @fa-circle-o;color: @color-partial} @@ -93,17 +93,17 @@ website: http://code.google.com/p/jquerytree/ &.radio_true_part::before {content: @fa-dot-circle-o;color: @color-partial} &.radio_true_part_focus::before {content: @fa-dot-circle-o;color: @color-partial;} &.radio_true_disable::before {content: @fa-circle-thin;color: @color-disabled} - + } &.switch {width:@w; height:@h} - &.root_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} - &.root_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} - &.roots_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} - &.roots_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} - &.center_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} - &.center_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} - &.bottom_open::before{content: @fa-chevron-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} - &.bottom_close::before{content: @fa-chevron-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} + &.root_open::before{content: @fa-angle-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} + &.root_close::before{content: @fa-angle-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} + &.roots_open::before{content: @fa-angle-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} + &.roots_close::before{content: @fa-angle-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} + &.center_open::before{content: @fa-angle-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} + &.center_close::before{content: @fa-angle-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} + &.bottom_open::before{content: @fa-angle-down;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} + &.bottom_close::before{content: @fa-angle-right;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;} &.noline_open{} &.noline_close{} &.root_docu{ background:none;} @@ -111,11 +111,15 @@ website: http://code.google.com/p/jquerytree/ &.center_docu::before{padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} &.bottom_docu::before{padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} &.noline_docu{ background:none;} - + &.ico_open::before {content: @fa-folder-open;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} &.ico_close::before {content: @fa-folder;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} - &.ico_docu::before{content: @fa-folder-o;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} - + &.ico_docu::before{content: @fa-folder;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} + + &.file_ico_docu::before{content: @fa-list-alt;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} + &.linux_ico_docu::before{content: @fa-linux;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} + &.windows_ico_docu::before{content: @fa-windows;font-family: FontAwesome;padding-top:@pad-top;padding-left:@pad-left;display: inline-block;color:@color-normal;} + &.edit {margin-left:4px; margin-right: -1px; vertical-align:top; *vertical-align:middle;padding-top:@pad-top;} &.edit::before{content: @fa-pencil-square-o;font-family: FontAwesome;} diff --git a/apps/static/js/jumpserver.js b/apps/static/js/jumpserver.js index 1083f3520..f2f8b8f55 100644 --- a/apps/static/js/jumpserver.js +++ b/apps/static/js/jumpserver.js @@ -62,7 +62,6 @@ function GetTableDataBox() { } } for (i in id_list) { - console.log(tabProduct); tableData.push(GetRowData(tabProduct.rows[id_list[i]])); } @@ -240,6 +239,13 @@ $.fn.serializeObject = function() }); return o; }; + +function makeLabel(data) { + return "" + data[1] + "
" +} + + + var jumpserver = {}; jumpserver.checked = false; jumpserver.selected = {}; @@ -281,7 +287,7 @@ jumpserver.initDataTable = function (options) { buttons: [], columnDefs: columnDefs, ajax: { - url: options.ajax_url , + url: options.ajax_url, dataSrc: "" }, columns: options.columns || [], diff --git a/apps/users/views/login.py b/apps/users/views/login.py index 0b70238c0..21c63f889 100644 --- a/apps/users/views/login.py +++ b/apps/users/views/login.py @@ -2,7 +2,6 @@ from __future__ import unicode_literals import os -from django import forms from django.shortcuts import render from django.contrib.auth import login as auth_login, logout as auth_logout from django.contrib.auth.mixins import LoginRequiredMixin @@ -20,10 +19,9 @@ from django.views.generic.base import TemplateView from django.views.generic.edit import FormView from formtools.wizard.views import SessionWizardView from django.conf import settings -from django.utils import timezone from common.utils import get_object_or_none -from common.mixins import DatetimeSearchMixin +from common.mixins import DatetimeSearchMixin, AdminUserRequiredMixin from ..models import User, LoginLog from ..utils import send_reset_password_mail from ..tasks import write_login_log_async @@ -228,7 +226,7 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView): return form -class LoginLogListView(DatetimeSearchMixin, ListView): +class LoginLogListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView): template_name = 'users/login_log_list.html' model = LoginLog paginate_by = settings.DISPLAY_PER_PAGE