diff --git a/apps/reports/api/__init__.py b/apps/reports/api/__init__.py index 8700721a5..67b395c54 100644 --- a/apps/reports/api/__init__.py +++ b/apps/reports/api/__init__.py @@ -1 +1,2 @@ from .report import * +from .users import * diff --git a/apps/reports/api/users/__init__.py b/apps/reports/api/users/__init__.py index e69de29bb..f4a2da081 100644 --- a/apps/reports/api/users/__init__.py +++ b/apps/reports/api/users/__init__.py @@ -0,0 +1 @@ +from .user import * diff --git a/apps/reports/api/users/user.py b/apps/reports/api/users/user.py index b1f980597..11074d52e 100644 --- a/apps/reports/api/users/user.py +++ b/apps/reports/api/users/user.py @@ -21,6 +21,7 @@ class UserReportApi(APIView): http_method_names = ['get'] # TODO: Define the required RBAC permissions for this API rbac_perms = { + 'GET': 'users..view_users', } permission_classes = [RBACPermission, IsValidLicense] @@ -46,15 +47,13 @@ class UserReportApi(APIView): date_range_bounds = self.days_to_datetime.date(), (local_now() + timezone.timedelta(days=1)).date() return queryset.filter(**{f'{field_name}__range': date_range_bounds}) - def get_user_login_metrics(self): - filtered_queryset = self.filter_by_date_range(self.user_login_log_queryset, 'datetime') - - data = defaultdict(set) - for t, username in filtered_queryset.values_list('datetime', 'username'): - date_str = str(t.date()) - data[date_str].add(username) - - metrics = [len(v) for __, v in data] + def get_user_login_metrics(self, status): + queryset = UserLoginLog.objects.filter(status=status) + queryset = UserLoginLog.filter_login_queryset_by_org(queryset) + filtered_queryset = self.filter_by_date_range(queryset, 'datetime').values( + 'datetime__date').annotate(user_count=Count('username', distinct=True)).order_by('datetime__date') + result_dict = {r['datetime__date']: r['user_count'] for r in filtered_queryset} + metrics = [result_dict.get(d, 0) for d in self.date_range_list] return metrics def get_user_login_method_metrics(self): @@ -66,11 +65,12 @@ class UserReportApi(APIView): backends.add(backend) date_str = str(t.date()) data[date_str][backend].add(username) - metrics = defaultdict(list) - for backend in backends: - for date_str, usernames in data.items(): - metrics[backend].append(len(usernames.get(backend, set()))) + for t in self.date_range_list: + date_str = str(t) + for backend in backends: + username = data.get(date_str) if data.get(date_str) else {backend: set()} + metrics[backend].append(len(username.get(backend, set()))) return metrics def get_user_login_region_distribution(self): @@ -79,36 +79,50 @@ class UserReportApi(APIView): data = filtered_queryset.values('city').annotate( user_count=Count('username', distinct=True) ).order_by('-user_count') - return list(data) + metrics = [{'name': d['city'], 'value': d['user_count']} for d in data] + return metrics + + def get_user_login_time_metrics(self): + time_buckets = { + '00:00-06:00': (0, 6), + '06:00-12:00': (6, 12), + '12:00-18:00': (12, 18), + '18:00-24:00': (18, 24), + } + filtered_queryset = self.filter_by_date_range(self.user_login_log_queryset, 'datetime').all() + metrics = {bucket: 0 for bucket in time_buckets.keys()} + for date in filtered_queryset: + hour = date.datetime.hour + for bucket, (start, end) in time_buckets.items(): + if start <= hour < end: + metrics[bucket] = metrics.get(bucket, 0) + 1 + return metrics @lazyproperty def user_login_log_queryset(self): queryset = UserLoginLog.objects.filter(status=LoginStatusChoices.success) return UserLoginLog.filter_login_queryset_by_org(queryset) + @lazyproperty + def user_login_failed_queryset(self): + queryset = UserLoginLog.objects.filter(status=LoginStatusChoices.failed) + return UserLoginLog.filter_login_queryset_by_org(queryset) + def get(self, request, *args, **kwargs): - query_params = self.request.query_params data = {} - - _all = query_params.get('all') - - if _all or query_params.get('user_login_log_metrics'): - metrics = self.get_user_login_metrics() - data.update({ - 'dates_metrics_date': [date.strftime('%m-%d') for date in self.date_range_list] or ['0'], - 'dates_metrics_total': metrics, - }) - - if _all or query_params.get('user_login_method_metrics'): - metrics = self.get_user_login_method_metrics() - data.update({ - 'dates_metrics_date': [date.strftime('%m-%d') for date in self.date_range_list] or ['0'], - 'dates_metrics_total': metrics, - }) - - if _all or query_params.get('user_login_region_distribution'): - data.update({ - 'user_login_region_distribution': self.get_user_login_region_distribution(), - }) + data['user_login_log_metrics'] = { + 'dates_metrics_date': [date.strftime('%m-%d') for date in self.date_range_list] or ['0'], + 'dates_metrics_total': self.get_user_login_metrics(LoginStatusChoices.success), + } + data['user_login_failed_metrics'] = { + 'dates_metrics_date': [date.strftime('%m-%d') for date in self.date_range_list] or ['0'], + 'dates_metrics_total': self.get_user_login_metrics(LoginStatusChoices.failed), + } + data['user_login_method_metrics'] = { + 'dates_metrics_date': [date.strftime('%m-%d') for date in self.date_range_list] or ['0'], + 'dates_metrics_total': self.get_user_login_method_metrics(), + } + data['user_login_region_distribution'] = self.get_user_login_region_distribution() + data['user_login_time_metrics'] = self.get_user_login_time_metrics() return JsonResponse(data, status=200) diff --git a/apps/reports/urls/api_urls.py b/apps/reports/urls/api_urls.py index 88ac80795..b1f40bbf0 100644 --- a/apps/reports/urls/api_urls.py +++ b/apps/reports/urls/api_urls.py @@ -6,4 +6,5 @@ app_name = 'reports' urlpatterns = [ path('reports/', api.ReportViewSet.as_view(), name='report-list'), + path('reports/users/', api.UserReportApi.as_view(), name='user-list') ]