mirror of https://github.com/jumpserver/jumpserver
Merge with audits
commit
688bfa556c
|
@ -3,6 +3,7 @@ from __future__ import unicode_literals, absolute_import
|
|||
|
||||
import functools
|
||||
from django.db import models
|
||||
from django.core import serializers
|
||||
import logging
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
@ -322,8 +323,8 @@ class Asset(models.Model):
|
|||
created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by'))
|
||||
is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
|
||||
date_created = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date added'))
|
||||
comment = models.TextField(max_length=128, null=True, blank=True, verbose_name=_('Comment'))
|
||||
tags = models.ManyToManyField('Tag', verbose_name='标签集合', blank=True)
|
||||
comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment'))
|
||||
tags = models.ManyToManyField('Tag', blank=True, verbose_name=_('Tags'))
|
||||
|
||||
def __unicode__(self):
|
||||
return '%(ip)s:%(port)s' % {'ip': self.ip, 'port': self.port}
|
||||
|
@ -336,6 +337,9 @@ class Asset(models.Model):
|
|||
return True, ''
|
||||
return False, warning
|
||||
|
||||
def json(self):
|
||||
pass
|
||||
|
||||
class Meta:
|
||||
db_table = 'asset'
|
||||
unique_together = ('ip', 'port')
|
||||
|
|
|
@ -65,7 +65,6 @@ class AssetCreateView(AdminUserRequiredMixin,CreateAssetTagsMiXin,CreateView):
|
|||
print(form.errors)
|
||||
return super(AssetCreateView, self).form_invalid(form)
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': 'Assets',
|
||||
|
@ -75,21 +74,24 @@ class AssetCreateView(AdminUserRequiredMixin,CreateAssetTagsMiXin,CreateView):
|
|||
|
||||
return super(AssetCreateView, self).get_context_data(**kwargs)
|
||||
|
||||
class AssetModalCreateView(AdminUserRequiredMixin,CreateAssetTagsMiXin,ListView):
|
||||
|
||||
class AssetModalCreateView(AdminUserRequiredMixin, CreateAssetTagsMiXin, ListView):
|
||||
model = Asset
|
||||
# tag_type = 'asset'
|
||||
form_class = AssetCreateForm
|
||||
template_name = 'assets/asset_modal_update.html'
|
||||
success_url = reverse_lazy('assets:asset-list')
|
||||
|
||||
def get_queryset(self):
|
||||
self.queryset = super(AssetModalCreateView,self).get_queryset()
|
||||
self.s = self.request.GET.get('plain_id_lists')
|
||||
if "," in str(self.s):
|
||||
self.plain_id_lists = [int(x) for x in self.s.split(',')]
|
||||
self.plain_id_lists = [int(x) for x in self.s.split(',')]
|
||||
else:
|
||||
self.plain_id_lists = [self.s]
|
||||
|
||||
return self.queryset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
asset_on_list = Asset.objects.filter(id__in = self.plain_id_lists)
|
||||
context = {
|
||||
|
@ -102,7 +104,8 @@ class AssetModalCreateView(AdminUserRequiredMixin,CreateAssetTagsMiXin,ListView)
|
|||
kwargs.update(context)
|
||||
return super(AssetModalCreateView, self).get_context_data(**kwargs)
|
||||
|
||||
class AssetUpdateView(AdminUserRequiredMixin,UpdateAssetTagsMiXin,UpdateView):
|
||||
|
||||
class AssetUpdateView(AdminUserRequiredMixin, UpdateAssetTagsMiXin, UpdateView):
|
||||
model = Asset
|
||||
form_class = AssetCreateForm
|
||||
template_name = 'assets/asset_update.html'
|
||||
|
@ -144,13 +147,13 @@ class AssetDetailView(DetailView):
|
|||
kwargs.update(context)
|
||||
return super(AssetDetailView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetModalListView(AdminUserRequiredMixin, ListView):
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
model = Asset
|
||||
context_object_name = 'asset_modal_list'
|
||||
template_name = 'assets/asset_modal_list.html'
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
group_id = self.request.GET.get('group_id')
|
||||
tag_id = self.request.GET.get('tag_id')
|
||||
|
@ -160,7 +163,7 @@ class AssetModalListView(AdminUserRequiredMixin, ListView):
|
|||
self.plain_id_lists = [int(x) for x in self.s.split(',')]
|
||||
else:
|
||||
self.plain_id_lists = [self.s]
|
||||
print plain_id_lists
|
||||
|
||||
if plain_id_lists:
|
||||
context = {
|
||||
'all_assets':plain_id_lists
|
||||
|
@ -179,6 +182,7 @@ class AssetModalListView(AdminUserRequiredMixin, ListView):
|
|||
kwargs.update(context)
|
||||
return super(AssetModalListView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
|
||||
model = AssetGroup
|
||||
form_class = AssetGroupForm
|
||||
|
@ -197,7 +201,6 @@ class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
|
|||
kwargs.update(context)
|
||||
return super(AssetGroupCreateView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
def form_valid(self, form):
|
||||
asset_group = form.save()
|
||||
assets_id_list = self.request.POST.getlist('assets', [])
|
||||
|
@ -207,6 +210,7 @@ class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
|
|||
asset_group.save()
|
||||
return super(AssetGroupCreateView, self).form_valid(form)
|
||||
|
||||
|
||||
class AssetGroupListView(AdminUserRequiredMixin, ListView):
|
||||
model = AssetGroup
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
|
@ -255,6 +259,7 @@ class AssetGroupDetailView(SingleObjectMixin, AdminUserRequiredMixin, ListView):
|
|||
kwargs.update(context)
|
||||
return super(AssetGroupDetailView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class AssetGroupUpdateView(AdminUserRequiredMixin, UpdateView):
|
||||
model = AssetGroup
|
||||
form_class = AssetGroupForm
|
||||
|
@ -334,6 +339,7 @@ class IDCCreateView(AdminUserRequiredMixin, CreateView):
|
|||
# IDC_add_success_next(user)
|
||||
return super(IDCCreateView, self).form_valid(form)
|
||||
|
||||
|
||||
class IDCUpdateView(AdminUserRequiredMixin, UpdateView):
|
||||
model = IDC
|
||||
form_class = IDCForm
|
||||
|
@ -365,7 +371,6 @@ class IDCDeleteView(AdminUserRequiredMixin, DeleteView):
|
|||
success_url = reverse_lazy('assets:idc-list')
|
||||
|
||||
|
||||
|
||||
class AdminUserListView(AdminUserRequiredMixin, ListView):
|
||||
model = AdminUser
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
#
|
||||
|
||||
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from rest_framework import generics
|
||||
from rest_framework.views import APIView, Response
|
||||
|
||||
import serializers
|
||||
|
||||
from .models import ProxyLog, CommandLog
|
||||
from . import models, serializers
|
||||
from .hands import IsSuperUserOrTerminalUser, Terminal
|
||||
|
||||
|
||||
|
@ -30,7 +30,7 @@ class ProxyLogListCreateApi(generics.ListCreateAPIView):
|
|||
}
|
||||
"""
|
||||
|
||||
queryset = ProxyLog.objects.all()
|
||||
queryset = models.ProxyLog.objects.all()
|
||||
serializer_class = serializers.ProxyLogSerializer
|
||||
permission_classes = (IsSuperUserOrTerminalUser,)
|
||||
|
||||
|
@ -40,12 +40,23 @@ class ProxyLogListCreateApi(generics.ListCreateAPIView):
|
|||
|
||||
|
||||
class ProxyLogDetailApi(generics.RetrieveUpdateDestroyAPIView):
|
||||
queryset = ProxyLog.objects.all()
|
||||
queryset = models.ProxyLog.objects.all()
|
||||
serializer_class = serializers.ProxyLogSerializer
|
||||
permission_classes = (IsSuperUserOrTerminalUser,)
|
||||
|
||||
|
||||
class CommandLogCreateApi(generics.ListCreateAPIView):
|
||||
queryset = CommandLog.objects.all()
|
||||
class CommandLogListCreateApi(generics.ListCreateAPIView):
|
||||
queryset = models.CommandLog.objects.all()
|
||||
serializer_class = serializers.CommandLogSerializer
|
||||
permission_classes = (IsSuperUserOrTerminalUser,)
|
||||
|
||||
|
||||
# class CommandLogTitleApi(APIView):
|
||||
# def get(self, request):
|
||||
# response = [
|
||||
# {"name": "command_no", "title": "ID", "type": "number"},
|
||||
# {"name": "command", "title": "Title", "visible": True, "filterable": True},
|
||||
# {"name": "datetime", "title": "Datetime", "type"},
|
||||
# {"name": "output", "title": "Output", "filterable": True},
|
||||
# ]
|
||||
#
|
|
@ -2,6 +2,7 @@
|
|||
#
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import base64
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
@ -53,6 +54,17 @@ class ProxyLog(models.Model):
|
|||
def __unicode__(self):
|
||||
return '%s-%s-%s-%s' % (self.username, self.hostname, self.system_user, self.id)
|
||||
|
||||
@property
|
||||
def commands_dict(self):
|
||||
commands = self.command_log.all()
|
||||
return [
|
||||
{
|
||||
"command_no": command.command_no,
|
||||
"command": command.command,
|
||||
"output": command.output_decode,
|
||||
"datetime": command.datetime,
|
||||
} for command in commands]
|
||||
|
||||
class Meta:
|
||||
db_table = 'proxy_log'
|
||||
ordering = ['-date_start', 'username']
|
||||
|
@ -68,6 +80,10 @@ class CommandLog(models.Model):
|
|||
def __unicode__(self):
|
||||
return '%s: %s' % (self.id, self.command)
|
||||
|
||||
@property
|
||||
def output_decode(self):
|
||||
return base64.b64decode(self.output).replace('\n', '<br />')
|
||||
|
||||
class Meta:
|
||||
db_table = 'command_log'
|
||||
ordering = ['command_no', 'command']
|
||||
|
|
|
@ -1,19 +1,33 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
#
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
from rest_framework import serializers
|
||||
|
||||
import models
|
||||
from common.utils import timesince
|
||||
from . import models
|
||||
|
||||
|
||||
class ProxyLogSerializer(serializers.ModelSerializer):
|
||||
time = serializers.SerializerMethodField()
|
||||
command_length = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = models.ProxyLog
|
||||
fields = ['id', 'name', 'username', 'hostname', 'ip', 'system_user', 'login_type', 'terminal',
|
||||
'log_file', 'was_failed', 'is_finished', 'date_start', 'time', 'command_length', "commands_dict"]
|
||||
|
||||
@staticmethod
|
||||
def get_time(obj):
|
||||
if not obj.is_finished:
|
||||
return ''
|
||||
else:
|
||||
return timesince(obj.date_start, since=obj.date_finished)
|
||||
|
||||
@staticmethod
|
||||
def get_command_length(obj):
|
||||
return len(obj.command_log.all())
|
||||
|
||||
|
||||
class CommandLogSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = models.CommandLog
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load common_tags %}
|
||||
{% block content_left_head %}
|
||||
{# <a href="{% url 'perms:asset-permission-create' %}" class="btn btn-sm btn-primary "> {% trans "Create permission" %} </a>#}
|
||||
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
|
||||
{% endblock %}
|
||||
|
||||
{% block table_container %}
|
||||
<table class="footable table table-stripped toggle-arrow-tiny" data-page="false">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-toggle="true">ID</th>
|
||||
<th>Command</th>
|
||||
<th>Username</th>
|
||||
<th>IP</th>
|
||||
<th>Datetime</th>
|
||||
<th data-hide="all">Output</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for command in command_list %}
|
||||
<tr>
|
||||
<td>{{ command.command_no }}</td>
|
||||
<td>{{ command.command }}</td>
|
||||
<td>{{ command.proxy_log.username }}</td>
|
||||
<td>{{ command.proxy_log.ip }}</td>
|
||||
<td>{{ command.datetime }}</td>
|
||||
<td>{{ command.output_decode |safe }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static "js/plugins/footable/footable.all.min.js" %}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.footable').footable();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="renderer" content="webkit">
|
||||
{% include '_head_css_js.html' %}
|
||||
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
||||
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
|
||||
<script src="{% static 'js/jquery-2.1.1.js' %}"></script>
|
||||
<script src="{% static 'js/plugins/sweetalert/sweetalert.min.js' %}"></script>
|
||||
<script src="{% static 'js/bootstrap.min.js' %}"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="tab-content">
|
||||
<div class="ibox-content">
|
||||
<input type="text" class="form-control input-sm m-b-xs" id="filter"
|
||||
placeholder="Search in table">
|
||||
<table class="footable table table-stripped toggle-arrow-tiny" data-page-size="10" data-filter=#filter>
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-toggle="true">ID</th>
|
||||
<th>Command</th>
|
||||
<th data-hide="all">Output</th>
|
||||
<th>Datetime</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table_body">
|
||||
{% for command in object_list %}
|
||||
<tr>
|
||||
<td>{{ command.command_no }}</td>
|
||||
<td>{{ command.command }}</td>
|
||||
<td>{{ command.output_decode |safe }}</td>
|
||||
<td>{{ command.datetime }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<ul class="pagination pull-right"></ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="{% static "js/plugins/footable/footable.all.min.js" %}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.footable').footable();
|
||||
});
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,109 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="panel-options">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active">
|
||||
<a href="#" class="text-center"> {% trans 'Proxy log detail' %} </a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="col-sm-7" style="padding-left: 0;">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span style="float: left">{% trans 'Command log list' %} <b>{{ user_object.name }}</b></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
</a>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-user">
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<table id="command-log" class="footable table table-stripped toggle-arrow-tiny" data-page-size="10">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-toggle="true">ID</th>
|
||||
<th>Command</th>
|
||||
<th data-hide="all">Output</th>
|
||||
<th>Datetime</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for command in object_list %}
|
||||
<tr>
|
||||
<td>{{ command.command_no }}</td>
|
||||
<td>{{ command.command }}</td>
|
||||
<td>{{ command.output_decode |safe }}</td>
|
||||
<td>{{ command.datetime }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="5">
|
||||
<ul class="pagination pull-right"></ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span style="float: left">{% trans 'Detail' %} <b>{{ user_object.name }}</b></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
</a>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-user">
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<table class="table2 table-stripped toggle-arrow-tiny" data-page-size="8">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static "js/plugins/footable/footable.all.min.js" %}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.footable').footable();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -0,0 +1,108 @@
|
|||
{% extends '_base_list.html' %}
|
||||
{% load i18n static %}
|
||||
{% block custom_head_css_js %}
|
||||
{{ block.super }}
|
||||
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
|
||||
<link href="{% static "css/plugins/layer/layer.css" %}" rel="stylesheet">
|
||||
<style>
|
||||
div.dataTables_wrapper div.dataTables_filter,
|
||||
.dataTables_length {
|
||||
float: right !important;
|
||||
}
|
||||
|
||||
div.dataTables_wrapper div.dataTables_filter {
|
||||
margin-left: 15px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block table_search %}{% endblock %}
|
||||
{% block table_container %}
|
||||
{#<div class="uc pull-left m-l-5 m-r-5"><a href="{% url "users:user-create" %}" class="btn btn-sm btn-primary"> {% trans "Create user" %} </a></div>#}
|
||||
<table class="table table-striped table-bordered table-hover " id="proxy_log_list_table" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">
|
||||
<div class="checkbox checkbox-default">
|
||||
<input type="checkbox" class="ipt_check_all">
|
||||
</div>
|
||||
</th>
|
||||
<th class="text-center">{% trans 'Username' %}</th>
|
||||
<th class="text-center">{% trans 'IP' %}</th>
|
||||
<th class="text-center">{% trans 'System user' %}</th>
|
||||
{# <th class="text-center">{% trans 'Login type' %}</th>#}
|
||||
<th class="text-center">{% trans 'Command' %}</th>
|
||||
<th class="text-center">{% trans 'Success' %}</th>
|
||||
<th class="text-center">{% trans 'Finished' %}</th>
|
||||
<th class="text-center">{% trans 'Date start' %}</th>
|
||||
<th class="text-center">{% trans 'Time' %}</th>
|
||||
<th class="text-center">{% trans 'Action' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/jquery.form.min.js' %}"></script>
|
||||
<script src="{% static "js/plugins/layer/layer.js" %}"></script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
var options = {
|
||||
ele: $('#proxy_log_list_table'),
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a href="{% url "users:user-detail" pk=99991937 %}">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('99991937', rowData.id));
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData, rowData) {
|
||||
if (cellData) {
|
||||
$(td).html('<a url="{% url "audits:proxy-log-commands-list" pk=99991938 %}" class="commands">99991937</a>'
|
||||
.replace('99991937', cellData)
|
||||
.replace('99991938',rowData.id))
|
||||
}
|
||||
}},
|
||||
{targets: 5, 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: 6, 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: 9, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a href="{% url "audits:proxy-log-detail" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Detail" %}</a>'
|
||||
.replace('99991937', cellData);
|
||||
var delete_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_delete" data-uid="99991937" data-name="99991938">{% trans "Delete" %}</a>'
|
||||
.replace('99991937', cellData)
|
||||
.replace('99991938', rowData.name);
|
||||
$(td).html(detail_btn + delete_btn)
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "audits:proxy-log-list-create-api" %}',
|
||||
columns: [{data: function(){return ""}}, {data: "name" }, {data: "ip"},
|
||||
{data: "system_user"}, {data: "command_length"}, {data: 'was_failed'},
|
||||
{data: "is_finished"}, {data: "date_start"}, {data: 'time'}, {data: 'id'}],
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
}).on('click', '.commands', function () {
|
||||
var url = $(this).attr('url');
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '很多时候,我们想最大化看,比如像这个页面。',
|
||||
shadeClose: true,
|
||||
shade: false,
|
||||
maxmin: true, //开启最大化最小化按钮
|
||||
area: ['893px', '600px'],
|
||||
content: url
|
||||
});
|
||||
})
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -7,11 +7,15 @@ import views
|
|||
app_name = 'audits'
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^proxy-log$', views.ProxyLogListView.as_view(), name='proxy-log-list'),
|
||||
url(r'^proxy-log/(?P<pk>\d+)$', views.ProxyLogDetailView.as_view(), name='proxy-log-detail'),
|
||||
url(r'^proxy-log/(?P<pk>\d+)/commands$', views.ProxyLogCommandsListView.as_view(), name='proxy-log-commands-list'),
|
||||
url(r'^command-log$', views.CommandLogListView.as_view(), name='command-log-list'),
|
||||
]
|
||||
|
||||
|
||||
urlpatterns += [
|
||||
url(r'^v1/proxy-log/$', api.ProxyLogListCreateApi.as_view(), name='proxy-log-list-create-api'),
|
||||
url(r'^v1/proxy-log/(?P<pk>\d+)/$', api.ProxyLogDetailApi.as_view(), name='proxy-log-detail-api'),
|
||||
url(r'^v1/command-log/$', api.CommandLogCreateApi.as_view(), name='command-log-create-api'),
|
||||
url(r'^v1/command-log/$', api.CommandLogListCreateApi.as_view(), name='command-log-create-list-api'),
|
||||
]
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
#
|
||||
|
||||
from users.utils import AdminUserRequiredMixin
|
||||
|
||||
|
|
|
@ -1,3 +1,79 @@
|
|||
from django.shortcuts import render
|
||||
# ~*~ coding: utf-8 ~*~
|
||||
#
|
||||
|
||||
# Create your views here.
|
||||
from django.views.generic import ListView, UpdateView, DeleteView, DetailView, TemplateView
|
||||
from django.views.generic.edit import SingleObjectMixin
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.urls import reverse_lazy
|
||||
from django.conf import settings
|
||||
|
||||
from .models import ProxyLog, CommandLog
|
||||
from .utils import AdminUserRequiredMixin
|
||||
|
||||
|
||||
class ProxyLogListView(TemplateView):
|
||||
template_name = 'audits/proxy_log_list.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ProxyLogListView, self).get_context_data(**kwargs)
|
||||
context.update({'app': _('Audits'), 'action': _('Proxy log list')})
|
||||
return context
|
||||
|
||||
|
||||
class ProxyLogDetailView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
||||
template_name = 'audits/proxy_log_detail.html'
|
||||
context_object_name = 'proxy_log'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object(queryset=ProxyLog.objects.all())
|
||||
return super(ProxyLogDetailView, self).get(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return list(self.object.command_log.all())
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': 'Audits',
|
||||
'action': 'Proxy log detail',
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(ProxyLogDetailView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class ProxyLogCommandsListView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
||||
template_name = 'audits/proxy_log_commands_list_modal.html'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object(queryset=ProxyLog.objects.all())
|
||||
return super(ProxyLogCommandsListView, self).get(request, *args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
return list(self.object.command_log.all())
|
||||
|
||||
|
||||
class CommandLogListView(AdminUserRequiredMixin, ListView):
|
||||
model = CommandLog
|
||||
template_name = 'audits/command_log_list.html'
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
context_object_name = 'command_list'
|
||||
|
||||
def get_queryset(self):
|
||||
# Todo: Default order by lose asset connection num
|
||||
self.queryset = super(CommandLogListView, self).get_queryset()
|
||||
self.keyword = keyword = self.request.GET.get('keyword', '')
|
||||
self.sort = sort = self.request.GET.get('sort', '-datetime')
|
||||
|
||||
if keyword:
|
||||
self.queryset = self.queryset.filter()
|
||||
|
||||
if sort:
|
||||
self.queryset = self.queryset.order_by(sort)
|
||||
return self.queryset
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': 'Audits',
|
||||
'action': 'Command log list'
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(CommandLogListView, self).get_context_data(**kwargs)
|
||||
|
|
|
@ -6,6 +6,7 @@ from six import string_types
|
|||
from itertools import chain
|
||||
import string
|
||||
import logging
|
||||
import datetime
|
||||
|
||||
from itsdangerous import Signer, TimedJSONWebSignatureSerializer, JSONWebSignatureSerializer, TimestampSigner, \
|
||||
BadSignature, SignatureExpired
|
||||
|
@ -133,3 +134,34 @@ def int_seq(seq):
|
|||
return map(int, seq)
|
||||
except ValueError:
|
||||
return seq
|
||||
|
||||
|
||||
def timesince(dt, since='', default="just now"):
|
||||
"""
|
||||
Returns string representing "time since" e.g.
|
||||
3 days, 5 hours.
|
||||
"""
|
||||
|
||||
if since is '':
|
||||
since = datetime.datetime.utcnow()
|
||||
|
||||
if since is None:
|
||||
return default
|
||||
|
||||
diff = since - dt
|
||||
|
||||
periods = (
|
||||
(diff.days / 365, "year", "years"),
|
||||
(diff.days / 30, "month", "months"),
|
||||
(diff.days / 7, "week", "weeks"),
|
||||
(diff.days, "day", "days"),
|
||||
(diff.seconds / 3600, "hour", "hours"),
|
||||
(diff.seconds / 60, "minute", "minutes"),
|
||||
(diff.seconds, "second", "seconds"),
|
||||
)
|
||||
|
||||
for period, singular, plural in periods:
|
||||
if period:
|
||||
return "%d %s" % (period, singular if period == 1 else plural)
|
||||
return default
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ urlpatterns = [
|
|||
url(r'^$', TemplateView.as_view(template_name='base.html'), name='index'),
|
||||
url(r'^(api/)?users/', include('users.urls')),
|
||||
url(r'^assets/', include('assets.urls')),
|
||||
url(r'^perms/', include('perms.urls')),
|
||||
url(r'^(api/)?perms/', include('perms.urls')),
|
||||
url(r'^(api/)?audits/', include('audits.urls')),
|
||||
url(r'^(api/)?terminal/', include('terminal.urls')),
|
||||
]
|
||||
|
|
|
@ -1,3 +1,36 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
#
|
||||
|
||||
from rest_framework.views import APIView, Response
|
||||
from users.backends import IsValidUser
|
||||
from .utils import get_user_granted_assets, get_user_granted_asset_groups
|
||||
|
||||
|
||||
class UserAssetsGrantedApi(APIView):
|
||||
permission_classes = (IsValidUser,)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
assets_json = []
|
||||
user = request.user
|
||||
|
||||
if user:
|
||||
assets = get_user_granted_assets(user)
|
||||
|
||||
for asset, system_users in assets.items():
|
||||
assets_json.append({
|
||||
'id': asset.id,
|
||||
'hostname': asset.hostname,
|
||||
'ip': asset.ip,
|
||||
'port': asset.port,
|
||||
'system_users': [
|
||||
{
|
||||
'id': system_user.id,
|
||||
'name': system_user.name,
|
||||
'username': system_user.username,
|
||||
} for system_user in system_users
|
||||
],
|
||||
'comment': asset.comment
|
||||
})
|
||||
|
||||
return Response(assets_json, status=200)
|
||||
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
#
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
from users.utils import AdminUserRequiredMixin
|
||||
# from users.backends import IsValdiUser
|
||||
from users.models import User, UserGroup
|
||||
from assets.models import Asset, AssetGroup, SystemUser
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from django.conf.urls import url
|
||||
import views
|
||||
import api
|
||||
|
||||
app_name = 'perms'
|
||||
|
||||
|
@ -20,3 +21,8 @@ urlpatterns = [
|
|||
name='asset-permission-asset-list'),
|
||||
]
|
||||
|
||||
urlpatterns += [
|
||||
url(r'^v1/user/assets/granted/$', api.UserAssetsGrantedApi.as_view(),
|
||||
name='user-assets-granted'),
|
||||
]
|
||||
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,78 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>
|
||||
This is a custom SVG font generated by IcoMoon.
|
||||
<iconset grid="16"></iconset>
|
||||
</metadata>
|
||||
<defs>
|
||||
<font id="footable" horiz-adv-x="512" >
|
||||
<font-face units-per-em="512" ascent="480" descent="-32" />
|
||||
<missing-glyph horiz-adv-x="512" />
|
||||
<glyph class="hidden" unicode="" d="M0,480L 512 -32L0 -32 z" horiz-adv-x="0" />
|
||||
<glyph unicode="" d="M 496,288L 320,288 L 320,464 c0,8.836-7.164,16-16,16l-96,0 c-8.836,0-16-7.164-16-16l0-176 L 16,288 c-8.836,0-16-7.164-16-16l0-96
|
||||
c0-8.836, 7.164-16, 16-16l 176,0 l0-176 c0-8.836, 7.164-16, 16-16l 96,0 c 8.836,0, 16,7.164, 16,16L 320,160 l 176,0 c 8.836,0, 16,7.164, 16,16l0,96
|
||||
C 512,280.836, 504.836,288, 496,288z" />
|
||||
<glyph unicode="" d="M0,272l0-96 c0-8.836, 7.164-16, 16-16l 480,0 c 8.836,0, 16,7.164, 16,16l0,96 c0,8.836-7.164,16-16,16L 16,288 C 7.164,288,0,280.836,0,272z" />
|
||||
<glyph unicode="" d="M 256,480C 114.615,480,0,365.385,0,224s 114.615-256, 256-256s 256,114.615, 256,256S 397.385,480, 256,480z M 288,192l0-128 l-64,0 L 224,192 L 96,192 l0,64
|
||||
l 128,0 L 224,384 l 64,0 l0-128 l 128,0 l0-64 L 288,192 z" />
|
||||
<glyph unicode="" d="M 256,480C 114.615,480,0,365.385,0,224s 114.615-256, 256-256s 256,114.615, 256,256S 397.385,480, 256,480z M 416,192L 96,192 l0,64 l 320,0 L 416,192 z" />
|
||||
<glyph unicode="" d="M 256,480C 114.615,480,0,365.385,0,224s 114.615-256, 256-256s 256,114.615, 256,256S 397.385,480, 256,480z M 256,32
|
||||
c-106.039,0-192,85.961-192,192c0,106.039, 85.961,192, 192,192c 106.039,0, 192-85.961, 192-192C 448,117.961, 362.039,32, 256,32zM 384,192 L 288,192 L 288,96 L 224,96 L 224,192 L 128,192 L 128,256 L 224,256 L 224,352 L 288,352 L 288,256 L 384,256 Z" />
|
||||
<glyph unicode="" d="M 256,480C 114.615,480,0,365.385,0,224s 114.615-256, 256-256s 256,114.615, 256,256S 397.385,480, 256,480z M 256,32
|
||||
c-106.039,0-192,85.961-192,192c0,106.039, 85.961,192, 192,192c 106.039,0, 192-85.961, 192-192C 448,117.961, 362.039,32, 256,32zM 128,256L 384,256L 384,192L 128,192z" />
|
||||
<glyph unicode="" d="M 256,214.857l0-18.286 q0-4 -2.571-6.571t-6.571-2.571l-64,0 l0-64 q0-4 -2.571-6.571t-6.571-2.571l-18.286,0 q-4,0 -6.571,2.571t-2.571,6.571l0,64 l-64,0 q-4,0 -6.571,2.571t-2.571,6.571l0,18.286 q0,4 2.571,6.571t 6.571,2.571l 64,0 l0,64 q0,4 2.571,6.571t 6.571,2.571l 18.286,0 q 4,0 6.571-2.571t 2.571-6.571l0-64 l 64,0 q 4,0 6.571-2.571t 2.571-6.571zM 292.571,105.143l0,201.143 q0,11.429 -8,19.429t-19.429,8l-201.143,0 q-11.429,0 -19.429-8 t-8-19.429l0-201.143 q0-11.429 8-19.429t 19.429-8l 201.143,0 q 11.429,0 19.429,8t 8,19.429zM 329.143,306.286l0-201.143 q0-26.286 -18.714-45.143t-45.286-18.857l-201.143,0 q-26.571,0 -45.286,18.857t-18.714,45.143l0,201.143 q0,26.571 18.714,45.286t 45.286,18.714l 201.143,0 q 26.571,0 45.286-18.714t 18.714-45.286z" horiz-adv-x="329.143" />
|
||||
<glyph unicode="" d="M 265.143,370.286q 26.571,0 45.286-18.714t 18.714-45.286l0-201.143 q0-26.286 -18.714-45.143t-45.286-18.857l-201.143,0 q-26.571,0 -45.286,18.857t-18.714,45.143l0,201.143 q0,26.571 18.714,45.286t 45.286,18.714l 201.143,0 zM 292.571,105.143l0,201.143 q0,11.429 -8,19.429t-19.429,8l-201.143,0 q-11.429,0 -19.429-8t-8-19.429l0-201.143 q0-11.429 8-19.429t 19.429-8l 201.143,0 q 11.429,0 19.429,8t 8,19.429z M 246.857,224q 4,0 6.571-2.571t 2.571-6.571l0-18.286 q0-4 -2.571-6.571t-6.571-2.571l-164.571,0 q-4,0 -6.571,2.571t-2.571,6.571l0,18.286 q0,4 2.571,6.571t 6.571,2.571l 164.571,0 z" horiz-adv-x="329.143" />
|
||||
<glyph unicode="" d="M 365.714,205.714l0,36.571 q0,7.429 -5.429,12.857t-12.857,5.429l-91.429,0 l0,91.429 q0,7.429 -5.429,12.857t-12.857,5.429l-36.571,0 q-7.429,0 -12.857-5.429t-5.429-12.857l0-91.429 l-91.429,0 q-7.429,0 -12.857-5.429t-5.429-12.857l0-36.571 q0-7.429 5.429-12.857t 12.857-5.429l 91.429,0 l0-91.429 q0-7.429 5.429-12.857t 12.857-5.429l 36.571,0 q 7.429,0 12.857,5.429t 5.429,12.857l0,91.429 l 91.429,0 q 7.429,0 12.857,5.429t 5.429,12.857zM 438.857,361.143l0-274.286 q0-34 -24.143-58.143t-58.143-24.143l-274.286,0 q-34,0 -58.143,24.143t-24.143,58.143l0,274.286 q0,34 24.143,58.143t 58.143,24.143l 274.286,0 q 34,0 58.143-24.143t 24.143-58.143z" horiz-adv-x="438.857" />
|
||||
<glyph unicode="" d="M 365.714,205.714l0,36.571 q0,7.429 -5.429,12.857t-12.857,5.429l-256,0 q-7.429,0 -12.857-5.429t-5.429-12.857l0-36.571 q0-7.429 5.429-12.857t 12.857-5.429l 256,0 q 7.429,0 12.857,5.429t 5.429,12.857zM 438.857,361.143l0-274.286 q0-34 -24.143-58.143t-58.143-24.143l-274.286,0 q-34,0 -58.143,24.143t-24.143,58.143l0,274.286 q0,34 24.143,58.143t 58.143,24.143l 274.286,0 q 34,0 58.143-24.143 t 24.143-58.143z" horiz-adv-x="438.857" />
|
||||
<glyph unicode="" d="M 512,224C 512,82.615, 397.385-32, 256-32s -256,114.615, -256,256s 114.615,256, 256,256S 512,365.385, 512,224z M 233.372,374.628
|
||||
l -128-128.001C 99.124,240.379, 96,232.189, 96,224s 3.124-16.379 9.372-22.627c 12.497-12.497 32.759-12.497, 45.256,0L 224,274.745
|
||||
L 224,96 c 0-17.673 14.327-32 32-32c 17.673,0, 32,14.327, 32,32l0,178.745 l 73.373-73.373c 12.497-12.497 32.758-12.497, 45.255,0
|
||||
c 12.497,12.497, 12.497,32.758, 0,45.254l -128,128.001C 266.131,387.124, 245.869,387.124, 233.372,374.628z" />
|
||||
<glyph unicode="" d="M 512,224C 512,365.385, 397.385,480, 256,480s -256-114.615, -256-256s 114.615-256, 256-256S 512,82.615, 512,224z M 233.372,73.372
|
||||
l -128,128.001C 99.124,207.621, 96,215.811, 96,224s 3.124,16.379 9.372,22.627c 12.497,12.497 32.759,12.497, 45.256,0L 224,173.255
|
||||
L 224,352 c 0,17.673 14.327,32 32,32c 17.673,0, 32-14.327, 32-32l0-178.745 l 73.373,73.373c 12.497,12.497 32.758,12.497, 45.255,0
|
||||
c 12.497-12.497, 12.497-32.758, 0-45.254l -128-128.001C 266.131,60.876, 245.869,60.876, 233.372,73.372z" />
|
||||
<glyph unicode="" d="M 256,480C 397.385,480, 512,365.385, 512,224s -114.615-256, -256-256s -256,114.615, -256,256S 114.615,480, 256,480z M 105.372,201.372
|
||||
l 128.001-128C 239.621,67.124, 247.811,64, 256,64s 16.379,3.124 22.627,9.372c 12.497,12.497 12.497,32.759,0,45.256L 205.255,192
|
||||
L 384,192 c 17.673,0 32,14.327 32,32c0,17.673, -14.327,32, -32,32l-178.745,0 l 73.373,73.373c 12.497,12.497 12.497,32.758,0,45.255
|
||||
c -12.497,12.497, -32.758,12.497, -45.254,0l -128.001-128C 92.876,234.131, 92.876,213.869, 105.372,201.372z" />
|
||||
<glyph unicode="" d="M 256,480C 114.615,480,0,365.385,0,224s 114.615-256, 256-256s 256,114.615, 256,256S 397.385,480, 256,480z M 406.628,201.372
|
||||
l-128.001-128C 272.379,67.124, 264.189,64, 256,64s-16.379,3.124-22.627,9.372c-12.497,12.497-12.497,32.759,0,45.256L 306.745,192
|
||||
L 128,192 c-17.673,0-32,14.327-32,32c0,17.673, 14.327,32, 32,32l 178.745,0 l-73.373,73.373c-12.497,12.497-12.497,32.758,0,45.255
|
||||
c 12.497,12.497, 32.758,12.497, 45.254,0l 128.001-128C 419.124,234.131, 419.124,213.869, 406.628,201.372z" />
|
||||
<glyph unicode="" d="M0,160L 96,64L 256,224L 416,64L 512,160L 256.001,416 z" />
|
||||
<glyph unicode="" d="M 512,288L 416,384L 256,224L 96,384L0,288L 256,32.001 z" />
|
||||
<glyph unicode="" d="M 320-32L 416,64L 256,224L 416,384L 320,480L 64,224 z" />
|
||||
<glyph unicode="" d="M 192,480L 96,384L 256,224L 96,64L 192-32L 448,224 z" />
|
||||
<glyph unicode="" d="M 292.571,132.571q0-7.429 -5.429-12.857t-12.857-5.429l-256,0 q-7.429,0 -12.857,5.429t-5.429,12.857t 5.429,12.857l 128,128q 5.429,5.429 12.857,5.429t 12.857-5.429l 128-128q 5.429-5.429 5.429-12.857z" horiz-adv-x="292.571" />
|
||||
<glyph unicode="" d="M 292.571,278.857q0-7.429 -5.429-12.857l-128-128q-5.429-5.429 -12.857-5.429t-12.857,5.429l-128,128q-5.429,5.429 -5.429,12.857t 5.429,12.857t 12.857,5.429l 256,0 q 7.429,0 12.857-5.429t 5.429-12.857z" horiz-adv-x="292.571" />
|
||||
<glyph unicode="" d="M 182.857,352l0-256 q0-7.429 -5.429-12.857t-12.857-5.429t-12.857,5.429l-128,128q-5.429,5.429 -5.429,12.857t 5.429,12.857l 128,128q 5.429,5.429 12.857,5.429t 12.857-5.429t 5.429-12.857z" horiz-adv-x="182.857" />
|
||||
<glyph unicode="" d="M 164.571,224q0-7.429 -5.429-12.857l-128-128q-5.429-5.429 -12.857-5.429t-12.857,5.429t-5.429,12.857l0,256 q0,7.429 5.429,12.857t 12.857,5.429t 12.857-5.429l 128-128q 5.429-5.429 5.429-12.857z" horiz-adv-x="182.857" />
|
||||
<glyph unicode="" d="M 256,480L 32-32L 256,64L 480-32 z" />
|
||||
<glyph unicode="" d="M 256-32L 480,480L 256,384L 32,480 z" />
|
||||
<glyph unicode="" d="M0,224L 512,0L 416,224L 512,448 z" />
|
||||
<glyph unicode="" d="M 512,224L0,448L 96,224L0,0 z" />
|
||||
<glyph unicode="" d="M 512,224C 512,82.615, 397.385-32, 256-32s -256,114.615, -256,256s 114.615,256, 256,256S 512,365.385, 512,224z M 48,224
|
||||
c 0-114.875 93.125-208 208-208S 464,109.125, 464,224s -93.125,208, -208,208S 48,338.875, 48,224zM 278.627,374.628l 128-128.001c 12.497-12.496 12.497-32.757 0-45.254c -12.497-12.497 -32.758-12.497,-45.255,0L 288,274.745
|
||||
L 288,96 c 0-17.673 -14.327-32 -32-32c-17.673,0, -32,14.327, -32,32l0,178.745 l -73.372-73.373c -12.497-12.497 -32.759-12.497,-45.256,0
|
||||
C 99.124,207.621, 96,215.811, 96,224s 3.124,16.379, 9.372,22.627l 128,128.001C 245.869,387.124, 266.131,387.124, 278.627,374.628z" />
|
||||
<glyph unicode="" d="M 512,224C 512,365.385, 397.385,480, 256,480s -256-114.615, -256-256s 114.615-256, 256-256S 512,82.615, 512,224z M 48,224
|
||||
c 0,114.875 93.125,208 208,208S 464,338.875, 464,224s -93.125-208, -208-208S 48,109.125, 48,224zM 278.627,73.372l 128,128.001c 12.497,12.496 12.497,32.757 0,45.254c -12.497,12.497 -32.758,12.497,-45.255,0L 288,173.255
|
||||
L 288,352 c 0,17.673 -14.327,32 -32,32c-17.673,0, -32-14.327, -32-32l0-178.745 l -73.372,73.373c -12.497,12.497 -32.759,12.497,-45.256,0
|
||||
C 99.124,240.379, 96,232.189, 96,224s 3.124-16.379, 9.372-22.627l 128-128.001C 245.869,60.876, 266.131,60.876, 278.627,73.372z" />
|
||||
<glyph unicode="" d="M 256,480C 397.385,480, 512,365.385, 512,224s -114.615-256, -256-256s -256,114.615, -256,256S 114.615,480, 256,480z M 256,16
|
||||
c 114.875,0 208,93.125 208,208S 370.875,432, 256,432s -208-93.125, -208-208S 141.125,16, 256,16zM 105.372,246.627l 128.001,128c 12.496,12.497 32.757,12.497 45.254,0c 12.497-12.497 12.497-32.758,0-45.255L 205.255,256
|
||||
L 384,256 c 17.673,0 32-14.327 32-32c0-17.673, -14.327-32, -32-32l-178.745,0 l 73.373-73.372c 12.497-12.497 12.497-32.759,0-45.256
|
||||
C 272.379,67.124, 264.189,64, 256,64s -16.379,3.124, -22.627,9.372l -128.001,128C 92.876,213.869, 92.876,234.131, 105.372,246.627z" />
|
||||
<glyph unicode="" d="M 256,480C 114.615,480,0,365.385,0,224s 114.615-256, 256-256s 256,114.615, 256,256S 397.385,480, 256,480z M 256,16
|
||||
c-114.875,0-208,93.125-208,208S 141.125,432, 256,432s 208-93.125, 208-208S 370.875,16, 256,16zM 406.628,246.627l-128.001,128c-12.496,12.497-32.757,12.497-45.254,0c-12.497-12.497-12.497-32.758,0-45.255L 306.745,256
|
||||
L 128,256 c-17.673,0-32-14.327-32-32c0-17.673, 14.327-32, 32-32l 178.745,0 l-73.373-73.372c-12.497-12.497-12.497-32.759,0-45.256
|
||||
C 239.621,67.124, 247.811,64, 256,64s 16.379,3.124, 22.627,9.372l 128.001,128C 419.124,213.869, 419.124,234.131, 406.628,246.627z" />
|
||||
<glyph unicode="" d="M 307.143,141.714q0-3.714 -2.857-6.571l-14.286-14.286q-2.857-2.857 -6.571-2.857t-6.571,2.857l-112.286,112.286l-112.286-112.286q-2.857-2.857 -6.571-2.857t-6.571,2.857l-14.286,14.286q-2.857,2.857 -2.857,6.571t 2.857,6.571l 133.143,133.143q 2.857,2.857 6.571,2.857t 6.571-2.857l 133.143-133.143q 2.857-2.857 2.857-6.571z" horiz-adv-x="329.143" />
|
||||
<glyph unicode="" d="M 307.143,269.714q0-3.714 -2.857-6.571l-133.143-133.143q-2.857-2.857 -6.571-2.857t-6.571,2.857l-133.143,133.143q-2.857,2.857 -2.857,6.571t 2.857,6.571l 14.286,14.286q 2.857,2.857 6.571,2.857t 6.571-2.857l 112.286-112.286l 112.286,112.286q 2.857,2.857 6.571,2.857t 6.571-2.857l 14.286-14.286q 2.857-2.857 2.857-6.571z" horiz-adv-x="329.143" />
|
||||
<glyph unicode="" d="M 179.143,324.571q0-3.714 -2.857-6.571l-112.286-112.286l 112.286-112.286q 2.857-2.857 2.857-6.571t-2.857-6.571l-14.286-14.286q-2.857-2.857 -6.571-2.857t-6.571,2.857l-133.143,133.143q-2.857,2.857 -2.857,6.571t 2.857,6.571l 133.143,133.143q 2.857,2.857 6.571,2.857t 6.571-2.857l 14.286-14.286q 2.857-2.857 2.857-6.571z" horiz-adv-x="182.857" />
|
||||
<glyph unicode="" d="M 170,205.714q0-3.714 -2.857-6.571l-133.143-133.143q-2.857-2.857 -6.571-2.857t-6.571,2.857l-14.286,14.286q-2.857,2.857 -2.857,6.571t 2.857,6.571l 112.286,112.286l-112.286,112.286q-2.857,2.857 -2.857,6.571t 2.857,6.571l 14.286,14.286q 2.857,2.857 6.571,2.857t 6.571-2.857l 133.143-133.143q 2.857-2.857 2.857-6.571z" horiz-adv-x="182.857" />
|
||||
<glyph unicode="" d="M 292.571,169.143q0-7.429 -5.429-12.857l-128-128q-5.429-5.429 -12.857-5.429t-12.857,5.429l-128,128q-5.429,5.429 -5.429,12.857t 5.429,12.857t 12.857,5.429l 256,0 q 7.429,0 12.857-5.429t 5.429-12.857zM 292.571,278.857q0-7.429 -5.429-12.857t-12.857-5.429l-256,0 q-7.429,0 -12.857,5.429t-5.429,12.857t 5.429,12.857l 128,128q 5.429,5.429 12.857,5.429t 12.857-5.429l 128-128q 5.429-5.429 5.429-12.857z" horiz-adv-x="292.571" />
|
||||
<glyph unicode=" " horiz-adv-x="256" />
|
||||
</font></defs></svg>
|
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,179 @@
|
|||
@font-face {
|
||||
font-family: 'footable';
|
||||
src: url('fonts/footable.eot');
|
||||
src: url('fonts/footable.eot?#iefix') format('embedded-opentype'), url('fonts/footable.woff') format('woff'), url('fonts/footable.ttf') format('truetype'), url('fonts/footable.svg#footable') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@media screen and (-webkit-min-device-pixel-ratio: 0) {
|
||||
@font-face {
|
||||
font-family: 'footable';
|
||||
src: url('fonts/footable.svg#footable') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.footable {
|
||||
width: 100%;
|
||||
/** SORTING **/
|
||||
|
||||
/** PAGINATION **/
|
||||
|
||||
}
|
||||
.footable.breakpoint > tbody > tr.footable-detail-show > td {
|
||||
border-bottom: none;
|
||||
}
|
||||
.footable.breakpoint > tbody > tr.footable-detail-show > td > span.footable-toggle:before {
|
||||
content: "\e001";
|
||||
}
|
||||
.footable.breakpoint > tbody > tr:hover:not(.footable-row-detail) {
|
||||
cursor: pointer;
|
||||
}
|
||||
.footable.breakpoint > tbody > tr > td.footable-cell-detail {
|
||||
background: #eee;
|
||||
border-top: none;
|
||||
}
|
||||
.footable.breakpoint > tbody > tr > td > span.footable-toggle {
|
||||
display: inline-block;
|
||||
font-family: 'footable';
|
||||
speak: none;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
padding-right: 5px;
|
||||
font-size: 14px;
|
||||
color: #888888;
|
||||
}
|
||||
.footable.breakpoint > tbody > tr > td > span.footable-toggle:before {
|
||||
content: "\e000";
|
||||
}
|
||||
.footable.breakpoint.toggle-circle > tbody > tr.footable-detail-show > td > span.footable-toggle:before {
|
||||
content: "\e005";
|
||||
}
|
||||
.footable.breakpoint.toggle-circle > tbody > tr > td > span.footable-toggle:before {
|
||||
content: "\e004";
|
||||
}
|
||||
.footable.breakpoint.toggle-circle-filled > tbody > tr.footable-detail-show > td > span.footable-toggle:before {
|
||||
content: "\e003";
|
||||
}
|
||||
.footable.breakpoint.toggle-circle-filled > tbody > tr > td > span.footable-toggle:before {
|
||||
content: "\e002";
|
||||
}
|
||||
.footable.breakpoint.toggle-square > tbody > tr.footable-detail-show > td > span.footable-toggle:before {
|
||||
content: "\e007";
|
||||
}
|
||||
.footable.breakpoint.toggle-square > tbody > tr > td > span.footable-toggle:before {
|
||||
content: "\e006";
|
||||
}
|
||||
.footable.breakpoint.toggle-square-filled > tbody > tr.footable-detail-show > td > span.footable-toggle:before {
|
||||
content: "\e009";
|
||||
}
|
||||
.footable.breakpoint.toggle-square-filled > tbody > tr > td > span.footable-toggle:before {
|
||||
content: "\e008";
|
||||
}
|
||||
.footable.breakpoint.toggle-arrow > tbody > tr.footable-detail-show > td > span.footable-toggle:before {
|
||||
content: "\e00f";
|
||||
}
|
||||
.footable.breakpoint.toggle-arrow > tbody > tr > td > span.footable-toggle:before {
|
||||
content: "\e011";
|
||||
}
|
||||
.footable.breakpoint.toggle-arrow-small > tbody > tr.footable-detail-show > td > span.footable-toggle:before {
|
||||
content: "\e013";
|
||||
}
|
||||
.footable.breakpoint.toggle-arrow-small > tbody > tr > td > span.footable-toggle:before {
|
||||
content: "\e015";
|
||||
}
|
||||
.footable.breakpoint.toggle-arrow-circle > tbody > tr.footable-detail-show > td > span.footable-toggle:before {
|
||||
content: "\e01b";
|
||||
}
|
||||
.footable.breakpoint.toggle-arrow-circle > tbody > tr > td > span.footable-toggle:before {
|
||||
content: "\e01d";
|
||||
}
|
||||
.footable.breakpoint.toggle-arrow-circle-filled > tbody > tr.footable-detail-show > td > span.footable-toggle:before {
|
||||
content: "\e00b";
|
||||
}
|
||||
.footable.breakpoint.toggle-arrow-circle-filled > tbody > tr > td > span.footable-toggle:before {
|
||||
content: "\e00d";
|
||||
}
|
||||
.footable.breakpoint.toggle-arrow-tiny > tbody > tr.footable-detail-show > td > span.footable-toggle:before {
|
||||
content: "\e01f";
|
||||
}
|
||||
.footable.breakpoint.toggle-arrow-tiny > tbody > tr > td > span.footable-toggle:before {
|
||||
content: "\e021";
|
||||
}
|
||||
.footable.breakpoint.toggle-arrow-alt > tbody > tr.footable-detail-show > td > span.footable-toggle:before {
|
||||
content: "\e017";
|
||||
}
|
||||
.footable.breakpoint.toggle-arrow-alt > tbody > tr > td > span.footable-toggle:before {
|
||||
content: "\e019";
|
||||
}
|
||||
.footable.breakpoint.toggle-medium > tbody > tr > td > span.footable-toggle {
|
||||
font-size: 18px;
|
||||
}
|
||||
.footable.breakpoint.toggle-large > tbody > tr > td > span.footable-toggle {
|
||||
font-size: 24px;
|
||||
}
|
||||
.footable > thead > tr > th {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: -moz-none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
.footable > thead > tr > th.footable-sortable:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
.footable > thead > tr > th.footable-sorted > span.footable-sort-indicator:before {
|
||||
content: "\e013";
|
||||
}
|
||||
.footable > thead > tr > th.footable-sorted-desc > span.footable-sort-indicator:before {
|
||||
content: "\e012";
|
||||
}
|
||||
.footable > thead > tr > th > span.footable-sort-indicator {
|
||||
display: inline-block;
|
||||
font-family: 'footable';
|
||||
speak: none;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
padding-left: 5px;
|
||||
}
|
||||
.footable > thead > tr > th > span.footable-sort-indicator:before {
|
||||
content: "\e022";
|
||||
}
|
||||
.footable > tfoot .pagination {
|
||||
margin: 0;
|
||||
}
|
||||
.footable.no-paging .hide-if-no-paging {
|
||||
display: none;
|
||||
}
|
||||
.footable-row-detail-inner {
|
||||
display: table;
|
||||
}
|
||||
.footable-row-detail-row {
|
||||
display: table-row;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
.footable-row-detail-group {
|
||||
display: block;
|
||||
line-height: 2em;
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.footable-row-detail-name {
|
||||
display: table-cell;
|
||||
font-weight: bold;
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
.footable-row-detail-value {
|
||||
display: table-cell;
|
||||
}
|
||||
.footable-odd {
|
||||
background-color: #f7f7f7;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 701 B |
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
File diff suppressed because one or more lines are too long
|
@ -197,7 +197,7 @@ function APIUpdateAttr(props) {
|
|||
type: props.method || "PATCH",
|
||||
data: props.body,
|
||||
contentType: props.content_type || "application/json; charset=utf-8",
|
||||
dataType: props.data_type || "json",
|
||||
dataType: props.data_type || "json"
|
||||
}).done(function(data, textStatue, jqXHR) {
|
||||
if (typeof props.success === 'function') {
|
||||
return props.success(data);
|
||||
|
@ -215,28 +215,37 @@ function APIUpdateAttr(props) {
|
|||
}
|
||||
|
||||
// Sweet Alert for Delete
|
||||
function objectDelete(obj, name, url){
|
||||
function objectDelete(obj, name, url) {
|
||||
var $this = $(this);
|
||||
function doDelete() {
|
||||
var uid = $this.data('uid');
|
||||
var body = {};
|
||||
var success = function() {
|
||||
swal('Deleted!', "[ "+name+"]"+" has been deleted ", "success");
|
||||
$(obj).parent().parent().remove();
|
||||
};
|
||||
var fail = function() {
|
||||
swal("Failed", "Delete"+"[ "+name+" ]"+"failed", "error");
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: url,
|
||||
body: JSON.stringify(body),
|
||||
method: 'DELETE',
|
||||
success: success,
|
||||
error: fail
|
||||
});
|
||||
}
|
||||
swal({
|
||||
title: 'Are you sure delete ?',
|
||||
text: "【" + name + "】",
|
||||
text: " [" + name + "] ",
|
||||
type: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonText: 'Cancel',
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: 'Yes, delete it!',
|
||||
confirmButtonText: 'Confirm',
|
||||
closeOnConfirm: false
|
||||
}, function () {
|
||||
$.ajax({
|
||||
type : "post",
|
||||
url : url,
|
||||
data : {
|
||||
},
|
||||
dataType : "text",
|
||||
success : function(data) {
|
||||
swal('Deleted!' , "【"+name+"】"+"has been deleted.", "success");
|
||||
$(obj).parent().parent().remove();
|
||||
}
|
||||
});
|
||||
doDelete()
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -279,7 +288,7 @@ jumpserver.initDataTable = function (options) {
|
|||
$(td).html('<div class="checkbox checkbox-default"><input type="checkbox" class="ipt_check"><label></label></div>');
|
||||
}
|
||||
},
|
||||
{className: 'text-center', targets: '_all'},
|
||||
{className: 'text-center', targets: '_all'}
|
||||
];
|
||||
columnDefs = options.columnDefs ? options.columnDefs.concat(columnDefs) : columnDefs;
|
||||
var table = ele.DataTable({
|
||||
|
@ -342,6 +351,6 @@ jumpserver.initDataTable = function (options) {
|
|||
jumpserver.checked = false;
|
||||
table.rows().deselect();
|
||||
}
|
||||
})
|
||||
});
|
||||
return table;
|
||||
}
|
||||
};
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,2 +0,0 @@
|
|||
/*! layer弹层组件拓展类 */
|
||||
;!function(){layer.use("skin/layer.ext.css",function(){layer.layui_layer_extendlayerextjs=!0});var a=layer.cache||{},b=function(b){return a.skin?" "+a.skin+" "+a.skin+"-"+b:""};layer.prompt=function(a,c){a=a||{},"function"==typeof a&&(c=a);var d,e=2==a.formType?'<textarea class="layui-layer-input">'+(a.value||"")+"</textarea>":function(){return'<input type="'+(1==a.formType?"password":"text")+'" class="layui-layer-input" value="'+(a.value||"")+'">'}();return layer.open($.extend({btn:["确定","取消"],content:e,skin:"layui-layer-prompt"+b("prompt"),success:function(a){d=a.find(".layui-layer-input"),d.focus()},yes:function(b){var e=d.val();""===e?d.focus():e.length>(a.maxlength||500)?layer.tips("最多输入"+(a.maxlength||500)+"个字数",d,{tips:1}):c&&c(e,b,d)}},a))},layer.tab=function(a){a=a||{};var c=a.tab||{};return layer.open($.extend({type:1,skin:"layui-layer-tab"+b("tab"),title:function(){var a=c.length,b=1,d="";if(a>0)for(d='<span class="layui-layer-tabnow">'+c[0].title+"</span>";a>b;b++)d+="<span>"+c[b].title+"</span>";return d}(),content:'<ul class="layui-layer-tabmain">'+function(){var a=c.length,b=1,d="";if(a>0)for(d='<li class="layui-layer-tabli xubox_tab_layer">'+(c[0].content||"no content")+"</li>";a>b;b++)d+='<li class="layui-layer-tabli">'+(c[b].content||"no content")+"</li>";return d}()+"</ul>",success:function(a){var b=a.find(".layui-layer-title").children(),c=a.find(".layui-layer-tabmain").children();b.on("mousedown",function(a){a.stopPropagation?a.stopPropagation():a.cancelBubble=!0;var b=$(this),d=b.index();b.addClass("layui-layer-tabnow").siblings().removeClass("layui-layer-tabnow"),c.eq(d).show().siblings().hide()})}},a))},layer.photos=function(a,c,d){function e(a,b,c){var d=new Image;d.onload=function(){d.onload=null,b(d)},d.onerror=function(a){d.onerror=null,c(a)},d.src=a}var f={};if(a=a||{},a.photos){var g=a.photos.constructor===Object,h=g?a.photos:{},i=h.data||[],j=h.start||0;if(f.imgIndex=j+1,g){if(0===i.length)return void layer.msg("没有图片")}else{var k=$(a.photos),l=k.find(a.img||"img");if(0===l.length)return;if(c||k.find(h.img||"img").each(function(b){var c=$(this);i.push({alt:c.attr("alt"),pid:c.attr("layer-pid"),src:c.attr("layer-src")||c.attr("src"),thumb:c.attr("src")}),c.on("click",function(){layer.photos($.extend(a,{photos:{start:b,data:i,tab:a.tab},full:a.full}),!0)})}),!c)return}f.imgprev=function(a){f.imgIndex--,f.imgIndex<1&&(f.imgIndex=i.length),f.tabimg(a)},f.imgnext=function(a,b){f.imgIndex++,f.imgIndex>i.length&&(f.imgIndex=1,b)||f.tabimg(a)},f.keyup=function(a){if(!f.end){var b=a.keyCode;a.preventDefault(),37===b?f.imgprev(!0):39===b?f.imgnext(!0):27===b&&layer.close(f.index)}},f.tabimg=function(b){i.length<=1||(h.start=f.imgIndex-1,layer.close(f.index),layer.photos(a,!0,b))},f.event=function(){f.bigimg.hover(function(){f.imgsee.show()},function(){f.imgsee.hide()}),f.bigimg.find(".layui-layer-imgprev").on("click",function(a){a.preventDefault(),f.imgprev()}),f.bigimg.find(".layui-layer-imgnext").on("click",function(a){a.preventDefault(),f.imgnext()}),$(document).on("keyup",f.keyup)},f.loadi=layer.load(1,{shade:"shade"in a?!1:.9,scrollbar:!1}),e(i[j].src,function(c){layer.close(f.loadi),f.index=layer.open($.extend({type:1,area:function(){var b=[c.width,c.height],d=[$(window).width()-100,$(window).height()-100];return!a.full&&b[0]>d[0]&&(b[0]=d[0],b[1]=b[0]*d[1]/b[0]),[b[0]+"px",b[1]+"px"]}(),title:!1,shade:.9,shadeClose:!0,closeBtn:!1,move:".layui-layer-phimg img",moveType:1,scrollbar:!1,moveOut:!0,shift:5*Math.random()|0,skin:"layui-layer-photos"+b("photos"),content:'<div class="layui-layer-phimg"><img src="'+i[j].src+'" alt="'+(i[j].alt||"")+'" layer-pid="'+i[j].pid+'"><div class="layui-layer-imgsee">'+(i.length>1?'<span class="layui-layer-imguide"><a href="javascript:;" class="layui-layer-iconext layui-layer-imgprev"></a><a href="javascript:;" class="layui-layer-iconext layui-layer-imgnext"></a></span>':"")+'<div class="layui-layer-imgbar" style="display:'+(d?"block":"")+'"><span class="layui-layer-imgtit"><a href="javascript:;">'+(i[j].alt||"")+"</a><em>"+f.imgIndex+"/"+i.length+"</em></span></div></div></div>",success:function(b,c){f.bigimg=b.find(".layui-layer-phimg"),f.imgsee=b.find(".layui-layer-imguide,.layui-layer-imgbar"),f.event(b),a.tab&&a.tab(i[j],b)},end:function(){f.end=!0,$(document).off("keyup",f.keyup)}},a))},function(){layer.close(f.loadi),layer.msg("当前图片地址异常<br>是否继续查看下一张?",{time:3e4,btn:["下一张","不看了"],yes:function(){i.length>1&&f.imgnext(!0,!0)}})})}}}();
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,8 +0,0 @@
|
|||
/*!
|
||||
|
||||
@Name: layer拓展样式
|
||||
@Date: 2012.12.13
|
||||
@Author: 贤心
|
||||
@blog: sentsin.com
|
||||
|
||||
*/.layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span{text-overflow:ellipsis;white-space:nowrap}.layui-layer-iconext{background:url(default/icon-ext.png) no-repeat}html #layui_layer_skinlayerextcss{display:none;position:absolute;width:1989px}.layui-layer-prompt .layui-layer-input{display:block;width:220px;height:30px;margin:0 auto;line-height:30px;padding:0 5px;border:1px solid #ccc;box-shadow:1px 1px 5px rgba(0,0,0,.1) inset;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;border-bottom:1px solid #ccc;background-color:#eee;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:260px;padding:0 20px;text-align:center;cursor:default;overflow:hidden}.layui-layer-tab .layui-layer-title span.layui-layer-tabnow{height:43px;border-left:1px solid #ccc;border-right:1px solid #ccc;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.xubox_tab_layer{display:block}.xubox_tabclose{position:absolute;right:10px;top:5px;cursor:pointer}.layui-layer-photos{-webkit-animation-duration:1s;animation-duration:1s;background:url(default/xubox_loading1.gif) center center no-repeat #000}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgbar,.layui-layer-imguide{display:none}.layui-layer-imgnext,.layui-layer-imgprev{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:0;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px;_background-position:-70px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px;_background-position:-120px -5px}.layui-layer-imgnext{right:10px;_right:8px;background-position:-5px -50px;_background-position:-70px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px;_background-position:-120px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:rgba(0,0,0,.8);background-color:#000\9;filter:Alpha(opacity=80);color:#fff;overflow:hidden;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;overflow:hidden;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}
|
|
@ -39,10 +39,23 @@
|
|||
<i class="fa fa-desktop"></i><span class="nav-label">{% trans 'Terminal' %}</span><span class="label label-info pull-right"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li id="">
|
||||
<a href="">
|
||||
<i class="fa fa-files-o"></i><span class="nav-label">{% trans 'Audits' %}</span><span class="label label-info pull-right"></span>
|
||||
</a>
|
||||
<li id="audits">
|
||||
<a href="#"><i class="fa fa-files-o"></i> <span class="nav-label">{% trans 'Audits' %}</span><span class="fa arrow"></span></a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li id="proxy-log">
|
||||
<a href="{% url 'audits:proxy-log-list' %}">{% trans 'Proxy log' %}</a>
|
||||
</li>
|
||||
<li id="command-log">
|
||||
<a href="{% url 'audits:command-log-list' %}">{% trans 'Command log' %}</a>
|
||||
</li>
|
||||
<li id="login">
|
||||
<a href="{% url 'perms:asset-permission-list' %}">{% trans 'Login log' %}</a>
|
||||
</li>
|
||||
<li id="admin">
|
||||
<a href="{% url 'perms:asset-permission-list' %}">{% trans 'Admin log' %}</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
<li id="">
|
||||
<a href="#">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
from rest_framework.generics import ListCreateAPIView, CreateAPIView
|
||||
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
|
||||
from rest_framework.views import APIView, Response
|
||||
from rest_framework.permissions import AllowAny
|
||||
|
||||
|
@ -11,7 +11,7 @@ from .serializers import TerminalSerializer, TerminalHeatbeatSerializer
|
|||
from .hands import IsSuperUserOrTerminalUser
|
||||
|
||||
|
||||
class TerminalApi(ListCreateAPIView):
|
||||
class TerminalCreateListApi(ListCreateAPIView):
|
||||
queryset = Terminal.objects.all()
|
||||
serializer_class = TerminalSerializer
|
||||
permission_classes = (AllowAny,)
|
||||
|
@ -21,26 +21,32 @@ class TerminalApi(ListCreateAPIView):
|
|||
if name:
|
||||
terminal = get_object_or_none(Terminal, name=name)
|
||||
if terminal:
|
||||
if terminal.is_accepted and terminal.is_active:
|
||||
if terminal.is_active:
|
||||
return Response(data={'data': {'name': name, 'id': terminal.id},
|
||||
'msg': 'Success'},
|
||||
status=200)
|
||||
else:
|
||||
return Response(data={'data': {'name': name, 'ip': terminal.ip},
|
||||
'msg': 'Need admin accept or active it'},
|
||||
'msg': 'Need admin active it'},
|
||||
status=203)
|
||||
|
||||
else:
|
||||
ip = request.META.get('X-Real-IP') or request.META.get('REMOTE_ADDR')
|
||||
terminal = Terminal.objects.create(name=name, ip=ip)
|
||||
return Response(data={'data': {'name': name, 'ip': terminal.ip},
|
||||
'msg': 'Need admin accept or active it'},
|
||||
status=204)
|
||||
'msg': 'Need admin active it'},
|
||||
status=201)
|
||||
else:
|
||||
return Response(data={'msg': 'Secrete key invalid'}, status=401)
|
||||
|
||||
|
||||
class TerminalHeatbeatApi(CreateAPIView):
|
||||
class TerminalHeatbeatApi(ListCreateAPIView):
|
||||
model = TerminalHeatbeat
|
||||
serializer_class = TerminalHeatbeatSerializer
|
||||
permission_classes = (IsSuperUserOrTerminalUser,)
|
||||
|
||||
|
||||
class TerminalApiDetailUpdateDetailApi(RetrieveUpdateDestroyAPIView):
|
||||
queryset = Terminal.objects.all()
|
||||
serializer_class = TerminalSerializer
|
||||
permission_classes = (IsSuperUserOrTerminalUser,)
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
#
|
||||
|
||||
from django import forms
|
||||
from django.utils.translation import ungettext_lazy as _
|
||||
|
||||
from .models import Terminal
|
||||
|
||||
|
||||
class TerminalForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Terminal
|
||||
fields = ['name', 'ip', 'is_active', 'type', 'url', 'comment']
|
||||
help_texts = {
|
||||
'url': 'Example: ssh://192.168.1.1:22 or http://jms.jumpserver.org, that user login'
|
||||
}
|
||||
|
|
@ -2,4 +2,5 @@
|
|||
#
|
||||
|
||||
from users.backends import IsSuperUserOrTerminalUser
|
||||
from audits.models import ProxyLog
|
||||
|
||||
|
|
|
@ -15,13 +15,10 @@ class Terminal(models.Model):
|
|||
ip = models.GenericIPAddressField(verbose_name=_('From ip'))
|
||||
is_active = models.BooleanField(default=False, verbose_name=_('Is active'))
|
||||
is_bound_ip = models.BooleanField(default=False, verbose_name=_('Is bound ip'))
|
||||
heatbeat_interval = models.IntegerField(default=60, verbose_name=_('Heatbeat interval'))
|
||||
type = models.CharField(choices=TYPE_CHOICES, max_length=2, verbose_name=_('Terminal type'))
|
||||
url = models.CharField(max_length=100, verbose_name=_('URL to login'))
|
||||
mail_to = models.ManyToManyField(User, verbose_name=_('Mail to'))
|
||||
is_accepted = models.BooleanField(default=False, verbose_name=_('Is accepted'))
|
||||
date_created = models.DateTimeField(auto_now_add=True)
|
||||
comment = models.TextField(verbose_name=_('Comment'))
|
||||
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
||||
|
||||
def is_valid(self):
|
||||
return self.is_active and self.is_accepted
|
||||
|
@ -36,7 +33,7 @@ class Terminal(models.Model):
|
|||
|
||||
class Meta:
|
||||
db_table = 'terminal'
|
||||
ordering = ['name']
|
||||
ordering = ['is_active']
|
||||
|
||||
|
||||
class TerminalHeatbeat(models.Model):
|
||||
|
|
|
@ -4,13 +4,20 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from .models import Terminal, TerminalHeatbeat
|
||||
from .hands import ProxyLog
|
||||
|
||||
|
||||
class TerminalSerializer(serializers.ModelSerializer):
|
||||
proxy_amount = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Terminal
|
||||
fields = ['name', 'ip', 'type', 'url', 'comment', 'is_active', 'is_accepted',
|
||||
'get_type_display']
|
||||
fields = ['id', 'name', 'ip', 'type', 'url', 'comment', 'is_active',
|
||||
'get_type_display', 'proxy_amount']
|
||||
|
||||
@staticmethod
|
||||
def get_proxy_amount(obj):
|
||||
return ProxyLog.objects.filter(terminal=obj.name, is_finished=False).count()
|
||||
|
||||
|
||||
class TerminalHeatbeatSerializer(serializers.ModelSerializer):
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<th class="text-center">{% trans 'Name' %}</th>
|
||||
<th class="text-center">{% trans 'IP' %}</th>
|
||||
<th class="text-center">{% trans 'Type' %}</th>
|
||||
<th class="text-center">{% trans 'url' %}</th>
|
||||
<th class="text-center">{% trans 'proxy_amount' %}</th>
|
||||
<th class="text-center">{% trans 'Active' %}</th>
|
||||
<th class="text-center">{% trans 'Action' %}</th>
|
||||
</tr>
|
||||
|
@ -36,44 +36,46 @@
|
|||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
||||
{% block content_bottom_left %}{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/jquery.form.min.js' %}"></script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
var options = {
|
||||
ele: $('#terminal_list_table'),
|
||||
{# columnDefs: [#}
|
||||
{# {targets: 1, createdCell: function (td, cellData, rowData) {#}
|
||||
{# var detail_btn = '<a href="{% url "users:user-detail" pk=99991937 %}">' + cellData + '</a>';#}
|
||||
{# $(td).html(detail_btn.replace('99991937', rowData.id));#}
|
||||
{# }}#}
|
||||
{# {targets: 4, createdCell: function (td, cellData) {#}
|
||||
{# var innerHtml = cellData.length > 8 ? cellData.substring(0, 8) + '...': cellData;#}
|
||||
{# $(td).html('<a href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</a>');#}
|
||||
{# }},#}
|
||||
{# {targets: 6, 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: 7, createdCell: function (td, cellData, rowData) {#}
|
||||
{# var update_btn = '<a href="{% url "users:user-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('99991937', cellData);#}
|
||||
{# var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_user_delete" data-uid="99991937">{% trans "Delete" %}</a>'.replace('99991937', cellData);#}
|
||||
{# if (rowData.id === 1) {#}
|
||||
{# $(td).html(update_btn)#}
|
||||
{# } else {#}
|
||||
{# $(td).html(update_btn + del_btn)#}
|
||||
{# }}],#}
|
||||
{# ],#}
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a href="{% url "users:user-detail" pk=99991937 %}">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('99991937', rowData.id));
|
||||
}},
|
||||
{targets: 5, 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: 6, createdCell: function (td, cellData, rowData) {
|
||||
console.log(rowData.name);
|
||||
var update_btn = '<a href="{% url "terminal:terminal-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
|
||||
.replace('99991937', cellData);
|
||||
var delete_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_delete" data-uid="99991937" data-name="99991938">{% trans "Delete" %}</a>'
|
||||
.replace('99991937', cellData)
|
||||
.replace('99991938', rowData.name);
|
||||
$(td).html(update_btn + delete_btn)
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "terminal:terminal-list-create-api" %}',
|
||||
columns: [{data: function(){return ""}}, {data: "name" }, {data: "ip" }, {data: "get_type_display" }, {data: "url" },
|
||||
{data: "is_active" }, {data: "ip"}],
|
||||
columns: [{data: function(){return ""}}, {data: "name" }, {data: "ip" }, {data: "get_type_display" },
|
||||
{data: "proxy_amount"}, {data: "is_active" }, {data: "id"}],
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
jumpserver.initDataTable(options);
|
||||
}).on('click', '.btn_delete', function(){
|
||||
var $this = $(this);
|
||||
var uid = $this.data('uid');
|
||||
var name = $(this).data('name');
|
||||
var the_url = '{% url "terminal:terminal-detail-update-delete-api" pk=99991937 %}'.replace('99991937', uid);
|
||||
objectDelete($this, name, the_url)
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load bootstrap %}
|
||||
{% block custom_head_css_js %}
|
||||
<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/datepicker/datepicker3.css" %}" rel="stylesheet">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<h5>{{ action }}</h5>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
</a>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</a>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<h3>{% trans 'Info' %}</h3>
|
||||
{{ form.name|bootstrap_horizontal }}
|
||||
{{ form.ip|bootstrap_horizontal }}
|
||||
{{ form.type|bootstrap_horizontal }}
|
||||
{{ form.url|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Other' %}</h3>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.is_active.id_for_label }}" class="col-sm-2 control-label">{% trans 'Active' %}</label>
|
||||
<div class="col-sm-8">
|
||||
{{ form.is_active}}
|
||||
</div>
|
||||
</div>
|
||||
{{ form.comment|bootstrap_horizontal }}
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-4 col-sm-offset-2">
|
||||
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
|
||||
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/plugins/datapicker/bootstrap-datepicker.js' %}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2();
|
||||
|
||||
$('.input-group.date').datepicker({
|
||||
format: "yyyy-mm-dd",
|
||||
todayBtn: "linked",
|
||||
keyboardNavigation: false,
|
||||
forceParse: false,
|
||||
calendarWeeks: true,
|
||||
autoclose: true
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -11,9 +11,12 @@ app_name = 'terminal'
|
|||
|
||||
urlpatterns = [
|
||||
url(r'^terminal$', views.TerminalListView.as_view(), name='terminal-list'),
|
||||
url(r'^terminal/(?P<pk>\d+)/update$', views.TerminalUpdateView.as_view(), name='terminal-update'),
|
||||
]
|
||||
|
||||
urlpatterns += [
|
||||
url(r'^v1/terminal/$', api.TerminalApi.as_view(), name='terminal-list-create-api'),
|
||||
url(r'^v1/terminal/$', api.TerminalCreateListApi.as_view(), name='terminal-list-create-api'),
|
||||
url(r'^v1/terminal/(?P<pk>\d+)/$', api.TerminalApiDetailUpdateDetailApi.as_view(),
|
||||
name='terminal-detail-update-delete-api'),
|
||||
url(r'^v1/terminal-heatbeat/$', api.TerminalHeatbeatApi.as_view(), name='terminal-heatbeat-api'),
|
||||
]
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
#
|
||||
|
||||
from django.views.generic import ListView
|
||||
from django.views.generic import ListView, UpdateView, DeleteView
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.urls import reverse_lazy
|
||||
|
||||
from .models import Terminal
|
||||
from .forms import TerminalForm
|
||||
|
||||
|
||||
class TerminalListView(ListView):
|
||||
|
@ -15,3 +17,21 @@ class TerminalListView(ListView):
|
|||
context = super(TerminalListView, self).get_context_data(**kwargs)
|
||||
context.update({'app': _('Terminal'), 'action': _('Terminal list')})
|
||||
return context
|
||||
|
||||
|
||||
class TerminalUpdateView(UpdateView):
|
||||
model = Terminal
|
||||
form_class = TerminalForm
|
||||
template_name = 'terminal/terminal_update.html'
|
||||
success_url = reverse_lazy('terminal:terminal-list')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(TerminalUpdateView, self).get_context_data(**kwargs)
|
||||
context.update({'app': _('Terminal'), 'action': _('Update terminal')})
|
||||
return context
|
||||
|
||||
|
||||
class TerminalDeleteView(DeleteView):
|
||||
model = Terminal
|
||||
template_name = 'assets/delete_confirm.html'
|
||||
success_url = reverse_lazy('terminal:terminal-list')
|
|
@ -6,6 +6,7 @@ from rest_framework.compat import is_authenticated
|
|||
from django.utils.translation import ugettext as _
|
||||
|
||||
from common.utils import unsign, get_object_or_none
|
||||
|
||||
from .hands import Terminal
|
||||
|
||||
|
||||
|
@ -40,7 +41,7 @@ class TerminalAuthentication(authentication.BaseAuthentication):
|
|||
else:
|
||||
raise exceptions.AuthenticationFailed(_('Invalid sign.'))
|
||||
|
||||
if not terminal.is_active:
|
||||
if not terminal or not terminal.is_active:
|
||||
raise exceptions.AuthenticationFailed(_('Terminal inactive or deleted.'))
|
||||
terminal.is_authenticated = True
|
||||
return terminal, None
|
||||
|
|
|
@ -10,6 +10,6 @@
|
|||
:license: GPL v2, see LICENSE for more details.
|
||||
"""
|
||||
|
||||
from terminal.models import Terminal
|
||||
from perms.models import AssetPermission
|
||||
from perms.utils import get_user_granted_assets, get_user_granted_asset_groups
|
||||
from terminal.models import Terminal
|
|
@ -10,12 +10,12 @@
|
|||
<th class="text-center">
|
||||
<div class="checkbox checkbox-default"><input id="" type="checkbox" class="ipt_check_all"><label></label></div>
|
||||
</th>
|
||||
<th class="text-center">{% trans 'Name' %}</a></th>
|
||||
<th class="text-center">{% trans 'Username' %}</a></th>
|
||||
<th class="text-center">{% trans 'Name' %}</th>
|
||||
<th class="text-center">{% trans 'Username' %}</th>
|
||||
<th class="text-center">{% trans 'Role' %}</th>
|
||||
<th class="text-center">{% trans 'User group' %}</th>
|
||||
<th class="text-center">{% trans 'Asset num' %}</th>
|
||||
<th class="text-center">{% trans 'Active' %}</a></th>
|
||||
<th class="text-center">{% trans 'Active' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
|
|
|
@ -92,7 +92,7 @@ $(document).ready(function(){
|
|||
jumpserver.initDataTable(options);
|
||||
}).on('click', '#btn_bulk_update', function(){
|
||||
var action = $('#slct_bulk_update').val();
|
||||
var $data_table = $('#user_list_table').DataTable()
|
||||
var $data_table = $('#user_list_table').DataTable();
|
||||
var id_list = [];
|
||||
var plain_id_list = [];
|
||||
$data_table.rows({selected: true}).every(function(){
|
||||
|
@ -101,7 +101,7 @@ $(document).ready(function(){
|
|||
});
|
||||
if (id_list === []) {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
var the_url = "{% url 'users:user-bulk-update-api' %}";
|
||||
function doDeactive() {
|
||||
var body = $.each(id_list, function(index, user_object) {
|
||||
|
|
Loading…
Reference in New Issue