api: add sms count statistics (#53856)
This commit is contained in:
parent
6740ded420
commit
c4c1312ae2
|
@ -16,8 +16,9 @@
|
|||
|
||||
from django.conf.urls import url
|
||||
|
||||
from .views import JobDetailView
|
||||
from .views import JobDetailView, StatisticsListView
|
||||
|
||||
urlpatterns = [
|
||||
url(r'jobs/(?P<pk>[\w,-]+)/$', JobDetailView.as_view(), name='api-job'),
|
||||
url(r'statistics/$', StatisticsListView.as_view(), name='api-statistics-list'),
|
||||
]
|
||||
|
|
|
@ -16,10 +16,11 @@
|
|||
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.http import Http404, JsonResponse
|
||||
from django.views.generic import DetailView
|
||||
from django.views.generic import DetailView, View
|
||||
|
||||
from passerelle.base.models import Job
|
||||
from passerelle.utils import is_authorized
|
||||
from passerelle.views import get_all_apps
|
||||
|
||||
|
||||
class JobDetailView(DetailView):
|
||||
|
@ -45,3 +46,13 @@ class JobDetailView(DetailView):
|
|||
'done_timestamp': job.done_timestamp,
|
||||
}
|
||||
return JsonResponse({'err': 0, 'data': data})
|
||||
|
||||
|
||||
class StatisticsListView(View):
|
||||
def get(self, request, *args, **kwargs):
|
||||
sources = []
|
||||
for app in get_all_apps():
|
||||
for connector in app.objects.all():
|
||||
if hasattr(connector, 'get_statistics_entries'):
|
||||
sources.extend(connector.get_statistics_entries(request))
|
||||
return JsonResponse({'data': sources})
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
from django.apps import apps
|
||||
from django.conf.urls import include, url
|
||||
|
||||
from .urls_utils import app_enabled, decorated_includes, manager_required, required
|
||||
from .urls_utils import app_enabled, decorated_includes, manager_required, required, trust_required
|
||||
|
||||
|
||||
def register_apps_urls(urlpatterns):
|
||||
|
@ -54,5 +54,12 @@ def register_apps_urls(urlpatterns):
|
|||
urls = required(app_enabled(app.label), urls)
|
||||
urls = required(manager_required, urls)
|
||||
after_urls.append(url(url_prefix, include(urls), kwargs={'connector': connector_slug}))
|
||||
if hasattr(obj, 'get_statistics_urls'):
|
||||
url_prefix = '^api/%s/' % connector_slug
|
||||
urls = obj.get_statistics_urls()
|
||||
if urls:
|
||||
urls = required(app_enabled(app.label), urls)
|
||||
urls = required(trust_required, urls)
|
||||
after_urls.append(url(url_prefix, include(urls), kwargs={'connector': connector_slug}))
|
||||
|
||||
return before_urls + urlpatterns + after_urls
|
||||
|
|
|
@ -16,8 +16,10 @@
|
|||
import logging
|
||||
import re
|
||||
|
||||
from django.conf.urls import url
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils import six
|
||||
from django.utils.module_loading import import_string
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
@ -99,6 +101,19 @@ class SMSResource(BaseResource):
|
|||
def get_management_urls(cls):
|
||||
return import_string('passerelle.sms.urls.management_urlpatterns')
|
||||
|
||||
@classmethod
|
||||
def get_statistics_urls(cls):
|
||||
from .views import SmsStatisticsView
|
||||
|
||||
statistics_urlpatterns = [
|
||||
url(
|
||||
r'^(?P<slug>[\w,-]+)/sms-count/$',
|
||||
SmsStatisticsView.as_view(),
|
||||
name='api-statistics-sms-%s' % cls.get_connector_slug(),
|
||||
),
|
||||
]
|
||||
return statistics_urlpatterns
|
||||
|
||||
def _get_authorized_display(self):
|
||||
result = []
|
||||
for key, value in self.AUTHORIZED:
|
||||
|
@ -202,6 +217,26 @@ class SMSResource(BaseResource):
|
|||
self.send_msg(**kwargs)
|
||||
SMSLog.objects.create(appname=self.get_connector_slug(), slug=self.slug)
|
||||
|
||||
def get_statistics_entries(self, request):
|
||||
return [
|
||||
{
|
||||
'name': _('SMS Count (%s)') % self.slug,
|
||||
'url': request.build_absolute_uri(
|
||||
reverse('api-statistics-sms-%s' % self.get_connector_slug(), kwargs={'slug': self.slug}),
|
||||
),
|
||||
'id': 'sms_count_%s_%s' % (self.get_connector_slug(), self.slug),
|
||||
'filters': [
|
||||
{
|
||||
'id': 'time_interval',
|
||||
'label': _('Interval'),
|
||||
'options': [{'id': 'day', 'label': _('Day')}],
|
||||
'required': True,
|
||||
'default': 'day',
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
import datetime
|
||||
|
||||
from django.apps import apps
|
||||
from django.contrib import messages
|
||||
from django.db.models import Count
|
||||
from django.db.models.functions import TruncDay
|
||||
from django.http import JsonResponse
|
||||
from django.utils.timezone import make_aware
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.views.generic import FormView
|
||||
from django.views.generic import FormView, View
|
||||
|
||||
from passerelle.utils.jsonresponse import APIError
|
||||
from passerelle.views import GenericConnectorMixin
|
||||
|
||||
from .forms import SmsTestSendForm
|
||||
from .models import SMSLog
|
||||
|
||||
|
||||
class SmsTestSendView(GenericConnectorMixin, FormView):
|
||||
|
@ -36,3 +43,39 @@ class SmsTestSendView(GenericConnectorMixin, FormView):
|
|||
else:
|
||||
messages.success(self.request, _('An SMS was just sent'))
|
||||
return super(SmsTestSendView, self).form_valid(form)
|
||||
|
||||
|
||||
class SmsStatisticsView(View):
|
||||
def get(self, request, *args, **kwargs):
|
||||
if 'time_interval' in request.GET and request.GET['time_interval'] != 'day':
|
||||
return JsonResponse({'err': 1, 'err_desc': 'unsupported time interval'})
|
||||
|
||||
logs = SMSLog.objects.filter(appname=kwargs['connector'], slug=kwargs['slug'])
|
||||
if 'start' in request.GET:
|
||||
start = make_aware(datetime.datetime.strptime(request.GET['start'], '%Y-%m-%d'))
|
||||
logs = logs.filter(timestamp__gte=start)
|
||||
if 'end' in request.GET:
|
||||
end = make_aware(datetime.datetime.strptime(request.GET['end'], '%Y-%m-%d'))
|
||||
logs = logs.filter(timestamp__lte=end)
|
||||
|
||||
logs = logs.annotate(day=TruncDay('timestamp'))
|
||||
logs = logs.values('day').annotate(total=Count('id')).order_by('day')
|
||||
|
||||
x_labels, data = [], []
|
||||
for log in logs:
|
||||
x_labels.append(log['day'].strftime('%Y-%m-%d'))
|
||||
data.append(log['total'])
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
'data': {
|
||||
'x_labels': x_labels,
|
||||
'series': [
|
||||
{
|
||||
'label': _('SMS Count'),
|
||||
'data': data,
|
||||
}
|
||||
],
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -15,6 +15,8 @@ except ImportError:
|
|||
from django.http import Http404
|
||||
from django.views.debug import technical_404_response
|
||||
|
||||
from passerelle.utils import is_trusted
|
||||
|
||||
|
||||
class DecoratedURLPattern(URLPattern):
|
||||
def resolve(self, *args, **kwargs):
|
||||
|
@ -148,3 +150,13 @@ def manager_required(function=None, login_url=None):
|
|||
if function:
|
||||
return actual_decorator(function)
|
||||
return actual_decorator
|
||||
|
||||
|
||||
def trust_required(func):
|
||||
@wraps(func)
|
||||
def f(request, *args, **kwargs):
|
||||
if not (request.user.is_superuser or is_trusted(request)):
|
||||
raise PermissionDenied()
|
||||
return func(request, *args, **kwargs)
|
||||
|
||||
return f
|
||||
|
|
|
@ -566,3 +566,43 @@ def test_manager(admin_user, app, connector):
|
|||
ResourceLog.objects.filter(levelno=30)[0].extra['exception']
|
||||
== 'no phone number was authorized: 0033188888888'
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('connector', [OVHSMSGateway], indirect=True)
|
||||
def test_api_statistics(app, freezer, connector, admin_user):
|
||||
resp = app.get('/api/statistics/')
|
||||
url = [x for x in resp.json['data'] if x['id'] == 'sms_count_ovh_ovhsmsgateway'][0]['url']
|
||||
|
||||
assert app.get(url, status=403)
|
||||
|
||||
login(app)
|
||||
resp = app.get(url)
|
||||
assert len(resp.json['data']['series'][0]['data']) == 0
|
||||
|
||||
freezer.move_to('2021-01-01 12:00')
|
||||
for _ in range(5):
|
||||
SMSLog.objects.create(appname='ovh', slug='ovhsmsgateway')
|
||||
|
||||
freezer.move_to('2021-02-03 13:00')
|
||||
for _ in range(3):
|
||||
SMSLog.objects.create(appname='ovh', slug='ovhsmsgateway')
|
||||
|
||||
freezer.move_to('2021-02-06 13:00')
|
||||
SMSLog.objects.create(appname='ovh', slug='ovhsmsgateway')
|
||||
SMSLog.objects.create(appname='ovh', slug='other')
|
||||
|
||||
resp = app.get(url + '?time_interval=day')
|
||||
assert resp.json['data'] == {
|
||||
'x_labels': ['2021-01-01', '2021-02-03', '2021-02-06'],
|
||||
'series': [{'label': 'SMS Count', 'data': [5, 3, 1]}],
|
||||
}
|
||||
|
||||
resp = app.get(url + '?start=2021-02-04&end=2021-02-07')
|
||||
assert resp.json['data'] == {
|
||||
'x_labels': ['2021-02-06'],
|
||||
'series': [{'label': 'SMS Count', 'data': [1]}],
|
||||
}
|
||||
|
||||
# invalid time_interval
|
||||
resp = app.get(url + '?time_interval=month')
|
||||
assert resp.json['err'] == 1
|
||||
|
|
Loading…
Reference in New Issue