0001-api-add-sms-count-statistics-53856.patch
passerelle/api/urls.py | ||
---|---|---|
16 | 16 | |
17 | 17 |
from django.conf.urls import url |
18 | 18 | |
19 |
from .views import JobDetailView |
|
19 |
from .views import JobDetailView, SMSStatisticsView, StatisticsListView
|
|
20 | 20 | |
21 | 21 |
urlpatterns = [ |
22 | 22 |
url(r'jobs/(?P<pk>[\w,-]+)/$', JobDetailView.as_view(), name='api-job'), |
23 |
url(r'statistics/$', StatisticsListView.as_view(), name='api-statistics-list'), |
|
24 |
url(r'statistics/sms/$', SMSStatisticsView.as_view(), name='api-statistics-sms'), |
|
23 | 25 |
] |
passerelle/api/views.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
import datetime |
|
18 | ||
17 | 19 |
from django.core.exceptions import PermissionDenied |
20 |
from django.db.models import Count |
|
21 |
from django.db.models.functions import TruncDay |
|
18 | 22 |
from django.http import Http404, JsonResponse |
19 |
from django.views.generic import DetailView |
|
23 |
from django.urls import reverse |
|
24 |
from django.utils.dateparse import parse_date, parse_datetime |
|
25 |
from django.utils.translation import ugettext_lazy as _ |
|
26 |
from django.views.generic import DetailView, View |
|
20 | 27 | |
21 | 28 |
from passerelle.base.models import Job |
29 |
from passerelle.sms.models import SMSLog |
|
22 | 30 |
from passerelle.utils import is_authorized |
23 | 31 | |
24 | 32 | |
... | ... | |
45 | 53 |
'done_timestamp': job.done_timestamp, |
46 | 54 |
} |
47 | 55 |
return JsonResponse({'err': 0, 'data': data}) |
56 | ||
57 | ||
58 |
class StatisticsListView(View): |
|
59 |
def get(self, request, *args, **kwargs): |
|
60 |
return JsonResponse( |
|
61 |
{ |
|
62 |
'data': [ |
|
63 |
{ |
|
64 |
'name': _('SMS Count'), |
|
65 |
'url': request.build_absolute_uri(reverse('api-statistics-sms')), |
|
66 |
'id': 'sms_count', |
|
67 |
'filters': [ |
|
68 |
{ |
|
69 |
'id': 'time_interval', |
|
70 |
'label': _('Interval'), |
|
71 |
'options': [{'id': 'day', 'label': _('Day')}], |
|
72 |
'required': True, |
|
73 |
'default': 'day', |
|
74 |
}, |
|
75 |
], |
|
76 |
} |
|
77 |
] |
|
78 |
} |
|
79 |
) |
|
80 | ||
81 | ||
82 |
class SMSStatisticsView(View): |
|
83 |
def get(self, request, *args, **kwargs): |
|
84 |
if 'time_interval' in request.GET and request.GET['time_interval'] != 'day': |
|
85 |
return JsonResponse({'err': 1, 'err_desc': 'unsupported time interval'}) |
|
86 | ||
87 |
logs = SMSLog.objects |
|
88 |
if 'start' in request.GET: |
|
89 |
start = datetime.datetime.strptime(request.GET['start'], '%Y-%m-%d') |
|
90 |
logs = logs.filter(timestamp__gte=start) |
|
91 |
if 'end' in request.GET: |
|
92 |
end = datetime.datetime.strptime(request.GET['end'], '%Y-%m-%d') |
|
93 |
logs = logs.filter(timestamp__lte=end) |
|
94 | ||
95 |
logs = logs.annotate(day=TruncDay('timestamp')) |
|
96 |
logs = logs.values('day').annotate(total=Count('id')).order_by('day') |
|
97 | ||
98 |
x_labels, data = [], [] |
|
99 |
for log in logs: |
|
100 |
x_labels.append(log['day'].strftime('%Y-%m-%d')) |
|
101 |
data.append(log['total']) |
|
102 | ||
103 |
return JsonResponse( |
|
104 |
{ |
|
105 |
'data': { |
|
106 |
'x_labels': x_labels, |
|
107 |
'series': [ |
|
108 |
{ |
|
109 |
'label': _('SMS Count'), |
|
110 |
'data': data, |
|
111 |
} |
|
112 |
], |
|
113 |
} |
|
114 |
} |
|
115 |
) |
tests/test_api.py | ||
---|---|---|
23 | 23 | |
24 | 24 |
from passerelle.apps.ovh.models import OVHSMSGateway |
25 | 25 |
from passerelle.base.models import AccessRight, ApiUser, Job |
26 |
from passerelle.sms.models import SMSLog |
|
26 | 27 | |
27 | 28 |
pytestmark = pytest.mark.django_db |
28 | 29 | |
... | ... | |
104 | 105 |
assert resp.json['data']['status'] == 'failed' |
105 | 106 |
assert resp.json['data']['status_details'] == {'error_summary': 'Exception: my error message'} |
106 | 107 |
assert resp.json['data']['done_timestamp'] is not None |
108 | ||
109 | ||
110 |
def test_api_statistics_list(app): |
|
111 |
resp = app.get('/api/statistics/') |
|
112 |
assert resp.json['data'][0]['name'] == 'SMS Count' |
|
113 | ||
114 | ||
115 |
def test_api_statistics_sms(app, freezer): |
|
116 |
resp = app.get('/api/statistics/') |
|
117 |
url = [x for x in resp.json['data'] if x['id'] == 'sms_count'][0]['url'] |
|
118 | ||
119 |
resp = app.get(url) |
|
120 |
assert len(resp.json['data']['series'][0]['data']) == 0 |
|
121 | ||
122 |
freezer.move_to('2021-01-01 12:00') |
|
123 |
for _ in range(5): |
|
124 |
SMSLog.objects.create(appname='ovh', slug='sms') |
|
125 | ||
126 |
freezer.move_to('2021-02-03 13:00') |
|
127 |
for _ in range(3): |
|
128 |
SMSLog.objects.create(appname='ovh', slug='sms') |
|
129 | ||
130 |
freezer.move_to('2021-02-06 13:00') |
|
131 |
SMSLog.objects.create(appname='ovh', slug='sms') |
|
132 | ||
133 |
resp = app.get(url + '?time_interval=day') |
|
134 |
assert resp.json['data'] == { |
|
135 |
'x_labels': ['2021-01-01', '2021-02-03', '2021-02-06'], |
|
136 |
'series': [{'label': 'SMS Count', 'data': [5, 3, 1]}], |
|
137 |
} |
|
138 | ||
139 |
resp = app.get(url + '?start=2021-02-04&end=2021-02-07') |
|
140 |
assert resp.json['data'] == { |
|
141 |
'x_labels': ['2021-02-06'], |
|
142 |
'series': [{'label': 'SMS Count', 'data': [1]}], |
|
143 |
} |
|
144 | ||
145 |
# invalid time_interval |
|
146 |
resp = app.get(url + '?time_interval=month') |
|
147 |
assert resp.json['err'] == 1 |
|
107 |
- |