Commit dfcbdb0c authored by ibuler's avatar ibuler

[Update] 修改command导出和搜索

parent 5f6af8c0
......@@ -44,8 +44,12 @@ app_view_patterns = [
if settings.XPACK_ENABLED:
app_view_patterns.append(path('xpack/', include('xpack.urls.view_urls', namespace='xpack')))
api_v1.append(path('xpack/v1/', include('xpack.urls.api_urls', namespace='api-xpack')))
app_view_patterns.append(
path('xpack/', include('xpack.urls.view_urls', namespace='xpack'))
)
api_v1.append(
path('xpack/v1/', include('xpack.urls.api_urls', namespace='api-xpack'))
)
js_i18n_patterns = i18n_patterns(
path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'),
......
......@@ -475,6 +475,7 @@ jumpserver.initDataTable = function (options) {
dom: options.dom || '<"#uc.pull-left">flt<"row m-t"<"col-md-8"<"#op.col-md-6"><"col-md-6 text-center"i>><"col-md-4"p>>',
order: options.order || [],
// select: options.select || 'multi',
searchDelay: 800,
buttons: [],
columnDefs: columnDefs,
ajax: {
......@@ -574,6 +575,7 @@ jumpserver.initServerSideDataTable = function (options) {
columnDefs: columnDefs,
serverSide: true,
processing: true,
searchDelay: 800,
ajax: {
url: options.ajax_url ,
error: function(jqXHR, textStatus, errorThrown) {
......@@ -1103,3 +1105,12 @@ function formatDateAsCN(d) {
var date = new Date(d);
return date.toISOString().replace("T", " ").replace(/\..*/, "");
}
function getUrlParams(url) {
url = url.split("?");
let params = "";
if (url.length === 2){
params = url[1];
}
return params
}
\ No newline at end of file
......@@ -2,4 +2,5 @@
#
from .terminal import *
from .session import *
from .command import *
from .task import *
# -*- coding: utf-8 -*-
#
import time
from django.utils import timezone
from django.shortcuts import HttpResponse
from rest_framework.pagination import LimitOffsetPagination
from rest_framework import viewsets
from rest_framework import generics
from rest_framework.response import Response
from django.template import loader
from common.permissions import IsOrgAdminOrAppUser, IsAuditor
from common.utils import get_logger
from ..backends import (
get_command_storage, get_multi_command_storage,
SessionCommandSerializer,
)
logger = get_logger(__name__)
__all__ = ['CommandViewSet', 'CommandExportApi']
class CommandQueryMixin:
command_store = get_command_storage()
pagination_class = LimitOffsetPagination
permission_classes = [IsOrgAdminOrAppUser | IsAuditor]
filter_fields = [
"asset", "system_user", "user", "input", "session",
]
default_days_ago = 5
def get_queryset(self):
date_from, date_to = self.get_date_range()
multi_command_storage = get_multi_command_storage()
queryset = multi_command_storage.filter(date_from=date_from, date_to=date_to)
return queryset
def get_filter_fields(self):
fields = self.filter_fields
fields.extend(["date_from", "date_to"])
return fields
def get_date_range(self):
now = timezone.now()
days_ago = now - timezone.timedelta(days=self.default_days_ago)
default_start_st = days_ago.timestamp()
default_end_st = now.timestamp()
query_params = self.request.query_params
date_from_st = query_params.get("date_from") or default_start_st
date_to_st = query_params.get("date_to") or default_end_st
return float(date_from_st), float(date_to_st)
class CommandViewSet(CommandQueryMixin, viewsets.ModelViewSet):
"""接受app发送来的command log, 格式如下
{
"user": "admin",
"asset": "localhost",
"system_user": "web",
"session": "xxxxxx",
"input": "whoami",
"output": "d2hvbWFp", # base64.b64encode(s)
"timestamp": 1485238673.0
}
"""
command_store = get_command_storage()
serializer_class = SessionCommandSerializer
def create(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data, many=True)
if serializer.is_valid():
ok = self.command_store.bulk_save(serializer.validated_data)
if ok:
return Response("ok", status=201)
else:
return Response("Save error", status=500)
else:
msg = "Command not valid: {}".format(serializer.errors)
logger.error(msg)
return Response({"msg": msg}, status=401)
class CommandExportApi(CommandQueryMixin, generics.ListAPIView):
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
template = 'terminal/command_report.html'
context = {
'queryset': queryset,
'total_count': len(queryset),
'now': time.time(),
}
content = loader.render_to_string(template, context, request)
content_type = 'application/octet-stream'
response = HttpResponse(content, content_type)
filename = 'command-report-{}.html'.format(int(time.time()))
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
return response
# -*- coding: utf-8 -*-
#
import logging
import os
from django.shortcuts import get_object_or_404
from django.core.files.storage import default_storage
from django.http import HttpResponseNotFound
from django.conf import settings
from django.utils import timezone
from rest_framework.pagination import LimitOffsetPagination
from rest_framework import viewsets
from rest_framework.response import Response
......@@ -15,16 +13,15 @@ from rest_framework_bulk import BulkModelViewSet
import jms_storage
from common.utils import is_uuid
from common.utils import is_uuid, get_logger
from common.permissions import IsOrgAdminOrAppUser, IsAuditor
from ..hands import SystemUser
from ..models import Terminal, Session
from ..models import Session
from .. import serializers
from ..backends import get_command_storage, get_multi_command_storage, \
SessionCommandSerializer
__all__ = ['SessionViewSet', 'SessionReplayViewSet', 'CommandViewSet']
logger = logging.getLogger(__file__)
__all__ = ['SessionViewSet', 'SessionReplayViewSet',]
logger = get_logger(__name__)
class SessionViewSet(BulkModelViewSet):
......@@ -32,15 +29,7 @@ class SessionViewSet(BulkModelViewSet):
serializer_class = serializers.SessionSerializer
pagination_class = LimitOffsetPagination
permission_classes = (IsOrgAdminOrAppUser | IsAuditor, )
def get_queryset(self):
queryset = super().get_queryset()
terminal_id = self.kwargs.get("terminal", None)
if terminal_id:
terminal = get_object_or_404(Terminal, id=terminal_id)
queryset = queryset.filter(terminal=terminal)
return queryset
return queryset
filter_fields = ["user", "asset", "system_user", "terminal"]
def get_object(self):
# 解决guacamole更新session时并发导致幽灵会话的问题
......@@ -60,63 +49,6 @@ class SessionViewSet(BulkModelViewSet):
return super().perform_create(serializer)
class CommandViewSet(viewsets.ModelViewSet):
"""接受app发送来的command log, 格式如下
{
"user": "admin",
"asset": "localhost",
"system_user": "web",
"session": "xxxxxx",
"input": "whoami",
"output": "d2hvbWFp", # base64.b64encode(s)
"timestamp": 1485238673.0
}
"""
command_store = get_command_storage()
serializer_class = SessionCommandSerializer
pagination_class = LimitOffsetPagination
permission_classes = [IsOrgAdminOrAppUser | IsAuditor]
filter_fields = [
"asset", "system_user", "user", "input", "session",
]
default_days_ago = 5
def get_queryset(self):
date_from, date_to = self.get_date_range()
multi_command_storage = get_multi_command_storage()
queryset = multi_command_storage.filter(date_from=date_from, date_to=date_to)
return queryset
def get_filter_fields(self):
fields = self.filter_fields
fields.extend(["date_from", "date_to"])
return fields
def get_date_range(self):
now = timezone.now()
days_ago = now - timezone.timedelta(days=self.default_days_ago)
default_start_st = days_ago.timestamp()
default_end_st = now.timestamp()
query_params = self.request.query_params
date_from_st = query_params.get("date_from") or default_start_st
date_to_st = query_params.get("date_to") or default_end_st
return int(date_from_st), int(date_to_st)
def create(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data, many=True)
if serializer.is_valid():
ok = self.command_store.bulk_save(serializer.validated_data)
if ok:
return Response("ok", status=201)
else:
return Response("Save error", status=500)
else:
msg = "Command not valid: {}".format(serializer.errors)
logger.error(msg)
return Response({"msg": msg}, status=401)
class SessionReplayViewSet(viewsets.ViewSet):
serializer_class = serializers.ReplaySerializer
permission_classes = (IsOrgAdminOrAppUser,)
......
......@@ -80,7 +80,7 @@ $(document).ready(function () {
table = initTable().on("init", function () {
var dateFromRef = $("#date_from");
var dateToRef = $("#date_to");
let options = {
var options = {
format: "yyyy-mm-dd",
todayBtn: "linked",
keyboardNavigation: false,
......@@ -90,16 +90,15 @@ $(document).ready(function () {
language: navigator.language || "en",
};
dateFromRef.datepicker(options).on("changeDate", function () {
let date = new Date($(this).val() + ' 0:0:0');
let url = table.ajax.url();
var date = new Date($(this).val() + ' 0:0:0');
var url = table.ajax.url();
url = setUrlParam(url, "date_from", date.getTime()/1000);
table.ajax.url(url);
table.ajax.reload();
console.log("On change")
});
dateToRef.datepicker(options).on("changeDate", function () {
let date = new Date($(this).val() + ' 23:59:59');
let url = table.ajax.url();
var date = new Date($(this).val() + ' 23:59:59');
var url = table.ajax.url();
url = setUrlParam(url, "date_to", date.getTime()/1000);
table.ajax.url(url);
table.ajax.reload();
......@@ -107,15 +106,11 @@ $(document).ready(function () {
});
})
.on('click', '#btn_bulk_update', function(){
var action = $('#slct_bulk_update').val();
var param_action = '&action=' + action;
var local_params = window.location.search;
if(!local_params){
param_action = '?action=' + action;
}
var params = local_params + param_action;
var pathname = window.location.pathname + 'export/';
var url = pathname + params;
// var action = $('#slct_bulk_update').val();
var params = getUrlParams(table.ajax.url());
var exportPath = "{% url 'api-terminal:command-export' %}";
var url = exportPath + "?" + params;
window.open(url);
}).on("click", '#command_table_filter input', function (e) {
e.preventDefault();
......@@ -182,8 +177,13 @@ function format(d) {
return output
}
var commandListUrl = '{% url "api-terminal:command-list" %}';
var dateFrom = "{{ date_from.timestamp }}";
var dateTo = "{{ date_to.timestamp }}";
function initTable() {
commandListUrl = setUrlParam(commandListUrl, "date_from", dateFrom);
commandListUrl = setUrlParam(commandListUrl, "date_to", dateTo);
var options = {
ele: $('#command_table'),
columnDefs: [
......@@ -202,7 +202,7 @@ function initTable() {
}},
],
toggle: true,
ajax_url: '{% url "api-terminal:command-list" %}',
ajax_url: commandListUrl,
columns: [
{data: "id"}, {data: "input", orderable: false}, {data: "user", orderable: false},
{data: "asset"}, {data: "system_user"},
......
......@@ -26,6 +26,7 @@ urlpatterns = [
path('terminal/<uuid:terminal>/access-key/', api.TerminalTokenApi.as_view(),
name='terminal-access-key'),
path('terminal/config/', api.TerminalConfig.as_view(), name='terminal-config'),
path('commands/export/', api.CommandExportApi.as_view(), name="command-export")
# v2: get session's replay
# path('v2/sessions/<uuid:pk>/replay/',
# api.SessionReplayV2ViewSet.as_view({'get': 'retrieve'}),
......
......@@ -25,6 +25,5 @@ urlpatterns = [
# Command view
path('command/', views.CommandListView.as_view(), name='command-list'),
path('command/export/', views.CommandExportView.as_view(), name='command-export')
]
......@@ -9,7 +9,7 @@ from .const import USERS_CACHE_KEY, ASSETS_CACHE_KEY, SYSTEM_USER_CACHE_KEY
def get_session_asset_list():
return Asset.objects.values_list()
return Asset.objects.values_list('hostname', flat=True)
def get_session_user_list():
......
......@@ -10,10 +10,9 @@ import time
from common.mixins import DatetimeSearchMixin
from common.permissions import PermissionsMixin, IsOrgAdmin, IsAuditor
from ..models import Command
from ..backends import get_multi_command_storage
__all__ = ['CommandListView', 'CommandExportView']
__all__ = ['CommandListView']
common_storage = get_multi_command_storage()
......@@ -33,45 +32,3 @@ class CommandListView(DatetimeSearchMixin, PermissionsMixin, TemplateView):
kwargs.update(context)
return super().get_context_data(**kwargs)
class CommandExportView(DatetimeSearchMixin, PermissionsMixin, View):
model = Command
command = user = asset = system_user = action = ''
date_from = date_to = None
permission_classes = [IsOrgAdmin | IsAuditor]
def get(self, request, *args, **kwargs):
queryset = self.get_queryset()
template = 'terminal/command_report.html'
context = {
'queryset': queryset,
'total_count': len(queryset),
'now': time.time(),
}
content = loader.render_to_string(template, context, request)
content_type = 'application/octet-stream'
response = HttpResponse(content, content_type)
filename = 'command-report-{}.html'.format(int(time.time()))
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
return response
def get_queryset(self):
self.get_date_range()
self.action = self.request.GET.get('action', '')
self.command = self.request.GET.get('command', '')
self.user = self.request.GET.get("user", '')
self.asset = self.request.GET.get('asset', '')
self.system_user = self.request.GET.get('system_user', '')
filter_kwargs = dict()
filter_kwargs['date_from'] = self.date_from
filter_kwargs['date_to'] = self.date_to
if self.user:
filter_kwargs['user'] = self.user
if self.asset:
filter_kwargs['asset'] = self.asset
if self.system_user:
filter_kwargs['system_user'] = self.system_user
if self.command:
filter_kwargs['input'] = self.command
queryset = common_storage.filter(**filter_kwargs)
return queryset
......@@ -38,21 +38,11 @@ class SessionListView(PermissionsMixin, DatetimeSearchMixin, ListView):
filter_kwargs = dict()
filter_kwargs['date_start__gt'] = self.date_from
filter_kwargs['date_start__lt'] = self.date_to
if self.user:
filter_kwargs['user'] = self.user
if self.asset:
filter_kwargs['asset'] = self.asset
if self.system_user:
filter_kwargs['system_user'] = self.system_user
if filter_kwargs:
self.queryset = self.queryset.filter(**filter_kwargs)
return self.queryset
def get_context_data(self, **kwargs):
context = {
'user_list': utils.get_session_user_list(),
'asset_list': utils.get_session_asset_list(),
'system_user_list': utils.get_session_system_user_list(),
'asset_list': utils.get_session_asset_list()[:10],
'date_from': self.date_from,
'date_to': self.date_to,
'user': self.user,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment