api: add cleaner endpoints for statistics (#63368)
This commit is contained in:
parent
104b33fb88
commit
30251c80b1
|
@ -1593,8 +1593,14 @@ class ServiceOUField(serializers.ListField):
|
|||
|
||||
class StatisticsSerializer(serializers.Serializer):
|
||||
TIME_INTERVAL_CHOICES = [('day', _('Day')), ('month', _('Month')), ('year', _('Year'))]
|
||||
GROUP_BY_CHOICES = [
|
||||
('authentication_type', _('Authentication type')),
|
||||
('service', _('Service')),
|
||||
('service_ou', _('Organizational unit')),
|
||||
]
|
||||
|
||||
time_interval = serializers.ChoiceField(choices=TIME_INTERVAL_CHOICES, default='month')
|
||||
group_by = serializers.ChoiceField(choices=GROUP_BY_CHOICES, default='authentication_type')
|
||||
service = ServiceOUField(child=serializers.SlugField(max_length=256), required=False)
|
||||
services_ou = serializers.SlugField(required=False, allow_blank=False, max_length=256)
|
||||
users_ou = serializers.SlugField(required=False, allow_blank=False, max_length=256)
|
||||
|
@ -1632,15 +1638,32 @@ class StatisticsAPI(ViewSet):
|
|||
'default': time_interval_field.default,
|
||||
}
|
||||
]
|
||||
group_by_field = StatisticsSerializer().get_fields()['group_by']
|
||||
group_by_filter = {
|
||||
'id': 'group_by',
|
||||
'label': _('Group by'),
|
||||
'options': [{'id': key, 'label': label} for key, label in group_by_field.choices.items()],
|
||||
'has_subfilters': True,
|
||||
'required': True,
|
||||
'default': group_by_field.default,
|
||||
}
|
||||
for action in self.get_extra_actions():
|
||||
url = self.reverse_action(action.url_name)
|
||||
filters = common_filters.copy()
|
||||
|
||||
if action.url_name in ('login-new', 'registration-new'):
|
||||
filters.append(group_by_filter)
|
||||
deprecated = False
|
||||
else:
|
||||
deprecated = True
|
||||
|
||||
filters.extend(self.get_additional_filters(action.filters))
|
||||
data = {
|
||||
'name': action.kwargs['name'],
|
||||
'url': url,
|
||||
'id': action.url_name,
|
||||
'filters': filters,
|
||||
'deprecated': deprecated,
|
||||
}
|
||||
statistics.append(data)
|
||||
|
||||
|
@ -1690,7 +1713,7 @@ class StatisticsAPI(ViewSet):
|
|||
)
|
||||
return filters
|
||||
|
||||
def get_statistics(self, request, klass, method):
|
||||
def get_statistics(self, request, klass, method=None):
|
||||
serializer = StatisticsSerializer(data=request.query_params)
|
||||
if not serializer.is_valid():
|
||||
response = {'data': [], 'err': 1, 'err_desc': serializer.errors}
|
||||
|
@ -1703,7 +1726,19 @@ class StatisticsAPI(ViewSet):
|
|||
'end': data.get('end'),
|
||||
}
|
||||
|
||||
allowed_filters = getattr(self, self.action).filters
|
||||
subfilters = []
|
||||
if not method:
|
||||
method = {
|
||||
'authentication_type': 'get_method_statistics',
|
||||
'service': 'get_service_statistics',
|
||||
'service_ou': 'get_service_ou_statistics',
|
||||
}[data['group_by']]
|
||||
|
||||
if data['group_by'] == 'authentication_type':
|
||||
allowed_filters = ('services_ou', 'users_ou', 'service')
|
||||
subfilters = self.get_additional_filters(allowed_filters)
|
||||
else:
|
||||
allowed_filters = getattr(self, self.action).filters
|
||||
service = data.get('service')
|
||||
services_ou = data.get('services_ou')
|
||||
users_ou = data.get('users_ou')
|
||||
|
@ -1722,12 +1757,17 @@ class StatisticsAPI(ViewSet):
|
|||
if users_ou and 'users_ou' in allowed_filters:
|
||||
kwargs['users_ou'] = get_object_or_404(OrganizationalUnit, slug=users_ou)
|
||||
|
||||
return Response(
|
||||
{
|
||||
'data': getattr(klass, method)(**kwargs),
|
||||
'err': 0,
|
||||
}
|
||||
)
|
||||
data = getattr(klass, method)(**kwargs)
|
||||
data['subfilters'] = subfilters
|
||||
return Response({'data': data, 'err': 0})
|
||||
|
||||
@stat(name=_('Login count'))
|
||||
def login_new(self, request):
|
||||
return self.get_statistics(request, UserLogin)
|
||||
|
||||
@stat(name=_('Registration count'))
|
||||
def registration_new(self, request):
|
||||
return self.get_statistics(request, UserRegistration)
|
||||
|
||||
@stat(name=_('Login count by authentication type'), filters=('services_ou', 'users_ou', 'service'))
|
||||
def login(self, request):
|
||||
|
|
|
@ -2592,7 +2592,7 @@ def test_api_users_delete(settings, app, admin, simple_user):
|
|||
def test_api_statistics_list(app, admin):
|
||||
headers = basic_authorization_header(admin)
|
||||
resp = app.get('/api/statistics/', headers=headers)
|
||||
assert len(resp.json['data']) == 6
|
||||
assert len(resp.json['data']) == 8
|
||||
login_stats = {
|
||||
'name': 'Login count by authentication type',
|
||||
'url': 'https://testserver/api/statistics/login/',
|
||||
|
@ -2611,6 +2611,7 @@ def test_api_statistics_list(app, admin):
|
|||
},
|
||||
{'id': 'service', 'label': 'Service', 'options': []},
|
||||
],
|
||||
'deprecated': True,
|
||||
}
|
||||
assert login_stats in resp.json['data']
|
||||
assert {
|
||||
|
@ -2630,6 +2631,7 @@ def test_api_statistics_list(app, admin):
|
|||
"default": "month",
|
||||
},
|
||||
],
|
||||
'deprecated': True,
|
||||
} in resp.json['data']
|
||||
|
||||
service = Service.objects.create(name='Service1', slug='service1', ou=get_default_ou())
|
||||
|
@ -2678,14 +2680,117 @@ def test_api_statistics_list(app, admin):
|
|||
assert login_stats in resp.json['data']
|
||||
|
||||
|
||||
def test_api_statistics_list_new(app, admin):
|
||||
headers = basic_authorization_header(admin)
|
||||
resp = app.get('/api/statistics/', headers=headers)
|
||||
login_stat = [x for x in resp.json['data'] if x['id'] == 'login-new'][0]
|
||||
assert login_stat == {
|
||||
'name': 'Login count',
|
||||
'url': 'https://testserver/api/statistics/login_new/',
|
||||
'id': 'login-new',
|
||||
'filters': [
|
||||
{
|
||||
'id': 'time_interval',
|
||||
'label': 'Time interval',
|
||||
'options': [
|
||||
{'id': 'day', 'label': 'Day'},
|
||||
{'id': 'month', 'label': 'Month'},
|
||||
{'id': 'year', 'label': 'Year'},
|
||||
],
|
||||
'required': True,
|
||||
'default': 'month',
|
||||
},
|
||||
{
|
||||
'id': 'group_by',
|
||||
'label': 'Group by',
|
||||
'options': [
|
||||
{'id': 'authentication_type', 'label': 'Authentication type'},
|
||||
{'id': 'service', 'label': 'Service'},
|
||||
{'id': 'service_ou', 'label': 'Organizational unit'},
|
||||
],
|
||||
'has_subfilters': True,
|
||||
'required': True,
|
||||
'default': 'authentication_type',
|
||||
},
|
||||
],
|
||||
'deprecated': False,
|
||||
}
|
||||
|
||||
registration_stat = [x for x in resp.json['data'] if x['id'] == 'registration-new'][0]
|
||||
assert registration_stat['name'] == 'Registration count'
|
||||
assert registration_stat['filters'] == login_stat['filters']
|
||||
|
||||
|
||||
@pytest.mark.parametrize('endpoint', ['login_new', 'registration_new'])
|
||||
def test_api_statistics_subfilters(app, admin, endpoint):
|
||||
service = Service.objects.create(name='Service1', slug='service1', ou=get_default_ou())
|
||||
service = Service.objects.create(name='Service2', slug='service2', ou=get_default_ou())
|
||||
|
||||
headers = basic_authorization_header(admin)
|
||||
resp = app.get('/api/statistics/%s/' % endpoint, headers=headers)
|
||||
assert len(resp.json['data']['subfilters']) == 1
|
||||
assert resp.json['data']['subfilters'][0] == {
|
||||
'id': 'service',
|
||||
'label': 'Service',
|
||||
'options': [
|
||||
{'id': 'service1 default', 'label': 'Service1'},
|
||||
{'id': 'service2 default', 'label': 'Service2'},
|
||||
],
|
||||
}
|
||||
|
||||
# adding second ou doesn't change anything
|
||||
ou = OU.objects.create(name='Second OU', slug='second')
|
||||
new_resp = app.get('/api/statistics/%s/' % endpoint, headers=headers)
|
||||
assert new_resp.json == resp.json
|
||||
|
||||
# if there are services in two differents OUs, filter is shown
|
||||
service.ou = ou
|
||||
service.save()
|
||||
resp = app.get('/api/statistics/%s/' % endpoint, headers=headers)
|
||||
assert len(resp.json['data']['subfilters']) == 2
|
||||
assert resp.json['data']['subfilters'][1] == {
|
||||
'id': 'services_ou',
|
||||
'label': 'Services organizational unit',
|
||||
'options': [
|
||||
{'id': 'default', 'label': 'Default organizational unit'},
|
||||
{'id': 'second', 'label': 'Second OU'},
|
||||
],
|
||||
}
|
||||
|
||||
# same goes with users
|
||||
User.objects.create(username='john.doe', email='john.doe@example.com', ou=ou)
|
||||
resp = app.get('/api/statistics/%s/' % endpoint, headers=headers)
|
||||
assert len(resp.json['data']['subfilters']) == 3
|
||||
assert resp.json['data']['subfilters'][2] == {
|
||||
'id': 'users_ou',
|
||||
'label': 'Users organizational unit',
|
||||
'options': [
|
||||
{'id': 'default', 'label': 'Default organizational unit'},
|
||||
{'id': 'second', 'label': 'Second OU'},
|
||||
],
|
||||
}
|
||||
|
||||
resp = app.get('/api/statistics/%s/?group_by=service' % endpoint, headers=headers)
|
||||
assert len(resp.json['data']['subfilters']) == 0
|
||||
|
||||
resp = app.get('/api/statistics/%s/?group_by=service_ou' % endpoint, headers=headers)
|
||||
assert len(resp.json['data']['subfilters']) == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'event_type_name,event_name', [('user.login', 'login'), ('user.registration', 'registration')]
|
||||
'event_type_name,event_name',
|
||||
[
|
||||
('user.login', 'login'),
|
||||
('user.registration', 'registration'),
|
||||
('user.login', 'login_new'),
|
||||
('user.registration', 'registration_new'),
|
||||
],
|
||||
)
|
||||
def test_api_statistics(app, admin, freezer, event_type_name, event_name):
|
||||
headers = basic_authorization_header(admin)
|
||||
|
||||
resp = app.get('/api/statistics/login/?time_interval=month', headers=headers)
|
||||
assert resp.json == {"data": {"series": [], "x_labels": []}, "err": 0}
|
||||
assert resp.json == {"data": {"series": [], "x_labels": [], "subfilters": []}, "err": 0}
|
||||
|
||||
user = User.objects.create(username='john.doe', email='john.doe@example.com', ou=get_default_ou())
|
||||
ou = OU.objects.create(name='Second OU', slug='second')
|
||||
|
@ -2775,14 +2880,22 @@ def test_api_statistics(app, admin, freezer, event_type_name, event_name):
|
|||
{'label': 'password', 'data': [1]},
|
||||
]
|
||||
|
||||
resp = app.get('/api/statistics/service_%s/?time_interval=month' % event_name, headers=headers)
|
||||
if 'new' in event_name:
|
||||
url = '/api/statistics/%s/?time_interval=month&group_by=service' % event_name
|
||||
else:
|
||||
url = '/api/statistics/service_%s/?time_interval=month' % event_name
|
||||
resp = app.get(url, headers=headers)
|
||||
assert resp.json['data']['x_labels'] == ['2020-02', '2020-03']
|
||||
assert resp.json['data']['series'] == [
|
||||
{'data': [1, 1], 'label': 'agendas'},
|
||||
{'data': [1, 1], 'label': 'portal'},
|
||||
]
|
||||
|
||||
resp = app.get('/api/statistics/service_ou_%s/?time_interval=month' % event_name, headers=headers)
|
||||
if 'new' in event_name:
|
||||
url = '/api/statistics/%s/?time_interval=month&group_by=service_ou' % event_name
|
||||
else:
|
||||
url = '/api/statistics/service_ou_%s/?time_interval=month' % event_name
|
||||
resp = app.get(url, headers=headers)
|
||||
assert resp.json['data']['x_labels'] == ['2020-02', '2020-03']
|
||||
assert resp.json['data']['series'] == [
|
||||
{'data': [1, 1], 'label': 'Default organizational unit'},
|
||||
|
|
Loading…
Reference in New Issue