diff --git a/apps/audits/api.py b/apps/audits/api.py index 3677a8e8e..5ed7a9cd6 100644 --- a/apps/audits/api.py +++ b/apps/audits/api.py @@ -1,10 +1,16 @@ # -*- coding: utf-8 -*- # +from rest_framework.viewsets import GenericViewSet +from rest_framework.mixins import ListModelMixin +from django.db.models import Q -from common.permissions import IsOrgAdminOrAppUser, IsOrgAuditor +from common.mixins.api import CommonApiMixin +from common.permissions import IsOrgAdminOrAppUser, IsOrgAuditor, IsOrgAdmin +from common.drf.filters import DatetimeRangeFilter from orgs.mixins.api import OrgModelViewSet -from .models import FTPLog -from .serializers import FTPLogSerializer +from orgs.utils import current_org +from .models import FTPLog, UserLoginLog +from .serializers import FTPLogSerializer, UserLoginLogSerializer class FTPLogViewSet(OrgModelViewSet): @@ -12,3 +18,29 @@ class FTPLogViewSet(OrgModelViewSet): serializer_class = FTPLogSerializer permission_classes = (IsOrgAdminOrAppUser | IsOrgAuditor,) http_method_names = ['get', 'post', 'head', 'options'] + + +class UserLoginLogViewSet(CommonApiMixin, + ListModelMixin, + GenericViewSet): + queryset = UserLoginLog.objects.all() + permission_classes = [IsOrgAdmin | IsOrgAuditor] + serializer_class = UserLoginLogSerializer + extra_filter_backends = [DatetimeRangeFilter] + date_range_filter_fields = [ + ('datetime', ('date_from', 'date_to')) + ] + filterset_fields = ['username'] + search_fields = ['ip', 'city', 'username'] + + @staticmethod + def get_org_members(): + users = current_org.get_org_members().values_list('username', flat=True) + return users + + def get_queryset(self): + queryset = super().get_queryset() + if not current_org.is_default(): + users = self.get_org_members() + queryset = queryset.filter(username__in=users) + return queryset diff --git a/apps/audits/serializers.py b/apps/audits/serializers.py index 7dcd94d73..70ca61dc2 100644 --- a/apps/audits/serializers.py +++ b/apps/audits/serializers.py @@ -14,10 +14,13 @@ class FTPLogSerializer(serializers.ModelSerializer): fields = '__all__' -class LoginLogSerializer(serializers.ModelSerializer): +class UserLoginLogSerializer(serializers.ModelSerializer): class Meta: model = models.UserLoginLog - fields = '__all__' + fields = ( + 'username', 'type', 'ip', 'city', 'user_agent', + 'mfa', 'reason', 'status', 'datetime' + ) class OperateLogSerializer(serializers.ModelSerializer): diff --git a/apps/audits/urls/api_urls.py b/apps/audits/urls/api_urls.py index 249843f24..86312dfe3 100644 --- a/apps/audits/urls/api_urls.py +++ b/apps/audits/urls/api_urls.py @@ -12,6 +12,7 @@ app_name = "audits" router = DefaultRouter() router.register(r'ftp-logs', api.FTPLogViewSet, 'ftp-log') +router.register(r'login-logs', api.UserLoginLogViewSet, 'login-log') urlpatterns = [ ] diff --git a/apps/common/drf/filters.py b/apps/common/drf/filters.py index c11a7864d..bf6ac7197 100644 --- a/apps/common/drf/filters.py +++ b/apps/common/drf/filters.py @@ -4,7 +4,9 @@ import coreapi from rest_framework import filters from rest_framework.fields import DateTimeField from rest_framework.serializers import ValidationError +from rest_framework.compat import coreapi, coreschema from django.core.cache import cache +from django.core.exceptions import ImproperlyConfigured import logging from common import const @@ -13,15 +15,48 @@ __all__ = ["DatetimeRangeFilter", "IDSpmFilter", "CustomFilter"] class DatetimeRangeFilter(filters.BaseFilterBackend): - def filter_queryset(self, request, queryset, view): + def get_schema_fields(self, view): + ret = [] + fields = self._get_date_range_filter_fields(view) + + for attr, date_range_keyword in fields.items(): + if len(date_range_keyword) != 2: + continue + for v in date_range_keyword: + ret.append( + coreapi.Field( + name=v, location='query', required=False, type='string', + schema=coreschema.String( + title=v, + description='%s %s' % (attr, v) + ) + ) + ) + + return ret + + def _get_date_range_filter_fields(self, view): if not hasattr(view, 'date_range_filter_fields'): - return queryset + return {} try: - fields = dict(view.date_range_filter_fields) + return dict(view.date_range_filter_fields) except ValueError: - msg = "View {} datetime_filter_fields set is error".format(view.name) + msg = """ + View {} `date_range_filter_fields` set is improperly. + For example: + ``` + class ExampleView: + date_range_filter_fields = [ + ('db column', ('query param date from', 'query param date to')) + ] + ``` + """.format(view.name) logging.error(msg) - return queryset + raise ImproperlyConfigured(msg) + + def filter_queryset(self, request, queryset, view): + fields = self._get_date_range_filter_fields(view) + kwargs = {} for attr, date_range_keyword in fields.items(): if len(date_range_keyword) != 2: diff --git a/apps/common/mixins/views.py b/apps/common/mixins/views.py index a00535b5b..b6685def5 100644 --- a/apps/common/mixins/views.py +++ b/apps/common/mixins/views.py @@ -36,5 +36,3 @@ class DatetimeSearchMixin: def get(self, request, *args, **kwargs): self.get_date_range() return super().get(request, *args, **kwargs) - -