mirror of https://github.com/jumpserver/jumpserver
[Update] 修改Permr认证
parent
fffa0def9e
commit
84634eb8c0
|
@ -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})
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -36,7 +36,9 @@ urlpatterns = [
|
|||
url(r'^v1/system-user/(?P<pk>[0-9a-zA-Z\-]{36})/connective/$',
|
||||
api.SystemUserTestConnectiveApi.as_view(), name='system-user-connective'),
|
||||
url(r'^v1/nodes/(?P<pk>[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<pk>[0-9a-zA-Z\-]{36})/children/add/$', api.NodeAddChildrenApi.as_view(), name='node-add-children'),
|
||||
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$', api.NodeAssetsApi.as_view(), name='node-assets'),
|
||||
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/add/$', api.NodeAddAssetsApi.as_view(), name='node-add-assets'),
|
||||
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/remove/$', api.NodeRemoveAssetsApi.as_view(), name='node-remove-assets'),
|
||||
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/refresh-hardware-info/$', api.RefreshNodeHardwareInfoApi.as_view(), name='node-refresh-hardware-info'),
|
||||
|
|
|
@ -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__()
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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 = "<b>{}: </b>".format(comment)
|
||||
for u in self.users.all():
|
||||
users += u.name + " "
|
||||
data += users + "<br/>"
|
||||
if self.assets.all():
|
||||
assets = _("<b>Assets: </b>")
|
||||
for a in self.assets.all():
|
||||
assets += a.hostname + " "
|
||||
data += assets + "<br/>"
|
||||
return data
|
||||
|
||||
|
||||
class NodePermission(models.Model):
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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 %}
|
||||
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
|
||||
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||
<link href="{% static 'css/plugins/jstree/style.min.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/plugins/ztree/awesomeStyle/awesome.css' %}" rel="stylesheet">
|
||||
<script type="text/javascript" src="{% static 'js/plugins/ztree/jquery.ztree.all.min.js' %}"></script>
|
||||
<style>
|
||||
#search_btn {
|
||||
margin-bottom: 0;
|
||||
.toggle {
|
||||
cursor: pointer;
|
||||
}
|
||||
.detail-key {
|
||||
width: 70px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content_left_head %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block table_search %}
|
||||
<div class="uc pull-left m-r-5">
|
||||
<a href="{% url 'perms:asset-permission-create' %}" class="btn btn-sm btn-primary ">
|
||||
{% trans "Create permission" %}
|
||||
</a>
|
||||
</div>
|
||||
<form id="search_form" method="get" action="" class="pull-right form-inline" style="padding-bottom: 8px">
|
||||
<div class="input-group">
|
||||
<select class="select2 form-control" name="user">
|
||||
<option value="">{% trans 'User' %}</option>
|
||||
{% for u in user_list %}
|
||||
<option value="{{ u }}" {% if u == user %} selected {% endif %}>{{ u }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<select class="select2 form-control" name="user_group">
|
||||
<option value="">{% trans 'User group' %}</option>
|
||||
{% for g in user_group_list %}
|
||||
<option value="{{ g }}" {% if g == user_group %} selected {% endif %}>{{ g }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<select class="select2 form-control" name="asset">
|
||||
<option value="">{% trans 'Asset' %}</option>
|
||||
{% for a in asset_list %}
|
||||
<option value="{{ a }}" {% if a == asset %} selected {% endif %}>{{ a }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<select class="select2 form-control" name="node">
|
||||
<option value="">{% trans 'Node' %}</option>
|
||||
{% for n in node_list %}
|
||||
<option value="{{ n }}" {% if n == node %} selected {% endif %}>{{ n }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<select class="select2 form-control" name="system_user">
|
||||
<option value="">{% trans 'System user' %}</option>
|
||||
{% for s in system_user_list %}
|
||||
<option value="{{ s }}" {% if s == system_user %} selected {% endif %}>{{ s }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control input-sm" name="q" placeholder="{% trans 'Search' %}" value="{{ q }}">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<div class="input-group-btn">
|
||||
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
|
||||
{% trans 'Search' %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% block table_container %}
|
||||
<table class="footable table table-stripped table-bordered toggle-arrow-tiny" data-page="false">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-sorted="true" data-toggle="true">ID</th>
|
||||
<th>{% trans 'Name' %}</th>
|
||||
<th class="text-center">{% trans 'User' %}</th>
|
||||
<th class="text-center">{% trans 'User group' %}</th>
|
||||
<th class="text-center">{% trans 'Asset' %}</th>
|
||||
<th class="text-center">{% trans 'Node'%}</th>
|
||||
<th class="text-center">{% trans 'System user' %}</th>
|
||||
<th class="text-center">{% trans 'Active' %}</th>
|
||||
<th class="text-center" >{% trans 'Action' %}</th>
|
||||
<th data-hide="all">{% trans 'User' %}</th>
|
||||
<th data-hide="all">{% trans 'User group' %}</th>
|
||||
<th data-hide="all">{% trans 'Asset' %}</th>
|
||||
<th data-hide="all">{% trans 'Node' %}</th>
|
||||
<th data-hide="all">{% trans 'System user' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for object in object_list %}
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td><a href="#">{{ object.name }}</a></td>
|
||||
<td class="text-center">{{ object.users.count }}</td>
|
||||
<td class="text-center">{{ object.user_groups.count }}</td>
|
||||
<td class="text-center">{{ object.assets.count }}</td>
|
||||
<td class="text-center">{{ object.nodes.count }}</td>
|
||||
<td class="text-center">{{ object.system_users.count }}</td>
|
||||
<td class="text-center">
|
||||
{% if object.is_valid %}
|
||||
<i class="fa fa-check text-navy"></i>
|
||||
{% else %}
|
||||
<i class="fa fa-times text-danger"></i>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="{% url 'perms:asset-permission-update' pk=object.id %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>
|
||||
<a data-uid="{{ object.id }}" class="btn btn-xs btn-danger m-l-xs btn-delete">{% trans "Delete" %}</a>
|
||||
</td>
|
||||
<td>{{ object.users_detail }}</td>
|
||||
<td>{{ object.user_groups_detail }}</td>
|
||||
<td>{{ object.assets_detail }}</td>
|
||||
<td>{{ object.nodes_detail }}</td>
|
||||
<td>{{ object.system_users_detail }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content">
|
||||
<div class="row">
|
||||
<div class="col-lg-3" id="split-left" style="padding-left: 3px">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-content mailbox-content" style="padding-top: 0;padding-left: 1px">
|
||||
<div class="file-manager ">
|
||||
<div id="assetTree" class="ztree">
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-9 animated fadeInRight" id="split-right">
|
||||
<div class="tree-toggle">
|
||||
<div class="btn btn-sm btn-primary tree-toggle-btn" onclick="toggle()">
|
||||
<i class="fa fa-angle-left fa-x" id="toggle-icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mail-box-header">
|
||||
<div class="uc pull-left m-r-5">
|
||||
<a class="btn btn-sm btn-primary btn-create-permission">
|
||||
{% trans "Create permission" %}
|
||||
</a>
|
||||
</div>
|
||||
<table class="table table-striped table-bordered table-hover" id="permission_list_table" style="width: 100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>{% trans 'Name' %}</th>
|
||||
<th class="text-center">{% trans 'User' %}</th>
|
||||
<th class="text-center">{% trans 'User group' %}</th>
|
||||
<th class="text-center">{% trans 'Asset' %}</th>
|
||||
<th class="text-center">{% trans 'Node'%}</th>
|
||||
<th class="text-center">{% trans 'System user' %}</th>
|
||||
<th class="text-center">{% trans 'Active' %}</th>
|
||||
<th class="text-center" >{% trans 'Action' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static "js/plugins/footable/footable.all.min.js" %}"></script>
|
||||
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.footable').footable();
|
||||
$('.select2').select2({
|
||||
dropdownAutoWidth : true,
|
||||
width: 'auto'
|
||||
});
|
||||
$('#date .input-daterange').datepicker({
|
||||
format: "yyyy-mm-dd",
|
||||
todayBtn: "linked",
|
||||
keyboardNavigation: false,
|
||||
forceParse: false,
|
||||
calendarWeeks: true,
|
||||
autoclose: true
|
||||
});
|
||||
}).on('click', '.btn-delete', function () {
|
||||
var $this = $(this);
|
||||
var uid = $this.data('uid');
|
||||
var the_url = '{% url "api-perms:asset-permission-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
|
||||
var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
|
||||
objectDelete($this, name, the_url);
|
||||
setTimeout( function () {
|
||||
window.reload();
|
||||
}, 1000);
|
||||
var zTree, table, show = 0;
|
||||
|
||||
function onSelected(event, treeNode) {
|
||||
setCookie('node_selected', treeNode.id);
|
||||
var url = table.ajax.url();
|
||||
if (treeNode.is_asset) {
|
||||
url = setUrlParam(url, 'node', "");
|
||||
url = setUrlParam(url, 'asset', treeNode.id)
|
||||
} else {
|
||||
url = setUrlParam(url, 'asset', "");
|
||||
url = setUrlParam(url, 'node', treeNode.id)
|
||||
}
|
||||
setCookie('node_selected', treeNode.id);
|
||||
table.ajax.url(url);
|
||||
table.ajax.reload();
|
||||
}
|
||||
|
||||
function selectQueryNode() {
|
||||
var query_node_id = $.getUrlParam("node");
|
||||
var cookie_node_id = getCookie('node_selected');
|
||||
var node;
|
||||
var node_id;
|
||||
|
||||
if (query_node_id !== null) {
|
||||
node_id = query_node_id
|
||||
} else if (cookie_node_id !== null) {
|
||||
node_id = cookie_node_id;
|
||||
}
|
||||
|
||||
node = zTree.getNodesByParam("id", node_id, null);
|
||||
if (node){
|
||||
zTree.selectNode(node[0]);
|
||||
node.open = true;
|
||||
}
|
||||
}
|
||||
|
||||
function filter(treeId, parentNode, childNodes) {
|
||||
$.each(childNodes, function (index, value) {
|
||||
value["pId"] = value["parent"];
|
||||
value["name"] = value["value"];
|
||||
value["isParent"] = value["assets_amount"] !== 0;
|
||||
value["iconSkin"] = value["is_asset"] ? "file" : null;
|
||||
});
|
||||
return childNodes;
|
||||
}
|
||||
|
||||
function beforeAsync(treeId, treeNode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function makeLabel(data) {
|
||||
return "<label class='detail-key'><b>" + data[0] + ": </b></label>" + data[1] + "</br>"
|
||||
}
|
||||
|
||||
function format(d) {
|
||||
var data = "";
|
||||
if (d.users.length > 0 ) {
|
||||
data += makeLabel(["{% trans 'User' %}", d.users.join(", ")])
|
||||
}
|
||||
if (d.user_groups.length > 0) {
|
||||
data += makeLabel(["{% trans 'User group' %}", d.user_groups.join(", ")])
|
||||
}
|
||||
if (d.assets.length > 0) {
|
||||
data += makeLabel(["{% trans 'Asset' %}", d.assets.join(", ")])
|
||||
}
|
||||
if (d.nodes.length > 0) {
|
||||
data += makeLabel(["{% trans 'Node' %}", d.nodes.join(", ")])
|
||||
}
|
||||
if (d.system_users.length > 0) {
|
||||
data += makeLabel(["{% trans 'System user' %}", d.system_users.join(", ")])
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
function initTable() {
|
||||
var options = {
|
||||
ele: $('#permission_list_table'),
|
||||
toggle: true,
|
||||
columnDefs: [
|
||||
{targets: 0, createdCell: function (td, cellData, rowData) {
|
||||
$(td).addClass("toggle");
|
||||
$(td).html("<i class='fa fa-angle-right'></i>");
|
||||
}},
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a href="{% url "perms:asset-permission-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
|
||||
}},
|
||||
{targets: 2, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 5, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 6, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 7, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{targets: 8, createdCell: function (td, cellData, rowData) {
|
||||
var update_btn = '<a href="{% url "perms:asset-permission-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
||||
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-uid="{{ DEFAULT_PK }}" mark=1 data-name="99991938">{% trans "Delete" %}</a>'
|
||||
.replace('{{ DEFAULT_PK }}', cellData)
|
||||
.replace('99991938', rowData.name);
|
||||
if (rowData.inherit) {
|
||||
del_btn = del_btn.replace("mark", "disabled")
|
||||
}
|
||||
$(td).html(update_btn + del_btn);
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-perms:asset-permission-list" %}',
|
||||
columns: [
|
||||
{data: "id"}, {data: "name"}, {data: "users"},
|
||||
{data: "user_groups"}, {data: "assets"},
|
||||
{data: "nodes"}, {data: "system_users"},
|
||||
{data: "is_active", orderable: false}, {data: "id", orderable: false}
|
||||
],
|
||||
select: {},
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
table = jumpserver.initDataTable(options);
|
||||
return table
|
||||
}
|
||||
|
||||
|
||||
function initTree() {
|
||||
var setting = {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showLine: true
|
||||
},
|
||||
data: {
|
||||
simpleData: {
|
||||
enable: true
|
||||
}
|
||||
},
|
||||
async: {
|
||||
enable: true,
|
||||
url: "{% url 'api-assets:node-children-2' %}?assets=1",
|
||||
autoParam:["id", "name=n", "level=lv"],
|
||||
dataFilter: filter,
|
||||
type: 'get'
|
||||
},
|
||||
callback: {
|
||||
onSelected: onSelected,
|
||||
beforeAsync: beforeAsync
|
||||
}
|
||||
};
|
||||
|
||||
var zNodes = [];
|
||||
$.get("{% url 'api-assets:node-children-2' %}", function(data, status){
|
||||
$.each(data, function (index, value) {
|
||||
value["pId"] = value["parent"];
|
||||
value["isParent"] = value["assets_amount"] !== 0;
|
||||
value["name"] = value["value"];
|
||||
value["open"] = value["key"] === "0";
|
||||
});
|
||||
zNodes = data;
|
||||
{#$.fn.zTree.init($("#assetTree"), setting);#}
|
||||
$.fn.zTree.init($("#assetTree"), setting, zNodes);
|
||||
zTree = $.fn.zTree.getZTreeObj("assetTree");
|
||||
selectQueryNode();
|
||||
});
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
if (show === 0) {
|
||||
$("#split-left").hide(500, function () {
|
||||
$("#split-right").attr("class", "col-lg-12");
|
||||
$("#toggle-icon").attr("class", "fa fa-angle-right fa-x");
|
||||
show = 1;
|
||||
});
|
||||
} else {
|
||||
$("#split-right").attr("class", "col-lg-9");
|
||||
$("#toggle-icon").attr("class", "fa fa-angle-left fa-x");
|
||||
$("#split-left").show(500);
|
||||
show = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
initTable();
|
||||
initTree();
|
||||
})
|
||||
.on('click', '.btn-del', function () {
|
||||
var $this = $(this);
|
||||
var uid = $this.data('uid');
|
||||
var name = $this.data('name');
|
||||
var the_url = '{% url "api-perms:asset-permission-detail" pk=DEFAULT_PK %}'
|
||||
.replace('{{ DEFAULT_PK }}', uid);
|
||||
objectDelete($this, name, the_url);
|
||||
})
|
||||
.on('click', '.btn-create-permission', function () {
|
||||
var url = "{% url 'perms:asset-permission-create' %}";
|
||||
var nodes = zTree.getSelectedNodes();
|
||||
var _nodes = [];
|
||||
var _assets = [];
|
||||
$.each(nodes, function (id, node) {
|
||||
if (node.is_asset) {
|
||||
_assets.push(node.id)
|
||||
} else {
|
||||
_nodes.push(node.id)
|
||||
}
|
||||
});
|
||||
url += "?assets=" + _assets.join(",") + "&nodes=" + _nodes.join(",");
|
||||
window.open(url, '_self');
|
||||
}).on('click', '.toggle', function (e) {
|
||||
e.preventDefault();
|
||||
var detailRows = [];
|
||||
var tr = $(this).closest('tr');
|
||||
var row = table.row(tr);
|
||||
var idx = $.inArray(tr.attr('id'), detailRows);
|
||||
|
||||
if (row.child.isShown()) {
|
||||
tr.removeClass('details');
|
||||
row.child.hide();
|
||||
|
||||
// Remove from the 'open' array
|
||||
detailRows.splice(idx, 1);
|
||||
}
|
||||
else {
|
||||
tr.addClass('details');
|
||||
$('.toggle i').removeClass('fa-angle-right').addClass('fa-angle-down');
|
||||
row.child(format(row.data())).show();
|
||||
// Add to the 'open' array
|
||||
if ( idx === -1 ) {
|
||||
detailRows.push(tr.attr('id'));
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
|
|
@ -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<pk>[0-9a-zA-Z\-]{36})/update$', views.AssetPermissionUpdateView.as_view(), name='asset-permission-update'),
|
||||
# url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})$', views.AssetPermissionDetailView.as_view(),name='asset-permission-detail'),
|
||||
url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})$', views.AssetPermissionDetailView.as_view(),name='asset-permission-detail'),
|
||||
url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/delete$', views.AssetPermissionDeleteView.as_view(), name='asset-permission-delete'),
|
||||
# url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/user$', views.AssetPermissionUserView.as_view(), name='asset-permission-user-list'),
|
||||
# url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/asset$', views.AssetPermissionAssetView.as_view(), name='asset-permission-asset-list'),
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;}
|
||||
|
||||
|
|
|
@ -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 "<label class='detail-key'><b>" + data[0] + ": </b></label>" + data[1] + "</br>"
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 || [],
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue