import time from django.core.cache import cache from django.utils import timezone from django.utils.timesince import timesince from django.db.models import Count, Max from django.http.response import JsonResponse, HttpResponse from rest_framework.views import APIView from rest_framework.permissions import AllowAny from collections import Counter from django.conf import settings from rest_framework.response import Response from users.models import User from assets.models import Asset from terminal.models import Session from terminal.utils import ComponentsPrometheusMetricsUtil from orgs.utils import current_org from common.permissions import IsOrgAdmin, IsOrgAuditor from common.utils import lazyproperty from orgs.caches import OrgResourceStatisticsCache __all__ = ['IndexApi'] class DatesLoginMetricMixin: @lazyproperty def days(self): query_params = self.request.query_params if query_params.get('monthly'): return 30 return 7 @lazyproperty def sessions_queryset(self): days = timezone.now() - timezone.timedelta(days=self.days) sessions_queryset = Session.objects.filter(date_start__gt=days) return sessions_queryset @lazyproperty def session_dates_list(self): now = timezone.now() dates = [(now - timezone.timedelta(days=i)).date() for i in range(self.days)] dates.reverse() # dates = self.sessions_queryset.dates('date_start', 'day') return dates def get_dates_metrics_date(self): dates_metrics_date = [d.strftime('%m-%d') for d in self.session_dates_list] or ['0'] return dates_metrics_date @staticmethod def get_cache_key(date, tp): date_str = date.strftime("%Y%m%d") key = "SESSION_DATE_{}_{}_{}".format(current_org.id, tp, date_str) return key def __get_data_from_cache(self, date, tp): if date == timezone.now().date(): return None cache_key = self.get_cache_key(date, tp) count = cache.get(cache_key) return count def __set_data_to_cache(self, date, tp, count): cache_key = self.get_cache_key(date, tp) cache.set(cache_key, count, 3600*24*7) @staticmethod def get_date_start_2_end(d): time_min = timezone.datetime.min.time() time_max = timezone.datetime.max.time() tz = timezone.get_current_timezone() ds = timezone.datetime.combine(d, time_min).replace(tzinfo=tz) de = timezone.datetime.combine(d, time_max).replace(tzinfo=tz) return ds, de def get_date_login_count(self, date): tp = "LOGIN" count = self.__get_data_from_cache(date, tp) if count is not None: return count ds, de = self.get_date_start_2_end(date) count = Session.objects.filter(date_start__range=(ds, de)).count() self.__set_data_to_cache(date, tp, count) return count def get_dates_metrics_total_count_login(self): data = [] for d in self.session_dates_list: count = self.get_date_login_count(d) data.append(count) if len(data) == 0: data = [0] return data def get_date_user_count(self, date): tp = "USER" count = self.__get_data_from_cache(date, tp) if count is not None: return count ds, de = self.get_date_start_2_end(date) count = len(set(Session.objects.filter(date_start__range=(ds, de)).values_list('user_id', flat=True))) self.__set_data_to_cache(date, tp, count) return count def get_dates_metrics_total_count_active_users(self): data = [] for d in self.session_dates_list: count = self.get_date_user_count(d) data.append(count) return data def get_date_asset_count(self, date): tp = "ASSET" count = self.__get_data_from_cache(date, tp) if count is not None: return count ds, de = self.get_date_start_2_end(date) count = len(set(Session.objects.filter(date_start__range=(ds, de)).values_list('asset', flat=True))) self.__set_data_to_cache(date, tp, count) return count def get_dates_metrics_total_count_active_assets(self): data = [] for d in self.session_dates_list: count = self.get_date_asset_count(d) data.append(count) return data @lazyproperty def dates_total_count_active_users(self): count = len(set(self.sessions_queryset.values_list('user_id', flat=True))) return count @lazyproperty def dates_total_count_inactive_users(self): total = current_org.get_members().count() active = self.dates_total_count_active_users count = total - active if count < 0: count = 0 return count @lazyproperty def dates_total_count_disabled_users(self): return current_org.get_members().filter(is_active=False).count() @lazyproperty def dates_total_count_active_assets(self): return len(set(self.sessions_queryset.values_list('asset', flat=True))) @lazyproperty def dates_total_count_inactive_assets(self): total = Asset.objects.all().count() active = self.dates_total_count_active_assets count = total - active if count < 0: count = 0 return count @lazyproperty def dates_total_count_disabled_assets(self): return Asset.objects.filter(is_active=False).count() # 以下是从week中而来 def get_dates_login_times_top5_users(self): users = self.sessions_queryset.values_list('user_id', flat=True) users = [ {'user': user, 'total': total} for user, total in Counter(users).most_common(5) ] return users def get_dates_total_count_login_users(self): return len(set(self.sessions_queryset.values_list('user_id', flat=True))) def get_dates_total_count_login_times(self): return self.sessions_queryset.count() def get_dates_login_times_top10_assets(self): assets = self.sessions_queryset.values("asset") \ .annotate(total=Count("asset")) \ .annotate(last=Max("date_start")).order_by("-total")[:10] for asset in assets: asset['last'] = str(asset['last']) return list(assets) def get_dates_login_times_top10_users(self): users = self.sessions_queryset.values("user_id") \ .annotate(total=Count("user_id")) \ .annotate(last=Max("date_start")).order_by("-total")[:10] for user in users: user['last'] = str(user['last']) return list(users) def get_dates_login_record_top10_sessions(self): sessions = self.sessions_queryset.order_by('-date_start')[:10] for session in sessions: session.avatar_url = User.get_avatar_url("") sessions = [ { 'user': session.user, 'asset': session.asset, 'is_finished': session.is_finished, 'date_start': str(session.date_start), 'timesince': timesince(session.date_start) } for session in sessions ] return sessions class IndexApi(DatesLoginMetricMixin, APIView): permission_classes = (IsOrgAdmin | IsOrgAuditor,) http_method_names = ['get'] def get(self, request, *args, **kwargs): data = {} query_params = self.request.query_params caches = OrgResourceStatisticsCache(self.request.user.user_orgs[0]) _all = query_params.get('all') if _all or query_params.get('total_count') or query_params.get('total_count_users'): data.update({ 'total_count_users': caches.users_amount, }) if _all or query_params.get('total_count') or query_params.get('total_count_assets'): data.update({ 'total_count_assets': caches.assets_amount, }) if _all or query_params.get('total_count') or query_params.get('total_count_online_users'): data.update({ 'total_count_online_users': caches.total_count_online_users, }) if _all or query_params.get('total_count') or query_params.get('total_count_online_sessions'): data.update({ 'total_count_online_sessions': caches.total_count_online_sessions, }) if _all or query_params.get('dates_metrics'): data.update({ 'dates_metrics_date': self.get_dates_metrics_date(), 'dates_metrics_total_count_login': self.get_dates_metrics_total_count_login(), 'dates_metrics_total_count_active_users': self.get_dates_metrics_total_count_active_users(), 'dates_metrics_total_count_active_assets': self.get_dates_metrics_total_count_active_assets(), }) if _all or query_params.get('dates_total_count_users'): data.update({ 'dates_total_count_active_users': self.dates_total_count_active_users, 'dates_total_count_inactive_users': self.dates_total_count_inactive_users, 'dates_total_count_disabled_users': self.dates_total_count_disabled_users, }) if _all or query_params.get('dates_total_count_assets'): data.update({ 'dates_total_count_active_assets': self.dates_total_count_active_assets, 'dates_total_count_inactive_assets': self.dates_total_count_inactive_assets, 'dates_total_count_disabled_assets': self.dates_total_count_disabled_assets, }) if _all or query_params.get('dates_total_count'): data.update({ 'dates_total_count_login_users': self.get_dates_total_count_login_users(), 'dates_total_count_login_times': self.get_dates_total_count_login_times(), }) if _all or query_params.get('dates_login_times_top5_users'): data.update({ 'dates_login_times_top5_users': self.get_dates_login_times_top5_users(), }) if _all or query_params.get('dates_login_times_top10_assets'): data.update({ 'dates_login_times_top10_assets': self.get_dates_login_times_top10_assets(), }) if _all or query_params.get('dates_login_times_top10_users'): data.update({ 'dates_login_times_top10_users': self.get_dates_login_times_top10_users(), }) if _all or query_params.get('dates_login_record_top10_sessions'): data.update({ 'dates_login_record_top10_sessions': self.get_dates_login_record_top10_sessions() }) return JsonResponse(data, status=200) class HealthApiMixin(APIView): def is_token_right(self): token = self.request.query_params.get('token') ok_token = settings.HEALTH_CHECK_TOKEN if ok_token and token != ok_token: return False return True def check_permissions(self, request): if not self.is_token_right(): msg = 'Health check token error, ' \ 'Please set query param in url and same with setting HEALTH_CHECK_TOKEN. ' \ 'eg: $PATH/?token=$HEALTH_CHECK_TOKEN' self.permission_denied(request, message={'error': msg}, code=403) class HealthCheckView(HealthApiMixin): permission_classes = (AllowAny,) @staticmethod def get_db_status(): t1 = time.time() try: User.objects.first() t2 = time.time() return True, t2 - t1 except: t2 = time.time() return False, t2 - t1 def get_redis_status(self): key = 'HEALTH_CHECK' t1 = time.time() try: value = '1' cache.set(key, '1', 10) got = cache.get(key) t2 = time.time() if value == got: return True, t2 -t1 return False, t2 -t1 except: t2 = time.time() return False, t2 - t1 def get(self, request): redis_status, redis_time = self.get_redis_status() db_status, db_time = self.get_db_status() status = all([redis_status, db_status]) data = { 'status': status, 'db_status': db_status, 'db_time': db_time, 'redis_status': redis_status, 'redis_time': redis_time, 'time': int(time.time()) } return Response(data) class PrometheusMetricsApi(HealthApiMixin): permission_classes = (AllowAny,) def get(self, request, *args, **kwargs): util = ComponentsPrometheusMetricsUtil() metrics_text = util.get_prometheus_metrics_text() return HttpResponse(metrics_text, content_type='text/plain; version=0.0.4; charset=utf-8')