Commit c3a54a89 authored by ibuler's avatar ibuler

[Update] 修改session

parent dfcbdb0c
# -*- coding: utf-8 -*-
#
from rest_framework import filters
from rest_framework.fields import DateTimeField
from rest_framework.serializers import ValidationError
import logging
__all__ = ["DatetimeRangeFilter"]
class DatetimeRangeFilter(filters.BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
if not hasattr(view, 'date_range_filter_fields'):
return queryset
try:
fields = dict(view.date_range_filter_fields)
except ValueError:
msg = "View {} datetime_filter_fields set is error".format(view.name)
logging.error(msg)
return queryset
kwargs = {}
for attr, date_range_keyword in fields.items():
if len(date_range_keyword) != 2:
continue
for i, v in enumerate(date_range_keyword):
value = request.query_params.get(v)
if not value:
continue
try:
field = DateTimeField()
value = field.to_internal_value(value)
if i == 0:
lookup = "__gte"
else:
lookup = "__lte"
kwargs[attr+lookup] = value
except ValidationError as e:
print(e)
continue
if kwargs:
queryset = queryset.filter(**kwargs)
return queryset
...@@ -38,8 +38,10 @@ class IDInFilterMixin(object): ...@@ -38,8 +38,10 @@ class IDInFilterMixin(object):
class IDInCacheFilterMixin(object): class IDInCacheFilterMixin(object):
def filter_queryset(self, queryset): def filter_queryset(self, queryset):
queryset = super(IDInCacheFilterMixin, self).filter_queryset(queryset) queryset = super().filter_queryset(queryset)
spm = self.request.query_params.get('spm') spm = self.request.query_params.get('spm')
if not spm:
return queryset
cache_key = KEY_CACHE_RESOURCES_ID.format(spm) cache_key = KEY_CACHE_RESOURCES_ID.format(spm)
resources_id = cache.get(cache_key) resources_id = cache.get(cache_key)
if resources_id and isinstance(resources_id, list): if resources_id and isinstance(resources_id, list):
......
...@@ -27,13 +27,14 @@ class BulkSerializerMixin(object): ...@@ -27,13 +27,14 @@ class BulkSerializerMixin(object):
if all((isinstance(self.root, BulkListSerializer), if all((isinstance(self.root, BulkListSerializer),
id_attr, id_attr,
request_method in ('PUT', 'PATCH'))): request_method in ('PUT', 'PATCH'))):
id_field = self.fields[id_attr] id_field = self.fields.get("id") or self.fields.get('pk')
if data.get("id"): if data.get("id"):
id_value = id_field.to_internal_value(data.get("id")) id_value = id_field.to_internal_value(data.get("id"))
else: else:
id_value = id_field.to_internal_value(data.get("pk")) id_value = id_field.to_internal_value(data.get("pk"))
print(">>>>>>>>>>>>>>>>>>>")
print(id_attr)
ret[id_attr] = id_value ret[id_attr] = id_value
return ret return ret
......
# -*- coding: utf-8 -*-
#
from .models import *
from .serializers import *
from .forms import *
from .api import *
# -*- coding: utf-8 -*-
#
from django.shortcuts import get_object_or_404
from rest_framework.viewsets import ModelViewSet
from rest_framework_bulk import BulkModelViewSet
from common.mixins import IDInCacheFilterMixin
from ..utils import set_to_root_org
from ..models import Organization
__all__ = [
'RootOrgViewMixin', 'OrgMembershipModelViewSetMixin', 'OrgModelViewSet',
'OrgBulkModelViewSet',
]
class RootOrgViewMixin:
def dispatch(self, request, *args, **kwargs):
set_to_root_org()
return super().dispatch(request, *args, **kwargs)
class OrgModelViewSet(IDInCacheFilterMixin, ModelViewSet):
def get_queryset(self):
return super().get_queryset().all()
class OrgBulkModelViewSet(IDInCacheFilterMixin, BulkModelViewSet):
def get_queryset(self):
return super().get_queryset().all()
class OrgMembershipModelViewSetMixin:
org = None
membership_class = None
lookup_field = 'user'
lookup_url_kwarg = 'user_id'
http_method_names = ['get', 'post', 'delete', 'head', 'options']
def dispatch(self, request, *args, **kwargs):
self.org = get_object_or_404(Organization, pk=kwargs.get('org_id'))
return super().dispatch(request, *args, **kwargs)
def get_serializer_context(self):
context = super().get_serializer_context()
context['org'] = self.org
return context
def get_queryset(self):
queryset = self.membership_class.objects.filter(organization=self.org)
return queryset
# -*- coding: utf-8 -*-
#
from django import forms
__all__ = ['OrgModelForm']
class OrgModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
if not hasattr(field, 'queryset'):
continue
model = field.queryset.model
field.queryset = model.objects.all()
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import traceback
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.shortcuts import redirect, get_object_or_404
from django import forms
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.http.response import HttpResponseForbidden
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator
from common.utils import get_logger from common.utils import get_logger
from common.validators import ProjectUniqueValidator from ..utils import (
from common.mixins import BulkSerializerMixin set_current_org, get_current_org, current_org,
from .utils import (
set_current_org, set_to_root_org, get_current_org, current_org,
get_current_org_id_for_serializer,
) )
from .models import Organization from ..models import Organization
logger = get_logger(__file__) logger = get_logger(__file__)
__all__ = [ __all__ = [
'OrgManager', 'OrgViewGenericMixin', 'OrgModelMixin', 'OrgModelForm', 'OrgManager', 'OrgModelMixin',
'RootOrgViewMixin', 'OrgMembershipSerializerMixin',
'OrgMembershipModelViewSetMixin', 'OrgResourceSerializerMixin',
'BulkOrgResourceSerializerMixin', 'BulkOrgResourceModelSerializer',
] ]
...@@ -124,93 +113,3 @@ class OrgModelMixin(models.Model): ...@@ -124,93 +113,3 @@ class OrgModelMixin(models.Model):
class Meta: class Meta:
abstract = True abstract = True
class OrgViewGenericMixin:
def dispatch(self, request, *args, **kwargs):
if current_org is None:
return redirect('orgs:switch-a-org')
if not current_org.can_admin_by(request.user):
if request.user.is_org_admin:
return redirect('orgs:switch-a-org')
return HttpResponseForbidden()
return super().dispatch(request, *args, **kwargs)
class RootOrgViewMixin:
def dispatch(self, request, *args, **kwargs):
set_to_root_org()
return super().dispatch(request, *args, **kwargs)
class OrgModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
if not hasattr(field, 'queryset'):
continue
model = field.queryset.model
field.queryset = model.objects.all()
class OrgMembershipSerializerMixin:
def run_validation(self, initial_data=None):
initial_data['organization'] = str(self.context['org'].id)
return super().run_validation(initial_data)
class OrgMembershipModelViewSetMixin:
org = None
membership_class = None
lookup_field = 'user'
lookup_url_kwarg = 'user_id'
http_method_names = ['get', 'post', 'delete', 'head', 'options']
def dispatch(self, request, *args, **kwargs):
self.org = get_object_or_404(Organization, pk=kwargs.get('org_id'))
return super().dispatch(request, *args, **kwargs)
def get_serializer_context(self):
context = super().get_serializer_context()
context['org'] = self.org
return context
def get_queryset(self):
queryset = self.membership_class.objects.filter(organization=self.org)
return queryset
class OrgResourceSerializerMixin(serializers.Serializer):
"""
通过API批量操作资源时, 自动给每个资源添加所需属性org_id的值为current_org_id
(同时为serializer.is_valid()对Model的unique_together校验做准备)
由于HiddenField字段不可读,API获取资产信息时获取不到org_id,
但是coco需要资产的org_id字段,所以修改为CharField类型
"""
org_id = serializers.ReadOnlyField(default=get_current_org_id_for_serializer, label=_("Organization"))
org_name = serializers.ReadOnlyField(label=_("Org name"))
def get_validators(self):
_validators = super().get_validators()
validators = []
for v in _validators:
if isinstance(v, UniqueTogetherValidator) \
and "org_id" in v.fields:
v = ProjectUniqueValidator(v.queryset, v.fields)
validators.append(v)
return validators
def get_field_names(self, declared_fields, info):
fields = super().get_field_names(declared_fields, info)
fields.extend(["org_id", "org_name"])
return fields
class BulkOrgResourceSerializerMixin(OrgResourceSerializerMixin, BulkSerializerMixin):
pass
class BulkOrgResourceModelSerializer(BulkOrgResourceSerializerMixin, serializers.ModelSerializer):
pass
# -*- coding: utf-8 -*-
#
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator
from common.validators import ProjectUniqueValidator
from common.mixins import BulkSerializerMixin
from ..utils import get_current_org_id_for_serializer
__all__ = [
"OrgResourceSerializerMixin", "BulkOrgResourceSerializerMixin",
"BulkOrgResourceModelSerializer", "OrgMembershipSerializerMixin"
]
class OrgResourceSerializerMixin(serializers.Serializer):
"""
通过API批量操作资源时, 自动给每个资源添加所需属性org_id的值为current_org_id
(同时为serializer.is_valid()对Model的unique_together校验做准备)
由于HiddenField字段不可读,API获取资产信息时获取不到org_id,
但是coco需要资产的org_id字段,所以修改为CharField类型
"""
org_id = serializers.ReadOnlyField(default=get_current_org_id_for_serializer, label=_("Organization"))
org_name = serializers.ReadOnlyField(label=_("Org name"))
def get_validators(self):
_validators = super().get_validators()
validators = []
for v in _validators:
if isinstance(v, UniqueTogetherValidator) \
and "org_id" in v.fields:
v = ProjectUniqueValidator(v.queryset, v.fields)
validators.append(v)
return validators
def get_field_names(self, declared_fields, info):
fields = super().get_field_names(declared_fields, info)
fields.extend(["org_id", "org_name"])
return fields
class BulkOrgResourceSerializerMixin(OrgResourceSerializerMixin, BulkSerializerMixin):
pass
class BulkOrgResourceModelSerializer(BulkOrgResourceSerializerMixin, serializers.ModelSerializer):
pass
class OrgMembershipSerializerMixin:
def run_validation(self, initial_data=None):
initial_data['organization'] = str(self.context['org'].id)
return super().run_validation(initial_data)
...@@ -1108,9 +1108,44 @@ function formatDateAsCN(d) { ...@@ -1108,9 +1108,44 @@ function formatDateAsCN(d) {
function getUrlParams(url) { function getUrlParams(url) {
url = url.split("?"); url = url.split("?");
let params = ""; var params = "";
if (url.length === 2){ if (url.length === 2){
params = url[1]; params = url[1];
} }
return params return params
}
function getTimeUnits(u) {
var units = {
"d": "天",
"h": "时",
"m": "分",
"s": "秒",
};
if (navigator.language || "zh-CN") {
return units[u]
}
return u
}
function timeOffset(a, b) {
var start = new Date(a);
var end = new Date(b);
var offset = (end - start)/1000;
var days = offset / 3600 / 24;
var hours = offset / 3600;
var minutes = offset / 60;
var seconds = offset;
if (days > 1) {
return days.toFixed(1) + " " + getTimeUnits("d");
} else if (hours > 1) {
return hours.toFixed(1) + " " + getTimeUnits("h");
} else if (minutes > 1) {
return minutes.toFixed(1) + " " + getTimeUnits("m")
} else if (seconds > 1) {
return seconds.toFixed(1) + " " + getTimeUnits("s")
}
return ""
} }
\ No newline at end of file
...@@ -9,12 +9,13 @@ from django.conf import settings ...@@ -9,12 +9,13 @@ from django.conf import settings
from rest_framework.pagination import LimitOffsetPagination from rest_framework.pagination import LimitOffsetPagination
from rest_framework import viewsets from rest_framework import viewsets
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework_bulk import BulkModelViewSet from rest_framework.generics import GenericAPIView
import jms_storage import jms_storage
from common.utils import is_uuid, get_logger from common.utils import is_uuid, get_logger
from common.permissions import IsOrgAdminOrAppUser, IsAuditor from common.permissions import IsOrgAdminOrAppUser, IsAuditor
from common.filters import DatetimeRangeFilter
from orgs.mixins import OrgBulkModelViewSet
from ..hands import SystemUser from ..hands import SystemUser
from ..models import Session from ..models import Session
from .. import serializers from .. import serializers
...@@ -24,12 +25,17 @@ __all__ = ['SessionViewSet', 'SessionReplayViewSet',] ...@@ -24,12 +25,17 @@ __all__ = ['SessionViewSet', 'SessionReplayViewSet',]
logger = get_logger(__name__) logger = get_logger(__name__)
class SessionViewSet(BulkModelViewSet): class SessionViewSet(OrgBulkModelViewSet):
queryset = Session.objects.all() queryset = Session.objects.all()
serializer_class = serializers.SessionSerializer serializer_class = serializers.SessionSerializer
pagination_class = LimitOffsetPagination pagination_class = LimitOffsetPagination
permission_classes = (IsOrgAdminOrAppUser | IsAuditor, ) permission_classes = (IsOrgAdminOrAppUser | IsAuditor, )
filter_fields = ["user", "asset", "system_user", "terminal"] filter_fields = [
"user", "asset", "system_user", "terminal", "is_finished",
]
date_range_filter_fields = [
('date_start', ('date_from', 'date_to'))
]
def get_object(self): def get_object(self):
# 解决guacamole更新session时并发导致幽灵会话的问题 # 解决guacamole更新session时并发导致幽灵会话的问题
...@@ -38,6 +44,12 @@ class SessionViewSet(BulkModelViewSet): ...@@ -38,6 +44,12 @@ class SessionViewSet(BulkModelViewSet):
obj = obj.select_for_update() obj = obj.select_for_update()
return obj return obj
@property
def filter_backends(self):
backends = list(GenericAPIView.filter_backends)
backends.append(DatetimeRangeFilter)
return backends
def perform_create(self, serializer): def perform_create(self, serializer):
if hasattr(self.request.user, 'terminal'): if hasattr(self.request.user, 'terminal'):
serializer.validated_data["terminal"] = self.request.user.terminal serializer.validated_data["terminal"] = self.request.user.terminal
......
...@@ -241,6 +241,10 @@ class Session(OrgModelMixin): ...@@ -241,6 +241,10 @@ class Session(OrgModelMixin):
command_store = get_multi_command_storage() command_store = get_multi_command_storage()
return command_store.count(session=str(self.id)) return command_store.count(session=str(self.id))
@property
def login_from_display(self):
return self.get_login_from_display()
class Meta: class Meta:
db_table = "terminal_session" db_table = "terminal_session"
ordering = ["-date_start"] ordering = ["-date_start"]
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# #
from rest_framework import serializers from rest_framework import serializers
from orgs.mixins import BulkOrgResourceModelSerializer
from common.mixins import BulkSerializerMixin from common.mixins import BulkSerializerMixin
from common.serializers import AdaptedBulkListSerializer from common.serializers import AdaptedBulkListSerializer
from ..models import Terminal, Status, Session, Task from ..models import Terminal, Status, Session, Task
...@@ -24,13 +25,18 @@ class TerminalSerializer(serializers.ModelSerializer): ...@@ -24,13 +25,18 @@ class TerminalSerializer(serializers.ModelSerializer):
return Session.objects.filter(terminal=obj, is_finished=False).count() return Session.objects.filter(terminal=obj, is_finished=False).count()
class SessionSerializer(BulkSerializerMixin, serializers.ModelSerializer): class SessionSerializer(BulkOrgResourceModelSerializer):
command_amount = serializers.IntegerField(read_only=True) command_amount = serializers.IntegerField(read_only=True)
class Meta: class Meta:
model = Session model = Session
list_serializer_class = AdaptedBulkListSerializer list_serializer_class = AdaptedBulkListSerializer
fields = '__all__' fields = [
"id", "user", "asset", "system_user", "login_from",
"login_from_display", "remote_addr", "is_finished",
"has_replay", "can_replay", "protocol", "date_start", "date_end",
"terminal", "command_amount",
]
class StatusSerializer(serializers.ModelSerializer): class StatusSerializer(serializers.ModelSerializer):
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
.toggle { .toggle {
cursor: pointer; cursor: pointer;
} }
.detail-key { .detail-key {
width: 70px; width: 70px;
} }
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django.views.generic import View, TemplateView from django.views.generic import TemplateView
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.http import HttpResponse
from django.template import loader
from django.utils import timezone from django.utils import timezone
import time
from common.mixins import DatetimeSearchMixin
from common.permissions import PermissionsMixin, IsOrgAdmin, IsAuditor from common.permissions import PermissionsMixin, IsOrgAdmin, IsAuditor
from ..backends import get_multi_command_storage
__all__ = ['CommandListView'] __all__ = ['CommandListView']
common_storage = get_multi_command_storage()
class CommandListView(DatetimeSearchMixin, PermissionsMixin, TemplateView): class CommandListView(PermissionsMixin, TemplateView):
template_name = "terminal/command_list.html" template_name = "terminal/command_list.html"
permission_classes = [IsOrgAdmin | IsAuditor] permission_classes = [IsOrgAdmin | IsAuditor]
default_days_ago = 5 default_days_ago = 5
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django.views.generic import ListView from django.views.generic import ListView, TemplateView
from django.views.generic.edit import SingleObjectMixin from django.views.generic.edit import SingleObjectMixin
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.utils import timezone from django.utils import timezone
...@@ -20,68 +20,40 @@ __all__ = [ ...@@ -20,68 +20,40 @@ __all__ = [
] ]
class SessionListView(PermissionsMixin, DatetimeSearchMixin, ListView): class SessionListView(PermissionsMixin, TemplateView):
model = Session model = Session
template_name = 'terminal/session_list.html' template_name = 'terminal/session_list.html'
context_object_name = 'session_list'
paginate_by = settings.DISPLAY_PER_PAGE
user = asset = system_user = ''
date_from = date_to = None date_from = date_to = None
permission_classes = [IsOrgAdmin | IsAuditor] permission_classes = [IsOrgAdmin | IsAuditor]
default_days_ago = 5
def get_queryset(self):
self.queryset = super().get_queryset()
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_start__gt'] = self.date_from
filter_kwargs['date_start__lt'] = self.date_to
return self.queryset
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
now = timezone.now()
context = { context = {
'asset_list': utils.get_session_asset_list()[:10], 'date_from': now - timezone.timedelta(days=self.default_days_ago),
'date_from': self.date_from, 'date_to': now,
'date_to': self.date_to,
'user': self.user,
'asset': self.asset,
'system_user': self.system_user,
} }
kwargs.update(context) kwargs.update(context)
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
class SessionOnlineListView(SessionListView): class SessionOnlineListView(SessionListView):
def get_queryset(self):
queryset = super().get_queryset().filter(is_finished=False)
return queryset
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = { context = {
'app': _('Sessions'), 'app': _('Sessions'),
'action': _('Session online list'), 'action': _('Session online list'),
'type': 'online', 'type': 'online',
'now': timezone.now(),
} }
kwargs.update(context) kwargs.update(context)
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
class SessionOfflineListView(SessionListView): class SessionOfflineListView(SessionListView):
def get_queryset(self):
queryset = super().get_queryset()
queryset = queryset.filter(is_finished=True)
return queryset
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = { context = {
'app': _('Sessions'), 'app': _('Sessions'),
'action': _('Session offline'), 'action': _('Session offline'),
'now': timezone.now(), 'type': 'offline',
} }
kwargs.update(context) kwargs.update(context)
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
......
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